[clang] fix: C++ empty record with align lead to va_list out of sync (PR #72197)

via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 24 22:31:44 PST 2023


https://github.com/hstk30-hw updated https://github.com/llvm/llvm-project/pull/72197

>From 2c8d9c8dcd9780749b788bc3029fc45373007ae0 Mon Sep 17 00:00:00 2001
From: hstk30-hw <hanwei62 at huawei.com>
Date: Sat, 18 Nov 2023 11:00:29 +0000
Subject: [PATCH] fix: empty record size > 64 with align let va_list get out of
 sync

---
 clang/lib/CodeGen/Targets/AArch64.cpp         |  9 +++++---
 clang/test/CodeGen/aarch64-args.cpp           | 23 +++++++++++++++++--
 .../CodeGen/arm64-microsoft-arguments.cpp     |  4 ++--
 clang/test/CodeGenCXX/aarch64-arguments.cpp   |  2 +-
 clang/test/CodeGenCXX/arm64-darwinpcs.cpp     |  2 +-
 5 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index be5145daa00b7f5..d0df2813dd72f6a 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -295,8 +295,12 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic,
                                      CGCXXABI::RAA_DirectInMemory);
   }
 
-  // Empty records are always ignored on Darwin, but actually passed in C++ mode
-  // elsewhere for GNU compatibility.
+  // AAPCS64 does not say that empty records are ignored as arguments,
+  // but other compilers do so in certain situations, and we copy that behavior.
+  // Those situations are in fact language-mode-specific, which seems really
+  // unfortunate, but it's something we just have to accept. If this doesn't
+  // apply, just fall through to the standard argument-handling path.
+  // Darwin overrides the psABI here to ignore all empty records in all modes.
   uint64_t Size = getContext().getTypeSize(Ty);
   bool IsEmpty = isEmptyRecord(getContext(), Ty, true);
   if (IsEmpty || Size == 0) {
@@ -307,7 +311,6 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic,
     // 0.
     if (IsEmpty && Size == 0)
       return ABIArgInfo::getIgnore();
-    return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
   }
 
   // Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
diff --git a/clang/test/CodeGen/aarch64-args.cpp b/clang/test/CodeGen/aarch64-args.cpp
index fe1298cc683a404..709f916d7a677d1 100644
--- a/clang/test/CodeGen/aarch64-args.cpp
+++ b/clang/test/CodeGen/aarch64-args.cpp
@@ -17,7 +17,7 @@ struct Empty {};
 
 // CHECK: define{{.*}} i32 @empty_arg(i32 noundef %a)
 // CHECK-GNU-C: define{{.*}} i32 @empty_arg(i32 noundef %a)
-// CHECK-GNU-CXX: define{{.*}} i32 @empty_arg(i8 %e.coerce, i32 noundef %a)
+// CHECK-GNU-CXX: define{{.*}} i32 @empty_arg(i64 %e.coerce, i32 noundef %a)
 EXTERNC int empty_arg(struct Empty e, int a) {
   return a;
 }
