43
43
44
44
export compile
45
45
46
- # NOTE: the keyword arguments to compile/codegen control those aspects of compilation that
47
- # might have to be changed (e.g. set libraries=false when recursing, or set
48
- # strip=true for reflection). What remains defines the compilation job itself,
49
- # and those values are contained in the CompilerJob struct.
50
-
51
46
# (::CompilerJob)
52
47
const compile_hook = Ref {Union{Nothing,Function}} (nothing )
53
48
54
49
"""
55
- compile(target::Symbol, job::CompilerJob; kwargs...)
56
-
57
- Compile a function `f` invoked with types `tt` for device capability `cap` to one of the
58
- following formats as specified by the `target` argument: `:julia` for Julia IR, `:llvm` for
59
- LLVM IR and `:asm` for machine code.
60
-
61
- The following keyword arguments are supported:
62
- - `toplevel`: indicates that this compilation is the outermost invocation of the compiler
63
- (default: true)
64
- - `libraries`: link the GPU runtime and `libdevice` libraries (default: true, if toplevel)
65
- - `optimize`: optimize the code (default: true, if toplevel)
66
- - `cleanup`: run cleanup passes on the code (default: true, if toplevel)
67
- - `validate`: enable optional validation of input and outputs (default: true, if toplevel)
68
- - `strip`: strip non-functional metadata and debug information (default: false)
69
- - `only_entry`: only keep the entry function, remove all others (default: false).
70
- This option is only for internal use, to implement reflection's `dump_module`.
71
-
72
- Other keyword arguments can be found in the documentation of [`cufunction`](@ref).
50
+ compile(target::Symbol, job::CompilerJob)
51
+
52
+ Compile a `job` to one of the following formats as specified by the `target` argument:
53
+ `:julia` for Julia IR, `:llvm` for LLVM IR and `:asm` for machine code.
73
54
"""
74
55
function compile (target:: Symbol , @nospecialize (job:: CompilerJob ); kwargs... )
56
+ # XXX : remove on next major version
57
+ if ! isempty (kwargs)
58
+ Base. depwarn (" The GPUCompiler `compile` API does not take keyword arguments anymore. Use CompilerConfig instead." , :compile )
59
+ config = CompilerConfig (job. config; kwargs... )
60
+ job = CompilerJob (job. source, config)
61
+ end
62
+
75
63
if compile_hook[] != = nothing
76
64
compile_hook[](job)
77
65
end
78
66
79
- return codegen (target, job; kwargs ... )
67
+ return compile_unhooked (target, job)
80
68
end
81
69
82
- function codegen (output:: Symbol , @nospecialize (job:: CompilerJob ); toplevel:: Bool = true ,
83
- libraries:: Bool = toplevel, optimize:: Bool = toplevel, cleanup:: Bool = toplevel,
84
- validate:: Bool = toplevel, strip:: Bool = false , only_entry:: Bool = false ,
85
- parent_job:: Union{Nothing, CompilerJob} = nothing )
70
+ # XXX : remove on next major version
71
+ function codegen (output:: Symbol , @nospecialize (job:: CompilerJob ); kwargs... )
72
+ if ! isempty (kwargs)
73
+ Base. depwarn (" The GPUCompiler `codegen` function is an internal API. Use `GPUCompiler.compile` (with any kwargs passed to `CompilerConfig`) instead." , :codegen )
74
+ config = CompilerConfig (job. config; kwargs... )
75
+ job = CompilerJob (job. source, config)
76
+ end
77
+ compile_unhooked (output, job)
78
+ end
79
+
80
+ function compile_unhooked (output:: Symbol , @nospecialize (job:: CompilerJob ); kwargs... )
86
81
if context (; throw_error= false ) === nothing
87
82
error (" No active LLVM context. Use `JuliaContext()` do-block syntax to create one." )
88
83
end
89
84
90
85
@timeit_debug to " Validation" begin
91
86
check_method (job) # not optional
92
- validate && check_invocation (job)
87
+ job . config . validate && check_invocation (job)
93
88
end
94
89
95
90
prepare_job! (job)
96
91
97
92
98
93
# # LLVM IR
99
94
100
- ir, ir_meta = emit_llvm (job; libraries, toplevel, optimize, cleanup, only_entry, validate )
95
+ ir, ir_meta = emit_llvm (job)
101
96
102
97
if output == :llvm
103
- if strip
98
+ if job . config . strip
104
99
@timeit_debug to " strip debug info" strip_debuginfo! (ir)
105
100
end
106
101
@@ -117,7 +112,7 @@ function codegen(output::Symbol, @nospecialize(job::CompilerJob); toplevel::Bool
117
112
else
118
113
error (" Unknown assembly format $output " )
119
114
end
120
- asm, asm_meta = emit_asm (job, ir; strip, validate , format)
115
+ asm, asm_meta = emit_asm (job, ir, format)
121
116
122
117
if output == :asm || output == :obj
123
118
return asm, (; asm_meta... , ir_meta... , ir)
156
151
157
152
const __llvm_initialized = Ref (false )
158
153
159
- @locked function emit_llvm (@nospecialize (job:: CompilerJob ); toplevel:: Bool ,
160
- libraries:: Bool , optimize:: Bool , cleanup:: Bool ,
161
- validate:: Bool , only_entry:: Bool )
154
+ @locked function emit_llvm (@nospecialize (job:: CompilerJob ); kwargs... )
155
+ # XXX : remove on next major version
156
+ if ! isempty (kwargs)
157
+ Base. depwarn (" The GPUCompiler `emit_llvm` function is an internal API. Use `GPUCompiler.compile` (with any kwargs passed to `CompilerConfig`) instead." , :emit_llvm )
158
+ config = CompilerConfig (job. config; kwargs... )
159
+ job = CompilerJob (job. source, config)
160
+ end
161
+
162
162
if ! __llvm_initialized[]
163
163
InitializeAllTargets ()
164
164
InitializeAllTargetInfos ()
@@ -183,7 +183,8 @@ const __llvm_initialized = Ref(false)
183
183
entry = finish_module! (job, ir, entry)
184
184
185
185
# deferred code generation
186
- has_deferred_jobs = toplevel && ! only_entry && haskey (functions (ir), " deferred_codegen" )
186
+ has_deferred_jobs = job. config. toplevel && ! job. config. only_entry &&
187
+ haskey (functions (ir), " deferred_codegen" )
187
188
jobs = Dict {CompilerJob, String} (job => entry_fn)
188
189
if has_deferred_jobs
189
190
dyn_marker = functions (ir)[" deferred_codegen" ]
@@ -221,8 +222,8 @@ const __llvm_initialized = Ref(false)
221
222
for dyn_job in keys (worklist)
222
223
# cached compilation
223
224
dyn_entry_fn = get! (jobs, dyn_job) do
224
- dyn_ir, dyn_meta = codegen ( :llvm , dyn_job; toplevel= false ,
225
- parent_job = job )
225
+ config = CompilerConfig ( dyn_job. config ; toplevel= false )
226
+ dyn_ir, dyn_meta = codegen ( :llvm , CompilerJob (dyn_job; config) )
226
227
dyn_entry_fn = LLVM. name (dyn_meta. entry)
227
228
merge! (compiled, dyn_meta. compiled)
228
229
@assert context (dyn_ir) == context (ir)
@@ -258,7 +259,7 @@ const __llvm_initialized = Ref(false)
258
259
erase! (dyn_marker)
259
260
end
260
261
261
- if libraries
262
+ if job . config . toplevel && job . config . libraries
262
263
# load the runtime outside of a timing block (because it recurses into the compiler)
263
264
if ! uses_julia_runtime (job)
264
265
runtime = load_runtime (job)
@@ -284,7 +285,7 @@ const __llvm_initialized = Ref(false)
284
285
# mark everything internal except for entrypoints and any exported
285
286
# global variables. this makes sure that the optimizer can, e.g.,
286
287
# rewrite function signatures.
287
- if toplevel
288
+ if job . config . toplevel
288
289
preserved_gvs = collect (values (jobs))
289
290
for gvar in globals (ir)
290
291
if linkage (gvar) == LLVM. API. LLVMExternalLinkage
@@ -310,7 +311,7 @@ const __llvm_initialized = Ref(false)
310
311
# so that we can reconstruct the CompileJob instead of setting it globally
311
312
end
312
313
313
- if optimize
314
+ if job . config . toplevel && job . config . optimize
314
315
@timeit_debug to " optimization" begin
315
316
optimize! (job, ir; job. config. opt_level)
316
317
@@ -337,7 +338,7 @@ const __llvm_initialized = Ref(false)
337
338
entry = functions (ir)[entry_fn]
338
339
end
339
340
340
- if cleanup
341
+ if job . config . toplevel && job . config . cleanup
341
342
@timeit_debug to " clean-up" begin
342
343
@dispose pb= NewPMPassBuilder () begin
343
344
add! (pb, RecomputeGlobalsAAPass ())
@@ -355,7 +356,7 @@ const __llvm_initialized = Ref(false)
355
356
# we want to finish the module after optimization, so we cannot do so
356
357
# during deferred code generation. instead, process the deferred jobs
357
358
# here.
358
- if toplevel
359
+ if job . config . toplevel
359
360
entry = finish_ir! (job, ir, entry)
360
361
361
362
for (job′, fn′) in jobs
@@ -367,7 +368,7 @@ const __llvm_initialized = Ref(false)
367
368
# replace non-entry function definitions with a declaration
368
369
# NOTE: we can't do this before optimization, because the definitions of called
369
370
# functions may affect optimization.
370
- if only_entry
371
+ if job . config . only_entry
371
372
for f in functions (ir)
372
373
f == entry && continue
373
374
isdeclaration (f) && continue
@@ -377,7 +378,7 @@ const __llvm_initialized = Ref(false)
377
378
end
378
379
end
379
380
380
- if validate
381
+ if job . config . toplevel && job . config . validate
381
382
@timeit_debug to " Validation" begin
382
383
check_ir (job, ir)
383
384
end
@@ -390,10 +391,10 @@ const __llvm_initialized = Ref(false)
390
391
return ir, (; entry, compiled)
391
392
end
392
393
393
- @locked function emit_asm (@nospecialize (job:: CompilerJob ), ir:: LLVM.Module ;
394
- strip :: Bool , validate :: Bool , format:: LLVM.API.LLVMCodeGenFileType )
394
+ @locked function emit_asm (@nospecialize (job:: CompilerJob ), ir:: LLVM.Module ,
395
+ format:: LLVM.API.LLVMCodeGenFileType )
395
396
# NOTE: strip after validation to get better errors
396
- if strip
397
+ if job . config . strip
397
398
@timeit_debug to " Debug info removal" strip_debuginfo! (ir)
398
399
end
399
400
0 commit comments