Skip to main content

rustc_codegen_llvm/
abi.rs

1use std::cmp;
2
3use libc::c_uint;
4use rustc_abi::{
5    ArmCall, BackendRepr, CanonAbi, Float, HasDataLayout, Integer, InterruptKind, Primitive, Reg,
6    RegKind, Size, X86Call,
7};
8use rustc_codegen_ssa::MemFlags;
9use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
10use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
11use rustc_codegen_ssa::traits::*;
12use rustc_middle::ty;
13use rustc_middle::ty::Ty;
14use rustc_middle::ty::layout::LayoutOf;
15use rustc_session::{Session, config};
16use rustc_span::bug;
17use rustc_target::callconv::{
18    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, IndirectMode, PassMode,
19};
20use rustc_target::spec::{Arch, SanitizerSet};
21use smallvec::SmallVec;
22
23use crate::attributes::{self, llfn_attrs_from_instance};
24use crate::builder::Builder;
25use crate::context::CodegenCx;
26use crate::llvm::{self, Attribute, AttributePlace, Type, Value};
27use crate::type_of::LayoutLlvmExt;
28
29trait ArgAttributesExt {
30    fn apply_attrs_to_llfn<'ll>(
31        &self,
32        idx: AttributePlace,
33        cx: &CodegenCx<'ll, '_>,
34        llfn: Value<'ll>,
35    );
36    fn apply_attrs_to_callsite<'ll>(
37        &self,
38        idx: AttributePlace,
39        cx: &CodegenCx<'ll, '_>,
40        callsite: Value<'ll>,
41    );
42}
43
44const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
45    [(ArgAttribute::InReg, llvm::AttributeKind::InReg)];
46
47const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 6] = [
48    (ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias),
49    (ArgAttribute::NonNull, llvm::AttributeKind::NonNull),
50    (ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly),
51    (ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
52    (ArgAttribute::Writable, llvm::AttributeKind::Writable),
53    // Our internal NoFree attribute still allows deallocation of zero-size allocations. However,
54    // these don't render any bytes non-dereferenceable, so it's still fine to apply LLVM NoFree
55    // for them.
56    (ArgAttribute::NoFree, llvm::AttributeKind::NoFree),
57];
58
59const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [
60    (ArgAttribute::CapturesNone, llvm::AttributeKind::CapturesNone),
61    (ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress),
62    (ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly),
63];
64
65fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 8]> {
66    let mut regular = this.regular;
67
68    let mut attrs = SmallVec::new();
69
70    // ABI-affecting attributes must always be applied
71    for (attr, llattr) in ABI_AFFECTING_ATTRIBUTES {
72        if regular.contains(attr) {
73            attrs.push(llattr.create_attr(cx.llcx));
74        }
75    }
76    if let Some(align) = this.pointee_align {
77        attrs.push(llvm::CreateAlignmentAttr(cx.llcx, align.bytes()));
78    }
79    match this.arg_ext {
80        ArgExtension::None => {}
81        ArgExtension::Zext => attrs.push(llvm::AttributeKind::ZExt.create_attr(cx.llcx)),
82        ArgExtension::Sext => attrs.push(llvm::AttributeKind::SExt.create_attr(cx.llcx)),
83    }
84
85    // Only apply remaining attributes when optimizing
86    if cx.sess().opts.optimize != config::OptLevel::No {
87        let deref = this.pointee_size.bytes();
88        // Prior to <https://github.com/llvm/llvm-project/pull/204795> dereferenceable in LLVM
89        // implied nofree, so only emit dereferenceable on older versions of LLVM if nofree
90        // is also set.
91        let llvm_version = crate::llvm_util::get_version();
92        if deref != 0 && (llvm_version >= (23, 0, 0) || regular.contains(ArgAttribute::NoFree)) {
93            if regular.contains(ArgAttribute::NonNull) {
94                attrs.push(llvm::CreateDereferenceableAttr(cx.llcx, deref));
95            } else {
96                attrs.push(llvm::CreateDereferenceableOrNullAttr(cx.llcx, deref));
97            }
98            regular -= ArgAttribute::NonNull;
99        }
100        for (attr, llattr) in OPTIMIZATION_ATTRIBUTES {
101            if regular.contains(attr) {
102                attrs.push(llattr.create_attr(cx.llcx));
103            }
104        }
105        for (attr, llattr) in CAPTURES_ATTRIBUTES {
106            if regular.contains(attr) {
107                attrs.push(llattr.create_attr(cx.llcx));
108                break;
109            }
110        }
111    } else if cx.tcx.sess.sanitizers().contains(SanitizerSet::MEMORY) {
112        // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
113        // memory sanitizer's behavior.
114
115        if regular.contains(ArgAttribute::NoUndef) {
116            attrs.push(llvm::AttributeKind::NoUndef.create_attr(cx.llcx));
117        }
118    }
119
120    attrs
121}
122
123impl ArgAttributesExt for ArgAttributes {
124    fn apply_attrs_to_llfn<'ll>(
125        &self,
126        idx: AttributePlace,
127        cx: &CodegenCx<'ll, '_>,
128        llfn: Value<'ll>,
129    ) {
130        let attrs = get_attrs(self, cx);
131        attributes::apply_to_llfn(llfn, idx, &attrs);
132    }
133
134    fn apply_attrs_to_callsite<'ll>(
135        &self,
136        idx: AttributePlace,
137        cx: &CodegenCx<'ll, '_>,
138        callsite: Value<'ll>,
139    ) {
140        let attrs = get_attrs(self, cx);
141        attributes::apply_to_callsite(callsite, idx, &attrs);
142    }
143}
144
145pub(crate) trait LlvmType {
146    fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> Type<'ll>;
147}
148
149impl LlvmType for Reg {
150    fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> Type<'ll> {
151        match self.kind {
152            RegKind::Integer => cx.type_ix(self.size.bits()),
153            RegKind::Float => match self.size.bits() {
154                16 => cx.type_f16(),
155                32 => cx.type_f32(),
156                64 => cx.type_f64(),
157                80 => cx.type_x87_f80(),
158                128 => cx.type_f128(),
159                _ => ::rustc_span::macros::bug_impl(None,
    format_args!("unsupported float: {0:?}", self), Location::caller())bug!("unsupported float: {:?}", self),
160            },
161            RegKind::PpcF128 => cx.type_ppcf128(),
162            RegKind::Vector { hint_vector_elem } => {
163                // NOTE: it is valid to ignore the element type hint (and always pick i8).
164                // But providing a more accurate type means fewer casts in LLVM IR,
165                // which helps with optimization.
166                let ty = match hint_vector_elem {
167                    Primitive::Int(integer, _) => match integer {
168                        Integer::I8 => cx.type_ix(8),
169                        Integer::I16 => cx.type_ix(16),
170                        Integer::I32 => cx.type_ix(32),
171                        Integer::I64 => cx.type_ix(64),
172                        Integer::I128 => cx.type_ix(128),
173                    },
174                    Primitive::Float(float) => match float {
175                        Float::F16 => cx.type_f16(),
176                        Float::F16B => cx.type_f16b(),
177                        Float::F32 => cx.type_f32(),
178                        Float::F64 => cx.type_f64(),
179                        Float::F128 => cx.type_f128(),
180                        Float::PpcF128 => ::rustc_span::macros::bug_impl(None,
    format_args!("ppcf128 is not a valid vector element type"),
    Location::caller())bug!("ppcf128 is not a valid vector element type"),
181                        Float::X87F80 => ::rustc_span::macros::bug_impl(None,
    format_args!("x87_f80 is not a valid vector element type"),
    Location::caller())bug!("x87_f80 is not a valid vector element type"),
182                    },
183                    Primitive::Pointer(_) => cx.type_ptr(),
184                };
185
186                if !self.size.bytes().is_multiple_of(hint_vector_elem.size(cx).bytes()) {
    ::core::panicking::panic("assertion failed: self.size.bytes().is_multiple_of(hint_vector_elem.size(cx).bytes())")
};assert!(self.size.bytes().is_multiple_of(hint_vector_elem.size(cx).bytes()));
187                let len = self.size.bytes() / hint_vector_elem.size(cx).bytes();
188                cx.type_vector(ty, len)
189            }
190        }
191    }
192}
193
194impl LlvmType for CastTarget {
195    fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> Type<'ll> {
196        let rest_ll_unit = self.rest.unit.llvm_type(cx);
197        let rest_count = if self.rest.total == Size::ZERO {
198            0
199        } else {
200            {
    match (&(self.rest.unit.size), &(Size::ZERO)) {
        (left_val, right_val) => {
            if *left_val == *right_val {
                let kind = ::core::panicking::AssertKind::Ne;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val,
                    ::core::option::Option::Some(format_args!("total size {0:?} cannot be divided into units of zero size",
                            self.rest.total)));
            }
        }
    }
};assert_ne!(
201                self.rest.unit.size,
202                Size::ZERO,
203                "total size {:?} cannot be divided into units of zero size",
204                self.rest.total
205            );
206            if !self.rest.total.bytes().is_multiple_of(self.rest.unit.size.bytes()) {
207                {
    match (&self.rest.unit.kind, &RegKind::Integer) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val,
                    ::core::option::Option::Some(format_args!("only int regs can be split")));
            }
        }
    }
};assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split");
208            }
209            self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes())
210        };
211
212        // Simplify to an array if there is no prefix.
213        if self.prefix.is_empty() {
214            // Pass `[1 x unit]` as just `unit`.
215            //
216            // On little-endian targets this produces a compatible layout, but using a simpler type.
217            // But on big-endian targets (e.g. aarch64_be or powerpc64) the value may be passed in
218            // different halves of the register-sized slot, so unit and [1 x unit] are incompatible.
219            //
220            // Setting `is_consecutive` forces use of an array.
221            if rest_count == 1 && !self.rest.is_consecutive {
222                return rest_ll_unit;
223            }
224
225            // The x87_f80 type has a store size of 10 bytes, but an allocation size of 12 or 16
226            // bytes. Ensure we don't cast to it, because that could have unintened behavior.
227            if !(rest_ll_unit != cx.type_x87_f80()) {
    ::core::panicking::panic("assertion failed: rest_ll_unit != cx.type_x87_f80()")
};assert!(rest_ll_unit != cx.type_x87_f80());
228
229            return cx.type_array(rest_ll_unit, rest_count);
230        }
231
232        // Generate a struct type with the prefix and the "rest" arguments.
233        let prefix_args = self.prefix.iter().map(|reg| reg.llvm_type(cx));
234        let rest_args = (0..rest_count).map(|_| rest_ll_unit);
235        let args: Vec<_> = prefix_args.chain(rest_args).collect();
236
237        // The x87_f80 type has a store size of 10 bytes, but an allocation size of 12 or 16 bytes.
238        // Ensure we don't cast to it, because that could have unintened behavior.
239        if !args.iter().all(|a| *a != cx.type_x87_f80()) {
    ::core::panicking::panic("assertion failed: args.iter().all(|a| *a != cx.type_x87_f80())")
};assert!(args.iter().all(|a| *a != cx.type_x87_f80()));
240
241        cx.type_struct(&args)
242    }
243}
244
245trait ArgAbiExt<'ll, 'tcx> {
246    fn store(
247        &self,
248        bx: &mut Builder<'_, 'll, 'tcx>,
249        val: Value<'ll>,
250        dst: PlaceRef<'tcx, Value<'ll>>,
251    );
252    fn store_fn_arg(
253        &self,
254        bx: &mut Builder<'_, 'll, 'tcx>,
255        idx: &mut usize,
256        dst: PlaceRef<'tcx, Value<'ll>>,
257    );
258}
259
260impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
261    /// Stores a direct/indirect value described by this ArgAbi into a
262    /// place for the original Rust type of this argument/return.
263    /// Can be used for both storing formal arguments into Rust variables
264    /// or results of call/invoke instructions into their destinations.
265    fn store(
266        &self,
267        bx: &mut Builder<'_, 'll, 'tcx>,
268        val: Value<'ll>,
269        dst: PlaceRef<'tcx, Value<'ll>>,
270    ) {
271        match &self.mode {
272            PassMode::Ignore => {}
273            // Sized indirect arguments
274            PassMode::Indirect { attrs, address_space: _, mode: _ } => {
275                let align = attrs.pointee_align.unwrap_or(self.layout.align);
276                OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst);
277            }
278            // Unsized indirect arguments cannot be stored
279            PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => {
280                ::rustc_span::macros::bug_impl(None,
    format_args!("unsized `ArgAbi` cannot be stored"), Location::caller());bug!("unsized `ArgAbi` cannot be stored");
281            }
282            PassMode::Cast { cast, pad_i32_count: _ } => {
283                // The ABI mandates that the value is passed as a different struct representation.
284                // Spill and reload it from the stack to convert from the ABI representation to
285                // the Rust representation.
286                let scratch_size = cast.size(bx);
287                let scratch_align = cast.align(bx);
288                // Note that the ABI type may be either larger or smaller than the Rust type,
289                // due to the presence or absence of trailing padding. For example:
290                // - On some ABIs, the Rust layout { f64, f32, <f32 padding> } may omit padding
291                //   when passed by value, making it smaller.
292                // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
293                //   when passed by value, making it larger.
294                let copy_bytes =
295                    cmp::min(cast.unaligned_size(bx).bytes(), self.layout.size.bytes());
296                // Allocate some scratch space...
297                let llscratch = bx.alloca(scratch_size, scratch_align);
298                bx.lifetime_start(llscratch, scratch_size);
299                // ...store the value...
300                rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
301                // ... and then memcpy it to the intended destination.
302                bx.memcpy(
303                    dst.val.llval,
304                    self.layout.align,
305                    llscratch,
306                    scratch_align,
307                    bx.const_usize(copy_bytes),
308                    MemFlags::empty(),
309                    None,
310                );
311                bx.lifetime_end(llscratch, scratch_size);
312            }
313            PassMode::Pair(..) | PassMode::Direct { .. } => {
314                OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
315            }
316        }
317    }
318
319    fn store_fn_arg(
320        &self,
321        bx: &mut Builder<'_, 'll, 'tcx>,
322        idx: &mut usize,
323        dst: PlaceRef<'tcx, Value<'ll>>,
324    ) {
325        let mut next = || {
326            let val = llvm::get_param(bx.llfn(), *idx as c_uint);
327            *idx += 1;
328            val
329        };
330        match self.mode {
331            PassMode::Ignore => {}
332            PassMode::Pair(..) => {
333                OperandValue::Pair(next(), next()).store(bx, dst);
334            }
335            PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => {
336                ::rustc_span::macros::bug_impl(None,
    format_args!("unsized `ArgAbi` cannot be stored"), Location::caller());bug!("unsized `ArgAbi` cannot be stored");
337            }
338            PassMode::Direct(_)
339            | PassMode::Indirect { attrs: _, address_space: _, mode: _ }
340            | PassMode::Cast { .. } => {
341                let next_arg = next();
342                self.store(bx, next_arg, dst);
343            }
344        }
345    }
346}
347
348impl<'ll, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
349    fn store_fn_arg(
350        &mut self,
351        arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
352        idx: &mut usize,
353        dst: PlaceRef<'tcx, Self::Value>,
354    ) {
355        arg_abi.store_fn_arg(self, idx, dst)
356    }
357    fn store_arg(
358        &mut self,
359        arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
360        val: Value<'ll>,
361        dst: PlaceRef<'tcx, Value<'ll>>,
362    ) {
363        arg_abi.store(self, val, dst)
364    }
365}
366
367pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> {
368    fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> Type<'ll>;
369    fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> Type<'ll>;
370    fn llvm_cconv(&self, cx: &CodegenCx<'ll, 'tcx>) -> llvm::CallConv;
371
372    /// Apply attributes to a function declaration/definition.
373    fn apply_attrs_llfn(
374        &self,
375        cx: &CodegenCx<'ll, 'tcx>,
376        llfn: Value<'ll>,
377        instance: Option<ty::Instance<'tcx>>,
378    );
379
380    /// Apply attributes to a function call.
381    fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: Value<'ll>);
382}
383
384impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
385    fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> Type<'ll> {
386        // Ignore "extra" args from the call site for C variadic functions.
387        // Only the "fixed" args are part of the LLVM function signature.
388        let args =
389            if self.c_variadic { &self.args[..self.fixed_count as usize] } else { &self.args };
390
391        // This capacity calculation is approximate.
392        let mut llargument_tys = Vec::with_capacity(
393            self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 },
394        );
395
396        let llreturn_ty = match &self.ret.mode {
397            PassMode::Ignore => cx.type_void(),
398            PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
399            PassMode::Cast { cast, pad_i32_count: _ } => cast.llvm_type(cx),
400            PassMode::Indirect { address_space, .. } => {
401                let ty = if let Some(address_space) = address_space {
402                    cx.type_ptr_ext(*address_space)
403                } else {
404                    cx.type_ptr()
405                };
406                llargument_tys.push(ty);
407                cx.type_void()
408            }
409            PassMode::IndirectUnsized { .. } => ::rustc_span::macros::bug_impl(None,
    format_args!("unsized returns are not supported"), Location::caller())bug!("unsized returns are not supported"),
410        };
411
412        for arg in args {
413            // Note that the exact number of arguments pushed here is carefully synchronized with
414            // code all over the place, both in the codegen_llvm and codegen_ssa crates. That's how
415            // other code then knows which LLVM argument(s) correspond to the n-th Rust argument.
416            let llarg_ty = match &arg.mode {
417                PassMode::Ignore => continue,
418                PassMode::Direct(_) => {
419                    // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
420                    // and for Scalar ABIs the LLVM type is fully determined by `layout.abi`,
421                    // guaranteeing that we generate ABI-compatible LLVM IR.
422                    arg.layout.immediate_llvm_type(cx)
423                }
424                PassMode::Pair(..) => {
425                    // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
426                    // so for ScalarPair we can easily be sure that we are generating ABI-compatible
427                    // LLVM IR.
428                    llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
429                    llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
430                    continue;
431                }
432                PassMode::IndirectUnsized { attrs: _, meta_attrs: _ } => {
433                    // Construct the type of a (wide) pointer to `ty`, and pass its two fields.
434                    // Any two ABI-compatible unsized types have the same metadata type and
435                    // moreover the same metadata value leads to the same dynamic size and
436                    // alignment, so this respects ABI compatibility.
437                    let ptr_ty = Ty::new_mut_ptr(cx.tcx, arg.layout.ty);
438                    let ptr_layout = cx.layout_of(ptr_ty);
439                    llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
440                    llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
441                    continue;
442                }
443                PassMode::Indirect { attrs: _, address_space, mode: _ } => {
444                    if let Some(address_space) = address_space {
445                        cx.type_ptr_ext(*address_space)
446                    } else {
447                        cx.type_ptr()
448                    }
449                }
450                PassMode::Cast { cast, pad_i32_count } => {
451                    // Add padding.
452                    llargument_tys.extend(std::iter::repeat_n(
453                        Reg::i32().llvm_type(cx),
454                        usize::from(*pad_i32_count),
455                    ));
456
457                    // Compute the LLVM type we use for this function from the cast type.
458                    // We assume here that ABI-compatible Rust types have the same cast type.
459                    cast.llvm_type(cx)
460                }
461            };
462            llargument_tys.push(llarg_ty);
463        }
464
465        if self.c_variadic {
466            cx.type_variadic_func(&llargument_tys, llreturn_ty)
467        } else {
468            cx.type_func(&llargument_tys, llreturn_ty)
469        }
470    }
471
472    fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> Type<'ll> {
473        cx.type_ptr_ext(cx.data_layout().instruction_address_space)
474    }
475
476    fn llvm_cconv(&self, cx: &CodegenCx<'ll, 'tcx>) -> llvm::CallConv {
477        to_llvm_calling_convention(cx.tcx.sess, self.conv)
478    }
479
480    fn apply_attrs_llfn(
481        &self,
482        cx: &CodegenCx<'ll, 'tcx>,
483        llfn: Value<'ll>,
484        instance: Option<ty::Instance<'tcx>>,
485    ) {
486        let mut func_attrs = SmallVec::<[_; 3]>::new();
487        if self.ret.layout.is_uninhabited() {
488            func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
489        }
490        if !self.can_unwind {
491            func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx));
492        }
493        match self.conv {
494            CanonAbi::Interrupt(InterruptKind::RiscvMachine) => {
495                func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "machine"))
496            }
497            CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) => {
498                func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "supervisor"))
499            }
500            CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) => {
501                func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"))
502            }
503            _ => (),
504        }
505        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs });
506
507        let mut i = 0;
508        let mut apply = |attrs: &ArgAttributes| {
509            attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), cx, llfn);
510            i += 1;
511            i - 1
512        };
513
514        let apply_range_attr = |idx: AttributePlace, scalar: rustc_abi::Scalar| {
515            if cx.sess().opts.optimize != config::OptLevel::No
516                && #[allow(non_exhaustive_omitted_patterns)] match scalar.primitive() {
    Primitive::Int(..) => true,
    _ => false,
}matches!(scalar.primitive(), Primitive::Int(..))
517                // If the value is a boolean, the range is 0..2 and that ultimately
518                // become 0..0 when the type becomes i1, which would be rejected
519                // by the LLVM verifier.
520                && !scalar.is_bool()
521                // LLVM also rejects full range.
522                && !scalar.is_always_valid(cx)
523            {
524                attributes::apply_to_llfn(
525                    llfn,
526                    idx,
527                    &[llvm::CreateRangeAttr(cx.llcx, scalar.size(cx), scalar.valid_range(cx))],
528                );
529            }
530        };
531
532        match &self.ret.mode {
533            PassMode::Direct(attrs) => {
534                attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
535                if let BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr {
536                    apply_range_attr(llvm::AttributePlace::ReturnValue, scalar);
537                }
538            }
539            PassMode::Indirect { attrs, address_space: _, mode } => {
540                if !(*mode == IndirectMode::Pointer) {
    ::core::panicking::panic("assertion failed: *mode == IndirectMode::Pointer")
};assert!(*mode == IndirectMode::Pointer);
541                let i = apply(attrs);
542                let sret = llvm::CreateStructRetAttr(
543                    cx.llcx,
544                    cx.type_array(cx.type_i8(), self.ret.layout.size.bytes()),
545                );
546                attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
547                if cx.sess().opts.optimize != config::OptLevel::No {
548                    attributes::apply_to_llfn(
549                        llfn,
550                        llvm::AttributePlace::Argument(i),
551                        &[
552                            llvm::AttributeKind::Writable.create_attr(cx.llcx),
553                            llvm::AttributeKind::DeadOnUnwind.create_attr(cx.llcx),
554                        ],
555                    );
556                }
557            }
558            PassMode::IndirectUnsized { .. } => ::rustc_span::macros::bug_impl(None,
    format_args!("unsized returns are not supported"), Location::caller())bug!("unsized returns are not supported"),
559            PassMode::Cast { cast, pad_i32_count: _ } => {
560                cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
561            }
562            _ => {}
563        }
564        for arg in self.args.iter() {
565            match &arg.mode {
566                PassMode::Ignore => {}
567                PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::OnStack } => {
568                    let i = apply(attrs);
569                    let byval = llvm::CreateByValAttr(
570                        cx.llcx,
571                        cx.type_array(cx.type_i8(), arg.layout.size.bytes()),
572                    );
573                    attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
574                }
575                PassMode::Indirect {
576                    attrs,
577                    address_space: _,
578                    mode: IndirectMode::AmdgpuKernelArg,
579                } => {
580                    let i = apply(attrs);
581                    let byref = llvm::CreateByRefAttr(
582                        cx.llcx,
583                        cx.type_array(cx.type_i8(), arg.layout.size.bytes()),
584                    );
585                    attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byref]);
586                }
587                PassMode::Direct(attrs) => {
588                    let i = apply(attrs);
589                    if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
590                        apply_range_attr(llvm::AttributePlace::Argument(i), scalar);
591                    }
592                }
593                PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::Pointer } => {
594                    let i = apply(attrs);
595                    if cx.sess().opts.optimize != config::OptLevel::No {
596                        attributes::apply_to_llfn(
597                            llfn,
598                            llvm::AttributePlace::Argument(i),
599                            &[llvm::AttributeKind::DeadOnReturn.create_attr(cx.llcx)],
600                        );
601                    }
602                }
603                PassMode::IndirectUnsized { attrs, meta_attrs } => {
604                    apply(attrs);
605                    apply(meta_attrs);
606                }
607                PassMode::Pair(a, b) => {
608                    let i = apply(a);
609                    let ii = apply(b);
610                    if let BackendRepr::ScalarPair { a: scalar_a, b: scalar_b, b_offset: _ } =
611                        arg.layout.backend_repr
612                    {
613                        apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
614                        let primitive_b = scalar_b.primitive();
615                        let scalar_b = if let rustc_abi::Primitive::Int(int, false) = primitive_b
616                            && let ty::Ref(_, pointee_ty, _) = *arg.layout.ty.kind()
617                            && let ty::Slice(element_ty) = *pointee_ty.kind()
618                            && let elem_size = cx.layout_of(element_ty).size
619                            && elem_size != rustc_abi::Size::ZERO
620                        {
621                            // Ideally the layout calculations would have set the range,
622                            // but that's complicated due to cycles, so in the mean time
623                            // we calculate and apply it here.
624                            if true {
    if !scalar_b.is_always_valid(cx) {
        ::core::panicking::panic("assertion failed: scalar_b.is_always_valid(cx)")
    };
};debug_assert!(scalar_b.is_always_valid(cx));
625                            let isize_max = int.signed_max() as u64;
626                            rustc_abi::Scalar::Initialized {
627                                value: primitive_b,
628                                valid_range: rustc_abi::WrappingRange {
629                                    start: 0,
630                                    end: u128::from(isize_max / elem_size.bytes()),
631                                },
632                            }
633                        } else {
634                            scalar_b
635                        };
636                        apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b);
637                    }
638                }
639                PassMode::Cast { cast, pad_i32_count } => {
640                    for _ in 0..*pad_i32_count {
641                        apply(&ArgAttributes::new());
642                    }
643                    apply(&cast.attrs);
644                }
645            }
646        }
647
648        // If the declaration has an associated instance, compute extra attributes based on that.
649        if let Some(instance) = instance {
650            llfn_attrs_from_instance(
651                cx,
652                cx.tcx,
653                llfn,
654                &cx.tcx.codegen_instance_attrs(instance.def),
655                Some(instance),
656                cx.sanitizer_ignorelist.as_ref(),
657            );
658        }
659    }
660
661    fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: Value<'ll>) {
662        let mut func_attrs = SmallVec::<[_; 2]>::new();
663        if self.ret.layout.is_uninhabited() {
664            func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx));
665        }
666        if !self.can_unwind {
667            func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(bx.cx.llcx));
668        }
669        attributes::apply_to_callsite(callsite, llvm::AttributePlace::Function, &{ func_attrs });
670
671        let mut i = 0;
672        let mut apply = |cx: &CodegenCx<'ll, '_>, attrs: &ArgAttributes| {
673            attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), cx, callsite);
674            i += 1;
675            i - 1
676        };
677        match &self.ret.mode {
678            PassMode::Direct(attrs) => {
679                attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
680            }
681            PassMode::Indirect { attrs, address_space: _, mode } => {
682                if !(*mode == IndirectMode::Pointer) {
    ::core::panicking::panic("assertion failed: *mode == IndirectMode::Pointer")
};assert!(*mode == IndirectMode::Pointer);
683                let i = apply(bx.cx, attrs);
684                let sret = llvm::CreateStructRetAttr(
685                    bx.cx.llcx,
686                    bx.cx.type_array(bx.cx.type_i8(), self.ret.layout.size.bytes()),
687                );
688                attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
689            }
690            PassMode::IndirectUnsized { .. } => ::rustc_span::macros::bug_impl(None,
    format_args!("unsized returns are not supported"), Location::caller())bug!("unsized returns are not supported"),
691            PassMode::Cast { cast, pad_i32_count: _ } => {
692                cast.attrs.apply_attrs_to_callsite(
693                    llvm::AttributePlace::ReturnValue,
694                    bx.cx,
695                    callsite,
696                );
697            }
698            _ => {}
699        }
700        for arg in self.args.iter() {
701            match &arg.mode {
702                PassMode::Ignore => {}
703                PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::OnStack } => {
704                    let i = apply(bx.cx, attrs);
705                    let byval = llvm::CreateByValAttr(
706                        bx.cx.llcx,
707                        bx.cx.type_array(bx.cx.type_i8(), arg.layout.size.bytes()),
708                    );
709                    attributes::apply_to_callsite(
710                        callsite,
711                        llvm::AttributePlace::Argument(i),
712                        &[byval],
713                    );
714                }
715                PassMode::Indirect {
716                    attrs,
717                    address_space: _,
718                    mode: IndirectMode::AmdgpuKernelArg,
719                } => {
720                    let i = apply(bx.cx, attrs);
721                    let byref = llvm::CreateByRefAttr(
722                        bx.cx.llcx,
723                        bx.cx.type_array(bx.cx.type_i8(), arg.layout.size.bytes()),
724                    );
725                    attributes::apply_to_callsite(
726                        callsite,
727                        llvm::AttributePlace::Argument(i),
728                        &[byref],
729                    );
730                }
731                PassMode::Direct(attrs)
732                | PassMode::Indirect { attrs, address_space: _, mode: IndirectMode::Pointer } => {
733                    apply(bx.cx, attrs);
734                }
735                PassMode::IndirectUnsized { attrs, meta_attrs } => {
736                    apply(bx.cx, attrs);
737                    apply(bx.cx, meta_attrs);
738                }
739                PassMode::Pair(a, b) => {
740                    apply(bx.cx, a);
741                    apply(bx.cx, b);
742                }
743                PassMode::Cast { cast, pad_i32_count } => {
744                    for _ in 0..*pad_i32_count {
745                        apply(bx.cx, &ArgAttributes::new());
746                    }
747                    apply(bx.cx, &cast.attrs);
748                }
749            }
750        }
751
752        let cconv = self.llvm_cconv(bx.cx);
753        if cconv != llvm::CCallConv {
754            llvm::SetInstructionCallConv(callsite, cconv);
755        }
756
757        if self.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) {
758            // This will probably get ignored on all targets but those supporting the TrustZone-M
759            // extension (thumbv8m targets).
760            let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call");
761            attributes::apply_to_callsite(
762                callsite,
763                llvm::AttributePlace::Function,
764                &[cmse_nonsecure_call],
765            );
766        }
767
768        // Some intrinsics require that an elementtype attribute (with the pointee type of a
769        // pointer argument) is added to the callsite.
770        let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) };
771        if element_type_index >= 0 {
772            let arg_ty = self.args[element_type_index as usize].layout.ty;
773            let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument");
774            let element_type_attr = unsafe {
775                llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx))
776            };
777            attributes::apply_to_callsite(
778                callsite,
779                llvm::AttributePlace::Argument(element_type_index as u32),
780                &[element_type_attr],
781            );
782        }
783    }
784}
785
786impl AbiBuilderMethods for Builder<'_, '_, '_> {
787    fn get_param(&mut self, index: usize) -> Self::Value {
788        llvm::get_param(self.llfn(), index as c_uint)
789    }
790}
791
792/// Determines the appropriate [`llvm::CallConv`] to use for a given function
793/// ABI, for the current target.
794pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm::CallConv {
795    match abi {
796        CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
797        CanonAbi::RustCold => llvm::PreserveMost,
798        CanonAbi::RustPreserveNone => match &sess.target.arch {
799            Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone,
800            _ => llvm::CCallConv,
801        },
802        CanonAbi::RustTail => match &sess.target.arch {
803            Arch::X86 | Arch::X86_64 | Arch::AArch64 => llvm::Tail,
804            _ => sess.dcx().fatal("extern \"tail\" is only supported on x86, x86_64 and aarch64"),
805        },
806        // Functions with this calling convention can only be called from assembly, but it is
807        // possible to declare an `extern "custom"` block, so the backend still needs a calling
808        // convention for declaring foreign functions.
809        CanonAbi::Custom => llvm::CCallConv,
810        CanonAbi::Swift => llvm::SwiftCallConv,
811        CanonAbi::GpuKernel => match &sess.target.arch {
812            Arch::AmdGpu => llvm::AmdgpuKernel,
813            Arch::Nvptx64 => llvm::PtxKernel,
814            arch => {
    ::core::panicking::panic_fmt(format_args!("Architecture {0} does not support GpuKernel calling convention",
            arch));
}panic!("Architecture {arch} does not support GpuKernel calling convention"),
815        },
816        CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
817            InterruptKind::Avr => llvm::AvrInterrupt,
818            InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt,
819            InterruptKind::Msp430 => llvm::Msp430Intr,
820            InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv,
821            InterruptKind::X86 => llvm::X86_Intr,
822        },
823        CanonAbi::Arm(arm_call) => match arm_call {
824            ArmCall::Aapcs => llvm::ArmAapcsCallConv,
825            ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv,
826        },
827        CanonAbi::X86(x86_call) => match x86_call {
828            X86Call::Fastcall => llvm::X86FastcallCallConv,
829            X86Call::Stdcall => llvm::X86StdcallCallConv,
830            X86Call::SysV64 => llvm::X86_64_SysV,
831            X86Call::Thiscall => llvm::X86_ThisCall,
832            X86Call::Vectorcall => llvm::X86_VectorCall,
833            X86Call::Win64 => llvm::X86_64_Win64,
834        },
835    }
836}