diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt index 711bb402b40bd..016544ef870a5 100644 --- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt +++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt @@ -6,6 +6,7 @@ add_flang_library(FIRCodeGen TBAABuilder.cpp Target.cpp TargetRewrite.cpp + TypeConverter.cpp DEPENDS FIRDialect diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp new file mode 100644 index 0000000000000..e6d8f62e7ec57 --- /dev/null +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp @@ -0,0 +1,344 @@ +//===-- TypeConverter.cpp -- type conversion --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "flang-type-conversion" + +#include "TypeConverter.h" +#include "DescriptorModel.h" +#include "TBAABuilder.h" +#include "Target.h" +#include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Dialect/Support/FIRContext.h" +#include "flang/Optimizer/Dialect/Support/KindMapping.h" +#include "mlir/Conversion/LLVMCommon/TypeConverter.h" +#include "llvm/Support/Debug.h" + +namespace fir { + +LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA) + : mlir::LLVMTypeConverter(module.getContext(), + [&] { + mlir::LowerToLLVMOptions options( + module.getContext()); + options.useOpaquePointers = false; + return options; + }()), + kindMapping(getKindMapping(module)), + specifics(CodeGenSpecifics::get(module.getContext(), + getTargetTriple(module), + getKindMapping(module))), + tbaaBuilder(module, applyTBAA) { + 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([&](BoxCharType boxchar) { + LLVM_DEBUG(llvm::dbgs() << "type convert: " << boxchar << '\n'); + return convertType(specifics->boxcharMemoryType(boxchar.getEleTy())); + }); + addConversion([&](BoxProcType boxproc) { + // TODO: Support for this type will be added later when the Fortran 2003 + // procedure pointer feature is implemented. + return std::nullopt; + }); + addConversion( + [&](fir::ClassType classTy) { return convertBoxType(classTy); }); + addConversion( + [&](fir::CharacterType charTy) { return convertCharType(charTy); }); + addConversion( + [&](fir::ComplexType cmplx) { return convertComplexType(cmplx); }); + addConversion([&](fir::FieldType field) { + // Convert to i32 because of LLVM GEP indexing restriction. + return mlir::IntegerType::get(field.getContext(), 32); + }); + addConversion([&](HeapType heap) { return convertPointerLike(heap); }); + addConversion([&](fir::IntegerType intTy) { + return mlir::IntegerType::get( + &getContext(), kindMapping.getIntegerBitsize(intTy.getFKind())); + }); + addConversion([&](fir::LenType field) { + // Get size of len paramter from the descriptor. + return getModel()( + &getContext()); + }); + addConversion([&](fir::LogicalType boolTy) { + return mlir::IntegerType::get( + &getContext(), kindMapping.getLogicalBitsize(boolTy.getFKind())); + }); + addConversion([&](fir::LLVMPointerType pointer) { + return convertPointerLike(pointer); + }); + addConversion( + [&](fir::PointerType pointer) { return convertPointerLike(pointer); }); + addConversion([&](fir::RecordType derived, + llvm::SmallVectorImpl &results, + llvm::ArrayRef callStack) { + return convertRecordType(derived, results, callStack); + }); + addConversion( + [&](fir::RealType real) { return convertRealType(real.getFKind()); }); + addConversion( + [&](fir::ReferenceType ref) { return convertPointerLike(ref); }); + addConversion([&](fir::SequenceType sequence) { + return convertSequenceType(sequence); + }); + addConversion([&](fir::TypeDescType tdesc) { + return convertTypeDescType(tdesc.getContext()); + }); + addConversion([&](fir::VectorType vecTy) { + return mlir::VectorType::get(llvm::ArrayRef(vecTy.getLen()), + convertType(vecTy.getEleTy())); + }); + addConversion([&](mlir::TupleType tuple) { + LLVM_DEBUG(llvm::dbgs() << "type convert: " << tuple << '\n'); + llvm::SmallVector members; + for (auto mem : tuple.getTypes()) { + // Prevent fir.box from degenerating to a pointer to a descriptor in the + // context of a tuple type. + if (auto box = mem.dyn_cast()) + members.push_back(convertBoxTypeAsStruct(box)); + else + members.push_back(convertType(mem).cast()); + } + return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), members, + /*isPacked=*/false); + }); + addConversion([&](mlir::NoneType none) { + return mlir::LLVM::LLVMStructType::getLiteral( + none.getContext(), std::nullopt, /*isPacked=*/false); + }); + // FIXME: https://reviews.llvm.org/D82831 introduced an automatic + // materialization of conversion around function calls that is not working + // well with fir lowering to llvm (incorrect llvm.mlir.cast are inserted). + // Workaround until better analysis: register a handler that does not insert + // any conversions. + addSourceMaterialization( + [&](mlir::OpBuilder &builder, mlir::Type resultType, + mlir::ValueRange inputs, + mlir::Location loc) -> std::optional { + if (inputs.size() != 1) + return std::nullopt; + return inputs[0]; + }); + // Similar FIXME workaround here (needed for compare.fir/select-type.fir + // as well as rebox-global.fir tests). This is needed to cope with the + // the fact that codegen does not lower some operation results to the LLVM + // type produced by this LLVMTypeConverter. For instance, inside FIR + // globals, fir.box are lowered to llvm.struct, while the fir.box type + // conversion translates it into an llvm.ptr> because + // descriptors are manipulated in memory outside of global initializers + // where this is not possible. Hence, MLIR inserts + // builtin.unrealized_conversion_cast after the translation of operations + // producing fir.box in fir.global codegen. addSourceMaterialization and + // addTargetMaterialization allow ignoring these ops and removing them + // after codegen assuming the type discrepencies are intended (like for + // fir.box inside globals). + addTargetMaterialization( + [&](mlir::OpBuilder &builder, mlir::Type resultType, + mlir::ValueRange inputs, + mlir::Location loc) -> std::optional { + if (inputs.size() != 1) + return std::nullopt; + return inputs[0]; + }); +} + +// i32 is used here because LLVM wants i32 constants when indexing into struct +// types. Indexing into other aggregate types is more flexible. +mlir::Type LLVMTypeConverter::offsetType() { + return mlir::IntegerType::get(&getContext(), 32); +} + +// i64 can be used to index into aggregates like arrays +mlir::Type LLVMTypeConverter::indexType() { + return mlir::IntegerType::get(&getContext(), 64); +} + +// fir.type --> llvm<"%name = { ty... }"> +std::optional +LLVMTypeConverter::convertRecordType(fir::RecordType derived, + llvm::SmallVectorImpl &results, + llvm::ArrayRef callStack) { + auto name = derived.getName(); + auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name); + if (llvm::count(callStack, derived) > 1) { + results.push_back(st); + return mlir::success(); + } + llvm::SmallVector members; + for (auto mem : derived.getTypeList()) { + // Prevent fir.box from degenerating to a pointer to a descriptor in the + // context of a record type. + if (auto box = mem.second.dyn_cast()) + members.push_back(convertBoxTypeAsStruct(box)); + else + members.push_back(convertType(mem.second).cast()); + } + if (mlir::failed(st.setBody(members, /*isPacked=*/false))) + return mlir::failure(); + results.push_back(st); + return mlir::success(); +} + +// Is an extended descriptor needed given the element type of a fir.box type ? +// Extended descriptors are required for derived types. +bool LLVMTypeConverter::requiresExtendedDesc(mlir::Type boxElementType) { + auto eleTy = fir::unwrapSequenceType(boxElementType); + return eleTy.isa(); +} + +// This corresponds to the descriptor as defined in ISO_Fortran_binding.h and +// the addendum defined in descriptor.h. +mlir::Type LLVMTypeConverter::convertBoxType(BaseBoxType box, int rank) { + // (base_addr*, elem_len, version, rank, type, attribute, f18Addendum, [dim] + llvm::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()(&getContext())); + // version + dataDescFields.push_back( + getDescFieldTypeModel()(&getContext())); + // rank + dataDescFields.push_back( + getDescFieldTypeModel()(&getContext())); + // type + dataDescFields.push_back( + getDescFieldTypeModel()(&getContext())); + // attribute + dataDescFields.push_back( + getDescFieldTypeModel()(&getContext())); + // f18Addendum + dataDescFields.push_back( + getDescFieldTypeModel()(&getContext())); + // [dims] + if (rank == unknownRank()) { + if (auto seqTy = ele.dyn_cast()) + rank = seqTy.getDimension(); + else + rank = 0; + } + if (rank > 0) { + auto rowTy = getDescFieldTypeModel()(&getContext()); + dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank)); + } + // opt-type-ptr: i8* (see fir.tdesc) + if (requiresExtendedDesc(ele) || fir::isUnlimitedPolymorphicType(box)) { + dataDescFields.push_back( + getExtendedDescFieldTypeModel()(&getContext())); + auto rowTy = + getExtendedDescFieldTypeModel()(&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)); + } + } + // TODO: send the box type and the converted LLVM structure layout + // to tbaaBuilder for proper creation of TBAATypeDescriptorOp. + return mlir::LLVM::LLVMPointerType::get( + mlir::LLVM::LLVMStructType::getLiteral(&getContext(), dataDescFields, + /*isPacked=*/false)); +} + +/// Convert fir.box type to the corresponding llvm struct type instead of a +/// pointer to this struct type. +mlir::Type LLVMTypeConverter::convertBoxTypeAsStruct(BaseBoxType box) { + return convertBoxType(box) + .cast() + .getElementType(); +} + +// fir.boxproc --> llvm<"{ any*, i8* }"> +mlir::Type LLVMTypeConverter::convertBoxProcType(BoxProcType boxproc) { + auto funcTy = convertType(boxproc.getEleTy()); + auto i8PtrTy = mlir::LLVM::LLVMPointerType::get( + mlir::IntegerType::get(&getContext(), 8)); + llvm::SmallVector tuple = {funcTy, i8PtrTy}; + return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), tuple, + /*isPacked=*/false); +} + +unsigned LLVMTypeConverter::characterBitsize(fir::CharacterType charTy) { + return kindMapping.getCharacterBitsize(charTy.getFKind()); +} + +// fir.char --> llvm<"ix"> where ix is scaled by kind mapping +// fir.char --> llvm.array +mlir::Type LLVMTypeConverter::convertCharType(fir::CharacterType charTy) { + auto iTy = mlir::IntegerType::get(&getContext(), characterBitsize(charTy)); + if (charTy.getLen() == fir::CharacterType::unknownLen()) + return iTy; + return mlir::LLVM::LLVMArrayType::get(iTy, charTy.getLen()); +} + +// convert a front-end kind value to either a std or LLVM IR dialect type +// fir.real --> llvm.anyfloat where anyfloat is a kind mapping +mlir::Type LLVMTypeConverter::convertRealType(fir::KindTy kind) { + return fir::fromRealTypeID(&getContext(), kindMapping.getRealTypeID(kind), + kind); +} + +// fir.array --> llvm<"[...[c x any]]"> +mlir::Type LLVMTypeConverter::convertSequenceType(SequenceType seq) { + auto baseTy = convertType(seq.getEleTy()); + if (characterWithDynamicLen(seq.getEleTy())) + return mlir::LLVM::LLVMPointerType::get(baseTy); + auto shape = seq.getShape(); + auto constRows = seq.getConstantRows(); + if (constRows) { + decltype(constRows) i = constRows; + for (auto e : shape) { + baseTy = mlir::LLVM::LLVMArrayType::get(baseTy, e); + if (--i == 0) + break; + } + if (!seq.hasDynamicExtents()) + return baseTy; + } + return mlir::LLVM::LLVMPointerType::get(baseTy); +} + +// fir.tdesc --> llvm<"i8*"> +// TODO: For now use a void*, however pointer identity is not sufficient for +// the f18 object v. class distinction (F2003). +mlir::Type LLVMTypeConverter::convertTypeDescType(mlir::MLIRContext *ctx) { + return mlir::LLVM::LLVMPointerType::get( + mlir::IntegerType::get(&getContext(), 8)); +} + +// Relay TBAA tag attachment to TBAABuilder. +void LLVMTypeConverter::attachTBAATag(mlir::LLVM::AliasAnalysisOpInterface op, + mlir::Type baseFIRType, + mlir::Type accessFIRType, + mlir::LLVM::GEPOp gep) { + tbaaBuilder.attachTBAATag(op, baseFIRType, accessFIRType, gep); +} + +} // namespace fir diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.h b/flang/lib/Optimizer/CodeGen/TypeConverter.h index 36c02b8ff71c8..d2bcfd14162e7 100644 --- a/flang/lib/Optimizer/CodeGen/TypeConverter.h +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.h @@ -13,7 +13,6 @@ #ifndef FORTRAN_OPTIMIZER_CODEGEN_TYPECONVERTER_H #define FORTRAN_OPTIMIZER_CODEGEN_TYPECONVERTER_H -#include "DescriptorModel.h" #include "TBAABuilder.h" #include "Target.h" #include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done @@ -46,173 +45,24 @@ namespace fir { /// This converts FIR types to LLVM types (for now) class LLVMTypeConverter : public mlir::LLVMTypeConverter { public: - LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA) - : mlir::LLVMTypeConverter(module.getContext(), - [&] { - mlir::LowerToLLVMOptions options( - module.getContext()); - options.useOpaquePointers = false; - return options; - }()), - kindMapping(getKindMapping(module)), - specifics(CodeGenSpecifics::get(module.getContext(), - getTargetTriple(module), - getKindMapping(module))), - tbaaBuilder(module, applyTBAA) { - 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([&](BoxCharType boxchar) { - LLVM_DEBUG(llvm::dbgs() << "type convert: " << boxchar << '\n'); - return convertType(specifics->boxcharMemoryType(boxchar.getEleTy())); - }); - addConversion([&](BoxProcType boxproc) { - // TODO: Support for this type will be added later when the Fortran 2003 - // procedure pointer feature is implemented. - return std::nullopt; - }); - addConversion( - [&](fir::ClassType classTy) { return convertBoxType(classTy); }); - addConversion( - [&](fir::CharacterType charTy) { return convertCharType(charTy); }); - addConversion( - [&](fir::ComplexType cmplx) { return convertComplexType(cmplx); }); - addConversion([&](fir::FieldType field) { - // Convert to i32 because of LLVM GEP indexing restriction. - return mlir::IntegerType::get(field.getContext(), 32); - }); - addConversion([&](HeapType heap) { return convertPointerLike(heap); }); - addConversion([&](fir::IntegerType intTy) { - return mlir::IntegerType::get( - &getContext(), kindMapping.getIntegerBitsize(intTy.getFKind())); - }); - addConversion([&](fir::LenType field) { - // Get size of len paramter from the descriptor. - return getModel()( - &getContext()); - }); - addConversion([&](fir::LogicalType boolTy) { - return mlir::IntegerType::get( - &getContext(), kindMapping.getLogicalBitsize(boolTy.getFKind())); - }); - addConversion([&](fir::LLVMPointerType pointer) { - return convertPointerLike(pointer); - }); - addConversion( - [&](fir::PointerType pointer) { return convertPointerLike(pointer); }); - addConversion([&](fir::RecordType derived, - llvm::SmallVectorImpl &results, - llvm::ArrayRef callStack) { - return convertRecordType(derived, results, callStack); - }); - addConversion( - [&](fir::RealType real) { return convertRealType(real.getFKind()); }); - addConversion( - [&](fir::ReferenceType ref) { return convertPointerLike(ref); }); - addConversion([&](fir::SequenceType sequence) { - return convertSequenceType(sequence); - }); - addConversion([&](fir::TypeDescType tdesc) { - return convertTypeDescType(tdesc.getContext()); - }); - addConversion([&](fir::VectorType vecTy) { - return mlir::VectorType::get(llvm::ArrayRef(vecTy.getLen()), - convertType(vecTy.getEleTy())); - }); - addConversion([&](mlir::TupleType tuple) { - LLVM_DEBUG(llvm::dbgs() << "type convert: " << tuple << '\n'); - llvm::SmallVector members; - for (auto mem : tuple.getTypes()) { - // Prevent fir.box from degenerating to a pointer to a descriptor in the - // context of a tuple type. - if (auto box = mem.dyn_cast()) - members.push_back(convertBoxTypeAsStruct(box)); - else - members.push_back(convertType(mem).cast()); - } - return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), members, - /*isPacked=*/false); - }); - addConversion([&](mlir::NoneType none) { - return mlir::LLVM::LLVMStructType::getLiteral( - none.getContext(), std::nullopt, /*isPacked=*/false); - }); - // FIXME: https://reviews.llvm.org/D82831 introduced an automatic - // materialization of conversion around function calls that is not working - // well with fir lowering to llvm (incorrect llvm.mlir.cast are inserted). - // Workaround until better analysis: register a handler that does not insert - // any conversions. - addSourceMaterialization( - [&](mlir::OpBuilder &builder, mlir::Type resultType, - mlir::ValueRange inputs, - mlir::Location loc) -> std::optional { - if (inputs.size() != 1) - return std::nullopt; - return inputs[0]; - }); - // Similar FIXME workaround here (needed for compare.fir/select-type.fir - // as well as rebox-global.fir tests). This is needed to cope with the - // the fact that codegen does not lower some operation results to the LLVM - // type produced by this LLVMTypeConverter. For instance, inside FIR - // globals, fir.box are lowered to llvm.struct, while the fir.box type - // conversion translates it into an llvm.ptr> because - // descriptors are manipulated in memory outside of global initializers - // where this is not possible. Hence, MLIR inserts - // builtin.unrealized_conversion_cast after the translation of operations - // producing fir.box in fir.global codegen. addSourceMaterialization and - // addTargetMaterialization allow ignoring these ops and removing them - // after codegen assuming the type discrepencies are intended (like for - // fir.box inside globals). - addTargetMaterialization( - [&](mlir::OpBuilder &builder, mlir::Type resultType, - mlir::ValueRange inputs, - mlir::Location loc) -> std::optional { - if (inputs.size() != 1) - return std::nullopt; - return inputs[0]; - }); - } + LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA); // i32 is used here because LLVM wants i32 constants when indexing into struct // types. Indexing into other aggregate types is more flexible. - mlir::Type offsetType() { return mlir::IntegerType::get(&getContext(), 32); } + mlir::Type offsetType(); // i64 can be used to index into aggregates like arrays - mlir::Type indexType() { return mlir::IntegerType::get(&getContext(), 64); } + mlir::Type indexType(); // fir.type --> llvm<"%name = { ty... }"> std::optional convertRecordType(fir::RecordType derived, llvm::SmallVectorImpl &results, - llvm::ArrayRef callStack) { - auto name = derived.getName(); - auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name); - if (llvm::count(callStack, derived) > 1) { - results.push_back(st); - return mlir::success(); - } - llvm::SmallVector members; - for (auto mem : derived.getTypeList()) { - // Prevent fir.box from degenerating to a pointer to a descriptor in the - // context of a record type. - if (auto box = mem.second.dyn_cast()) - members.push_back(convertBoxTypeAsStruct(box)); - else - members.push_back(convertType(mem.second).cast()); - } - if (mlir::failed(st.setBody(members, /*isPacked=*/false))) - return mlir::failure(); - results.push_back(st); - return mlir::success(); - } + llvm::ArrayRef callStack); // 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(); - } + bool requiresExtendedDesc(mlir::Type boxElementType); // 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. @@ -220,104 +70,20 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter { // This corresponds to the descriptor as defined in ISO_Fortran_binding.h and // the addendum defined in descriptor.h. - mlir::Type convertBoxType(BaseBoxType box, int rank = unknownRank()) { - // (base_addr*, elem_len, version, rank, type, attribute, f18Addendum, [dim] - llvm::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()(&getContext())); - // version - dataDescFields.push_back( - getDescFieldTypeModel()(&getContext())); - // rank - dataDescFields.push_back( - getDescFieldTypeModel()(&getContext())); - // type - dataDescFields.push_back( - getDescFieldTypeModel()(&getContext())); - // attribute - dataDescFields.push_back( - getDescFieldTypeModel()(&getContext())); - // f18Addendum - dataDescFields.push_back( - getDescFieldTypeModel()(&getContext())); - // [dims] - if (rank == unknownRank()) { - if (auto seqTy = ele.dyn_cast()) - rank = seqTy.getDimension(); - else - rank = 0; - } - if (rank > 0) { - auto rowTy = getDescFieldTypeModel()(&getContext()); - dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank)); - } - // opt-type-ptr: i8* (see fir.tdesc) - if (requiresExtendedDesc(ele) || fir::isUnlimitedPolymorphicType(box)) { - dataDescFields.push_back( - getExtendedDescFieldTypeModel()(&getContext())); - auto rowTy = - getExtendedDescFieldTypeModel()(&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)); - } - } - // TODO: send the box type and the converted LLVM structure layout - // to tbaaBuilder for proper creation of TBAATypeDescriptorOp. - return mlir::LLVM::LLVMPointerType::get( - mlir::LLVM::LLVMStructType::getLiteral(&getContext(), dataDescFields, - /*isPacked=*/false)); - } + mlir::Type convertBoxType(BaseBoxType box, int rank = unknownRank()); /// Convert fir.box type to the corresponding llvm struct type instead of a /// pointer to this struct type. - mlir::Type convertBoxTypeAsStruct(BaseBoxType box) { - return convertBoxType(box) - .cast() - .getElementType(); - } + mlir::Type convertBoxTypeAsStruct(BaseBoxType box); // fir.boxproc --> llvm<"{ any*, i8* }"> - mlir::Type convertBoxProcType(BoxProcType boxproc) { - auto funcTy = convertType(boxproc.getEleTy()); - auto i8PtrTy = mlir::LLVM::LLVMPointerType::get( - mlir::IntegerType::get(&getContext(), 8)); - llvm::SmallVector tuple = {funcTy, i8PtrTy}; - return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), tuple, - /*isPacked=*/false); - } + mlir::Type convertBoxProcType(BoxProcType boxproc); - unsigned characterBitsize(fir::CharacterType charTy) { - return kindMapping.getCharacterBitsize(charTy.getFKind()); - } + unsigned characterBitsize(fir::CharacterType charTy); // fir.char --> llvm<"ix"> where ix is scaled by kind mapping // fir.char --> llvm.array - mlir::Type convertCharType(fir::CharacterType charTy) { - auto iTy = mlir::IntegerType::get(&getContext(), characterBitsize(charTy)); - if (charTy.getLen() == fir::CharacterType::unknownLen()) - return iTy; - return mlir::LLVM::LLVMArrayType::get(iTy, charTy.getLen()); - } + mlir::Type convertCharType(fir::CharacterType charTy); // Use the target specifics to figure out how to map complex to LLVM IR. The // use of complex values in function signatures is handled before conversion @@ -360,47 +126,22 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter { // convert a front-end kind value to either a std or LLVM IR dialect type // fir.real --> llvm.anyfloat where anyfloat is a kind mapping - mlir::Type convertRealType(fir::KindTy kind) { - return fir::fromRealTypeID(&getContext(), kindMapping.getRealTypeID(kind), - kind); - } + mlir::Type convertRealType(fir::KindTy kind); // fir.array --> llvm<"[...[c x any]]"> - mlir::Type convertSequenceType(SequenceType seq) { - auto baseTy = convertType(seq.getEleTy()); - if (characterWithDynamicLen(seq.getEleTy())) - return mlir::LLVM::LLVMPointerType::get(baseTy); - auto shape = seq.getShape(); - auto constRows = seq.getConstantRows(); - if (constRows) { - decltype(constRows) i = constRows; - for (auto e : shape) { - baseTy = mlir::LLVM::LLVMArrayType::get(baseTy, e); - if (--i == 0) - break; - } - if (!seq.hasDynamicExtents()) - return baseTy; - } - return mlir::LLVM::LLVMPointerType::get(baseTy); - } + mlir::Type convertSequenceType(SequenceType seq); // fir.tdesc --> llvm<"i8*"> // TODO: For now use a void*, however pointer identity is not sufficient for // the f18 object v. class distinction (F2003). - mlir::Type convertTypeDescType(mlir::MLIRContext *ctx) { - return mlir::LLVM::LLVMPointerType::get( - mlir::IntegerType::get(&getContext(), 8)); - } + mlir::Type convertTypeDescType(mlir::MLIRContext *ctx); KindMapping &getKindMap() { return kindMapping; } // Relay TBAA tag attachment to TBAABuilder. void attachTBAATag(mlir::LLVM::AliasAnalysisOpInterface op, mlir::Type baseFIRType, mlir::Type accessFIRType, - mlir::LLVM::GEPOp gep) { - tbaaBuilder.attachTBAATag(op, baseFIRType, accessFIRType, gep); - } + mlir::LLVM::GEPOp gep); private: KindMapping kindMapping;