[clang] [SystemZ][z/OS] Implement z/OS XPLINK ABI (PR #101024)
Abhina Sree via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 7 06:06:50 PDT 2024
https://github.com/abhina-sree updated https://github.com/llvm/llvm-project/pull/101024
>From 9d30fcbac4ecdc592663d20a2b18b6b4e2ee873e Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Mon, 29 Jul 2024 10:49:08 -0400
Subject: [PATCH 1/4] [SystemZ][z/OS] Implement z/OS XPLINK ABI
---
clang/lib/CodeGen/CodeGenModule.cpp | 2 +
clang/lib/CodeGen/TargetInfo.h | 4 +
clang/lib/CodeGen/Targets/SystemZ.cpp | 290 ++++++++++++++++++++++++++
clang/test/CodeGen/zos-abi.c | 247 ++++++++++++++++++++++
clang/test/CodeGen/zos-abi.cpp | 24 +++
5 files changed, 567 insertions(+)
create mode 100644 clang/test/CodeGen/zos-abi.c
create mode 100644 clang/test/CodeGen/zos-abi.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 63ed5b4dd0c31..49ff482168eb9 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -244,6 +244,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
case llvm::Triple::systemz: {
bool SoftFloat = CodeGenOpts.FloatABI == "soft";
bool HasVector = !SoftFloat && Target.getABI() == "vector";
+ if (Triple.getOS() == llvm::Triple::ZOS)
+ return createSystemZ_ZOS_TargetCodeGenInfo(CGM, HasVector, SoftFloat);
return createSystemZTargetCodeGenInfo(CGM, HasVector, SoftFloat);
}
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 8f17c053f4783..eaa303963e8ee 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -541,6 +541,10 @@ std::unique_ptr<TargetCodeGenInfo>
createSystemZTargetCodeGenInfo(CodeGenModule &CGM, bool HasVector,
bool SoftFloatABI);
+std::unique_ptr<TargetCodeGenInfo>
+createSystemZ_ZOS_TargetCodeGenInfo(CodeGenModule &CGM, bool HasVector,
+ bool SoftFloatABI);
+
std::unique_ptr<TargetCodeGenInfo>
createTCETargetCodeGenInfo(CodeGenModule &CGM);
diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 4d61f51379346..5bb91232a3285 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -10,6 +10,7 @@
#include "TargetInfo.h"
#include "clang/Basic/Builtins.h"
#include "llvm/IR/IntrinsicsS390.h"
+#include <optional>
using namespace clang;
using namespace clang::CodeGen;
@@ -532,9 +533,298 @@ bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty,
return false;
}
+//===----------------------------------------------------------------------===//
+// z/OS XPLINK ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ZOSXPLinkABIInfo : public ABIInfo {
+ const unsigned GPRBits = 64;
+ bool HasVector;
+
+public:
+ ZOSXPLinkABIInfo(CodeGenTypes &CGT, bool HV) : ABIInfo(CGT), HasVector(HV) {}
+
+ bool isPromotableIntegerType(QualType Ty) const;
+ bool isVectorArgumentType(QualType Ty) const;
+ bool isFPArgumentType(QualType Ty) const;
+ std::optional<QualType> getFPTypeOfComplexLikeType(QualType Ty) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType ArgTy, bool IsNamedArg) const;
+
+ void computeInfo(CGFunctionInfo &FI) const override {
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+
+ unsigned NumRequiredArgs = FI.getNumRequiredArgs();
+ unsigned ArgNo = 0;
+
+ for (auto &I : FI.arguments()) {
+ bool IsNamedArg = ArgNo < NumRequiredArgs;
+ I.info = classifyArgumentType(I.type, IsNamedArg);
+ ++ArgNo;
+ }
+ }
+
+ RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
+ AggValueSlot Slot) const override;
+};
+
+class ZOSXPLinkTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ ZOSXPLinkTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector)
+ : TargetCodeGenInfo(std::make_unique<ZOSXPLinkABIInfo>(CGT, HasVector)) {
+ SwiftInfo =
+ std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
+ }
+};
+
+} // namespace
+
+// Return true if the ABI requires Ty to be passed sign- or zero-
+// extended to 64 bits.
+bool ZOSXPLinkABIInfo::isPromotableIntegerType(QualType Ty) const {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ // Promotable integer types are required to be promoted by the ABI.
+ if (getContext().isPromotableIntegerType(Ty))
+ return true;
+
+ if (const auto *EIT = Ty->getAs<BitIntType>())
+ if (EIT->getNumBits() < 64)
+ return true;
+
+ // In addition to the usual promotable integer types, we also need to
+ // extend all 32-bit types, since the ABI requires promotion to 64 bits.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool ZOSXPLinkABIInfo::isVectorArgumentType(QualType Ty) const {
+ return (HasVector && Ty->isVectorType() &&
+ getContext().getTypeSize(Ty) <= 128);
+}
+
+bool ZOSXPLinkABIInfo::isFPArgumentType(QualType Ty) const {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+std::optional<QualType>
+ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
+ if (const RecordType *RT = Ty->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl();
+
+ // Check for non-empty base classes.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ if (CXXRD->hasDefinition())
+ for (const auto &I : CXXRD->bases()) {
+ QualType Base = I.getType();
+ if (!isEmptyRecord(getContext(), Base, true))
+ return std::nullopt;
+ }
+
+ // Check for exactly two elements with exactly the same floating point type.
+ // A single-element struct containing only a float, double, or long double
+ // counts as a field of that type. If the struct has one field consisting
+ // of a complex type, it does not count. This design may be somewhat
+ // inconsistent but it matches the behavior of the legacy C compiler.
+ int Count = 0;
+ clang::BuiltinType::Kind ElemKind;
+ QualType RetTy;
+ for (const auto *FD : RD->fields()) {
+ if (Count >= 2)
+ return std::nullopt;
+
+ QualType FTSingleTy = FD->getType();
+ if (isAggregateTypeForABI(FTSingleTy)) {
+ const Type *Ty = isSingleElementStruct(FTSingleTy, getContext());
+ if (!Ty)
+ return std::nullopt;
+ FTSingleTy = QualType(Ty, 0);
+ }
+
+ if (isFPArgumentType(FTSingleTy)) {
+ clang::BuiltinType::Kind Kind =
+ FTSingleTy->getAs<BuiltinType>()->getKind();
+ if (Count == 0) {
+ ElemKind = Kind;
+ RetTy = FTSingleTy;
+ } else if (ElemKind != Kind)
+ return std::nullopt;
+ } else
+ return std::nullopt;
+
+ Count++;
+ }
+ if (Count == 2) {
+ // The last thing that needs to be checked is the size of the struct.
+ // If we have to emit any padding (eg. because of attribute aligned), this
+ // disqualifies the type from being complex.
+ unsigned RecordSize = getContext().getTypeSize(RT);
+ unsigned ElemSize = getContext().getTypeSize(RetTy);
+ if (RecordSize > 2 * ElemSize)
+ return std::nullopt;
+ return RetTy;
+ }
+ }
+ return std::nullopt;
+}
+
+ABIArgInfo ZOSXPLinkABIInfo::classifyReturnType(QualType RetTy) const {
+
+ // Ignore void types.
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ // Vectors are returned directly.
+ if (isVectorArgumentType(RetTy))
+ return ABIArgInfo::getDirect();
+
+ // Complex types are returned by value as per the XPLINK docs.
+ // Their members will be placed in FPRs.
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
+ // Complex LIKE structures are returned by value as per the XPLINK docs.
+ // Their members will be placed in FPRs.
+ if (RetTy->getAs<RecordType>()) {
+ if (auto CompTy = getFPTypeOfComplexLikeType(RetTy)) {
+ llvm::Type *FPTy = CGT.ConvertType(*CompTy);
+ llvm::Type *CoerceTy = llvm::StructType::get(FPTy, FPTy);
+ auto AI = ABIArgInfo::getDirect(CoerceTy);
+ AI.setCanBeFlattened(false);
+ return AI;
+ }
+ }
+
+ // Aggregates with a size of less than 3 GPRs are returned in GRPs 1, 2 and 3.
+ // Other aggregates are passed in memory as an implicit first parameter.
+ if (isAggregateTypeForABI(RetTy)) {
+ uint64_t AggregateTypeSize = getContext().getTypeSize(RetTy);
+
+ if (AggregateTypeSize <= 3 * GPRBits) {
+ uint64_t NumElements =
+ AggregateTypeSize / GPRBits + (AggregateTypeSize % GPRBits != 0);
+
+ // Types up to 8 bytes are passed as an integer type in GPR1.
+ // Types between 8 and 16 bytes are passed as integer types in GPR1, 2.
+ // Types between 16 and 24 bytes are passed as integer types in GPR1, 2
+ // and 3.
+ llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
+ if (NumElements > 1)
+ CoerceTy = llvm::ArrayType::get(CoerceTy, NumElements);
+ return ABIArgInfo::getDirectInReg(CoerceTy);
+ }
+ return getNaturalAlignIndirect(RetTy);
+ }
+
+ return (isPromotableIntegerType(RetTy) ? ABIArgInfo::getExtend(RetTy)
+ : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType Ty,
+ bool IsNamedArg) const {
+ // Handle transparent union types.
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
+ // Handle the generic C++ ABI.
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
+
+ // Integers and enums are extended to full register width.
+ if (isPromotableIntegerType(Ty))
+ return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+
+ // Complex types are passed by value as per the XPLINK docs.
+ // If place available, their members will be placed in FPRs.
+ if (IsNamedArg) {
+ if (Ty->isComplexType()) {
+ auto AI = ABIArgInfo::getDirect(CGT.ConvertType(Ty));
+ AI.setCanBeFlattened(false);
+ return AI;
+ }
+
+ if (auto CompTy = getFPTypeOfComplexLikeType(Ty)) {
+ llvm::Type *FPTy = CGT.ConvertType(*CompTy);
+ llvm::Type *CoerceTy = llvm::StructType::get(FPTy, FPTy);
+ auto AI = ABIArgInfo::getDirect(CoerceTy);
+ AI.setCanBeFlattened(false);
+ return AI;
+ }
+ }
+
+ // Vectors are passed directly.
+ if (isVectorArgumentType(Ty))
+ return ABIArgInfo::getDirect();
+
+ // Handle structures. They are returned by value.
+ // If not complex like types, they are passed in GPRs, if possible.
+ if (isAggregateTypeForABI(Ty) || Ty->isAnyComplexType()) {
+ // Since an aggregate may end up in registers, pass the aggregate as
+ // array. This is usually beneficial since we avoid forcing the back-end
+ // to store the argument to memory.
+ uint64_t Bits = getContext().getTypeSize(Ty);
+ llvm::Type *CoerceTy;
+
+ if (Bits <= GPRBits) {
+ // Struct types up to 8 bytes are passed as integer type (which will be
+ // properly aligned in the argument save area doubleword).
+ CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
+ } else {
+ // Larger types are passed as arrays, with the base type selected
+ // according to the required alignment in the save area.
+ uint64_t NumRegs = llvm::alignTo(Bits, GPRBits) / GPRBits;
+ llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), GPRBits);
+ CoerceTy = llvm::ArrayType::get(RegTy, NumRegs);
+ }
+
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+
+ // Other types. E,g. pointers.
+ return ABIArgInfo::getDirect();
+}
+
+RValue ZOSXPLinkABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty, AggValueSlot Slot) const {
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
+ CGF.getContext().getTypeInfoInChars(Ty),
+ CGF.getPointerSize(),
+ /*allowHigherAlign*/ false, Slot);
+}
+
std::unique_ptr<TargetCodeGenInfo>
CodeGen::createSystemZTargetCodeGenInfo(CodeGenModule &CGM, bool HasVector,
bool SoftFloatABI) {
return std::make_unique<SystemZTargetCodeGenInfo>(CGM.getTypes(), HasVector,
SoftFloatABI);
}
+
+std::unique_ptr<TargetCodeGenInfo>
+CodeGen::createSystemZ_ZOS_TargetCodeGenInfo(CodeGenModule &CGM, bool HasVector,
+ bool SoftFloatABI) {
+ return std::make_unique<ZOSXPLinkTargetCodeGenInfo>(CGM.getTypes(),
+ HasVector);
+}
diff --git a/clang/test/CodeGen/zos-abi.c b/clang/test/CodeGen/zos-abi.c
new file mode 100644
index 0000000000000..f0896edc8ac69
--- /dev/null
+++ b/clang/test/CodeGen/zos-abi.c
@@ -0,0 +1,247 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-feature +vector \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z13 \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch11 \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z14 \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch12 \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z15 \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch13 \
+// RUN: -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch11 \
+// RUN: -DTEST_VEC -fzvector -emit-llvm -no-enable-noundef-analysis \
+// RUN: -o - %s | FileCheck --check-prefixes=CHECKVEC %s
+
+// Scalar types
+
+signed char pass_schar(signed char arg) { return arg; }
+// CHECK-LABEL: define signext i8 @pass_schar(i8 signext %{{.*}})
+
+unsigned char pass_uchar(unsigned char arg) { return arg; }
+// CHECK-LABEL: define zeroext i8 @pass_uchar(i8 zeroext %{{.*}})
+
+short pass_short(short arg) { return arg; }
+// CHECK-LABEL: define signext i16 @pass_short(i16 signext %{{.*}})
+
+int pass_int(int arg) { return arg; }
+// CHECK-LABEL: define signext i32 @pass_int(i32 signext %{{.*}})
+
+long pass_long(long arg) { return arg; }
+// CHECK-LABEL: define i64 @pass_long(i64 %{{.*}})
+
+long long pass_longlong(long long arg) { return arg; }
+// CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}})
+
+float pass_float(float arg) { return arg; }
+// CHECK-LABEL: define float @pass_float(float %{{.*}})
+
+double pass_double(double arg) { return arg; }
+// CHECK-LABEL: define double @pass_double(double %{{.*}})
+
+long double pass_longdouble(long double arg) { return arg; }
+// CHECK-LABEL: define fp128 @pass_longdouble(fp128 %{{.*}})
+
+enum Color { Red, Blue };
+enum Color pass_enum(enum Color arg) { return arg; }
+// CHECK-LABEL: define zeroext i32 @pass_enum(i32 zeroext %{{.*}})
+
+#ifdef TEST_VEC
+vector unsigned int pass_vector(vector unsigned int arg) { return arg; };
+// CHECKVEC-LABEL: define <4 x i32> @pass_vector(<4 x i32> %{{.*}})
+
+struct SingleVec { vector unsigned int v; };
+struct SingleVec pass_SingleVec_agg(struct SingleVec arg) { return arg; };
+// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg([2 x i64] %{{.*}})
+#endif
+
+// Complex types
+
+_Complex float pass_complex_float(_Complex float arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complex_float({ float, float } %{{.*}})
+
+_Complex double pass_complex_double(_Complex double arg) { return arg; }
+// CHECK-LABEL: define { double, double } @pass_complex_double({ double, double } %{{.*}})
+
+_Complex long double pass_complex_longdouble(_Complex long double arg) { return arg; }
+// CHECK-LABEL: define { fp128, fp128 } @pass_complex_longdouble({ fp128, fp128 } %{{.*}})
+
+// Verify that the following are complex-like types
+struct complexlike_float { float re, im; };
+struct complexlike_float pass_complexlike_float(struct complexlike_float arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_float({ float, float } %{{.*}})
+
+struct complexlike_double { double re, im; };
+struct complexlike_double pass_complexlike_double(struct complexlike_double arg) { return arg; }
+// CHECK-LABEL: define { double, double } @pass_complexlike_double({ double, double } %{{.*}})
+
+struct complexlike_longdouble { long double re, im; };
+struct complexlike_longdouble pass_complexlike_longdouble(struct complexlike_longdouble arg) { return arg; }
+// CHECK-LABEL: define { fp128, fp128 } @pass_complexlike_longdouble({ fp128, fp128 } %{{.*}})
+
+struct single_element_float { float f; };
+struct complexlike_struct {
+ struct single_element_float x;
+ struct single_element_float y;
+};
+struct complexlike_struct pass_complexlike_struct(struct complexlike_struct arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_struct({ float, float } %{{.*}})
+
+struct single_element_float_arr {
+ unsigned int :0;
+ float f[1];
+};
+struct complexlike_struct2 {
+ struct single_element_float_arr x;
+ struct single_element_float_arr y;
+};
+struct complexlike_struct2 pass_complexlike_struct2(struct complexlike_struct2 arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_struct2({ float, float } %{{.*}})
+
+struct float_and_empties {
+ struct S {} s;
+ int a[0];
+ float f;
+};
+struct complexlike_struct3 {
+ struct float_and_empties x;
+ struct float_and_empties y;
+};
+struct complexlike_struct3 pass_complexlike_struct3(struct complexlike_struct3 arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_struct3({ float, float } %{{.*}})
+
+union two_float_union { float a; float b; };
+struct complexlike_struct_with_union {
+ float a;
+ union two_float_union b;
+};
+struct complexlike_struct_with_union pass_complexlike_struct_with_union(struct complexlike_struct_with_union arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_complexlike_struct_with_union(i64 %{{.*}})
+
+// structures with one field as complex type are not considered complex types.
+
+struct single_complex_struct {
+ _Complex float f;
+};
+struct single_complex_struct pass_single_complex_struct(struct single_complex_struct arg) {return arg; }
+// CHECK-LABEL: define inreg i64 @pass_single_complex_struct(i64 %{{.*}})
+
+// Structures with extra padding are not considered complex types.
+struct complexlike_float_padded1 {
+ float x __attribute__((aligned(8)));
+ float y __attribute__((aligned(8)));
+};
+struct complexlike_float_padded1 pass_complexlike_float_padded1(struct complexlike_float_padded1 arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded1([2 x i64] %{{.*}})
+
+struct complexlike_float_padded2 {
+ float x;
+ float y;
+} __attribute__((aligned(16)));
+struct complexlike_float_padded2 pass_complexlike_float_padded2(struct complexlike_float_padded2 arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded2([2 x i64] %{{.*}})
+
+struct single_padded_struct {
+ float f;
+ unsigned int :2;
+};
+struct complexlike_float_padded3 {
+ struct single_padded_struct x;
+ struct single_padded_struct y;
+};
+struct complexlike_float_padded3 pass_complexlike_float_padded3(struct complexlike_float_padded3 arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded3([2 x i64] %{{.*}})
+
+struct multi_element_float_arr { float f[2]; };
+struct complexlike_struct4 {
+ struct multi_element_float_arr x;
+ struct multi_element_float_arr y;
+};
+struct complexlike_struct4 pass_complexlike_struct4(struct complexlike_struct4 arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_struct4([2 x i64] %{{.*}})
+
+typedef double align32_double __attribute__((aligned(32)));
+struct complexlike_double_padded {
+ align32_double x;
+ double y;
+};
+struct complexlike_double_padded pass_complexlike_double_padded(struct complexlike_double_padded arg) { return arg; }
+// CHECK-LABEL: define void @pass_complexlike_double_padded(ptr {{.*}} sret(%struct.complexlike_double_padded) align 32 %{{.*}}, [4 x i64] %{{.*}})
+
+// Aggregate types
+
+struct agg_1byte { char a[1]; };
+struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_1byte(i64 %{{.*}})
+
+struct agg_2byte { char a[2]; };
+struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_2byte(i64 %{{.*}})
+
+struct agg_3byte { char a[3]; };
+struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_3byte(i64 %{{.*}})
+
+struct agg_4byte { char a[4]; };
+struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_4byte(i64 %{{.*}})
+
+struct agg_5byte { char a[5]; };
+struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_5byte(i64 %{{.*}})
+
+struct agg_6byte { char a[6]; };
+struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_6byte(i64 %{{.*}})
+
+struct agg_7byte { char a[7]; };
+struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_7byte(i64 %{{.*}})
+
+struct agg_8byte { char a[8]; };
+struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_8byte(i64 %{{.*}})
+
+struct agg_9byte { char a[9]; };
+struct agg_9byte pass_agg_9byte(struct agg_9byte arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte([2 x i64] %{{.*}})
+
+struct agg_16byte { char a[16]; };
+struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte([2 x i64] %{{.*}})
+
+struct agg_24byte { char a[24]; };
+struct agg_24byte pass_agg_24byte(struct agg_24byte arg) { return arg; }
+// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte([3 x i64] %{{.*}})
+
+struct agg_25byte { char a[25]; };
+struct agg_25byte pass_agg_25byte(struct agg_25byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_25byte(ptr dead_on_unwind noalias writable sret{{.*}} align 1 %{{.*}}, [4 x i64] %{{.*}})
+
+// Check that a float-like aggregate type is really passed as aggregate
+struct agg_float { float a; };
+struct agg_float pass_agg_float(struct agg_float arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_float(i64 %{{.*}})
+
+// Verify that the following are *not* float-like aggregate types
+
+struct agg_nofloat2 { float a; int b; };
+struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_nofloat2(i64 %{{.*}})
+
+struct agg_nofloat3 { float a; int : 0; };
+struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_agg_nofloat3(i64 %{{.*}})
+
+char * pass_pointer(char * arg) { return arg; }
+// CHECK-LABEL: define ptr @pass_pointer(ptr %{{.*}})
+
+typedef int vecint __attribute__ ((vector_size(16)));
+vecint pass_vector_type(vecint arg) { return arg; }
+// CHECK-LABEL: define <4 x i32> @pass_vector_type(<4 x i32> %{{.*}})
diff --git a/clang/test/CodeGen/zos-abi.cpp b/clang/test/CodeGen/zos-abi.cpp
new file mode 100644
index 0000000000000..a662db6f59d1b
--- /dev/null
+++ b/clang/test/CodeGen/zos-abi.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos -emit-llvm -x c++ -o - %s | FileCheck %s
+
+struct empty { };
+struct agg_nofloat_empty { float a; empty dummy; };
+struct complex_like_agg_nofloat_empty { struct agg_nofloat_empty a; struct agg_nofloat_empty b; };
+struct complex_like_agg_nofloat_empty pass_complex_like_agg_nofloat_empty(struct complex_like_agg_nofloat_empty arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @_Z35pass_complex_like_agg_nofloat_empty30complex_like_agg_nofloat_empty([2 x i64] %{{.*}})
+
+struct agg_float_empty { float a; [[no_unique_address]] empty dummy; };
+struct complex_like_agg_float_empty { struct agg_float_empty a; struct agg_float_empty b; };
+struct complex_like_agg_float_empty pass_complex_like_agg_float_empty(struct complex_like_agg_float_empty arg) { return arg; }
+// CHECK-LABEL: define { float, float } @_Z33pass_complex_like_agg_float_empty28complex_like_agg_float_empty({ float, float } %{{.*}})
+
+struct noemptybase { empty dummy; };
+struct agg_nofloat_emptybase : noemptybase { float a; };
+struct complex_like_agg_nofloat_emptybase { struct agg_nofloat_emptybase a; struct agg_nofloat_emptybase b; };
+struct complex_like_agg_nofloat_emptybase pass_agg_nofloat_emptybase(struct complex_like_agg_nofloat_emptybase arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @_Z26pass_agg_nofloat_emptybase34complex_like_agg_nofloat_emptybase([2 x i64] %{{.*}})
+
+struct emptybase { [[no_unique_address]] empty dummy; };
+struct agg_float_emptybase : emptybase { float a; };
+struct complex_like_agg_float_emptybase { struct agg_float_emptybase a; struct agg_float_emptybase b; };
+struct complex_like_agg_float_emptybase pass_agg_float_emptybase(struct complex_like_agg_float_emptybase arg) { return arg; }
+// CHECK-LABEL: define { float, float } @_Z24pass_agg_float_emptybase32complex_like_agg_float_emptybase({ float, float } %{{.*}})
>From c95773e1c99dcdffdda317d55feaabe20721a67f Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Wed, 31 Jul 2024 15:35:37 -0400
Subject: [PATCH 2/4] Treat union with just one float type as float
---
clang/lib/CodeGen/Targets/SystemZ.cpp | 106 +++++++++++++++----
clang/test/CodeGen/{ => SystemZ}/zos-abi.c | 55 +++++++++-
clang/test/CodeGen/{ => SystemZ}/zos-abi.cpp | 0
3 files changed, 142 insertions(+), 19 deletions(-)
rename clang/test/CodeGen/{ => SystemZ}/zos-abi.c (87%)
rename clang/test/CodeGen/{ => SystemZ}/zos-abi.cpp (100%)
diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 5bb91232a3285..540a3d98901b1 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -10,7 +10,6 @@
#include "TargetInfo.h"
#include "clang/Basic/Builtins.h"
#include "llvm/IR/IntrinsicsS390.h"
-#include <optional>
using namespace clang;
using namespace clang::CodeGen;
@@ -549,7 +548,8 @@ class ZOSXPLinkABIInfo : public ABIInfo {
bool isPromotableIntegerType(QualType Ty) const;
bool isVectorArgumentType(QualType Ty) const;
bool isFPArgumentType(QualType Ty) const;
- std::optional<QualType> getFPTypeOfComplexLikeType(QualType Ty) const;
+ QualType getSingleElementType(QualType Ty) const;
+ QualType getFPTypeOfComplexLikeType(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType ArgTy, bool IsNamedArg) const;
@@ -631,8 +631,76 @@ bool ZOSXPLinkABIInfo::isFPArgumentType(QualType Ty) const {
return false;
}
-std::optional<QualType>
-ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
+QualType ZOSXPLinkABIInfo::getSingleElementType(QualType Ty) const {
+ // Unions just containing a floating point type, e.g. union { float f1, f2; };
+ // are treated as a single floating point number. Check if the union only
+ // consists of a single type (handling embedded unions recursively), and
+ // return that type.
+ if (const RecordType *RT = Ty->getAsUnionType()) {
+ QualType Found;
+ // Check the fields.
+ const RecordDecl *RD = RT->getDecl();
+ for (const auto *FD : RD->fields()) {
+ if (Found.isNull())
+ Found = getSingleElementType(FD->getType());
+ else if (Found != getSingleElementType(FD->getType()))
+ return Ty;
+ }
+ return Found.isNull() ? Ty : Found;
+ }
+
+ const RecordType *RT = Ty->getAs<RecordType>();
+
+ if (RT && RT->isStructureOrClassType()) {
+ const RecordDecl *RD = RT->getDecl();
+ QualType Found;
+
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ if (CXXRD->hasDefinition())
+ for (const auto &I : CXXRD->bases()) {
+ QualType Base = I.getType();
+
+ // Empty bases don't affect things either way.
+ if (isEmptyRecord(getContext(), Base, true))
+ continue;
+
+ if (!Found.isNull())
+ return Ty;
+ Found = getSingleElementType(Base);
+ }
+
+ // Check the fields.
+ for (const auto *FD : RD->fields()) {
+ QualType FT = FD->getType();
+
+ // Ignore empty fields.
+ if (isEmptyField(getContext(), FD, true))
+ continue;
+
+ if (!Found.isNull())
+ return Ty;
+
+ // Treat single element arrays as the element.
+ while (const ConstantArrayType *AT =
+ getContext().getAsConstantArrayType(FT)) {
+ if (AT->getZExtSize() != 1)
+ break;
+ FT = AT->getElementType();
+ }
+
+ Found = getSingleElementType(FT);
+ }
+
+ // Unlike isSingleElementStruct(), trailing padding is allowed.
+ if (!Found.isNull())
+ return Found;
+ }
+
+ return Ty;
+}
+
+QualType ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
if (const RecordType *RT = Ty->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl();
@@ -642,7 +710,7 @@ ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
for (const auto &I : CXXRD->bases()) {
QualType Base = I.getType();
if (!isEmptyRecord(getContext(), Base, true))
- return std::nullopt;
+ return QualType();
}
// Check for exactly two elements with exactly the same floating point type.
@@ -655,14 +723,14 @@ ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
QualType RetTy;
for (const auto *FD : RD->fields()) {
if (Count >= 2)
- return std::nullopt;
+ return QualType();
QualType FTSingleTy = FD->getType();
if (isAggregateTypeForABI(FTSingleTy)) {
- const Type *Ty = isSingleElementStruct(FTSingleTy, getContext());
- if (!Ty)
- return std::nullopt;
- FTSingleTy = QualType(Ty, 0);
+ QualType Ty = getSingleElementType(FTSingleTy);
+ if (Ty.isNull())
+ return QualType();
+ FTSingleTy = Ty;
}
if (isFPArgumentType(FTSingleTy)) {
@@ -672,9 +740,9 @@ ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
ElemKind = Kind;
RetTy = FTSingleTy;
} else if (ElemKind != Kind)
- return std::nullopt;
+ return QualType();
} else
- return std::nullopt;
+ return QualType();
Count++;
}
@@ -685,11 +753,11 @@ ZOSXPLinkABIInfo::getFPTypeOfComplexLikeType(QualType Ty) const {
unsigned RecordSize = getContext().getTypeSize(RT);
unsigned ElemSize = getContext().getTypeSize(RetTy);
if (RecordSize > 2 * ElemSize)
- return std::nullopt;
+ return QualType();
return RetTy;
}
}
- return std::nullopt;
+ return QualType();
}
ABIArgInfo ZOSXPLinkABIInfo::classifyReturnType(QualType RetTy) const {
@@ -710,8 +778,9 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyReturnType(QualType RetTy) const {
// Complex LIKE structures are returned by value as per the XPLINK docs.
// Their members will be placed in FPRs.
if (RetTy->getAs<RecordType>()) {
- if (auto CompTy = getFPTypeOfComplexLikeType(RetTy)) {
- llvm::Type *FPTy = CGT.ConvertType(*CompTy);
+ auto CompTy = getFPTypeOfComplexLikeType(RetTy);
+ if (!CompTy.isNull()) {
+ llvm::Type *FPTy = CGT.ConvertType(CompTy);
llvm::Type *CoerceTy = llvm::StructType::get(FPTy, FPTy);
auto AI = ABIArgInfo::getDirect(CoerceTy);
AI.setCanBeFlattened(false);
@@ -766,8 +835,9 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType Ty,
return AI;
}
- if (auto CompTy = getFPTypeOfComplexLikeType(Ty)) {
- llvm::Type *FPTy = CGT.ConvertType(*CompTy);
+ auto CompTy = getFPTypeOfComplexLikeType(Ty);
+ if (!CompTy.isNull()) {
+ llvm::Type *FPTy = CGT.ConvertType(CompTy);
llvm::Type *CoerceTy = llvm::StructType::get(FPTy, FPTy);
auto AI = ABIArgInfo::getDirect(CoerceTy);
AI.setCanBeFlattened(false);
diff --git a/clang/test/CodeGen/zos-abi.c b/clang/test/CodeGen/SystemZ/zos-abi.c
similarity index 87%
rename from clang/test/CodeGen/zos-abi.c
rename to clang/test/CodeGen/SystemZ/zos-abi.c
index f0896edc8ac69..56ffdc3a6c4d1 100644
--- a/clang/test/CodeGen/zos-abi.c
+++ b/clang/test/CodeGen/SystemZ/zos-abi.c
@@ -122,7 +122,7 @@ struct complexlike_struct_with_union {
union two_float_union b;
};
struct complexlike_struct_with_union pass_complexlike_struct_with_union(struct complexlike_struct_with_union arg) { return arg; }
-// CHECK-LABEL: define inreg i64 @pass_complexlike_struct_with_union(i64 %{{.*}})
+// CHECK-LABEL: define { float, float } @pass_complexlike_struct_with_union({ float, float } %{{.*}})
// structures with one field as complex type are not considered complex types.
@@ -245,3 +245,56 @@ char * pass_pointer(char * arg) { return arg; }
typedef int vecint __attribute__ ((vector_size(16)));
vecint pass_vector_type(vecint arg) { return arg; }
// CHECK-LABEL: define <4 x i32> @pass_vector_type(<4 x i32> %{{.*}})
+
+// Union with just a single float element are treated as float inside a struct.
+union u1 {
+ float m1, m2;
+};
+
+union u2 {
+ float m1;
+ union u1 m2;
+};
+
+union u3 {
+ float m1;
+ int m2;
+};
+
+struct complexlike_union1 {
+ float m1;
+ union u1 m2;
+};
+
+struct complexlike_union2 {
+ float m1;
+ union u2 m2;
+};
+
+struct complexlike_union3 {
+ union u1 m1;
+ union u2 m2;
+};
+
+struct normal_struct {
+ float m1;
+ union u3 m2;
+};
+
+struct complexlike_union1 pass_complexlike_union1(struct complexlike_union1 arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_union1({ float, float } %{{.*}})
+
+struct complexlike_union2 pass_complexlike_union2(struct complexlike_union2 arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_union2({ float, float } %{{.*}})
+
+struct complexlike_union3 pass_complexlike_union3(struct complexlike_union3 arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complexlike_union3({ float, float } %{{.*}})
+
+union u1 pass_union1(union u1 arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_union1(i64 %{{.*}})
+
+union u2 pass_union2(union u2 arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_union2(i64 %{{.*}})
+
+struct normal_struct pass_normal_struct(struct normal_struct arg) { return arg; }
+// CHECK-LABEL: define inreg i64 @pass_normal_struct(i64 %{{.*}})
diff --git a/clang/test/CodeGen/zos-abi.cpp b/clang/test/CodeGen/SystemZ/zos-abi.cpp
similarity index 100%
rename from clang/test/CodeGen/zos-abi.cpp
rename to clang/test/CodeGen/SystemZ/zos-abi.cpp
>From 5336a3154ab7f6c2b0a8d21c5d8107dd5ab74acc Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Wed, 31 Jul 2024 15:38:36 -0400
Subject: [PATCH 3/4] use byval when bits > 64
---
clang/lib/CodeGen/Targets/SystemZ.cpp | 4 +++-
clang/test/CodeGen/SystemZ/zos-abi.c | 20 ++++++++++----------
clang/test/CodeGen/SystemZ/zos-abi.cpp | 4 ++--
3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 540a3d98901b1..d1634ce2a7d21 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -862,7 +862,9 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType Ty,
// Struct types up to 8 bytes are passed as integer type (which will be
// properly aligned in the argument save area doubleword).
CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
- } else {
+ } else if (Bits > 64)
+ return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
+ else {
// Larger types are passed as arrays, with the base type selected
// according to the required alignment in the save area.
uint64_t NumRegs = llvm::alignTo(Bits, GPRBits) / GPRBits;
diff --git a/clang/test/CodeGen/SystemZ/zos-abi.c b/clang/test/CodeGen/SystemZ/zos-abi.c
index 56ffdc3a6c4d1..17f31b08d1b07 100644
--- a/clang/test/CodeGen/SystemZ/zos-abi.c
+++ b/clang/test/CodeGen/SystemZ/zos-abi.c
@@ -58,7 +58,7 @@ vector unsigned int pass_vector(vector unsigned int arg) { return arg; };
struct SingleVec { vector unsigned int v; };
struct SingleVec pass_SingleVec_agg(struct SingleVec arg) { return arg; };
-// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg([2 x i64] %{{.*}})
+// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg(ptr byval(%struct.SingleVec) align 8 %{{.*}})
#endif
// Complex types
@@ -138,14 +138,14 @@ struct complexlike_float_padded1 {
float y __attribute__((aligned(8)));
};
struct complexlike_float_padded1 pass_complexlike_float_padded1(struct complexlike_float_padded1 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded1([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded1(ptr byval(%struct.complexlike_float_padded1) align 8 %{{.*}})
struct complexlike_float_padded2 {
float x;
float y;
} __attribute__((aligned(16)));
struct complexlike_float_padded2 pass_complexlike_float_padded2(struct complexlike_float_padded2 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded2([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded2(ptr byval(%struct.complexlike_float_padded2) align 16 %{{.*}})
struct single_padded_struct {
float f;
@@ -156,7 +156,7 @@ struct complexlike_float_padded3 {
struct single_padded_struct y;
};
struct complexlike_float_padded3 pass_complexlike_float_padded3(struct complexlike_float_padded3 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded3([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded3(ptr byval(%struct.complexlike_float_padded3) align 4 %{{.*}})
struct multi_element_float_arr { float f[2]; };
struct complexlike_struct4 {
@@ -164,7 +164,7 @@ struct complexlike_struct4 {
struct multi_element_float_arr y;
};
struct complexlike_struct4 pass_complexlike_struct4(struct complexlike_struct4 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_struct4([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_struct4(ptr byval(%struct.complexlike_struct4) align 4 %{{.*}})
typedef double align32_double __attribute__((aligned(32)));
struct complexlike_double_padded {
@@ -172,7 +172,7 @@ struct complexlike_double_padded {
double y;
};
struct complexlike_double_padded pass_complexlike_double_padded(struct complexlike_double_padded arg) { return arg; }
-// CHECK-LABEL: define void @pass_complexlike_double_padded(ptr {{.*}} sret(%struct.complexlike_double_padded) align 32 %{{.*}}, [4 x i64] %{{.*}})
+// CHECK-LABEL: define void @pass_complexlike_double_padded(ptr {{.*}} sret(%struct.complexlike_double_padded) align 32 %agg.result, ptr byval(%struct.complexlike_double_padded) align 32 %{{.*}}
// Aggregate types
@@ -210,19 +210,19 @@ struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
struct agg_9byte { char a[9]; };
struct agg_9byte pass_agg_9byte(struct agg_9byte arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte(ptr byval(%struct.agg_9byte) align 1 %{{.*}})
struct agg_16byte { char a[16]; };
struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte(ptr byval(%struct.agg_16byte) align 1 %{{.*}})
struct agg_24byte { char a[24]; };
struct agg_24byte pass_agg_24byte(struct agg_24byte arg) { return arg; }
-// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte([3 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte(ptr byval(%struct.agg_24byte) align 1 %{{.*}})
struct agg_25byte { char a[25]; };
struct agg_25byte pass_agg_25byte(struct agg_25byte arg) { return arg; }
-// CHECK-LABEL: define void @pass_agg_25byte(ptr dead_on_unwind noalias writable sret{{.*}} align 1 %{{.*}}, [4 x i64] %{{.*}})
+// CHECK-LABEL: define void @pass_agg_25byte(ptr {{.*}} sret(%struct.agg_25byte) align 1 %agg.result, ptr byval(%struct.agg_25byte) align 1 %{{.*}})
// Check that a float-like aggregate type is really passed as aggregate
struct agg_float { float a; };
diff --git a/clang/test/CodeGen/SystemZ/zos-abi.cpp b/clang/test/CodeGen/SystemZ/zos-abi.cpp
index a662db6f59d1b..d4bb657aca003 100644
--- a/clang/test/CodeGen/SystemZ/zos-abi.cpp
+++ b/clang/test/CodeGen/SystemZ/zos-abi.cpp
@@ -4,7 +4,7 @@ struct empty { };
struct agg_nofloat_empty { float a; empty dummy; };
struct complex_like_agg_nofloat_empty { struct agg_nofloat_empty a; struct agg_nofloat_empty b; };
struct complex_like_agg_nofloat_empty pass_complex_like_agg_nofloat_empty(struct complex_like_agg_nofloat_empty arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @_Z35pass_complex_like_agg_nofloat_empty30complex_like_agg_nofloat_empty([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @_Z35pass_complex_like_agg_nofloat_empty30complex_like_agg_nofloat_empty(ptr noundef byval(%struct.complex_like_agg_nofloat_empty) align 4 %{{.*}})
struct agg_float_empty { float a; [[no_unique_address]] empty dummy; };
struct complex_like_agg_float_empty { struct agg_float_empty a; struct agg_float_empty b; };
@@ -15,7 +15,7 @@ struct noemptybase { empty dummy; };
struct agg_nofloat_emptybase : noemptybase { float a; };
struct complex_like_agg_nofloat_emptybase { struct agg_nofloat_emptybase a; struct agg_nofloat_emptybase b; };
struct complex_like_agg_nofloat_emptybase pass_agg_nofloat_emptybase(struct complex_like_agg_nofloat_emptybase arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @_Z26pass_agg_nofloat_emptybase34complex_like_agg_nofloat_emptybase([2 x i64] %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @_Z26pass_agg_nofloat_emptybase34complex_like_agg_nofloat_emptybase(ptr noundef byval(%struct.complex_like_agg_nofloat_emptybase) align 4 %{{.*}})
struct emptybase { [[no_unique_address]] empty dummy; };
struct agg_float_emptybase : emptybase { float a; };
>From 28de6136ae560156d94f75956ad446bfcfc37ace Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Wed, 7 Aug 2024 09:03:35 -0400
Subject: [PATCH 4/4] Revert "use byval when bits > 64"
This reverts commit 5336a3154ab7f6c2b0a8d21c5d8107dd5ab74acc.
---
clang/lib/CodeGen/Targets/SystemZ.cpp | 4 +---
clang/test/CodeGen/SystemZ/zos-abi.c | 20 ++++++++++----------
clang/test/CodeGen/SystemZ/zos-abi.cpp | 4 ++--
3 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp
index d1634ce2a7d21..540a3d98901b1 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -862,9 +862,7 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType Ty,
// Struct types up to 8 bytes are passed as integer type (which will be
// properly aligned in the argument save area doubleword).
CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
- } else if (Bits > 64)
- return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
- else {
+ } else {
// Larger types are passed as arrays, with the base type selected
// according to the required alignment in the save area.
uint64_t NumRegs = llvm::alignTo(Bits, GPRBits) / GPRBits;
diff --git a/clang/test/CodeGen/SystemZ/zos-abi.c b/clang/test/CodeGen/SystemZ/zos-abi.c
index 17f31b08d1b07..56ffdc3a6c4d1 100644
--- a/clang/test/CodeGen/SystemZ/zos-abi.c
+++ b/clang/test/CodeGen/SystemZ/zos-abi.c
@@ -58,7 +58,7 @@ vector unsigned int pass_vector(vector unsigned int arg) { return arg; };
struct SingleVec { vector unsigned int v; };
struct SingleVec pass_SingleVec_agg(struct SingleVec arg) { return arg; };
-// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg(ptr byval(%struct.SingleVec) align 8 %{{.*}})
+// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg([2 x i64] %{{.*}})
#endif
// Complex types
@@ -138,14 +138,14 @@ struct complexlike_float_padded1 {
float y __attribute__((aligned(8)));
};
struct complexlike_float_padded1 pass_complexlike_float_padded1(struct complexlike_float_padded1 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded1(ptr byval(%struct.complexlike_float_padded1) align 8 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded1([2 x i64] %{{.*}})
struct complexlike_float_padded2 {
float x;
float y;
} __attribute__((aligned(16)));
struct complexlike_float_padded2 pass_complexlike_float_padded2(struct complexlike_float_padded2 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded2(ptr byval(%struct.complexlike_float_padded2) align 16 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded2([2 x i64] %{{.*}})
struct single_padded_struct {
float f;
@@ -156,7 +156,7 @@ struct complexlike_float_padded3 {
struct single_padded_struct y;
};
struct complexlike_float_padded3 pass_complexlike_float_padded3(struct complexlike_float_padded3 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded3(ptr byval(%struct.complexlike_float_padded3) align 4 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_float_padded3([2 x i64] %{{.*}})
struct multi_element_float_arr { float f[2]; };
struct complexlike_struct4 {
@@ -164,7 +164,7 @@ struct complexlike_struct4 {
struct multi_element_float_arr y;
};
struct complexlike_struct4 pass_complexlike_struct4(struct complexlike_struct4 arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_struct4(ptr byval(%struct.complexlike_struct4) align 4 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_complexlike_struct4([2 x i64] %{{.*}})
typedef double align32_double __attribute__((aligned(32)));
struct complexlike_double_padded {
@@ -172,7 +172,7 @@ struct complexlike_double_padded {
double y;
};
struct complexlike_double_padded pass_complexlike_double_padded(struct complexlike_double_padded arg) { return arg; }
-// CHECK-LABEL: define void @pass_complexlike_double_padded(ptr {{.*}} sret(%struct.complexlike_double_padded) align 32 %agg.result, ptr byval(%struct.complexlike_double_padded) align 32 %{{.*}}
+// CHECK-LABEL: define void @pass_complexlike_double_padded(ptr {{.*}} sret(%struct.complexlike_double_padded) align 32 %{{.*}}, [4 x i64] %{{.*}})
// Aggregate types
@@ -210,19 +210,19 @@ struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
struct agg_9byte { char a[9]; };
struct agg_9byte pass_agg_9byte(struct agg_9byte arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte(ptr byval(%struct.agg_9byte) align 1 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte([2 x i64] %{{.*}})
struct agg_16byte { char a[16]; };
struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte(ptr byval(%struct.agg_16byte) align 1 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte([2 x i64] %{{.*}})
struct agg_24byte { char a[24]; };
struct agg_24byte pass_agg_24byte(struct agg_24byte arg) { return arg; }
-// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte(ptr byval(%struct.agg_24byte) align 1 %{{.*}})
+// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte([3 x i64] %{{.*}})
struct agg_25byte { char a[25]; };
struct agg_25byte pass_agg_25byte(struct agg_25byte arg) { return arg; }
-// CHECK-LABEL: define void @pass_agg_25byte(ptr {{.*}} sret(%struct.agg_25byte) align 1 %agg.result, ptr byval(%struct.agg_25byte) align 1 %{{.*}})
+// CHECK-LABEL: define void @pass_agg_25byte(ptr dead_on_unwind noalias writable sret{{.*}} align 1 %{{.*}}, [4 x i64] %{{.*}})
// Check that a float-like aggregate type is really passed as aggregate
struct agg_float { float a; };
diff --git a/clang/test/CodeGen/SystemZ/zos-abi.cpp b/clang/test/CodeGen/SystemZ/zos-abi.cpp
index d4bb657aca003..a662db6f59d1b 100644
--- a/clang/test/CodeGen/SystemZ/zos-abi.cpp
+++ b/clang/test/CodeGen/SystemZ/zos-abi.cpp
@@ -4,7 +4,7 @@ struct empty { };
struct agg_nofloat_empty { float a; empty dummy; };
struct complex_like_agg_nofloat_empty { struct agg_nofloat_empty a; struct agg_nofloat_empty b; };
struct complex_like_agg_nofloat_empty pass_complex_like_agg_nofloat_empty(struct complex_like_agg_nofloat_empty arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @_Z35pass_complex_like_agg_nofloat_empty30complex_like_agg_nofloat_empty(ptr noundef byval(%struct.complex_like_agg_nofloat_empty) align 4 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @_Z35pass_complex_like_agg_nofloat_empty30complex_like_agg_nofloat_empty([2 x i64] %{{.*}})
struct agg_float_empty { float a; [[no_unique_address]] empty dummy; };
struct complex_like_agg_float_empty { struct agg_float_empty a; struct agg_float_empty b; };
@@ -15,7 +15,7 @@ struct noemptybase { empty dummy; };
struct agg_nofloat_emptybase : noemptybase { float a; };
struct complex_like_agg_nofloat_emptybase { struct agg_nofloat_emptybase a; struct agg_nofloat_emptybase b; };
struct complex_like_agg_nofloat_emptybase pass_agg_nofloat_emptybase(struct complex_like_agg_nofloat_emptybase arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @_Z26pass_agg_nofloat_emptybase34complex_like_agg_nofloat_emptybase(ptr noundef byval(%struct.complex_like_agg_nofloat_emptybase) align 4 %{{.*}})
+// CHECK-LABEL: define inreg [2 x i64] @_Z26pass_agg_nofloat_emptybase34complex_like_agg_nofloat_emptybase([2 x i64] %{{.*}})
struct emptybase { [[no_unique_address]] empty dummy; };
struct agg_float_emptybase : emptybase { float a; };
More information about the cfe-commits
mailing list