diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index dea574a53cd7b..07637e6112803 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -1,10 +1,7 @@ -use std::cmp; - use libc::c_uint; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; use rustc_middle::ty::layout::LayoutOf; pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use rustc_middle::ty::Ty; @@ -215,35 +212,8 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } - PassMode::Cast { cast, pad_i32: _ } => { - // The ABI mandates that the value is passed as a different struct representation. - // Spill and reload it from the stack to convert from the ABI representation to - // the Rust representation. - let scratch_size = cast.size(bx); - let scratch_align = cast.align(bx); - // Note that the ABI type may be either larger or smaller than the Rust type, - // due to the presence or absence of trailing padding. For example: - // - On some ABIs, the Rust layout { f64, f32, } may omit padding - // when passed by value, making it smaller. - // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes - // when passed by value, making it larger. - let copy_bytes = - cmp::min(cast.unaligned_size(bx).bytes(), self.layout.size.bytes()); - // Allocate some scratch space... - let llscratch = bx.alloca(scratch_size, scratch_align); - bx.lifetime_start(llscratch, scratch_size); - // ...store the value... - bx.store(val, llscratch, scratch_align); - // ... and then memcpy it to the intended destination. - bx.memcpy( - dst.val.llval, - self.layout.align.abi, - llscratch, - scratch_align, - bx.const_usize(copy_bytes), - MemFlags::empty(), - ); - bx.lifetime_end(llscratch, scratch_size); + PassMode::Cast { cast, .. } => { + cast.cast_other_abi_to_rust(bx, val, dst.val.llval, self.layout); } _ => { OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 817e2ca72ec12..f424cb50807a6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -23,8 +23,8 @@ use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization}; use crate::common::{self, IntPredicate}; use crate::errors::CompilerBuiltinsCannotCall; +use crate::meth; use crate::traits::*; -use crate::{meth, MemFlags}; // Indicates if we are in the middle of merging a BB's successor into it. This // can happen when BB jumps directly to its successor and the successor has no @@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - PassMode::Cast { cast: cast_ty, pad_i32: _ } => { + PassMode::Cast { cast, pad_i32: _ } => { let op = match self.locals[mir::RETURN_PLACE] { LocalRef::Operand(op) => op, LocalRef::PendingOperand => bug!("use of return before def"), @@ -471,23 +471,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), }; - let llslot = match op.val { - Immediate(_) | Pair(..) => { - let scratch = PlaceRef::alloca(bx, self.fn_abi.ret.layout); - op.val.store(bx, scratch); - scratch.val.llval - } - Ref(place_val) => { - assert_eq!( - place_val.align, op.layout.align.abi, - "return place is unaligned!" - ); - place_val.llval - } - ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"), - }; - let ty = bx.cast_backend_type(cast_ty); - bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi) + cast.cast_rust_abi_to_other(bx, op) } }; bx.ret(llval); @@ -1460,10 +1444,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => {} } - // Force by-ref if we have to load through a cast pointer. - let (mut llval, align, by_ref) = match op.val { - Immediate(_) | Pair(..) => match arg.mode { - PassMode::Indirect { attrs, .. } => { + let llval = match arg.mode { + PassMode::Indirect { attrs, on_stack, .. } => match op.val { + Immediate(_) | Pair(..) => { // Indirect argument may have higher alignment requirements than the type's alignment. // This can happen, e.g. when passing types with <4 byte alignment on the stack on x86. let required_align = match attrs.pointee_align { @@ -1472,17 +1455,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align); op.val.store(bx, scratch.with_type(arg.layout)); - (scratch.llval, scratch.align, true) - } - PassMode::Cast { .. } => { - let scratch = PlaceRef::alloca(bx, arg.layout); - op.val.store(bx, scratch); - (scratch.val.llval, scratch.val.align, true) + scratch.llval } - _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false), - }, - Ref(op_place_val) => match arg.mode { - PassMode::Indirect { attrs, .. } => { + Ref(op_place_val) => { let required_align = match attrs.pointee_align { Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), None => arg.layout.align.abi, @@ -1493,15 +1468,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to a higher-aligned alloca. let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align); bx.typed_place_copy(scratch, op_place_val, op.layout); - (scratch.llval, scratch.align, true) + scratch.llval } else { - (op_place_val.llval, op_place_val.align, true) + op_place_val.llval } } - _ => (op_place_val.llval, op_place_val.align, true), - }, - ZeroSized => match arg.mode { - PassMode::Indirect { on_stack, .. } => { + ZeroSized => { if on_stack { // It doesn't seem like any target can have `byval` ZSTs, so this assert // is here to replace a would-be untested codepath. @@ -1511,59 +1483,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // a pointer for `repr(C)` structs even when empty, so get // one from an `alloca` (which can be left uninitialized). let scratch = PlaceRef::alloca(bx, arg.layout); - (scratch.val.llval, scratch.val.align, true) + scratch.val.llval } - _ => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"), }, - }; - - if by_ref && !arg.is_indirect() { - // Have to load the argument, maybe while casting it. - if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode { - // The ABI mandates that the value is passed as a different struct representation. - // Spill and reload it from the stack to convert from the Rust representation to - // the ABI representation. - let scratch_size = cast.size(bx); - let scratch_align = cast.align(bx); - // Note that the ABI type may be either larger or smaller than the Rust type, - // due to the presence or absence of trailing padding. For example: - // - On some ABIs, the Rust layout { f64, f32, } may omit padding - // when passed by value, making it smaller. - // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes - // when passed by value, making it larger. - let copy_bytes = cmp::min(cast.unaligned_size(bx).bytes(), arg.layout.size.bytes()); - // Allocate some scratch space... - let llscratch = bx.alloca(scratch_size, scratch_align); - bx.lifetime_start(llscratch, scratch_size); - // ...memcpy the value... - bx.memcpy( - llscratch, - scratch_align, - llval, - align, - bx.const_usize(copy_bytes), - MemFlags::empty(), - ); - // ...and then load it with the ABI type. - let cast_ty = bx.cast_backend_type(cast); - llval = bx.load(cast_ty, llscratch, scratch_align); - bx.lifetime_end(llscratch, scratch_size); - } else { - // We can't use `PlaceRef::load` here because the argument - // may have a type we don't treat as immediate, but the ABI - // used for this call is passing it by-value. In that case, - // the load would just produce `OperandValue::Ref` instead - // of the `OperandValue::Immediate` we need for the call. - llval = bx.load(bx.backend_type(arg.layout), llval, align); - if let abi::Abi::Scalar(scalar) = arg.layout.abi { - if scalar.is_bool() { + PassMode::Cast { ref cast, .. } => cast.cast_rust_abi_to_other(bx, op), + _ => match op.val { + Immediate(_) | Pair(..) => op.immediate_or_packed_pair(bx), + Ref(op_place_val) => { + // We can't use `PlaceRef::load` here because the argument + // may have a type we don't treat as immediate, but the ABI + // used for this call is passing it by-value. In that case, + // the load would just produce `OperandValue::Ref` instead + // of the `OperandValue::Immediate` we need for the call. + let mut llval = bx.load( + bx.backend_type(arg.layout), + op_place_val.llval, + op_place_val.align, + ); + if let abi::Abi::Scalar(scalar) = arg.layout.abi + && scalar.is_bool() + { bx.range_metadata(llval, WrappingRange { start: 0, end: 1 }); } + // We store bools as `i8` so we need to truncate to `i1`. + llval = bx.to_immediate(llval, arg.layout); + llval } - // We store bools as `i8` so we need to truncate to `i1`. - llval = bx.to_immediate(llval, arg.layout); - } - } + ZeroSized => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"), + }, + }; llargs.push(llval); } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index de94d87bcea7a..1f108ba9f0093 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -229,20 +229,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let layout = start_bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); - if local == mir::RETURN_PLACE { - match fx.fn_abi.ret.mode { - PassMode::Indirect { .. } => { - debug!("alloc: {:?} (return place) -> place", local); - let llretptr = start_bx.get_param(0); - return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); - } - PassMode::Cast { ref cast, .. } => { - debug!("alloc: {:?} (return place) -> place", local); - let size = cast.size(&start_bx); - return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout)); - } - _ => {} - }; + if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { + debug!("alloc: {:?} (return place) -> place", local); + let llretptr = start_bx.get_param(0); + return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); } if memory_locals.contains(local) { diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs index 60d8f2a9ece48..bffb7b38973da 100644 --- a/compiler/rustc_codegen_ssa/src/traits/abi.rs +++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs @@ -1,5 +1,170 @@ -use super::BackendTypes; +use rustc_middle::bug; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::abi::call::CastTarget; + +use super::consts::ConstMethods; +use super::type_::BaseTypeMethods; +use super::{BackendTypes, BuilderMethods, LayoutTypeMethods}; +use crate::mir::operand::{OperandRef, OperandValue}; +use crate::mir::place::PlaceRef; pub trait AbiBuilderMethods<'tcx>: BackendTypes { fn get_param(&mut self, index: usize) -> Self::Value; } + +/// The ABI mandates that the value is passed as a different struct representation. +pub trait CastTargetAbiExt<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { + /// Spill and reload it from the stack to convert from the Rust representation to the ABI representation. + fn cast_rust_abi_to_other(&self, bx: &mut Bx, op: OperandRef<'tcx, Bx::Value>) -> Bx::Value; + /// Spill and reload it from the stack to convert from the ABI representation to the Rust representation. + fn cast_other_abi_to_rust( + &self, + bx: &mut Bx, + src: Bx::Value, + dst: Bx::Value, + layout: TyAndLayout<'tcx>, + ); +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> CastTargetAbiExt<'a, 'tcx, Bx> for CastTarget { + fn cast_rust_abi_to_other(&self, bx: &mut Bx, op: OperandRef<'tcx, Bx::Value>) -> Bx::Value { + let scratch_size = self.unaligned_size(bx); + let (has_scratch, src, align) = match op.val { + // If the source already has enough space, we can cast from it directly. + OperandValue::Ref(place_val) if op.layout.size >= scratch_size => { + (false, place_val.llval, place_val.align) + } + OperandValue::Immediate(_) | OperandValue::Pair(..) | OperandValue::Ref(_) => { + // When `op.layout.size` is larger than `scratch_size`, the extra space is just padding. + let scratch = PlaceRef::alloca_size(bx, scratch_size, op.layout); + let llscratch = scratch.val.llval; + bx.lifetime_start(llscratch, scratch_size); + op.val.store(bx, scratch); + (true, llscratch, scratch.val.align) + } + OperandValue::ZeroSized => bug!("ZST value shouldn't be in PassMode::Cast"), + }; + let cast_ty = bx.cast_backend_type(self); + let ret = match bx.type_kind(cast_ty) { + crate::common::TypeKind::Struct | crate::common::TypeKind::Array => { + let mut index = 0; + let mut offset = 0; + let mut target = bx.const_poison(cast_ty); + for reg in self.prefix.iter().filter_map(|&x| x) { + let ptr = if offset == 0 { + src + } else { + bx.inbounds_ptradd(src, bx.const_usize(offset)) + }; + let load = bx.load(bx.reg_backend_type(®), ptr, align); + target = bx.insert_value(target, load, index); + index += 1; + offset += reg.size.bytes(); + } + let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { + (0, 0) + } else { + ( + self.rest.total.bytes() / self.rest.unit.size.bytes(), + self.rest.total.bytes() % self.rest.unit.size.bytes(), + ) + }; + for _ in 0..rest_count { + let ptr = if offset == 0 { + src + } else { + bx.inbounds_ptradd(src, bx.const_usize(offset)) + }; + let load = bx.load(bx.reg_backend_type(&self.rest.unit), ptr, align); + target = bx.insert_value(target, load, index); + index += 1; + offset += self.rest.unit.size.bytes(); + } + if rem_bytes != 0 { + let ptr = bx.inbounds_ptradd(src, bx.const_usize(offset)); + let load = bx.load(bx.reg_backend_type(&self.rest.unit), ptr, align); + target = bx.insert_value(target, load, index); + } + target + } + ty_kind if bx.type_kind(bx.reg_backend_type(&self.rest.unit)) == ty_kind => { + bx.load(cast_ty, src, align) + } + ty_kind => bug!("cannot cast {ty_kind:?} to the ABI representation in CastTarget"), + }; + if has_scratch { + bx.lifetime_end(src, scratch_size); + } + ret + } + + fn cast_other_abi_to_rust( + &self, + bx: &mut Bx, + src: Bx::Value, + dst: Bx::Value, + layout: TyAndLayout<'tcx>, + ) { + let scratch_size = self.unaligned_size(bx); + let scratch_align = self.align(bx); + let has_scratch = scratch_size > layout.size; + let (store_dst, align) = if has_scratch { + // We must allocate enough space for the final store instruction. + let llscratch = bx.alloca(scratch_size, scratch_align); + bx.lifetime_start(llscratch, scratch_size); + (llscratch, scratch_align) + } else { + (dst, layout.align.abi) + }; + match bx.type_kind(bx.val_ty(src)) { + crate::common::TypeKind::Struct | crate::common::TypeKind::Array => { + let mut index = 0; + let mut offset = 0; + for reg in self.prefix.iter().filter_map(|&x| x) { + let from = bx.extract_value(src, index); + let ptr = if index == 0 { + store_dst + } else { + bx.inbounds_ptradd(store_dst, bx.const_usize(offset)) + }; + bx.store(from, ptr, align); + index += 1; + offset += reg.size.bytes(); + } + let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { + (0, 0) + } else { + ( + self.rest.total.bytes() / self.rest.unit.size.bytes(), + self.rest.total.bytes() % self.rest.unit.size.bytes(), + ) + }; + for _ in 0..rest_count { + let from = bx.extract_value(src, index); + let ptr = if offset == 0 { + store_dst + } else { + bx.inbounds_ptradd(store_dst, bx.const_usize(offset)) + }; + bx.store(from, ptr, align); + index += 1; + offset += self.rest.unit.size.bytes(); + } + if rem_bytes != 0 { + let from = bx.extract_value(src, index); + let ptr = bx.inbounds_ptradd(store_dst, bx.const_usize(offset)); + bx.store(from, ptr, align); + } + } + ty_kind if bx.type_kind(bx.reg_backend_type(&self.rest.unit)) == ty_kind => { + bx.store(src, store_dst, align); + } + ty_kind => bug!("cannot cast {ty_kind:?} to the Rust representation in CastTarget"), + }; + if has_scratch { + let tmp = bx.load(bx.backend_type(layout), store_dst, scratch_align); + bx.lifetime_end(store_dst, scratch_size); + bx.store(tmp, dst, layout.align.abi); + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 9ac923bef880c..fd5c01879e02f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -33,7 +33,7 @@ use std::fmt; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt}; use rustc_target::spec::HasTargetSpec; -pub use self::abi::AbiBuilderMethods; +pub use self::abi::{AbiBuilderMethods, CastTargetAbiExt}; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs index 9a3540d8b4163..cada1d96e664f 100644 --- a/tests/assembly/powerpc64-struct-abi.rs +++ b/tests/assembly/powerpc64-struct-abi.rs @@ -1,6 +1,6 @@ //@ revisions: elfv1-be elfv2-be elfv2-le //@ assembly-output: emit-asm -//@ compile-flags: -O +//@ compile-flags: -O -Zlint-llvm-ir -Cllvm-args=-lint-abort-on-error //@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu //@[elfv1-be] needs-llvm-components: powerpc //@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs index fc272f2556cbf..77b5bfdd69fa3 100644 --- a/tests/codegen/array-codegen.rs +++ b/tests/codegen/array-codegen.rs @@ -5,26 +5,23 @@ // CHECK-LABEL: @array_load #[no_mangle] pub fn array_load(a: &[u8; 4]) -> [u8; 4] { - // CHECK-NOT: alloca - // CHECK: %[[ALLOCA:.+]] = alloca [4 x i8], align 1 - // CHECK-NOT: alloca - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[ALLOCA]], ptr align 1 %a, {{.+}} 4, i1 false) - // CHECK: %[[TEMP:.+]] = load i32, ptr %[[ALLOCA]], align 1 - // CHECK: ret i32 %[[TEMP]] + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: %[[ALLOCA:.+]] = alloca [4 x i8], align 1 + // CHECK-NEXT: call void @llvm.memcpy.{{.+}}(ptr align 1 %[[ALLOCA]], ptr align 1 %a, {{.+}} 4, i1 false) + // CHECK-NEXT: %[[TEMP:.+]] = load i32, ptr %[[ALLOCA]], align 1 + // CHECK-NEXT: ret i32 %[[TEMP]] *a } // CHECK-LABEL: @array_store #[no_mangle] pub fn array_store(a: [u8; 4], p: &mut [u8; 4]) { - // CHECK-NOT: alloca - // CHECK: %[[TEMP:.+]] = alloca [4 x i8], [[TEMPALIGN:align [0-9]+]] - // CHECK-NOT: alloca - // CHECK: %a = alloca [4 x i8] - // CHECK-NOT: alloca - // store i32 %0, ptr %[[TEMP]] - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %a, ptr [[TEMPALIGN]] %[[TEMP]], {{.+}} 4, i1 false) - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %p, ptr align 1 %a, {{.+}} 4, i1 false) + // CHECK-SAME: i32 [[TMP0:%.*]], ptr{{.*}} [[P:%.*]]) + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[A:%.*]] = alloca [4 x i8], align 1 + // CHECK-NEXT: store i32 [[TMP0]], ptr [[A]], align 1 + // CHECK-NEXT: call void @llvm.memcpy.{{.+}}(ptr align 1 [[P]], ptr align 1 [[A]], {{.+}} 4, i1 false) + // CHECK-NEXT: ret void *p = a; } diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index db76aae3dd005..b0592a868d579 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -81,17 +81,37 @@ pub struct Three32s { #[no_mangle] #[inline(never)] pub extern "C" fn receives_twou16s(x: TwoU16s) { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // CHECK-NEXT: [[START:.*:]] + + // aarch64-NEXT: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // loongarch64-NEXT: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // sparc64-NEXT: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + + // CHECK-NEXT: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + + // aarch64-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[ABI_ALLOCA]]) + // loongarch64-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[ABI_ALLOCA]]) + // sparc64-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[ABI_ALLOCA]]) + // + // aarch64-NEXT: store i64 [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align 8 + // loongarch64-NEXT: store i64 [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align 8 + // sparc64-NEXT: store i64 [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align 8 + // + // aarch64-NEXT: [[RUST_VALUE:%.+]] = load [[RUST_TYPE:%TwoU16s]], ptr [[ABI_ALLOCA]], align 8 + // loongarch64-NEXT: [[RUST_VALUE:%.+]] = load [[RUST_TYPE:%TwoU16s]], ptr [[ABI_ALLOCA]], align 8 + // sparc64-NEXT: [[RUST_VALUE:%.+]] = load [[RUST_TYPE:%TwoU16s]], ptr [[ABI_ALLOCA]], align 8 + // + // aarch64-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[ABI_ALLOCA]]) + // loongarch64-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[ABI_ALLOCA]]) + // sparc64-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[ABI_ALLOCA]]) + + // aarch64-NEXT: store [[RUST_TYPE]] [[RUST_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store [[RUST_TYPE]] [[RUST_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // powerpc64-NEXT: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // sparc64-NEXT: store [[RUST_TYPE]] [[RUST_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64-NEXT: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // CHECK-NEXT: ret void } // CHECK-LABEL: @returns_twou16s @@ -128,13 +148,14 @@ pub extern "C" fn returns_twou16s() -> TwoU16s { #[no_mangle] #[inline(never)] pub extern "C" fn receives_fiveu16s(x: FiveU16s) { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[RUST_ALLOCA:%.*]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + // CHECK-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // CHECK-NEXT: store i64 [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN:2]] + // CHECK-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // CHECK-NEXT: store {{i64|i16}} [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN:2]] + // CHECK-NEXT: ret void } // CHECK-LABEL: @returns_fiveu16s @@ -145,20 +166,40 @@ pub extern "C" fn returns_fiveu16s() -> FiveU16s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + + // aarch64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // sparc64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // sparc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ i64, i16 }]] poison, i64 [[TMP4]], 0 + // + // aarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // loongarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // sparc64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // x86_64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // + // aarch64-NEXT: [[TMP7:%.*]] = load {{i64|i16}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // loongarch64-NEXT: [[TMP7:%.*]] = load {{i64|i16}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // sparc64-NEXT: [[TMP7:%.*]] = load {{i64|i16}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // x86_64-NEXT: [[TMP7:%.*]] = load {{i64|i16}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // loongarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // sparc64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // x86_64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i16 [[TMP7]], 1 + // + // aarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] FiveU16s { a: 0, b: 1, c: 2, d: 3, e: 4 } } @@ -171,13 +212,14 @@ pub extern "C" fn returns_fiveu16s() -> FiveU16s { #[no_mangle] #[inline(never)] pub extern "C" fn receives_doubledouble(x: DoubleDouble) { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[RUST_ALLOCA:%.*]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // CHECK-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // CHECK-NEXT: store {{double|i64}} [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // CHECK-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 [[RUST_ALIGN]] + // CHECK-NEXT: store {{double|i64}} [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // CHECK-NEXT: ret void } // CHECK-LABEL: @returns_doubledouble @@ -188,20 +230,40 @@ pub extern "C" fn returns_doubledouble() -> DoubleDouble { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // aarch64: [[TMP4:%.*]] = load double, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64: [[TMP4:%.*]] = load double, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // sparc64: [[TMP4:%.*]] = load double, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: [[TMP4:%.*]] = load double, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x double\]]] poison, double [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + // sparc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + // + // aarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // loongarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // sparc64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // x86_64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // + // aarch64-NEXT: [[TMP7:%.*]] = load double, ptr [[TMP6]], align [[RUST_ALIGN]] + // loongarch64-NEXT: [[TMP7:%.*]] = load double, ptr [[TMP6]], align [[RUST_ALIGN]] + // sparc64-NEXT: [[TMP7:%.*]] = load double, ptr [[TMP6]], align [[RUST_ALIGN]] + // x86_64-NEXT: [[TMP7:%.*]] = load double, ptr [[TMP6]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], double [[TMP7]], 1 + // loongarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], double [[TMP7]], 1 + // sparc64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], double [[TMP7]], 1 + // x86_64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], double [[TMP7]], 1 + // + // aarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] DoubleDouble { f: 0., g: 1. } } @@ -214,13 +276,14 @@ pub extern "C" fn returns_doubledouble() -> DoubleDouble { #[no_mangle] #[inline(never)] pub extern "C" fn receives_three32s(x: Three32s) { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] - - // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[RUST_ALLOCA:%.*]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + // CHECK-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // CHECK-NEXT: store i64 [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // CHECK-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // CHECK-NEXT: store {{i64|i32}} [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // CHECK-NEXT: ret void } // CHECK-LABEL: @returns_three32s @@ -231,20 +294,40 @@ pub extern "C" fn returns_three32s() -> Three32s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + + // aarch64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // sparc64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // sparc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ i64, i32 }]] poison, i64 [[TMP4]], 0 + // + // aarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // loongarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // sparc64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // x86_64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // + // aarch64-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align [[RUST_ALIGN]] + // loongarch64-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align [[RUST_ALIGN]] + // sparc64-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align [[RUST_ALIGN]] + // x86_64-NEXT: [[TMP7:%.*]] = load i32, ptr [[TMP6]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // loongarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // sparc64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // x86_64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i32 [[TMP7]], 1 + // + // aarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] Three32s { a: 0, b: 0, c: 0 } } @@ -262,25 +345,45 @@ pub extern "C" fn returns_three32s() -> Three32s { #[no_mangle] #[inline(never)] pub extern "C" fn receives_doublefloat(x: DoubleFloat) { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // aarch64-NEXT: [[START:.*:]] + // loongarch64-NEXT: [[START:.*:]] + // powerpc64-NEXT: [[START:.*:]] + // x86_64-NEXT: [[START:.*:]] + + // aarch64-NEXT: [[RUST_ALLOCA:%.*]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64-NEXT: [[RUST_ALLOCA:%.*]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // powerpc64-NEXT: [[RUST_ALLOCA:%.*]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64-NEXT: [[RUST_ALLOCA:%.*]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // aarch64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // loongarch64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // powerpc64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // x86_64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + + // aarch64-NEXT: store i64 [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store double [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // powerpc64-NEXT: store i64 [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64-NEXT: store double [[TMP1]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // aarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // loongarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // powerpc64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // x86_64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + + // aarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // loongarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // powerpc64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // x86_64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + + // aarch64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store float [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // powerpc64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // x86_64-NEXT: store double [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + + // aarch64-NEXT: ret void + // loongarch64-NEXT: ret void + // powerpc64-NEXT: ret void + // x86_64-NEXT: ret void } #[cfg(not(target_arch = "sparc64"))] @@ -296,40 +399,53 @@ pub extern "C" fn returns_doublefloat() -> DoubleFloat { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] - // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // aarch64: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64: [[TMP4:%.*]] = load double, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: [[TMP4:%.*]] = load double, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, float }]] poison, double [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + + // aarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // loongarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // x86_64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // + // aarch64-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align [[RUST_ALIGN]] + // loongarch64-NEXT: [[TMP7:%.*]] = load float, ptr [[TMP6]], align [[RUST_ALIGN]] + // x86_64-NEXT: [[TMP7:%.*]] = load double, ptr [[TMP6]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // loongarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], float [[TMP7]], 1 + // x86_64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], double [[TMP7]], 1 + // + // aarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64-NEXT: ret [[ABI_TYPE]] [[ABI_VALUE]] DoubleFloat { f: 0., g: 0. } } // CHECK-LABEL: @call_twou16s #[no_mangle] pub fn call_twou16s() { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[RUST_ALLOCA:%.*]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // CHECK-NEXT: store i16 1, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 2 + // CHECK-NEXT: store i16 2, ptr [[TMP1]], align [[RUST_ALIGN]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // CHECK-NEXT: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK-NEXT: ret void let x = TwoU16s { a: 1, b: 2 }; receives_twou16s(x); } @@ -337,56 +453,67 @@ pub fn call_twou16s() { // CHECK-LABEL: @return_twou16s #[no_mangle] pub fn return_twou16s() -> TwoU16s { + // CHECK-NEXT: [[START:.*:]] + // + // aarch64-NEXT: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // loongarch64-NEXT: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // sparc64-NEXT: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // + // CHECK-NEXT: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // powerpc64: [[RETVAL:%.+]] = alloca [4 x i8], align 2 - // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]]) + // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RUST_ALLOCA]]) - // The other targets copy the cast ABI type to an alloca. - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - // sparc64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // The other targets copy the cast ABI type to by extractvalue. // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i32]] @returns_twou16s() - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // aarch64: call void @llvm.lifetime.start.p0(i64 8, ptr [[ABI_ALLOCA]]) + // loongarch64: call void @llvm.lifetime.start.p0(i64 8, ptr [[ABI_ALLOCA]]) + // sparc64: call void @llvm.lifetime.start.p0(i64 8, ptr [[ABI_ALLOCA]]) + // + // aarch64-NEXT: store i64 [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align 8 + // loongarch64-NEXT: store i64 [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align 8 + // sparc64-NEXT: store i64 [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align 8 + + // aarch64-NEXT: [[RUST_VALUE:%.+]] = load [[RUST_TYPE:%TwoU16s]], ptr [[ABI_ALLOCA]], align 8 + // loongarch64-NEXT: [[RUST_VALUE:%.+]] = load [[RUST_TYPE:%TwoU16s]], ptr [[ABI_ALLOCA]], align 8 + // sparc64-NEXT: [[RUST_VALUE:%.+]] = load [[RUST_TYPE:%TwoU16s]], ptr [[ABI_ALLOCA]], align 8 + // + // aarch64-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[ABI_ALLOCA]]) + // loongarch64-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[ABI_ALLOCA]]) + // sparc64-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[ABI_ALLOCA]]) + + // aarch64-NEXT: store [[RUST_TYPE]] [[RUST_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store [[RUST_TYPE]] [[RUST_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // sparc64-NEXT: store [[RUST_TYPE]] [[RUST_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) returns_twou16s() + // %_0.0 = load i16, ptr %0, align 2, !noundef !3 } // CHECK-LABEL: @call_fiveu16s #[no_mangle] pub fn call_fiveu16s() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2 - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + // CHECK: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // powerpc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // sparc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ i64, i16 }]] poison, i64 [[TMP4]], 0 + + // CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // CHECK-NEXT: [[TMP7:%.*]] = load {{i64|i16}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // CHECK-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], {{i64|i16}} [[TMP7]], 1 + // CHECK-NEXT: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK-NEXT: ret void let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 }; receives_fiveu16s(x); } @@ -395,50 +522,64 @@ pub fn call_fiveu16s() { // CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]]) #[no_mangle] pub fn return_fiveu16s() -> FiveU16s { + // CHECK-NEXT: [[START:.*:]] // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]]) + // powerpc64-NEXT: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]]) // The other targets copy the cast ABI type to the sret pointer. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s() - - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // + // aarch64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // loongarch64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // sparc64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // x86_64-NEXT: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // + // aarch64-NEXT: store i64 [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store i64 [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // sparc64-NEXT: store i64 [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // x86_64-NEXT: store i64 [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // loongarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // sparc64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // x86_64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // + // aarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // loongarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // sparc64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // x86_64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // + // aarch64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // sparc64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // x86_64-NEXT: store i16 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + + // CHECK-NEXT: ret void returns_fiveu16s() } // CHECK-LABEL: @call_doubledouble #[no_mangle] pub fn call_doubledouble() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK: [[TMP4:%.*]] = load {{double|i64}}, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x double\]]] poison, double [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + // powerpc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // sparc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + + // CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // CHECK-NEXT: [[TMP7:%.*]] = load {{double|i64}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // CHECK-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], {{i64|double}} [[TMP7]], 1 + // CHECK-NEXT: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK-NEXT: ret void let x = DoubleDouble { f: 1., g: 2. }; receives_doubledouble(x); } @@ -446,37 +587,43 @@ pub fn call_doubledouble() { // CHECK-LABEL: @return_doubledouble #[no_mangle] pub fn return_doubledouble() -> DoubleDouble { + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[RET_PTR:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 - // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]]) + // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RET_PTR]]) // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // sparc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x double\]]] @returns_doubledouble() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // aarch64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // loongarch64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // sparc64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // x86_64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // + // aarch64-NEXT: store double [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store double [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // sparc64-NEXT: store double [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // x86_64-NEXT: store double [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // loongarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // sparc64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // x86_64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // + // aarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // loongarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // sparc64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // x86_64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // + // aarch64-NEXT: store double [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store double [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // sparc64-NEXT: store double [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // x86_64-NEXT: store double [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] returns_doubledouble() } @@ -488,30 +635,40 @@ pub fn return_doubledouble() -> DoubleDouble { // x86_64-LABEL: @call_doublefloat #[no_mangle] pub fn call_doublefloat() { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) - // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - // powerpc64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) - // x86_64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // aarch64: [[TMP4:%.*]] = load {{double|i64}}, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // loongarch64: [[TMP4:%.*]] = load {{double|i64}}, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // powerpc64: [[TMP4:%.*]] = load {{double|i64}}, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + // x86_64: [[TMP4:%.*]] = load {{double|i64}}, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, float }]] poison, double [[TMP4]], 0 + // powerpc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ double, double }]] poison, double [[TMP4]], 0 + + // aarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // loongarch64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // powerpc64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // x86_64-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + + // aarch64-NEXT: [[TMP7:%.*]] = load {{double|i64|float}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // loongarch64-NEXT: [[TMP7:%.*]] = load {{double|i64|float}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // powerpc64-NEXT: [[TMP7:%.*]] = load {{double|i64|float}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // x86_64-NEXT: [[TMP7:%.*]] = load {{double|i64|float}}, ptr [[TMP6]], align [[RUST_ALIGN]] + + // aarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // loongarch64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], float [[TMP7]], 1 + // powerpc64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], i64 [[TMP7]], 1 + // x86_64-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], double [[TMP7]], 1 + + // aarch64-NEXT: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // loongarch64-NEXT: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // powerpc64-NEXT: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // x86_64-NEXT: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) let x = DoubleFloat { f: 1., g: 2. }; receives_doublefloat(x); } @@ -524,49 +681,58 @@ pub fn call_doublefloat() { // x86_64-LABEL: @return_doublefloat #[no_mangle] pub fn return_doublefloat() -> DoubleFloat { + // aarch64: [[RET_PTR:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RET_PTR:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // powerpc64: [[RET_PTR:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RET_PTR:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 - // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]]) + // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RET_PTR]]) // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - - // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] - // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_doublefloat() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, float }]] @returns_doublefloat() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat() - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // aarch64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // loongarch64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // x86_64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // + // aarch64-NEXT: store i64 [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store double [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // x86_64-NEXT: store double [[TMP1]], ptr [[RET_PTR]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // loongarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // x86_64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // + // aarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // loongarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // x86_64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RET_PTR]], i64 8 + // + // aarch64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store float [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // x86_64-NEXT: store double [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] returns_doublefloat() } // CHECK-LABEL: @call_three32s #[no_mangle] pub fn call_three32s() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] - // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) - - // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]]) + // CHECK: [[TMP4:%.*]] = load i64, ptr [[RUST_ALLOCA]], align [[RUST_ALIGN]] + + // aarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // loongarch64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // powerpc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // sparc64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:\[2 x i64\]]] poison, i64 [[TMP4]], 0 + // x86_64-NEXT: [[TMP5:%.*]] = insertvalue [[ABI_TYPE:{ i64, i32 }]] poison, i64 [[TMP4]], 0 + + // CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[RUST_ALLOCA]], i64 8 + // CHECK-NEXT: [[TMP7:%.*]] = load {{i64|i32}}, ptr [[TMP6]], align [[RUST_ALIGN]] + // CHECK-NEXT: [[ABI_VALUE:%.*]] = insertvalue [[ABI_TYPE]] [[TMP5]], {{i64|i32}} [[TMP7]], 1 + // CHECK-NEXT: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]]) let x = Three32s { a: 1, b: 2, c: 3 }; receives_three32s(x); } @@ -576,28 +742,41 @@ pub fn call_three32s() { // CHECK-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RUST_RETVAL:%.*]]) #[no_mangle] pub fn return_three32s() -> Three32s { + // CHECK-NEXT: [[START:.*:]] // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. - // powerpc64: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]]) - - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64-NEXT: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]]) // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s() - // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - - // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // aarch64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // loongarch64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // sparc64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // x86_64: [[TMP1:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 0 + // + // aarch64-NEXT: store i64 [[TMP1]], ptr [[RUST_RETVAL]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store i64 [[TMP1]], ptr [[RUST_RETVAL]], align [[RUST_ALIGN]] + // sparc64-NEXT: store i64 [[TMP1]], ptr [[RUST_RETVAL]], align [[RUST_ALIGN]] + // x86_64-NEXT: store i64 [[TMP1]], ptr [[RUST_RETVAL]], align [[RUST_ALIGN]] + // + // aarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // loongarch64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // sparc64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // x86_64-NEXT: [[TMP2:%.*]] = extractvalue [[ABI_TYPE]] [[ABI_VALUE]], 1 + // + // aarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_RETVAL]], i64 8 + // loongarch64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_RETVAL]], i64 8 + // sparc64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_RETVAL]], i64 8 + // x86_64-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[RUST_RETVAL]], i64 8 + // + // aarch64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // loongarch64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // sparc64-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // x86_64-NEXT: store i32 [[TMP2]], ptr [[TMP3]], align [[RUST_ALIGN]] + // + // CHECK-NEXT: ret void returns_three32s() } diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs index ae8d8383f5b91..a0e45c7622ff9 100644 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs @@ -35,11 +35,22 @@ extern "C" { // CHECK-LABEL: @test #[no_mangle] pub fn test() { + // CHECK-NEXT: [[START:.*:]] + // CHECK-NEXT: [[S:%.*]] = alloca [12 x i8], align 4 + // CHECK-NEXT: store i32 1, ptr [[S]], align 4 + // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 4 + // CHECK-NEXT: store i32 2, ptr [[TMP0]], align 4 + // CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 8 + // CHECK-NEXT: store i32 3, ptr [[TMP1]], align 4 + // CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[S]], align 4 + // CHECK-NEXT: [[TMP3:%.*]] = insertvalue { i64, i32 } poison, i64 [[TMP2]], 0 + // CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 8 + // CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4 + // CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i32 } [[TMP3]], i32 [[TMP5]], 1 + // CHECK-NEXT: call void @foo({ i64, i32 } [[TMP6]]) #[[ATTR2:[0-9]+]] + // CHECK-NEXT: ret void let s = S { f1: 1, f2: 2, f3: 3 }; unsafe { - // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8 - // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8 - // CHECK: call void @foo({ i64, i32 } [[LOAD]]) foo(s); } } diff --git a/tests/codegen/stores.rs b/tests/codegen/stores.rs index aa3090db6d317..14f323e17babd 100644 --- a/tests/codegen/stores.rs +++ b/tests/codegen/stores.rs @@ -15,10 +15,9 @@ pub struct Bytes { // dependent alignment #[no_mangle] pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { - // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4 // CHECK: %y = alloca [4 x i8], align 1 - // CHECK: store i32 %0, ptr [[TMP]] - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false) + // CHECK: store i32 %0, ptr %y, align 1 + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %x, ptr align 1 %y, i{{[0-9]+}} 4, i1 false) *x = y; } @@ -27,9 +26,8 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { // dependent alignment #[no_mangle] pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { - // CHECK: [[TMP:%.+]] = alloca [4 x i8], align 4 // CHECK: %y = alloca [4 x i8], align 1 - // CHECK: store i32 %0, ptr [[TMP]] - // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 {{.+}}, ptr align 4 {{.+}}, i{{[0-9]+}} 4, i1 false) + // CHECK: store i32 %0, ptr %y, align 1 + // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %x, ptr align 1 %y, i{{[0-9]+}} 4, i1 false) *x = y; }