[flang-commits] [flang] [flang] RISCV64 support for BIND(C) derived types (PR #198335)

via flang-commits flang-commits at lists.llvm.org
Wed May 20 01:53:44 PDT 2026


================
@@ -1425,6 +1433,301 @@ struct TargetRISCV64 : public GenericTarget<TargetRISCV64> {
     }
     return marshal;
   }
+
+  void checkValidTypeOrCrash(mlir::Location loc, mlir::Type type) const {
+    llvm::TypeSwitch<mlir::Type>(type)
+        .Case<mlir::IntegerType>([&](auto integerTy) {
+          // 128 bit int will be passed like any other 128bit struct as 2
+          // registers.
+          if (integerTy.getWidth() > 128)
+            TODO(loc,
+                 "integerType with width exceeding 128 bits is unsupported");
+        })
+        .Case<mlir::FloatType>([&](auto floatTy) {
+          if (floatTy.getWidth() > 64)
+            TODO(loc, "128 bit float is not supported by RISCV64");
+        })
+        .Case([&](mlir::ComplexType cmplx) {
+          const auto *sem = &floatToSemantics(kindMap, cmplx.getElementType());
+          if (sem != &llvm::APFloat::IEEEsingle() &&
+              sem != &llvm::APFloat::IEEEdouble())
+            TODO(loc, "unsupported complex type(not IEEEsingle, IEEEdouble) "
+                      "as a structure component for BIND(C), "
+                      "VALUE derived type argument and type return");
+        })
+        .Case<fir::LogicalType, fir::CharacterType>([&](auto ty) {
+          // Always fine, characters with len>1 get already rejected before.
+        })
+        .Case([&](fir::RecordType recTy) {
+          for (auto [name, ty] : recTy.getTypeList())
+            checkValidTypeOrCrash(loc, ty);
+        })
+        .Case([&](fir::SequenceType seqTy) {
+          if (seqTy.hasDynamicExtents())
+            TODO(loc, "passing dynamic sequence argument to C by value is not "
+                      "supported");
+          checkValidTypeOrCrash(loc, seqTy.getElementType());
+        })
+        .Case([&](fir::VectorType vecTy) {
+          TODO(loc, "passing vector argument to C by value is not supported");
+        })
+        .Default([&](mlir::Type ty) {
+          if (!fir::conformsWithPassByRef(ty))
+            TODO(loc, "unsupported component type for BIND(C), VALUE derived "
+                      "type argument and type return");
+        });
+  }
+
+  CodeGenSpecifics::Marshalling
+  passOnTheStack(unsigned short recAlign, mlir::Type ty, bool isResult) const {
+    CodeGenSpecifics::Marshalling marshal;
+    // The stack is always 8 byte aligned
+    unsigned short align = std::max(recAlign, static_cast<unsigned short>(8));
+    marshal.emplace_back(fir::ReferenceType::get(ty),
+                         AT{align, /*byval=*/!isResult, /*sret=*/isResult});
+    return marshal;
+  }
+
+  // Flatten a RecordType::TypeList containing more record types or array types
+  static std::vector<mlir::Type>
+  flattenTypeList(const RecordType::TypeList &types) {
+    std::vector<mlir::Type> flatTypes;
+    // The flat list will be at least the same size as the non-flat list.
+    flatTypes.reserve(types.size());
+    for (auto [c, type] : types) {
+      // Flatten record type
+      if (auto recTy = mlir::dyn_cast<RecordType>(type)) {
+        auto subTypeList = flattenTypeList(recTy.getTypeList());
+        llvm::copy(subTypeList, std::back_inserter(flatTypes));
+        continue;
+      }
+
+      // Flatten array type
+      if (auto seqTy = mlir::dyn_cast<SequenceType>(type)) {
+        assert(!seqTy.hasDynamicExtents() &&
+               "dynamic sequences should have been caught before.");
+        std::size_t n = seqTy.getConstantArraySize();
+        auto eleTy = seqTy.getElementType();
+        // Flatten array of record types
+        if (auto recTy = mlir::dyn_cast<RecordType>(eleTy)) {
+          auto subTypeList = flattenTypeList(recTy.getTypeList());
+          for (std::size_t i = 0; i < n; ++i)
+            llvm::copy(subTypeList, std::back_inserter(flatTypes));
+        } else {
+          std::fill_n(std::back_inserter(flatTypes),
+                      seqTy.getConstantArraySize(), eleTy);
+        }
+        continue;
+      }
+
+      // Complex type is made up of 2 floats
+      if (auto compTy = mlir::dyn_cast<mlir::ComplexType>(type)) {
+        flatTypes.push_back(compTy.getElementType());
+        flatTypes.push_back(compTy.getElementType());
+        continue;
+      }
+
+      // Other types are already flat
+      flatTypes.push_back(type);
+    }
+    return flatTypes;
+  }
+
+  static bool floatAndCanPassInRegister(const mlir::Type &ty) {
+    return mlir::isa<mlir::FloatType>(ty) &&
+           mlir::cast<mlir::FloatType>(ty).getWidth() <= defaultWidth;
+  }
+
+  static bool integerAndCanPassInRegister(const mlir::Type &ty) {
+    return mlir::isa<mlir::IntegerType>(ty) &&
+           mlir::cast<mlir::IntegerType>(ty).getWidth() <= defaultWidth;
+  }
+
+  void checkAvailableRegisters(mlir::Location loc,
+                               const Marshalling &previousArguments,
+                               int &gprArgs, int &fprArgs) const {
+    for (auto [ty, attr] : previousArguments) {
+      if (gprArgs <= 0 && fprArgs <= 0)
+        break;
+
+      // previous argument was passed by value and thus takes no registers.
+      if (attr.isByVal())
+        continue;
----------------
jeanPerier wrote:

This may be correct, I just want to double check that the stack address is not being passed in register in that case on RISCV64 (the LoongArch64 is considering them for instance).

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


More information about the flang-commits mailing list