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