1 //===-- ConvertConstant.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
11 //===----------------------------------------------------------------------===//
13 #include "flang/Lower/ConvertConstant.h"
14 #include "flang/Evaluate/expression.h"
15 #include "flang/Lower/AbstractConverter.h"
16 #include "flang/Lower/BuiltinModules.h"
17 #include "flang/Lower/ConvertExprToHLFIR.h"
18 #include "flang/Lower/ConvertType.h"
19 #include "flang/Lower/ConvertVariable.h"
20 #include "flang/Lower/Mangler.h"
21 #include "flang/Lower/StatementContext.h"
22 #include "flang/Lower/SymbolMap.h"
23 #include "flang/Optimizer/Builder/Complex.h"
24 #include "flang/Optimizer/Builder/MutableBox.h"
25 #include "flang/Optimizer/Builder/Todo.h"
29 /// Convert string, \p s, to an APFloat value. Recognize and handle Inf and
30 /// NaN strings as well. \p s is assumed to not contain any spaces.
31 static llvm::APFloat
consAPFloat(const llvm::fltSemantics
&fsem
,
33 assert(!s
.contains(' '));
34 if (s
.compare_insensitive("-inf") == 0)
35 return llvm::APFloat::getInf(fsem
, /*negative=*/true);
36 if (s
.compare_insensitive("inf") == 0 || s
.compare_insensitive("+inf") == 0)
37 return llvm::APFloat::getInf(fsem
);
38 // TODO: Add support for quiet and signaling NaNs.
39 if (s
.compare_insensitive("-nan") == 0)
40 return llvm::APFloat::getNaN(fsem
, /*negative=*/true);
41 if (s
.compare_insensitive("nan") == 0 || s
.compare_insensitive("+nan") == 0)
42 return llvm::APFloat::getNaN(fsem
);
46 //===----------------------------------------------------------------------===//
47 // Fortran::lower::tryCreatingDenseGlobal implementation
48 //===----------------------------------------------------------------------===//
50 /// Generate an mlir attribute from a literal value
51 template <Fortran::common::TypeCategory TC
, int KIND
>
52 static mlir::Attribute
convertToAttribute(
53 fir::FirOpBuilder
&builder
,
54 const Fortran::evaluate::Scalar
<Fortran::evaluate::Type
<TC
, KIND
>> &value
,
56 if constexpr (TC
== Fortran::common::TypeCategory::Integer
) {
57 if constexpr (KIND
<= 8)
58 return builder
.getIntegerAttr(type
, value
.ToInt64());
60 static_assert(KIND
<= 16, "integers with KIND > 16 are not supported");
61 return builder
.getIntegerAttr(
62 type
, llvm::APInt(KIND
* 8,
63 {value
.ToUInt64(), value
.SHIFTR(64).ToUInt64()}));
65 } else if constexpr (TC
== Fortran::common::TypeCategory::Logical
) {
66 return builder
.getIntegerAttr(type
, value
.IsTrue());
68 auto getFloatAttr
= [&](const auto &value
, mlir::Type type
) {
69 std::string str
= value
.DumpHexadecimal();
71 consAPFloat(builder
.getKindMap().getFloatSemantics(KIND
), str
);
72 return builder
.getFloatAttr(type
, floatVal
);
75 if constexpr (TC
== Fortran::common::TypeCategory::Real
) {
76 return getFloatAttr(value
, type
);
78 static_assert(TC
== Fortran::common::TypeCategory::Complex
,
79 "type values cannot be converted to attributes");
80 mlir::Type eleTy
= mlir::cast
<mlir::ComplexType
>(type
).getElementType();
81 llvm::SmallVector
<mlir::Attribute
, 2> attrs
= {
82 getFloatAttr(value
.REAL(), eleTy
),
83 getFloatAttr(value
.AIMAG(), eleTy
)};
84 return builder
.getArrayAttr(attrs
);
91 /// Helper class to lower an array constant to a global with an MLIR dense
94 /// If we have an array of integer, real, complex, or logical, then we can
95 /// create a global array with the dense attribute.
97 /// The mlir tensor type can only handle integer, real, complex, or logical.
98 /// It does not currently support nested structures.
99 class DenseGlobalBuilder
{
101 static fir::GlobalOp
tryCreating(fir::FirOpBuilder
&builder
,
102 mlir::Location loc
, mlir::Type symTy
,
103 llvm::StringRef globalName
,
104 mlir::StringAttr linkage
, bool isConst
,
105 const Fortran::lower::SomeExpr
&initExpr
,
106 cuf::DataAttributeAttr dataAttr
) {
107 DenseGlobalBuilder globalBuilder
;
108 Fortran::common::visit(
109 Fortran::common::visitors
{
110 [&](const Fortran::evaluate::Expr
<Fortran::evaluate::SomeLogical
> &
111 x
) { globalBuilder
.tryConvertingToAttributes(builder
, x
); },
112 [&](const Fortran::evaluate::Expr
<Fortran::evaluate::SomeInteger
> &
113 x
) { globalBuilder
.tryConvertingToAttributes(builder
, x
); },
114 [&](const Fortran::evaluate::Expr
<Fortran::evaluate::SomeReal
> &x
) {
115 globalBuilder
.tryConvertingToAttributes(builder
, x
);
117 [&](const Fortran::evaluate::Expr
<Fortran::evaluate::SomeComplex
> &
118 x
) { globalBuilder
.tryConvertingToAttributes(builder
, x
); },
122 return globalBuilder
.tryCreatingGlobal(builder
, loc
, symTy
, globalName
,
123 linkage
, isConst
, dataAttr
);
126 template <Fortran::common::TypeCategory TC
, int KIND
>
127 static fir::GlobalOp
tryCreating(
128 fir::FirOpBuilder
&builder
, mlir::Location loc
, mlir::Type symTy
,
129 llvm::StringRef globalName
, mlir::StringAttr linkage
, bool isConst
,
130 const Fortran::evaluate::Constant
<Fortran::evaluate::Type
<TC
, KIND
>>
132 cuf::DataAttributeAttr dataAttr
) {
133 DenseGlobalBuilder globalBuilder
;
134 globalBuilder
.tryConvertingToAttributes(builder
, constant
);
135 return globalBuilder
.tryCreatingGlobal(builder
, loc
, symTy
, globalName
,
136 linkage
, isConst
, dataAttr
);
140 DenseGlobalBuilder() = default;
142 /// Try converting an evaluate::Constant to a list of MLIR attributes.
143 template <Fortran::common::TypeCategory TC
, int KIND
>
144 void tryConvertingToAttributes(
145 fir::FirOpBuilder
&builder
,
146 const Fortran::evaluate::Constant
<Fortran::evaluate::Type
<TC
, KIND
>>
148 static_assert(TC
!= Fortran::common::TypeCategory::Character
,
149 "must be numerical or logical");
150 auto attrTc
= TC
== Fortran::common::TypeCategory::Logical
151 ? Fortran::common::TypeCategory::Integer
153 attributeElementType
= Fortran::lower::getFIRType(
154 builder
.getContext(), attrTc
, KIND
, std::nullopt
);
155 for (auto element
: constant
.values())
156 attributes
.push_back(
157 convertToAttribute
<TC
, KIND
>(builder
, element
, attributeElementType
));
160 /// Try converting an evaluate::Expr to a list of MLIR attributes.
161 template <typename SomeCat
>
162 void tryConvertingToAttributes(fir::FirOpBuilder
&builder
,
163 const Fortran::evaluate::Expr
<SomeCat
> &expr
) {
164 Fortran::common::visit(
166 using TR
= Fortran::evaluate::ResultType
<decltype(x
)>;
167 if (const auto *constant
=
168 std::get_if
<Fortran::evaluate::Constant
<TR
>>(&x
.u
))
169 tryConvertingToAttributes
<TR::category
, TR::kind
>(builder
,
175 /// Create a fir::Global if MLIR attributes have been successfully created by
176 /// tryConvertingToAttributes.
177 fir::GlobalOp
tryCreatingGlobal(fir::FirOpBuilder
&builder
,
178 mlir::Location loc
, mlir::Type symTy
,
179 llvm::StringRef globalName
,
180 mlir::StringAttr linkage
, bool isConst
,
181 cuf::DataAttributeAttr dataAttr
) const {
182 // Not a "trivial" intrinsic constant array, or empty array.
183 if (!attributeElementType
|| attributes
.empty())
186 assert(mlir::isa
<fir::SequenceType
>(symTy
) && "expecting an array global");
187 auto arrTy
= mlir::cast
<fir::SequenceType
>(symTy
);
188 llvm::SmallVector
<int64_t> tensorShape(arrTy
.getShape());
189 std::reverse(tensorShape
.begin(), tensorShape
.end());
191 mlir::RankedTensorType::get(tensorShape
, attributeElementType
);
192 auto init
= mlir::DenseElementsAttr::get(tensorTy
, attributes
);
193 return builder
.createGlobal(loc
, symTy
, globalName
, linkage
, init
, isConst
,
194 /*isTarget=*/false, dataAttr
);
197 llvm::SmallVector
<mlir::Attribute
> attributes
;
198 mlir::Type attributeElementType
;
202 fir::GlobalOp
Fortran::lower::tryCreatingDenseGlobal(
203 fir::FirOpBuilder
&builder
, mlir::Location loc
, mlir::Type symTy
,
204 llvm::StringRef globalName
, mlir::StringAttr linkage
, bool isConst
,
205 const Fortran::lower::SomeExpr
&initExpr
, cuf::DataAttributeAttr dataAttr
) {
206 return DenseGlobalBuilder::tryCreating(builder
, loc
, symTy
, globalName
,
207 linkage
, isConst
, initExpr
, dataAttr
);
210 //===----------------------------------------------------------------------===//
211 // Fortran::lower::convertConstant
212 // Lower a constant to a fir::ExtendedValue.
213 //===----------------------------------------------------------------------===//
215 /// Generate a real constant with a value `value`.
217 static mlir::Value
genRealConstant(fir::FirOpBuilder
&builder
,
219 const llvm::APFloat
&value
) {
220 mlir::Type fltTy
= Fortran::lower::convertReal(builder
.getContext(), KIND
);
221 return builder
.createRealConstant(loc
, fltTy
, value
);
224 /// Convert a scalar literal constant to IR.
225 template <Fortran::common::TypeCategory TC
, int KIND
>
226 static mlir::Value
genScalarLit(
227 fir::FirOpBuilder
&builder
, mlir::Location loc
,
228 const Fortran::evaluate::Scalar
<Fortran::evaluate::Type
<TC
, KIND
>> &value
) {
229 if constexpr (TC
== Fortran::common::TypeCategory::Integer
||
230 TC
== Fortran::common::TypeCategory::Unsigned
) {
231 // MLIR requires constants to be signless
232 mlir::Type ty
= Fortran::lower::getFIRType(
233 builder
.getContext(), Fortran::common::TypeCategory::Integer
, KIND
,
236 auto bigInt
= llvm::APInt(ty
.getIntOrFloatBitWidth(),
237 TC
== Fortran::common::TypeCategory::Unsigned
238 ? value
.UnsignedDecimal()
239 : value
.SignedDecimal(),
241 return builder
.create
<mlir::arith::ConstantOp
>(
242 loc
, ty
, mlir::IntegerAttr::get(ty
, bigInt
));
244 return builder
.createIntegerConstant(loc
, ty
, value
.ToInt64());
245 } else if constexpr (TC
== Fortran::common::TypeCategory::Logical
) {
246 return builder
.createBool(loc
, value
.IsTrue());
247 } else if constexpr (TC
== Fortran::common::TypeCategory::Real
) {
248 std::string str
= value
.DumpHexadecimal();
249 if constexpr (KIND
== 2) {
250 auto floatVal
= consAPFloat(llvm::APFloatBase::IEEEhalf(), str
);
251 return genRealConstant
<KIND
>(builder
, loc
, floatVal
);
252 } else if constexpr (KIND
== 3) {
253 auto floatVal
= consAPFloat(llvm::APFloatBase::BFloat(), str
);
254 return genRealConstant
<KIND
>(builder
, loc
, floatVal
);
255 } else if constexpr (KIND
== 4) {
256 auto floatVal
= consAPFloat(llvm::APFloatBase::IEEEsingle(), str
);
257 return genRealConstant
<KIND
>(builder
, loc
, floatVal
);
258 } else if constexpr (KIND
== 10) {
259 auto floatVal
= consAPFloat(llvm::APFloatBase::x87DoubleExtended(), str
);
260 return genRealConstant
<KIND
>(builder
, loc
, floatVal
);
261 } else if constexpr (KIND
== 16) {
262 auto floatVal
= consAPFloat(llvm::APFloatBase::IEEEquad(), str
);
263 return genRealConstant
<KIND
>(builder
, loc
, floatVal
);
265 // convert everything else to double
266 auto floatVal
= consAPFloat(llvm::APFloatBase::IEEEdouble(), str
);
267 return genRealConstant
<KIND
>(builder
, loc
, floatVal
);
269 } else if constexpr (TC
== Fortran::common::TypeCategory::Complex
) {
270 mlir::Value real
= genScalarLit
<Fortran::common::TypeCategory::Real
, KIND
>(
271 builder
, loc
, value
.REAL());
272 mlir::Value imag
= genScalarLit
<Fortran::common::TypeCategory::Real
, KIND
>(
273 builder
, loc
, value
.AIMAG());
274 return fir::factory::Complex
{builder
, loc
}.createComplex(real
, imag
);
275 } else /*constexpr*/ {
276 llvm_unreachable("unhandled constant");
280 /// Create fir::string_lit from a scalar character constant.
282 static fir::StringLitOp
283 createStringLitOp(fir::FirOpBuilder
&builder
, mlir::Location loc
,
284 const Fortran::evaluate::Scalar
<Fortran::evaluate::Type
<
285 Fortran::common::TypeCategory::Character
, KIND
>> &value
,
286 [[maybe_unused
]] int64_t len
) {
287 if constexpr (KIND
== 1) {
288 assert(value
.size() == static_cast<std::uint64_t>(len
));
289 return builder
.createStringLitOp(loc
, value
);
291 using ET
= typename
std::decay_t
<decltype(value
)>::value_type
;
292 fir::CharacterType type
=
293 fir::CharacterType::get(builder
.getContext(), KIND
, len
);
294 mlir::MLIRContext
*context
= builder
.getContext();
295 std::int64_t size
= static_cast<std::int64_t>(value
.size());
296 mlir::ShapedType shape
= mlir::RankedTensorType::get(
297 llvm::ArrayRef
<std::int64_t>{size
},
298 mlir::IntegerType::get(builder
.getContext(), sizeof(ET
) * 8));
299 auto denseAttr
= mlir::DenseElementsAttr::get(
300 shape
, llvm::ArrayRef
<ET
>{value
.data(), value
.size()});
301 auto denseTag
= mlir::StringAttr::get(context
, fir::StringLitOp::xlist());
302 mlir::NamedAttribute
dataAttr(denseTag
, denseAttr
);
303 auto sizeTag
= mlir::StringAttr::get(context
, fir::StringLitOp::size());
304 mlir::NamedAttribute
sizeAttr(sizeTag
, builder
.getI64IntegerAttr(len
));
305 llvm::SmallVector
<mlir::NamedAttribute
> attrs
= {dataAttr
, sizeAttr
};
306 return builder
.create
<fir::StringLitOp
>(
307 loc
, llvm::ArrayRef
<mlir::Type
>{type
}, std::nullopt
, attrs
);
311 /// Convert a scalar literal CHARACTER to IR.
314 genScalarLit(fir::FirOpBuilder
&builder
, mlir::Location loc
,
315 const Fortran::evaluate::Scalar
<Fortran::evaluate::Type
<
316 Fortran::common::TypeCategory::Character
, KIND
>> &value
,
317 int64_t len
, bool outlineInReadOnlyMemory
) {
318 // When in an initializer context, construct the literal op itself and do
319 // not construct another constant object in rodata.
320 if (!outlineInReadOnlyMemory
)
321 return createStringLitOp
<KIND
>(builder
, loc
, value
, len
);
323 // Otherwise, the string is in a plain old expression so "outline" the value
324 // in read only data by hash consing it to a constant literal object.
326 // ASCII global constants are created using an mlir string attribute.
327 if constexpr (KIND
== 1) {
328 return fir::getBase(fir::factory::createStringLiteral(builder
, loc
, value
));
331 auto size
= builder
.getKindMap().getCharacterBitsize(KIND
) / 8 * value
.size();
332 llvm::StringRef
strVal(reinterpret_cast<const char *>(value
.c_str()), size
);
333 std::string globalName
= fir::factory::uniqueCGIdent(
334 KIND
== 1 ? "cl"s
: "cl"s
+ std::to_string(KIND
), strVal
);
335 fir::GlobalOp global
= builder
.getNamedGlobal(globalName
);
336 fir::CharacterType type
=
337 fir::CharacterType::get(builder
.getContext(), KIND
, len
);
339 global
= builder
.createGlobalConstant(
340 loc
, type
, globalName
,
341 [&](fir::FirOpBuilder
&builder
) {
342 fir::StringLitOp str
=
343 createStringLitOp
<KIND
>(builder
, loc
, value
, len
);
344 builder
.create
<fir::HasValueOp
>(loc
, str
);
346 builder
.createLinkOnceLinkage());
347 return builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
351 // Helper to generate StructureConstructor component values.
352 static fir::ExtendedValue
353 genConstantValue(Fortran::lower::AbstractConverter
&converter
,
355 const Fortran::lower::SomeExpr
&constantExpr
);
357 static mlir::Value
genStructureComponentInit(
358 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
359 const Fortran::semantics::Symbol
&sym
, const Fortran::lower::SomeExpr
&expr
,
361 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
362 fir::RecordType recTy
= mlir::cast
<fir::RecordType
>(res
.getType());
363 std::string name
= converter
.getRecordTypeFieldName(sym
);
364 mlir::Type componentTy
= recTy
.getType(name
);
365 auto fieldTy
= fir::FieldType::get(recTy
.getContext());
366 assert(componentTy
&& "failed to retrieve component");
367 // FIXME: type parameters must come from the derived-type-spec
368 auto field
= builder
.create
<fir::FieldIndexOp
>(
369 loc
, fieldTy
, name
, recTy
,
370 /*typeParams=*/mlir::ValueRange
{} /*TODO*/);
372 if (Fortran::semantics::IsAllocatable(sym
)) {
373 if (!Fortran::evaluate::IsNullPointer(expr
)) {
374 fir::emitFatalError(loc
, "constant structure constructor with an "
375 "allocatable component value that is not NULL");
377 // Handle NULL() initialization
378 mlir::Value componentValue
{fir::factory::createUnallocatedBox(
379 builder
, loc
, componentTy
, std::nullopt
)};
380 componentValue
= builder
.createConvert(loc
, componentTy
, componentValue
);
382 return builder
.create
<fir::InsertValueOp
>(
383 loc
, recTy
, res
, componentValue
,
384 builder
.getArrayAttr(field
.getAttributes()));
388 if (Fortran::semantics::IsPointer(sym
)) {
389 mlir::Value initialTarget
;
390 if (Fortran::semantics::IsProcedure(sym
)) {
391 if (Fortran::evaluate::UnwrapExpr
<Fortran::evaluate::NullPointer
>(expr
))
393 fir::factory::createNullBoxProc(builder
, loc
, componentTy
);
395 Fortran::lower::SymMap globalOpSymMap
;
396 Fortran::lower::StatementContext stmtCtx
;
397 auto box
{getBase(Fortran::lower::convertExprToAddress(
398 loc
, converter
, expr
, globalOpSymMap
, stmtCtx
))};
399 initialTarget
= builder
.createConvert(loc
, componentTy
, box
);
402 initialTarget
= Fortran::lower::genInitialDataTarget(converter
, loc
,
404 res
= builder
.create
<fir::InsertValueOp
>(
405 loc
, recTy
, res
, initialTarget
,
406 builder
.getArrayAttr(field
.getAttributes()));
410 if (Fortran::lower::isDerivedTypeWithLenParameters(sym
))
411 TODO(loc
, "component with length parameters in structure constructor");
413 // Special handling for scalar c_ptr/c_funptr constants. The array constant
414 // must fall through to genConstantValue() below.
415 if (Fortran::semantics::IsBuiltinCPtr(sym
) && sym
.Rank() == 0 &&
416 (Fortran::evaluate::GetLastSymbol(expr
) ||
417 Fortran::evaluate::IsNullPointer(expr
))) {
418 // Builtin c_ptr and c_funptr have special handling because designators
419 // and NULL() are handled as initial values for them as an extension
420 // (otherwise only c_ptr_null/c_funptr_null are allowed and these are
421 // replaced by structure constructors by semantics, so GetLastSymbol
424 // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or
425 // NULL()) that must be inserted into an intermediate cptr record value's
426 // address field, which ought to be an intptr_t on the target.
427 mlir::Value addr
= fir::getBase(
428 Fortran::lower::genExtAddrInInitializer(converter
, loc
, expr
));
429 if (mlir::isa
<fir::BoxProcType
>(addr
.getType()))
430 addr
= builder
.create
<fir::BoxAddrOp
>(loc
, addr
);
431 assert((fir::isa_ref_type(addr
.getType()) ||
432 mlir::isa
<mlir::FunctionType
>(addr
.getType())) &&
433 "expect reference type for address field");
434 assert(fir::isa_derived(componentTy
) &&
435 "expect C_PTR, C_FUNPTR to be a record");
436 auto cPtrRecTy
= mlir::cast
<fir::RecordType
>(componentTy
);
437 llvm::StringRef addrFieldName
= Fortran::lower::builtin::cptrFieldName
;
438 mlir::Type addrFieldTy
= cPtrRecTy
.getType(addrFieldName
);
439 auto addrField
= builder
.create
<fir::FieldIndexOp
>(
440 loc
, fieldTy
, addrFieldName
, componentTy
,
441 /*typeParams=*/mlir::ValueRange
{});
442 mlir::Value castAddr
= builder
.createConvert(loc
, addrFieldTy
, addr
);
443 auto undef
= builder
.create
<fir::UndefOp
>(loc
, componentTy
);
444 addr
= builder
.create
<fir::InsertValueOp
>(
445 loc
, componentTy
, undef
, castAddr
,
446 builder
.getArrayAttr(addrField
.getAttributes()));
447 res
= builder
.create
<fir::InsertValueOp
>(
448 loc
, recTy
, res
, addr
, builder
.getArrayAttr(field
.getAttributes()));
452 mlir::Value val
= fir::getBase(genConstantValue(converter
, loc
, expr
));
453 assert(!fir::isa_ref_type(val
.getType()) && "expecting a constant value");
454 mlir::Value castVal
= builder
.createConvert(loc
, componentTy
, val
);
455 res
= builder
.create
<fir::InsertValueOp
>(
456 loc
, recTy
, res
, castVal
, builder
.getArrayAttr(field
.getAttributes()));
460 // Generate a StructureConstructor inlined (returns raw fir.type<T> value,
461 // not the address of a global constant).
462 static mlir::Value
genInlinedStructureCtorLitImpl(
463 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
464 const Fortran::evaluate::StructureConstructor
&ctor
, mlir::Type type
) {
465 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
466 auto recTy
= mlir::cast
<fir::RecordType
>(type
);
468 if (!converter
.getLoweringOptions().getLowerToHighLevelFIR()) {
469 mlir::Value res
= builder
.create
<fir::UndefOp
>(loc
, recTy
);
470 for (const auto &[sym
, expr
] : ctor
.values()) {
471 // Parent components need more work because they do not appear in the
473 if (sym
->test(Fortran::semantics::Symbol::Flag::ParentComp
))
474 TODO(loc
, "parent component in structure constructor");
475 res
= genStructureComponentInit(converter
, loc
, sym
, expr
.value(), res
);
480 auto fieldTy
= fir::FieldType::get(recTy
.getContext());
482 // When the first structure component values belong to some parent type PT
483 // and the next values belong to a type extension ET, a new undef for ET must
484 // be created and the previous PT value inserted into it. There may
485 // be empty parent types in between ET and PT, hence the list and while loop.
486 auto insertParentValueIntoExtension
= [&](mlir::Type typeExtension
) {
487 assert(res
&& "res must be set");
488 llvm::SmallVector
<mlir::Type
> parentTypes
= {typeExtension
};
490 fir::RecordType last
= mlir::cast
<fir::RecordType
>(parentTypes
.back());
492 last
.getType(0); // parent components are first in HLFIR.
493 if (next
!= res
.getType())
494 parentTypes
.push_back(next
);
498 for (mlir::Type parentType
: llvm::reverse(parentTypes
)) {
499 auto undef
= builder
.create
<fir::UndefOp
>(loc
, parentType
);
500 fir::RecordType parentRecTy
= mlir::cast
<fir::RecordType
>(parentType
);
501 auto field
= builder
.create
<fir::FieldIndexOp
>(
502 loc
, fieldTy
, parentRecTy
.getTypeList()[0].first
, parentType
,
503 /*typeParams=*/mlir::ValueRange
{} /*TODO*/);
504 res
= builder
.create
<fir::InsertValueOp
>(
505 loc
, parentRecTy
, undef
, res
,
506 builder
.getArrayAttr(field
.getAttributes()));
510 const Fortran::semantics::DerivedTypeSpec
*curentType
= nullptr;
511 for (const auto &[sym
, expr
] : ctor
.values()) {
512 const Fortran::semantics::DerivedTypeSpec
*componentParentType
=
513 sym
->owner().derivedTypeSpec();
514 assert(componentParentType
&& "failed to retrieve component parent type");
516 mlir::Type parentType
= converter
.genType(*componentParentType
);
517 curentType
= componentParentType
;
518 res
= builder
.create
<fir::UndefOp
>(loc
, parentType
);
519 } else if (*componentParentType
!= *curentType
) {
520 mlir::Type parentType
= converter
.genType(*componentParentType
);
521 insertParentValueIntoExtension(parentType
);
522 curentType
= componentParentType
;
524 res
= genStructureComponentInit(converter
, loc
, sym
, expr
.value(), res
);
527 if (!res
) // structure constructor for empty type.
528 return builder
.create
<fir::UndefOp
>(loc
, recTy
);
530 // The last component may belong to a parent type.
531 if (res
.getType() != recTy
)
532 insertParentValueIntoExtension(recTy
);
536 static mlir::Value
genScalarLit(
537 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
538 const Fortran::evaluate::Scalar
<Fortran::evaluate::SomeDerived
> &value
,
539 mlir::Type eleTy
, bool outlineBigConstantsInReadOnlyMemory
) {
540 if (!outlineBigConstantsInReadOnlyMemory
)
541 return genInlinedStructureCtorLitImpl(converter
, loc
, value
, eleTy
);
542 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
543 auto expr
= std::make_unique
<Fortran::lower::SomeExpr
>(toEvExpr(
544 Fortran::evaluate::Constant
<Fortran::evaluate::SomeDerived
>(value
)));
545 llvm::StringRef globalName
=
546 converter
.getUniqueLitName(loc
, std::move(expr
), eleTy
);
547 fir::GlobalOp global
= builder
.getNamedGlobal(globalName
);
549 global
= builder
.createGlobalConstant(
550 loc
, eleTy
, globalName
,
551 [&](fir::FirOpBuilder
&builder
) {
553 genInlinedStructureCtorLitImpl(converter
, loc
, value
, eleTy
);
554 builder
.create
<fir::HasValueOp
>(loc
, result
);
556 builder
.createInternalLinkage());
558 return builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
562 /// Create an evaluate::Constant<T> array to a fir.array<> value
563 /// built with a chain of fir.insert or fir.insert_on_range operations.
564 /// This is intended to be called when building the body of a fir.global.
565 template <typename T
>
567 genInlinedArrayLit(Fortran::lower::AbstractConverter
&converter
,
568 mlir::Location loc
, mlir::Type arrayTy
,
569 const Fortran::evaluate::Constant
<T
> &con
) {
570 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
571 mlir::IndexType idxTy
= builder
.getIndexType();
572 Fortran::evaluate::ConstantSubscripts subscripts
= con
.lbounds();
573 auto createIdx
= [&]() {
574 llvm::SmallVector
<mlir::Attribute
> idx
;
575 for (size_t i
= 0; i
< subscripts
.size(); ++i
)
577 builder
.getIntegerAttr(idxTy
, subscripts
[i
] - con
.lbounds()[i
]));
580 mlir::Value array
= builder
.create
<fir::UndefOp
>(loc
, arrayTy
);
581 if (Fortran::evaluate::GetSize(con
.shape()) == 0)
583 if constexpr (T::category
== Fortran::common::TypeCategory::Character
) {
585 mlir::Value elementVal
=
586 genScalarLit
<T::kind
>(builder
, loc
, con
.At(subscripts
), con
.LEN(),
587 /*outlineInReadOnlyMemory=*/false);
588 array
= builder
.create
<fir::InsertValueOp
>(
589 loc
, arrayTy
, array
, elementVal
, builder
.getArrayAttr(createIdx()));
590 } while (con
.IncrementSubscripts(subscripts
));
591 } else if constexpr (T::category
== Fortran::common::TypeCategory::Derived
) {
594 mlir::cast
<fir::SequenceType
>(arrayTy
).getElementType();
595 mlir::Value elementVal
=
596 genScalarLit(converter
, loc
, con
.At(subscripts
), eleTy
,
597 /*outlineInReadOnlyMemory=*/false);
598 array
= builder
.create
<fir::InsertValueOp
>(
599 loc
, arrayTy
, array
, elementVal
, builder
.getArrayAttr(createIdx()));
600 } while (con
.IncrementSubscripts(subscripts
));
602 llvm::SmallVector
<mlir::Attribute
> rangeStartIdx
;
603 uint64_t rangeSize
= 0;
604 mlir::Type eleTy
= mlir::cast
<fir::SequenceType
>(arrayTy
).getElementType();
606 auto getElementVal
= [&]() {
607 return builder
.createConvert(loc
, eleTy
,
608 genScalarLit
<T::category
, T::kind
>(
609 builder
, loc
, con
.At(subscripts
)));
611 Fortran::evaluate::ConstantSubscripts nextSubscripts
= subscripts
;
612 bool nextIsSame
= con
.IncrementSubscripts(nextSubscripts
) &&
613 con
.At(subscripts
) == con
.At(nextSubscripts
);
614 if (!rangeSize
&& !nextIsSame
) { // single (non-range) value
615 array
= builder
.create
<fir::InsertValueOp
>(
616 loc
, arrayTy
, array
, getElementVal(),
617 builder
.getArrayAttr(createIdx()));
618 } else if (!rangeSize
) { // start a range
619 rangeStartIdx
= createIdx();
621 } else if (nextIsSame
) { // expand a range
623 } else { // end a range
624 llvm::SmallVector
<int64_t> rangeBounds
;
625 llvm::SmallVector
<mlir::Attribute
> idx
= createIdx();
626 for (size_t i
= 0; i
< idx
.size(); ++i
) {
627 rangeBounds
.push_back(mlir::cast
<mlir::IntegerAttr
>(rangeStartIdx
[i
])
630 rangeBounds
.push_back(
631 mlir::cast
<mlir::IntegerAttr
>(idx
[i
]).getValue().getSExtValue());
633 array
= builder
.create
<fir::InsertOnRangeOp
>(
634 loc
, arrayTy
, array
, getElementVal(),
635 builder
.getIndexVectorAttr(rangeBounds
));
638 } while (con
.IncrementSubscripts(subscripts
));
643 /// Convert an evaluate::Constant<T> array into a fir.ref<fir.array<>> value
644 /// that points to the storage of a fir.global in read only memory and is
645 /// initialized with the value of the constant.
646 /// This should not be called while generating the body of a fir.global.
647 template <typename T
>
649 genOutlineArrayLit(Fortran::lower::AbstractConverter
&converter
,
650 mlir::Location loc
, mlir::Type arrayTy
,
651 const Fortran::evaluate::Constant
<T
> &constant
) {
652 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
653 mlir::Type eleTy
= mlir::cast
<fir::SequenceType
>(arrayTy
).getElementType();
654 llvm::StringRef globalName
= converter
.getUniqueLitName(
655 loc
, std::make_unique
<Fortran::lower::SomeExpr
>(toEvExpr(constant
)),
657 fir::GlobalOp global
= builder
.getNamedGlobal(globalName
);
659 // Using a dense attribute for the initial value instead of creating an
660 // intialization body speeds up MLIR/LLVM compilation, but this is not
662 if constexpr (T::category
== Fortran::common::TypeCategory::Logical
||
663 T::category
== Fortran::common::TypeCategory::Integer
||
664 T::category
== Fortran::common::TypeCategory::Real
||
665 T::category
== Fortran::common::TypeCategory::Complex
) {
666 global
= DenseGlobalBuilder::tryCreating(
667 builder
, loc
, arrayTy
, globalName
, builder
.createInternalLinkage(),
671 // If the number of elements of the array is huge, the compilation may
672 // use a lot of memory and take a very long time to complete.
673 // Empirical evidence shows that an array with 150000 elements of
674 // complex type takes roughly 30 seconds to compile and uses 4GB of RAM,
675 // on a modern machine.
676 // It would be nice to add a driver switch to control the array size
677 // after which flang should not continue to compile.
678 global
= builder
.createGlobalConstant(
679 loc
, arrayTy
, globalName
,
680 [&](fir::FirOpBuilder
&builder
) {
682 genInlinedArrayLit(converter
, loc
, arrayTy
, constant
);
683 builder
.create
<fir::HasValueOp
>(loc
, result
);
685 builder
.createInternalLinkage());
687 return builder
.create
<fir::AddrOfOp
>(loc
, global
.resultType(),
691 /// Convert an evaluate::Constant<T> array into an fir::ExtendedValue.
692 template <typename T
>
693 static fir::ExtendedValue
694 genArrayLit(Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
695 const Fortran::evaluate::Constant
<T
> &con
,
696 bool outlineInReadOnlyMemory
) {
697 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
698 Fortran::evaluate::ConstantSubscript size
=
699 Fortran::evaluate::GetSize(con
.shape());
700 if (size
> std::numeric_limits
<std::uint32_t>::max())
701 // llvm::SmallVector has limited size
702 TODO(loc
, "Creation of very large array constants");
703 fir::SequenceType::Shape
shape(con
.shape().begin(), con
.shape().end());
704 llvm::SmallVector
<std::int64_t> typeParams
;
705 if constexpr (T::category
== Fortran::common::TypeCategory::Character
)
706 typeParams
.push_back(con
.LEN());
708 if constexpr (T::category
== Fortran::common::TypeCategory::Derived
)
709 eleTy
= Fortran::lower::translateDerivedTypeToFIRType(
710 converter
, con
.GetType().GetDerivedTypeSpec());
712 eleTy
= Fortran::lower::getFIRType(builder
.getContext(), T::category
,
713 T::kind
, typeParams
);
714 auto arrayTy
= fir::SequenceType::get(shape
, eleTy
);
715 mlir::Value array
= outlineInReadOnlyMemory
716 ? genOutlineArrayLit(converter
, loc
, arrayTy
, con
)
717 : genInlinedArrayLit(converter
, loc
, arrayTy
, con
);
719 mlir::IndexType idxTy
= builder
.getIndexType();
720 llvm::SmallVector
<mlir::Value
> extents
;
721 for (auto extent
: shape
)
722 extents
.push_back(builder
.createIntegerConstant(loc
, idxTy
, extent
));
723 // Convert lower bounds if they are not all ones.
724 llvm::SmallVector
<mlir::Value
> lbounds
;
725 if (llvm::any_of(con
.lbounds(), [](auto lb
) { return lb
!= 1; }))
726 for (auto lb
: con
.lbounds())
727 lbounds
.push_back(builder
.createIntegerConstant(loc
, idxTy
, lb
));
729 if constexpr (T::category
== Fortran::common::TypeCategory::Character
) {
730 mlir::Value len
= builder
.createIntegerConstant(loc
, idxTy
, con
.LEN());
731 return fir::CharArrayBoxValue
{array
, len
, extents
, lbounds
};
733 return fir::ArrayBoxValue
{array
, extents
, lbounds
};
737 template <typename T
>
738 fir::ExtendedValue
Fortran::lower::ConstantBuilder
<T
>::gen(
739 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
740 const Fortran::evaluate::Constant
<T
> &constant
,
741 bool outlineBigConstantsInReadOnlyMemory
) {
742 if (constant
.Rank() > 0)
743 return genArrayLit(converter
, loc
, constant
,
744 outlineBigConstantsInReadOnlyMemory
);
745 std::optional
<Fortran::evaluate::Scalar
<T
>> opt
= constant
.GetScalarValue();
746 assert(opt
.has_value() && "constant has no value");
747 if constexpr (T::category
== Fortran::common::TypeCategory::Character
) {
748 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
750 genScalarLit
<T::kind
>(builder
, loc
, opt
.value(), constant
.LEN(),
751 outlineBigConstantsInReadOnlyMemory
);
752 mlir::Value len
= builder
.createIntegerConstant(
753 loc
, builder
.getCharacterLengthType(), constant
.LEN());
754 return fir::CharBoxValue
{value
, len
};
755 } else if constexpr (T::category
== Fortran::common::TypeCategory::Derived
) {
756 mlir::Type eleTy
= Fortran::lower::translateDerivedTypeToFIRType(
757 converter
, opt
->GetType().GetDerivedTypeSpec());
758 return genScalarLit(converter
, loc
, *opt
, eleTy
,
759 outlineBigConstantsInReadOnlyMemory
);
761 return genScalarLit
<T::category
, T::kind
>(converter
.getFirOpBuilder(), loc
,
766 static fir::ExtendedValue
767 genConstantValue(Fortran::lower::AbstractConverter
&converter
,
769 const Fortran::evaluate::Expr
<Fortran::evaluate::SomeDerived
>
771 if (const auto *constant
= std::get_if
<
772 Fortran::evaluate::Constant
<Fortran::evaluate::SomeDerived
>>(
774 return Fortran::lower::convertConstant(converter
, loc
, *constant
,
776 if (const auto *structCtor
=
777 std::get_if
<Fortran::evaluate::StructureConstructor
>(&constantExpr
.u
))
778 return Fortran::lower::genInlinedStructureCtorLit(converter
, loc
,
780 fir::emitFatalError(loc
, "not a constant derived type expression");
783 template <Fortran::common::TypeCategory TC
, int KIND
>
784 static fir::ExtendedValue
genConstantValue(
785 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
786 const Fortran::evaluate::Expr
<Fortran::evaluate::Type
<TC
, KIND
>>
788 using T
= Fortran::evaluate::Type
<TC
, KIND
>;
789 if (const auto *constant
=
790 std::get_if
<Fortran::evaluate::Constant
<T
>>(&constantExpr
.u
))
791 return Fortran::lower::convertConstant(converter
, loc
, *constant
,
793 fir::emitFatalError(loc
, "not an evaluate::Constant<T>");
796 static fir::ExtendedValue
797 genConstantValue(Fortran::lower::AbstractConverter
&converter
,
799 const Fortran::lower::SomeExpr
&constantExpr
) {
800 return Fortran::common::visit(
801 [&](const auto &x
) -> fir::ExtendedValue
{
802 using T
= std::decay_t
<decltype(x
)>;
803 if constexpr (Fortran::common::HasMember
<
804 T
, Fortran::lower::CategoryExpression
>) {
805 if constexpr (T::Result::category
==
806 Fortran::common::TypeCategory::Derived
) {
807 return genConstantValue(converter
, loc
, x
);
809 return Fortran::common::visit(
810 [&](const auto &preciseKind
) {
811 return genConstantValue(converter
, loc
, preciseKind
);
816 fir::emitFatalError(loc
, "unexpected typeless constant value");
822 fir::ExtendedValue
Fortran::lower::genInlinedStructureCtorLit(
823 Fortran::lower::AbstractConverter
&converter
, mlir::Location loc
,
824 const Fortran::evaluate::StructureConstructor
&ctor
) {
825 mlir::Type type
= Fortran::lower::translateDerivedTypeToFIRType(
826 converter
, ctor
.derivedTypeSpec());
827 return genInlinedStructureCtorLitImpl(converter
, loc
, ctor
, type
);
830 using namespace Fortran::evaluate
;
831 FOR_EACH_SPECIFIC_TYPE(template class Fortran::lower::ConstantBuilder
, )