From 96a72676d1134f58c378b0b8003922b09b9f1e5f Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 25 Feb 2024 00:43:03 -0500 Subject: [PATCH 1/5] use [N x i8] for byval/sret types This avoids depending on LLVM's struct types to determine the size of the byval/sret slot. --- compiler/rustc_codegen_llvm/src/abi.rs | 20 ++++- tests/codegen/align-byval-vector.rs | 8 +- tests/codegen/align-byval.rs | 92 ++++++++++---------- tests/codegen/align-enum.rs | 1 - tests/codegen/align-struct.rs | 4 - tests/codegen/function-arguments-noopt.rs | 4 +- tests/codegen/function-arguments.rs | 2 +- tests/codegen/mem-replace-big-type.rs | 2 +- tests/codegen/repr/transparent-struct-ptr.rs | 16 ++-- tests/codegen/simd/unpadded-simd.rs | 4 +- 10 files changed, 80 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index b5b4f894e4d82..147939d3a529a 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -424,7 +424,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { attrs, meta_attrs: _, on_stack } => { assert!(!on_stack); let i = apply(attrs); - let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx)); + let sret = llvm::CreateStructRetAttr( + cx.llcx, + cx.type_array(cx.type_i8(), self.ret.layout.size.bytes()), + ); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); } PassMode::Cast { cast, pad_i32: _ } => { @@ -437,7 +440,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Ignore => {} PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => { let i = apply(attrs); - let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx)); + let byval = llvm::CreateByValAttr( + cx.llcx, + cx.type_array(cx.type_i8(), arg.layout.size.bytes()), + ); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]); } PassMode::Direct(attrs) @@ -486,7 +492,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { attrs, meta_attrs: _, on_stack } => { assert!(!on_stack); let i = apply(bx.cx, attrs); - let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx)); + let sret = llvm::CreateStructRetAttr( + bx.cx.llcx, + bx.cx.type_array(bx.cx.type_i8(), self.ret.layout.size.bytes()), + ); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); } PassMode::Cast { cast, pad_i32: _ } => { @@ -513,7 +522,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Ignore => {} PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => { let i = apply(bx.cx, attrs); - let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx)); + let byval = llvm::CreateByValAttr( + bx.cx.llcx, + bx.cx.type_array(bx.cx.type_i8(), arg.layout.size.bytes()), + ); attributes::apply_to_callsite( callsite, llvm::AttributePlace::Argument(i), diff --git a/tests/codegen/align-byval-vector.rs b/tests/codegen/align-byval-vector.rs index 6596792ec88a4..02b7d6b0c5e28 100644 --- a/tests/codegen/align-byval-vector.rs +++ b/tests/codegen/align-byval-vector.rs @@ -37,12 +37,12 @@ pub struct DoubleFoo { } extern "C" { - // x86-linux: declare void @f({{.*}}byval(%Foo) align 4{{.*}}) - // x86-darwin: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + // x86-linux: declare void @f({{.*}}byval([32 x i8]) align 4{{.*}}) + // x86-darwin: declare void @f({{.*}}byval([32 x i8]) align 16{{.*}}) fn f(foo: Foo); - // x86-linux: declare void @g({{.*}}byval(%DoubleFoo) align 4{{.*}}) - // x86-darwin: declare void @g({{.*}}byval(%DoubleFoo) align 16{{.*}}) + // x86-linux: declare void @g({{.*}}byval([64 x i8]) align 4{{.*}}) + // x86-darwin: declare void @g({{.*}}byval([64 x i8]) align 16{{.*}}) fn g(foo: DoubleFoo); } diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 1016c7903eb2d..c74e236f29d37 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -107,20 +107,20 @@ pub unsafe fn call_na1(x: NaturalAlign1) { // CHECK: start: // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 1 - // m68k: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}} [[ALLOCA]]) + // m68k: call void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}} [[ALLOCA]]) // wasm: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 1 - // wasm: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}} [[ALLOCA]]) + // wasm: call void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}} [[ALLOCA]]) // x86_64-linux: call void @natural_align_1(i16 // x86_64-windows: call void @natural_align_1(i16 // i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 4 - // i686-linux: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}} [[ALLOCA]]) + // i686-linux: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]]) // i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 4 - // i686-windows: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}} [[ALLOCA]]) + // i686-windows: call void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}} [[ALLOCA]]) natural_align_1(x); } @@ -135,10 +135,10 @@ pub unsafe fn call_na2(x: NaturalAlign2) { // x86_64-windows-NEXT: call void @natural_align_2 // i686-linux: [[ALLOCA:%[0-9]+]] = alloca %NaturalAlign2, align 4 - // i686-linux: call void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}} [[ALLOCA]]) + // i686-linux: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]]) // i686-windows: [[ALLOCA:%[0-9]+]] = alloca %NaturalAlign2, align 4 - // i686-windows: call void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}} [[ALLOCA]]) + // i686-windows: call void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}} [[ALLOCA]]) natural_align_2(x); } @@ -199,141 +199,141 @@ pub unsafe fn call_fa16(x: ForceAlign16) { } extern "C" { - // m68k: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}}) + // m68k: declare void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}}) - // wasm: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}}) + // wasm: declare void @natural_align_1({{.*}}byval([2 x i8]) align 1{{.*}}) // x86_64-linux: declare void @natural_align_1(i16) // x86_64-windows: declare void @natural_align_1(i16) - // i686-linux: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}}) + // i686-linux: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}}) - // i686-windows: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}}) + // i686-windows: declare void @natural_align_1({{.*}}byval([2 x i8]) align 4{{.*}}) fn natural_align_1(x: NaturalAlign1); - // m68k: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) + // m68k: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) - // wasm: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) + // wasm: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) - // x86_64-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) + // x86_64-linux: declare void @natural_align_2({{.*}}byval([34 x i8]) align 2{{.*}}) // x86_64-windows: declare void @natural_align_2( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 2{{.*}}) - // i686-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}}) + // i686-linux: declare void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}}) - // i686-windows: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}}) + // i686-windows: declare void @natural_align_2({{.*}}byval([34 x i8]) align 4{{.*}}) fn natural_align_2(x: NaturalAlign2); - // m68k: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + // m68k: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // wasm: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + // wasm: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // x86_64-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + // x86_64-linux: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) // x86_64-windows: declare void @force_align_4( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 4{{.*}}) - // i686-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + // i686-linux: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) - // i686-windows: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + // i686-windows: declare void @force_align_4({{.*}}byval([20 x i8]) align 4{{.*}}) fn force_align_4(x: ForceAlign4); - // m68k: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) + // m68k: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - // wasm: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}}) + // wasm: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}}) + // x86_64-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) // x86_64-windows: declare void @natural_align_8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) + // i686-linux: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) + // i686-windows: declare void @natural_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) fn natural_align_8(x: NaturalAlign8); - // m68k: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}}) + // m68k: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // wasm: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}}) + // wasm: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}}) + // x86_64-linux: declare void @force_align_8({{.*}}byval([24 x i8]) align 8{{.*}}) // x86_64-windows: declare void @force_align_8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 4{{.*}}) + // i686-linux: declare void @force_align_8({{.*}}byval([24 x i8]) align 4{{.*}}) // i686-windows: declare void @force_align_8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) fn force_align_8(x: ForceAlign8); - // m68k: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) + // m68k: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - // wasm: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 8{{.*}}) + // wasm: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 8{{.*}}) + // x86_64-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) // x86_64-windows: declare void @lower_fa8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) + // i686-linux: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) - // i686-windows: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) + // i686-windows: declare void @lower_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) fn lower_fa8(x: LowerFA8); - // m68k: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) + // m68k: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // wasm: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) + // wasm: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) + // x86_64-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) // x86_64-windows: declare void @wrapped_fa8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 4{{.*}}) + // i686-linux: declare void @wrapped_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) // i686-windows: declare void @wrapped_fa8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) fn wrapped_fa8(x: WrappedFA8); - // m68k: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) + // m68k: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // wasm: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) + // wasm: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) - // x86_64-linux: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) + // x86_64-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 8{{.*}}) // x86_64-windows: declare void @transparent_fa8( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 8{{.*}}) - // i686-linux: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 4{{.*}}) + // i686-linux: declare void @transparent_fa8({{.*}}byval([24 x i8]) align 4{{.*}}) // i686-windows: declare void @transparent_fa8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) fn transparent_fa8(x: TransparentFA8); - // m68k: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) + // m68k: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) - // wasm: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) + // wasm: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) - // x86_64-linux: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) + // x86_64-linux: declare void @force_align_16({{.*}}byval([80 x i8]) align 16{{.*}}) // x86_64-windows: declare void @force_align_16( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 16{{.*}}) - // i686-linux: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 4{{.*}}) + // i686-linux: declare void @force_align_16({{.*}}byval([80 x i8]) align 4{{.*}}) // i686-windows: declare void @force_align_16( // i686-windows-NOT: byval diff --git a/tests/codegen/align-enum.rs b/tests/codegen/align-enum.rs index 17bf2cf725682..b40168d77a477 100644 --- a/tests/codegen/align-enum.rs +++ b/tests/codegen/align-enum.rs @@ -8,7 +8,6 @@ pub enum Align64 { A(u32), B(u32), } -// CHECK: %Align64 = type { i32, [15 x i32] } pub struct Nested64 { a: u8, diff --git a/tests/codegen/align-struct.rs b/tests/codegen/align-struct.rs index 31859152830a5..dbbb85bee6f37 100644 --- a/tests/codegen/align-struct.rs +++ b/tests/codegen/align-struct.rs @@ -5,7 +5,6 @@ #[repr(align(64))] pub struct Align64(i32); -// CHECK: %Align64 = type { i32, [15 x i32] } pub struct Nested64 { a: Align64, @@ -13,19 +12,16 @@ pub struct Nested64 { c: i32, d: i8, } -// CHECK: %Nested64 = type { %Align64, i32, i32, i8, [55 x i8] } pub enum Enum4 { A(i32), B(i32), } -// No Aggregate type, and hence nothing in LLVM IR. pub enum Enum64 { A(Align64), B(i32), } -// CHECK: %Enum64 = type { i32, [31 x i32] } // CHECK-LABEL: @align64 #[no_mangle] diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs index e99ceddfb7281..0d42915893bc0 100644 --- a/tests/codegen/function-arguments-noopt.rs +++ b/tests/codegen/function-arguments-noopt.rs @@ -42,7 +42,7 @@ pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 { f(x) } -// CHECK: void @struct_(ptr sret(%S) align 4{{( %_0)?}}, ptr align 4 %x) +// CHECK: void @struct_(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %x) #[no_mangle] pub fn struct_(x: S) -> S { x @@ -51,7 +51,7 @@ pub fn struct_(x: S) -> S { // CHECK-LABEL: @struct_call #[no_mangle] pub fn struct_call(x: S, f: fn(S) -> S) -> S { - // CHECK: call void %f(ptr sret(%S) align 4{{( %_0)?}}, ptr align 4 %{{.+}}) + // CHECK: call void %f(ptr sret([32 x i8]) align 4{{( %_0)?}}, ptr align 4 %{{.+}}) f(x) } diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index b75c188f51a9b..2a1c023a931b9 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -188,7 +188,7 @@ pub fn notunpin_box(x: Box) -> Box { x } -// CHECK: @struct_return(ptr noalias nocapture noundef sret(%S) align 4 dereferenceable(32){{( %_0)?}}) +// CHECK: @struct_return(ptr noalias nocapture noundef sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index c71cbbd08f9ac..d5eadda4469f6 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -23,7 +23,7 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big { // CHECK-NOT: call void @llvm.memcpy // For a large type, we expect exactly three `memcpy`s -// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big) +// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret([56 x i8]) // CHECK-NOT: call void @llvm.memcpy // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %result, ptr align 8 %dest, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy diff --git a/tests/codegen/repr/transparent-struct-ptr.rs b/tests/codegen/repr/transparent-struct-ptr.rs index ff531029e046b..0b85cdcd30f3a 100644 --- a/tests/codegen/repr/transparent-struct-ptr.rs +++ b/tests/codegen/repr/transparent-struct-ptr.rs @@ -34,19 +34,19 @@ pub enum TeBigS { Variant(BigS), } -// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]] byval(%BigS) [[BIGS_ARG_ATTRS2:.*]]) +// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr [[BIGS_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) #[no_mangle] pub extern "C" fn test_BigS(_: BigS) -> BigS { loop {} } -// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval(%TsBigS) [[BIGS_ARG_ATTRS2:.*]]) +// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) #[no_mangle] pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval(%TuBigS) [[BIGS_ARG_ATTRS2:.*]]) +// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2:.*]]) #[no_mangle] pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval(%"TeBigS::Variant") [[BIGS_ARG_ATTRS2]]) +// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr [[BIGS_ARG_ATTRS1]] byval([64 x i8]) [[BIGS_ARG_ATTRS2]]) #[no_mangle] pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } @@ -70,18 +70,18 @@ pub enum TeBigU { Variant(BigU), } -// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]] byval(%BigU) [[BIGU_ARG_ATTRS2:.*]]) +// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1:.*]] byval([64 x i8]) [[BIGU_ARG_ATTRS2:.*]]) #[no_mangle] pub extern "C" fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret(%TsBigU) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval(%TsBigU) [[BIGU_ARG_ATTRS2]]) +// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) #[no_mangle] pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } -// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval(%TuBigU) [[BIGU_ARG_ATTRS2]]) +// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) #[no_mangle] pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } -// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval(%"TeBigU::Variant") [[BIGU_ARG_ATTRS2]]) +// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr [[BIGU_ARG_ATTRS1]] byval([64 x i8]) [[BIGU_ARG_ATTRS2]]) #[no_mangle] pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/tests/codegen/simd/unpadded-simd.rs b/tests/codegen/simd/unpadded-simd.rs index 797bca38ffa1d..66d9298c0068c 100644 --- a/tests/codegen/simd/unpadded-simd.rs +++ b/tests/codegen/simd/unpadded-simd.rs @@ -3,7 +3,7 @@ // See #87254. #![crate_type = "lib"] -#![feature(repr_simd)] +#![feature(repr_simd, abi_unadjusted)] #[derive(Copy, Clone)] #[repr(simd)] @@ -14,6 +14,6 @@ pub struct int16x4x2_t(pub int16x4_t, pub int16x4_t); // CHECK: %int16x4x2_t = type { <4 x i16>, <4 x i16> } #[no_mangle] -fn takes_int16x4x2_t(t: int16x4x2_t) -> int16x4x2_t { +extern "unadjusted" fn takes_int16x4x2_t(t: int16x4x2_t) -> int16x4x2_t { t } From c56ffaa3af2647838c25c6e1afbfef9309710929 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Thu, 7 Mar 2024 09:56:27 -0500 Subject: [PATCH 2/5] fix now-incorrect parenthetical about byval attr --- compiler/rustc_target/src/abi/call/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 66177d551ba2d..6e24dc4bc0b85 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -54,8 +54,10 @@ pub enum PassMode { /// argument. (This is the only mode that supports unsized arguments.) /// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to /// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument - /// attribute (using the Rust type of this argument). `on_stack` cannot be true for unsized - /// arguments, i.e., when `meta_attrs` is `Some`. + /// attribute (using a byte array type with the same size as the Rust type [which ensures that + /// padding is preserved and that we do not rely on LLVM's struct layout], and with alignment + /// determined in a complex, target-specific manner [see callers of `make_indirect_byval`]). + /// `on_stack` cannot be true for unsized arguments, i.e., when `meta_attrs` is `Some`. Indirect { attrs: ArgAttributes, meta_attrs: Option, on_stack: bool }, } From 38324a1f4fd131112ece8b9e1c995ad364b0ca17 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 9 Mar 2024 11:40:40 -0500 Subject: [PATCH 3/5] improve byval abi docs --- compiler/rustc_target/src/abi/call/mod.rs | 37 +++++++++++++++++--- compiler/rustc_target/src/abi/call/x86_64.rs | 2 ++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 6e24dc4bc0b85..d326cff85c570 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -46,17 +46,23 @@ pub enum PassMode { /// /// The argument has a layout abi of `ScalarPair`. Pair(ArgAttributes, ArgAttributes), - /// Pass the argument after casting it. See the `CastTarget` docs for details. The bool - /// indicates if a `Reg::i32()` dummy argument is emitted before the real argument. + /// Pass the argument after casting it. See the `CastTarget` docs for details. + /// + /// `pad_i32` indicates if a `Reg::i32()` dummy argument is emitted before the real argument. Cast { pad_i32: bool, cast: Box }, /// Pass the argument indirectly via a hidden pointer. + /// /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized /// argument. (This is the only mode that supports unsized arguments.) + /// /// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to /// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument - /// attribute (using a byte array type with the same size as the Rust type [which ensures that - /// padding is preserved and that we do not rely on LLVM's struct layout], and with alignment - /// determined in a complex, target-specific manner [see callers of `make_indirect_byval`]). + /// attribute. The `byval` argument will use a byte array with the same size as the Rust type + /// (which ensures that padding is preserved and that we do not rely on LLVM's struct layout), + /// and will use the alignment specified in `attrs.pointee_align` (if `Some`) or the type's + /// alignment, depending on the target's ABI. This means that the alignment will not always + /// match the Rust type's alignment; see documentation of `make_indirect_byval` for more info. + /// /// `on_stack` cannot be true for unsized arguments, i.e., when `meta_attrs` is `Some`. Indirect { attrs: ArgAttributes, meta_attrs: Option, on_stack: bool }, } @@ -598,6 +604,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } + /// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead. + /// This is valid for both sized and unsized arguments. pub fn make_indirect(&mut self) { match self.mode { PassMode::Direct(_) | PassMode::Pair(_, _) => { @@ -611,7 +619,26 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } + /// Pass this argument indirectly, by placing it at a fixed stack offset. + /// This corresponds to the `byval` LLVM argument attribute. + /// This is only valid for sized arguments. + /// + /// `byval_align` specifies the alignment of the `byval` stack slot, which does not need to + /// correspond to the type's alignment. This will be `Some` if the target's ABI specifies that + /// stack slots used for arguments passed by-value have specific alignment requirements which + /// differ from the alignment used in other situations. + /// + /// If `None`, the type's alignment is used. + /// + /// If the resulting alignment differs from the type's alignment, + /// the argument will be copied to an alloca with sufficient alignment, + /// either in the caller (if the type's alignment is lower than the byval alignment) + /// or in the callee† (if the type's alignment is higher than the byval alignment), + /// to ensure that Rust code never sees an underaligned pointer. + /// + /// † This is currently broken, see . pub fn make_indirect_byval(&mut self, byval_align: Option) { + assert!(!self.layout.is_unsized(), "used byval ABI for unsized layout"); self.make_indirect(); match self.mode { PassMode::Indirect { ref mut attrs, meta_attrs: _, ref mut on_stack } => { diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index 2eb50cc8dea85..f3208fe5d0351 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -217,6 +217,8 @@ where match cls_or_mem { Err(Memory) => { if is_arg { + // The x86_64 ABI doesn't have any special requirements for `byval` alignment, + // the type's alignment is always used. arg.make_indirect_byval(None); } else { // `sret` parameter thus one less integer register available From 549eac374ff33bc249e4098fdb6179510133258c Mon Sep 17 00:00:00 2001 From: erikdesjardins Date: Sat, 9 Mar 2024 12:49:35 -0500 Subject: [PATCH 4/5] once byval abi is computed, the target abi isn't used further Co-authored-by: Ralf Jung --- compiler/rustc_target/src/abi/call/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index d326cff85c570..bf09a1f6a0ab5 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -60,7 +60,7 @@ pub enum PassMode { /// attribute. The `byval` argument will use a byte array with the same size as the Rust type /// (which ensures that padding is preserved and that we do not rely on LLVM's struct layout), /// and will use the alignment specified in `attrs.pointee_align` (if `Some`) or the type's - /// alignment, depending on the target's ABI. This means that the alignment will not always + /// alignment (if `None`). This means that the alignment will not always /// match the Rust type's alignment; see documentation of `make_indirect_byval` for more info. /// /// `on_stack` cannot be true for unsized arguments, i.e., when `meta_attrs` is `Some`. From 8fdd5e044b6bcbb42b4342a19a62ca501fe33b58 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 9 Mar 2024 23:07:27 -0500 Subject: [PATCH 5/5] convert codegen/repr/transparent-* tests to no_core, fix discrepancies --- .../loongarch-abi/loongarch64-lp64d-abi.rs | 14 ++- tests/codegen/repr/transparent-imm-array.rs | 55 ++++++---- tests/codegen/repr/transparent-mips64.rs | 39 ++++--- tests/codegen/repr/transparent-sparc64.rs | 101 ++++++++++++++++++ tests/codegen/repr/transparent-struct-ptr.rs | 34 ++++-- tests/codegen/repr/transparent-sysv64.rs | 19 +++- 6 files changed, 210 insertions(+), 52 deletions(-) create mode 100644 tests/codegen/repr/transparent-sparc64.rs diff --git a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs index 3c895eb9531a2..6ac78a3be0209 100644 --- a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs +++ b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs @@ -1,8 +1,14 @@ -//@ compile-flags: -C no-prepopulate-passes -//@ only-loongarch64 -//@ only-linux +//@ compile-flags: -C no-prepopulate-passes --target loongarch64-unknown-linux-gnu +//@ needs-llvm-components: loongarch +#![feature(no_core, lang_items)] #![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } // CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i) #[no_mangle] @@ -254,7 +260,7 @@ pub struct IntDoubleInt { #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(ptr noalias nocapture noundef sret(%IntDoubleInt) align 8 dereferenceable(24) %_0) +// CHECK: define void @f_ret_int_double_int_s(ptr noalias nocapture noundef sret([24 x i8]) align 8 dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/codegen/repr/transparent-imm-array.rs b/tests/codegen/repr/transparent-imm-array.rs index 842e36ca13dac..ac9fcc7ce4bcf 100644 --- a/tests/codegen/repr/transparent-imm-array.rs +++ b/tests/codegen/repr/transparent-imm-array.rs @@ -1,22 +1,40 @@ -//@ revisions: arm mips thumb wasm32 +//@ revisions: arm-linux arm-android armv7-linux armv7-android mips thumb sparc //@ compile-flags: -C no-prepopulate-passes -// -//@[arm] only-arm -//@[mips] only-mips -//@[thumb] only-thumb -//@[wasm32] only-wasm32 -//@ ignore-emscripten + +//@[arm-linux] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm-linux] needs-llvm-components: arm +//@[arm-android] compile-flags: --target arm-linux-androideabi +//@[arm-android] needs-llvm-components: arm +//@[armv7-linux] compile-flags: --target armv7-unknown-linux-gnueabi +//@[armv7-linux] needs-llvm-components: arm +//@[armv7-android] compile-flags: --target armv7-linux-androideabi +//@[armv7-android] needs-llvm-components: arm +//@[mips] compile-flags: --target mips-unknown-linux-gnu +//@[mips] needs-llvm-components: mips +//@[thumb] compile-flags: --target thumbv7neon-linux-androideabi +//@[thumb] needs-llvm-components: arm +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc + // See ./transparent.rs // Some platforms pass large aggregates using immediate arrays in LLVMIR // Other platforms pass large aggregates using struct pointer in LLVMIR // This covers the "immediate array" case. -#![feature(transparent_unions)] +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } -#![crate_type="lib"] +impl Copy for [u32; 16] {} +impl Copy for BigS {} +impl Copy for BigU {} -#[derive(Clone, Copy)] #[repr(C)] pub struct BigS([u32; 16]); @@ -33,24 +51,23 @@ pub enum TeBigS { Variant(BigS), } -// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32] +// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [16 x i32] #[no_mangle] pub extern fn test_BigS(_: BigS) -> BigS { loop {} } -// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } -#[derive(Clone, Copy)] #[repr(C)] pub union BigU { foo: [u32; 16], @@ -69,18 +86,18 @@ pub enum TeBigU { Variant(BigU), } -// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32] +// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [16 x i32] #[no_mangle] pub extern fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } -// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } -// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32] +// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [16 x i32] #[no_mangle] pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/tests/codegen/repr/transparent-mips64.rs b/tests/codegen/repr/transparent-mips64.rs index 55090e6bd8088..9a404ba696418 100644 --- a/tests/codegen/repr/transparent-mips64.rs +++ b/tests/codegen/repr/transparent-mips64.rs @@ -1,15 +1,25 @@ -//@ compile-flags: -C no-prepopulate-passes -// +//@ revisions: mips64 mips64el + +//@[mips64] compile-flags: -C no-prepopulate-passes --target mips64-unknown-linux-gnuabi64 +//@[mips64] needs-llvm-components: mips +//@[mips64el] compile-flags: -C no-prepopulate-passes --target mips64el-unknown-linux-gnuabi64 +//@[mips64el] needs-llvm-components: mips -//@ only-mips64 // See ./transparent.rs -#![feature(transparent_unions)] +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] -#![crate_type="lib"] +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } +impl Copy for [u32; 16] {} +impl Copy for BigS {} +impl Copy for BigU {} -#[derive(Clone, Copy)] #[repr(C)] pub struct BigS([u32; 16]); @@ -26,24 +36,23 @@ pub enum TeBigS { Variant(BigS), } -// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [8 x i64] +// CHECK: define void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], [8 x i64] #[no_mangle] pub extern fn test_BigS(_: BigS) -> BigS { loop {} } -// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [8 x i64] +// CHECK: define void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] #[no_mangle] pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } -// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [8 x i64] +// CHECK: define void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] #[no_mangle] pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } -// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [8 x i64] +// CHECK: define void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], [8 x i64] #[no_mangle] pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } -#[derive(Clone, Copy)] #[repr(C)] pub union BigU { foo: [u32; 16], @@ -62,18 +71,18 @@ pub enum TeBigU { Variant(BigU), } -// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [8 x i64] +// CHECK: define void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], [8 x i64] #[no_mangle] pub extern fn test_BigU(_: BigU) -> BigU { loop {} } -// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [8 x i64] +// CHECK: define void @test_TsBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] #[no_mangle] pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } -// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [8 x i64] +// CHECK: define void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] #[no_mangle] pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } -// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [8 x i64] +// CHECK: define void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2]], [8 x i64] #[no_mangle] pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/tests/codegen/repr/transparent-sparc64.rs b/tests/codegen/repr/transparent-sparc64.rs new file mode 100644 index 0000000000000..7005a07f554fc --- /dev/null +++ b/tests/codegen/repr/transparent-sparc64.rs @@ -0,0 +1,101 @@ +//@ compile-flags: -O -C no-prepopulate-passes --target sparc64-unknown-linux-gnu +//@ needs-llvm-components: sparc + +// See ./transparent.rs + +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } + +impl Copy for [u32; 16] {} +impl Copy for BigS {} +impl Copy for BigU {} + + +#[repr(C)] +pub struct BigS([u32; 16]); + +#[repr(transparent)] +pub struct TsBigS(BigS); + +#[repr(transparent)] +pub union TuBigS { + field: BigS, +} + +#[repr(transparent)] +pub enum TeBigS { + Variant(BigS), +} + +// CHECK: define{{.*}}void @test_BigS(ptr [[BIGS_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGS_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_BigS(_: BigS) -> BigS { loop {} } + +// CHECK: define{{.*}}void @test_TsBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} } + +// CHECK: define{{.*}}void @test_TuBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } + +// CHECK: define{{.*}}void @test_TeBigS(ptr [[BIGS_RET_ATTRS1]] sret([64 x i8]) [[BIGS_RET_ATTRS2]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } + + +#[repr(C)] +pub union BigU { + foo: [u32; 16], +} + +#[repr(transparent)] +pub struct TsBigU(BigU); + +#[repr(transparent)] +pub union TuBigU { + field: BigU, +} + +#[repr(transparent)] +pub enum TeBigU { + Variant(BigU), +} + +// CHECK: define{{.*}}void @test_BigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_BigU(_: BigU) -> BigU { loop {} } + +// CHECK: define{{.*}}void @test_TsBigU(ptr [[BIGU_RET_ATTRS1:.*]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} } + +// CHECK: define{{.*}}void @test_TuBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} } + +// CHECK: define{{.*}}void @test_TeBigU(ptr [[BIGU_RET_ATTRS1]] sret([64 x i8]) [[BIGU_RET_ATTRS2:.*]], ptr +// CHECK-NOT: byval +// CHECK-SAME: %{{[0-9a-z_]+}}) +#[no_mangle] +pub extern "C" fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} } diff --git a/tests/codegen/repr/transparent-struct-ptr.rs b/tests/codegen/repr/transparent-struct-ptr.rs index 0b85cdcd30f3a..26f0120752f2a 100644 --- a/tests/codegen/repr/transparent-struct-ptr.rs +++ b/tests/codegen/repr/transparent-struct-ptr.rs @@ -1,23 +1,36 @@ -//@ revisions: x32 x64 sparc sparc64 +//@ revisions: i686-linux i686-freebsd x64-linux x64-apple wasm32 //@ compile-flags: -O -C no-prepopulate-passes -// -//@[x32] only-x86 -//@[x64] only-x86_64 -//@[sparc] only-sparc -//@[sparc64] only-sparc64 -//@ ignore-windows + +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] needs-llvm-components: x86 +//@[i686-freebsd] compile-flags: --target i686-unknown-freebsd +//@[i686-freebsd] needs-llvm-components: x86 +//@[x64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x64-linux] needs-llvm-components: x86 +//@[x64-apple] compile-flags: --target x86_64-apple-darwin +//@[x64-apple] needs-llvm-components: x86 +//@[wasm32] compile-flags: --target wasm32-wasi +//@[wasm32] needs-llvm-components: webassembly + // See ./transparent.rs // Some platforms pass large aggregates using immediate arrays in LLVMIR // Other platforms pass large aggregates using struct pointer in LLVMIR // This covers the "struct pointer" case. +#![feature(no_core, lang_items, transparent_unions)] +#![crate_type = "lib"] +#![no_std] +#![no_core] -#![feature(transparent_unions)] +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } -#![crate_type="lib"] +impl Copy for [u32; 16] {} +impl Copy for BigS {} +impl Copy for BigU {} -#[derive(Clone, Copy)] #[repr(C)] pub struct BigS([u32; 16]); @@ -51,7 +64,6 @@ pub extern "C" fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} } pub extern "C" fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} } -#[derive(Clone, Copy)] #[repr(C)] pub union BigU { foo: [u32; 16], diff --git a/tests/codegen/repr/transparent-sysv64.rs b/tests/codegen/repr/transparent-sysv64.rs index 10524adf7d7a7..fe086179b9dc5 100644 --- a/tests/codegen/repr/transparent-sysv64.rs +++ b/tests/codegen/repr/transparent-sysv64.rs @@ -1,8 +1,21 @@ -//@ only-x86_64 - +//@ revisions: linux apple windows //@ compile-flags: -C no-prepopulate-passes -#![crate_type="lib"] +//@[linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux] needs-llvm-components: x86 +//@[apple] compile-flags: --target x86_64-apple-darwin +//@[apple] needs-llvm-components: x86 +//@[windows] compile-flags: --target x86_64-pc-windows-msvc +//@[windows] needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } #[repr(C)] pub struct Rgb8 { r: u8, g: u8, b: u8 }