]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/abi.rs
Auto merge of #84228 - SkiFire13:fix-84213, r=estebank
[rust.git] / compiler / rustc_codegen_llvm / src / abi.rs
1 use crate::builder::Builder;
2 use crate::context::CodegenCx;
3 use crate::llvm::{self, AttributePlace};
4 use crate::llvm_util;
5 use crate::type_::Type;
6 use crate::type_of::LayoutLlvmExt;
7 use crate::value::Value;
8
9 use rustc_codegen_ssa::mir::operand::OperandValue;
10 use rustc_codegen_ssa::mir::place::PlaceRef;
11 use rustc_codegen_ssa::traits::*;
12 use rustc_codegen_ssa::MemFlags;
13 use rustc_middle::bug;
14 pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
15 use rustc_middle::ty::Ty;
16 use rustc_target::abi::call::ArgAbi;
17 pub use rustc_target::abi::call::*;
18 use rustc_target::abi::{self, HasDataLayout, Int, LayoutOf};
19 pub use rustc_target::spec::abi::Abi;
20
21 use libc::c_uint;
22
23 macro_rules! for_each_kind {
24     ($flags: ident, $f: ident, $($kind: ident),+) => ({
25         $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+
26     })
27 }
28
29 trait ArgAttributeExt {
30     fn for_each_kind<F>(&self, f: F)
31     where
32         F: FnMut(llvm::Attribute);
33 }
34
35 impl ArgAttributeExt for ArgAttribute {
36     fn for_each_kind<F>(&self, mut f: F)
37     where
38         F: FnMut(llvm::Attribute),
39     {
40         for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg)
41     }
42 }
43
44 pub trait ArgAttributesExt {
45     fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
46     fn apply_attrs_to_callsite(
47         &self,
48         idx: AttributePlace,
49         cx: &CodegenCx<'_, '_>,
50         callsite: &Value,
51     );
52 }
53
54 fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
55     // LLVM prior to version 12 has known miscompiles in the presence of
56     // noalias attributes (see #54878). Only enable mutable noalias by
57     // default for versions we believe to be safe.
58     cx.tcx
59         .sess
60         .opts
61         .debugging_opts
62         .mutable_noalias
63         .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0))
64 }
65
66 impl ArgAttributesExt for ArgAttributes {
67     fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value) {
68         let mut regular = self.regular;
69         unsafe {
70             let deref = self.pointee_size.bytes();
71             if deref != 0 {
72                 if regular.contains(ArgAttribute::NonNull) {
73                     llvm::LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), deref);
74                 } else {
75                     llvm::LLVMRustAddDereferenceableOrNullAttr(llfn, idx.as_uint(), deref);
76                 }
77                 regular -= ArgAttribute::NonNull;
78             }
79             if let Some(align) = self.pointee_align {
80                 llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
81             }
82             regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
83             if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
84                 llvm::Attribute::NoAlias.apply_llfn(idx, llfn);
85             }
86             match self.arg_ext {
87                 ArgExtension::None => {}
88                 ArgExtension::Zext => {
89                     llvm::Attribute::ZExt.apply_llfn(idx, llfn);
90                 }
91                 ArgExtension::Sext => {
92                     llvm::Attribute::SExt.apply_llfn(idx, llfn);
93                 }
94             }
95         }
96     }
97
98     fn apply_attrs_to_callsite(
99         &self,
100         idx: AttributePlace,
101         cx: &CodegenCx<'_, '_>,
102         callsite: &Value,
103     ) {
104         let mut regular = self.regular;
105         unsafe {
106             let deref = self.pointee_size.bytes();
107             if deref != 0 {
108                 if regular.contains(ArgAttribute::NonNull) {
109                     llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, idx.as_uint(), deref);
110                 } else {
111                     llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr(
112                         callsite,
113                         idx.as_uint(),
114                         deref,
115                     );
116                 }
117                 regular -= ArgAttribute::NonNull;
118             }
119             if let Some(align) = self.pointee_align {
120                 llvm::LLVMRustAddAlignmentCallSiteAttr(
121                     callsite,
122                     idx.as_uint(),
123                     align.bytes() as u32,
124                 );
125             }
126             regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
127             if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
128                 llvm::Attribute::NoAlias.apply_callsite(idx, callsite);
129             }
130             match self.arg_ext {
131                 ArgExtension::None => {}
132                 ArgExtension::Zext => {
133                     llvm::Attribute::ZExt.apply_callsite(idx, callsite);
134                 }
135                 ArgExtension::Sext => {
136                     llvm::Attribute::SExt.apply_callsite(idx, callsite);
137                 }
138             }
139         }
140     }
141 }
142
143 pub trait LlvmType {
144     fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type;
145 }
146
147 impl LlvmType for Reg {
148     fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
149         match self.kind {
150             RegKind::Integer => cx.type_ix(self.size.bits()),
151             RegKind::Float => match self.size.bits() {
152                 32 => cx.type_f32(),
153                 64 => cx.type_f64(),
154                 _ => bug!("unsupported float: {:?}", self),
155             },
156             RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
157         }
158     }
159 }
160
161 impl LlvmType for CastTarget {
162     fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
163         let rest_ll_unit = self.rest.unit.llvm_type(cx);
164         let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
165             (0, 0)
166         } else {
167             (
168                 self.rest.total.bytes() / self.rest.unit.size.bytes(),
169                 self.rest.total.bytes() % self.rest.unit.size.bytes(),
170             )
171         };
172
173         if self.prefix.iter().all(|x| x.is_none()) {
174             // Simplify to a single unit when there is no prefix and size <= unit size
175             if self.rest.total <= self.rest.unit.size {
176                 return rest_ll_unit;
177             }
178
179             // Simplify to array when all chunks are the same size and type
180             if rem_bytes == 0 {
181                 return cx.type_array(rest_ll_unit, rest_count);
182             }
183         }
184
185         // Create list of fields in the main structure
186         let mut args: Vec<_> = self
187             .prefix
188             .iter()
189             .flat_map(|option_kind| {
190                 option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
191             })
192             .chain((0..rest_count).map(|_| rest_ll_unit))
193             .collect();
194
195         // Append final integer
196         if rem_bytes != 0 {
197             // Only integers can be really split further.
198             assert_eq!(self.rest.unit.kind, RegKind::Integer);
199             args.push(cx.type_ix(rem_bytes * 8));
200         }
201
202         cx.type_struct(&args, false)
203     }
204 }
205
206 pub trait ArgAbiExt<'ll, 'tcx> {
207     fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
208     fn store(
209         &self,
210         bx: &mut Builder<'_, 'll, 'tcx>,
211         val: &'ll Value,
212         dst: PlaceRef<'tcx, &'ll Value>,
213     );
214     fn store_fn_arg(
215         &self,
216         bx: &mut Builder<'_, 'll, 'tcx>,
217         idx: &mut usize,
218         dst: PlaceRef<'tcx, &'ll Value>,
219     );
220 }
221
222 impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
223     /// Gets the LLVM type for a place of the original Rust type of
224     /// this argument/return, i.e., the result of `type_of::type_of`.
225     fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
226         self.layout.llvm_type(cx)
227     }
228
229     /// Stores a direct/indirect value described by this ArgAbi into a
230     /// place for the original Rust type of this argument/return.
231     /// Can be used for both storing formal arguments into Rust variables
232     /// or results of call/invoke instructions into their destinations.
233     fn store(
234         &self,
235         bx: &mut Builder<'_, 'll, 'tcx>,
236         val: &'ll Value,
237         dst: PlaceRef<'tcx, &'ll Value>,
238     ) {
239         if self.is_ignore() {
240             return;
241         }
242         if self.is_sized_indirect() {
243             OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
244         } else if self.is_unsized_indirect() {
245             bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
246         } else if let PassMode::Cast(cast) = self.mode {
247             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
248             // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
249             let can_store_through_cast_ptr = false;
250             if can_store_through_cast_ptr {
251                 let cast_ptr_llty = bx.type_ptr_to(cast.llvm_type(bx));
252                 let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
253                 bx.store(val, cast_dst, self.layout.align.abi);
254             } else {
255                 // The actual return type is a struct, but the ABI
256                 // adaptation code has cast it into some scalar type.  The
257                 // code that follows is the only reliable way I have
258                 // found to do a transform like i64 -> {i32,i32}.
259                 // Basically we dump the data onto the stack then memcpy it.
260                 //
261                 // Other approaches I tried:
262                 // - Casting rust ret pointer to the foreign type and using Store
263                 //   is (a) unsafe if size of foreign type > size of rust type and
264                 //   (b) runs afoul of strict aliasing rules, yielding invalid
265                 //   assembly under -O (specifically, the store gets removed).
266                 // - Truncating foreign type to correct integral type and then
267                 //   bitcasting to the struct type yields invalid cast errors.
268
269                 // We instead thus allocate some scratch space...
270                 let scratch_size = cast.size(bx);
271                 let scratch_align = cast.align(bx);
272                 let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
273                 bx.lifetime_start(llscratch, scratch_size);
274
275                 // ... where we first store the value...
276                 bx.store(val, llscratch, scratch_align);
277
278                 // ... and then memcpy it to the intended destination.
279                 bx.memcpy(
280                     dst.llval,
281                     self.layout.align.abi,
282                     llscratch,
283                     scratch_align,
284                     bx.const_usize(self.layout.size.bytes()),
285                     MemFlags::empty(),
286                 );
287
288                 bx.lifetime_end(llscratch, scratch_size);
289             }
290         } else {
291             OperandValue::Immediate(val).store(bx, dst);
292         }
293     }
294
295     fn store_fn_arg(
296         &self,
297         bx: &mut Builder<'a, 'll, 'tcx>,
298         idx: &mut usize,
299         dst: PlaceRef<'tcx, &'ll Value>,
300     ) {
301         let mut next = || {
302             let val = llvm::get_param(bx.llfn(), *idx as c_uint);
303             *idx += 1;
304             val
305         };
306         match self.mode {
307             PassMode::Ignore => {}
308             PassMode::Pair(..) => {
309                 OperandValue::Pair(next(), next()).store(bx, dst);
310             }
311             PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
312                 OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
313             }
314             PassMode::Direct(_)
315             | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
316             | PassMode::Cast(_) => {
317                 let next_arg = next();
318                 self.store(bx, next_arg, dst);
319             }
320         }
321     }
322 }
323
324 impl ArgAbiMethods<'tcx> for Builder<'a, 'll, 'tcx> {
325     fn store_fn_arg(
326         &mut self,
327         arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
328         idx: &mut usize,
329         dst: PlaceRef<'tcx, Self::Value>,
330     ) {
331         arg_abi.store_fn_arg(self, idx, dst)
332     }
333     fn store_arg(
334         &mut self,
335         arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
336         val: &'ll Value,
337         dst: PlaceRef<'tcx, &'ll Value>,
338     ) {
339         arg_abi.store(self, val, dst)
340     }
341     fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
342         arg_abi.memory_ty(self)
343     }
344 }
345
346 pub trait FnAbiLlvmExt<'tcx> {
347     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
348     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
349     fn llvm_cconv(&self) -> llvm::CallConv;
350     fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
351     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
352 }
353
354 impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
355     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
356         let args_capacity: usize = self.args.iter().map(|arg|
357             if arg.pad.is_some() { 1 } else { 0 } +
358             if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
359         ).sum();
360         let mut llargument_tys = Vec::with_capacity(
361             if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + args_capacity,
362         );
363
364         let llreturn_ty = match self.ret.mode {
365             PassMode::Ignore => cx.type_void(),
366             PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
367             PassMode::Cast(cast) => cast.llvm_type(cx),
368             PassMode::Indirect { .. } => {
369                 llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
370                 cx.type_void()
371             }
372         };
373
374         for arg in &self.args {
375             // add padding
376             if let Some(ty) = arg.pad {
377                 llargument_tys.push(ty.llvm_type(cx));
378             }
379
380             let llarg_ty = match arg.mode {
381                 PassMode::Ignore => continue,
382                 PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
383                 PassMode::Pair(..) => {
384                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
385                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
386                     continue;
387                 }
388                 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
389                     let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty);
390                     let ptr_layout = cx.layout_of(ptr_ty);
391                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
392                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
393                     continue;
394                 }
395                 PassMode::Cast(cast) => cast.llvm_type(cx),
396                 PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
397                     cx.type_ptr_to(arg.memory_ty(cx))
398                 }
399             };
400             llargument_tys.push(llarg_ty);
401         }
402
403         if self.c_variadic {
404             cx.type_variadic_func(&llargument_tys, llreturn_ty)
405         } else {
406             cx.type_func(&llargument_tys, llreturn_ty)
407         }
408     }
409
410     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
411         unsafe {
412             llvm::LLVMPointerType(
413                 self.llvm_type(cx),
414                 cx.data_layout().instruction_address_space.0 as c_uint,
415             )
416         }
417     }
418
419     fn llvm_cconv(&self) -> llvm::CallConv {
420         match self.conv {
421             Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
422             Conv::AmdGpuKernel => llvm::AmdGpuKernel,
423             Conv::AvrInterrupt => llvm::AvrInterrupt,
424             Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
425             Conv::ArmAapcs => llvm::ArmAapcsCallConv,
426             Conv::Msp430Intr => llvm::Msp430Intr,
427             Conv::PtxKernel => llvm::PtxKernel,
428             Conv::X86Fastcall => llvm::X86FastcallCallConv,
429             Conv::X86Intr => llvm::X86_Intr,
430             Conv::X86Stdcall => llvm::X86StdcallCallConv,
431             Conv::X86ThisCall => llvm::X86_ThisCall,
432             Conv::X86VectorCall => llvm::X86_VectorCall,
433             Conv::X86_64SysV => llvm::X86_64_SysV,
434             Conv::X86_64Win64 => llvm::X86_64_Win64,
435         }
436     }
437
438     fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
439         // FIXME(eddyb) can this also be applied to callsites?
440         if self.ret.layout.abi.is_uninhabited() {
441             llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
442         }
443
444         // FIXME(eddyb, wesleywiser): apply this to callsites as well?
445         if !self.can_unwind {
446             llvm::Attribute::NoUnwind.apply_llfn(llvm::AttributePlace::Function, llfn);
447         }
448
449         let mut i = 0;
450         let mut apply = |attrs: &ArgAttributes| {
451             attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), cx, llfn);
452             i += 1;
453             i - 1
454         };
455         match self.ret.mode {
456             PassMode::Direct(ref attrs) => {
457                 attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
458             }
459             PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
460                 assert!(!on_stack);
461                 let i = apply(attrs);
462                 unsafe {
463                     llvm::LLVMRustAddStructRetAttr(
464                         llfn,
465                         llvm::AttributePlace::Argument(i).as_uint(),
466                         self.ret.layout.llvm_type(cx),
467                     );
468                 }
469             }
470             _ => {}
471         }
472         for arg in &self.args {
473             if arg.pad.is_some() {
474                 apply(&ArgAttributes::new());
475             }
476             match arg.mode {
477                 PassMode::Ignore => {}
478                 PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
479                     let i = apply(attrs);
480                     unsafe {
481                         llvm::LLVMRustAddByValAttr(
482                             llfn,
483                             llvm::AttributePlace::Argument(i).as_uint(),
484                             arg.layout.llvm_type(cx),
485                         );
486                     }
487                 }
488                 PassMode::Direct(ref attrs)
489                 | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
490                     apply(attrs);
491                 }
492                 PassMode::Indirect { ref attrs, extra_attrs: Some(ref extra_attrs), on_stack } => {
493                     assert!(!on_stack);
494                     apply(attrs);
495                     apply(extra_attrs);
496                 }
497                 PassMode::Pair(ref a, ref b) => {
498                     apply(a);
499                     apply(b);
500                 }
501                 PassMode::Cast(_) => {
502                     apply(&ArgAttributes::new());
503                 }
504             }
505         }
506     }
507
508     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
509         // FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
510
511         let mut i = 0;
512         let mut apply = |cx: &CodegenCx<'_, '_>, attrs: &ArgAttributes| {
513             attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), cx, callsite);
514             i += 1;
515             i - 1
516         };
517         match self.ret.mode {
518             PassMode::Direct(ref attrs) => {
519                 attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, &bx.cx, callsite);
520             }
521             PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
522                 assert!(!on_stack);
523                 let i = apply(bx.cx, attrs);
524                 unsafe {
525                     llvm::LLVMRustAddStructRetCallSiteAttr(
526                         callsite,
527                         llvm::AttributePlace::Argument(i).as_uint(),
528                         self.ret.layout.llvm_type(bx),
529                     );
530                 }
531             }
532             _ => {}
533         }
534         if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi {
535             // If the value is a boolean, the range is 0..2 and that ultimately
536             // become 0..0 when the type becomes i1, which would be rejected
537             // by the LLVM verifier.
538             if let Int(..) = scalar.value {
539                 if !scalar.is_bool() {
540                     let range = scalar.valid_range_exclusive(bx);
541                     if range.start != range.end {
542                         bx.range_metadata(callsite, range);
543                     }
544                 }
545             }
546         }
547         for arg in &self.args {
548             if arg.pad.is_some() {
549                 apply(bx.cx, &ArgAttributes::new());
550             }
551             match arg.mode {
552                 PassMode::Ignore => {}
553                 PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
554                     let i = apply(bx.cx, attrs);
555                     unsafe {
556                         llvm::LLVMRustAddByValCallSiteAttr(
557                             callsite,
558                             llvm::AttributePlace::Argument(i).as_uint(),
559                             arg.layout.llvm_type(bx),
560                         );
561                     }
562                 }
563                 PassMode::Direct(ref attrs)
564                 | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
565                     apply(bx.cx, attrs);
566                 }
567                 PassMode::Indirect {
568                     ref attrs,
569                     extra_attrs: Some(ref extra_attrs),
570                     on_stack: _,
571                 } => {
572                     apply(bx.cx, attrs);
573                     apply(bx.cx, extra_attrs);
574                 }
575                 PassMode::Pair(ref a, ref b) => {
576                     apply(bx.cx, a);
577                     apply(bx.cx, b);
578                 }
579                 PassMode::Cast(_) => {
580                     apply(bx.cx, &ArgAttributes::new());
581                 }
582             }
583         }
584
585         let cconv = self.llvm_cconv();
586         if cconv != llvm::CCallConv {
587             llvm::SetInstructionCallConv(callsite, cconv);
588         }
589
590         if self.conv == Conv::CCmseNonSecureCall {
591             // This will probably get ignored on all targets but those supporting the TrustZone-M
592             // extension (thumbv8m targets).
593             unsafe {
594                 llvm::AddCallSiteAttrString(
595                     callsite,
596                     llvm::AttributePlace::Function,
597                     cstr::cstr!("cmse_nonsecure_call"),
598                 );
599             }
600         }
601     }
602 }
603
604 impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
605     fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value) {
606         fn_abi.apply_attrs_callsite(self, callsite)
607     }
608
609     fn get_param(&self, index: usize) -> Self::Value {
610         llvm::get_param(self.llfn(), index as c_uint)
611     }
612 }