--- /dev/null
+//===-- ConvertConstant.h -- lowering of constants --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+///
+/// Implements the conversion from evaluate::Constant to FIR.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_LOWER_CONVERTCONSTANT_H
+#define FORTRAN_LOWER_CONVERTCONSTANT_H
+
+#include "flang/Evaluate/constant.h"
+#include "flang/Lower/Support/Utils.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+
+namespace Fortran::lower {
+template <typename T>
+class ConstantBuilder {};
+
+/// Class to lower intrinsic evaluate::Constant to fir::ExtendedValue.
+template <common::TypeCategory TC, int KIND>
+class ConstantBuilder<evaluate::Type<TC, KIND>> {
+public:
+ /// Lower \p constant into a fir::ExtendedValue.
+ /// If \p outlineBigConstantsInReadOnlyMemory is set, character and array
+ /// constants will be lowered into read only memory fir.global, and the
+ /// resulting fir::ExtendedValue will contain the address of the fir.global.
+ /// This option should not be set if the constant is being lowered while the
+ /// builder is already in a fir.global body because fir.global initialization
+ /// body cannot contain code manipulating memory (e.g. fir.load/fir.store...).
+ static fir::ExtendedValue
+ gen(fir::FirOpBuilder &builder, mlir::Location loc,
+ const evaluate::Constant<evaluate::Type<TC, KIND>> &constant,
+ bool outlineBigConstantsInReadOnlyMemory);
+};
+
+template <common::TypeCategory TC, int KIND>
+using IntrinsicConstantBuilder = ConstantBuilder<evaluate::Type<TC, KIND>>;
+
+using namespace evaluate;
+FOR_EACH_INTRINSIC_KIND(extern template class ConstantBuilder, )
+
+/// Create a fir.global array with a dense attribute containing the value of
+/// \p initExpr.
+/// Using a dense attribute allows faster MLIR compilation times compared to
+/// creating an initialization body for the initial value. However, a dense
+/// attribute can only be created if initExpr is a non-empty rank 1 numerical or
+/// logical Constant<T>. Otherwise, the value returned will be null.
+fir::GlobalOp tryCreatingDenseGlobal(fir::FirOpBuilder &builder,
+ mlir::Location loc, mlir::Type symTy,
+ llvm::StringRef globalName,
+ mlir::StringAttr linkage, bool isConst,
+ const Fortran::lower::SomeExpr &initExpr);
+
+} // namespace Fortran::lower
+
+#endif // FORTRAN_LOWER_CONVERTCONSTANT_H
SymMap &symMap,
StatementContext &stmtCtx);
-/// Create a global array symbol with the Dense attribute
-fir::GlobalOp createDenseGlobal(mlir::Location loc, mlir::Type symTy,
- llvm::StringRef globalName,
- mlir::StringAttr linkage, bool isConst,
- const SomeExpr &expr,
- Fortran::lower::AbstractConverter &converter);
-
/// Create the IR for the expression \p expr in an initialization context.
/// Expressions that appear in initializers may not allocate temporaries, do not
/// have a stack, etc.
Bridge.cpp
CallInterface.cpp
Coarray.cpp
+ ConvertConstant.cpp
ConvertExpr.cpp
ConvertExprToHLFIR.cpp
ConvertType.cpp
--- /dev/null
+//===-- ConvertConstant.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Lower/ConvertConstant.h"
+#include "flang/Evaluate/expression.h"
+#include "flang/Lower/ConvertType.h"
+#include "flang/Lower/Mangler.h"
+#include "flang/Optimizer/Builder/Complex.h"
+#include "flang/Optimizer/Builder/Todo.h"
+
+/// Convert string, \p s, to an APFloat value. Recognize and handle Inf and
+/// NaN strings as well. \p s is assumed to not contain any spaces.
+static llvm::APFloat consAPFloat(const llvm::fltSemantics &fsem,
+ llvm::StringRef s) {
+ assert(!s.contains(' '));
+ if (s.compare_insensitive("-inf") == 0)
+ return llvm::APFloat::getInf(fsem, /*negative=*/true);
+ if (s.compare_insensitive("inf") == 0 || s.compare_insensitive("+inf") == 0)
+ return llvm::APFloat::getInf(fsem);
+ // TODO: Add support for quiet and signaling NaNs.
+ if (s.compare_insensitive("-nan") == 0)
+ return llvm::APFloat::getNaN(fsem, /*negative=*/true);
+ if (s.compare_insensitive("nan") == 0 || s.compare_insensitive("+nan") == 0)
+ return llvm::APFloat::getNaN(fsem);
+ return {fsem, s};
+}
+
+//===----------------------------------------------------------------------===//
+// Fortran::lower::tryCreatingDenseGlobal implementation
+//===----------------------------------------------------------------------===//
+
+/// Generate an mlir attribute from a literal value
+template <Fortran::common::TypeCategory TC, int KIND>
+static mlir::Attribute convertToAttribute(
+ fir::FirOpBuilder &builder,
+ const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> &value,
+ mlir::Type type) {
+ if constexpr (TC == Fortran::common::TypeCategory::Integer) {
+ return builder.getIntegerAttr(type, value.ToInt64());
+ } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
+ return builder.getIntegerAttr(type, value.IsTrue());
+ } else {
+ static_assert(TC == Fortran::common::TypeCategory::Real,
+ "type values cannot be converted to attributes");
+ std::string str = value.DumpHexadecimal();
+ auto floatVal =
+ consAPFloat(builder.getKindMap().getFloatSemantics(KIND), str);
+ return builder.getFloatAttr(type, floatVal);
+ }
+ return {};
+}
+
+namespace {
+/// Helper class to lower an array constant to a global with an MLIR dense
+/// attribute.
+///
+/// If we have a rank-1 array of integer, real, or logical, then we can
+/// create a global array with the dense attribute.
+///
+/// The mlir tensor type can only handle integer, real, or logical. It
+/// does not currently support nested structures which is required for
+/// complex.
+///
+/// Also, we currently handle just rank-1 since tensor type assumes
+/// row major array ordering. We will need to reorder the dimensions
+/// in the tensor type to support Fortran's column major array ordering.
+/// How to create this tensor type is to be determined.
+class DenseGlobalBuilder {
+public:
+ static fir::GlobalOp tryCreating(fir::FirOpBuilder &builder,
+ mlir::Location loc, mlir::Type symTy,
+ llvm::StringRef globalName,
+ mlir::StringAttr linkage, bool isConst,
+ const Fortran::lower::SomeExpr &initExpr) {
+ DenseGlobalBuilder globalBuilder;
+ std::visit(
+ Fortran::common::visitors{
+ [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeLogical> &
+ x) { globalBuilder.tryConvertingToAttributes(builder, x); },
+ [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeInteger> &
+ x) { globalBuilder.tryConvertingToAttributes(builder, x); },
+ [&](const Fortran::evaluate::Expr<Fortran::evaluate::SomeReal> &x) {
+ globalBuilder.tryConvertingToAttributes(builder, x);
+ },
+ [](const auto &) {},
+ },
+ initExpr.u);
+ return globalBuilder.tryCreatingGlobal(builder, loc, symTy, globalName,
+ linkage, isConst);
+ }
+
+ template <Fortran::common::TypeCategory TC, int KIND>
+ static fir::GlobalOp tryCreating(
+ fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type symTy,
+ llvm::StringRef globalName, mlir::StringAttr linkage, bool isConst,
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
+ &constant) {
+ DenseGlobalBuilder globalBuilder;
+ globalBuilder.tryConvertingToAttributes(builder, constant);
+ return globalBuilder.tryCreatingGlobal(builder, loc, symTy, globalName,
+ linkage, isConst);
+ }
+
+private:
+ DenseGlobalBuilder() = default;
+
+ /// Try converting an evaluate::Constant to a list of MLIR attributes.
+ template <Fortran::common::TypeCategory TC, int KIND>
+ void tryConvertingToAttributes(
+ fir::FirOpBuilder &builder,
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
+ &constant) {
+ static_assert(TC != Fortran::common::TypeCategory::Character,
+ "must be numerical or logical");
+ if (constant.Rank() != 1)
+ return;
+ auto attrTc = TC == Fortran::common::TypeCategory::Logical
+ ? Fortran::common::TypeCategory::Integer
+ : TC;
+ attributeElementType = Fortran::lower::getFIRType(builder.getContext(),
+ attrTc, KIND, llvm::None);
+ for (auto element : constant.values())
+ attributes.push_back(
+ convertToAttribute<TC, KIND>(builder, element, attributeElementType));
+ }
+
+ /// Try converting an evaluate::Expr to a list of MLIR attributes.
+ template <typename SomeCat>
+ void tryConvertingToAttributes(fir::FirOpBuilder &builder,
+ const Fortran::evaluate::Expr<SomeCat> &expr) {
+ std::visit(
+ [&](const auto &x) {
+ using TR = Fortran::evaluate::ResultType<decltype(x)>;
+ if (const auto *constant =
+ std::get_if<Fortran::evaluate::Constant<TR>>(&x.u))
+ tryConvertingToAttributes<TR::category, TR::kind>(builder,
+ *constant);
+ },
+ expr.u);
+ }
+
+ /// Create a fir::Global if MLIR attributes have been successfully created by
+ /// tryConvertingToAttributes.
+ fir::GlobalOp tryCreatingGlobal(fir::FirOpBuilder &builder,
+ mlir::Location loc, mlir::Type symTy,
+ llvm::StringRef globalName,
+ mlir::StringAttr linkage,
+ bool isConst) const {
+ // Not a rank 1 "trivial" intrinsic constant array, or empty array.
+ if (!attributeElementType || attributes.empty())
+ return {};
+
+ auto tensorTy =
+ mlir::RankedTensorType::get(attributes.size(), attributeElementType);
+ auto init = mlir::DenseElementsAttr::get(tensorTy, attributes);
+ return builder.createGlobal(loc, symTy, globalName, linkage, init, isConst);
+ }
+
+ llvm::SmallVector<mlir::Attribute> attributes;
+ mlir::Type attributeElementType;
+};
+} // namespace
+
+fir::GlobalOp Fortran::lower::tryCreatingDenseGlobal(
+ fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type symTy,
+ llvm::StringRef globalName, mlir::StringAttr linkage, bool isConst,
+ const Fortran::lower::SomeExpr &initExpr) {
+ return DenseGlobalBuilder::tryCreating(builder, loc, symTy, globalName,
+ linkage, isConst, initExpr);
+}
+
+//===----------------------------------------------------------------------===//
+// Fortran::lower::IntrinsicConstantBuilder<TC, KIND>::gen
+// Lower an array constant to a fir::ExtendedValue.
+//===----------------------------------------------------------------------===//
+
+/// Generate a real constant with a value `value`.
+template <int KIND>
+static mlir::Value genRealConstant(fir::FirOpBuilder &builder,
+ mlir::Location loc,
+ const llvm::APFloat &value) {
+ mlir::Type fltTy = Fortran::lower::convertReal(builder.getContext(), KIND);
+ return builder.createRealConstant(loc, fltTy, value);
+}
+
+/// Convert a scalar literal constant to IR.
+template <Fortran::common::TypeCategory TC, int KIND>
+static mlir::Value genScalarLit(
+ fir::FirOpBuilder &builder, mlir::Location loc,
+ const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>> &value) {
+ if constexpr (TC == Fortran::common::TypeCategory::Integer) {
+ mlir::Type ty =
+ Fortran::lower::getFIRType(builder.getContext(), TC, KIND, llvm::None);
+ if (KIND == 16) {
+ auto bigInt =
+ llvm::APInt(ty.getIntOrFloatBitWidth(), value.SignedDecimal(), 10);
+ return builder.create<mlir::arith::ConstantOp>(
+ loc, ty, mlir::IntegerAttr::get(ty, bigInt));
+ }
+ return builder.createIntegerConstant(loc, ty, value.ToInt64());
+ } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
+ return builder.createBool(loc, value.IsTrue());
+ } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
+ std::string str = value.DumpHexadecimal();
+ if constexpr (KIND == 2) {
+ auto floatVal = consAPFloat(llvm::APFloatBase::IEEEhalf(), str);
+ return genRealConstant<KIND>(builder, loc, floatVal);
+ } else if constexpr (KIND == 3) {
+ auto floatVal = consAPFloat(llvm::APFloatBase::BFloat(), str);
+ return genRealConstant<KIND>(builder, loc, floatVal);
+ } else if constexpr (KIND == 4) {
+ auto floatVal = consAPFloat(llvm::APFloatBase::IEEEsingle(), str);
+ return genRealConstant<KIND>(builder, loc, floatVal);
+ } else if constexpr (KIND == 10) {
+ auto floatVal = consAPFloat(llvm::APFloatBase::x87DoubleExtended(), str);
+ return genRealConstant<KIND>(builder, loc, floatVal);
+ } else if constexpr (KIND == 16) {
+ auto floatVal = consAPFloat(llvm::APFloatBase::IEEEquad(), str);
+ return genRealConstant<KIND>(builder, loc, floatVal);
+ } else {
+ // convert everything else to double
+ auto floatVal = consAPFloat(llvm::APFloatBase::IEEEdouble(), str);
+ return genRealConstant<KIND>(builder, loc, floatVal);
+ }
+ } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
+ mlir::Value realPart =
+ genScalarLit<Fortran::common::TypeCategory::Real, KIND>(builder, loc,
+ value.REAL());
+ mlir::Value imagPart =
+ genScalarLit<Fortran::common::TypeCategory::Real, KIND>(builder, loc,
+ value.AIMAG());
+ return fir::factory::Complex{builder, loc}.createComplex(KIND, realPart,
+ imagPart);
+ } else /*constexpr*/ {
+ llvm_unreachable("unhandled constant");
+ }
+}
+
+/// Create fir::string_lit from a scalar character constant.
+template <int KIND>
+static fir::StringLitOp
+createStringLitOp(fir::FirOpBuilder &builder, mlir::Location loc,
+ const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
+ Fortran::common::TypeCategory::Character, KIND>> &value,
+ [[maybe_unused]] int64_t len) {
+ if constexpr (KIND == 1) {
+ assert(value.size() == static_cast<std::uint64_t>(len));
+ return builder.createStringLitOp(loc, value);
+ } else {
+ using ET = typename std::decay_t<decltype(value)>::value_type;
+ fir::CharacterType type =
+ fir::CharacterType::get(builder.getContext(), KIND, len);
+ mlir::MLIRContext *context = builder.getContext();
+ std::int64_t size = static_cast<std::int64_t>(value.size());
+ mlir::ShapedType shape = mlir::RankedTensorType::get(
+ llvm::ArrayRef<std::int64_t>{size},
+ mlir::IntegerType::get(builder.getContext(), sizeof(ET) * 8));
+ auto denseAttr = mlir::DenseElementsAttr::get(
+ shape, llvm::ArrayRef<ET>{value.data(), value.size()});
+ auto denseTag = mlir::StringAttr::get(context, fir::StringLitOp::xlist());
+ mlir::NamedAttribute dataAttr(denseTag, denseAttr);
+ auto sizeTag = mlir::StringAttr::get(context, fir::StringLitOp::size());
+ mlir::NamedAttribute sizeAttr(sizeTag, builder.getI64IntegerAttr(len));
+ llvm::SmallVector<mlir::NamedAttribute> attrs = {dataAttr, sizeAttr};
+ return builder.create<fir::StringLitOp>(
+ loc, llvm::ArrayRef<mlir::Type>{type}, llvm::None, attrs);
+ }
+}
+
+/// Convert a scalar literal CHARACTER to IR.
+template <int KIND>
+static mlir::Value
+genScalarLit(fir::FirOpBuilder &builder, mlir::Location loc,
+ const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
+ Fortran::common::TypeCategory::Character, KIND>> &value,
+ int64_t len, bool outlineInReadOnlyMemory) {
+ // When in an initializer context, construct the literal op itself and do
+ // not construct another constant object in rodata.
+ if (!outlineInReadOnlyMemory)
+ return createStringLitOp<KIND>(builder, loc, value, len);
+
+ // Otherwise, the string is in a plain old expression so "outline" the value
+ // in read only data by hash consing it to a constant literal object.
+
+ // ASCII global constants are created using an mlir string attribute.
+ if constexpr (KIND == 1) {
+ return fir::getBase(fir::factory::createStringLiteral(builder, loc, value));
+ }
+
+ auto size = builder.getKindMap().getCharacterBitsize(KIND) / 8 * value.size();
+ llvm::StringRef strVal(reinterpret_cast<const char *>(value.c_str()), size);
+ std::string globalName = fir::factory::uniqueCGIdent("cl", strVal);
+ fir::GlobalOp global = builder.getNamedGlobal(globalName);
+ fir::CharacterType type =
+ fir::CharacterType::get(builder.getContext(), KIND, len);
+ if (!global)
+ global = builder.createGlobalConstant(
+ loc, type, globalName,
+ [&](fir::FirOpBuilder &builder) {
+ fir::StringLitOp str =
+ createStringLitOp<KIND>(builder, loc, value, len);
+ builder.create<fir::HasValueOp>(loc, str);
+ },
+ builder.createLinkOnceLinkage());
+ return builder.create<fir::AddrOfOp>(loc, global.resultType(),
+ global.getSymbol());
+}
+
+/// Create an evaluate::Constant<T> array to a fir.array<> value
+/// built with a chain of fir.insert or fir.insert_on_range operations.
+/// This is intended to be called when building the body of a fir.global.
+template <Fortran::common::TypeCategory TC, int KIND>
+static mlir::Value genInlinedArrayLit(
+ fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type arrayTy,
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> &con) {
+ mlir::IndexType idxTy = builder.getIndexType();
+ Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds();
+ auto createIdx = [&]() {
+ llvm::SmallVector<mlir::Attribute> idx;
+ for (size_t i = 0; i < subscripts.size(); ++i)
+ idx.push_back(
+ builder.getIntegerAttr(idxTy, subscripts[i] - con.lbounds()[i]));
+ return idx;
+ };
+ mlir::Value array = builder.create<fir::UndefOp>(loc, arrayTy);
+ if (Fortran::evaluate::GetSize(con.shape()) == 0)
+ return array;
+ if constexpr (TC == Fortran::common::TypeCategory::Character) {
+ do {
+ mlir::Value elementVal =
+ genScalarLit<KIND>(builder, loc, con.At(subscripts), con.LEN(),
+ /*outlineInReadOnlyMemory=*/false);
+ array = builder.create<fir::InsertValueOp>(
+ loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx()));
+ } while (con.IncrementSubscripts(subscripts));
+ } else {
+ llvm::SmallVector<mlir::Attribute> rangeStartIdx;
+ uint64_t rangeSize = 0;
+ mlir::Type eleTy = arrayTy.cast<fir::SequenceType>().getEleTy();
+ do {
+ auto getElementVal = [&]() {
+ return builder.createConvert(
+ loc, eleTy,
+ genScalarLit<TC, KIND>(builder, loc, con.At(subscripts)));
+ };
+ Fortran::evaluate::ConstantSubscripts nextSubscripts = subscripts;
+ bool nextIsSame = con.IncrementSubscripts(nextSubscripts) &&
+ con.At(subscripts) == con.At(nextSubscripts);
+ if (!rangeSize && !nextIsSame) { // single (non-range) value
+ array = builder.create<fir::InsertValueOp>(
+ loc, arrayTy, array, getElementVal(),
+ builder.getArrayAttr(createIdx()));
+ } else if (!rangeSize) { // start a range
+ rangeStartIdx = createIdx();
+ rangeSize = 1;
+ } else if (nextIsSame) { // expand a range
+ ++rangeSize;
+ } else { // end a range
+ llvm::SmallVector<int64_t> rangeBounds;
+ llvm::SmallVector<mlir::Attribute> idx = createIdx();
+ for (size_t i = 0; i < idx.size(); ++i) {
+ rangeBounds.push_back(rangeStartIdx[i]
+ .cast<mlir::IntegerAttr>()
+ .getValue()
+ .getSExtValue());
+ rangeBounds.push_back(
+ idx[i].cast<mlir::IntegerAttr>().getValue().getSExtValue());
+ }
+ array = builder.create<fir::InsertOnRangeOp>(
+ loc, arrayTy, array, getElementVal(),
+ builder.getIndexVectorAttr(rangeBounds));
+ rangeSize = 0;
+ }
+ } while (con.IncrementSubscripts(subscripts));
+ }
+ return array;
+}
+
+/// Convert an evaluate::Constant<T> array into a fir.ref<fir.array<>> value
+/// that points to the storage of a fir.global in read only memory and is
+/// initialized with the value of the constant.
+/// This should not be called while generating the body of a fir.global.
+template <Fortran::common::TypeCategory TC, int KIND>
+static mlir::Value genOutlineArrayLit(
+ fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type arrayTy,
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
+ &constant) {
+ std::string globalName = Fortran::lower::mangle::mangleArrayLiteral(constant);
+ fir::GlobalOp global = builder.getNamedGlobal(globalName);
+ if (!global) {
+ // Using a dense attribute for the initial value instead of creating an
+ // intialization body speeds up MLIR/LLVM compilation, but this is not
+ // always possible.
+ if constexpr (TC == Fortran::common::TypeCategory::Logical ||
+ TC == Fortran::common::TypeCategory::Integer ||
+ TC == Fortran::common::TypeCategory::Real) {
+ global = DenseGlobalBuilder::tryCreating(
+ builder, loc, arrayTy, globalName, builder.createInternalLinkage(),
+ true, constant);
+ }
+ if (!global)
+ global = builder.createGlobalConstant(
+ loc, arrayTy, globalName,
+ [&](fir::FirOpBuilder &builder) {
+ mlir::Value result =
+ genInlinedArrayLit(builder, loc, arrayTy, constant);
+ builder.create<fir::HasValueOp>(loc, result);
+ },
+ builder.createInternalLinkage());
+ }
+ return builder.create<fir::AddrOfOp>(loc, global.resultType(),
+ global.getSymbol());
+}
+
+/// Convert an evaluate::Constant<T> array into an fir::ExtendedValue.
+template <Fortran::common::TypeCategory TC, int KIND>
+static fir::ExtendedValue genArrayLit(
+ fir::FirOpBuilder &builder, mlir::Location loc,
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> &con,
+ bool outlineInReadOnlyMemory) {
+ Fortran::evaluate::ConstantSubscript size =
+ Fortran::evaluate::GetSize(con.shape());
+ if (size > std::numeric_limits<std::uint32_t>::max())
+ // llvm::SmallVector has limited size
+ TODO(loc, "Creation of very large array constants");
+ fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end());
+ llvm::SmallVector<std::int64_t> typeParams;
+ if constexpr (TC == Fortran::common::TypeCategory::Character)
+ typeParams.push_back(con.LEN());
+ mlir::Type eleTy =
+ Fortran::lower::getFIRType(builder.getContext(), TC, KIND, typeParams);
+ auto arrayTy = fir::SequenceType::get(shape, eleTy);
+ mlir::Value array = outlineInReadOnlyMemory
+ ? genOutlineArrayLit(builder, loc, arrayTy, con)
+ : genInlinedArrayLit(builder, loc, arrayTy, con);
+
+ mlir::IndexType idxTy = builder.getIndexType();
+ llvm::SmallVector<mlir::Value> extents;
+ for (auto extent : shape)
+ extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
+ // Convert lower bounds if they are not all ones.
+ llvm::SmallVector<mlir::Value> lbounds;
+ if (llvm::any_of(con.lbounds(), [](auto lb) { return lb != 1; }))
+ for (auto lb : con.lbounds())
+ lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb));
+
+ if constexpr (TC == Fortran::common::TypeCategory::Character) {
+ mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
+ return fir::CharArrayBoxValue{array, len, extents, lbounds};
+ } else {
+ return fir::ArrayBoxValue{array, extents, lbounds};
+ }
+}
+
+template <Fortran::common::TypeCategory TC, int KIND>
+fir::ExtendedValue
+Fortran::lower::ConstantBuilder<Fortran::evaluate::Type<TC, KIND>>::gen(
+ fir::FirOpBuilder &builder, mlir::Location loc,
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
+ &constant,
+ bool outlineBigConstantsInReadOnlyMemory) {
+ if (constant.Rank() > 0)
+ return genArrayLit<TC, KIND>(builder, loc, constant,
+ outlineBigConstantsInReadOnlyMemory);
+ std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>>
+ opt = constant.GetScalarValue();
+ assert(opt.has_value() && "constant has no value");
+ if constexpr (TC == Fortran::common::TypeCategory::Character) {
+ auto value = genScalarLit<KIND>(builder, loc, opt.value(), constant.LEN(),
+ outlineBigConstantsInReadOnlyMemory);
+ mlir::Value len = builder.createIntegerConstant(
+ loc, builder.getCharacterLengthType(), constant.LEN());
+ return fir::CharBoxValue{value, len};
+ } else {
+ return genScalarLit<TC, KIND>(builder, loc, opt.value());
+ }
+}
+
+using namespace Fortran::evaluate;
+FOR_EACH_INTRINSIC_KIND(template class Fortran::lower::ConstantBuilder, )
#include "flang/Lower/CallInterface.h"
#include "flang/Lower/Coarray.h"
#include "flang/Lower/ComponentPath.h"
+#include "flang/Lower/ConvertConstant.h"
#include "flang/Lower/ConvertType.h"
#include "flang/Lower/ConvertVariable.h"
#include "flang/Lower/CustomIntrinsicCall.h"
return false;
}
-/// Some auxiliary data for processing initialization in ScalarExprLowering
-/// below. This is currently used for generating dense attributed global
-/// arrays.
-struct InitializerData {
- explicit InitializerData(bool getRawVals = false) : genRawVals{getRawVals} {}
- llvm::SmallVector<mlir::Attribute> rawVals; // initialization raw values
- mlir::Type rawType; // Type of elements processed for rawVals vector.
- bool genRawVals; // generate the rawVals vector if set.
-};
-
/// If \p arg is the address of a function with a denoted host-association tuple
/// argument, then return the host-associations tuple value of the current
/// procedure. Otherwise, return nullptr.
Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap,
Fortran::lower::StatementContext &stmtCtx,
- InitializerData *initializer = nullptr)
+ bool inInitializer = false)
: location{loc}, converter{converter},
builder{converter.getFirOpBuilder()}, stmtCtx{stmtCtx}, symMap{symMap},
- inInitializer{initializer} {}
+ inInitializer{inInitializer} {}
ExtValue genExtAddr(const Fortran::lower::SomeExpr &expr) {
return gen(expr);
return builder.createBool(getLoc(), value);
}
- /// Generate a real constant with a value `value`.
- template <int KIND>
- mlir::Value genRealConstant(mlir::MLIRContext *context,
- const llvm::APFloat &value) {
- mlir::Type fltTy = Fortran::lower::convertReal(context, KIND);
- return builder.createRealConstant(getLoc(), fltTy, value);
- }
-
mlir::Type getSomeKindInteger() { return builder.getIndexType(); }
mlir::func::FuncOp getFunction(llvm::StringRef name,
llvm_unreachable("unhandled logical operation");
}
- /// Convert a scalar literal constant to IR.
- template <Fortran::common::TypeCategory TC, int KIND>
- ExtValue genScalarLit(
- const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
- &value) {
- if constexpr (TC == Fortran::common::TypeCategory::Integer) {
- if (KIND == 16) {
- mlir::Type ty =
- converter.genType(Fortran::common::TypeCategory::Integer, KIND);
- auto bigInt =
- llvm::APInt(ty.getIntOrFloatBitWidth(), value.SignedDecimal(), 10);
- return builder.create<mlir::arith::ConstantOp>(
- getLoc(), ty, mlir::IntegerAttr::get(ty, bigInt));
- }
- return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64());
- } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
- return genBoolConstant(value.IsTrue());
- } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
- std::string str = value.DumpHexadecimal();
- if constexpr (KIND == 2) {
- auto floatVal = consAPFloat(llvm::APFloatBase::IEEEhalf(), str);
- return genRealConstant<KIND>(builder.getContext(), floatVal);
- } else if constexpr (KIND == 3) {
- auto floatVal = consAPFloat(llvm::APFloatBase::BFloat(), str);
- return genRealConstant<KIND>(builder.getContext(), floatVal);
- } else if constexpr (KIND == 4) {
- auto floatVal = consAPFloat(llvm::APFloatBase::IEEEsingle(), str);
- return genRealConstant<KIND>(builder.getContext(), floatVal);
- } else if constexpr (KIND == 10) {
- auto floatVal =
- consAPFloat(llvm::APFloatBase::x87DoubleExtended(), str);
- return genRealConstant<KIND>(builder.getContext(), floatVal);
- } else if constexpr (KIND == 16) {
- auto floatVal = consAPFloat(llvm::APFloatBase::IEEEquad(), str);
- return genRealConstant<KIND>(builder.getContext(), floatVal);
- } else {
- // convert everything else to double
- auto floatVal = consAPFloat(llvm::APFloatBase::IEEEdouble(), str);
- return genRealConstant<KIND>(builder.getContext(), floatVal);
- }
- } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
- using TR =
- Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>;
- Fortran::evaluate::ComplexConstructor<KIND> ctor(
- Fortran::evaluate::Expr<TR>{
- Fortran::evaluate::Constant<TR>{value.REAL()}},
- Fortran::evaluate::Expr<TR>{
- Fortran::evaluate::Constant<TR>{value.AIMAG()}});
- return genunbox(ctor);
- } else /*constexpr*/ {
- llvm_unreachable("unhandled constant");
- }
- }
-
- /// Convert string, \p s, to an APFloat value. Recognize and handle Inf and
- /// NaN strings as well. \p s is assumed to not contain any spaces.
- static llvm::APFloat consAPFloat(const llvm::fltSemantics &fsem,
- llvm::StringRef s) {
- assert(!s.contains(' '));
- if (s.compare_insensitive("-inf") == 0)
- return llvm::APFloat::getInf(fsem, /*negative=*/true);
- if (s.compare_insensitive("inf") == 0 || s.compare_insensitive("+inf") == 0)
- return llvm::APFloat::getInf(fsem);
- // TODO: Add support for quiet and signaling NaNs.
- if (s.compare_insensitive("-nan") == 0)
- return llvm::APFloat::getNaN(fsem, /*negative=*/true);
- if (s.compare_insensitive("nan") == 0 || s.compare_insensitive("+nan") == 0)
- return llvm::APFloat::getNaN(fsem);
- return {fsem, s};
- }
-
- /// Generate a raw literal value and store it in the rawVals vector.
- template <Fortran::common::TypeCategory TC, int KIND>
- void
- genRawLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
- &value) {
- mlir::Attribute val;
- assert(inInitializer != nullptr);
- if constexpr (TC == Fortran::common::TypeCategory::Integer) {
- inInitializer->rawType = converter.genType(TC, KIND);
- val = builder.getIntegerAttr(inInitializer->rawType, value.ToInt64());
- } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
- inInitializer->rawType =
- converter.genType(Fortran::common::TypeCategory::Integer, KIND);
- val = builder.getIntegerAttr(inInitializer->rawType, value.IsTrue());
- } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
- std::string str = value.DumpHexadecimal();
- inInitializer->rawType = converter.genType(TC, KIND);
- auto floatVal =
- consAPFloat(builder.getKindMap().getFloatSemantics(KIND), str);
- val = builder.getFloatAttr(inInitializer->rawType, floatVal);
- } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
- std::string strReal = value.REAL().DumpHexadecimal();
- std::string strImg = value.AIMAG().DumpHexadecimal();
- inInitializer->rawType = converter.genType(TC, KIND);
- auto realVal =
- consAPFloat(builder.getKindMap().getFloatSemantics(KIND), strReal);
- val = builder.getFloatAttr(inInitializer->rawType, realVal);
- inInitializer->rawVals.push_back(val);
- auto imgVal =
- consAPFloat(builder.getKindMap().getFloatSemantics(KIND), strImg);
- val = builder.getFloatAttr(inInitializer->rawType, imgVal);
- }
- inInitializer->rawVals.push_back(val);
- }
-
- /// Convert a scalar literal CHARACTER to IR.
- template <int KIND>
- ExtValue
- genScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
- Fortran::common::TypeCategory::Character, KIND>> &value,
- int64_t len) {
- using ET = typename std::decay_t<decltype(value)>::value_type;
- if constexpr (KIND == 1) {
- assert(value.size() == static_cast<std::uint64_t>(len));
- // Outline character constant in ro data if it is not in an initializer.
- if (!inInitializer)
- return fir::factory::createStringLiteral(builder, getLoc(), value);
- // When in an initializer context, construct the literal op itself and do
- // not construct another constant object in rodata.
- fir::StringLitOp stringLit = builder.createStringLitOp(getLoc(), value);
- mlir::Value lenp = builder.createIntegerConstant(
- getLoc(), builder.getCharacterLengthType(), len);
- return fir::CharBoxValue{stringLit.getResult(), lenp};
- }
- fir::CharacterType type =
- fir::CharacterType::get(builder.getContext(), KIND, len);
- auto consLit = [&]() -> fir::StringLitOp {
- mlir::MLIRContext *context = builder.getContext();
- std::int64_t size = static_cast<std::int64_t>(value.size());
- mlir::ShapedType shape = mlir::RankedTensorType::get(
- llvm::ArrayRef<std::int64_t>{size},
- mlir::IntegerType::get(builder.getContext(), sizeof(ET) * 8));
- auto denseAttr = mlir::DenseElementsAttr::get(
- shape, llvm::ArrayRef<ET>{value.data(), value.size()});
- auto denseTag = mlir::StringAttr::get(context, fir::StringLitOp::xlist());
- mlir::NamedAttribute dataAttr(denseTag, denseAttr);
- auto sizeTag = mlir::StringAttr::get(context, fir::StringLitOp::size());
- mlir::NamedAttribute sizeAttr(sizeTag, builder.getI64IntegerAttr(len));
- llvm::SmallVector<mlir::NamedAttribute> attrs = {dataAttr, sizeAttr};
- return builder.create<fir::StringLitOp>(
- getLoc(), llvm::ArrayRef<mlir::Type>{type}, llvm::None, attrs);
- };
-
- mlir::Value lenp = builder.createIntegerConstant(
- getLoc(), builder.getCharacterLengthType(), len);
- // When in an initializer context, construct the literal op itself and do
- // not construct another constant object in rodata.
- if (inInitializer)
- return fir::CharBoxValue{consLit().getResult(), lenp};
-
- // Otherwise, the string is in a plain old expression so "outline" the value
- // by hashconsing it to a constant literal object.
-
- auto size =
- converter.getKindMap().getCharacterBitsize(KIND) / 8 * value.size();
- llvm::StringRef strVal(reinterpret_cast<const char *>(value.c_str()), size);
- std::string globalName = fir::factory::uniqueCGIdent("cl", strVal);
- fir::GlobalOp global = builder.getNamedGlobal(globalName);
- if (!global)
- global = builder.createGlobalConstant(
- getLoc(), type, globalName,
- [&](fir::FirOpBuilder &builder) {
- fir::StringLitOp str = consLit();
- builder.create<fir::HasValueOp>(getLoc(), str);
- },
- builder.createLinkOnceLinkage());
- auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(),
- global.getSymbol());
- return fir::CharBoxValue{addr, lenp};
- }
-
- template <Fortran::common::TypeCategory TC, int KIND>
- ExtValue genArrayLit(
- const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
- &con) {
- mlir::Location loc = getLoc();
- mlir::IndexType idxTy = builder.getIndexType();
- Fortran::evaluate::ConstantSubscript size =
- Fortran::evaluate::GetSize(con.shape());
- if (size > std::numeric_limits<std::uint32_t>::max())
- // llvm::SmallVector has limited size
- TODO(getLoc(), "Creation of very large array constants");
- fir::SequenceType::Shape shape(con.shape().begin(), con.shape().end());
- mlir::Type eleTy;
- if constexpr (TC == Fortran::common::TypeCategory::Character)
- eleTy = converter.genType(TC, KIND, {con.LEN()});
- else
- eleTy = converter.genType(TC, KIND);
- auto arrayTy = fir::SequenceType::get(shape, eleTy);
- mlir::Value array;
- llvm::SmallVector<mlir::Value> lbounds;
- llvm::SmallVector<mlir::Value> extents;
- if (!inInitializer || !inInitializer->genRawVals) {
- array = builder.create<fir::UndefOp>(loc, arrayTy);
- for (auto [lb, extent] : llvm::zip(con.lbounds(), shape)) {
- lbounds.push_back(builder.createIntegerConstant(loc, idxTy, lb - 1));
- extents.push_back(builder.createIntegerConstant(loc, idxTy, extent));
- }
- }
- if (size == 0) {
- if constexpr (TC == Fortran::common::TypeCategory::Character) {
- mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
- return fir::CharArrayBoxValue{array, len, extents, lbounds};
- } else {
- return fir::ArrayBoxValue{array, extents, lbounds};
- }
- }
- Fortran::evaluate::ConstantSubscripts subscripts = con.lbounds();
- auto createIdx = [&]() {
- llvm::SmallVector<mlir::Attribute> idx;
- for (size_t i = 0; i < subscripts.size(); ++i)
- idx.push_back(
- builder.getIntegerAttr(idxTy, subscripts[i] - con.lbounds()[i]));
- return idx;
- };
- if constexpr (TC == Fortran::common::TypeCategory::Character) {
- assert(array && "array must not be nullptr");
- do {
- mlir::Value elementVal =
- fir::getBase(genScalarLit<KIND>(con.At(subscripts), con.LEN()));
- array = builder.create<fir::InsertValueOp>(
- loc, arrayTy, array, elementVal, builder.getArrayAttr(createIdx()));
- } while (con.IncrementSubscripts(subscripts));
- mlir::Value len = builder.createIntegerConstant(loc, idxTy, con.LEN());
- return fir::CharArrayBoxValue{array, len, extents, lbounds};
- } else {
- llvm::SmallVector<mlir::Attribute> rangeStartIdx;
- uint64_t rangeSize = 0;
- do {
- if (inInitializer && inInitializer->genRawVals) {
- genRawLit<TC, KIND>(con.At(subscripts));
- continue;
- }
- auto getElementVal = [&]() {
- return builder.createConvert(
- loc, eleTy,
- fir::getBase(genScalarLit<TC, KIND>(con.At(subscripts))));
- };
- Fortran::evaluate::ConstantSubscripts nextSubscripts = subscripts;
- bool nextIsSame = con.IncrementSubscripts(nextSubscripts) &&
- con.At(subscripts) == con.At(nextSubscripts);
- if (!rangeSize && !nextIsSame) { // single (non-range) value
- array = builder.create<fir::InsertValueOp>(
- loc, arrayTy, array, getElementVal(),
- builder.getArrayAttr(createIdx()));
- } else if (!rangeSize) { // start a range
- rangeStartIdx = createIdx();
- rangeSize = 1;
- } else if (nextIsSame) { // expand a range
- ++rangeSize;
- } else { // end a range
- llvm::SmallVector<int64_t> rangeBounds;
- llvm::SmallVector<mlir::Attribute> idx = createIdx();
- for (size_t i = 0; i < idx.size(); ++i) {
- rangeBounds.push_back(rangeStartIdx[i]
- .cast<mlir::IntegerAttr>()
- .getValue()
- .getSExtValue());
- rangeBounds.push_back(
- idx[i].cast<mlir::IntegerAttr>().getValue().getSExtValue());
- }
- array = builder.create<fir::InsertOnRangeOp>(
- loc, arrayTy, array, getElementVal(),
- builder.getIndexVectorAttr(rangeBounds));
- rangeSize = 0;
- }
- } while (con.IncrementSubscripts(subscripts));
- return fir::ArrayBoxValue{array, extents, lbounds};
- }
- }
-
fir::ExtendedValue genArrayLit(
const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
mlir::Location loc = getLoc();
ExtValue
genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
&con) {
- if (con.Rank() > 0)
- return genArrayLit(con);
- std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>>
- opt = con.GetScalarValue();
- assert(opt.has_value() && "constant has no value");
- if constexpr (TC == Fortran::common::TypeCategory::Character) {
- return genScalarLit<KIND>(opt.value(), con.LEN());
- } else {
- return genScalarLit<TC, KIND>(opt.value());
- }
+ return Fortran::lower::IntrinsicConstantBuilder<TC, KIND>::gen(
+ builder, getLoc(), con,
+ /*outlineBigConstantsInReadOnlyMemory=*/!inInitializer);
}
+
fir::ExtendedValue genval(
const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
if (con.Rank() > 0)
fir::FirOpBuilder &builder;
Fortran::lower::StatementContext &stmtCtx;
Fortran::lower::SymMap &symMap;
- InitializerData *inInitializer = nullptr;
+ bool inInitializer = false;
bool useBoxArg = false; // expression lowered as argument
};
} // namespace
};
}
- template <typename A>
- CC genarr(const Fortran::evaluate::Constant<A> &x) {
+ template <Fortran::common::TypeCategory TC, int KIND>
+ CC genarr(
+ const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> &x) {
+ if (x.Rank() == 0)
+ return genScalarAndForwardValue(x);
+ return genarr(Fortran::lower::IntrinsicConstantBuilder<TC, KIND>::gen(
+ builder, getLoc(), x,
+ /*outlineBigConstantsInReadOnlyMemory=*/true));
+ }
+
+ CC genarr(
+ const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &x) {
if (x.Rank() == 0)
return genScalarAndForwardValue(x);
mlir::Location loc = getLoc();
std::string globalName = Fortran::lower::mangle::mangleArrayLiteral(x);
fir::GlobalOp global = builder.getNamedGlobal(globalName);
if (!global) {
- mlir::Type symTy = arrTy;
- mlir::Type eleTy = symTy.cast<fir::SequenceType>().getEleTy();
- // If we have a rank-1 array of integer, real, or logical, then we can
- // create a global array with the dense attribute.
- //
- // The mlir tensor type can only handle integer, real, or logical. It
- // does not currently support nested structures which is required for
- // complex.
- //
- // Also, we currently handle just rank-1 since tensor type assumes
- // row major array ordering. We will need to reorder the dimensions
- // in the tensor type to support Fortran's column major array ordering.
- // How to create this tensor type is to be determined.
- if (x.Rank() == 1 &&
- eleTy.isa<fir::LogicalType, mlir::IntegerType, mlir::FloatType>())
- global = Fortran::lower::createDenseGlobal(
- loc, arrTy, globalName, builder.createInternalLinkage(), true,
- toEvExpr(x), converter);
- // Note: If call to createDenseGlobal() returns 0, then call
- // createGlobalConstant() below.
- if (!global)
- global = builder.createGlobalConstant(
- loc, arrTy, globalName,
- [&](fir::FirOpBuilder &builder) {
- Fortran::lower::StatementContext stmtCtx(
- /*cleanupProhibited=*/true);
- fir::ExtendedValue result =
- Fortran::lower::createSomeInitializerExpression(
- loc, converter, toEvExpr(x), symMap, stmtCtx);
- mlir::Value castTo =
- builder.createConvert(loc, arrTy, fir::getBase(result));
- builder.create<fir::HasValueOp>(loc, castTo);
- },
- builder.createInternalLinkage());
+ global = builder.createGlobalConstant(
+ loc, arrTy, globalName,
+ [&](fir::FirOpBuilder &builder) {
+ Fortran::lower::StatementContext stmtCtx(
+ /*cleanupProhibited=*/true);
+ fir::ExtendedValue result =
+ Fortran::lower::createSomeInitializerExpression(
+ loc, converter, toEvExpr(x), symMap, stmtCtx);
+ mlir::Value castTo =
+ builder.createConvert(loc, arrTy, fir::getBase(result));
+ builder.create<fir::HasValueOp>(loc, castTo);
+ },
+ builder.createInternalLinkage());
}
auto addr = builder.create<fir::AddrOfOp>(getLoc(), global.resultType(),
global.getSymbol());
return ScalarExprLowering{loc, converter, symMap, stmtCtx}.genval(expr);
}
-fir::GlobalOp Fortran::lower::createDenseGlobal(
- mlir::Location loc, mlir::Type symTy, llvm::StringRef globalName,
- mlir::StringAttr linkage, bool isConst,
- const Fortran::lower::SomeExpr &expr,
- Fortran::lower::AbstractConverter &converter) {
-
- Fortran::lower::StatementContext stmtCtx(/*prohibited=*/true);
- Fortran::lower::SymMap emptyMap;
- InitializerData initData(/*genRawVals=*/true);
- ScalarExprLowering sel(loc, converter, emptyMap, stmtCtx,
- /*initializer=*/&initData);
- sel.genval(expr);
-
- size_t sz = initData.rawVals.size();
- llvm::ArrayRef<mlir::Attribute> ar = {initData.rawVals.data(), sz};
-
- mlir::RankedTensorType tensorTy;
- auto &builder = converter.getFirOpBuilder();
- mlir::Type iTy = initData.rawType;
- if (!iTy)
- return 0; // array extent is probably 0 in this case, so just return 0.
- tensorTy = mlir::RankedTensorType::get(sz, iTy);
- auto init = mlir::DenseElementsAttr::get(tensorTy, ar);
- return builder.createGlobal(loc, symTy, globalName, linkage, init, isConst);
-}
-
fir::ExtendedValue Fortran::lower::createSomeInitializerExpression(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
Fortran::lower::StatementContext &stmtCtx) {
LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
- InitializerData initData; // needed for initializations
return ScalarExprLowering{loc, converter, symMap, stmtCtx,
- /*initializer=*/&initData}
+ /*inInitializer=*/true}
.genval(expr);
}
const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
Fortran::lower::StatementContext &stmtCtx) {
LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n');
- InitializerData init;
- return ScalarExprLowering(loc, converter, symMap, stmtCtx, &init).gen(expr);
+ return ScalarExprLowering(loc, converter, symMap, stmtCtx,
+ /*inInitializer=*/true)
+ .gen(expr);
}
void Fortran::lower::createSomeArrayAssignment(
#include "flang/Lower/Allocatable.h"
#include "flang/Lower/BoxAnalyzer.h"
#include "flang/Lower/CallInterface.h"
+#include "flang/Lower/ConvertConstant.h"
#include "flang/Lower/ConvertExpr.h"
#include "flang/Lower/IntrinsicCall.h"
#include "flang/Lower/Mangler.h"
const auto *details =
sym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
if (details->init()) {
- global = Fortran::lower::createDenseGlobal(
- loc, symTy, globalName, linkage, isConst, details->init().value(),
- converter);
+ global = Fortran::lower::tryCreatingDenseGlobal(
+ builder, loc, symTy, globalName, linkage, isConst,
+ details->init().value());
if (global) {
global.setVisibility(mlir::SymbolTable::Visibility::Public);
return global;
! CHECK-DAG: %[[VAL_2:.*]] = arith.constant 0 : index
! CHECK-DAG: %[[VAL_3:.*]] = arith.constant 0 : i32
! CHECK-DAG: %[[VAL_4:.*]] = arith.constant 8 : index
-! CHECK-DAG: %[[VAL_5:.*]] = arith.constant 8 : i64
! CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<1x!fir.char<1,12>>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.array<1x!fir.logical<4>> {bindc_name = "test", uniq_name = "_QFtestEtest"}
! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_19]] : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_20]] : (!fir.ref<!fir.char<1,8>>) -> !fir.ref<i8>
! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_4]] : (index) -> i64
-! CHECK: %[[VAL_24:.*]] = fir.call @_FortranACharacterCompareScalar1(%[[VAL_21]], %[[VAL_22]], %[[VAL_23]], %[[VAL_5]]) : (!fir.ref<i8>, !fir.ref<i8>, i64, i64) -> i32
+! CHECK: %[[VAL_24:.*]] = fir.call @_FortranACharacterCompareScalar1(%[[VAL_21]], %[[VAL_22]], %[[VAL_23]], %[[VAL_23]]) : (!fir.ref<i8>, !fir.ref<i8>, i64, i64) -> i32
! CHECK: %[[VAL_25:.*]] = arith.cmpi eq, %[[VAL_24]], %[[VAL_3]] : i32
! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i1) -> !fir.logical<4>
! CHECK: %[[VAL_27:.*]] = fir.array_coor %[[VAL_8]](%[[VAL_9]]) %[[VAL_15]] : (!fir.ref<!fir.array<1x!fir.logical<4>>>, !fir.shape<1>, index) -> !fir.ref<!fir.logical<4>>