================
@@ -544,9 +544,421 @@ 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 isCompoundType(QualType Ty) const;
+  bool isVectorArgumentType(QualType Ty) const;
+  bool isFPArgumentType(QualType Ty) const;
+  QualType getSingleElementType(QualType Ty) const;
+  unsigned getMaxAlignFromTypeDefs(QualType Ty) const;
+  std::optional<QualType> getFPTypeOfComplexLikeType(QualType Ty) const;
+
+  ABIArgInfo classifyReturnType(QualType RetTy,
+                                unsigned functionCallConv) const;
+  ABIArgInfo classifyArgumentType(QualType ArgTy, bool IsNamedArg,
+                                  unsigned functionCallConv) const;
+
+  void computeInfo(CGFunctionInfo &FI) const override {
+    if (!getCXXABI().classifyReturnType(FI))
+      FI.getReturnInfo() =
+          classifyReturnType(FI.getReturnType(), FI.getCallingConvention());
+
+    unsigned NumRequiredArgs = FI.getNumRequiredArgs();
+    unsigned ArgNo = 0;
+
+    for (auto &I : FI.arguments()) {
+      bool IsNamedArg = ArgNo < NumRequiredArgs;
+      I.info =
+          classifyArgumentType(I.type, IsNamedArg, FI.getCallingConvention());
+      ++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;
+
+  // 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 {
+  // 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;
+  }
+
+  if (const RecordType *RT = Ty->getAsStructureType()) {
+    const RecordDecl *RD = RT->getDecl();
+    QualType Found;
+
+    // If this is a C++ class/struct, inspect its base classes first.
+    if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+      for (const auto &I : CXXRD->bases()) {
+        QualType Base = I.getType();
+
+        // Skip empty base classes, they cannot contribute a data member.
+        if (isEmptyRecord(getContext(), Base, true))
+          continue;
+
+        // A candidate base type was already found; encountering another
+        // non-empty base means the choice is no longer unique. Return the type
+        // from the first candidate.
+        if (!Found.isNull())
+          return Ty;
+        Found = getSingleElementType(Base);
+      }
+
+    // Now inspect the record's own fields. We allow at most one field to
+    // contribute a single element type. If we've already recorded one
+    // candidate, encountering another field immediately disqualifies the
+    // record from being a single element aggregate.
+    for (const auto *FD : RD->fields()) {
+      if (!Found.isNull())
+        return Ty; // more than one field,  not a single-element
+      Found = getSingleElementType(FD->getType());
+    }
+    return Found.isNull() ? Ty : Found;
+  }
+  return Ty; // not record/union, unchanged
+}
+
+unsigned ZOSXPLinkABIInfo::getMaxAlignFromTypeDefs(QualType Ty) const {
+  unsigned MaxAlign = 0;
+  clang::QualType Cur = Ty;
+
+  while (true) {
+    if (auto *TypedefTy = dyn_cast<TypedefType>(Cur.getTypePtr())) {
+      auto *TyDecl = TypedefTy->getDecl();
+      unsigned CurrAlign = TyDecl->getMaxAlignment();
+      MaxAlign = std::max(CurrAlign, MaxAlign);
+    }
+    // Peel exactly one sugar layer (Typedef, Attributed, Paren, Elaborated,
+    // etc.).
+    clang::QualType Next = Cur.getSingleStepDesugaredType(getContext());
+    if (Next == Cur) // no more sugar to peel
+      break;
+    Cur = Next;
+  }
+  return MaxAlign;
+}
+
+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;
+
+      unsigned MaxAlignOnDecl = FD->getMaxAlignment();
+      QualType FT = FD->getType();
+      QualType FTSingleTy = getSingleElementType(FT);
+      unsigned MaxAlign =
+          std::max(getMaxAlignFromTypeDefs(FTSingleTy), MaxAlignOnDecl);
+
+      // The first element of a complex type may have an alignment enforced
+      // that is less strict than twice its size, since that would be naturally
+      // enforced by any complex type anyways. The second element may have an
+      // alignment enforced that is less strict than its size.
+      if (Count == 0) {
+        if (MaxAlign > 2 * getContext().getTypeSize(FTSingleTy))
+          return std::nullopt;
+      } else if (Count == 1) {
+        if (MaxAlign > getContext().getTypeSize(FTSingleTy))
+          return std::nullopt;
+      }
----------------
zibi2 wrote:

It looks like I can simplify this. I write additional lit test to validate that 
existing code and new I'm going to push produced the same layout.

https://github.com/llvm/llvm-project/pull/188501
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to