[clang] [AArch64] Change the coercion type of structs with pointer members. (PR #135064)
David Green via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 10 09:20:33 PDT 2025
https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/135064
>From 33a204bcc884178971c4327528b1e3b75336914e Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 9 Apr 2025 11:18:25 +0100
Subject: [PATCH 1/4] [AArch64] Add a test case for the coerced arguments. NFC
---
.../AArch64/struct-coerce-using-ptr.cpp | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
diff --git a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
new file mode 100644
index 0000000000000..295a5158f7e97
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
@@ -0,0 +1,94 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple aarch64-none-elf -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+
+struct Sp {
+ int *x;
+};
+// CHECK-LABEL: define dso_local void @_Z2Tp2Sp(
+// CHECK-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 8
+// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr
+// CHECK-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8
+// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-NEXT: ret void
+//
+void Tp(Sp s) { *s.x = 1; }
+
+struct Spp {
+ int *x, *y;
+};
+// CHECK-LABEL: define dso_local void @_Z3Tpp3Spp(
+// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 8
+// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-NEXT: ret void
+//
+void Tpp(Spp s) { *s.x = 1; }
+
+struct Sppp {
+ int *x, *y, *z;
+};
+// CHECK-LABEL: define dso_local void @_Z4Tppp4Sppp(
+// CHECK-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[S_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: store ptr [[S]], ptr [[S_INDIRECT_ADDR]], align 8
+// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPP:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-NEXT: ret void
+//
+void Tppp(Sppp s) { *s.x = 1; }
+
+struct Spi {
+ int *x, y;
+};
+// CHECK-LABEL: define dso_local void @_Z3Tpi3Spi(
+// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPI:%.*]], align 8
+// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPI]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-NEXT: ret void
+//
+void Tpi(Spi s) { *s.x = 1; }
+
+struct Srp {
+ int &x, *y;
+};
+// CHECK-LABEL: define dso_local void @_Z3Trp3Srp(
+// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8
+// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-NEXT: ret void
+//
+void Trp(Srp s) { s.x = 1; }
+
+struct __attribute__((__packed__)) Spp_packed {
+ int *x, *y;
+};
+// CHECK-LABEL: define dso_local void @_Z10Tpp_packed10Spp_packed(
+// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
+// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 1
+// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
+// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-NEXT: ret void
+//
+void Tpp_packed(Spp_packed s) { *s.x = 1; }
>From 662912d1559a23f91915e996ff0de3cd10ac99d8 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 9 Apr 2025 19:07:04 +0100
Subject: [PATCH 2/4] [AArch64] Change the coercion type of structs with
pointer members.
The aim here is to avoid a ptrtoint->inttoptr round-trip throught the function
argument whilst keeping the calling convention the same. Given a struct which
is <= 128bits in size, which can only contain either 1 or 2 pointers, we
convert to a ptr or [2 x ptr] as opposed to the old coercion that uses i64 or
[2 x i64].
---
clang/lib/CodeGen/Targets/AArch64.cpp | 18 ++++++++++++++++++
.../AArch64/struct-coerce-using-ptr.cpp | 17 ++++++++---------
clang/test/CodeGenCXX/trivial_abi.cpp | 13 +++++--------
3 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 073ca3cc82690..9dc5f824254eb 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -485,6 +485,24 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn,
}
Size = llvm::alignTo(Size, Alignment);
+ // If the Aggregate is made up of pointers, use an array of pointers for the
+ // coerced type. This prevents having to convert ptr2int->int2ptr through
+ // the call, allowing alias analysis to produce better code.
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (const RecordDecl *RD = RT->getDecl()) {
+ if (all_of(RD->fields(), [](FieldDecl *FD) {
+ return FD->getType()->isPointerOrReferenceType();
+ })) {
+ assert((Size == 64 || Size == 128) &&
+ "Expected a 64 or 128bit struct containing pointers");
+ llvm::Type *PtrTy = llvm::PointerType::getUnqual(getVMContext());
+ if (Size == 128)
+ PtrTy = llvm::ArrayType::get(PtrTy, 2);
+ return ABIArgInfo::getDirect(PtrTy);
+ }
+ }
+ }
+
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
// For aggregates with 16-byte alignment, we use i128.
llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment);
diff --git a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
index 295a5158f7e97..c2d68ae7ef6cd 100644
--- a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
+++ b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
@@ -5,12 +5,11 @@ struct Sp {
int *x;
};
// CHECK-LABEL: define dso_local void @_Z2Tp2Sp(
-// CHECK-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 8
// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr
-// CHECK-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8
+// CHECK-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -22,10 +21,10 @@ struct Spp {
int *x, *y;
};
// CHECK-LABEL: define dso_local void @_Z3Tpp3Spp(
-// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 8
-// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -67,10 +66,10 @@ struct Srp {
int &x, *y;
};
// CHECK-LABEL: define dso_local void @_Z3Trp3Srp(
-// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8
-// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -82,10 +81,10 @@ struct __attribute__((__packed__)) Spp_packed {
int *x, *y;
};
// CHECK-LABEL: define dso_local void @_Z10Tpp_packed10Spp_packed(
-// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
-// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 1
+// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 1
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
diff --git a/clang/test/CodeGenCXX/trivial_abi.cpp b/clang/test/CodeGenCXX/trivial_abi.cpp
index 90054dbf37ae3..b8cc0d1cc6528 100644
--- a/clang/test/CodeGenCXX/trivial_abi.cpp
+++ b/clang/test/CodeGenCXX/trivial_abi.cpp
@@ -68,11 +68,10 @@ struct D0 : B0, B1 {
Small D0::m0() { return {}; }
-// CHECK: define{{.*}} void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
+// CHECK: define{{.*}} void @_Z14testParamSmall5Small(ptr %[[A_COERCE:.*]])
// CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[A]], i32 0, i32 0
-// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to ptr
-// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
+// CHECK: store ptr %[[A_COERCE]], ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[A]])
// CHECK: ret void
// CHECK: }
@@ -101,8 +100,7 @@ Small testReturnSmall() {
// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5SmallC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(8) %[[T]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
-// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
-// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
+// CHECK: call void @_Z14testParamSmall5Small(ptr %[[V0]])
// CHECK: %[[CALL2:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[T]])
// CHECK: ret void
// CHECK: }
@@ -120,8 +118,7 @@ void testCallSmall0() {
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE1]], align 8
-// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
-// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
+// CHECK: call void @_Z14testParamSmall5Small(ptr %[[V0]])
// CHECK: ret void
// CHECK: }
@@ -226,7 +223,7 @@ NonTrivial testReturnHasNonTrivial() {
// CHECK: call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
// CHECK: invoke noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP1]])
-// CHECK: call void @_Z20calleeExceptionSmall5SmallS_(i64 %{{.*}}, i64 %{{.*}})
+// CHECK: call void @_Z20calleeExceptionSmall5SmallS_(ptr %{{.*}}, ptr %{{.*}})
// CHECK-NEXT: ret void
// CHECK: landingpad { ptr, i32 }
>From 4277570fb3374568cae5e1acf321c9751c7c35e7 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Thu, 10 Apr 2025 16:56:35 +0100
Subject: [PATCH 3/4] Test update
---
.../AArch64/struct-coerce-using-ptr.cpp | 461 +++++++++++++++---
1 file changed, 405 insertions(+), 56 deletions(-)
diff --git a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
index c2d68ae7ef6cd..efbf6cb04de95 100644
--- a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
+++ b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
@@ -1,93 +1,442 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
-// RUN: %clang_cc1 -triple aarch64-none-elf -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-elf -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-A64
+// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-A64_32
struct Sp {
int *x;
};
-// CHECK-LABEL: define dso_local void @_Z2Tp2Sp(
-// CHECK-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 8
-// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
-// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
-// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
-// CHECK-NEXT: ret void
+// CHECK-A64-LABEL: define dso_local void @_Z2Tp2Sp(
+// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 8
+// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z2Tp2Sp(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
//
void Tp(Sp s) { *s.x = 1; }
struct Spp {
int *x, *y;
};
-// CHECK-LABEL: define dso_local void @_Z3Tpp3Spp(
-// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 8
-// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
-// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
-// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
-// CHECK-NEXT: ret void
+// CHECK-A64-LABEL: define dso_local void @_Z3Tpp3Spp(
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z3Tpp3Spp(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
//
void Tpp(Spp s) { *s.x = 1; }
struct Sppp {
int *x, *y, *z;
};
-// CHECK-LABEL: define dso_local void @_Z4Tppp4Sppp(
-// CHECK-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[S_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT: store ptr [[S]], ptr [[S_INDIRECT_ADDR]], align 8
-// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPP:%.*]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
-// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
-// CHECK-NEXT: ret void
+// CHECK-A64-LABEL: define dso_local void @_Z4Tppp4Sppp(
+// CHECK-A64-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-A64-NEXT: store ptr [[S]], ptr [[S_INDIRECT_ADDR]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPP:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z4Tppp4Sppp(
+// CHECK-A64_32-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPPP:%.*]], align 4
+// CHECK-A64_32-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
//
void Tppp(Sppp s) { *s.x = 1; }
struct Spi {
int *x, y;
};
-// CHECK-LABEL: define dso_local void @_Z3Tpi3Spi(
-// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPI:%.*]], align 8
-// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
-// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPI]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
-// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
-// CHECK-NEXT: ret void
+// CHECK-A64-LABEL: define dso_local void @_Z3Tpi3Spi(
+// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPI:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPI]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z3Tpi3Spi(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPI:%.*]], align 4
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPI]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
//
void Tpi(Spi s) { *s.x = 1; }
struct Srp {
int &x, *y;
};
-// CHECK-LABEL: define dso_local void @_Z3Trp3Srp(
-// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8
-// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
-// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
-// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
-// CHECK-NEXT: ret void
+// CHECK-A64-LABEL: define dso_local void @_Z3Trp3Srp(
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z3Trp3Srp(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
//
void Trp(Srp s) { s.x = 1; }
struct __attribute__((__packed__)) Spp_packed {
int *x, *y;
};
-// CHECK-LABEL: define dso_local void @_Z10Tpp_packed10Spp_packed(
-// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
-// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 1
-// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
-// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
-// CHECK-NEXT: ret void
+// CHECK-A64-LABEL: define dso_local void @_Z10Tpp_packed10Spp_packed(
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 1
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z10Tpp_packed10Spp_packed(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 1
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
//
void Tpp_packed(Spp_packed s) { *s.x = 1; }
+
+union Upp {
+ int *x;
+ long long *y;
+};
+// CHECK-A64-LABEL: define dso_local void @_Z11Tupp_packed3Upp(
+// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[UNION_UPP:%.*]], align 8
+// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_UPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z11Tupp_packed3Upp(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[UNION_UPP:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_UPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void Tupp_packed(Upp s) { *s.x = 1; }
+
+union USpp {
+ Spp s;
+ long long y;
+};
+// CHECK-A64-LABEL: define dso_local void @_Z12TUSpp_packed4USpp(
+// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[UNION_USPP:%.*]], align 8
+// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_USPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z12TUSpp_packed4USpp(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[UNION_USPP:%.*]], align 8
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_USPP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void TUSpp_packed(USpp s) { *s.s.x = 1; }
+
+struct Spf {
+ int *x;
+ int z[];
+};
+// CHECK-A64-LABEL: define dso_local void @_Z3Tpf3Spf(
+// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPF:%.*]], align 8
+// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPF]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr
+// CHECK-A64-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPF]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z3Tpf3Spf(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPF:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPF]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32
+// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPF]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void Tpf(Spf s) { *s.x = 1; }
+
+struct Sppf {
+ int *x, *y;
+ int z[];
+};
+// CHECK-A64-LABEL: define dso_local void @_Z4Tppf4Sppf(
+// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPPF:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPF]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z4Tppf4Sppf(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPPF:%.*]], align 4
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPF]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void Tppf(Sppf s) { *s.x = 1; }
+
+struct SSpSp {
+ struct Sp a, b;
+};
+// CHECK-A64-LABEL: define dso_local void @_Z5TSpSp5SSpSp(
+// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPSP:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPSP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[A]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z5TSpSp5SSpSp(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPSP:%.*]], align 4
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPSP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[A]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void TSpSp(SSpSp s) { *s.a.x = 1; }
+
+struct SSp : public Sp {
+ int* b;
+};
+// CHECK-A64-LABEL: define dso_local void @_Z3TSp3SSp(
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSP:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z3TSp3SSp(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSP:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[COERCE_DIVE]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE1]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void TSp(SSp s) { *s.x = 1; }
+
+struct Si {
+ int x;
+};
+struct SSpi : public Si {
+ int* y;
+};
+// CHECK-A64-LABEL: define dso_local void @_Z4TSpi4SSpi(
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPI:%.*]], align 8
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: store i32 1, ptr [[X]], align 8
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z4TSpi4SSpi(
+// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPI:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPI]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[COERCE_DIVE]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE1]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store i32 1, ptr [[X]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void TSpi(SSpi s) { s.x = 1; }
+
+struct Spa {
+ int* xs[1];
+};
+// CHECK-A64-LABEL: define dso_local void @_Z3Tpa3Spa(
+// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA:%.*]], align 8
+// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1 x ptr], ptr [[XS]], i64 0, i64 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z3Tpa3Spa(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32
+// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1 x ptr], ptr [[XS]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void Tpa(Spa s) { *s.xs[0] = 1; }
+
+struct Spa2 {
+ int* xs[2];
+};
+// CHECK-A64-LABEL: define dso_local void @_Z4Tpa24Spa2(
+// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA2:%.*]], align 8
+// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr], ptr [[XS]], i64 0, i64 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z4Tpa24Spa2(
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA2:%.*]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr], ptr [[XS]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void Tpa2(Spa2 s) { *s.xs[0] = 1; }
+
+struct Spa3 {
+ int* xs[3];
+};
+// CHECK-A64-LABEL: define dso_local void @_Z4Tpa34Spa3(
+// CHECK-A64-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] {
+// CHECK-A64-NEXT: [[ENTRY:.*:]]
+// CHECK-A64-NEXT: [[S_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-A64-NEXT: store ptr [[S]], ptr [[S_INDIRECT_ADDR]], align 8
+// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA3:%.*]], ptr [[S]], i32 0, i32 0
+// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x ptr], ptr [[XS]], i64 0, i64 0
+// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
+// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64-NEXT: ret void
+//
+// CHECK-A64_32-LABEL: define void @_Z4Tpa34Spa3(
+// CHECK-A64_32-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
+// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA3:%.*]], align 4
+// CHECK-A64_32-NEXT: [[TMP_COERCE:%.*]] = alloca [2 x i64], align 8
+// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA3]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store [2 x i64] [[S_COERCE]], ptr [[TMP_COERCE]], align 8
+// CHECK-A64_32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[COERCE_DIVE]], ptr align 8 [[TMP_COERCE]], i32 12, i1 false)
+// CHECK-A64_32-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA3]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x ptr], ptr [[XS]], i32 0, i32 0
+// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 4
+// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
+// CHECK-A64_32-NEXT: ret void
+//
+void Tpa3(Spa3 s) { *s.xs[0] = 1; }
+
+//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+// CHECK: {{.*}}
>From 6d0fa9f764219f759bb9fb882cdbad75dc0748e3 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Thu, 10 Apr 2025 17:20:18 +0100
Subject: [PATCH 4/4] Update to recursive check fields, check bases, exclude
aarch64_32, more tests.
---
clang/lib/CodeGen/Targets/AArch64.cpp | 37 +++++++----
.../AArch64/struct-coerce-using-ptr.cpp | 63 +++++++++----------
2 files changed, 55 insertions(+), 45 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 9dc5f824254eb..61ac69c39c89b 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -488,19 +488,32 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn,
// If the Aggregate is made up of pointers, use an array of pointers for the
// coerced type. This prevents having to convert ptr2int->int2ptr through
// the call, allowing alias analysis to produce better code.
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- if (const RecordDecl *RD = RT->getDecl()) {
- if (all_of(RD->fields(), [](FieldDecl *FD) {
- return FD->getType()->isPointerOrReferenceType();
- })) {
- assert((Size == 64 || Size == 128) &&
- "Expected a 64 or 128bit struct containing pointers");
- llvm::Type *PtrTy = llvm::PointerType::getUnqual(getVMContext());
- if (Size == 128)
- PtrTy = llvm::ArrayType::get(PtrTy, 2);
- return ABIArgInfo::getDirect(PtrTy);
- }
+ std::function<bool(QualType Ty)> ContainsOnlyPointers = [&](QualType Ty) {
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT)
+ return false;
+ const RecordDecl *RD = RT->getDecl();
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const auto &I : CXXRD->bases())
+ if (!ContainsOnlyPointers(I.getType()))
+ return false;
}
+ return all_of(RD->fields(), [&](FieldDecl *FD) {
+ QualType FDTy = FD->getType();
+ return FDTy->isPointerOrReferenceType() ||
+ (FDTy->isArrayType() &&
+ FDTy->getBaseElementTypeUnsafe()->isPointerOrReferenceType()) ||
+ ContainsOnlyPointers(FDTy);
+ });
+ };
+ if (getTarget().getTriple().getArch() != llvm::Triple::aarch64_32 &&
+ ContainsOnlyPointers(Ty)) {
+ assert((Size == 64 || Size == 128) &&
+ "Expected a 64 or 128bit struct containing pointers");
+ llvm::Type *PtrTy = llvm::PointerType::getUnqual(getVMContext());
+ if (Size == 128)
+ PtrTy = llvm::ArrayType::get(PtrTy, 2);
+ return ABIArgInfo::getDirect(PtrTy);
}
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
diff --git a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
index efbf6cb04de95..e8b17a91b3302 100644
--- a/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
+++ b/clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
@@ -17,11 +17,12 @@ struct Sp {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z2Tp2Sp(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 4
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32
+// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -43,11 +44,10 @@ struct Spp {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z3Tpp3Spp(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 4
-// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -69,10 +69,12 @@ struct Sppp {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z4Tppp4Sppp(
-// CHECK-A64_32-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPPP:%.*]], align 4
-// CHECK-A64_32-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[TMP_COERCE:%.*]] = alloca [2 x i64], align 8
+// CHECK-A64_32-NEXT: store [2 x i64] [[S_COERCE]], ptr [[TMP_COERCE]], align 8
+// CHECK-A64_32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[S]], ptr align 8 [[TMP_COERCE]], i32 12, i1 false)
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPP]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -119,11 +121,10 @@ struct Srp {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z3Trp3Srp(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 4
-// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -145,11 +146,10 @@ struct __attribute__((__packed__)) Spp_packed {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z10Tpp_packed10Spp_packed(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
-// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 1
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 1
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -172,11 +172,12 @@ union Upp {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z11Tupp_packed3Upp(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[UNION_UPP:%.*]], align 4
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_UPP]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
+// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32
+// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 4
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
// CHECK-A64_32-NEXT: ret void
@@ -271,10 +272,10 @@ struct SSpSp {
struct Sp a, b;
};
// CHECK-A64-LABEL: define dso_local void @_Z5TSpSp5SSpSp(
-// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64-NEXT: [[ENTRY:.*:]]
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPSP:%.*]], align 8
-// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
// CHECK-A64-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPSP]], ptr [[S]], i32 0, i32 0
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[A]], i32 0, i32 0
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
@@ -308,13 +309,11 @@ struct SSp : public Sp {
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z3TSp3SSp(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSP:%.*]], align 4
-// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSP]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[COERCE_DIVE]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE1]], align 4
-// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
// CHECK-A64_32-NEXT: ret void
@@ -328,22 +327,20 @@ struct SSpi : public Si {
int* y;
};
// CHECK-A64-LABEL: define dso_local void @_Z4TSpi4SSpi(
-// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64-NEXT: [[ENTRY:.*:]]
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPI:%.*]], align 8
-// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
+// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[S]], i32 0, i32 0
// CHECK-A64-NEXT: store i32 1, ptr [[X]], align 8
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z4TSpi4SSpi(
-// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPI:%.*]], align 4
-// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPI]], ptr [[S]], i32 0, i32 0
-// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[COERCE_DIVE]], i32 0, i32 0
-// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE1]], align 4
-// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI]], ptr [[S]], i32 0, i32 0
+// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
+// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: store i32 1, ptr [[X]], align 4
// CHECK-A64_32-NEXT: ret void
//
@@ -353,11 +350,11 @@ struct Spa {
int* xs[1];
};
// CHECK-A64-LABEL: define dso_local void @_Z3Tpa3Spa(
-// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64-NEXT: [[ENTRY:.*:]]
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA:%.*]], align 8
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
-// CHECK-A64-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1 x ptr], ptr [[XS]], i64 0, i64 0
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
@@ -383,11 +380,11 @@ struct Spa2 {
int* xs[2];
};
// CHECK-A64-LABEL: define dso_local void @_Z4Tpa24Spa2(
-// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64-NEXT: [[ENTRY:.*:]]
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA2:%.*]], align 8
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
-// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
+// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr], ptr [[XS]], i64 0, i64 0
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
More information about the cfe-commits
mailing list