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

source code of flang/lib/Optimizer/CodeGen/TypeConverter.cpp