@@ -53,7 +53,7 @@ struct SortOfEmpty {
 
 // CHECK: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)
 // CHECK-GNU-C: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)
-// CHECK-GNU-CXX: define{{.*}} i32 @sort_of_empty_arg(i8 %e.coerce, i32 noundef %a)
+// CHECK-GNU-CXX: define{{.*}} i32 @sort_of_empty_arg(i64 %e.coerce, i32 noundef %a)
 EXTERNC int sort_of_empty_arg(struct Empty e, int a) {
   return a;
 }
@@ -65,3 +65,22 @@ EXTERNC struct SortOfEmpty sort_of_empty_ret(void) {
   struct SortOfEmpty e;
   return e;
 }
+
+// CHECK-GNU-CXX: define{{.*}} i32 @empty_align8_arg(i64 %a.coerce, i32 noundef %b)
+struct EmptyAlign8 { int __attribute__((aligned(8))) : 0; };
+EXTERNC int empty_align8_arg(struct EmptyAlign8 a, int b) {
+  return b;
+}
+
+// CHECK-GNU-CXX: define{{.*}} i32 @empty_align16_arg(i128 %a.coerce, i32 noundef %b)
+struct EmptyAlign16 { long long int __attribute__((aligned(16))) : 0; };
+EXTERNC int empty_align16_arg(struct EmptyAlign16 a, int b) {
+  return b;
+}
+
+// CHECK-GNU-CXX: define{{.*}} i32 @empty_align32_arg(ptr noundef %a, i32 noundef %b)
+struct EmptyAlign32 { long long int __attribute__((aligned(32))) : 0; };
+EXTERNC int empty_align32_arg(struct EmptyAlign32 a, int b) {
+  return b;
+}
+
diff --git a/clang/test/CodeGen/arm64-microsoft-arguments.cpp b/clang/test/CodeGen/arm64-microsoft-arguments.cpp
index a9ae6911b16e339..f7370e9f5351c5b 100644
--- a/clang/test/CodeGen/arm64-microsoft-arguments.cpp
+++ b/clang/test/CodeGen/arm64-microsoft-arguments.cpp
@@ -57,7 +57,7 @@ S4 f4() {
 
 // Pass and return from instance method called from instance method.
 // CHECK: define {{.*}} void @{{.*}}bar at Q1{{.*}}(ptr {{[^,]*}} %this, ptr inreg noalias sret(%class.P1) align 1 %agg.result)
-// CHECK: call void {{.*}}foo at P1{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P1) align 1 %agg.result, i8 %0)
+// CHECK: call void {{.*}}foo at P1{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P1) align 1 %agg.result, i64 %coerce.val.ii)
 
 class P1 {
 public:
@@ -76,7 +76,7 @@ P1 Q1::bar() {
 
 // Pass and return from instance method called from free function.
 // CHECK: define {{.*}} void {{.*}}bar{{.*}}()
-// CHECK: call void {{.*}}foo at P2{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P2) align 1 %retval, i8 %0)
+// CHECK: call void {{.*}}foo at P2{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P2) align 1 %retval, i64 %coerce.val.ii)
 class P2 {
 public:
   P2 foo(P2 x);
diff --git a/clang/test/CodeGenCXX/aarch64-arguments.cpp b/clang/test/CodeGenCXX/aarch64-arguments.cpp
index ffb0cafa8882d28..3206e38ad0090f2 100644
--- a/clang/test/CodeGenCXX/aarch64-arguments.cpp
+++ b/clang/test/CodeGenCXX/aarch64-arguments.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple arm64-none-linux -emit-llvm -w -o - %s | FileCheck -check-prefix=PCS %s
 
-// PCS: define{{.*}} void @{{.*}}(i8 %a
+// PCS: define{{.*}} void @{{.*}}(i64 %a.coerce)
 struct s0 {};
 void f0(s0 a) {}
diff --git a/clang/test/CodeGenCXX/arm64-darwinpcs.cpp b/clang/test/CodeGenCXX/arm64-darwinpcs.cpp
index a0b0d9efdd4c4f7..ef0e2da3effac7a 100644
--- a/clang/test/CodeGenCXX/arm64-darwinpcs.cpp
+++ b/clang/test/CodeGenCXX/arm64-darwinpcs.cpp
@@ -7,7 +7,7 @@ void test_extensions(bool a, char b, short c) {}
 
 struct Empty {};
 void test_empty(Empty e) {}
-// CHECK: define{{.*}} void @_Z10test_empty5Empty(i8
+// CHECK: define{{.*}} void @_Z10test_empty5Empty(i64 %e.coerce)
 // CHECK-DARWIN: define{{.*}} void @_Z10test_empty5Empty()
 
 struct HFA {



More information about the cfe-commits mailing list