1 //===-- ConvertType.cpp ---------------------------------------------------===//
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 #include "flang/Lower/ConvertType.h"
10 #include "flang/Lower/AbstractConverter.h"
11 #include "flang/Lower/CallInterface.h"
12 #include "flang/Lower/ConvertVariable.h"
13 #include "flang/Lower/Mangler.h"
14 #include "flang/Lower/PFTBuilder.h"
15 #include "flang/Lower/Support/Utils.h"
16 #include "flang/Optimizer/Builder/Todo.h"
17 #include "flang/Optimizer/Dialect/FIRType.h"
18 #include "flang/Semantics/tools.h"
19 #include "flang/Semantics/type.h"
20 #include "mlir/IR/Builders.h"
21 #include "mlir/IR/BuiltinTypes.h"
22 #include "llvm/Support/Debug.h"
23
24 #define DEBUG_TYPE "flang-lower-type"
25
26 //===--------------------------------------------------------------------===//
27 // Intrinsic type translation helpers
28 //===--------------------------------------------------------------------===//
29
genRealType(mlir::MLIRContext * context,int kind)30 static mlir::Type genRealType(mlir::MLIRContext *context, int kind) {
31 if (Fortran::evaluate::IsValidKindOfIntrinsicType(
32 Fortran::common::TypeCategory::Real, kind)) {
33 switch (kind) {
34 case 2:
35 return mlir::FloatType::getF16(context);
36 case 3:
37 return mlir::FloatType::getBF16(context);
38 case 4:
39 return mlir::FloatType::getF32(context);
40 case 8:
41 return mlir::FloatType::getF64(context);
42 case 10:
43 return mlir::FloatType::getF80(context);
44 case 16:
45 return mlir::FloatType::getF128(context);
46 }
47 }
48 llvm_unreachable("REAL type translation not implemented");
49 }
50
51 template <int KIND>
getIntegerBits()52 int getIntegerBits() {
53 return Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer,
54 KIND>::Scalar::bits;
55 }
genIntegerType(mlir::MLIRContext * context,int kind)56 static mlir::Type genIntegerType(mlir::MLIRContext *context, int kind) {
57 if (Fortran::evaluate::IsValidKindOfIntrinsicType(
58 Fortran::common::TypeCategory::Integer, kind)) {
59 switch (kind) {
60 case 1:
61 return mlir::IntegerType::get(context, getIntegerBits<1>());
62 case 2:
63 return mlir::IntegerType::get(context, getIntegerBits<2>());
64 case 4:
65 return mlir::IntegerType::get(context, getIntegerBits<4>());
66 case 8:
67 return mlir::IntegerType::get(context, getIntegerBits<8>());
68 case 16:
69 return mlir::IntegerType::get(context, getIntegerBits<16>());
70 }
71 }
72 llvm_unreachable("INTEGER kind not translated");
73 }
74
genLogicalType(mlir::MLIRContext * context,int KIND)75 static mlir::Type genLogicalType(mlir::MLIRContext *context, int KIND) {
76 if (Fortran::evaluate::IsValidKindOfIntrinsicType(
77 Fortran::common::TypeCategory::Logical, KIND))
78 return fir::LogicalType::get(context, KIND);
79 return {};
80 }
81
genCharacterType(mlir::MLIRContext * context,int KIND,Fortran::lower::LenParameterTy len=fir::CharacterType::unknownLen ())82 static mlir::Type genCharacterType(
83 mlir::MLIRContext *context, int KIND,
84 Fortran::lower::LenParameterTy len = fir::CharacterType::unknownLen()) {
85 if (Fortran::evaluate::IsValidKindOfIntrinsicType(
86 Fortran::common::TypeCategory::Character, KIND))
87 return fir::CharacterType::get(context, KIND, len);
88 return {};
89 }
90
genComplexType(mlir::MLIRContext * context,int KIND)91 static mlir::Type genComplexType(mlir::MLIRContext *context, int KIND) {
92 if (Fortran::evaluate::IsValidKindOfIntrinsicType(
93 Fortran::common::TypeCategory::Complex, KIND))
94 return fir::ComplexType::get(context, KIND);
95 return {};
96 }
97
98 static mlir::Type
genFIRType(mlir::MLIRContext * context,Fortran::common::TypeCategory tc,int kind,llvm::ArrayRef<Fortran::lower::LenParameterTy> lenParameters)99 genFIRType(mlir::MLIRContext *context, Fortran::common::TypeCategory tc,
100 int kind,
101 llvm::ArrayRef<Fortran::lower::LenParameterTy> lenParameters) {
102 switch (tc) {
103 case Fortran::common::TypeCategory::Real:
104 return genRealType(context, kind);
105 case Fortran::common::TypeCategory::Integer:
106 return genIntegerType(context, kind);
107 case Fortran::common::TypeCategory::Complex:
108 return genComplexType(context, kind);
109 case Fortran::common::TypeCategory::Logical:
110 return genLogicalType(context, kind);
111 case Fortran::common::TypeCategory::Character:
112 if (!lenParameters.empty())
113 return genCharacterType(context, kind, lenParameters[0]);
114 return genCharacterType(context, kind);
115 default:
116 break;
117 }
118 llvm_unreachable("unhandled type category");
119 }
120
121 //===--------------------------------------------------------------------===//
122 // Symbol and expression type translation
123 //===--------------------------------------------------------------------===//
124
125 /// TypeBuilder translates expression and symbol type taking into account
126 /// their shape and length parameters. For symbols, attributes such as
127 /// ALLOCATABLE or POINTER are reflected in the fir type.
128 /// It uses evaluate::DynamicType and evaluate::Shape when possible to
129 /// avoid re-implementing type/shape analysis here.
130 /// Do not use the FirOpBuilder from the AbstractConverter to get fir/mlir types
131 /// since it is not guaranteed to exist yet when we lower types.
132 namespace {
133 struct TypeBuilder {
134
TypeBuilder__anon8bca3fa80111::TypeBuilder135 TypeBuilder(Fortran::lower::AbstractConverter &converter)
136 : converter{converter}, context{&converter.getMLIRContext()} {}
137
genExprType__anon8bca3fa80111::TypeBuilder138 mlir::Type genExprType(const Fortran::lower::SomeExpr &expr) {
139 std::optional<Fortran::evaluate::DynamicType> dynamicType = expr.GetType();
140 if (!dynamicType)
141 return genTypelessExprType(expr);
142 Fortran::common::TypeCategory category = dynamicType->category();
143
144 mlir::Type baseType;
145 if (category == Fortran::common::TypeCategory::Derived) {
146 baseType = genDerivedType(dynamicType->GetDerivedTypeSpec());
147 } else {
148 // LOGICAL, INTEGER, REAL, COMPLEX, CHARACTER
149 llvm::SmallVector<Fortran::lower::LenParameterTy> params;
150 translateLenParameters(params, category, expr);
151 baseType = genFIRType(context, category, dynamicType->kind(), params);
152 }
153 std::optional<Fortran::evaluate::Shape> shapeExpr =
154 Fortran::evaluate::GetShape(converter.getFoldingContext(), expr);
155 fir::SequenceType::Shape shape;
156 if (shapeExpr) {
157 translateShape(shape, std::move(*shapeExpr));
158 } else {
159 // Shape static analysis cannot return something useful for the shape.
160 // Use unknown extents.
161 int rank = expr.Rank();
162 if (rank < 0)
163 TODO(converter.getCurrentLocation(), "assumed rank expression types");
164 for (int dim = 0; dim < rank; ++dim)
165 shape.emplace_back(fir::SequenceType::getUnknownExtent());
166 }
167 if (!shape.empty())
168 return fir::SequenceType::get(shape, baseType);
169 return baseType;
170 }
171
172 template <typename A>
translateShape__anon8bca3fa80111::TypeBuilder173 void translateShape(A &shape, Fortran::evaluate::Shape &&shapeExpr) {
174 for (Fortran::evaluate::MaybeExtentExpr extentExpr : shapeExpr) {
175 fir::SequenceType::Extent extent = fir::SequenceType::getUnknownExtent();
176 if (std::optional<std::int64_t> constantExtent =
177 toInt64(std::move(extentExpr)))
178 extent = *constantExtent;
179 shape.push_back(extent);
180 }
181 }
182
183 template <typename A>
toInt64__anon8bca3fa80111::TypeBuilder184 std::optional<std::int64_t> toInt64(A &&expr) {
185 return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
186 converter.getFoldingContext(), std::move(expr)));
187 }
188
genTypelessExprType__anon8bca3fa80111::TypeBuilder189 mlir::Type genTypelessExprType(const Fortran::lower::SomeExpr &expr) {
190 return std::visit(
191 Fortran::common::visitors{
192 [&](const Fortran::evaluate::BOZLiteralConstant &) -> mlir::Type {
193 return mlir::NoneType::get(context);
194 },
195 [&](const Fortran::evaluate::NullPointer &) -> mlir::Type {
196 return fir::ReferenceType::get(mlir::NoneType::get(context));
197 },
198 [&](const Fortran::evaluate::ProcedureDesignator &proc)
199 -> mlir::Type {
200 return Fortran::lower::translateSignature(proc, converter);
201 },
202 [&](const Fortran::evaluate::ProcedureRef &) -> mlir::Type {
203 return mlir::NoneType::get(context);
204 },
205 [](const auto &x) -> mlir::Type {
206 using T = std::decay_t<decltype(x)>;
207 static_assert(!Fortran::common::HasMember<
208 T, Fortran::evaluate::TypelessExpression>,
209 "missing typeless expr handling");
210 llvm::report_fatal_error("not a typeless expression");
211 },
212 },
213 expr.u);
214 }
215
genSymbolType__anon8bca3fa80111::TypeBuilder216 mlir::Type genSymbolType(const Fortran::semantics::Symbol &symbol,
217 bool isAlloc = false, bool isPtr = false) {
218 mlir::Location loc = converter.genLocation(symbol.name());
219 mlir::Type ty;
220 // If the symbol is not the same as the ultimate one (i.e, it is host or use
221 // associated), all the symbol properties are the ones of the ultimate
222 // symbol but the volatile and asynchronous attributes that may differ. To
223 // avoid issues with helper functions that would not follow association
224 // links, the fir type is built based on the ultimate symbol. This relies
225 // on the fact volatile and asynchronous are not reflected in fir types.
226 const Fortran::semantics::Symbol &ultimate = symbol.GetUltimate();
227 if (Fortran::semantics::IsProcedurePointer(ultimate))
228 TODO(loc, "procedure pointers");
229 if (const Fortran::semantics::DeclTypeSpec *type = ultimate.GetType()) {
230 if (const Fortran::semantics::IntrinsicTypeSpec *tySpec =
231 type->AsIntrinsic()) {
232 int kind = toInt64(Fortran::common::Clone(tySpec->kind())).value();
233 llvm::SmallVector<Fortran::lower::LenParameterTy> params;
234 translateLenParameters(params, tySpec->category(), ultimate);
235 ty = genFIRType(context, tySpec->category(), kind, params);
236 } else if (type->IsPolymorphic()) {
237 TODO(loc, "support for polymorphic types");
238 } else if (const Fortran::semantics::DerivedTypeSpec *tySpec =
239 type->AsDerived()) {
240 ty = genDerivedType(*tySpec);
241 } else {
242 fir::emitFatalError(loc, "symbol's type must have a type spec");
243 }
244 } else {
245 fir::emitFatalError(loc, "symbol must have a type");
246 }
247 if (ultimate.IsObjectArray()) {
248 auto shapeExpr = Fortran::evaluate::GetShapeHelper{
249 converter.getFoldingContext()}(ultimate);
250 if (!shapeExpr)
251 TODO(loc, "assumed rank symbol type");
252 fir::SequenceType::Shape shape;
253 translateShape(shape, std::move(*shapeExpr));
254 ty = fir::SequenceType::get(shape, ty);
255 }
256
257 if (Fortran::semantics::IsPointer(symbol))
258 return fir::BoxType::get(fir::PointerType::get(ty));
259 if (Fortran::semantics::IsAllocatable(symbol))
260 return fir::BoxType::get(fir::HeapType::get(ty));
261 // isPtr and isAlloc are variable that were promoted to be on the
262 // heap or to be pointers, but they do not have Fortran allocatable
263 // or pointer semantics, so do not use box for them.
264 if (isPtr)
265 return fir::PointerType::get(ty);
266 if (isAlloc)
267 return fir::HeapType::get(ty);
268 return ty;
269 }
270
271 /// Does \p component has non deferred lower bounds that are not compile time
272 /// constant 1.
componentHasNonDefaultLowerBounds__anon8bca3fa80111::TypeBuilder273 static bool componentHasNonDefaultLowerBounds(
274 const Fortran::semantics::Symbol &component) {
275 if (const auto *objDetails =
276 component.detailsIf<Fortran::semantics::ObjectEntityDetails>())
277 for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape())
278 if (auto lb = bounds.lbound().GetExplicit())
279 if (auto constant = Fortran::evaluate::ToInt64(*lb))
280 if (!constant || *constant != 1)
281 return true;
282 return false;
283 }
284
genDerivedType__anon8bca3fa80111::TypeBuilder285 mlir::Type genDerivedType(const Fortran::semantics::DerivedTypeSpec &tySpec) {
286 std::vector<std::pair<std::string, mlir::Type>> ps;
287 std::vector<std::pair<std::string, mlir::Type>> cs;
288 const Fortran::semantics::Symbol &typeSymbol = tySpec.typeSymbol();
289 if (mlir::Type ty = getTypeIfDerivedAlreadyInConstruction(typeSymbol))
290 return ty;
291
292 if (Fortran::semantics::IsFinalizable(tySpec))
293 TODO(converter.genLocation(tySpec.name()), "derived type finalization");
294
295 auto rec = fir::RecordType::get(context,
296 Fortran::lower::mangle::mangleName(tySpec));
297 // Maintain the stack of types for recursive references.
298 derivedTypeInConstruction.emplace_back(typeSymbol, rec);
299
300 // Gather the record type fields.
301 // (1) The data components.
302 for (const auto &field :
303 Fortran::semantics::OrderedComponentIterator(tySpec)) {
304 // Lowering is assuming non deferred component lower bounds are always 1.
305 // Catch any situations where this is not true for now.
306 if (componentHasNonDefaultLowerBounds(field))
307 TODO(converter.genLocation(field.name()),
308 "derived type components with non default lower bounds");
309 if (IsProcedure(field))
310 TODO(converter.genLocation(field.name()), "procedure components");
311 mlir::Type ty = genSymbolType(field);
312 // Do not add the parent component (component of the parents are
313 // added and should be sufficient, the parent component would
314 // duplicate the fields).
315 if (field.test(Fortran::semantics::Symbol::Flag::ParentComp))
316 continue;
317 cs.emplace_back(field.name().ToString(), ty);
318 }
319
320 // (2) The LEN type parameters.
321 for (const auto ¶m :
322 Fortran::semantics::OrderParameterDeclarations(typeSymbol))
323 if (param->get<Fortran::semantics::TypeParamDetails>().attr() ==
324 Fortran::common::TypeParamAttr::Len)
325 ps.emplace_back(param->name().ToString(), genSymbolType(*param));
326
327 rec.finalize(ps, cs);
328 popDerivedTypeInConstruction();
329
330 mlir::Location loc = converter.genLocation(typeSymbol.name());
331 if (!ps.empty()) {
332 // This type is a PDT (parametric derived type). Create the functions to
333 // use for allocation, dereferencing, and address arithmetic here.
334 TODO(loc, "parameterized derived types");
335 }
336 LLVM_DEBUG(llvm::dbgs() << "derived type: " << rec << '\n');
337
338 // Generate the type descriptor object if any
339 if (const Fortran::semantics::Scope *derivedScope =
340 tySpec.scope() ? tySpec.scope() : tySpec.typeSymbol().scope())
341 if (const Fortran::semantics::Symbol *typeInfoSym =
342 derivedScope->runtimeDerivedTypeDescription())
343 converter.registerRuntimeTypeInfo(loc, *typeInfoSym);
344 return rec;
345 }
346
347 // To get the character length from a symbol, make an fold a designator for
348 // the symbol to cover the case where the symbol is an assumed length named
349 // constant and its length comes from its init expression length.
350 template <int Kind>
351 fir::SequenceType::Extent
getCharacterLengthHelper__anon8bca3fa80111::TypeBuilder352 getCharacterLengthHelper(const Fortran::semantics::Symbol &symbol) {
353 using TC =
354 Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, Kind>;
355 auto designator = Fortran::evaluate::Fold(
356 converter.getFoldingContext(),
357 Fortran::evaluate::Expr<TC>{Fortran::evaluate::Designator<TC>{symbol}});
358 if (auto len = toInt64(std::move(designator.LEN())))
359 return *len;
360 return fir::SequenceType::getUnknownExtent();
361 }
362
363 template <typename T>
translateLenParameters__anon8bca3fa80111::TypeBuilder364 void translateLenParameters(
365 llvm::SmallVectorImpl<Fortran::lower::LenParameterTy> ¶ms,
366 Fortran::common::TypeCategory category, const T &exprOrSym) {
367 if (category == Fortran::common::TypeCategory::Character)
368 params.push_back(getCharacterLength(exprOrSym));
369 else if (category == Fortran::common::TypeCategory::Derived)
370 TODO(converter.getCurrentLocation(), "derived type length parameters");
371 }
372 Fortran::lower::LenParameterTy
getCharacterLength__anon8bca3fa80111::TypeBuilder373 getCharacterLength(const Fortran::semantics::Symbol &symbol) {
374 const Fortran::semantics::DeclTypeSpec *type = symbol.GetType();
375 if (!type ||
376 type->category() != Fortran::semantics::DeclTypeSpec::Character ||
377 !type->AsIntrinsic())
378 llvm::report_fatal_error("not a character symbol");
379 int kind =
380 toInt64(Fortran::common::Clone(type->AsIntrinsic()->kind())).value();
381 switch (kind) {
382 case 1:
383 return getCharacterLengthHelper<1>(symbol);
384 case 2:
385 return getCharacterLengthHelper<2>(symbol);
386 case 4:
387 return getCharacterLengthHelper<4>(symbol);
388 }
389 llvm_unreachable("unknown character kind");
390 }
391 Fortran::lower::LenParameterTy
getCharacterLength__anon8bca3fa80111::TypeBuilder392 getCharacterLength(const Fortran::lower::SomeExpr &expr) {
393 // Do not use dynamic type length here. We would miss constant
394 // lengths opportunities because dynamic type only has the length
395 // if it comes from a declaration.
396 auto charExpr =
397 std::get<Fortran::evaluate::Expr<Fortran::evaluate::SomeCharacter>>(
398 expr.u);
399 if (auto constantLen = toInt64(charExpr.LEN()))
400 return *constantLen;
401 return fir::SequenceType::getUnknownExtent();
402 }
403
genVariableType__anon8bca3fa80111::TypeBuilder404 mlir::Type genVariableType(const Fortran::lower::pft::Variable &var) {
405 return genSymbolType(var.getSymbol(), var.isHeapAlloc(), var.isPointer());
406 }
407
408 /// Derived type can be recursive. That is, pointer components of a derived
409 /// type `t` have type `t`. This helper returns `t` if it is already being
410 /// lowered to avoid infinite loops.
getTypeIfDerivedAlreadyInConstruction__anon8bca3fa80111::TypeBuilder411 mlir::Type getTypeIfDerivedAlreadyInConstruction(
412 const Fortran::lower::SymbolRef derivedSym) const {
413 for (const auto &[sym, type] : derivedTypeInConstruction)
414 if (sym == derivedSym)
415 return type;
416 return {};
417 }
418
popDerivedTypeInConstruction__anon8bca3fa80111::TypeBuilder419 void popDerivedTypeInConstruction() {
420 assert(!derivedTypeInConstruction.empty());
421 derivedTypeInConstruction.pop_back();
422 }
423
424 /// Stack derived type being processed to avoid infinite loops in case of
425 /// recursive derived types. The depth of derived types is expected to be
426 /// shallow (<10), so a SmallVector is sufficient.
427 llvm::SmallVector<std::pair<const Fortran::lower::SymbolRef, mlir::Type>>
428 derivedTypeInConstruction;
429 Fortran::lower::AbstractConverter &converter;
430 mlir::MLIRContext *context;
431 };
432 } // namespace
433
getFIRType(mlir::MLIRContext * context,Fortran::common::TypeCategory tc,int kind,llvm::ArrayRef<LenParameterTy> params)434 mlir::Type Fortran::lower::getFIRType(mlir::MLIRContext *context,
435 Fortran::common::TypeCategory tc,
436 int kind,
437 llvm::ArrayRef<LenParameterTy> params) {
438 return genFIRType(context, tc, kind, params);
439 }
440
translateDerivedTypeToFIRType(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::DerivedTypeSpec & tySpec)441 mlir::Type Fortran::lower::translateDerivedTypeToFIRType(
442 Fortran::lower::AbstractConverter &converter,
443 const Fortran::semantics::DerivedTypeSpec &tySpec) {
444 return TypeBuilder{converter}.genDerivedType(tySpec);
445 }
446
translateSomeExprToFIRType(Fortran::lower::AbstractConverter & converter,const SomeExpr & expr)447 mlir::Type Fortran::lower::translateSomeExprToFIRType(
448 Fortran::lower::AbstractConverter &converter, const SomeExpr &expr) {
449 return TypeBuilder{converter}.genExprType(expr);
450 }
451
translateSymbolToFIRType(Fortran::lower::AbstractConverter & converter,const SymbolRef symbol)452 mlir::Type Fortran::lower::translateSymbolToFIRType(
453 Fortran::lower::AbstractConverter &converter, const SymbolRef symbol) {
454 return TypeBuilder{converter}.genSymbolType(symbol);
455 }
456
translateVariableToFIRType(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var)457 mlir::Type Fortran::lower::translateVariableToFIRType(
458 Fortran::lower::AbstractConverter &converter,
459 const Fortran::lower::pft::Variable &var) {
460 return TypeBuilder{converter}.genVariableType(var);
461 }
462
convertReal(mlir::MLIRContext * context,int kind)463 mlir::Type Fortran::lower::convertReal(mlir::MLIRContext *context, int kind) {
464 return genRealType(context, kind);
465 }
466