1
+ use object:: { Architecture , SubArchitecture } ;
1
2
use rustc_abi:: { BackendRepr , Float , Integer , Primitive , RegKind } ;
2
3
use rustc_attr_parsing:: InstructionSetAttr ;
3
4
use rustc_hir:: def_id:: DefId ;
5
+ use rustc_middle:: middle:: codegen_fn_attrs:: { CodegenFnAttrs , TargetFeature } ;
4
6
use rustc_middle:: mir:: mono:: { Linkage , MonoItem , MonoItemData , Visibility } ;
5
7
use rustc_middle:: mir:: { Body , InlineAsmOperand } ;
6
8
use rustc_middle:: ty:: layout:: { FnAbiOf , HasTyCtxt , HasTypingEnv , LayoutOf } ;
@@ -104,6 +106,215 @@ fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
104
106
}
105
107
}
106
108
109
+ // FIXME share code with `create_object_file`
110
+ fn parse_architecture (
111
+ sess : & rustc_session:: Session ,
112
+ ) -> Option < ( Architecture , Option < SubArchitecture > ) > {
113
+ let ( architecture, subarchitecture) = match & sess. target . arch [ ..] {
114
+ "arm" => ( Architecture :: Arm , None ) ,
115
+ "aarch64" => (
116
+ if sess. target . pointer_width == 32 {
117
+ Architecture :: Aarch64_Ilp32
118
+ } else {
119
+ Architecture :: Aarch64
120
+ } ,
121
+ None ,
122
+ ) ,
123
+ "x86" => ( Architecture :: I386 , None ) ,
124
+ "s390x" => ( Architecture :: S390x , None ) ,
125
+ "mips" | "mips32r6" => ( Architecture :: Mips , None ) ,
126
+ "mips64" | "mips64r6" => ( Architecture :: Mips64 , None ) ,
127
+ "x86_64" => (
128
+ if sess. target . pointer_width == 32 {
129
+ Architecture :: X86_64_X32
130
+ } else {
131
+ Architecture :: X86_64
132
+ } ,
133
+ None ,
134
+ ) ,
135
+ "powerpc" => ( Architecture :: PowerPc , None ) ,
136
+ "powerpc64" => ( Architecture :: PowerPc64 , None ) ,
137
+ "riscv32" => ( Architecture :: Riscv32 , None ) ,
138
+ "riscv64" => ( Architecture :: Riscv64 , None ) ,
139
+ "sparc" => {
140
+ if sess. unstable_target_features . contains ( & sym:: v8plus) {
141
+ // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode
142
+ ( Architecture :: Sparc32Plus , None )
143
+ } else {
144
+ // Target uses V7 or V8, aka EM_SPARC
145
+ ( Architecture :: Sparc , None )
146
+ }
147
+ }
148
+ "sparc64" => ( Architecture :: Sparc64 , None ) ,
149
+ "avr" => ( Architecture :: Avr , None ) ,
150
+ "msp430" => ( Architecture :: Msp430 , None ) ,
151
+ "hexagon" => ( Architecture :: Hexagon , None ) ,
152
+ "bpf" => ( Architecture :: Bpf , None ) ,
153
+ "loongarch64" => ( Architecture :: LoongArch64 , None ) ,
154
+ "csky" => ( Architecture :: Csky , None ) ,
155
+ "arm64ec" => ( Architecture :: Aarch64 , Some ( SubArchitecture :: Arm64EC ) ) ,
156
+
157
+ // added here
158
+ "wasm32" => ( Architecture :: Wasm32 , None ) ,
159
+ "wasm64" => ( Architecture :: Wasm64 , None ) ,
160
+ "m68k" => ( Architecture :: M68k , None ) ,
161
+
162
+ // Unsupported architecture.
163
+ _ => return None ,
164
+ } ;
165
+
166
+ Some ( ( architecture, subarchitecture) )
167
+ }
168
+
169
+ /// Enable the function's target features in the body of the function, then disable them again
170
+ fn enable_disable_target_features < ' tcx > (
171
+ tcx : TyCtxt < ' tcx > ,
172
+ attrs : & CodegenFnAttrs ,
173
+ ) -> Option < ( String , String ) > {
174
+ use std:: fmt:: Write ;
175
+
176
+ let mut begin = String :: new ( ) ;
177
+ let mut end = String :: new ( ) ;
178
+
179
+ let ( architecture, _subarchitecture) = parse_architecture ( tcx. sess ) ?;
180
+ let features = attrs. target_features . iter ( ) . filter ( |attr| !attr. implied ) ;
181
+
182
+ match architecture {
183
+ Architecture :: X86_64 | Architecture :: X86_64_X32 => { /* do nothing */ }
184
+
185
+ Architecture :: Aarch64 | Architecture :: Aarch64_Ilp32 | Architecture :: Arm => {
186
+ // https://developer.arm.com/documentation/100067/0611/armclang-Integrated-Assembler/AArch32-Target-selection-directives?lang=en
187
+
188
+ for feature in features {
189
+ writeln ! ( begin, ".arch_extension {}" , feature. name) . unwrap ( ) ;
190
+
191
+ writeln ! ( end, ".arch_extension no{}" , feature. name) . unwrap ( ) ;
192
+ }
193
+ }
194
+ Architecture :: Riscv32 | Architecture :: Riscv64 => {
195
+ // https://github.com./riscv-non-isa/riscv-asm-manual/blob/ad0de8c004e29c9a7ac33cfd054f4d4f9392f2fb/src/asm-manual.adoc#arch
196
+
197
+ for feature in features {
198
+ writeln ! ( begin, ".option arch, +{}" , feature. name) . unwrap ( ) ;
199
+
200
+ writeln ! ( end, ".option arch, -{}" , feature. name) . unwrap ( ) ;
201
+ }
202
+ }
203
+ Architecture :: Mips | Architecture :: Mips64 | Architecture :: Mips64_N32 => {
204
+ // https://sourceware.org/binutils/docs/as/MIPS-ISA.html
205
+ // https://sourceware.org/binutils/docs/as/MIPS-ASE-Instruction-Generation-Overrides.html
206
+
207
+ for feature in features {
208
+ writeln ! ( begin, ".set {}" , feature. name) . unwrap ( ) ;
209
+
210
+ writeln ! ( end, ".set no{}" , feature. name) . unwrap ( ) ;
211
+ }
212
+ }
213
+
214
+ Architecture :: S390x => {
215
+ // https://sourceware.org/binutils/docs/as/s390-Directives.html
216
+
217
+ // based on src/llvm-project/llvm/lib/Target/SystemZ/SystemZFeatures.td
218
+ let isa_revision_for_feature = |feature : & TargetFeature | match feature. name . as_str ( ) {
219
+ "backchain" => None , // does not define any instructions
220
+ "deflate-conversion" => Some ( 13 ) ,
221
+ "enhanced-sort" => Some ( 13 ) ,
222
+ "guarded-storage" => Some ( 12 ) ,
223
+ "high-word" => None , // technically 9, but LLVM supports only >= 10
224
+ "nnp-assist" => Some ( 14 ) ,
225
+ "transactional-execution" => Some ( 10 ) ,
226
+ "vector" => Some ( 11 ) ,
227
+ "vector-enhancements-1" => Some ( 12 ) ,
228
+ "vector-enhancements-2" => Some ( 13 ) ,
229
+ "vector-packed-decimal" => Some ( 12 ) ,
230
+ "vector-packed-decimal-enhancement" => Some ( 13 ) ,
231
+ "vector-packed-decimal-enhancement-2" => Some ( 14 ) ,
232
+ _ => None ,
233
+ } ;
234
+
235
+ if let Some ( minimum_isa) = features. filter_map ( isa_revision_for_feature) . max ( ) {
236
+ writeln ! ( begin, ".machine arch{minimum_isa}" ) . unwrap ( ) ;
237
+
238
+ // NOTE: LLVM does not support `.machine push` and `.machine pop`, so we rely on these
239
+ // target features only being applied to this ASM block (LLVM clears them for the next)
240
+ //
241
+ // https://github.com./llvm/llvm-project/blob/74306afe87b85cb9b5734044eb6c74b8290098b3/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp#L1362
242
+ }
243
+ }
244
+ Architecture :: PowerPc | Architecture :: PowerPc64 => {
245
+ // https://www.ibm.com/docs/en/ssw_aix_71/assembler/assembler_pdf.pdf
246
+
247
+ // based on src/llvm-project/llvm/lib/Target/PowerPC/PPC.td
248
+ let isa_revision_for_feature = |feature : & TargetFeature | match feature. name . as_str ( ) {
249
+ "altivec" => Some ( 7 ) ,
250
+ "partword-atomics" => Some ( 8 ) ,
251
+ "power10-vector" => Some ( 10 ) ,
252
+ "power8-altivec" => Some ( 8 ) ,
253
+ "power8-crypto" => Some ( 8 ) ,
254
+ "power8-vector" => Some ( 9 ) ,
255
+ "power9-altivec" => Some ( 9 ) ,
256
+ "power9-vector" => Some ( 9 ) ,
257
+ "quadword-atomics" => Some ( 8 ) ,
258
+ "vsx" => Some ( 7 ) ,
259
+ _ => None ,
260
+ } ;
261
+
262
+ if let Some ( minimum_isa) = features. filter_map ( isa_revision_for_feature) . max ( ) {
263
+ writeln ! ( begin, ".machine push" ) . unwrap ( ) ;
264
+
265
+ // LLVM currently ignores the .machine directive, and allows all instructions regardless
266
+ // of the machine. This may be fixed in the future.
267
+ //
268
+ // https://github.com./llvm/llvm-project/blob/74306afe87b85cb9b5734044eb6c74b8290098b3/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp#L1799
269
+ writeln ! ( begin, ".machine pwr{minimum_isa}" ) . unwrap ( ) ;
270
+
271
+ writeln ! ( end, ".machine pop" ) . unwrap ( ) ;
272
+ }
273
+ }
274
+
275
+ Architecture :: M68k => {
276
+ // https://sourceware.org/binutils/docs/as/M68K_002dDirectives.html#index-directives_002c-M680x0
277
+
278
+ // FIXME support m64k
279
+ // return None;
280
+ }
281
+
282
+ Architecture :: Wasm32 | Architecture :: Wasm64 => {
283
+ // LLVM does not appear to accept any directive to enable target features
284
+ //
285
+ // https://github.com./llvm/llvm-project/blob/74306afe87b85cb9b5734044eb6c74b8290098b3/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp#L909
286
+ return None ;
287
+ }
288
+
289
+ Architecture :: LoongArch64 => {
290
+ // LLVM does not appear to accept any directive to enable target features
291
+ //
292
+ // https://github.com./llvm/llvm-project/blob/74306afe87b85cb9b5734044eb6c74b8290098b3/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp#L1918
293
+ }
294
+
295
+ // FIXME: support naked_asm! on more architectures
296
+ Architecture :: Avr => return None ,
297
+ Architecture :: Bpf => return None ,
298
+ Architecture :: Csky => return None ,
299
+ Architecture :: E2K32 => return None ,
300
+ Architecture :: E2K64 => return None ,
301
+ Architecture :: I386 => return None ,
302
+ Architecture :: Hexagon => return None ,
303
+ Architecture :: Msp430 => return None ,
304
+ Architecture :: Sbf => return None ,
305
+ Architecture :: Sharc => return None ,
306
+ Architecture :: Sparc => return None ,
307
+ Architecture :: Sparc32Plus => return None ,
308
+ Architecture :: Sparc64 => return None ,
309
+ Architecture :: Xtensa => return None ,
310
+
311
+ // the Architecture enum is non-exhaustive
312
+ Architecture :: Unknown | _ => return None ,
313
+ }
314
+
315
+ Some ( ( begin, end) )
316
+ }
317
+
107
318
fn prefix_and_suffix < ' tcx > (
108
319
tcx : TyCtxt < ' tcx > ,
109
320
instance : Instance < ' tcx > ,
@@ -186,6 +397,12 @@ fn prefix_and_suffix<'tcx>(
186
397
Ok ( ( ) )
187
398
} ;
188
399
400
+ let Some ( ( target_feature_begin, target_feature_end) ) =
401
+ enable_disable_target_features ( tcx, attrs)
402
+ else {
403
+ panic ! ( "target features on naked functions are not supported for this architecture" ) ;
404
+ } ;
405
+
189
406
let mut begin = String :: new ( ) ;
190
407
let mut end = String :: new ( ) ;
191
408
match asm_binary_format {
@@ -205,6 +422,8 @@ fn prefix_and_suffix<'tcx>(
205
422
writeln ! ( begin, ".pushsection {section},\" ax\" , {progbits}" ) . unwrap ( ) ;
206
423
writeln ! ( begin, ".balign {align}" ) . unwrap ( ) ;
207
424
write_linkage ( & mut begin) . unwrap ( ) ;
425
+ begin. push_str ( & target_feature_begin) ;
426
+
208
427
if let Visibility :: Hidden = item_data. visibility {
209
428
writeln ! ( begin, ".hidden {asm_name}" ) . unwrap ( ) ;
210
429
}
@@ -215,6 +434,7 @@ fn prefix_and_suffix<'tcx>(
215
434
writeln ! ( begin, "{asm_name}:" ) . unwrap ( ) ;
216
435
217
436
writeln ! ( end) . unwrap ( ) ;
437
+ end. push_str ( & target_feature_end) ;
218
438
writeln ! ( end, ".size {asm_name}, . - {asm_name}" ) . unwrap ( ) ;
219
439
writeln ! ( end, ".popsection" ) . unwrap ( ) ;
220
440
if !arch_suffix. is_empty ( ) {
@@ -226,12 +446,14 @@ fn prefix_and_suffix<'tcx>(
226
446
writeln ! ( begin, ".pushsection {},regular,pure_instructions" , section) . unwrap ( ) ;
227
447
writeln ! ( begin, ".balign {align}" ) . unwrap ( ) ;
228
448
write_linkage ( & mut begin) . unwrap ( ) ;
449
+ begin. push_str ( & target_feature_begin) ;
229
450
if let Visibility :: Hidden = item_data. visibility {
230
451
writeln ! ( begin, ".private_extern {asm_name}" ) . unwrap ( ) ;
231
452
}
232
453
writeln ! ( begin, "{asm_name}:" ) . unwrap ( ) ;
233
454
234
455
writeln ! ( end) . unwrap ( ) ;
456
+ end. push_str ( & target_feature_end) ;
235
457
writeln ! ( end, ".popsection" ) . unwrap ( ) ;
236
458
if !arch_suffix. is_empty ( ) {
237
459
writeln ! ( end, "{}" , arch_suffix) . unwrap ( ) ;
@@ -242,13 +464,15 @@ fn prefix_and_suffix<'tcx>(
242
464
writeln ! ( begin, ".pushsection {},\" xr\" " , section) . unwrap ( ) ;
243
465
writeln ! ( begin, ".balign {align}" ) . unwrap ( ) ;
244
466
write_linkage ( & mut begin) . unwrap ( ) ;
467
+ begin. push_str ( & target_feature_begin) ;
245
468
writeln ! ( begin, ".def {asm_name}" ) . unwrap ( ) ;
246
469
writeln ! ( begin, ".scl 2" ) . unwrap ( ) ;
247
470
writeln ! ( begin, ".type 32" ) . unwrap ( ) ;
248
471
writeln ! ( begin, ".endef {asm_name}" ) . unwrap ( ) ;
249
472
writeln ! ( begin, "{asm_name}:" ) . unwrap ( ) ;
250
473
251
474
writeln ! ( end) . unwrap ( ) ;
475
+ end. push_str ( & target_feature_end) ;
252
476
writeln ! ( end, ".popsection" ) . unwrap ( ) ;
253
477
if !arch_suffix. is_empty ( ) {
254
478
writeln ! ( end, "{}" , arch_suffix) . unwrap ( ) ;
0 commit comments