Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Name LLVM variables from codegen #50094

Merged
merged 18 commits into from
Jun 20, 2023
Merged

Name LLVM variables from codegen #50094

merged 18 commits into from
Jun 20, 2023

Conversation

pchintalapudi
Copy link
Member

@pchintalapudi pchintalapudi commented Jun 6, 2023

This makes it easier to identify where particular LLVM IR statements come from in codegen, without impacting the final generated code (note the array* and memcpy_refined statements in the example). Names are best-effort guesses.

Example
julia> function f(m)
           a = Vector{Union{Nothing, Int}}(zeros(Int, 64))
           for i in eachindex(a)
               a[i] = 0
           end
           a
       end
f (generic function with 1 method)

julia> @code_llvm f(100)
;  @ REPL[10]:1 within `f`
define nonnull {}* @julia_f_250(i64 signext %0) #0 {
top:
  %gcframe41 = alloca [3 x {}*], align 16
  %gcframe41.sub = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe41, i64 0, i64 0
  %1 = bitcast [3 x {}*]* %gcframe41 to i8*
  call void @llvm.memset.p0i8.i32(i8* noundef nonnull align 16 dereferenceable(24) %1, i8 0, i32 24, i1 false)
  %thread_ptr = call i8* asm "movq %fs:0, $0", "=r"() #8
  %ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
  %ppgcstack = bitcast i8* %ppgcstack_i8 to {}****
  %pgcstack = load {}***, {}**** %ppgcstack, align 8
;  @ REPL[10]:2 within `f`
; ┌ @ array.jl:630 within `zeros` @ array.jl:634
; │┌ @ boot.jl:484 within `Array` @ boot.jl:475
    %2 = bitcast [3 x {}*]* %gcframe41 to i64*
    store i64 4, i64* %2, align 16
    %3 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe41, i64 0, i64 1
    %4 = bitcast {}** %3 to {}***
    %5 = load {}**, {}*** %pgcstack, align 8
    store {}** %5, {}*** %4, align 8
    %6 = bitcast {}*** %pgcstack to {}***
    store {}** %gcframe41.sub, {}*** %6, align 8
    %7 = call nonnull {}* inttoptr (i64 140041092268144 to {}* ({}*, i64)*)({}* inttoptr (i64 140040736320576 to {}*), i64 64)
; │└
; │ @ array.jl:630 within `zeros` @ array.jl:635
; │┌ @ array.jl:392 within `fill!`
; ││┌ @ abstractarray.jl:318 within `eachindex`
; │││┌ @ abstractarray.jl:134 within `axes1`
; ││││┌ @ abstractarray.jl:98 within `axes`
; │││││┌ @ array.jl:191 within `size`
        %8 = bitcast {}* %7 to { i8*, i64, i16, i16, i32 }*
        %9 = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %8, i64 0, i32 1
        %arraylen = load i64, i64* %9, align 8
; ││└└└└
; ││┌ @ range.jl:893 within `iterate`
; │││┌ @ range.jl:668 within `isempty`
; ││││┌ @ operators.jl:376 within `>`
; │││││┌ @ int.jl:83 within `<`
        %.not.not = icmp eq i64 %arraylen, 0
; ││└└└└
    br i1 %.not.not, label %L31, label %L14.preheader

L14.preheader:                                    ; preds = %top
    %10 = bitcast {}* %7 to i8**
    %arrayptr2639 = load i8*, i8** %10, align 8
; ││ @ array.jl:394 within `fill!`
    %11 = shl nuw i64 %arraylen, 3
; ││ @ array.jl:393 within `fill!`
; ││┌ @ array.jl:1019 within `setindex!`
     call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %arrayptr2639, i8 0, i64 %11, i1 false)
; └└└
  br label %L31

L31:                                              ; preds = %L14.preheader, %top
  %12 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe41, i64 0, i64 2
  store {}* %7, {}** %12, align 16
  %13 = call nonnull {}* @j_Array_252({}* nonnull %7)
;  @ REPL[10]:3 within `f`
; ┌ @ abstractarray.jl:318 within `eachindex`
; │┌ @ abstractarray.jl:134 within `axes1`
; ││┌ @ abstractarray.jl:98 within `axes`
; │││┌ @ array.jl:191 within `size`
      %14 = bitcast {}* %13 to { i8*, i64, i16, i16, i32 }*
      %15 = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %14, i64 0, i32 1
      %arraylen8 = load i64, i64* %15, align 8
; └└└└
; ┌ @ range.jl:893 within `iterate`
; │┌ @ range.jl:668 within `isempty`
; ││┌ @ operators.jl:376 within `>`
; │││┌ @ int.jl:83 within `<`
      %.not.not28 = icmp eq i64 %arraylen8, 0
; └└└└
  br i1 %.not.not28, label %L58, label %L44.preheader33

L44.preheader33:                                  ; preds = %L31
  %16 = bitcast {}* %13 to [1 x i64]**
  %17 = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %14, i64 0, i32 4
  %18 = bitcast {}* %13 to {}**
  %19 = getelementptr inbounds {}*, {}** %18, i64 4
  %20 = bitcast {}** %19 to i64*
;  @ REPL[10]:4 within `f`
; ┌ @ array.jl:1019 within `setindex!`
   %arrayptr1629.pre = load [1 x i64]*, [1 x i64]** %16, align 8
   %arrayoffset.pre = load i32, i32* %17, align 4
   %arraysize.pre = load i64, i64* %20, align 8
   br label %idxend

L58:                                              ; preds = %idxend, %L31
   %21 = load {}*, {}** %3, align 8
   %22 = bitcast {}*** %pgcstack to {}**
   store {}* %21, {}** %22, align 8
; └
;  @ REPL[10]:6 within `f`
  ret {}* %13

idxend:                                           ; preds = %idxend, %L44.preheader33
  %value_phi13 = phi i64 [ %28, %idxend ], [ 1, %L44.preheader33 ]
;  @ REPL[10]:4 within `f`
; ┌ @ array.jl:1019 within `setindex!`
   %23 = add nsw i64 %value_phi13, -1
   %24 = zext i32 %arrayoffset.pre to i64
   %selidx_v = sub nsw i64 %arraysize.pre, %24
   %ptindex = getelementptr inbounds [1 x i64], [1 x i64]* %arrayptr1629.pre, i64 %selidx_v
   %25 = bitcast [1 x i64]* %ptindex to i8*
   %26 = sext i32 %arrayoffset.pre to i64
   %27 = getelementptr inbounds i8, i8* %25, i64 %26
   %ptindex18 = getelementptr inbounds i8, i8* %27, i64 %23
   store i8 1, i8* %ptindex18, align 1
   %memcpy_refined_dst19 = getelementptr inbounds [1 x i64], [1 x i64]* %arrayptr1629.pre, i64 %23, i64 0
   store i64 0, i64* %memcpy_refined_dst19, align 8
; └
;  @ REPL[10]:5 within `f`
; ┌ @ range.jl:897 within `iterate`
   %28 = add nuw nsw i64 %value_phi13, 1
; └
  %29 = icmp ult i64 %value_phi13, %arraylen8
  br i1 %29, label %idxend, label %L58
}

@pchintalapudi pchintalapudi added system:32-bit Affects only 32-bit systems compiler:codegen Generation of LLVM IR and native code compiler:llvm For issues that relate to LLVM and removed system:32-bit Affects only 32-bit systems labels Jun 6, 2023
@gbaraldi
Copy link
Member

gbaraldi commented Jun 6, 2023

I wonder if we can get the julia level names as well?

@pchintalapudi
Copy link
Member Author

I don't see much point in grabbing the julia-level names here, if those are accessible they should go into proper debug info rather than instruction names.

@maleadt
Copy link
Member

maleadt commented Jun 7, 2023

I don't see much point in grabbing the julia-level names

It would make the IR more legible just like this PR does?

@pchintalapudi
Copy link
Member Author

@vtjnash looks like the issue from #49121 with llvm::Any is back for windows, is there a change to the expmap file that's needed here?

@pchintalapudi
Copy link
Member Author

In the interest of not holding this up due to no-gnu-unique, I've just disabled the offending tests on Windows. Since the test isn't really platform-specific, I don't think we'll lose any real coverage by disabling it.

@pchintalapudi pchintalapudi force-pushed the pc/codegen-named branch 2 times, most recently from 0c46b6a to fe39c22 Compare June 18, 2023 21:32
@gbaraldi
Copy link
Member

Does the example still look the same after the changes?

@pchintalapudi
Copy link
Member Author

More or less, I added a handful of other names and named the arguments of the invoke stub, since those are pretty simple compared to the specsig function's arguments. Imaging mode results in poor IR output, so that's not turned on for code_llvm, and unfortunately the OOMs on win32 seem to not be related to the sysimg and are more related to the upping of debug level on code_llvm, so I can't turn that on either.

New Example
julia> @code_llvm dump_module=true f(100)
; ModuleID = 'f'
source_filename = "f"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@_j_const1 = private unnamed_addr constant i64 0

