Author: Harald van Dijk Date: 2025-04-18T02:11:02+01:00 New Revision: ca9ec7dfc3a5ebad9e5c25b30511b2ed73287f61
URL: https://github.com/llvm/llvm-project/commit/ca9ec7dfc3a5ebad9e5c25b30511b2ed73287f61 DIFF: https://github.com/llvm/llvm-project/commit/ca9ec7dfc3a5ebad9e5c25b30511b2ed73287f61.diff LOG: [ARM, AArch64] Fix passing of structures with aligned base classes (#135564) RecordLayout::UnadjustedAlignment was documented as "Maximum of the alignments of the record members in characters", but RecordLayout::getUnadjustedAlignment(), which just returns UnadjustedAlignment, was documented as getting "the record alignment in characters, before alignment adjustement." These are not the same thing: the former excludes alignment of base classes, the latter takes it into account. ItaniumRecordLayoutBuilder::LayoutBase was setting it according to the former, but the AAPCS calling convention handling, currently the only user, relies on it being set according to the latter. Fixes #135551. Added: Modified: clang/include/clang/AST/RecordLayout.h clang/lib/AST/RecordLayoutBuilder.cpp clang/test/CodeGen/AArch64/args.cpp clang/test/CodeGen/aapcs64-align.cpp clang/test/CodeGen/arm-vfp16-arguments2.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h index dd18f9c49f84f..6cf08e76396e2 100644 --- a/clang/include/clang/AST/RecordLayout.h +++ b/clang/include/clang/AST/RecordLayout.h @@ -75,8 +75,9 @@ class ASTRecordLayout { // performance or backwards compatibility preserving (e.g. AIX-ABI). CharUnits PreferredAlignment; - // UnadjustedAlignment - Maximum of the alignments of the record members in - // characters. + // UnadjustedAlignment - Alignment of record in characters before alignment + // adjustments. Maximum of the alignments of the record members and base + // classes in characters. CharUnits UnadjustedAlignment; /// RequiredAlignment - The required alignment of the object. In the MS-ABI @@ -186,7 +187,7 @@ class ASTRecordLayout { CharUnits getPreferredAlignment() const { return PreferredAlignment; } /// getUnadjustedAlignment - Get the record alignment in characters, before - /// alignment adjustement. + /// alignment adjustment. CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; } /// getSize - Get the record size in characters. diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index ea353f88a8aec..dd932f6179f88 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -1302,6 +1302,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { setSize(std::max(getSize(), Offset + Layout.getSize())); // Remember max struct/class alignment. + UnadjustedAlignment = std::max(UnadjustedAlignment, BaseAlign); UpdateAlignment(BaseAlign, UnpackedAlignTo, PreferredBaseAlign); return Offset; diff --git a/clang/test/CodeGen/AArch64/args.cpp b/clang/test/CodeGen/AArch64/args.cpp index 6f1f3d5e2a062..3cb62d3119ecf 100644 --- a/clang/test/CodeGen/AArch64/args.cpp +++ b/clang/test/CodeGen/AArch64/args.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,DARWIN -// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefixes=CHECK,C -// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CXX +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefixes=CHECK,C,AAPCS +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CXX,AAPCS // Empty structs are ignored for PCS purposes on Darwin and in C mode elsewhere. // In C++ mode on ELF they consume a register slot though. Functions are @@ -110,3 +110,110 @@ EXTERNC struct SortOfEmpty sort_of_empty_arg_variadic(int a, ...) { return b; } +// Base case, nothing interesting. +struct S { + long x, y; +}; + +// CHECK-LABEL: @g_S( +// CHECK: call void @f_S(i64 noundef 1, [2 x i64] {{.*}}) +// CHECK: call void @fm_S(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, [2 x i64] {{.*}}) +EXTERNC void f_S(long, struct S); +EXTERNC void fm_S(long, long, long, long, long, struct S); +EXTERNC void g_S() { + struct S s = {6, 7}; + f_S(1, s); + fm_S(1, 2, 3, 4, 5, s); +} + +// Aligned struct passed according to its natural alignment. +struct __attribute__((aligned(16))) S16 { + long x, y; +}; + +// CHECK-LABEL: @g_S16( +// DARWIN: call void @f_S16(i64 noundef 1, i128 {{.*}}) +// AAPCS: call void @f_S16(i64 noundef 1, [2 x i64] {{.*}}) +// DARWIN: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}}) +// AAPCS: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, [2 x i64] {{.*}}) +EXTERNC void f_S16(long, struct S16); +EXTERNC void fm_S16(long, long, long, long, long, struct S16); +EXTERNC void g_S16() { + struct S16 s = {6, 7}; + f_S16(1, s); + fm_S16(1, 2, 3, 4, 5, s); +} + +// Aligned struct with increased natural alignment through an aligned field. +struct SF16 { + __attribute__((aligned(16))) long x; + long y; +}; + +// CHECK-LABEL: @g_SF16( +// DARWIN: call void @f_SF16(i64 noundef 1, i128 {{.*}}) +// AAPCS: call void @f_SF16(i64 noundef 1, i128 {{.*}}) +// DARWIN: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}}) +// AAPCS: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}}) +EXTERNC void f_SF16(long, struct SF16); +EXTERNC void fm_SF16(long, long, long, long, long, struct SF16); +EXTERNC void g_SF16() { + struct SF16 s = {6, 7}; + f_SF16(1, s); + fm_SF16(1, 2, 3, 4, 5, s); +} + +#ifdef __cplusplus +// Aligned struct with increased natural alignment through an aligned base class. +struct SB16 : S16 {}; + +// DARWIN-LABEL: @g_SB16( +// CXX-LABEL: @g_SB16( +// DARWIN: call void @f_SB16(i64 noundef 1, i128 {{.*}}) +// CXX: call void @f_SB16(i64 noundef 1, i128 {{.*}}) +// DARWIN: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}}) +// CXX: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}}) +EXTERNC void f_SB16(long, struct SB16); +EXTERNC void fm_SB16(long, long, long, long, long, struct SB16); +EXTERNC void g_SB16() { + struct SB16 s = {6, 7}; + f_SB16(1, s); + fm_SB16(1, 2, 3, 4, 5, s); +} +#endif + +// Packed structure. +struct __attribute__((packed)) SP { + int x; + long y; +}; + +// CHECK-LABEL: @g_SP( +// CHECK: call void @f_SP(i32 noundef 1, [2 x i64] {{.*}}) +// CHECK: call void @fm_SP(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] {{.*}}) +EXTERNC void f_SP(int, struct SP); +EXTERNC void fm_SP(int, int, int, int, int, struct SP); +EXTERNC void g_SP() { + struct SP s = {6, 7}; + f_SP(1, s); + fm_SP(1, 2, 3, 4, 5, s); +} + +// Packed structure, overaligned, same as above. +struct __attribute__((packed, aligned(16))) SP16 { + int x; + long y; +}; + +// CHECK-LABEL: @g_SP16( +// DARWIN: call void @f_SP16(i32 noundef 1, i128 {{.*}}) +// AAPCS: call void @f_SP16(i32 noundef 1, [2 x i64] {{.*}}) +// DARWIN: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i128 {{.*}}) +// AAPCS: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] {{.*}}) +EXTERNC void f_SP16(int, struct SP16); +EXTERNC void fm_SP16(int, int, int, int, int, struct SP16); +EXTERNC void g_SP16() { + struct SP16 s = {6, 7}; + f_SP16(1, s); + fm_SP16(1, 2, 3, 4, 5, s); +} diff --git a/clang/test/CodeGen/aapcs64-align.cpp b/clang/test/CodeGen/aapcs64-align.cpp index e69faf231936c..1c26d68e434f4 100644 --- a/clang/test/CodeGen/aapcs64-align.cpp +++ b/clang/test/CodeGen/aapcs64-align.cpp @@ -12,101 +12,6 @@ extern "C" { // CHECK: @sizeof_RidiculouslyOverSizedBitfield ={{.*}} global i32 32 // CHECK: @alignof_RidiculouslyOverSizedBitfield ={{.*}} global i32 16 -// Base case, nothing interesting. -struct S { - long x, y; -}; - -void f0(long, S); -void f0m(long, long, long, long, long, S); -void g0() { - S s = {6, 7}; - f0(1, s); - f0m(1, 2, 3, 4, 5, s); -} -// CHECK: define{{.*}} void @g0 -// CHECK: call void @f0(i64 noundef 1, [2 x i64] [i64 6, i64 7] -// CHECK: call void @f0m{{.*}}[2 x i64] [i64 6, i64 7] -// CHECK: declare void @f0(i64 noundef, [2 x i64]) -// CHECK: declare void @f0m(i64 noundef, i64 noundef, i64 noundef, i64 noundef, i64 noundef, [2 x i64]) - -// Aligned struct, passed according to its natural alignment. -struct __attribute__((aligned(16))) S16 { - long x, y; -} s16; - -void f1(long, S16); -void f1m(long, long, long, long, long, S16); -void g1() { - S16 s = {6, 7}; - f1(1, s); - f1m(1, 2, 3, 4, 5, s); -} -// CHECK: define{{.*}} void @g1 -// CHECK: call void @f1{{.*}}[2 x i64] [i64 6, i64 7] -// CHECK: call void @f1m{{.*}}[2 x i64] [i64 6, i64 7] -// CHECK: declare void @f1(i64 noundef, [2 x i64]) -// CHECK: declare void @f1m(i64 noundef, i64 noundef, i64 noundef, i64 noundef, i64 noundef, [2 x i64]) - -// Increased natural alignment. -struct SF16 { - long x __attribute__((aligned(16))); - long y; -}; - -void f3(long, SF16); -void f3m(long, long, long, long, long, SF16); -void g3() { - SF16 s = {6, 7}; - f3(1, s); - f3m(1, 2, 3, 4, 5, s); -} -// CHECK: define{{.*}} void @g3 -// CHECK: call void @f3(i64 noundef 1, i128 129127208515966861318) -// CHECK: call void @f3m(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 129127208515966861318) -// CHECK: declare void @f3(i64 noundef, i128) -// CHECK: declare void @f3m(i64 noundef, i64 noundef, i64 noundef, i64 noundef, i64 noundef, i128) - - -// Packed structure. -struct __attribute__((packed)) P { - int x; - long u; -}; - -void f4(int, P); -void f4m(int, int, int, int, int, P); -void g4() { - P s = {6, 7}; - f4(1, s); - f4m(1, 2, 3, 4, 5, s); -} -// CHECK: define{{.*}} void @g4() -// CHECK: call void @f4(i32 noundef 1, [2 x i64] [i64 30064771078, i64 0]) -// CHECK: void @f4m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] [i64 30064771078, i64 0]) -// CHECK: declare void @f4(i32 noundef, [2 x i64]) -// CHECK: declare void @f4m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i64]) - - -// Packed structure, overaligned, same as above. -struct __attribute__((packed, aligned(16))) P16 { - int x; - long y; -}; - -void f5(int, P16); -void f5m(int, int, int, int, int, P16); - void g5() { - P16 s = {6, 7}; - f5(1, s); - f5m(1, 2, 3, 4, 5, s); -} -// CHECK: define{{.*}} void @g5() -// CHECK: call void @f5(i32 noundef 1, [2 x i64] [i64 30064771078, i64 0]) -// CHECK: void @f5m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] [i64 30064771078, i64 0]) -// CHECK: declare void @f5(i32 noundef, [2 x i64]) -// CHECK: declare void @f5m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i64]) - //BitInt alignment struct BITINT129 { char ch; diff --git a/clang/test/CodeGen/arm-vfp16-arguments2.cpp b/clang/test/CodeGen/arm-vfp16-arguments2.cpp index 6e9a24e70c141..7273f64effa92 100644 --- a/clang/test/CodeGen/arm-vfp16-arguments2.cpp +++ b/clang/test/CodeGen/arm-vfp16-arguments2.cpp @@ -42,7 +42,7 @@ struct S5 : B1 { // CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S1 @_Z2f12S1(%struct.S1 returned %s1.coerce) struct S1 f1(struct S1 s1) { return s1; } -// CHECK-SOFT: define{{.*}} void @_Z2f22S2(ptr dead_on_unwind noalias writable writeonly sret(%struct.S2) align 8 captures(none) initializes((0, 16)) %agg.result, [4 x i32] %s2.coerce) +// CHECK-SOFT: define{{.*}} void @_Z2f22S2(ptr dead_on_unwind noalias writable writeonly sret(%struct.S2) align 8 captures(none) initializes((0, 16)) %agg.result, [2 x i64] %s2.coerce) // CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f22S2([2 x <2 x i32>] returned %s2.coerce) // CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S2 @_Z2f22S2(%struct.S2 %s2.coerce) struct S2 f2(struct S2 s2) { return s2; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits