From 448885c2c7fb777469208b4b5b976627746d7d65 Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 5 Aug 2024 21:35:50 +0800 Subject: [PATCH] Use `insertvalue` and `extractvalue` instead of `memcpy` in CastTarget --- compiler/rustc_codegen_llvm/src/abi.rs | 34 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 44 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 8 +- compiler/rustc_codegen_ssa/src/traits/abi.rs | 145 +++- compiler/rustc_codegen_ssa/src/traits/mod.rs | 2 +- tests/codegen/array-codegen.rs | 25 +- tests/codegen/cast-target-abi.rs | 705 +++++++++++------- tests/codegen/cffi/ffi-out-of-bounds-loads.rs | 17 +- tests/codegen/stores.rs | 10 +- 9 files changed, 633 insertions(+), 357 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 1277b7898c2d9..f091bb43d3f6f 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 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 bc3076528da24..0a3326495cc08 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,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), }; - let llslot = match op.val { + let (llslot, align) = match op.val { Immediate(_) | Pair(..) => { let scratch = PlaceRef::alloca(bx, self.fn_abi.ret.layout); op.val.store(bx, scratch); - scratch.val.llval + (scratch.val.llval, scratch.val.align) } Ref(place_val) => { assert_eq!( place_val.align, op.layout.align.abi, "return place is unaligned!" ); - place_val.llval + (place_val.llval, place_val.align) } 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, llslot, align) } }; bx.ret(llval); @@ -1515,35 +1514,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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); + if let PassMode::Cast { cast, .. } = &arg.mode { + llval = cast.cast_rust_abi_to_other(bx, llval, align); } else { // We can't use `PlaceRef::load` here because the argument // may have a type we don't treat as immediate, but the ABI diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 4ce07269cd2c1..d62ea8f974f83 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -236,7 +236,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let llretptr = start_bx.get_param(0); return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); } - PassMode::Cast { ref cast, .. } => { + PassMode::Cast { ref cast, .. } + if start_bx.cast_backend_type(cast) + == start_bx.reg_backend_type(&cast.rest.unit) + && cast.size(&start_bx) > layout.size => + { + // When using just a single register, we directly use load or store instructions, + // so we need to ensure that the allocated space is sufficiently large. debug!("alloc: {:?} (return place) -> place", local); let size = cast.size(&start_bx); return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout)); diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs index 60d8f2a9ece48..f577463eef1ab 100644 --- a/compiler/rustc_codegen_ssa/src/traits/abi.rs +++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs @@ -1,5 +1,148 @@ -use super::BackendTypes; +use rustc_middle::bug; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::abi::call::CastTarget; +use rustc_target::abi::Align; + +use super::consts::ConstMethods; +use super::type_::BaseTypeMethods; +use super::{BackendTypes, BuilderMethods, LayoutTypeMethods}; 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, src: Bx::Value, align: Align) -> 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, src: Bx::Value, align: Align) -> Bx::Value { + let cast_ty = bx.cast_backend_type(self); + 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"), + } + } + + fn cast_other_abi_to_rust( + &self, + bx: &mut Bx, + src: Bx::Value, + dst: Bx::Value, + layout: TyAndLayout<'tcx>, + ) { + let align = 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 { + dst + } else { + bx.inbounds_ptradd(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 { + dst + } else { + bx.inbounds_ptradd(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(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 => { + let scratch_size = self.size(bx); + let src = if scratch_size > layout.size { + // When using just a single register, we directly use load or store instructions, + // so we must allocate sufficient space. + let scratch_align = self.align(bx); + let llscratch = bx.alloca(scratch_size, scratch_align); + bx.lifetime_start(llscratch, scratch_size); + bx.store(src, llscratch, scratch_align); + let tmp = bx.load(bx.backend_type(layout), llscratch, scratch_align); + bx.lifetime_end(llscratch, scratch_size); + tmp + } else { + src + }; + bx.store(src, dst, align); + } + ty_kind => bug!("cannot cast {ty_kind:?} to the Rust representation in CastTarget"), + }; + } +} 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/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 34e52d38bbea9..7d52ce3f6c688 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 a4b7c0caa6d46..84a8343ada28e 100644 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs @@ -34,11 +34,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; }