[clang] [SystemZ][z/OS] Implement z/OS XPLINK ABI (PR #91384)

Fanbo Meng via cfe-commits cfe-commits at lists.llvm.org
Wed May 8 06:44:16 PDT 2024


https://github.com/fanbo-meng updated https://github.com/llvm/llvm-project/pull/91384

>From 7b40fa0aab937dfc0ab8db48ed93db1a5debef0b Mon Sep 17 00:00:00 2001
From: Fanbo Meng <Fanbo.Meng at ibm.com>
Date: Tue, 7 May 2024 13:36:38 -0400
Subject: [PATCH 1/3] [SystemZ][z/OS] Implement z/OS XPLINK ABI

The XPLINK calling convention is specified in the Language
Environment Vendor Interface, chapter 22,
(https://www.ibm.com/support/knowledgecenter/SSLTBW_2.4.0/com.ibm.zos.v2r4.cee/cee.htm)
and in Redbook XPLink: OS/390 Extra Performance Linkage
(http://www.redbooks.ibm.com/abstracts/sg245991.html?Open)
---
 clang/lib/CodeGen/CodeGenModule.cpp   |   2 +
 clang/lib/CodeGen/TargetInfo.h        |   4 +
 clang/lib/CodeGen/Targets/SystemZ.cpp | 317 ++++++++++++++++++++++++++
 clang/test/CodeGen/zos-abi.c          | 137 +++++++++++
 4 files changed, 460 insertions(+)
 create mode 100644 clang/test/CodeGen/zos-abi.c

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c8898ce196c1e..39491d699f6d2 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -241,6 +241,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 f242d9e36ed40..e15f9bdf39356 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -527,6 +527,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 deaafc85a3157..903e7391b314d 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -529,9 +529,326 @@ bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty,
   return false;
 }
 
+//===----------------------------------------------------------------------===//
+// z/OS XPLINK ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ZOSXPLinkABIInfo : public ABIInfo {
+  static const unsigned GPRBits = 64;
+  bool HasVector;
+
+public:
+  ZOSXPLinkABIInfo(CodeGenTypes &CGT, bool HV)
+      : ABIInfo(CGT), HasVector(HV) {}
+
+  bool isPromotableIntegerType(QualType Ty) const;
+  bool isCompoundType(QualType Ty) const;
+  bool isVectorArgumentType(QualType Ty) const;
+  bool isFPArgumentType(QualType Ty) const;
+  QualType GetSingleElementType(QualType Ty) const;
+  bool IsLikeComplexType(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;
+    }
+  }
+
+  Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+                    QualType Ty) 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;
+
+  // 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::isCompoundType(QualType Ty) const {
+  return (Ty->isAnyComplexType() || Ty->isVectorType() ||
+          isAggregateTypeForABI(Ty));
+}
+
+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;
+}
+
+QualType ZOSXPLinkABIInfo::GetSingleElementType(QualType Ty) const {
+  if (const RecordType *RT = Ty->getAsStructureType()) {
+    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))
+      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()) {
+      // For compatibility with GCC, ignore empty bitfields in C++ mode.
+      // Unlike isSingleElementStruct(), empty structure and array fields
+      // do count.  So do anonymous bitfields that aren't zero-sized.
+      if (getContext().getLangOpts().CPlusPlus &&
+          FD->isZeroLengthBitField(getContext()))
+        continue;
+
+      // Unlike isSingleElementStruct(), arrays do not count.
+      // Nested structures still do though.
+      if (!Found.isNull())
+        return Ty;
+      Found = GetSingleElementType(FD->getType());
+    }
+
+    // Unlike isSingleElementStruct(), trailing padding is allowed.
+    // An 8-byte aligned struct s { float f; } is passed as a double.
+    if (!Found.isNull())
+      return Found;
+  }
+
+  return Ty;
+}
+
+bool ZOSXPLinkABIInfo::IsLikeComplexType(QualType Ty) const {
+  if (const RecordType *RT = Ty->getAsStructureType()) {
+    const RecordDecl *RD = RT->getDecl();
+    int i = 0;
+    clang::BuiltinType::Kind elemKind;
+
+    // Check for exactly two elements with exactly the same floating point type.
+    for (const auto *FD : RD->fields()) {
+      if (i >= 2)
+        return false;
+
+      QualType FT = FD->getType();
+      if (const BuiltinType *BT = FT->getAs<BuiltinType>()) {
+        switch (BT->getKind()) {
+        case BuiltinType::Float:
+        case BuiltinType::Double:
+        case BuiltinType::LongDouble:
+          if (i == 0) {
+            elemKind = BT->getKind();
+            break;
+          } else if (elemKind == BT->getKind())
+            break;
+          else
+            return false;
+        default:
+          return false;
+        }
+      } else
+        return false;
+
+      i++;
+    }
+
+    return i == 2;
+  }
+  return false;
+}
+
+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 (IsLikeComplexType(RetTy))
+      return ABIArgInfo::getDirect();
+  }
+
+  // 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);
+      CoerceTy = llvm::ArrayType::get(CoerceTy, NumElements);
+      return ABIArgInfo::getDirectInReg(CoerceTy);
+    } else
+      return getNaturalAlignIndirect(RetTy);
+  }
+
+  // Treat an enum type as its underlying type.
+  if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+    RetTy = EnumTy->getDecl()->getIntegerType();
+
+  return (isPromotableIntegerType(RetTy) ? ABIArgInfo::getExtend(RetTy)
+                                         : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType Ty,
+                                                  bool IsNamedArg) const {
+  // 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);
+
+  // Complex types are passed by value as per the XPLINK docs.
+  // If place available, their members will be placed in FPRs.
+  if (Ty->isAnyComplexType() && IsNamedArg)
+    return ABIArgInfo::getDirect();
+
+  // Handle vector types and vector-like structure types. Note that
+  // as opposed to float-like structure types, we do not allow any
+  // padding for vector-like structures, so verify the sizes match.
+  uint64_t Size = getContext().getTypeSize(Ty);
+  QualType SingleElementTy = GetSingleElementType(Ty);
+  if (isVectorArgumentType(SingleElementTy) &&
+      getContext().getTypeSize(SingleElementTy) == Size)
+    return ABIArgInfo::getDirect(CGT.ConvertType(SingleElementTy));
+
+  // Handle structures. They are returned by value.
+  // If not complex like types, they are passed in GPRs, if possible.
+  // If place available, complex like types will have their members
+  // placed in FPRs.
+  if (Ty->getAs<RecordType>() || Ty->isAnyComplexType()) {
+    if (IsLikeComplexType(Ty) && IsNamedArg)
+      return ABIArgInfo::getDirect();
+
+    if (isAggregateTypeForABI(Ty) || Ty->isAnyComplexType()) {
+      // MVS64 alligns on 8 bytes.
+      uint64_t ABIAlign = CharUnits::fromQuantity(8).getQuantity();
+      const uint64_t RegBits = ABIAlign * 8;
+
+      // 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;
+
+      // Struct types up to 8 bytes are passed as integer type (which  will be
+      // properly aligned in the argument save area doubleword).
+      if (Bits <= GPRBits)
+        CoerceTy = llvm::IntegerType::get(getVMContext(), RegBits);
+      // Larger types are passed as arrays, with the base type selected
+      // according to the required alignment in the save area.
+      else {
+        uint64_t NumRegs = llvm::alignTo(Bits, RegBits) / RegBits;
+        llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits);
+        CoerceTy = llvm::ArrayType::get(RegTy, NumRegs);
+      }
+
+      return ABIArgInfo::getDirectInReg(CoerceTy);
+    }
+
+    return ABIArgInfo::getDirectInReg();
+  }
+
+  // Non-structure compounds are passed indirectly, i.e. arrays.
+  if (isCompoundType(Ty))
+    return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+
+  return ABIArgInfo::getDirect();
+}
+
+Address ZOSXPLinkABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+                                    QualType Ty) const {
+  return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
+                          CGF.getContext().getTypeInfoInChars(Ty),
+                          CharUnits::fromQuantity(8),
+                          /*allowHigherAlign*/ false);
+}
+
 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..9c2fb1308523d
