Skip to content

Commit 04e9aa9

Browse files
vchuravymaleadt
andauthored
Turn Julia passes into closures (#864)
Co-authored-by: Tim Besard <tim.besard@gmail.com>
1 parent 03ae9a5 commit 04e9aa9

6 files changed

Lines changed: 122 additions & 125 deletions

File tree

src/driver.jl

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -82,53 +82,44 @@ function compile_unhooked(output::Symbol, @nospecialize(job::CompilerJob); kwarg
8282
error("No active LLVM context. Use `JuliaContext()` do-block syntax to create one.")
8383
end
8484

85-
# save/restore the `current_job` global that passes read: compilation nests (the relink
86-
# pass rebuilds the runtime via `compile_unhooked` on a cold cache), and a leaked inner
87-
# `kernel=false` job would make the outer kernel-state passes misfire.
88-
global current_job
89-
prev_job = @isdefined(current_job) ? current_job : nothing
90-
try
91-
@tracepoint "Validation" begin
92-
check_method(job) # not optional
93-
job.config.validate && check_invocation(job)
94-
end
85+
@tracepoint "Validation" begin
86+
check_method(job) # not optional
87+
job.config.validate && check_invocation(job)
88+
end
9589

96-
prepare_job!(job)
90+
prepare_job!(job)
9791

9892

99-
## LLVM IR
93+
## LLVM IR
10094

101-
ir, ir_meta = emit_llvm(job)
95+
ir, ir_meta = emit_llvm(job)
10296

103-
if output == :llvm
104-
if job.config.strip
105-
@tracepoint "strip debug info" strip_debuginfo!(ir)
106-
end
107-
108-
return ir, ir_meta
97+
if output == :llvm
98+
if job.config.strip
99+
@tracepoint "strip debug info" strip_debuginfo!(ir)
109100
end
110101

102+
return ir, ir_meta
103+
end
111104

112-
## machine code
113-
114-
format = if output == :asm
115-
LLVM.API.LLVMAssemblyFile
116-
elseif output == :obj
117-
LLVM.API.LLVMObjectFile
118-
else
119-
error("Unknown assembly format $output")
120-
end
121-
asm, asm_meta = emit_asm(job, ir, format)
122105

123-
if output == :asm || output == :obj
124-
return asm, (; asm_meta..., ir_meta..., ir)
125-
end
106+
## machine code
126107

108+
format = if output == :asm
109+
LLVM.API.LLVMAssemblyFile
110+
elseif output == :obj
111+
LLVM.API.LLVMObjectFile
112+
else
113+
error("Unknown assembly format $output")
114+
end
115+
asm, asm_meta = emit_asm(job, ir, format)
127116

128-
error("Unknown compilation output $output")
129-
finally
130-
current_job = prev_job
117+
if output == :asm || output == :obj
118+
return asm, (; asm_meta..., ir_meta..., ir)
131119
end
120+
121+
122+
error("Unknown compilation output $output")
132123
end
133124

134125
# primitive mechanism for deferred compilation, for implementing CUDA dynamic parallelism.

src/gcn.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pass_by_ref(@nospecialize(job::CompilerJob{GCNCompilerTarget})) = true
4444

4545
function finish_module!(@nospecialize(job::CompilerJob{GCNCompilerTarget}),
4646
mod::LLVM.Module, entry::LLVM.Function)
47-
lower_throw_extra!(mod)
47+
lower_throw_extra!(job, mod)
4848

4949
if job.config.kernel
5050
# calling convention
@@ -156,8 +156,7 @@ end
156156

157157
## LLVM passes
158158

159-
function lower_throw_extra!(mod::LLVM.Module)
160-
job = current_job::CompilerJob
159+
function lower_throw_extra!(@nospecialize(job::CompilerJob), mod::LLVM.Module)
161160
changed = false
162161
@tracepoint "lower throw (extra)" begin
163162

@@ -179,7 +178,7 @@ function lower_throw_extra!(mod::LLVM.Module)
179178
# replace the throw with a trap
180179
@dispose builder=IRBuilder() begin
181180
position!(builder, call)
182-
emit_exception!(builder, f_name, call)
181+
emit_exception!(job, builder, f_name, call)
183182
end
184183

185184
# remove the call

src/irgen.jl

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,7 @@ function irgen(@nospecialize(job::CompilerJob))
143143
end
144144
end
145145

146-
global current_job
147-
current_job = job
148-
can_throw(job) || lower_throw!(mod)
146+
can_throw(job) || lower_throw!(job, mod)
149147

150148
# resolve the `julia.gpu.debug_level` intrinsic (see `kernel_debug_level_value`) to
151149
# the job's configured level, so device code can branch on it as a compile-time
@@ -166,8 +164,7 @@ end
166164
#
167165
# once we have thorough inference (ie. discarding `@nospecialize` and thus supporting
168166
# exception arguments) and proper debug info to unwind the stack, this pass can go.
169-
function lower_throw!(mod::LLVM.Module)
170-
job = current_job::CompilerJob
167+
function lower_throw!(@nospecialize(job::CompilerJob), mod::LLVM.Module)
171168
changed = false
172169
@tracepoint "lower throw" begin
173170

@@ -200,7 +197,7 @@ function lower_throw!(mod::LLVM.Module)
200197
# replace the throw with a PTX-compatible exception
201198
@dispose builder=IRBuilder() begin
202199
position!(builder, call)
203-
emit_exception!(builder, name, call)
200+
emit_exception!(job, builder, name, call)
204201
end
205202

206203
# remove the call
@@ -249,8 +246,7 @@ end
249246
# while `!mayThrow() && willReturn()`) from deleting the `signal_exception` call below and
250247
# folding away the guarding bounds-check branch. so the trap is the optimizer-correctness guard;
251248
# do not move its removal earlier than post-`optimize!`.
252-
function emit_exception!(builder, name, inst)
253-
job = current_job::CompilerJob
249+
function emit_exception!(@nospecialize(job::CompilerJob), builder, name, inst)
254250
bb = position(builder)
255251
fun = LLVM.parent(bb)
256252
mod = LLVM.parent(fun)
@@ -822,12 +818,13 @@ end
822818
# so that the julia.gpu.state_getter` can be simplified to return an opaque pointer.
823819

824820
# add a state argument to every function in the module, starting from the kernel entry point
825-
function add_kernel_state!(mod::LLVM.Module)
826-
job = current_job::CompilerJob
827-
821+
struct AddKernelState
822+
job::CompilerJob
823+
end
824+
function (self::AddKernelState)(mod::LLVM.Module)
828825
# check if we even need a kernel state argument
829-
job.config.kernel || return false
830-
state = kernel_state_type(job)
826+
self.job.config.kernel || return false
827+
state = kernel_state_type(self.job)
831828
if state === Nothing
832829
return false
833830
end
@@ -1022,18 +1019,20 @@ function add_kernel_state!(mod::LLVM.Module)
10221019

10231020
return true
10241021
end
1025-
AddKernelStatePass() = NewPMModulePass("AddKernelStatePass", add_kernel_state!)
1022+
AddKernelStatePass(job) = NewPMModulePass("AddKernelStatePass", AddKernelState(job))
10261023

10271024
# lower calls to the state getter intrinsic. this is a two-step process, so that the state
10281025
# argument can be added before optimization, and that optimization can introduce new uses
10291026
# before the intrinsic getting lowered late during optimization.
1030-
function lower_kernel_state!(fun::LLVM.Function)
1031-
job = current_job::CompilerJob
1027+
struct LowerKernelState
1028+
job::CompilerJob
1029+
end
1030+
function (self::LowerKernelState)(fun::LLVM.Function)
10321031
mod = LLVM.parent(fun)
10331032
changed = false
10341033

10351034
# check if we even need a kernel state argument
1036-
state = kernel_state_type(job)
1035+
state = kernel_state_type(self.job)
10371036
if state === Nothing
10381037
return false
10391038
end
@@ -1084,10 +1083,12 @@ function lower_kernel_state!(fun::LLVM.Function)
10841083

10851084
return changed
10861085
end
1087-
LowerKernelStatePass() = NewPMFunctionPass("LowerKernelStatePass", lower_kernel_state!)
1086+
LowerKernelStatePass(job) = NewPMFunctionPass("LowerKernelStatePass", LowerKernelState(job))
10881087

1089-
function cleanup_kernel_state!(mod::LLVM.Module)
1090-
job = current_job::CompilerJob
1088+
struct CleanupKernelState
1089+
job::CompilerJob
1090+
end
1091+
function (self::CleanupKernelState)(mod::LLVM.Module)
10911092
changed = false
10921093

10931094
# remove the getter intrinsic
@@ -1102,7 +1103,7 @@ function cleanup_kernel_state!(mod::LLVM.Module)
11021103

11031104
return changed
11041105
end
1105-
CleanupKernelStatePass() = NewPMModulePass("CleanupKernelStatePass", cleanup_kernel_state!)
1106+
CleanupKernelStatePass(job) = NewPMModulePass("CleanupKernelStatePass", CleanupKernelState(job))
11061107

11071108
function kernel_state_intr(mod::LLVM.Module, T_state)
11081109
state_intr = if haskey(functions(mod), "julia.gpu.state_getter")
@@ -1147,7 +1148,7 @@ end
11471148

11481149
# device code can query the job's configured debug level as a compile-time constant via
11491150
# `kernel_debug_level()`, which emits the `julia.gpu.debug_level` intrinsic; `lower_debug_level!`
1150-
# (run from `irgen`, with `current_job` in scope) replaces it with the constant. this keeps
1151+
# (run from `irgen`, with `job` in scope) replaces it with the constant. this keeps
11511152
# the level part of the cache key (it lives in `CompilerConfig`), unlike reading the `-g`
11521153
# global at parse time (which would bake the wrong level under pkgimage reuse across `-g`).
11531154

src/mcgen.jl

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33
# final preparations for the module to be compiled to machine code
44
# these passes should not be run when e.g. compiling to write to disk.
55
function prepare_execution!(@nospecialize(job::CompilerJob), mod::LLVM.Module)
6-
global current_job
7-
current_job = job
8-
96
@dispose pb=NewPMPassBuilder() begin
10-
register!(pb, ResolveCPUReferencesPass())
7+
register!(pb, ResolveCPUReferencesPass(job))
118

129
add!(pb, RecomputeGlobalsAAPass())
1310
add!(pb, GlobalOptPass())
14-
add!(pb, ResolveCPUReferencesPass())
11+
add!(pb, ResolveCPUReferencesPass(job))
1512
add!(pb, GlobalDCEPass())
1613
add!(pb, StripDeadPrototypesPass())
1714

@@ -29,8 +26,10 @@ end
2926
# but at the same time the GPU can't resolve them at run-time.
3027
#
3128
# this pass performs that resolution at link time.
32-
function resolve_cpu_references!(mod::LLVM.Module)
33-
job = current_job::CompilerJob
29+
struct ResolveCPUReferences
30+
job::CompilerJob
31+
end
32+
function (self::ResolveCPUReferences)(mod::LLVM.Module)
3433
changed = false
3534

3635
for f in functions(mod)
@@ -65,8 +64,8 @@ function resolve_cpu_references!(mod::LLVM.Module)
6564

6665
return changed
6766
end
68-
ResolveCPUReferencesPass() =
69-
NewPMModulePass("ResolveCPUReferences", resolve_cpu_references!)
67+
ResolveCPUReferencesPass(job) =
68+
NewPMModulePass("ResolveCPUReferences", ResolveCPUReferences(job))
7069

7170

7271
function mcgen(@nospecialize(job::CompilerJob), mod::LLVM.Module, format=LLVM.API.LLVMAssemblyFile)

0 commit comments

Comments
 (0)