[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / flang / lib / Optimizer / CodeGen / TypeConverter.cpp
blobc23203efcd3df28701fc0ac1cbf582983d73ba03
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/
11 //===----------------------------------------------------------------------===//
13 #define DEBUG_TYPE "flang-type-conversion"
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"
29 namespace fir {
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");
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);
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)));
110 return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), members,
111 /*isPacked=*/false);
113 addConversion([&](mlir::NoneType none) {
114 return mlir::LLVM::LLVMStructType::getLiteral(
115 none.getContext(), std::nullopt, /*isPacked=*/false);
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);
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);
130 // i64 can be used to index into aggregates like arrays
131 mlir::Type LLVMTypeConverter::indexType() const {
132 return mlir::IntegerType::get(&getContext(), 64);
135 // fir.type<name(p : TY'...){f : TY...}> --> llvm<"%name = { ty... }">
136 std::optional<llvm::LogicalResult> LLVMTypeConverter::convertRecordType(
137 fir::RecordType derived, llvm::SmallVectorImpl<mlir::Type> &results) {
138 auto name = fir::NameUniquer::dropTypeConversionMarkers(derived.getName());
139 auto st = mlir::LLVM::LLVMStructType::getIdentified(&getContext(), name);
141 auto &callStack = getCurrentThreadRecursiveStack();
142 if (llvm::count(callStack, derived)) {
143 results.push_back(st);
144 return mlir::success();
146 callStack.push_back(derived);
147 auto popConversionCallStack =
148 llvm::make_scope_exit([&callStack]() { callStack.pop_back(); });
150 llvm::SmallVector<mlir::Type> members;
151 for (auto mem : derived.getTypeList()) {
152 // Prevent fir.box from degenerating to a pointer to a descriptor in the
153 // context of a record type.
154 if (auto box = mlir::dyn_cast<fir::BaseBoxType>(mem.second))
155 members.push_back(convertBoxTypeAsStruct(box));
156 else
157 members.push_back(mlir::cast<mlir::Type>(convertType(mem.second)));
159 if (mlir::failed(st.setBody(members, /*isPacked=*/false)))
160 return mlir::failure();
161 results.push_back(st);
162 return mlir::success();
165 // Is an extended descriptor needed given the element type of a fir.box type ?
166 // Extended descriptors are required for derived types.
167 bool LLVMTypeConverter::requiresExtendedDesc(mlir::Type boxElementType) const {
168 auto eleTy = fir::unwrapSequenceType(boxElementType);
169 return mlir::isa<fir::RecordType>(eleTy);
172 // This corresponds to the descriptor as defined in ISO_Fortran_binding.h and
173 // the addendum defined in descriptor.h.
174 mlir::Type LLVMTypeConverter::convertBoxTypeAsStruct(BaseBoxType box,
175 int rank) const {
176 // (base_addr*, elem_len, version, rank, type, attribute, extra, [dim]
177 llvm::SmallVector<mlir::Type> dataDescFields;
178 mlir::Type ele = box.getEleTy();
179 // remove fir.heap/fir.ref/fir.ptr
180 if (auto removeIndirection = fir::dyn_cast_ptrEleTy(ele))
181 ele = removeIndirection;
182 auto eleTy = convertType(ele);
183 // base_addr*
184 if (mlir::isa<SequenceType>(ele) &&
185 mlir::isa<mlir::LLVM::LLVMPointerType>(eleTy))
186 dataDescFields.push_back(eleTy);
187 else
188 dataDescFields.push_back(
189 mlir::LLVM::LLVMPointerType::get(eleTy.getContext()));
190 // elem_len
191 dataDescFields.push_back(
192 getDescFieldTypeModel<kElemLenPosInBox>()(&getContext()));
193 // version
194 dataDescFields.push_back(
195 getDescFieldTypeModel<kVersionPosInBox>()(&getContext()));
196 // rank
197 dataDescFields.push_back(
198 getDescFieldTypeModel<kRankPosInBox>()(&getContext()));
199 // type
200 dataDescFields.push_back(
201 getDescFieldTypeModel<kTypePosInBox>()(&getContext()));
202 // attribute
203 dataDescFields.push_back(
204 getDescFieldTypeModel<kAttributePosInBox>()(&getContext()));
205 // extra
206 dataDescFields.push_back(
207 getDescFieldTypeModel<kExtraPosInBox>()(&getContext()));
208 // [dims]
209 if (rank == unknownRank()) {
210 if (auto seqTy = mlir::dyn_cast<SequenceType>(ele))
211 if (seqTy.hasUnknownShape())
212 rank = Fortran::common::maxRank;
213 else
214 rank = seqTy.getDimension();
215 else
216 rank = 0;
218 if (rank > 0) {
219 auto rowTy = getDescFieldTypeModel<kDimsPosInBox>()(&getContext());
220 dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank));
222 // opt-type-ptr: i8* (see fir.tdesc)
223 if (requiresExtendedDesc(ele) || fir::isUnlimitedPolymorphicType(box)) {
224 dataDescFields.push_back(
225 getExtendedDescFieldTypeModel<kOptTypePtrPosInBox>()(&getContext()));
226 auto rowTy =
227 getExtendedDescFieldTypeModel<kOptRowTypePosInBox>()(&getContext());
228 dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, 1));
229 if (auto recTy =
230 mlir::dyn_cast<fir::RecordType>(fir::unwrapSequenceType(ele)))
231 if (recTy.getNumLenParams() > 0) {
232 // The descriptor design needs to be clarified regarding the number of
233 // length parameters in the addendum. Since it can change for
234 // polymorphic allocatables, it seems all length parameters cannot
235 // always possibly be placed in the addendum.
236 TODO_NOLOC("extended descriptor derived with length parameters");
237 unsigned numLenParams = recTy.getNumLenParams();
238 dataDescFields.push_back(
239 mlir::LLVM::LLVMArrayType::get(rowTy, numLenParams));
242 return mlir::LLVM::LLVMStructType::getLiteral(&getContext(), dataDescFields,
243 /*isPacked=*/false);
246 /// Convert fir.box type to the corresponding llvm struct type instead of a
247 /// pointer to this struct type.
248 mlir::Type LLVMTypeConverter::convertBoxType(BaseBoxType box, int rank) const {
249 // TODO: send the box type and the converted LLVM structure layout
250 // to tbaaBuilder for proper creation of TBAATypeDescriptorOp.
251 return mlir::LLVM::LLVMPointerType::get(box.getContext());
254 // fir.boxproc<any> --> llvm<"{ any*, i8* }">
255 mlir::Type LLVMTypeConverter::convertBoxProcType(BoxProcType boxproc) const {
256 auto funcTy = convertType(boxproc.getEleTy());
257 auto voidPtrTy = mlir::LLVM::LLVMPointerType::get(boxproc.getContext());
258 llvm::SmallVector<mlir::Type, 2> tuple = {funcTy, voidPtrTy};
259 return mlir::LLVM::LLVMStructType::getLiteral(boxproc.getContext(), tuple,
260 /*isPacked=*/false);
263 unsigned LLVMTypeConverter::characterBitsize(fir::CharacterType charTy) const {
264 return kindMapping.getCharacterBitsize(charTy.getFKind());
267 // fir.char<k,?> --> llvm<"ix"> where ix is scaled by kind mapping
268 // fir.char<k,n> --> llvm.array<n x "ix">
269 mlir::Type LLVMTypeConverter::convertCharType(fir::CharacterType charTy) const {
270 auto iTy = mlir::IntegerType::get(&getContext(), characterBitsize(charTy));
271 if (charTy.getLen() == fir::CharacterType::unknownLen())
272 return iTy;
273 return mlir::LLVM::LLVMArrayType::get(iTy, charTy.getLen());
276 // fir.array<c ... :any> --> llvm<"[...[c x any]]">
277 mlir::Type LLVMTypeConverter::convertSequenceType(SequenceType seq) const {
278 auto baseTy = convertType(seq.getEleTy());
279 if (characterWithDynamicLen(seq.getEleTy()))
280 return baseTy;
281 auto shape = seq.getShape();
282 auto constRows = seq.getConstantRows();
283 if (constRows) {
284 decltype(constRows) i = constRows;
285 for (auto e : shape) {
286 baseTy = mlir::LLVM::LLVMArrayType::get(baseTy, e);
287 if (--i == 0)
288 break;
290 if (!seq.hasDynamicExtents())
291 return baseTy;
293 return baseTy;
296 // fir.tdesc<any> --> llvm<"i8*">
297 // TODO: For now use a void*, however pointer identity is not sufficient for
298 // the f18 object v. class distinction (F2003).
299 mlir::Type
300 LLVMTypeConverter::convertTypeDescType(mlir::MLIRContext *ctx) const {
301 return mlir::LLVM::LLVMPointerType::get(ctx);
304 // Relay TBAA tag attachment to TBAABuilder.
305 void LLVMTypeConverter::attachTBAATag(mlir::LLVM::AliasAnalysisOpInterface op,
306 mlir::Type baseFIRType,
307 mlir::Type accessFIRType,
308 mlir::LLVM::GEPOp gep) const {
309 tbaaBuilder->attachTBAATag(op, baseFIRType, accessFIRType, gep);
312 } // namespace fir