xref: /llvm-project/flang/lib/Lower/ConvertConstant.cpp (revision fc97d2e68b03bc2979395e84b645e5b3ba35aecd)
1af91b193SJean Perier //===-- ConvertConstant.cpp -----------------------------------------------===//
2af91b193SJean Perier //
3af91b193SJean Perier // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af91b193SJean Perier // See https://llvm.org/LICENSE.txt for license information.
5af91b193SJean Perier // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af91b193SJean Perier //
7af91b193SJean Perier //===----------------------------------------------------------------------===//
8af91b193SJean Perier //
9af91b193SJean Perier // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10af91b193SJean Perier //
11af91b193SJean Perier //===----------------------------------------------------------------------===//
12af91b193SJean Perier 
13af91b193SJean Perier #include "flang/Lower/ConvertConstant.h"
14af91b193SJean Perier #include "flang/Evaluate/expression.h"
152d9b4a50SJean Perier #include "flang/Lower/AbstractConverter.h"
162d9b4a50SJean Perier #include "flang/Lower/BuiltinModules.h"
17e84a985cSDaniel Chen #include "flang/Lower/ConvertExprToHLFIR.h"
18af91b193SJean Perier #include "flang/Lower/ConvertType.h"
192d9b4a50SJean Perier #include "flang/Lower/ConvertVariable.h"
20af91b193SJean Perier #include "flang/Lower/Mangler.h"
21e84a985cSDaniel Chen #include "flang/Lower/StatementContext.h"
22e84a985cSDaniel Chen #include "flang/Lower/SymbolMap.h"
23af91b193SJean Perier #include "flang/Optimizer/Builder/Complex.h"
243d3c63daSKelvin Li #include "flang/Optimizer/Builder/MutableBox.h"
25af91b193SJean Perier #include "flang/Optimizer/Builder/Todo.h"
26af91b193SJean Perier 
27556483feSLeandro Lupori #include <algorithm>
28556483feSLeandro Lupori 
29af91b193SJean Perier /// Convert string, \p s, to an APFloat value. Recognize and handle Inf and
30af91b193SJean Perier /// NaN strings as well. \p s is assumed to not contain any spaces.
31af91b193SJean Perier static llvm::APFloat consAPFloat(const llvm::fltSemantics &fsem,
32af91b193SJean Perier                                  llvm::StringRef s) {
33af91b193SJean Perier   assert(!s.contains(' '));
34af91b193SJean Perier   if (s.compare_insensitive("-inf") == 0)
35af91b193SJean Perier     return llvm::APFloat::getInf(fsem, /*negative=*/true);
36af91b193SJean Perier   if (s.compare_insensitive("inf") == 0 || s.compare_insensitive("+inf") == 0)
37af91b193SJean Perier     return llvm::APFloat::getInf(fsem);
38af91b193SJean Perier   // TODO: Add support for quiet and signaling NaNs.
39af91b193SJean Perier   if (s.compare_insensitive("-nan") == 0)
40af91b193SJean Perier     return llvm::APFloat::getNaN(fsem, /*negative=*/true);
41af91b193SJean Perier   if (s.compare_insensitive("nan") == 0 || s.compare_insensitive("+nan") == 0)
42af91b193SJean Perier     return llvm::APFloat::getNaN(fsem);
43af91b193SJean Perier   return {fsem, s};
44af91b193SJean Perier }
45af91b193SJean Perier 
46af91b193SJean Perier //===----------------------------------------------------------------------===//
47af91b193SJean Perier // Fortran::lower::tryCreatingDenseGlobal implementation
48af91b193SJean Perier //===----------------------------------------------------------------------===//
49af91b193SJean Perier 
50af91b193SJean Perier /// Generate an mlir attribute from a literal value
51af91b193SJean Perier template <Fortran::common::TypeCategory TC, int KIND>
52af91b193SJean Perier static mlir::Attribute convertToAttribute(
53af91b193SJean Perier     fir::FirOpBuilder &builder,
54af91b193SJean Perier     const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> &value,
55af91b193SJean Perier     mlir::Type type) {
56af91b193SJean Perier   if constexpr (TC == Fortran::common::TypeCategory::Integer) {
57556483feSLeandro Lupori     if constexpr (KIND <= 8)
58af91b193SJean Perier       return builder.getIntegerAttr(type, value.ToInt64());
59556483feSLeandro Lupori     else {
60556483feSLeandro Lupori       static_assert(KIND <= 16, "integers with KIND > 16 are not supported");
61556483feSLeandro Lupori       return builder.getIntegerAttr(
62556483feSLeandro Lupori           type, llvm::APInt(KIND * 8,
63556483feSLeandro Lupori                             {value.ToUInt64(), value.SHIFTR(64).ToUInt64()}));
64556483feSLeandro Lupori     }
65af91b193SJean Perier   } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
66af91b193SJean Perier     return builder.getIntegerAttr(type, value.IsTrue());
67af91b193SJean Perier   } else {
68c8517f17SLeandro Lupori     auto getFloatAttr = [&](const auto &value, mlir::Type type) {
69af91b193SJean Perier       std::string str = value.DumpHexadecimal();
70af91b193SJean Perier       auto floatVal =
71af91b193SJean Perier           consAPFloat(builder.getKindMap().getFloatSemantics(KIND), str);
72af91b193SJean Perier       return builder.getFloatAttr(type, floatVal);
73c8517f17SLeandro Lupori     };
74c8517f17SLeandro Lupori 
75c8517f17SLeandro Lupori     if constexpr (TC == Fortran::common::TypeCategory::Real) {
76c8517f17SLeandro Lupori       return getFloatAttr(value, type);
77c8517f17SLeandro Lupori     } else {
78c8517f17SLeandro Lupori       static_assert(TC == Fortran::common::TypeCategory::Complex,
79c8517f17SLeandro Lupori                     "type values cannot be converted to attributes");
80c8517f17SLeandro Lupori       mlir::Type eleTy = mlir::cast<mlir::ComplexType>(type).getElementType();
81c8517f17SLeandro Lupori       llvm::SmallVector<mlir::Attribute, 2> attrs = {
82c8517f17SLeandro Lupori           getFloatAttr(value.REAL(), eleTy),
83c8517f17SLeandro Lupori           getFloatAttr(value.AIMAG(), eleTy)};
84c8517f17SLeandro Lupori       return builder.getArrayAttr(attrs);
85c8517f17SLeandro Lupori     }
86af91b193SJean Perier   }
87af91b193SJean Perier   return {};
88af91b193SJean Perier }
89af91b193SJean Perier 
90af91b193SJean Perier namespace {
91af91b193SJean Perier /// Helper class to lower an array constant to a global with an MLIR dense
92af91b193SJean Perier /// attribute.
93af91b193SJean Perier ///
94c8517f17SLeandro Lupori /// If we have an array of integer, real, complex, or logical, then we can
95af91b193SJean Perier /// create a global array with the dense attribute.
96af91b193SJean Perier ///
97c8517f17SLeandro Lupori /// The mlir tensor type can only handle integer, real, complex, or logical.
98c8517f17SLeandro Lupori /// It does not currently support nested structures.
99af91b193SJean Perier class DenseGlobalBuilder {
100af91b193SJean Perier public:
101af91b193SJean Perier   static fir::GlobalOp tryCreating(fir::FirOpBuilder &builder,
102af91b193SJean Perier                                    mlir::Location loc, mlir::Type symTy,
103af91b193SJean Perier                                    llvm::StringRef globalName,
104af91b193SJean Perier                                    mlir::StringAttr linkage, bool isConst,
1053a47d948SValentin Clement (バレンタイン クレメン)                                    const Fortran::lower::SomeExpr &initExpr,
1063a47d948SValentin Clement (バレンタイン クレメン)                                    cuf::DataAttributeAttr dataAttr) {
107af91b193SJean Perier     DenseGlobalBuilder globalBuilder;
10877d8cfb3SAlexander Shaposhnikov     Fortran::common::visit(
109af91b193SJean Perier         Fortran::common::visitors{
110af91b193SJean Perier             [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeLogical> &
111af91b193SJean Perier                     x) { globalBuilder.tryConvertingToAttributes(builder, x); },
112af91b193SJean Perier             [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeInteger> &
113af91b193SJean Perier                     x) { globalBuilder.tryConvertingToAttributes(builder, x); },
114af91b193SJean Perier             [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeReal> &x) {
115af91b193SJean Perier               globalBuilder.tryConvertingToAttributes(builder, x);
116af91b193SJean Perier             },
117c8517f17SLeandro Lupori             [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeComplex> &
118c8517f17SLeandro Lupori                     x) { globalBuilder.tryConvertingToAttributes(builder, x); },
119af91b193SJean Perier             [](const auto &) {},
120af91b193SJean Perier         },
121af91b193SJean Perier         initExpr.u);
122af91b193SJean Perier     return globalBuilder.tryCreatingGlobal(builder, loc, symTy, globalName,
1233a47d948SValentin Clement (バレンタイン クレメン)                                            linkage, isConst, dataAttr);
124af91b193SJean Perier   }
125af91b193SJean Perier 
126af91b193SJean Perier   template <Fortran::common::TypeCategory TC, int KIND>
127af91b193SJean Perier   static fir::GlobalOp tryCreating(
128af91b193SJean Perier       fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type symTy,
129af91b193SJean Perier       llvm::StringRef globalName, mlir::StringAttr linkage, bool isConst,
130af91b193SJean Perier       const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
1313a47d948SValentin Clement (バレンタイン クレメン)           &constant,
1323a47d948SValentin Clement (バレンタイン クレメン)       cuf::DataAttributeAttr dataAttr) {
133af91b193SJean Perier     DenseGlobalBuilder globalBuilder;
134af91b193SJean Perier     globalBuilder.tryConvertingToAttributes(builder, constant);
135af91b193SJean Perier     return globalBuilder.tryCreatingGlobal(builder, loc, symTy, globalName,
1363a47d948SValentin Clement (バレンタイン クレメン)                                            linkage, isConst, dataAttr);
137af91b193SJean Perier   }
138af91b193SJean Perier 
139af91b193SJean Perier private:
140af91b193SJean Perier   DenseGlobalBuilder() = default;
141af91b193SJean Perier 
142af91b193SJean Perier   /// Try converting an evaluate::Constant to a list of MLIR attributes.
143af91b193SJean Perier   template <Fortran::common::TypeCategory TC, int KIND>
144af91b193SJean Perier   void tryConvertingToAttributes(
145af91b193SJean Perier       fir::FirOpBuilder &builder,
146af91b193SJean Perier       const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
147af91b193SJean Perier           &constant) {
148af91b193SJean Perier     static_assert(TC != Fortran::common::TypeCategory::Character,
149af91b193SJean Perier                   "must be numerical or logical");
150af91b193SJean Perier     auto attrTc = TC == Fortran::common::TypeCategory::Logical
151af91b193SJean Perier                       ? Fortran::common::TypeCategory::Integer
152af91b193SJean Perier                       : TC;
1539a417395SKazu Hirata     attributeElementType = Fortran::lower::getFIRType(
1549a417395SKazu Hirata         builder.getContext(), attrTc, KIND, std::nullopt);
155af91b193SJean Perier     for (auto element : constant.values())
156af91b193SJean Perier       attributes.push_back(
157af91b193SJean Perier           convertToAttribute<TC, KIND>(builder, element, attributeElementType));
158af91b193SJean Perier   }
159af91b193SJean Perier 
160af91b193SJean Perier   /// Try converting an evaluate::Expr to a list of MLIR attributes.
161af91b193SJean Perier   template <typename SomeCat>
162af91b193SJean Perier   void tryConvertingToAttributes(fir::FirOpBuilder &builder,
163af91b193SJean Perier                                  const Fortran::evaluate::Expr<SomeCat> &expr) {
16477d8cfb3SAlexander Shaposhnikov     Fortran::common::visit(
165af91b193SJean Perier         [&](const auto &x) {
166af91b193SJean Perier           using TR = Fortran::evaluate::ResultType<decltype(x)>;
167af91b193SJean Perier           if (const auto *constant =
168af91b193SJean Perier                   std::get_if<Fortran::evaluate::Constant<TR>>(&x.u))
169af91b193SJean Perier             tryConvertingToAttributes<TR::category, TR::kind>(builder,
170af91b193SJean Perier                                                               *constant);
171af91b193SJean Perier         },
172af91b193SJean Perier         expr.u);
173af91b193SJean Perier   }
174af91b193SJean Perier 
175af91b193SJean Perier   /// Create a fir::Global if MLIR attributes have been successfully created by
176af91b193SJean Perier   /// tryConvertingToAttributes.
177af91b193SJean Perier   fir::GlobalOp tryCreatingGlobal(fir::FirOpBuilder &builder,
178af91b193SJean Perier                                   mlir::Location loc, mlir::Type symTy,
179af91b193SJean Perier                                   llvm::StringRef globalName,
1803a47d948SValentin Clement (バレンタイン クレメン)                                   mlir::StringAttr linkage, bool isConst,
1813a47d948SValentin Clement (バレンタイン クレメン)                                   cuf::DataAttributeAttr dataAttr) const {
182556483feSLeandro Lupori     // Not a "trivial" intrinsic constant array, or empty array.
183af91b193SJean Perier     if (!attributeElementType || attributes.empty())
184af91b193SJean Perier       return {};
185af91b193SJean Perier 
186fac349a1SChristian Sigg     assert(mlir::isa<fir::SequenceType>(symTy) && "expecting an array global");
187fac349a1SChristian Sigg     auto arrTy = mlir::cast<fir::SequenceType>(symTy);
188556483feSLeandro Lupori     llvm::SmallVector<int64_t> tensorShape(arrTy.getShape());
189556483feSLeandro Lupori     std::reverse(tensorShape.begin(), tensorShape.end());
190af91b193SJean Perier     auto tensorTy =
191556483feSLeandro Lupori         mlir::RankedTensorType::get(tensorShape, attributeElementType);
192af91b193SJean Perier     auto init = mlir::DenseElementsAttr::get(tensorTy, attributes);
1933a47d948SValentin Clement (バレンタイン クレメン)     return builder.createGlobal(loc, symTy, globalName, linkage, init, isConst,
1943a47d948SValentin Clement (バレンタイン クレメン)                                 /*isTarget=*/false, dataAttr);
195af91b193SJean Perier   }
196af91b193SJean Perier 
197af91b193SJean Perier   llvm::SmallVector<mlir::Attribute> attributes;
198af91b193SJean Perier   mlir::Type attributeElementType;
199af91b193SJean Perier };
200af91b193SJean Perier } // namespace
201af91b193SJean Perier 
202af91b193SJean Perier fir::GlobalOp Fortran::lower::tryCreatingDenseGlobal(
203af91b193SJean Perier     fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type symTy,
204af91b193SJean Perier     llvm::StringRef globalName, mlir::StringAttr linkage, bool isConst,
2053a47d948SValentin Clement (バレンタイン クレメン)     const Fortran::lower::SomeExpr &initExpr, cuf::DataAttributeAttr dataAttr) {
206af91b193SJean Perier   return DenseGlobalBuilder::tryCreating(builder, loc, symTy, globalName,
2073a47d948SValentin Clement (バレンタイン クレメン)                                          linkage, isConst, initExpr, dataAttr);
208af91b193SJean Perier }
209af91b193SJean Perier 
210af91b193SJean Perier //===----------------------------------------------------------------------===//
2112d9b4a50SJean Perier // Fortran::lower::convertConstant
2122d9b4a50SJean Perier // Lower a constant to a fir::ExtendedValue.
213af91b193SJean Perier //===----------------------------------------------------------------------===//
214af91b193SJean Perier 
215af91b193SJean Perier /// Generate a real constant with a value `value`.
216af91b193SJean Perier template <int KIND>
217af91b193SJean Perier static mlir::Value genRealConstant(fir::FirOpBuilder &builder,
218af91b193SJean Perier                                    mlir::Location loc,
219af91b193SJean Perier                                    const llvm::APFloat &value) {
220af91b193SJean Perier   mlir::Type fltTy = Fortran::lower::convertReal(builder.getContext(), KIND);
221af91b193SJean Perier   return builder.createRealConstant(loc, fltTy, value);
222af91b193SJean Perier }
223af91b193SJean Perier 
224af91b193SJean Perier /// Convert a scalar literal constant to IR.
225af91b193SJean Perier template <Fortran::common::TypeCategory TC, int KIND>
226af91b193SJean Perier static mlir::Value genScalarLit(
227af91b193SJean Perier     fir::FirOpBuilder &builder, mlir::Location loc,
228af91b193SJean Perier     const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> &value) {
229*fc97d2e6SPeter Klausler   if constexpr (TC == Fortran::common::TypeCategory::Integer ||
230*fc97d2e6SPeter Klausler                 TC == Fortran::common::TypeCategory::Unsigned) {
231*fc97d2e6SPeter Klausler     // MLIR requires constants to be signless
232*fc97d2e6SPeter Klausler     mlir::Type ty = Fortran::lower::getFIRType(
233*fc97d2e6SPeter Klausler         builder.getContext(), Fortran::common::TypeCategory::Integer, KIND,
2349a417395SKazu Hirata         std::nullopt);
235af91b193SJean Perier     if (KIND == 16) {
236*fc97d2e6SPeter Klausler       auto bigInt = llvm::APInt(ty.getIntOrFloatBitWidth(),
237*fc97d2e6SPeter Klausler                                 TC == Fortran::common::TypeCategory::Unsigned
238*fc97d2e6SPeter Klausler                                     ? value.UnsignedDecimal()
239*fc97d2e6SPeter Klausler                                     : value.SignedDecimal(),
240*fc97d2e6SPeter Klausler                                 10);
241af91b193SJean Perier       return builder.create<mlir::arith::ConstantOp>(
242af91b193SJean Perier           loc, ty, mlir::IntegerAttr::get(ty, bigInt));
243af91b193SJean Perier     }
244af91b193SJean Perier     return builder.createIntegerConstant(loc, ty, value.ToInt64());
245af91b193SJean Perier   } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
246af91b193SJean Perier     return builder.createBool(loc, value.IsTrue());
247af91b193SJean Perier   } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
248af91b193SJean Perier     std::string str = value.DumpHexadecimal();
249af91b193SJean Perier     if constexpr (KIND == 2) {
250af91b193SJean Perier       auto floatVal = consAPFloat(llvm::APFloatBase::IEEEhalf(), str);
251af91b193SJean Perier       return genRealConstant<KIND>(builder, loc, floatVal);
252af91b193SJean Perier     } else if constexpr (KIND == 3) {
253af91b193SJean Perier       auto floatVal = consAPFloat(llvm::APFloatBase::BFloat(), str);
254af91b193SJean Perier       return genRealConstant<KIND>(builder, loc, floatVal);
255af91b193SJean Perier     } else if constexpr (KIND == 4) {
256af91b193SJean Perier       auto floatVal = consAPFloat(llvm::APFloatBase::IEEEsingle(), str);
257af91b193SJean Perier       return genRealConstant<KIND>(builder, loc, floatVal);
258af91b193SJean Perier     } else if constexpr (KIND == 10) {
259af91b193SJean Perier       auto floatVal = consAPFloat(llvm::APFloatBase::x87DoubleExtended(), str);
260af91b193SJean Perier       return genRealConstant<KIND>(builder, loc, floatVal);
261af91b193SJean Perier     } else if constexpr (KIND == 16) {
262af91b193SJean Perier       auto floatVal = consAPFloat(llvm::APFloatBase::IEEEquad(), str);
263af91b193SJean Perier       return genRealConstant<KIND>(builder, loc, floatVal);
264af91b193SJean Perier     } else {
265af91b193SJean Perier       // convert everything else to double
266af91b193SJean Perier       auto floatVal = consAPFloat(llvm::APFloatBase::IEEEdouble(), str);
267af91b193SJean Perier       return genRealConstant<KIND>(builder, loc, floatVal);
268af91b193SJean Perier     }
269af91b193SJean Perier   } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
270c4204c0bSjeanPerier     mlir::Value real = genScalarLit<Fortran::common::TypeCategory::Real, KIND>(
271c4204c0bSjeanPerier         builder, loc, value.REAL());
272c4204c0bSjeanPerier     mlir::Value imag = genScalarLit<Fortran::common::TypeCategory::Real, KIND>(
273c4204c0bSjeanPerier         builder, loc, value.AIMAG());
274c4204c0bSjeanPerier     return fir::factory::Complex{builder, loc}.createComplex(real, imag);
275af91b193SJean Perier   } else /*constexpr*/ {
276af91b193SJean Perier     llvm_unreachable("unhandled constant");
277af91b193SJean Perier   }
278af91b193SJean Perier }
279af91b193SJean Perier 
280af91b193SJean Perier /// Create fir::string_lit from a scalar character constant.
281af91b193SJean Perier template <int KIND>
282af91b193SJean Perier static fir::StringLitOp
283af91b193SJean Perier createStringLitOp(fir::FirOpBuilder &builder, mlir::Location loc,
284af91b193SJean Perier                   const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
285af91b193SJean Perier                       Fortran::common::TypeCategory::Character, KIND>> &value,
286af91b193SJean Perier                   [[maybe_unused]] int64_t len) {
287af91b193SJean Perier   if constexpr (KIND == 1) {
288af91b193SJean Perier     assert(value.size() == static_cast<std::uint64_t>(len));
289af91b193SJean Perier     return builder.createStringLitOp(loc, value);
290af91b193SJean Perier   } else {
291af91b193SJean Perier     using ET = typename std::decay_t<decltype(value)>::value_type;
292af91b193SJean Perier     fir::CharacterType type =
293af91b193SJean Perier         fir::CharacterType::get(builder.getContext(), KIND, len);
294af91b193SJean Perier     mlir::MLIRContext *context = builder.getContext();
295af91b193SJean Perier     std::int64_t size = static_cast<std::int64_t>(value.size());
296af91b193SJean Perier     mlir::ShapedType shape = mlir::RankedTensorType::get(
297af91b193SJean Perier         llvm::ArrayRef<std::int64_t>{size},
298af91b193SJean Perier         mlir::IntegerType::get(builder.getContext(), sizeof(ET) * 8));
299af91b193SJean Perier     auto denseAttr = mlir::DenseElementsAttr::get(
300af91b193SJean Perier         shape, llvm::ArrayRef<ET>{value.data(), value.size()});
301af91b193SJean Perier     auto denseTag = mlir::StringAttr::get(context, fir::StringLitOp::xlist());
302af91b193SJean Perier     mlir::NamedAttribute dataAttr(denseTag, denseAttr);
303af91b193SJean Perier     auto sizeTag = mlir::StringAttr::get(context, fir::StringLitOp::size());
304af91b193SJean Perier     mlir::NamedAttribute sizeAttr(sizeTag, builder.getI64IntegerAttr(len));
305af91b193SJean Perier     llvm::SmallVector<mlir::NamedAttribute> attrs = {dataAttr, sizeAttr};
306af91b193SJean Perier     return builder.create<fir::StringLitOp>(
3079a417395SKazu Hirata         loc, llvm::ArrayRef<mlir::Type>{type}, std::nullopt, attrs);
308af91b193SJean Perier   }
309af91b193SJean Perier }
310af91b193SJean Perier 
311af91b193SJean Perier /// Convert a scalar literal CHARACTER to IR.
312af91b193SJean Perier template <int KIND>
313af91b193SJean Perier static mlir::Value
314af91b193SJean Perier genScalarLit(fir::FirOpBuilder &builder, mlir::Location loc,
315af91b193SJean Perier              const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
316af91b193SJean Perier                  Fortran::common::TypeCategory::Character, KIND>> &value,
317af91b193SJean Perier              int64_t len, bool outlineInReadOnlyMemory) {
318af91b193SJean Perier   // When in an initializer context, construct the literal op itself and do
319af91b193SJean Perier   // not construct another constant object in rodata.
320af91b193SJean Perier   if (!outlineInReadOnlyMemory)
321af91b193SJean Perier     return createStringLitOp<KIND>(builder, loc, value, len);
322af91b193SJean Perier 
323af91b193SJean Perier   // Otherwise, the string is in a plain old expression so "outline" the value
324af91b193SJean Perier   // in read only data by hash consing it to a constant literal object.
325af91b193SJean Perier 
326af91b193SJean Perier   // ASCII global constants are created using an mlir string attribute.
327af91b193SJean Perier   if constexpr (KIND == 1) {
328af91b193SJean Perier     return fir::getBase(fir::factory::createStringLiteral(builder, loc, value));
329af91b193SJean Perier   }
330af91b193SJean Perier 
331af91b193SJean Perier   auto size = builder.getKindMap().getCharacterBitsize(KIND) / 8 * value.size();
332af91b193SJean Perier   llvm::StringRef strVal(reinterpret_cast<const char *>(value.c_str()), size);
3337ad38259SjeanPerier   std::string globalName = fir::factory::uniqueCGIdent(
3347ad38259SjeanPerier       KIND == 1 ? "cl"s : "cl"s + std::to_string(KIND), strVal);
335af91b193SJean Perier   fir::GlobalOp global = builder.getNamedGlobal(globalName);
336af91b193SJean Perier   fir::CharacterType type =
337af91b193SJean Perier       fir::CharacterType::get(builder.getContext(), KIND, len);
338af91b193SJean Perier   if (!global)
339af91b193SJean Perier     global = builder.createGlobalConstant(
340af91b193SJean Perier         loc, type, globalName,
341af91b193SJean Perier         [&](fir::FirOpBuilder &builder) {
342af91b193SJean Perier           fir::StringLitOp str =
343af91b193SJean Perier               createStringLitOp<KIND>(builder, loc, value, len);
344af91b193SJean Perier           builder.create<fir::HasValueOp>(loc, str);
345af91b193SJean Perier         },
346af91b193SJean Perier         builder.createLinkOnceLinkage());
347af91b193SJean Perier   return builder.create<fir::AddrOfOp>(loc, global.resultType(),
348af91b193SJean Perier                                        global.getSymbol());
349af91b193SJean Perier }
350af91b193SJean Perier 
3512d9b4a50SJean Perier // Helper to generate StructureConstructor component values.
3522d9b4a50SJean Perier static fir::ExtendedValue
3532d9b4a50SJean Perier genConstantValue(Fortran::lower::AbstractConverter &converter,
3542d9b4a50SJean Perier                  mlir::Location loc,
3552d9b4a50SJean Perier                  const Fortran::lower::SomeExpr &constantExpr);
3562d9b4a50SJean Perier 
357e45f6e93SjeanPerier static mlir::Value genStructureComponentInit(
3582d9b4a50SJean Perier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
359e45f6e93SjeanPerier     const Fortran::semantics::Symbol &sym, const Fortran::lower::SomeExpr &expr,
360e45f6e93SjeanPerier     mlir::Value res) {
3612d9b4a50SJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
362e45f6e93SjeanPerier   fir::RecordType recTy = mlir::cast<fir::RecordType>(res.getType());
36399a54b83SjeanPerier   std::string name = converter.getRecordTypeFieldName(sym);
3642d9b4a50SJean Perier   mlir::Type componentTy = recTy.getType(name);
365e45f6e93SjeanPerier   auto fieldTy = fir::FieldType::get(recTy.getContext());
36699a54b83SjeanPerier   assert(componentTy && "failed to retrieve component");
3672d9b4a50SJean Perier   // FIXME: type parameters must come from the derived-type-spec
3682d9b4a50SJean Perier   auto field = builder.create<fir::FieldIndexOp>(
369e45f6e93SjeanPerier       loc, fieldTy, name, recTy,
3702d9b4a50SJean Perier       /*typeParams=*/mlir::ValueRange{} /*TODO*/);
3712d9b4a50SJean Perier 
3723d3c63daSKelvin Li   if (Fortran::semantics::IsAllocatable(sym)) {
3733d3c63daSKelvin Li     if (!Fortran::evaluate::IsNullPointer(expr)) {
3743d3c63daSKelvin Li       fir::emitFatalError(loc, "constant structure constructor with an "
3753d3c63daSKelvin Li                                "allocatable component value that is not NULL");
3763d3c63daSKelvin Li     } else {
3773d3c63daSKelvin Li       // Handle NULL() initialization
3783d3c63daSKelvin Li       mlir::Value componentValue{fir::factory::createUnallocatedBox(
3793d3c63daSKelvin Li           builder, loc, componentTy, std::nullopt)};
3803d3c63daSKelvin Li       componentValue = builder.createConvert(loc, componentTy, componentValue);
3813d3c63daSKelvin Li 
3823d3c63daSKelvin Li       return builder.create<fir::InsertValueOp>(
3833d3c63daSKelvin Li           loc, recTy, res, componentValue,
3843d3c63daSKelvin Li           builder.getArrayAttr(field.getAttributes()));
3853d3c63daSKelvin Li     }
3863d3c63daSKelvin Li   }
3872d9b4a50SJean Perier 
3882d9b4a50SJean Perier   if (Fortran::semantics::IsPointer(sym)) {
389e84a985cSDaniel Chen     mlir::Value initialTarget;
390e84a985cSDaniel Chen     if (Fortran::semantics::IsProcedure(sym)) {
391e84a985cSDaniel Chen       if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr))
392e84a985cSDaniel Chen         initialTarget =
393e84a985cSDaniel Chen             fir::factory::createNullBoxProc(builder, loc, componentTy);
394e84a985cSDaniel Chen       else {
395e84a985cSDaniel Chen         Fortran::lower::SymMap globalOpSymMap;
396e84a985cSDaniel Chen         Fortran::lower::StatementContext stmtCtx;
397e84a985cSDaniel Chen         auto box{getBase(Fortran::lower::convertExprToAddress(
398e84a985cSDaniel Chen             loc, converter, expr, globalOpSymMap, stmtCtx))};
399e84a985cSDaniel Chen         initialTarget = builder.createConvert(loc, componentTy, box);
400e84a985cSDaniel Chen       }
401e84a985cSDaniel Chen     } else
402e84a985cSDaniel Chen       initialTarget = Fortran::lower::genInitialDataTarget(converter, loc,
403e84a985cSDaniel Chen                                                            componentTy, expr);
4042d9b4a50SJean Perier     res = builder.create<fir::InsertValueOp>(
4052d9b4a50SJean Perier         loc, recTy, res, initialTarget,
4062d9b4a50SJean Perier         builder.getArrayAttr(field.getAttributes()));
407e45f6e93SjeanPerier     return res;
4082d9b4a50SJean Perier   }
4092d9b4a50SJean Perier 
4102d9b4a50SJean Perier   if (Fortran::lower::isDerivedTypeWithLenParameters(sym))
4112d9b4a50SJean Perier     TODO(loc, "component with length parameters in structure constructor");
4122d9b4a50SJean Perier 
413fb730e2bSSlava Zakharin   // Special handling for scalar c_ptr/c_funptr constants. The array constant
414fb730e2bSSlava Zakharin   // must fall through to genConstantValue() below.
415e45f6e93SjeanPerier   if (Fortran::semantics::IsBuiltinCPtr(sym) && sym.Rank() == 0 &&
416e45f6e93SjeanPerier       (Fortran::evaluate::GetLastSymbol(expr) ||
417e45f6e93SjeanPerier        Fortran::evaluate::IsNullPointer(expr))) {
418e91a4becSjeanPerier     // Builtin c_ptr and c_funptr have special handling because designators
419e91a4becSjeanPerier     // and NULL() are handled as initial values for them as an extension
420e91a4becSjeanPerier     // (otherwise only c_ptr_null/c_funptr_null are allowed and these are
421e91a4becSjeanPerier     // replaced by structure constructors by semantics, so GetLastSymbol
422e91a4becSjeanPerier     // returns nothing).
423e91a4becSjeanPerier 
424e91a4becSjeanPerier     // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or
425e91a4becSjeanPerier     // NULL()) that must be inserted into an intermediate cptr record value's
426e91a4becSjeanPerier     // address field, which ought to be an intptr_t on the target.
427e45f6e93SjeanPerier     mlir::Value addr = fir::getBase(
428e45f6e93SjeanPerier         Fortran::lower::genExtAddrInInitializer(converter, loc, expr));
429fac349a1SChristian Sigg     if (mlir::isa<fir::BoxProcType>(addr.getType()))
430a98b031eSJean Perier       addr = builder.create<fir::BoxAddrOp>(loc, addr);
4312d9b4a50SJean Perier     assert((fir::isa_ref_type(addr.getType()) ||
432fac349a1SChristian Sigg             mlir::isa<mlir::FunctionType>(addr.getType())) &&
4332d9b4a50SJean Perier            "expect reference type for address field");
4342d9b4a50SJean Perier     assert(fir::isa_derived(componentTy) &&
4352d9b4a50SJean Perier            "expect C_PTR, C_FUNPTR to be a record");
436fac349a1SChristian Sigg     auto cPtrRecTy = mlir::cast<fir::RecordType>(componentTy);
4372d9b4a50SJean Perier     llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName;
4382d9b4a50SJean Perier     mlir::Type addrFieldTy = cPtrRecTy.getType(addrFieldName);
4392d9b4a50SJean Perier     auto addrField = builder.create<fir::FieldIndexOp>(
4402d9b4a50SJean Perier         loc, fieldTy, addrFieldName, componentTy,
4412d9b4a50SJean Perier         /*typeParams=*/mlir::ValueRange{});
4422d9b4a50SJean Perier     mlir::Value castAddr = builder.createConvert(loc, addrFieldTy, addr);
4432d9b4a50SJean Perier     auto undef = builder.create<fir::UndefOp>(loc, componentTy);
4442d9b4a50SJean Perier     addr = builder.create<fir::InsertValueOp>(
4452d9b4a50SJean Perier         loc, componentTy, undef, castAddr,
4462d9b4a50SJean Perier         builder.getArrayAttr(addrField.getAttributes()));
4472d9b4a50SJean Perier     res = builder.create<fir::InsertValueOp>(
4482d9b4a50SJean Perier         loc, recTy, res, addr, builder.getArrayAttr(field.getAttributes()));
449e45f6e93SjeanPerier     return res;
4502d9b4a50SJean Perier   }
4512d9b4a50SJean Perier 
452e45f6e93SjeanPerier   mlir::Value val = fir::getBase(genConstantValue(converter, loc, expr));
4532d9b4a50SJean Perier   assert(!fir::isa_ref_type(val.getType()) && "expecting a constant value");
4542d9b4a50SJean Perier   mlir::Value castVal = builder.createConvert(loc, componentTy, val);
4552d9b4a50SJean Perier   res = builder.create<fir::InsertValueOp>(
4562d9b4a50SJean Perier       loc, recTy, res, castVal, builder.getArrayAttr(field.getAttributes()));
457e45f6e93SjeanPerier   return res;
4582d9b4a50SJean Perier }
459e45f6e93SjeanPerier 
460e45f6e93SjeanPerier // Generate a StructureConstructor inlined (returns raw fir.type<T> value,
461e45f6e93SjeanPerier // not the address of a global constant).
462e45f6e93SjeanPerier static mlir::Value genInlinedStructureCtorLitImpl(
463e45f6e93SjeanPerier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
464e45f6e93SjeanPerier     const Fortran::evaluate::StructureConstructor &ctor, mlir::Type type) {
465e45f6e93SjeanPerier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
466fac349a1SChristian Sigg   auto recTy = mlir::cast<fir::RecordType>(type);
467e45f6e93SjeanPerier 
468e45f6e93SjeanPerier   if (!converter.getLoweringOptions().getLowerToHighLevelFIR()) {
469e45f6e93SjeanPerier     mlir::Value res = builder.create<fir::UndefOp>(loc, recTy);
470e45f6e93SjeanPerier     for (const auto &[sym, expr] : ctor.values()) {
471e45f6e93SjeanPerier       // Parent components need more work because they do not appear in the
472e45f6e93SjeanPerier       // fir.rec type.
473e45f6e93SjeanPerier       if (sym->test(Fortran::semantics::Symbol::Flag::ParentComp))
474e45f6e93SjeanPerier         TODO(loc, "parent component in structure constructor");
475e45f6e93SjeanPerier       res = genStructureComponentInit(converter, loc, sym, expr.value(), res);
476e45f6e93SjeanPerier     }
477e45f6e93SjeanPerier     return res;
478e45f6e93SjeanPerier   }
479e45f6e93SjeanPerier 
480e45f6e93SjeanPerier   auto fieldTy = fir::FieldType::get(recTy.getContext());
481e45f6e93SjeanPerier   mlir::Value res{};
482e45f6e93SjeanPerier   // When the first structure component values belong to some parent type PT
483e45f6e93SjeanPerier   // and the next values belong to a type extension ET, a new undef for ET must
484e45f6e93SjeanPerier   // be created and the previous PT value inserted into it. There may
485e45f6e93SjeanPerier   // be empty parent types in between ET and PT, hence the list and while loop.
486e45f6e93SjeanPerier   auto insertParentValueIntoExtension = [&](mlir::Type typeExtension) {
487e45f6e93SjeanPerier     assert(res && "res must be set");
488e45f6e93SjeanPerier     llvm::SmallVector<mlir::Type> parentTypes = {typeExtension};
489e45f6e93SjeanPerier     while (true) {
490e45f6e93SjeanPerier       fir::RecordType last = mlir::cast<fir::RecordType>(parentTypes.back());
491e45f6e93SjeanPerier       mlir::Type next =
492e45f6e93SjeanPerier           last.getType(0); // parent components are first in HLFIR.
493e45f6e93SjeanPerier       if (next != res.getType())
494e45f6e93SjeanPerier         parentTypes.push_back(next);
495e45f6e93SjeanPerier       else
496e45f6e93SjeanPerier         break;
497e45f6e93SjeanPerier     }
498e45f6e93SjeanPerier     for (mlir::Type parentType : llvm::reverse(parentTypes)) {
499e45f6e93SjeanPerier       auto undef = builder.create<fir::UndefOp>(loc, parentType);
500e45f6e93SjeanPerier       fir::RecordType parentRecTy = mlir::cast<fir::RecordType>(parentType);
501e45f6e93SjeanPerier       auto field = builder.create<fir::FieldIndexOp>(
502e45f6e93SjeanPerier           loc, fieldTy, parentRecTy.getTypeList()[0].first, parentType,
503e45f6e93SjeanPerier           /*typeParams=*/mlir::ValueRange{} /*TODO*/);
504e45f6e93SjeanPerier       res = builder.create<fir::InsertValueOp>(
505e45f6e93SjeanPerier           loc, parentRecTy, undef, res,
506e45f6e93SjeanPerier           builder.getArrayAttr(field.getAttributes()));
507e45f6e93SjeanPerier     }
508e45f6e93SjeanPerier   };
509e45f6e93SjeanPerier 
510e45f6e93SjeanPerier   const Fortran::semantics::DerivedTypeSpec *curentType = nullptr;
511e45f6e93SjeanPerier   for (const auto &[sym, expr] : ctor.values()) {
512e45f6e93SjeanPerier     const Fortran::semantics::DerivedTypeSpec *componentParentType =
513e45f6e93SjeanPerier         sym->owner().derivedTypeSpec();
514e45f6e93SjeanPerier     assert(componentParentType && "failed to retrieve component parent type");
515e45f6e93SjeanPerier     if (!res) {
516e45f6e93SjeanPerier       mlir::Type parentType = converter.genType(*componentParentType);
517e45f6e93SjeanPerier       curentType = componentParentType;
518e45f6e93SjeanPerier       res = builder.create<fir::UndefOp>(loc, parentType);
519e45f6e93SjeanPerier     } else if (*componentParentType != *curentType) {
520e45f6e93SjeanPerier       mlir::Type parentType = converter.genType(*componentParentType);
521e45f6e93SjeanPerier       insertParentValueIntoExtension(parentType);
522e45f6e93SjeanPerier       curentType = componentParentType;
523e45f6e93SjeanPerier     }
524e45f6e93SjeanPerier     res = genStructureComponentInit(converter, loc, sym, expr.value(), res);
525e45f6e93SjeanPerier   }
526e45f6e93SjeanPerier 
527e45f6e93SjeanPerier   if (!res) // structure constructor for empty type.
528e45f6e93SjeanPerier     return builder.create<fir::UndefOp>(loc, recTy);
529e45f6e93SjeanPerier 
530e45f6e93SjeanPerier   // The last component may belong to a parent type.
531e45f6e93SjeanPerier   if (res.getType() != recTy)
532e45f6e93SjeanPerier     insertParentValueIntoExtension(recTy);
5332d9b4a50SJean Perier   return res;
5342d9b4a50SJean Perier }
5352d9b4a50SJean Perier 
5362d9b4a50SJean Perier static mlir::Value genScalarLit(
5372d9b4a50SJean Perier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
5382d9b4a50SJean Perier     const Fortran::evaluate::Scalar<Fortran::evaluate::SomeDerived> &value,
5392d9b4a50SJean Perier     mlir::Type eleTy, bool outlineBigConstantsInReadOnlyMemory) {
5402d9b4a50SJean Perier   if (!outlineBigConstantsInReadOnlyMemory)
5412d9b4a50SJean Perier     return genInlinedStructureCtorLitImpl(converter, loc, value, eleTy);
5422d9b4a50SJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
543be5747e5SSlava Zakharin   auto expr = std::make_unique<Fortran::lower::SomeExpr>(toEvExpr(
544be5747e5SSlava Zakharin       Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived>(value)));
545be5747e5SSlava Zakharin   llvm::StringRef globalName =
546be5747e5SSlava Zakharin       converter.getUniqueLitName(loc, std::move(expr), eleTy);
5472d9b4a50SJean Perier   fir::GlobalOp global = builder.getNamedGlobal(globalName);
5482d9b4a50SJean Perier   if (!global) {
5492d9b4a50SJean Perier     global = builder.createGlobalConstant(
5502d9b4a50SJean Perier         loc, eleTy, globalName,
5512d9b4a50SJean Perier         [&](fir::FirOpBuilder &builder) {
5522d9b4a50SJean Perier           mlir::Value result =
5532d9b4a50SJean Perier               genInlinedStructureCtorLitImpl(converter, loc, value, eleTy);
5542d9b4a50SJean Perier           builder.create<fir::HasValueOp>(loc, result);
5552d9b4a50SJean Perier         },
5562d9b4a50SJean Perier         builder.createInternalLinkage());
5572d9b4a50SJean Perier   }
5582d9b4a50SJean Perier   return builder.create<fir::AddrOfOp>(loc, global.resultType(),
5592d9b4a50SJean Perier                                        global.getSymbol());
5602d9b4a50SJean Perier }
5612d9b4a50SJean Perier 
562af91b193SJean Perier /// Create an evaluate::Constant<T> array to a fir.array<> value
563af91b193SJean Perier /// built with a chain of fir.insert or fir.insert_on_range operations.
564af91b193SJean Perier /// This is intended to be called when building the body of a fir.global.
5652d9b4a50SJean Perier template <typename T>
5662d9b4a50SJean Perier static mlir::Value
5672d9b4a50SJean Perier genInlinedArrayLit(Fortran::lower::AbstractConverter &converter,
5682d9b4a50SJean Perier                    mlir::Location loc, mlir::Type arrayTy,
5692d9b4a50SJean Perier                    const Fortran::evaluate::Constant<T> &con) {
5702d9b4a50SJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
571af91b193SJean Perier   mlir::IndexType idxTy = builder.getIndexType();
572af91b193SJean Perier   Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds();
573af91b193SJean Perier   auto createIdx = [&]() {
574af91b193SJean Perier     llvm::SmallVector<mlir::Attribute> idx;
575af91b193SJean Perier     for (size_t i = 0; i < subscripts.size(); ++i)
576af91b193SJean Perier       idx.push_back(
577af91b193SJean Perier           builder.getIntegerAttr(idxTy, subscripts[i] - con.lbounds()[i]));
578af91b193SJean Perier     return idx;
579af91b193SJean Perier   };
580af91b193SJean Perier   mlir::Value array = builder.create<fir::UndefOp>(loc, arrayTy);
581af91b193SJean Perier   if (Fortran::evaluate::GetSize(con.shape()) == 0)
582af91b193SJean Perier     return array;
5832d9b4a50SJean Perier   if constexpr (T::category == Fortran::common::TypeCategory::Character) {
584af91b193SJean Perier     do {
585af91b193SJean Perier       mlir::Value elementVal =
5862d9b4a50SJean Perier           genScalarLit<T::kind>(builder, loc, con.At(subscripts), con.LEN(),
5872d9b4a50SJean Perier                                 /*outlineInReadOnlyMemory=*/false);
5882d9b4a50SJean Perier       array = builder.create<fir::InsertValueOp>(
5892d9b4a50SJean Perier           loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx()));
5902d9b4a50SJean Perier     } while (con.IncrementSubscripts(subscripts));
5912d9b4a50SJean Perier   } else if constexpr (T::category == Fortran::common::TypeCategory::Derived) {
5922d9b4a50SJean Perier     do {
593e6a4346bSScott Manley       mlir::Type eleTy =
594e6a4346bSScott Manley           mlir::cast<fir::SequenceType>(arrayTy).getElementType();
5952d9b4a50SJean Perier       mlir::Value elementVal =
5962d9b4a50SJean Perier           genScalarLit(converter, loc, con.At(subscripts), eleTy,
597af91b193SJean Perier                        /*outlineInReadOnlyMemory=*/false);
598af91b193SJean Perier       array = builder.create<fir::InsertValueOp>(
599af91b193SJean Perier           loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx()));
600af91b193SJean Perier     } while (con.IncrementSubscripts(subscripts));
601af91b193SJean Perier   } else {
602af91b193SJean Perier     llvm::SmallVector<mlir::Attribute> rangeStartIdx;
603af91b193SJean Perier     uint64_t rangeSize = 0;
604e6a4346bSScott Manley     mlir::Type eleTy = mlir::cast<fir::SequenceType>(arrayTy).getElementType();
605af91b193SJean Perier     do {
606af91b193SJean Perier       auto getElementVal = [&]() {
6072d9b4a50SJean Perier         return builder.createConvert(loc, eleTy,
6082d9b4a50SJean Perier                                      genScalarLit<T::category, T::kind>(
6092d9b4a50SJean Perier                                          builder, loc, con.At(subscripts)));
610af91b193SJean Perier       };
611af91b193SJean Perier       Fortran::evaluate::ConstantSubscripts nextSubscripts = subscripts;
612af91b193SJean Perier       bool nextIsSame = con.IncrementSubscripts(nextSubscripts) &&
613af91b193SJean Perier                         con.At(subscripts) == con.At(nextSubscripts);
614af91b193SJean Perier       if (!rangeSize && !nextIsSame) { // single (non-range) value
615af91b193SJean Perier         array = builder.create<fir::InsertValueOp>(
616af91b193SJean Perier             loc, arrayTy, array, getElementVal(),
617af91b193SJean Perier             builder.getArrayAttr(createIdx()));
618af91b193SJean Perier       } else if (!rangeSize) { // start a range
619af91b193SJean Perier         rangeStartIdx = createIdx();
620af91b193SJean Perier         rangeSize = 1;
621af91b193SJean Perier       } else if (nextIsSame) { // expand a range
622af91b193SJean Perier         ++rangeSize;
623af91b193SJean Perier       } else { // end a range
624af91b193SJean Perier         llvm::SmallVector<int64_t> rangeBounds;
625af91b193SJean Perier         llvm::SmallVector<mlir::Attribute> idx = createIdx();
626af91b193SJean Perier         for (size_t i = 0; i < idx.size(); ++i) {
627fac349a1SChristian Sigg           rangeBounds.push_back(mlir::cast<mlir::IntegerAttr>(rangeStartIdx[i])
628af91b193SJean Perier                                     .getValue()
629af91b193SJean Perier                                     .getSExtValue());
630af91b193SJean Perier           rangeBounds.push_back(
631fac349a1SChristian Sigg               mlir::cast<mlir::IntegerAttr>(idx[i]).getValue().getSExtValue());
632af91b193SJean Perier         }
633af91b193SJean Perier         array = builder.create<fir::InsertOnRangeOp>(
634af91b193SJean Perier             loc, arrayTy, array, getElementVal(),
635af91b193SJean Perier             builder.getIndexVectorAttr(rangeBounds));
636af91b193SJean Perier         rangeSize = 0;
637af91b193SJean Perier       }
638af91b193SJean Perier     } while (con.IncrementSubscripts(subscripts));
639af91b193SJean Perier   }
640af91b193SJean Perier   return array;
641af91b193SJean Perier }
642af91b193SJean Perier 
643af91b193SJean Perier /// Convert an evaluate::Constant<T> array into a fir.ref<fir.array<>> value
644af91b193SJean Perier /// that points to the storage of a fir.global in read only memory and is
645af91b193SJean Perier /// initialized with the value of the constant.
646af91b193SJean Perier /// This should not be called while generating the body of a fir.global.
6472d9b4a50SJean Perier template <typename T>
6482d9b4a50SJean Perier static mlir::Value
6492d9b4a50SJean Perier genOutlineArrayLit(Fortran::lower::AbstractConverter &converter,
6502d9b4a50SJean Perier                    mlir::Location loc, mlir::Type arrayTy,
6512d9b4a50SJean Perier                    const Fortran::evaluate::Constant<T> &constant) {
6522d9b4a50SJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
653e6a4346bSScott Manley   mlir::Type eleTy = mlir::cast<fir::SequenceType>(arrayTy).getElementType();
654be5747e5SSlava Zakharin   llvm::StringRef globalName = converter.getUniqueLitName(
655be5747e5SSlava Zakharin       loc, std::make_unique<Fortran::lower::SomeExpr>(toEvExpr(constant)),
656be5747e5SSlava Zakharin       eleTy);
657af91b193SJean Perier   fir::GlobalOp global = builder.getNamedGlobal(globalName);
658af91b193SJean Perier   if (!global) {
659af91b193SJean Perier     // Using a dense attribute for the initial value instead of creating an
660af91b193SJean Perier     // intialization body speeds up MLIR/LLVM compilation, but this is not
661af91b193SJean Perier     // always possible.
6622d9b4a50SJean Perier     if constexpr (T::category == Fortran::common::TypeCategory::Logical ||
6632d9b4a50SJean Perier                   T::category == Fortran::common::TypeCategory::Integer ||
664c8517f17SLeandro Lupori                   T::category == Fortran::common::TypeCategory::Real ||
665c8517f17SLeandro Lupori                   T::category == Fortran::common::TypeCategory::Complex) {
666af91b193SJean Perier       global = DenseGlobalBuilder::tryCreating(
667af91b193SJean Perier           builder, loc, arrayTy, globalName, builder.createInternalLinkage(),
6683a47d948SValentin Clement (バレンタイン クレメン)           true, constant, {});
669af91b193SJean Perier     }
670af91b193SJean Perier     if (!global)
671556483feSLeandro Lupori       // If the number of elements of the array is huge, the compilation may
672556483feSLeandro Lupori       // use a lot of memory and take a very long time to complete.
673556483feSLeandro Lupori       // Empirical evidence shows that an array with 150000 elements of
674556483feSLeandro Lupori       // complex type takes roughly 30 seconds to compile and uses 4GB of RAM,
675556483feSLeandro Lupori       // on a modern machine.
676556483feSLeandro Lupori       // It would be nice to add a driver switch to control the array size
677556483feSLeandro Lupori       // after which flang should not continue to compile.
678af91b193SJean Perier       global = builder.createGlobalConstant(
679af91b193SJean Perier           loc, arrayTy, globalName,
680af91b193SJean Perier           [&](fir::FirOpBuilder &builder) {
681af91b193SJean Perier             mlir::Value result =
6822d9b4a50SJean Perier                 genInlinedArrayLit(converter, loc, arrayTy, constant);
683af91b193SJean Perier             builder.create<fir::HasValueOp>(loc, result);
684af91b193SJean Perier           },
685af91b193SJean Perier           builder.createInternalLinkage());
686af91b193SJean Perier   }
687af91b193SJean Perier   return builder.create<fir::AddrOfOp>(loc, global.resultType(),
688af91b193SJean Perier                                        global.getSymbol());
689af91b193SJean Perier }
690af91b193SJean Perier 
691af91b193SJean Perier /// Convert an evaluate::Constant<T> array into an fir::ExtendedValue.
6922d9b4a50SJean Perier template <typename T>
6932d9b4a50SJean Perier static fir::ExtendedValue
6942d9b4a50SJean Perier genArrayLit(Fortran::lower::AbstractConverter &converter, mlir::Location loc,
6952d9b4a50SJean Perier             const Fortran::evaluate::Constant<T> &con,
696af91b193SJean Perier             bool outlineInReadOnlyMemory) {
6972d9b4a50SJean Perier   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
698af91b193SJean Perier   Fortran::evaluate::ConstantSubscript size =
699af91b193SJean Perier       Fortran::evaluate::GetSize(con.shape());
700af91b193SJean Perier   if (size > std::numeric_limits<std::uint32_t>::max())
701af91b193SJean Perier     // llvm::SmallVector has limited size
702af91b193SJean Perier     TODO(loc, "Creation of very large array constants");
703af91b193SJean Perier   fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end());
704af91b193SJean Perier   llvm::SmallVector<std::int64_t> typeParams;
7052d9b4a50SJean Perier   if constexpr (T::category == Fortran::common::TypeCategory::Character)
706af91b193SJean Perier     typeParams.push_back(con.LEN());
7072d9b4a50SJean Perier   mlir::Type eleTy;
7082d9b4a50SJean Perier   if constexpr (T::category == Fortran::common::TypeCategory::Derived)
7092d9b4a50SJean Perier     eleTy = Fortran::lower::translateDerivedTypeToFIRType(
7102d9b4a50SJean Perier         converter, con.GetType().GetDerivedTypeSpec());
7112d9b4a50SJean Perier   else
7122d9b4a50SJean Perier     eleTy = Fortran::lower::getFIRType(builder.getContext(), T::category,
7132d9b4a50SJean Perier                                        T::kind, typeParams);
714af91b193SJean Perier   auto arrayTy = fir::SequenceType::get(shape, eleTy);
715af91b193SJean Perier   mlir::Value array = outlineInReadOnlyMemory
7162d9b4a50SJean Perier                           ? genOutlineArrayLit(converter, loc, arrayTy, con)
7172d9b4a50SJean Perier                           : genInlinedArrayLit(converter, loc, arrayTy, con);
718af91b193SJean Perier 
719af91b193SJean Perier   mlir::IndexType idxTy = builder.getIndexType();
720af91b193SJean Perier   llvm::SmallVector<mlir::Value> extents;
721af91b193SJean Perier   for (auto extent : shape)
722af91b193SJean Perier     extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
723af91b193SJean Perier   // Convert  lower bounds if they are not all ones.
724af91b193SJean Perier   llvm::SmallVector<mlir::Value> lbounds;
725af91b193SJean Perier   if (llvm::any_of(con.lbounds(), [](auto lb) { return lb != 1; }))
726af91b193SJean Perier     for (auto lb : con.lbounds())
727af91b193SJean Perier       lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb));
728af91b193SJean Perier 
7292d9b4a50SJean Perier   if constexpr (T::category == Fortran::common::TypeCategory::Character) {
730af91b193SJean Perier     mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
731af91b193SJean Perier     return fir::CharArrayBoxValue{array, len, extents, lbounds};
732af91b193SJean Perier   } else {
733af91b193SJean Perier     return fir::ArrayBoxValue{array, extents, lbounds};
734af91b193SJean Perier   }
735af91b193SJean Perier }
736af91b193SJean Perier 
7372d9b4a50SJean Perier template <typename T>
7382d9b4a50SJean Perier fir::ExtendedValue Fortran::lower::ConstantBuilder<T>::gen(
7392d9b4a50SJean Perier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
7402d9b4a50SJean Perier     const Fortran::evaluate::Constant<T> &constant,
741af91b193SJean Perier     bool outlineBigConstantsInReadOnlyMemory) {
742af91b193SJean Perier   if (constant.Rank() > 0)
7432d9b4a50SJean Perier     return genArrayLit(converter, loc, constant,
744af91b193SJean Perier                        outlineBigConstantsInReadOnlyMemory);
7452d9b4a50SJean Perier   std::optional<Fortran::evaluate::Scalar<T>> opt = constant.GetScalarValue();
746af91b193SJean Perier   assert(opt.has_value() && "constant has no value");
7472d9b4a50SJean Perier   if constexpr (T::category == Fortran::common::TypeCategory::Character) {
7482d9b4a50SJean Perier     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
7492d9b4a50SJean Perier     auto value =
7502d9b4a50SJean Perier         genScalarLit<T::kind>(builder, loc, opt.value(), constant.LEN(),
751af91b193SJean Perier                               outlineBigConstantsInReadOnlyMemory);
752af91b193SJean Perier     mlir::Value len = builder.createIntegerConstant(
753af91b193SJean Perier         loc, builder.getCharacterLengthType(), constant.LEN());
754af91b193SJean Perier     return fir::CharBoxValue{value, len};
7552d9b4a50SJean Perier   } else if constexpr (T::category == Fortran::common::TypeCategory::Derived) {
7562d9b4a50SJean Perier     mlir::Type eleTy = Fortran::lower::translateDerivedTypeToFIRType(
7572d9b4a50SJean Perier         converter, opt->GetType().GetDerivedTypeSpec());
7582d9b4a50SJean Perier     return genScalarLit(converter, loc, *opt, eleTy,
7592d9b4a50SJean Perier                         outlineBigConstantsInReadOnlyMemory);
760af91b193SJean Perier   } else {
7612d9b4a50SJean Perier     return genScalarLit<T::category, T::kind>(converter.getFirOpBuilder(), loc,
7622d9b4a50SJean Perier                                               opt.value());
763af91b193SJean Perier   }
764af91b193SJean Perier }
765af91b193SJean Perier 
7662d9b4a50SJean Perier static fir::ExtendedValue
7672d9b4a50SJean Perier genConstantValue(Fortran::lower::AbstractConverter &converter,
7682d9b4a50SJean Perier                  mlir::Location loc,
7692d9b4a50SJean Perier                  const Fortran::evaluate::Expr<Fortran::evaluate::SomeDerived>
7702d9b4a50SJean Perier                      &constantExpr) {
7712d9b4a50SJean Perier   if (const auto *constant = std::get_if<
7722d9b4a50SJean Perier           Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived>>(
7732d9b4a50SJean Perier           &constantExpr.u))
7742d9b4a50SJean Perier     return Fortran::lower::convertConstant(converter, loc, *constant,
7752d9b4a50SJean Perier                                            /*outline=*/false);
7762d9b4a50SJean Perier   if (const auto *structCtor =
7772d9b4a50SJean Perier           std::get_if<Fortran::evaluate::StructureConstructor>(&constantExpr.u))
7782d9b4a50SJean Perier     return Fortran::lower::genInlinedStructureCtorLit(converter, loc,
7792d9b4a50SJean Perier                                                       *structCtor);
7802d9b4a50SJean Perier   fir::emitFatalError(loc, "not a constant derived type expression");
7812d9b4a50SJean Perier }
7822d9b4a50SJean Perier 
7832d9b4a50SJean Perier template <Fortran::common::TypeCategory TC, int KIND>
7842d9b4a50SJean Perier static fir::ExtendedValue genConstantValue(
7852d9b4a50SJean Perier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
7862d9b4a50SJean Perier     const Fortran::evaluate::Expr<Fortran::evaluate::Type<TC, KIND>>
7872d9b4a50SJean Perier         &constantExpr) {
7882d9b4a50SJean Perier   using T = Fortran::evaluate::Type<TC, KIND>;
7892d9b4a50SJean Perier   if (const auto *constant =
7902d9b4a50SJean Perier           std::get_if<Fortran::evaluate::Constant<T>>(&constantExpr.u))
7912d9b4a50SJean Perier     return Fortran::lower::convertConstant(converter, loc, *constant,
7922d9b4a50SJean Perier                                            /*outline=*/false);
7932d9b4a50SJean Perier   fir::emitFatalError(loc, "not an evaluate::Constant<T>");
7942d9b4a50SJean Perier }
7952d9b4a50SJean Perier 
7962d9b4a50SJean Perier static fir::ExtendedValue
7972d9b4a50SJean Perier genConstantValue(Fortran::lower::AbstractConverter &converter,
7982d9b4a50SJean Perier                  mlir::Location loc,
7992d9b4a50SJean Perier                  const Fortran::lower::SomeExpr &constantExpr) {
80077d8cfb3SAlexander Shaposhnikov   return Fortran::common::visit(
8012d9b4a50SJean Perier       [&](const auto &x) -> fir::ExtendedValue {
8022d9b4a50SJean Perier         using T = std::decay_t<decltype(x)>;
8032d9b4a50SJean Perier         if constexpr (Fortran::common::HasMember<
8042d9b4a50SJean Perier                           T, Fortran::lower::CategoryExpression>) {
8052d9b4a50SJean Perier           if constexpr (T::Result::category ==
8062d9b4a50SJean Perier                         Fortran::common::TypeCategory::Derived) {
8072d9b4a50SJean Perier             return genConstantValue(converter, loc, x);
8082d9b4a50SJean Perier           } else {
80977d8cfb3SAlexander Shaposhnikov             return Fortran::common::visit(
8102d9b4a50SJean Perier                 [&](const auto &preciseKind) {
8112d9b4a50SJean Perier                   return genConstantValue(converter, loc, preciseKind);
8122d9b4a50SJean Perier                 },
8132d9b4a50SJean Perier                 x.u);
8142d9b4a50SJean Perier           }
8152d9b4a50SJean Perier         } else {
8162d9b4a50SJean Perier           fir::emitFatalError(loc, "unexpected typeless constant value");
8172d9b4a50SJean Perier         }
8182d9b4a50SJean Perier       },
8192d9b4a50SJean Perier       constantExpr.u);
8202d9b4a50SJean Perier }
8212d9b4a50SJean Perier 
8222d9b4a50SJean Perier fir::ExtendedValue Fortran::lower::genInlinedStructureCtorLit(
8232d9b4a50SJean Perier     Fortran::lower::AbstractConverter &converter, mlir::Location loc,
8242d9b4a50SJean Perier     const Fortran::evaluate::StructureConstructor &ctor) {
8252d9b4a50SJean Perier   mlir::Type type = Fortran::lower::translateDerivedTypeToFIRType(
8262d9b4a50SJean Perier       converter, ctor.derivedTypeSpec());
8272d9b4a50SJean Perier   return genInlinedStructureCtorLitImpl(converter, loc, ctor, type);
8282d9b4a50SJean Perier }
8292d9b4a50SJean Perier 
830af91b193SJean Perier using namespace Fortran::evaluate;
8312d9b4a50SJean Perier FOR_EACH_SPECIFIC_TYPE(template class Fortran::lower::ConstantBuilder, )
832