;  @ REPL[1]:1 within `f`
define nonnull {}* @julia_f_153(i64 signext %0) #0 {
top:
  %gcframe45 = alloca [3 x {}*], align 16
  %gcframe45.sub = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe45, i64 0, i64 0
  %1 = bitcast [3 x {}*]* %gcframe45 to i8*
  call void @llvm.memset.p0i8.i32(i8* noundef nonnull align 16 dereferenceable(24) %1, i8 0, i32 24, i1 false)
  %thread_ptr = call i8* asm "movq %fs:0, $0", "=r"() #8
  %ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
  %ppgcstack = bitcast i8* %ppgcstack_i8 to {}****
  %pgcstack = load {}***, {}**** %ppgcstack, align 8
;  @ REPL[1]:2 within `f`
; ┌ @ array.jl:630 within `zeros` @ array.jl:634
; │┌ @ boot.jl:484 within `Array` @ boot.jl:475
    %2 = bitcast [3 x {}*]* %gcframe45 to i64*
    store i64 4, i64* %2, align 16
    %3 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe45, i64 0, i64 1
    %4 = bitcast {}** %3 to {}***
    %5 = load {}**, {}*** %pgcstack, align 8
    store {}** %5, {}*** %4, align 8
    %6 = bitcast {}*** %pgcstack to {}***
    store {}** %gcframe45.sub, {}*** %6, align 8
    %7 = call nonnull {}* inttoptr (i64 139653478707344 to {}* ({}*, i64)*)({}* inttoptr (i64 139653122672256 to {}*), i64 64)
; │└
; │ @ array.jl:630 within `zeros` @ array.jl:635
; │┌ @ array.jl:392 within `fill!`
; ││┌ @ abstractarray.jl:318 within `eachindex`
; │││┌ @ abstractarray.jl:134 within `axes1`
; ││││┌ @ abstractarray.jl:98 within `axes`
; │││││┌ @ array.jl:191 within `size`
        %8 = bitcast {}* %7 to { i8*, i64, i16, i16, i32 }*
        %arraylen_ptr = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %8, i64 0, i32 1
        %arraylen = load i64, i64* %arraylen_ptr, align 8
; ││└└└└
; ││┌ @ range.jl:893 within `iterate`
; │││┌ @ range.jl:668 within `isempty`
; ││││┌ @ operators.jl:376 within `>`
; │││││┌ @ int.jl:83 within `<`
        %.not.not = icmp eq i64 %arraylen, 0
; ││└└└└
    br i1 %.not.not, label %L31, label %L14.preheader

L14.preheader:                                    ; preds = %top
    %9 = bitcast {}* %7 to i8**
    %arrayptr3043 = load i8*, i8** %9, align 8
; ││ @ array.jl:394 within `fill!`
    %10 = shl nuw i64 %arraylen, 3
; ││ @ array.jl:393 within `fill!`
; ││┌ @ array.jl:1019 within `setindex!`
     call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %arrayptr3043, i8 0, i64 %10, i1 false)
; └└└
  br label %L31

L31:                                              ; preds = %L14.preheader, %top
  %11 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe45, i64 0, i64 2
  store {}* %7, {}** %11, align 16
  %12 = call nonnull {}* @j_Array_155({}* nonnull %7)
;  @ REPL[1]:3 within `f`
; ┌ @ abstractarray.jl:318 within `eachindex`
; │┌ @ abstractarray.jl:134 within `axes1`
; ││┌ @ abstractarray.jl:98 within `axes`
; │││┌ @ array.jl:191 within `size`
      %13 = bitcast {}* %12 to { i8*, i64, i16, i16, i32 }*
      %arraylen_ptr8 = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %13, i64 0, i32 1
      %arraylen9 = load i64, i64* %arraylen_ptr8, align 8
; └└└└
; ┌ @ range.jl:893 within `iterate`
; │┌ @ range.jl:668 within `isempty`
; ││┌ @ operators.jl:376 within `>`
; │││┌ @ int.jl:83 within `<`
      %.not.not32 = icmp eq i64 %arraylen9, 0
; └└└└
  br i1 %.not.not32, label %L58, label %L44.preheader37

L44.preheader37:                                  ; preds = %L31
  %14 = bitcast {}* %12 to [1 x i64]**
  %arrayoffset_ptr = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %13, i64 0, i32 4
  %15 = bitcast {}* %12 to {}**
  %arraysize_ptr = getelementptr inbounds {}*, {}** %15, i64 4
  %16 = bitcast {}** %arraysize_ptr to i64*
;  @ REPL[1]:4 within `f`
; ┌ @ array.jl:1019 within `setindex!`
   %arrayptr1933.pre = load [1 x i64]*, [1 x i64]** %14, align 8
   %arrayoffset.pre = load i32, i32* %arrayoffset_ptr, align 4
   %arraysize.pre = load i64, i64* %16, align 8
   br label %idxend

