diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.h b/flang/lib/Optimizer/CodeGen/TypeConverter.h --- a/flang/lib/Optimizer/CodeGen/TypeConverter.h +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.h @@ -29,6 +29,7 @@ LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n"); // Each conversion should return a value of type mlir::Type. + addConversion([&](BoxType box) { return convertBoxType(box); }); addConversion( [&](fir::RecordType derived) { return convertRecordType(derived); }); addConversion( @@ -60,6 +61,78 @@ return mlir::Type(); } + // Is an extended descriptor needed given the element type of a fir.box type ? + // Extended descriptors are required for derived types. + bool requiresExtendedDesc(mlir::Type boxElementType) { + auto eleTy = fir::unwrapSequenceType(boxElementType); + return eleTy.isa(); + } + + // Magic value to indicate we do not know the rank of an entity, either + // because it is assumed rank or because we have not determined it yet. + static constexpr int unknownRank() { return -1; } + + // This corresponds to the descriptor as defined in ISO_Fortran_binding.h and + // the addendum defined in descriptor.h. + mlir::Type convertBoxType(BoxType box, int rank = unknownRank()) { + // (base_addr*, elem_len, version, rank, type, attribute, f18Addendum, [dim] + SmallVector dataDescFields; + mlir::Type ele = box.getEleTy(); + // remove fir.heap/fir.ref/fir.ptr + if (auto removeIndirection = fir::dyn_cast_ptrEleTy(ele)) + ele = removeIndirection; + auto eleTy = convertType(ele); + // base_addr* + if (ele.isa() && eleTy.isa()) + dataDescFields.push_back(eleTy); + else + dataDescFields.push_back(mlir::LLVM::LLVMPointerType::get(eleTy)); + // elem_len + dataDescFields.push_back(getDescFieldTypeModel<1>()(&getContext())); + // version + dataDescFields.push_back(getDescFieldTypeModel<2>()(&getContext())); + // rank + dataDescFields.push_back(getDescFieldTypeModel<3>()(&getContext())); + // type + dataDescFields.push_back(getDescFieldTypeModel<4>()(&getContext())); + // attribute + dataDescFields.push_back(getDescFieldTypeModel<5>()(&getContext())); + // f18Addendum + dataDescFields.push_back(getDescFieldTypeModel<6>()(&getContext())); + // [dims] + if (rank == unknownRank()) { + if (auto seqTy = ele.dyn_cast()) + rank = seqTy.getDimension(); + else + rank = 0; + } + if (rank > 0) { + auto rowTy = getDescFieldTypeModel<7>()(&getContext()); + dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank)); + } + // opt-type-ptr: i8* (see fir.tdesc) + if (requiresExtendedDesc(ele)) { + dataDescFields.push_back( + getExtendedDescFieldTypeModel<8>()(&getContext())); + auto rowTy = getExtendedDescFieldTypeModel<9>()(&getContext()); + dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, 1)); + if (auto recTy = fir::unwrapSequenceType(ele).dyn_cast()) + if (recTy.getNumLenParams() > 0) { + // The descriptor design needs to be clarified regarding the number of + // length parameters in the addendum. Since it can change for + // polymorphic allocatables, it seems all length parameters cannot + // always possibly be placed in the addendum. + TODO_NOLOC("extended descriptor derived with length parameters"); + unsigned numLenParams = recTy.getNumLenParams(); + dataDescFields.push_back( + mlir::LLVM::LLVMArrayType::get(rowTy, numLenParams)); + } + } + return mlir::LLVM::LLVMPointerType::get( + mlir::LLVM::LLVMStructType::getLiteral(&getContext(), dataDescFields, + /*isPacked=*/false)); + } + template mlir::Type convertPointerLike(A &ty) { mlir::Type eleTy = ty.getEleTy(); diff --git a/flang/test/Fir/types-to-llvm.fir b/flang/test/Fir/types-to-llvm.fir --- a/flang/test/Fir/types-to-llvm.fir +++ b/flang/test/Fir/types-to-llvm.fir @@ -29,3 +29,22 @@ // CHECK-LABEL: foo1 // CHECK-SAME: !llvm.ptr> +// ----- + +// Test box types `!fir.box` + +func private @foo0(%arg0: !fir.box>) +// CHECK-LABEL: foo0 +// CHECK-SAME: !llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>> + +func private @foo1(%arg0: !fir.box>) +// CHECK-LABEL: foo1 +// CHECK-SAME: !llvm.ptr>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>> + +func private @foo2(%arg0: !fir.box>) +// CHECK-LABEL: foo2 +// CHECK-SAME: !llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>> + +func private @foo3(%arg0: !fir.box>) +// CHECK-LABEL: foo3 +// CHECK-SAME: !llvm.ptr>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>>