xref: /llvm-project/flang/lib/Optimizer/CodeGen/TypeConverter.cpp (revision 79e788d02eefdacb08af365389b9055518f3fad6)
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