//===-- 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/SymbolMap.h" #include "flang/Lower/Todo.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. //===----------------------------------------------------------------------===// /// 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()) return v; return builder.create(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"); }); } namespace { /// Lowering of Fortran::evaluate::Expr 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; } /// Generate an integral constant of `value` template 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); } /// 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 ac-do-variable, 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 ExtValue genval(const Fortran::evaluate::ComplexComponent &part) { TODO(getLoc(), "genval ComplexComponent"); } template ExtValue genval(const Fortran::evaluate::Negate> &op) { TODO(getLoc(), "genval Negate integer"); } template ExtValue genval(const Fortran::evaluate::Negate> &op) { TODO(getLoc(), "genval Negate real"); } template ExtValue genval(const Fortran::evaluate::Negate> &op) { TODO(getLoc(), "genval Negate complex"); } #undef GENBIN #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ template \ ExtValue genval(const Fortran::evaluate::GenBinEvOp> &x) { \ TODO(getLoc(), "genval GenBinEvOp"); \ } 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 ExtValue genval( const Fortran::evaluate::Power> &op) { TODO(getLoc(), "genval Power"); } template ExtValue genval( const Fortran::evaluate::RealToIntPower> &op) { TODO(getLoc(), "genval RealToInt"); } template ExtValue genval(const Fortran::evaluate::ComplexConstructor &op) { TODO(getLoc(), "genval ComplexConstructor"); } template ExtValue genval(const Fortran::evaluate::Concat &op) { TODO(getLoc(), "genval Concat"); } /// MIN and MAX operations template ExtValue genval(const Fortran::evaluate::Extremum> &op) { TODO(getLoc(), "genval Extremum"); } template ExtValue genval(const Fortran::evaluate::SetLength &x) { TODO(getLoc(), "genval SetLength"); } template ExtValue genval(const Fortran::evaluate::Relational> &op) { TODO(getLoc(), "genval integer comparison"); } template ExtValue genval(const Fortran::evaluate::Relational> &op) { TODO(getLoc(), "genval real comparison"); } template ExtValue genval(const Fortran::evaluate::Relational> &op) { TODO(getLoc(), "genval complex comparison"); } template ExtValue genval(const Fortran::evaluate::Relational> &op) { TODO(getLoc(), "genval char comparison"); } ExtValue genval(const Fortran::evaluate::Relational &op) { TODO(getLoc(), "genval comparison"); } template ExtValue genval(const Fortran::evaluate::Convert, TC2> &convert) { TODO(getLoc(), "genval convert"); } template ExtValue genval(const Fortran::evaluate::Parentheses &op) { TODO(getLoc(), "genval parentheses"); } template ExtValue genval(const Fortran::evaluate::Not &op) { TODO(getLoc(), "genval Not"); } template ExtValue genval(const Fortran::evaluate::LogicalOperation &op) { TODO(getLoc(), "genval LogicalOperation"); } /// Convert a scalar literal constant to IR. template ExtValue genScalarLit( const Fortran::evaluate::Scalar> &value) { if constexpr (TC == Fortran::common::TypeCategory::Integer) { return genIntegerConstant(builder.getContext(), value.ToInt64()); } else if constexpr (TC == Fortran::common::TypeCategory::Logical) { return genBoolConstant(value.IsTrue()); } else if constexpr (TC == Fortran::common::TypeCategory::Real) { TODO(getLoc(), "genval real constant"); } else if constexpr (TC == Fortran::common::TypeCategory::Complex) { TODO(getLoc(), "genval complex constant"); } else /*constexpr*/ { llvm_unreachable("unhandled constant"); } } /// Convert a ascii scalar literal CHARACTER to IR. (specialization) ExtValue genAsciiScalarLit(const Fortran::evaluate::Scalar> &value, int64_t len) { assert(value.size() == static_cast(len) && "value.size() doesn't match with len"); return fir::factory::createStringLiteral(builder, getLoc(), value); } template ExtValue genval(const Fortran::evaluate::Constant> &con) { if (con.Rank() > 0) TODO(getLoc(), "genval array constant"); std::optional>> 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(opt.value()); } } fir::ExtendedValue genval( const Fortran::evaluate::Constant &con) { TODO(getLoc(), "genval constant derived"); } template ExtValue genval(const Fortran::evaluate::ArrayConstructor &) { TODO(getLoc(), "genval ArrayConstructor"); } ExtValue genval(const Fortran::evaluate::ComplexPart &x) { TODO(getLoc(), "genval ComplexPart"); } ExtValue genval(const Fortran::evaluate::Substring &ss) { TODO(getLoc(), "genval Substring"); } ExtValue genval(const Fortran::evaluate::Subscript &subs) { TODO(getLoc(), "genval Subscript"); } ExtValue genval(const Fortran::evaluate::DataRef &dref) { TODO(getLoc(), "genval DataRef"); } ExtValue genval(const Fortran::evaluate::Component &cmpt) { TODO(getLoc(), "genval Component"); } ExtValue genval(const Fortran::semantics::Bound &bound) { TODO(getLoc(), "genval Bound"); } ExtValue genval(const Fortran::evaluate::ArrayRef &aref) { TODO(getLoc(), "genval ArrayRef"); } ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) { TODO(getLoc(), "genval CoarrayRef"); } template ExtValue genval(const Fortran::evaluate::Designator &des) { return std::visit([&](const auto &x) { return genval(x); }, des.u); } template ExtValue genval(const Fortran::evaluate::FunctionRef &funcRef) { TODO(getLoc(), "genval FunctionRef"); } ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) { TODO(getLoc(), "genval ProcedureRef"); } template bool isScalar(const A &x) { return x.Rank() == 0; } template ExtValue genval(const Fortran::evaluate::Expr &x) { if (isScalar(x)) return std::visit([&](const auto &e) { return genval(e); }, x.u); TODO(getLoc(), "genval Expr arrays"); } template ExtValue genval(const Fortran::evaluate::Expr> &exp) { return std::visit([&](const auto &e) { return genval(e); }, exp.u); } 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); }