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.sreeskanthara...@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.sreeskanthara...@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.sreeskanthara...@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.sreeskanthara...@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; }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits