Files
clang-p2996/flang/lib/Lower/ConvertExpr.cpp
Valentin Clement e9d2f17391 [flang] Lower complex constant
Add ability to lower complex constant.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D120402

Co-authored-by: Kiran Chandramohan <kiran.chandramohan@arm.com>
Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: Jean Perier <jperier@nvidia.com>
2022-02-23 18:03:30 +01:00

699 lines
26 KiB
C++

//===-- ConvertExpr.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/ConvertExpr.h"
#include "flang/Evaluate/fold.h"
#include "flang/Evaluate/real.h"
#include "flang/Evaluate/traverse.h"
#include "flang/Lower/AbstractConverter.h"
#include "flang/Lower/ConvertType.h"
#include "flang/Lower/IntrinsicCall.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Lower/Todo.h"
#include "flang/Optimizer/Builder/Complex.h"
#include "flang/Semantics/expression.h"
#include "flang/Semantics/symbol.h"
#include "flang/Semantics/tools.h"
#include "flang/Semantics/type.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "flang-lower-expr"
//===----------------------------------------------------------------------===//
// The composition and structure of Fortran::evaluate::Expr is defined in
// the various header files in include/flang/Evaluate. You are referred
// there for more information on these data structures. Generally speaking,
// these data structures are a strongly typed family of abstract data types
// that, composed as trees, describe the syntax of Fortran expressions.
//
// This part of the bridge can traverse these tree structures and lower them
// to the correct FIR representation in SSA form.
//===----------------------------------------------------------------------===//
/// Place \p exv in memory if it is not already a memory reference. If
/// \p forceValueType is provided, the value is first casted to the provided
/// type before being stored (this is mainly intended for logicals whose value
/// may be `i1` but needed to be stored as Fortran logicals).
static fir::ExtendedValue
placeScalarValueInMemory(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &exv,
mlir::Type storageType) {
mlir::Value valBase = fir::getBase(exv);
if (fir::conformsWithPassByRef(valBase.getType()))
return exv;
assert(!fir::hasDynamicSize(storageType) &&
"only expect statically sized scalars to be by value");
// Since `a` is not itself a valid referent, determine its value and
// create a temporary location at the beginning of the function for
// referencing.
mlir::Value val = builder.createConvert(loc, storageType, valBase);
mlir::Value temp = builder.createTemporary(
loc, storageType,
llvm::ArrayRef<mlir::NamedAttribute>{
Fortran::lower::getAdaptToByRefAttr(builder)});
builder.create<fir::StoreOp>(loc, val, temp);
return fir::substBase(exv, temp);
}
/// Generate a load of a value from an address. Beware that this will lose
/// any dynamic type information for polymorphic entities (note that unlimited
/// polymorphic cannot be loaded and must not be provided here).
static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::ExtendedValue &addr) {
return addr.match(
[](const fir::CharBoxValue &box) -> fir::ExtendedValue { return box; },
[&](const fir::UnboxedValue &v) -> fir::ExtendedValue {
if (fir::unwrapRefType(fir::getBase(v).getType())
.isa<fir::RecordType>())
return v;
return builder.create<fir::LoadOp>(loc, fir::getBase(v));
},
[&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
TODO(loc, "genLoad for MutableBoxValue");
},
[&](const fir::BoxValue &box) -> fir::ExtendedValue {
TODO(loc, "genLoad for BoxValue");
},
[&](const auto &) -> fir::ExtendedValue {
fir::emitFatalError(
loc, "attempting to load whole array or procedure address");
});
}
/// Is this a call to an elemental procedure with at least one array argument?
static bool
isElementalProcWithArrayArgs(const Fortran::evaluate::ProcedureRef &procRef) {
if (procRef.IsElemental())
for (const std::optional<Fortran::evaluate::ActualArgument> &arg :
procRef.arguments())
if (arg && arg->Rank() != 0)
return true;
return false;
}
namespace {
/// Lowering of Fortran::evaluate::Expr<T> expressions
class ScalarExprLowering {
public:
using ExtValue = fir::ExtendedValue;
explicit ScalarExprLowering(mlir::Location loc,
Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap)
: location{loc}, converter{converter},
builder{converter.getFirOpBuilder()}, symMap{symMap} {}
mlir::Location getLoc() { return location; }
template <typename A>
mlir::Value genunbox(const A &expr) {
ExtValue e = genval(expr);
if (const fir::UnboxedValue *r = e.getUnboxed())
return *r;
fir::emitFatalError(getLoc(), "unboxed expression expected");
}
/// Generate an integral constant of `value`
template <int KIND>
mlir::Value genIntegerConstant(mlir::MLIRContext *context,
std::int64_t value) {
mlir::Type type =
converter.genType(Fortran::common::TypeCategory::Integer, KIND);
return builder.createIntegerConstant(getLoc(), type, value);
}
/// Generate a logical/boolean constant of `value`
mlir::Value genBoolConstant(bool value) {
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);
}
/// Returns a reference to a symbol or its box/boxChar descriptor if it has
/// one.
ExtValue gen(Fortran::semantics::SymbolRef sym) {
if (Fortran::lower::SymbolBox val = symMap.lookupSymbol(sym))
return val.match([&val](auto &) { return val.toExtendedValue(); });
LLVM_DEBUG(llvm::dbgs()
<< "unknown symbol: " << sym << "\nmap: " << symMap << '\n');
fir::emitFatalError(getLoc(), "symbol is not mapped to any IR value");
}
ExtValue genLoad(const ExtValue &exv) {
return ::genLoad(builder, getLoc(), exv);
}
ExtValue genval(Fortran::semantics::SymbolRef sym) {
ExtValue var = gen(sym);
if (const fir::UnboxedValue *s = var.getUnboxed())
if (fir::isReferenceLike(s->getType()))
return genLoad(*s);
return var;
}
ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) {
TODO(getLoc(), "genval BOZ");
}
/// Return indirection to function designated in ProcedureDesignator.
/// The type of the function indirection is not guaranteed to match the one
/// of the ProcedureDesignator due to Fortran implicit typing rules.
ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) {
TODO(getLoc(), "genval ProcedureDesignator");
}
ExtValue genval(const Fortran::evaluate::NullPointer &) {
TODO(getLoc(), "genval NullPointer");
}
ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) {
TODO(getLoc(), "genval StructureConstructor");
}
/// Lowering of an <i>ac-do-variable</i>, which is not a Symbol.
ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) {
TODO(getLoc(), "genval ImpliedDoIndex");
}
ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) {
TODO(getLoc(), "genval DescriptorInquiry");
}
ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) {
TODO(getLoc(), "genval TypeParamInquiry");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) {
TODO(getLoc(), "genval ComplexComponent");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Integer, KIND>> &op) {
mlir::Value input = genunbox(op.left());
// Like LLVM, integer negation is the binary op "0 - value"
mlir::Value zero = genIntegerConstant<KIND>(builder.getContext(), 0);
return builder.create<mlir::arith::SubIOp>(getLoc(), zero, input);
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Real, KIND>> &op) {
return builder.create<mlir::arith::NegFOp>(getLoc(), genunbox(op.left()));
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Complex, KIND>> &op) {
return builder.create<fir::NegcOp>(getLoc(), genunbox(op.left()));
}
template <typename OpTy>
mlir::Value createBinaryOp(const ExtValue &left, const ExtValue &right) {
assert(fir::isUnboxedValue(left) && fir::isUnboxedValue(right));
mlir::Value lhs = fir::getBase(left);
mlir::Value rhs = fir::getBase(right);
assert(lhs.getType() == rhs.getType() && "types must be the same");
return builder.create<OpTy>(getLoc(), lhs, rhs);
}
template <typename OpTy, typename A>
mlir::Value createBinaryOp(const A &ex) {
ExtValue left = genval(ex.left());
return createBinaryOp<OpTy>(left, genval(ex.right()));
}
#undef GENBIN
#define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \
template <int KIND> \
ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \
Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \
return createBinaryOp<GenBinFirOp>(x); \
}
GENBIN(Add, Integer, mlir::arith::AddIOp)
GENBIN(Add, Real, mlir::arith::AddFOp)
GENBIN(Add, Complex, fir::AddcOp)
GENBIN(Subtract, Integer, mlir::arith::SubIOp)
GENBIN(Subtract, Real, mlir::arith::SubFOp)
GENBIN(Subtract, Complex, fir::SubcOp)
GENBIN(Multiply, Integer, mlir::arith::MulIOp)
GENBIN(Multiply, Real, mlir::arith::MulFOp)
GENBIN(Multiply, Complex, fir::MulcOp)
GENBIN(Divide, Integer, mlir::arith::DivSIOp)
GENBIN(Divide, Real, mlir::arith::DivFOp)
GENBIN(Divide, Complex, fir::DivcOp)
template <Fortran::common::TypeCategory TC, int KIND>
ExtValue genval(
const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) {
TODO(getLoc(), "genval Power");
}
template <Fortran::common::TypeCategory TC, int KIND>
ExtValue genval(
const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
&op) {
TODO(getLoc(), "genval RealToInt");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) {
mlir::Value realPartValue = genunbox(op.left());
return fir::factory::Complex{builder, getLoc()}.createComplex(
KIND, realPartValue, genunbox(op.right()));
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) {
TODO(getLoc(), "genval Concat<KIND>");
}
/// MIN and MAX operations
template <Fortran::common::TypeCategory TC, int KIND>
ExtValue
genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>
&op) {
TODO(getLoc(), "genval Extremum<TC, KIND>");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) {
TODO(getLoc(), "genval SetLength<KIND>");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Integer, KIND>> &op) {
TODO(getLoc(), "genval integer comparison");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Real, KIND>> &op) {
TODO(getLoc(), "genval real comparison");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Complex, KIND>> &op) {
TODO(getLoc(), "genval complex comparison");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Character, KIND>> &op) {
TODO(getLoc(), "genval char comparison");
}
ExtValue
genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) {
TODO(getLoc(), "genval comparison");
}
template <Fortran::common::TypeCategory TC1, int KIND,
Fortran::common::TypeCategory TC2>
ExtValue
genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>,
TC2> &convert) {
mlir::Type ty = converter.genType(TC1, KIND);
mlir::Value operand = genunbox(convert.left());
return builder.convertWithSemantics(getLoc(), ty, operand);
}
template <typename A>
ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) {
TODO(getLoc(), "genval parentheses<A>");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Not<KIND> &op) {
TODO(getLoc(), "genval Not<KIND>");
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) {
TODO(getLoc(), "genval LogicalOperation<KIND>");
}
/// 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) {
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) {
llvm::APFloat floatVal{llvm::APFloatBase::IEEEhalf(), str};
return genRealConstant<KIND>(builder.getContext(), floatVal);
} else if constexpr (KIND == 3) {
llvm::APFloat floatVal{llvm::APFloatBase::BFloat(), str};
return genRealConstant<KIND>(builder.getContext(), floatVal);
} else if constexpr (KIND == 4) {
llvm::APFloat floatVal{llvm::APFloatBase::IEEEsingle(), str};
return genRealConstant<KIND>(builder.getContext(), floatVal);
} else if constexpr (KIND == 10) {
llvm::APFloat floatVal{llvm::APFloatBase::x87DoubleExtended(), str};
return genRealConstant<KIND>(builder.getContext(), floatVal);
} else if constexpr (KIND == 16) {
llvm::APFloat floatVal{llvm::APFloatBase::IEEEquad(), str};
return genRealConstant<KIND>(builder.getContext(), floatVal);
} else {
// convert everything else to double
llvm::APFloat floatVal{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 a ascii scalar literal CHARACTER to IR. (specialization)
ExtValue
genAsciiScalarLit(const Fortran::evaluate::Scalar<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Character, 1>> &value,
int64_t len) {
assert(value.size() == static_cast<std::uint64_t>(len) &&
"value.size() doesn't match with len");
return fir::factory::createStringLiteral(builder, getLoc(), value);
}
template <Fortran::common::TypeCategory TC, int KIND>
ExtValue
genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
&con) {
if (con.Rank() > 0)
TODO(getLoc(), "genval array constant");
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) {
if constexpr (KIND == 1)
return genAsciiScalarLit(opt.value(), con.LEN());
TODO(getLoc(), "genval for Character with KIND != 1");
} else {
return genScalarLit<TC, KIND>(opt.value());
}
}
fir::ExtendedValue genval(
const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
TODO(getLoc(), "genval constant derived");
}
template <typename A>
ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) {
TODO(getLoc(), "genval ArrayConstructor<A>");
}
ExtValue gen(const Fortran::evaluate::ComplexPart &x) {
TODO(getLoc(), "gen ComplexPart");
}
ExtValue genval(const Fortran::evaluate::ComplexPart &x) {
TODO(getLoc(), "genval ComplexPart");
}
ExtValue gen(const Fortran::evaluate::Substring &s) {
TODO(getLoc(), "gen Substring");
}
ExtValue genval(const Fortran::evaluate::Substring &ss) {
TODO(getLoc(), "genval Substring");
}
ExtValue genval(const Fortran::evaluate::Subscript &subs) {
TODO(getLoc(), "genval Subscript");
}
ExtValue gen(const Fortran::evaluate::DataRef &dref) {
TODO(getLoc(), "gen DataRef");
}
ExtValue genval(const Fortran::evaluate::DataRef &dref) {
TODO(getLoc(), "genval DataRef");
}
ExtValue gen(const Fortran::evaluate::Component &cmpt) {
TODO(getLoc(), "gen Component");
}
ExtValue genval(const Fortran::evaluate::Component &cmpt) {
TODO(getLoc(), "genval Component");
}
ExtValue genval(const Fortran::semantics::Bound &bound) {
TODO(getLoc(), "genval Bound");
}
ExtValue gen(const Fortran::evaluate::ArrayRef &aref) {
TODO(getLoc(), "gen ArrayRef");
}
ExtValue genval(const Fortran::evaluate::ArrayRef &aref) {
TODO(getLoc(), "genval ArrayRef");
}
ExtValue gen(const Fortran::evaluate::CoarrayRef &coref) {
TODO(getLoc(), "gen CoarrayRef");
}
ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) {
TODO(getLoc(), "genval CoarrayRef");
}
template <typename A>
ExtValue gen(const Fortran::evaluate::Designator<A> &des) {
return std::visit([&](const auto &x) { return gen(x); }, des.u);
}
template <typename A>
ExtValue genval(const Fortran::evaluate::Designator<A> &des) {
return std::visit([&](const auto &x) { return genval(x); }, des.u);
}
mlir::Type genType(const Fortran::evaluate::DynamicType &dt) {
if (dt.category() != Fortran::common::TypeCategory::Derived)
return converter.genType(dt.category(), dt.kind());
TODO(getLoc(), "genType Derived Type");
}
/// Lower a function reference
template <typename A>
ExtValue genFunctionRef(const Fortran::evaluate::FunctionRef<A> &funcRef) {
if (!funcRef.GetType().has_value())
fir::emitFatalError(getLoc(), "internal: a function must have a type");
mlir::Type resTy = genType(*funcRef.GetType());
return genProcedureRef(funcRef, {resTy});
}
/// Lower function call `funcRef` and return a reference to the resultant
/// value. This is required for lowering expressions such as `f1(f2(v))`.
template <typename A>
ExtValue gen(const Fortran::evaluate::FunctionRef<A> &funcRef) {
TODO(getLoc(), "gen FunctionRef<A>");
}
template <typename A>
ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) {
ExtValue result = genFunctionRef(funcRef);
if (result.rank() == 0 && fir::isa_ref_type(fir::getBase(result).getType()))
return genLoad(result);
return result;
}
ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) {
TODO(getLoc(), "genval ProcedureRef");
}
/// Generate a call to an intrinsic function.
ExtValue
genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef,
const Fortran::evaluate::SpecificIntrinsic &intrinsic,
llvm::Optional<mlir::Type> resultType) {
llvm::SmallVector<ExtValue> operands;
llvm::StringRef name = intrinsic.name;
mlir::Location loc = getLoc();
const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering =
Fortran::lower::getIntrinsicArgumentLowering(name);
for (const auto &[arg, dummy] :
llvm::zip(procRef.arguments(),
intrinsic.characteristics.value().dummyArguments)) {
auto *expr = Fortran::evaluate::UnwrapExpr<Fortran::lower::SomeExpr>(arg);
if (!expr) {
// Absent optional.
operands.emplace_back(Fortran::lower::getAbsentIntrinsicArgument());
continue;
}
if (!argLowering) {
// No argument lowering instruction, lower by value.
operands.emplace_back(genval(*expr));
continue;
}
// Ad-hoc argument lowering handling.
Fortran::lower::ArgLoweringRule argRules =
Fortran::lower::lowerIntrinsicArgumentAs(loc, *argLowering,
dummy.name);
switch (argRules.lowerAs) {
case Fortran::lower::LowerIntrinsicArgAs::Value:
operands.emplace_back(genval(*expr));
continue;
case Fortran::lower::LowerIntrinsicArgAs::Addr:
TODO(getLoc(), "argument lowering for Addr");
continue;
case Fortran::lower::LowerIntrinsicArgAs::Box:
TODO(getLoc(), "argument lowering for Box");
continue;
case Fortran::lower::LowerIntrinsicArgAs::Inquired:
TODO(getLoc(), "argument lowering for Inquired");
continue;
}
llvm_unreachable("bad switch");
}
// Let the intrinsic library lower the intrinsic procedure call
return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType,
operands);
}
template <typename A>
ExtValue genval(const Fortran::evaluate::Expr<A> &x) {
if (isScalar(x))
return std::visit([&](const auto &e) { return genval(e); }, x.u);
TODO(getLoc(), "genval Expr<A> arrays");
}
/// Lower a non-elemental procedure reference.
// TODO: Handle read allocatable and pointer results.
ExtValue genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
llvm::Optional<mlir::Type> resultType) {
ExtValue res = genRawProcedureRef(procRef, resultType);
return res;
}
/// Lower a non-elemental procedure reference.
ExtValue genRawProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
llvm::Optional<mlir::Type> resultType) {
mlir::Location loc = getLoc();
if (isElementalProcWithArrayArgs(procRef))
fir::emitFatalError(loc, "trying to lower elemental procedure with array "
"arguments as normal procedure");
if (const Fortran::evaluate::SpecificIntrinsic *intrinsic =
procRef.proc().GetSpecificIntrinsic())
return genIntrinsicRef(procRef, *intrinsic, resultType);
return {};
}
/// Helper to detect Transformational function reference.
template <typename T>
bool isTransformationalRef(const T &) {
return false;
}
template <typename T>
bool isTransformationalRef(const Fortran::evaluate::FunctionRef<T> &funcRef) {
return !funcRef.IsElemental() && funcRef.Rank();
}
template <typename T>
bool isTransformationalRef(Fortran::evaluate::Expr<T> expr) {
return std::visit([&](const auto &e) { return isTransformationalRef(e); },
expr.u);
}
template <typename A>
ExtValue gen(const Fortran::evaluate::Expr<A> &x) {
// Whole array symbols or components, and results of transformational
// functions already have a storage and the scalar expression lowering path
// is used to not create a new temporary storage.
if (isScalar(x) ||
Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(x) ||
isTransformationalRef(x))
return std::visit([&](const auto &e) { return genref(e); }, x.u);
TODO(getLoc(), "gen Expr non-scalar");
}
template <typename A>
bool isScalar(const A &x) {
return x.Rank() == 0;
}
template <int KIND>
ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type<
Fortran::common::TypeCategory::Logical, KIND>> &exp) {
return std::visit([&](const auto &e) { return genval(e); }, exp.u);
}
using RefSet =
std::tuple<Fortran::evaluate::ComplexPart, Fortran::evaluate::Substring,
Fortran::evaluate::DataRef, Fortran::evaluate::Component,
Fortran::evaluate::ArrayRef, Fortran::evaluate::CoarrayRef,
Fortran::semantics::SymbolRef>;
template <typename A>
static constexpr bool inRefSet = Fortran::common::HasMember<A, RefSet>;
template <typename A, typename = std::enable_if_t<inRefSet<A>>>
ExtValue genref(const A &a) {
return gen(a);
}
template <typename A>
ExtValue genref(const A &a) {
mlir::Type storageType = converter.genType(toEvExpr(a));
return placeScalarValueInMemory(builder, getLoc(), genval(a), storageType);
}
template <typename A, template <typename> typename T,
typename B = std::decay_t<T<A>>,
std::enable_if_t<
std::is_same_v<B, Fortran::evaluate::Expr<A>> ||
std::is_same_v<B, Fortran::evaluate::Designator<A>> ||
std::is_same_v<B, Fortran::evaluate::FunctionRef<A>>,
bool> = true>
ExtValue genref(const T<A> &x) {
return gen(x);
}
private:
mlir::Location location;
Fortran::lower::AbstractConverter &converter;
fir::FirOpBuilder &builder;
Fortran::lower::SymMap &symMap;
};
} // namespace
fir::ExtendedValue Fortran::lower::createSomeExtendedExpression(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) {
LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
return ScalarExprLowering{loc, converter, symMap}.genval(expr);
}
fir::ExtendedValue Fortran::lower::createSomeExtendedAddress(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) {
LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "address: ") << '\n');
return ScalarExprLowering{loc, converter, symMap}.gen(expr);
}