//===-- lib/Evaluate/fold-logical.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 // //===----------------------------------------------------------------------===// #include "fold-implementation.h" #include "flang/Evaluate/check-expression.h" namespace Fortran::evaluate { template Expr> FoldIntrinsicFunction( FoldingContext &context, FunctionRef> &&funcRef) { using T = Type; ActualArguments &args{funcRef.arguments()}; auto *intrinsic{std::get_if(&funcRef.proc().u)}; CHECK(intrinsic); std::string name{intrinsic->name}; if (name == "all") { if (!args[1]) { // TODO: ALL(x,DIM=d) if (const auto *constant{UnwrapConstantValue(args[0])}) { bool result{true}; for (const auto &element : constant->values()) { if (!element.IsTrue()) { result = false; break; } } return Expr{result}; } } } else if (name == "any") { if (!args[1]) { // TODO: ANY(x,DIM=d) if (const auto *constant{UnwrapConstantValue(args[0])}) { bool result{false}; for (const auto &element : constant->values()) { if (element.IsTrue()) { result = true; break; } } return Expr{result}; } } } else if (name == "bge" || name == "bgt" || name == "ble" || name == "blt") { using LargestInt = Type; static_assert(std::is_same_v, BOZLiteralConstant>); // Arguments do not have to be of the same integer type. Convert all // arguments to the biggest integer type before comparing them to // simplify. for (int i{0}; i <= 1; ++i) { if (auto *x{UnwrapExpr>(args[i])}) { *args[i] = AsGenericExpr( Fold(context, ConvertToType(std::move(*x)))); } else if (auto *x{UnwrapExpr(args[i])}) { *args[i] = AsGenericExpr(Constant{std::move(*x)}); } } auto fptr{&Scalar::BGE}; if (name == "bge") { // done in fptr declaration } else if (name == "bgt") { fptr = &Scalar::BGT; } else if (name == "ble") { fptr = &Scalar::BLE; } else if (name == "blt") { fptr = &Scalar::BLT; } else { common::die("missing case to fold intrinsic function %s", name.c_str()); } return FoldElementalIntrinsic(context, std::move(funcRef), ScalarFunc( [&fptr](const Scalar &i, const Scalar &j) { return Scalar{std::invoke(fptr, i, j)}; })); } else if (name == "is_contiguous") { if (args.at(0)) { if (auto *expr{args[0]->UnwrapExpr()}) { if (IsSimplyContiguous(*expr, context.intrinsics())) { return Expr{true}; } } } } else if (name == "merge") { return FoldMerge(context, std::move(funcRef)); } // TODO: btest, cshift, dot_product, eoshift, is_iostat_end, // is_iostat_eor, lge, lgt, lle, llt, logical, matmul, out_of_range, // pack, parity, reduce, spread, transfer, transpose, unpack, // extends_type_of, same_type_as return Expr{std::move(funcRef)}; } template Expr FoldOperation( FoldingContext &context, Relational &&relation) { if (auto array{ApplyElementwise(context, relation, std::function(Expr &&, Expr &&)>{ [=](Expr &&x, Expr &&y) { return Expr{Relational{ Relational{relation.opr, std::move(x), std::move(y)}}}; }})}) { return *array; } if (auto folded{OperandsAreConstants(relation)}) { bool result{}; if constexpr (T::category == TypeCategory::Integer) { result = Satisfies(relation.opr, folded->first.CompareSigned(folded->second)); } else if constexpr (T::category == TypeCategory::Real) { result = Satisfies(relation.opr, folded->first.Compare(folded->second)); } else if constexpr (T::category == TypeCategory::Character) { result = Satisfies(relation.opr, Compare(folded->first, folded->second)); } else { static_assert(T::category != TypeCategory::Complex && T::category != TypeCategory::Logical); } return Expr{Constant{result}}; } return Expr{Relational{std::move(relation)}}; } Expr FoldOperation( FoldingContext &context, Relational &&relation) { return std::visit( [&](auto &&x) { return Expr{FoldOperation(context, std::move(x))}; }, std::move(relation.u)); } template Expr> FoldOperation( FoldingContext &context, Not &&x) { if (auto array{ApplyElementwise(context, x)}) { return *array; } using Ty = Type; auto &operand{x.left()}; if (auto value{GetScalarConstantValue(operand)}) { return Expr{Constant{!value->IsTrue()}}; } return Expr{x}; } template Expr> FoldOperation( FoldingContext &context, LogicalOperation &&operation) { using LOGICAL = Type; if (auto array{ApplyElementwise(context, operation, std::function(Expr &&, Expr &&)>{ [=](Expr &&x, Expr &&y) { return Expr{LogicalOperation{ operation.logicalOperator, std::move(x), std::move(y)}}; }})}) { return *array; } if (auto folded{OperandsAreConstants(operation)}) { bool xt{folded->first.IsTrue()}, yt{folded->second.IsTrue()}, result{}; switch (operation.logicalOperator) { case LogicalOperator::And: result = xt && yt; break; case LogicalOperator::Or: result = xt || yt; break; case LogicalOperator::Eqv: result = xt == yt; break; case LogicalOperator::Neqv: result = xt != yt; break; case LogicalOperator::Not: DIE("not a binary operator"); } return Expr{Constant{result}}; } return Expr{std::move(operation)}; } FOR_EACH_LOGICAL_KIND(template class ExpressionBase, ) template class ExpressionBase; }