1
1
# implementation of the GPUCompiler interfaces for generating Metal code
2
2
3
- const Metal_LLVM_Tools_jll = LazyModule (" Metal_LLVM_Tools_jll" , UUID (" 0418c028-ff8c-56b8-a53e-0f9676ed36fc" ))
4
-
5
3
# # target
6
4
7
5
export MetalCompilerTarget
@@ -47,21 +45,11 @@ runtime_slug(job::CompilerJob{MetalCompilerTarget}) = "metal-macos$(job.config.t
47
45
isintrinsic (@nospecialize (job:: CompilerJob{MetalCompilerTarget} ), fn:: String ) =
48
46
return startswith (fn, " air." )
49
47
50
- const LLVMMETALFUNCCallConv = LLVM. API. LLVMCallConv (102 )
51
- const LLVMMETALKERNELCallConv = LLVM. API. LLVMCallConv (103 )
52
-
53
48
function finish_module! (@nospecialize (job:: CompilerJob{MetalCompilerTarget} ), mod:: LLVM.Module , entry:: LLVM.Function )
54
49
entry_fn = LLVM. name (entry)
55
50
56
51
# update calling conventions
57
- for f in functions (mod)
58
- # callconv!(f, LLVMMETALFUNCCallConv)
59
- # XXX : this makes InstCombine erase kernel->func calls.
60
- # do we even need this? if we do, do so in metallib-instead.
61
- end
62
52
if job. config. kernel
63
- callconv! (entry, LLVMMETALKERNELCallConv)
64
-
65
53
entry = pass_by_reference! (job, mod, entry)
66
54
67
55
add_input_arguments! (job, mod, entry)
@@ -110,6 +98,49 @@ function validate_ir(job::CompilerJob{MetalCompilerTarget}, mod::LLVM.Module)
110
98
check_ir_values (mod, LLVM. DoubleType ())
111
99
end
112
100
101
+ # hide `noreturn` function attributes, which cause issues with the back-end compiler,
102
+ # probably because of thread-divergent control flow as we've encountered with CUDA.
103
+ # note that it isn't enough to remove the function attribute, because the Metal LLVM
104
+ # compiler re-optimizes and will rediscover the property. to avoid this, we inline
105
+ # all functions that are marked noreturn, i.e., until LLVM cannot rediscover it.
106
+ function hide_noreturn! (mod:: LLVM.Module )
107
+ noreturn_attr = EnumAttribute (" noreturn" , 0 )
108
+ noinline_attr = EnumAttribute (" noinline" , 0 )
109
+ alwaysinline_attr = EnumAttribute (" alwaysinline" , 0 )
110
+
111
+ any_noreturn = false
112
+ for f in functions (mod)
113
+ attrs = function_attributes (f)
114
+ if noreturn_attr in collect (attrs)
115
+ delete! (attrs, noreturn_attr)
116
+ delete! (attrs, noinline_attr)
117
+ push! (attrs, alwaysinline_attr)
118
+ any_noreturn = true
119
+ end
120
+ end
121
+ any_noreturn || return false
122
+
123
+ if use_newpm
124
+ @dispose pb= PassBuilder () mpm= NewPMModulePassManager (pb) begin
125
+ add! (mpm, AlwaysInlinerPass ())
126
+ add! (mpm, NewPMFunctionPassManager) do fpm
127
+ add! (fpm, SimplifyCFGPass ())
128
+ add! (fpm, InstCombinePass ())
129
+ end
130
+ run! (mpm, mod)
131
+ end
132
+ else
133
+ @dispose pm= ModulePassManager () begin
134
+ always_inliner! (pm)
135
+ cfgsimplification! (pm)
136
+ instruction_combining! (pm)
137
+ run! (pm, mod)
138
+ end
139
+ end
140
+
141
+ return true
142
+ end
143
+
113
144
function finish_ir! (@nospecialize (job:: CompilerJob{MetalCompilerTarget} ), mod:: LLVM.Module ,
114
145
entry:: LLVM.Function )
115
146
entry_fn = LLVM. name (entry)
@@ -121,6 +152,8 @@ function finish_ir!(@nospecialize(job::CompilerJob{MetalCompilerTarget}), mod::L
121
152
add_argument_metadata! (job, mod, entry)
122
153
123
154
add_module_metadata! (job, mod)
155
+
156
+ hide_noreturn! (mod)
124
157
end
125
158
126
159
# lower LLVM intrinsics that AIR doesn't support
154
187
155
188
@unlocked function mcgen (job:: CompilerJob{MetalCompilerTarget} , mod:: LLVM.Module ,
156
189
format= LLVM. API. LLVMObjectFile)
157
- strip_debuginfo! (mod) # XXX : is this needed?
158
-
159
- # hide `noreturn` function attributes, which cause issues with the back-end compiler,
160
- # probably because of thread-divergent control flow as we've encountered with CUDA.
161
- # note that it isn't enough to remove the function attribute, because the Metal LLVM
162
- # compiler re-optimizes and will rediscover the property. to avoid this, we inline
163
- # all functions that are marked noreturn, i.e., until LLVM cannot rediscover it.
164
- let
165
- noreturn_attr = EnumAttribute (" noreturn" , 0 )
166
- noinline_attr = EnumAttribute (" noinline" , 0 )
167
- alwaysinline_attr = EnumAttribute (" alwaysinline" , 0 )
168
-
169
- any_noreturn = false
170
- for f in functions (mod)
171
- attrs = function_attributes (f)
172
- if noreturn_attr in collect (attrs)
173
- delete! (attrs, noreturn_attr)
174
- delete! (attrs, noinline_attr)
175
- push! (attrs, alwaysinline_attr)
176
- any_noreturn = true
177
- end
178
- end
179
-
180
- if any_noreturn
181
- if use_newpm
182
- @dispose pb= PassBuilder () mpm= NewPMModulePassManager (pb) begin
183
- add! (mpm, AlwaysInlinerPass ())
184
- add! (mpm, NewPMFunctionPassManager) do fpm
185
- add! (fpm, SimplifyCFGPass ())
186
- add! (fpm, InstCombinePass ())
187
- end
188
- run! (mpm, mod)
189
- end
190
- else
191
- @dispose pm= ModulePassManager () begin
192
- always_inliner! (pm)
193
- cfgsimplification! (pm)
194
- instruction_combining! (pm)
195
- run! (pm, mod)
196
- end
197
- end
198
- end
199
- end
200
-
201
- # translate to metallib
202
- input = tempname (cleanup= false ) * " .bc"
203
- translated = tempname (cleanup= false ) * " .metallib"
204
- write (input, mod)
205
- let cmd = ` $(Metal_LLVM_Tools_jll. metallib_as ()) -o $translated $input `
206
- proc = run (ignorestatus (cmd))
207
- if ! success (proc)
208
- error (""" Failed to translate LLVM code to MetalLib.
209
- If you think this is a bug, please file an issue and attach $(input) .""" )
210
- end
211
- end
212
-
213
- output = if format == LLVM. API. LLVMObjectFile
214
- read (translated)
215
- else
216
- # disassemble
217
- read (` $(Metal_LLVM_Tools_jll. metallib_dis ()) -o - $translated ` , String)
218
- end
219
-
220
- rm (input)
221
- rm (translated)
222
-
223
- return output
190
+ # our LLVM version does not support emitting Metal libraries
191
+ return nothing
224
192
end
225
193
226
194
0 commit comments