--- /dev/null
+++ b/clang/test/CodeGen/zos-abi.c
@@ -0,0 +1,137 @@
+// 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
+
+// Scalar types
+
+char pass_char(char arg) { return arg; }
+// CHECK-LABEL: define signext i8 @pass_char(i8 signext %{{.*}})
+
+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 %{{.*}})
+
+// Complex types
+
+// TODO: Add tests for complex integer 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 %struct.complexlike_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 %struct.complexlike_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 %struct.complexlike_longdouble @pass_complexlike_longdouble(fp128 %{{.*}}, fp128 %{{.*}})
+
+// Aggregate types
+
+struct agg_1byte { char a[1]; };
+struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_1byte(i64 inreg %{{.*}})
+
+struct agg_2byte { char a[2]; };
+struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_2byte(i64 inreg %{{.*}})
+
+struct agg_3byte { char a[3]; };
+struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_3byte(i64 inreg %{{.*}})
+
+struct agg_4byte { char a[4]; };
+struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_4byte(i64 inreg %{{.*}})
+
+struct agg_5byte { char a[5]; };
+struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_5byte(i64 inreg %{{.*}})
+
+struct agg_6byte { char a[6]; };
+struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_6byte(i64 inreg %{{.*}})
+
+struct agg_7byte { char a[7]; };
+struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_7byte(i64 inreg %{{.*}})
+
+struct agg_8byte { char a[8]; };
+struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_8byte(i64 inreg %{{.*}})
+
+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] inreg %{{.*}})
+
+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] inreg %{{.*}})
+
+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] inreg %{{.*}})
+
+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] inreg %{{.*}})
+
+// 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 [1 x i64] @pass_agg_float(i64 inreg %{{.*}})
+
+// 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 [1 x i64] @pass_agg_nofloat2(i64 inreg %{{.*}})
+
+struct agg_nofloat3 { float a; int : 0; };
+struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_nofloat3(i64 inreg %{{.*}})

>From d5a673b42c8ae9f89f018bf04e9720ebf7df0d4a Mon Sep 17 00:00:00 2001
From: Fanbo Meng <Fanbo.Meng at ibm.com>
Date: Tue, 7 May 2024 15:41:08 -0400
Subject: [PATCH 2/3] apply clang-format

---
 clang/lib/CodeGen/Targets/SystemZ.cpp | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 903e7391b314d..1eef5aa83e6e7 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -540,8 +540,7 @@ class ZOSXPLinkABIInfo : public ABIInfo {
   bool HasVector;
 
 public:
-  ZOSXPLinkABIInfo(CodeGenTypes &CGT, bool HV)
-      : ABIInfo(CGT), HasVector(HV) {}
+  ZOSXPLinkABIInfo(CodeGenTypes &CGT, bool HV) : ABIInfo(CGT), HasVector(HV) {}
 
   bool isPromotableIntegerType(QualType Ty) const;
   bool isCompoundType(QualType Ty) const;
@@ -575,9 +574,9 @@ 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);
-      }
+    SwiftInfo =
+        std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
+  }
 };
 
 } // namespace

>From b79c247abbc34d79e52d7239348fd49cb3666bbe Mon Sep 17 00:00:00 2001
From: Fanbo Meng <Fanbo.Meng at ibm.com>
Date: Wed, 8 May 2024 09:43:57 -0400
Subject: [PATCH 3/3] improve format; remove redundant code; Do not use 1
 element array for return type

---
 clang/lib/CodeGen/Targets/SystemZ.cpp | 25 ++++++++++++-------------
 clang/test/CodeGen/zos-abi.c          | 22 +++++++++++-----------
 2 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 1eef5aa83e6e7..fd35161498031 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -694,15 +694,17 @@ bool ZOSXPLinkABIInfo::IsLikeComplexType(QualType Ty) const {
           if (i == 0) {
             elemKind = BT->getKind();
             break;
-          } else if (elemKind == BT->getKind())
+          } else if (elemKind == BT->getKind()) {
             break;
-          else
+          } else {
             return false;
+          }
         default:
           return false;
         }
-      } else
+      } else {
         return false;
+      }
 
       i++;
     }
@@ -748,16 +750,13 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyReturnType(QualType RetTy) const {
       // Types between 16 and 24 bytes are passed as integer types in GPR1, 2
       // and 3.
       llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
-      CoerceTy = llvm::ArrayType::get(CoerceTy, NumElements);
+      if (NumElements > 1)
+        CoerceTy = llvm::ArrayType::get(CoerceTy, NumElements);
       return ABIArgInfo::getDirectInReg(CoerceTy);
-    } else
-      return getNaturalAlignIndirect(RetTy);
+    }
+    return getNaturalAlignIndirect(RetTy);
   }
 
-  // Treat an enum type as its underlying type.
-  if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
-    RetTy = EnumTy->getDecl()->getIntegerType();
-
   return (isPromotableIntegerType(RetTy) ? ABIArgInfo::getExtend(RetTy)
                                          : ABIArgInfo::getDirect());
 }
@@ -805,13 +804,13 @@ ABIArgInfo ZOSXPLinkABIInfo::classifyArgumentType(QualType Ty,
       uint64_t Bits = getContext().getTypeSize(Ty);
       llvm::Type *CoerceTy;
 
-      // Struct types up to 8 bytes are passed as integer type (which  will be
+      // Struct types up to 8 bytes are passed as integer type (which will be
       // properly aligned in the argument save area doubleword).
-      if (Bits <= GPRBits)
+      if (Bits <= GPRBits) {
         CoerceTy = llvm::IntegerType::get(getVMContext(), RegBits);
       // Larger types are passed as arrays, with the base type selected
       // according to the required alignment in the save area.
-      else {
+      } else {
         uint64_t NumRegs = llvm::alignTo(Bits, RegBits) / RegBits;
         llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits);
         CoerceTy = llvm::ArrayType::get(RegTy, NumRegs);
diff --git a/clang/test/CodeGen/zos-abi.c b/clang/test/CodeGen/zos-abi.c
index 9c2fb1308523d..0c6532d2a1fd6 100644
--- a/clang/test/CodeGen/zos-abi.c
+++ b/clang/test/CodeGen/zos-abi.c
@@ -75,35 +75,35 @@ struct complexlike_longdouble pass_complexlike_longdouble(struct complexlike_lon
 
 struct agg_1byte { char a[1]; };
 struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_1byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_1byte(i64 inreg %{{.*}})
 
 struct agg_2byte { char a[2]; };
 struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_2byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_2byte(i64 inreg %{{.*}})
 
 struct agg_3byte { char a[3]; };
 struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_3byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_3byte(i64 inreg %{{.*}})
 
 struct agg_4byte { char a[4]; };
 struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_4byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_4byte(i64 inreg %{{.*}})
 
 struct agg_5byte { char a[5]; };
 struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_5byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_5byte(i64 inreg %{{.*}})
 
 struct agg_6byte { char a[6]; };
 struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_6byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_6byte(i64 inreg %{{.*}})
 
 struct agg_7byte { char a[7]; };
 struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_7byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_7byte(i64 inreg %{{.*}})
 
 struct agg_8byte { char a[8]; };
 struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_8byte(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_8byte(i64 inreg %{{.*}})
 
 struct agg_9byte { char a[9]; };
 struct agg_9byte pass_agg_9byte(struct agg_9byte arg) { return arg; }
@@ -124,14 +124,14 @@ struct agg_25byte pass_agg_25byte(struct agg_25byte arg) { return arg; }
 // 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 [1 x i64] @pass_agg_float(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_float(i64 inreg %{{.*}})
 
 // 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 [1 x i64] @pass_agg_nofloat2(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_nofloat2(i64 inreg %{{.*}})
 
 struct agg_nofloat3 { float a; int : 0; };
 struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_nofloat3(i64 inreg %{{.*}})
+// CHECK-LABEL: define inreg i64 @pass_agg_nofloat3(i64 inreg %{{.*}})



More information about the cfe-commits mailing list