1 //===-- TypeConverter.cpp -- type conversion --------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 13 #define DEBUG_TYPE "flang-type-conversion" 14 15 #include "flang/Optimizer/CodeGen/TypeConverter.h" 16 #include "flang/Common/Fortran.h" 17 #include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done 18 #include "flang/Optimizer/CodeGen/DescriptorModel.h" 19 #include "flang/Optimizer/CodeGen/TBAABuilder.h" 20 #include "flang/Optimizer/CodeGen/Target.h" 21 #include "flang/Optimizer/Dialect/FIRType.h" 22 #include "flang/Optimizer/Dialect/Support/FIRContext.h" 23 #include "flang/Optimizer/Dialect/Support/KindMapping.h" 24 #include "flang/Optimizer/Support/InternalNames.h" 25 #include "mlir/Conversion/LLVMCommon/TypeConverter.h" 26 #include "llvm/ADT/ScopeExit.h" 27 #include "llvm/Support/Debug.h" 28 29 namespace fir { 30 31 LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA, 32 bool forceUnifiedTBAATree, 33 const mlir::DataLayout &dl) 34 : mlir::LLVMTypeConverter(module.getContext()), 35 kindMapping(getKindMapping(module)), 36 specifics(CodeGenSpecifics::get( 37 module.getContext(), getTargetTriple(module), getKindMapping(module), 38 getTargetCPU(module), getTargetFeatures(module), dl, 39 getTuneCPU(module))), 40 tbaaBuilder(std::make_unique<TBAABuilder>(module->getContext(), applyTBAA, 41 forceUnifiedTBAATree)), 42 dataLayout{&dl} { 43 LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n"); 44 45 // Each conversion should return a value of type mlir::Type. 46 addConversion([&](BoxType box) { return convertBoxType(box); }); 47 addConversion([&](BoxCharType boxchar) { 48 LLVM_DEBUG(llvm::dbgs() << "type convert: " << boxchar << '\n'); 49 return convertType(specifics->boxcharMemoryType(boxchar.getEleTy())); 50 }); 51 addConversion([&](BoxProcType boxproc) { 52 // TODO: Support for this type will be added later when the Fortran 2003 53 // procedure pointer feature is implemented. 54 return std::nullopt; 55 }); 56 addConversion( 57 [&](fir::ClassType classTy) { return convertBoxType(classTy); }); 58 addConversion( 59 [&](fir::CharacterType charTy) { return convertCharType(charTy); }); 60 addConversion([&](fir::FieldType field) { 61 // Convert to i32 because of LLVM GEP indexing restriction. 62 return mlir::IntegerType::get(field.getContext(), 32); 63 }); 64 addConversion([&](HeapType heap) { return convertPointerLike(heap); }); 65 addConversion([&](fir::IntegerType intTy) { 66 return mlir::IntegerType::get( 67 &getContext(), kindMapping.getIntegerBitsize(intTy.getFKind())); 68 }); 69 addConversion([&](fir::LenType field) { 70 // Get size of len paramter from the descriptor. 71 return getModel<Fortran::runtime::typeInfo::TypeParameterValue>()( 72 &getContext()); 73 }); 74 addConversion([&](fir::LogicalType boolTy) { 75 return mlir::IntegerType::get( 76 &getContext(), kindMapping.getLogicalBitsize(boolTy.getFKind())); 77 }); 78 addConversion([&](fir::LLVMPointerType pointer) { 79 return convertPointerLike(pointer); 80 }); 81 addConversion( 82 [&](fir::PointerType pointer) { return convertPointerLike(pointer); }); 83 addConversion( 84 [&](fir::RecordType derived, llvm::SmallVectorImpl<mlir::Type> &results) { 85 return convertRecordType(derived, results, derived.isPacked()); 86 }); 87 addConversion( 88 [&](fir::ReferenceType ref) { return convertPointerLike(ref); }); 89 addConversion([&](fir::SequenceType sequence) { 90 return convertSequenceType(sequence); 91 }); 92 addConversion([&](fir::TypeDescType tdesc) { 93 return convertTypeDescType(tdesc.getContext()); 94 }); 95 addConversion([&](fir::VectorType vecTy) { 96 return mlir::VectorType::get(llvm::ArrayRef<int64_t>(vecTy.getLen()), 97 convertType(vecTy.getEleTy())); 98 }); 99 addConversion([&](mlir::TupleType tuple) { 100 LLVM_DEBUG(llvm::dbgs() << "type convert: " << tuple << '\n'); 101 llvm::SmallVector<mlir::Type> members; 102 for (auto mem : tuple.getTypes()) { 103 // Prevent fir.box from degenerating to a pointer to a descriptor in the 104 // context of a tuple type. 105 if (auto box = mlir::dyn_cast<fir::BaseBoxType>(mem)) 106 members.push_back(convertBoxTypeAsStruct(box)); 107 else 108 members.push_back(mlir::cast<mlir::Type>(convertType(mem))); 109 } 110 return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), members, 111 /*isPacked=*/false); 112 }); 113 addConversion([&](mlir::NoneType none) { 114 return mlir::LLVM::LLVMStructType::getLiteral( 115 none.getContext(), std::nullopt, /*isPacked=*/false); 116 }); 117 addConversion([&](fir::DummyScopeType dscope) { 118 // DummyScopeType values must not have any uses after PreCGRewrite. 119 // Convert it here to i1 just in case it survives. 120 return mlir::IntegerType::get(&getContext(), 1); 121 }); 122 } 123 124 // i32 is used here because LLVM wants i32 constants when indexing into struct 125 // types. Indexing into other aggregate types is more flexible. 126 mlir::Type LLVMTypeConverter::offsetType() const { 127 return mlir::IntegerType::get(&getContext(), 32); 128 } 129 130 // i64 can be used to index into aggregates like arrays 131 mlir::Type LLVMTypeConverter::indexType() const { 132 return mlir::IntegerType::get(&getContext(), 64); 133 } 134 135 // fir.type<name(p : TY'...){f : TY...}> --> llvm<"%name = { ty... }"> 136 std::optional<llvm::LogicalResult> 137 LLVMTypeConverter::convertRecordType(fir::RecordType derived, 138 llvm::SmallVectorImpl<mlir::Type> &results, 139 bool isPacked) { 140 auto name = fir::NameUniquer::dropTypeConversionMarkers(derived.getName()); 141 auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name); 142 143 auto &callStack = getCurrentThreadRecursiveStack(); 144 if (llvm::count(callStack, derived)) { 145 results.push_back(st); 146 return mlir::success(); 147 } 148 callStack.push_back(derived); 149 auto popConversionCallStack = 150 llvm::make_scope_exit([&callStack]() { callStack.pop_back(); }); 151 152 llvm::SmallVector<mlir::Type> members; 153 for (auto mem : derived.getTypeList()) { 154 // Prevent fir.box from degenerating to a pointer to a descriptor in the 155 // context of a record type. 156 if (auto box = mlir::dyn_cast<fir::BaseBoxType>(mem.second)) 157 members.push_back(convertBoxTypeAsStruct(box)); 158 else 159 members.push_back(mlir::cast<mlir::Type>(convertType(mem.second))); 160 } 161 if (mlir::failed(st.setBody(members, isPacked))) 162 return mlir::failure(); 163 results.push_back(st); 164 return mlir::success(); 165 } 166 167 // Is an extended descriptor needed given the element type of a fir.box type ? 168 // Extended descriptors are required for derived types. 169 bool LLVMTypeConverter::requiresExtendedDesc(mlir::Type boxElementType) const { 170 auto eleTy = fir::unwrapSequenceType(boxElementType); 171 return mlir::isa<fir::RecordType>(eleTy); 172 } 173 174 // This corresponds to the descriptor as defined in ISO_Fortran_binding.h and 175 // the addendum defined in descriptor.h. 176 mlir::Type LLVMTypeConverter::convertBoxTypeAsStruct(BaseBoxType box, 177 int rank) const { 178 // (base_addr*, elem_len, version, rank, type, attribute, extra, [dim] 179 llvm::SmallVector<mlir::Type> dataDescFields; 180 mlir::Type ele = box.getEleTy(); 181 // remove fir.heap/fir.ref/fir.ptr 182 if (auto removeIndirection = fir::dyn_cast_ptrEleTy(ele)) 183 ele = removeIndirection; 184 auto eleTy = convertType(ele); 185 // base_addr* 186 if (mlir::isa<SequenceType>(ele) && 187 mlir::isa<mlir::LLVM::LLVMPointerType>(eleTy)) 188 dataDescFields.push_back(eleTy); 189 else 190 dataDescFields.push_back( 191 mlir::LLVM::LLVMPointerType::get(eleTy.getContext())); 192 // elem_len 193 dataDescFields.push_back( 194 getDescFieldTypeModel<kElemLenPosInBox>()(&getContext())); 195 // version 196 dataDescFields.push_back( 197 getDescFieldTypeModel<kVersionPosInBox>()(&getContext())); 198 // rank 199 dataDescFields.push_back( 200 getDescFieldTypeModel<kRankPosInBox>()(&getContext())); 201 // type 202 dataDescFields.push_back( 203 getDescFieldTypeModel<kTypePosInBox>()(&getContext())); 204 // attribute 205 dataDescFields.push_back( 206 getDescFieldTypeModel<kAttributePosInBox>()(&getContext())); 207 // extra 208 dataDescFields.push_back( 209 getDescFieldTypeModel<kExtraPosInBox>()(&getContext())); 210 // [dims] 211 if (rank == unknownRank()) { 212 if (auto seqTy = mlir::dyn_cast<SequenceType>(ele)) 213 if (seqTy.hasUnknownShape()) 214 rank = Fortran::common::maxRank; 215 else 216 rank = seqTy.getDimension(); 217 else 218 rank = 0; 219 } 220 if (rank > 0) { 221 auto rowTy = getDescFieldTypeModel<kDimsPosInBox>()(&getContext()); 222 dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank)); 223 } 224 // opt-type-ptr: i8* (see fir.tdesc) 225 if (requiresExtendedDesc(ele) || fir::isUnlimitedPolymorphicType(box)) { 226 dataDescFields.push_back( 227 getExtendedDescFieldTypeModel<kOptTypePtrPosInBox>()(&getContext())); 228 auto rowTy = 229 getExtendedDescFieldTypeModel<kOptRowTypePosInBox>()(&getContext()); 230 dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, 1)); 231 if (auto recTy = 232 mlir::dyn_cast<fir::RecordType>(fir::unwrapSequenceType(ele))) 233 if (recTy.getNumLenParams() > 0) { 234 // The descriptor design needs to be clarified regarding the number of 235 // length parameters in the addendum. Since it can change for 236 // polymorphic allocatables, it seems all length parameters cannot 237 // always possibly be placed in the addendum. 238 TODO_NOLOC("extended descriptor derived with length parameters"); 239 unsigned numLenParams = recTy.getNumLenParams(); 240 dataDescFields.push_back( 241 mlir::LLVM::LLVMArrayType::get(rowTy, numLenParams)); 242 } 243 } 244 return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), dataDescFields, 245 /*isPacked=*/false); 246 } 247 248 /// Convert fir.box type to the corresponding llvm struct type instead of a 249 /// pointer to this struct type. 250 mlir::Type LLVMTypeConverter::convertBoxType(BaseBoxType box, int rank) const { 251 // TODO: send the box type and the converted LLVM structure layout 252 // to tbaaBuilder for proper creation of TBAATypeDescriptorOp. 253 return mlir::LLVM::LLVMPointerType::get(box.getContext()); 254 } 255 256 // fir.boxproc<any> --> llvm<"{ any*, i8* }"> 257 mlir::Type LLVMTypeConverter::convertBoxProcType(BoxProcType boxproc) const { 258 auto funcTy = convertType(boxproc.getEleTy()); 259 auto voidPtrTy = mlir::LLVM::LLVMPointerType::get(boxproc.getContext()); 260 llvm::SmallVector<mlir::Type, 2> tuple = {funcTy, voidPtrTy}; 261 return mlir::LLVM::LLVMStructType::getLiteral(boxproc.getContext(), tuple, 262 /*isPacked=*/false); 263 } 264 265 unsigned LLVMTypeConverter::characterBitsize(fir::CharacterType charTy) const { 266 return kindMapping.getCharacterBitsize(charTy.getFKind()); 267 } 268 269 // fir.char<k,?> --> llvm<"ix"> where ix is scaled by kind mapping 270 // fir.char<k,n> --> llvm.array<n x "ix"> 271 mlir::Type LLVMTypeConverter::convertCharType(fir::CharacterType charTy) const { 272 auto iTy = mlir::IntegerType::get(&getContext(), characterBitsize(charTy)); 273 if (charTy.getLen() == fir::CharacterType::unknownLen()) 274 return iTy; 275 return mlir::LLVM::LLVMArrayType::get(iTy, charTy.getLen()); 276 } 277 278 // fir.array<c ... :any> --> llvm<"[...[c x any]]"> 279 mlir::Type LLVMTypeConverter::convertSequenceType(SequenceType seq) const { 280 auto baseTy = convertType(seq.getEleTy()); 281 if (characterWithDynamicLen(seq.getEleTy())) 282 return baseTy; 283 auto shape = seq.getShape(); 284 auto constRows = seq.getConstantRows(); 285 if (constRows) { 286 decltype(constRows) i = constRows; 287 for (auto e : shape) { 288 baseTy = mlir::LLVM::LLVMArrayType::get(baseTy, e); 289 if (--i == 0) 290 break; 291 } 292 if (!seq.hasDynamicExtents()) 293 return baseTy; 294 } 295 return baseTy; 296 } 297 298 // fir.tdesc<any> --> llvm<"i8*"> 299 // TODO: For now use a void*, however pointer identity is not sufficient for 300 // the f18 object v. class distinction (F2003). 301 mlir::Type 302 LLVMTypeConverter::convertTypeDescType(mlir::MLIRContext *ctx) const { 303 return mlir::LLVM::LLVMPointerType::get(ctx); 304 } 305 306 // Relay TBAA tag attachment to TBAABuilder. 307 void LLVMTypeConverter::attachTBAATag(mlir::LLVM::AliasAnalysisOpInterface op, 308 mlir::Type baseFIRType, 309 mlir::Type accessFIRType, 310 mlir::LLVM::GEPOp gep) const { 311 tbaaBuilder->attachTBAATag(op, baseFIRType, accessFIRType, gep); 312 } 313 314 } // namespace fir 315