[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