L58:                                              ; preds = %idxend, %L31
   %17 = load {}*, {}** %3, align 8
   %18 = bitcast {}*** %pgcstack to {}**
   store {}* %17, {}** %18, align 8
; └
;  @ REPL[1]:6 within `f`
  ret {}* %12

idxend:                                           ; preds = %idxend, %L44.preheader37
  %value_phi14 = phi i64 [ %24, %idxend ], [ 1, %L44.preheader37 ]
;  @ REPL[1]:4 within `f`
; ┌ @ array.jl:1019 within `setindex!`
   %19 = add nsw i64 %value_phi14, -1
   %20 = zext i32 %arrayoffset.pre to i64
   %selidx_v = sub nsw i64 %arraysize.pre, %20
   %ptindex = getelementptr inbounds [1 x i64], [1 x i64]* %arrayptr1933.pre, i64 %selidx_v
   %21 = bitcast [1 x i64]* %ptindex to i8*
   %22 = sext i32 %arrayoffset.pre to i64
   %23 = getelementptr inbounds i8, i8* %21, i64 %22
   %ptindex22 = getelementptr inbounds i8, i8* %23, i64 %19
   store i8 1, i8* %ptindex22, align 1
   %memcpy_refined_dst23 = getelementptr inbounds [1 x i64], [1 x i64]* %arrayptr1933.pre, i64 %19, i64 0
   store i64 0, i64* %memcpy_refined_dst23, align 8
; └
;  @ REPL[1]:5 within `f`
; ┌ @ range.jl:897 within `iterate`
   %24 = add nuw nsw i64 %value_phi14, 1
; └
  %25 = icmp ult i64 %value_phi14, %arraylen9
  br i1 %25, label %idxend, label %L58
}

; Function Attrs: noinline optnone
define nonnull {}* @jfptr_f_154({}* %function, {}** noalias nocapture noundef readonly %args, i32 %nargs) #1 {
top:
  %0 = getelementptr inbounds {}*, {}** %args, i32 0
  %1 = load {}*, {}** %0, align 8
  %2 = bitcast {}* %1 to i64*
  %3 = load i64, i64* %2, align 8
  %4 = call nonnull {}* @julia_f_153(i64 signext %3)
  ret {}* %4
}

declare nonnull {}* @j_Array_155({}*) #0

; Function Attrs: noreturn
declare void @ijl_bounds_error_ints({}*, i64*, i64) #2

; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
declare i64 @llvm.umin.i64(i64, i64) #3

declare noalias nonnull {}** @julia.new_gc_frame(i32)

declare void @julia.push_gc_frame({}**, i32)

declare {}** @julia.get_gc_frame_slot({}**, i32)

declare void @julia.pop_gc_frame({}**)

; Function Attrs: inaccessiblemem_or_argmemonly
declare void @ijl_gc_queue_root({}*) #4

; Function Attrs: allocsize(2)
declare noalias nonnull {}* @ijl_gc_pool_alloc(i8*, i32, i32) #5

; Function Attrs: allocsize(1)
declare noalias nonnull {}* @ijl_gc_big_alloc(i8*, i64) #6

; Function Attrs: allocsize(1)
declare noalias nonnull {}* @ijl_gc_alloc_typed(i8*, i64, i8*) #6

; Function Attrs: argmemonly nocallback nofree nounwind willreturn writeonly
declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) #7

; Function Attrs: argmemonly nocallback nofree nounwind willreturn writeonly
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #7

attributes #0 = { "frame-pointer"="all" "probe-stack"="inline-asm" }
attributes #1 = { noinline optnone "frame-pointer"="all" "probe-stack"="inline-asm" }
attributes #2 = { noreturn }
attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
attributes #4 = { inaccessiblemem_or_argmemonly }
attributes #5 = { allocsize(2) }
attributes #6 = { allocsize(1) }
attributes #7 = { argmemonly nocallback nofree nounwind willreturn writeonly }
attributes #8 = { nounwind }

!llvm.module.flags = !{!0, !1}

!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}

@pchintalapudi
Copy link
Member Author

I imagine this will be even more effective once we transition to opaque pointers and all of the unnamed bitcasts go away, since we'll have more instructions being operations on other named instructions.

@pchintalapudi pchintalapudi merged commit 0da46e2 into master Jun 20, 2023
@pchintalapudi pchintalapudi deleted the pc/codegen-named branch June 20, 2023 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:codegen Generation of LLVM IR and native code compiler:llvm For issues that relate to LLVM
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants