[clang] [flang] [Flang] LoongArch64 support for BIND(C) derived types in mabi=lp64d. (PR #117108)

Tom Eccles via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 26 03:19:57 PST 2024


================
@@ -1151,6 +1154,311 @@ struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> {
 
     return GenericTarget::integerArgumentType(loc, argTy);
   }
+
+  /// Flatten non-basic types, resulting in an array of types containing only
+  /// `IntegerType` and `FloatType`.
+  std::vector<mlir::Type> flattenTypeList(mlir::Location loc,
+                                          const mlir::Type type) const {
+    std::vector<mlir::Type> flatTypes;
+
+    llvm::TypeSwitch<mlir::Type>(type)
+        .template Case<mlir::IntegerType>([&](mlir::IntegerType intTy) {
+          if (intTy.getWidth() != 0)
+            flatTypes.push_back(intTy);
+        })
+        .template Case<mlir::FloatType>([&](mlir::FloatType floatTy) {
+          if (floatTy.getWidth() != 0)
+            flatTypes.push_back(floatTy);
+        })
+        .template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
+          const auto *sem = &floatToSemantics(kindMap, cmplx.getElementType());
+          if (sem == &llvm::APFloat::IEEEsingle() ||
+              sem == &llvm::APFloat::IEEEdouble() ||
+              sem == &llvm::APFloat::IEEEquad())
+            std::fill_n(std::back_inserter(flatTypes), 2,
+                        cmplx.getElementType());
+          else
+            TODO(loc, "unsupported complx type(not IEEEsingle, IEEEdouble, "
+                      "IEEEquad) as a structure component for BIND(C), "
+                      "VALUE derived type argument and type return");
+        })
+        .template Case<fir::LogicalType>([&](fir::LogicalType logicalTy) {
+          const auto width = kindMap.getLogicalBitsize(logicalTy.getFKind());
+          if (width != 0)
+            flatTypes.push_back(
+                mlir::IntegerType::get(type.getContext(), width));
+        })
+        .template Case<fir::CharacterType>([&](fir::CharacterType charTy) {
+          flatTypes.push_back(mlir::IntegerType::get(type.getContext(), 8));
+        })
+        .template Case<fir::SequenceType>([&](fir::SequenceType seqTy) {
+          if (!seqTy.hasDynamicExtents()) {
+            std::size_t numOfEle = seqTy.getConstantArraySize();
+            auto eleTy = seqTy.getEleTy();
+            if (!mlir::isa<mlir::IntegerType, mlir::FloatType>(eleTy)) {
+              auto subTypeList = flattenTypeList(loc, eleTy);
+              if (subTypeList.size() != 0)
+                for (std::size_t i = 0; i < numOfEle; ++i)
+                  llvm::copy(subTypeList, std::back_inserter(flatTypes));
+            } else {
+              std::fill_n(std::back_inserter(flatTypes), numOfEle, eleTy);
+            }
+          } else
+            TODO(loc, "unsupported dynamic extent sequence type as a structure "
+                      "component for BIND(C), "
+                      "VALUE derived type argument and type return");
+        })
+        .template Case<fir::RecordType>([&](fir::RecordType recTy) {
+          for (auto component : recTy.getTypeList()) {
+            mlir::Type eleTy = component.second;
+            auto subTypeList = flattenTypeList(loc, eleTy);
+            if (subTypeList.size() != 0)
+              llvm::copy(subTypeList, std::back_inserter(flatTypes));
+          }
+        })
+        .template Case<fir::VectorType>([&](fir::VectorType vecTy) {
+          std::size_t numOfEle = vecTy.getLen();
+          auto eleTy = vecTy.getEleTy();
+          if (!(mlir::isa<mlir::IntegerType, mlir::FloatType>(eleTy))) {
+            auto subTypeList = flattenTypeList(loc, eleTy);
+            if (subTypeList.size() != 0)
+              for (std::size_t i = 0; i < numOfEle; ++i)
+                llvm::copy(subTypeList, std::back_inserter(flatTypes));
+          } else {
+            std::fill_n(std::back_inserter(flatTypes), numOfEle, eleTy);
+          }
+        })
+        .Default([&](mlir::Type ty) {
+          if (fir::conformsWithPassByRef(ty))
+            flatTypes.push_back(
+                mlir::IntegerType::get(type.getContext(), GRLen));
+          else
+            TODO(loc, "unsupported component type for BIND(C), VALUE derived "
+                      "type argument and type return");
+        });
+
+    return flatTypes;
+  }
+
+  /// Determine if a struct is eligible to be passed in FARs (and GARs) (i.e.,
+  /// when flattened it contains a single fp value, fp+fp, or int+fp of
+  /// appropriate size).
+  bool detectFARsEligibleStruct(mlir::Location loc, fir::RecordType recTy,
+                                mlir::Type &Field1Ty,
+                                mlir::Type &Field2Ty) const {
+
+    Field1Ty = Field2Ty = nullptr;
+    auto flatTypes = flattenTypeList(loc, recTy);
+    size_t flatSize = flatTypes.size();
+
+    // Cannot be eligible if the number of flattened types is equal to 0 or
+    // greater than 2.
+    if (flatSize == 0 || flatSize > 2)
+      return false;
+
+    bool isFirstAvaliableFloat = false;
+
+    assert((mlir::isa<mlir::IntegerType, mlir::FloatType>(flatTypes[0])) &&
+           "Type must be int or float after flattening");
+    if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(flatTypes[0])) {
+      auto Size = floatTy.getWidth();
+      // Can't be eligible if larger than the FP registers. Half precision isn't
+      // currently supported on LoongArch and the ABI hasn't been confirmed, so
+      // default to the integer ABI in that case.
+      if (Size > FRLen || Size < 32)
+        return false;
+      isFirstAvaliableFloat = true;
+      Field1Ty = floatTy;
+    } else if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(flatTypes[0])) {
+      if (intTy.getWidth() > GRLen)
+        return false;
+      Field1Ty = intTy;
+    }
+
+    // flatTypes has two elements
+    if (flatSize == 2) {
+      assert((mlir::isa<mlir::IntegerType, mlir::FloatType>(flatTypes[1])) &&
+             "Type must be integer or float after flattening");
+      if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(flatTypes[1])) {
+        auto Size = floatTy.getWidth();
+        if (Size > FRLen || Size < 32)
+          return false;
+        Field2Ty = floatTy;
+        return true;
+      } else if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(flatTypes[1])) {
+        // Can't be eligible if an integer type was already found (int+int pairs
+        // are not eligible).
+        if (!isFirstAvaliableFloat)
+          return false;
+        if (intTy.getWidth() > GRLen)
+          return false;
+        Field2Ty = intTy;
+        return true;
+      }
+    }
+
+    // return isFirstAvaliableFloat if flatTypes only has one element
+    return isFirstAvaliableFloat;
+  }
+
+  bool checkTypehasEnoughReg(mlir::Location loc, int &GARsLeft, int &FARsLeft,
+                             const mlir::Type type) const {
+    if (type == nullptr)
+      return true;
+
+    llvm::TypeSwitch<mlir::Type>(type)
+        .template Case<mlir::IntegerType>([&](mlir::IntegerType intTy) {
+          const auto width = intTy.getWidth();
+          assert(width <= 128 &&
+                 "integer type with width more than 128 bits is unexpected");
----------------
tblah wrote:

nit: I don't think flang supports integers larger than 128 bits, but it would be easy to forget to update this line if that were added later. I think this should be a `TODO()` so that non-assertion builds do not generate incorrect code in this case.

https://github.com/llvm/llvm-project/pull/117108


More information about the cfe-commits mailing list