[clang] ca9ec7d - [ARM, AArch64] Fix passing of structures with aligned base classes (#135564)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 17 18:11:05 PDT 2025
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; }
More information about the cfe-commits
mailing list