[flang-commits] [flang] [flang] preserve logical operations in single FIR operation (PR #190771)
via flang-commits
flang-commits at lists.llvm.org
Tue Apr 7 03:47:08 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
@llvm/pr-subscribers-flang-openmp
Author: jeanPerier
<details>
<summary>Changes</summary>
This patch adds new operations to represent AND/OR/EQV/NEQV logical operation with the main goal of preserving them at a higher level in the IR to make it easier to match them and to dispatch them to atomic implementations when working on reductions.
They are only generated when one of the argument is actually a logical, otherwise, the when dealing with AND/OR... where both operands are comparisons, the i1 arith operations are still generated since using the new operation would make the IR more complex and preserving logical operation is only valuable when one of the operand is a logical variable.
---
Patch is 106.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/190771.diff
27 Files Affected:
- (modified) flang/include/flang/Optimizer/Dialect/FIROps.td (+71)
- (modified) flang/include/flang/Optimizer/Dialect/FIRTypes.td (+3)
- (modified) flang/lib/Lower/ConvertExprToHLFIR.cpp (+27-1)
- (modified) flang/lib/Lower/Support/ReductionProcessor.cpp (+12-27)
- (modified) flang/lib/Optimizer/CodeGen/CodeGen.cpp (+132-13)
- (modified) flang/lib/Optimizer/Dialect/FIROps.cpp (+76)
- (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp (+7-24)
- (modified) flang/lib/Optimizer/Transforms/FIRToMemRef.cpp (+36-4)
- (modified) flang/test/Fir/fir-ops.fir (+22)
- (modified) flang/test/Fir/invalid.fir (+17)
- (modified) flang/test/Fir/logical-convert.fir (+75)
- (modified) flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 (+6-8)
- (modified) flang/test/Lower/HLFIR/binary-ops.f90 (+4-6)
- (modified) flang/test/Lower/HLFIR/expr-box.f90 (+2-3)
- (modified) flang/test/Lower/HLFIR/user-defined-assignment.f90 (+2-5)
- (modified) flang/test/Lower/OpenACC/acc-reduction.f90 (+10-25)
- (modified) flang/test/Lower/OpenMP/atomic-update-reassoc-logical.f90 (+12-33)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-and-byref.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv-byref.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv-byref.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-or-byref.f90 (+12-30)
- (modified) flang/test/Lower/OpenMP/wsloop-reduction-logical-or.f90 (+12-30)
- (modified) flang/test/Lower/array-elemental-calls-2.f90 (+2-5)
- (modified) flang/test/Transforms/FIRToMemRef/logical.mlir (+28)
``````````diff
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index f499be9fb5dd2..aa371511dc2d8 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -2845,6 +2845,77 @@ def fir_DivcOp : ComplexArithmeticOp<"divc",
[DeclareOpInterfaceMethods<ArithFastMathInterface>]>;
// Pow is a builtin call and not a primitive
+// Logical operations
+
+class LogicalBinaryOp<string mnemonic, list<Trait> traits = []> :
+ fir_ArithmeticOp<mnemonic, traits>,
+ Arguments<(ins AnyLogicalOrIntegerLike:$lhs,
+ AnyLogicalOrIntegerLike:$rhs)>;
+
+def fir_LogicalAndOp : LogicalBinaryOp<"logical_and", [Commutative]> {
+ let summary = "logical AND";
+
+ let description = [{
+ Logical AND of two values of fir.logical or integer type.
+ Both operands and the result must have the same type.
+
+ ```
+ %r = fir.logical_and %a, %b : !fir.logical<4>
+ %s = fir.logical_and %x, %y : i32
+ ```
+ }];
+
+ let hasFolder = 1;
+}
+
+def fir_LogicalOrOp : LogicalBinaryOp<"logical_or", [Commutative]> {
+ let summary = "logical OR";
+
+ let description = [{
+ Logical OR of two values of fir.logical or integer type.
+ Both operands and the result must have the same type.
+
+ ```
+ %r = fir.logical_or %a, %b : !fir.logical<4>
+ %s = fir.logical_or %x, %y : i32
+ ```
+ }];
+
+ let hasFolder = 1;
+}
+
+def fir_EqvOp : LogicalBinaryOp<"eqv", [Commutative]> {
+ let summary = "logical equivalence";
+
+ let description = [{
+ Logical equivalence (EQV) of two values of fir.logical or integer type.
+ Both operands and the result must have the same type.
+
+ ```
+ %r = fir.eqv %a, %b : !fir.logical<4>
+ %s = fir.eqv %x, %y : i32
+ ```
+ }];
+
+ let hasFolder = 1;
+}
+
+def fir_NeqvOp : LogicalBinaryOp<"neqv", [Commutative]> {
+ let summary = "logical non-equivalence";
+
+ let description = [{
+ Logical non-equivalence (NEQV / XOR) of two values of fir.logical or
+ integer type. Both operands and the result must have the same type.
+
+ ```
+ %r = fir.neqv %a, %b : !fir.logical<4>
+ %s = fir.neqv %x, %y : i32
+ ```
+ }];
+
+ let hasFolder = 1;
+}
+
def fir_CmpcOp : fir_Op<"cmpc",
[NoMemoryEffect, SameTypeOperands, SameOperandsAndResultShape,
DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
index 7c7fe706d29d4..c58d75851349e 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
@@ -602,6 +602,9 @@ def AnyLogicalLike : TypeConstraint<Or<[BoolLike.predicate,
def AnyRealLike : TypeConstraint<FloatLike.predicate, "any real">;
def AnyIntegerType : Type<AnyIntegerLike.predicate, "any integer">;
def AnyLogicalType : Type<AnyLogicalLike.predicate, "any logical">;
+def AnyLogicalOrIntegerLike : TypeConstraint<Or<[
+ fir_LogicalType.predicate,
+ SignlessIntegerLike.predicate]>, "fir.logical or signless integer">;
def AnyFirComplexLike : TypeConstraint<CPred<"::fir::isa_complex($_self)">,
"any floating point complex type">;
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 0c015bc9a2f1b..1251190ac183d 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1326,6 +1326,33 @@ struct BinaryOp<Fortran::evaluate::LogicalOperation<KIND>> {
fir::FirOpBuilder &builder,
const Op &op, hlfir::Entity lhs,
hlfir::Entity rhs) {
+ bool lhsIsLogical = mlir::isa<fir::LogicalType>(lhs.getType());
+ bool rhsIsLogical = mlir::isa<fir::LogicalType>(rhs.getType());
+ if (lhsIsLogical || rhsIsLogical) {
+ // Use fir logical ops when at least one operand is a Fortran LOGICAL.
+ // Ensure both operands have the same type.
+ mlir::Type resTy = lhsIsLogical ? lhs.getType() : rhs.getType();
+ mlir::Value lhsVal = builder.createConvert(loc, resTy, lhs);
+ mlir::Value rhsVal = builder.createConvert(loc, resTy, rhs);
+ switch (op.logicalOperator) {
+ case Fortran::evaluate::LogicalOperator::And:
+ return hlfir::EntityWithAttributes{
+ fir::LogicalAndOp::create(builder, loc, resTy, lhsVal, rhsVal)};
+ case Fortran::evaluate::LogicalOperator::Or:
+ return hlfir::EntityWithAttributes{
+ fir::LogicalOrOp::create(builder, loc, resTy, lhsVal, rhsVal)};
+ case Fortran::evaluate::LogicalOperator::Eqv:
+ return hlfir::EntityWithAttributes{
+ fir::EqvOp::create(builder, loc, resTy, lhsVal, rhsVal)};
+ case Fortran::evaluate::LogicalOperator::Neqv:
+ return hlfir::EntityWithAttributes{
+ fir::NeqvOp::create(builder, loc, resTy, lhsVal, rhsVal)};
+ case Fortran::evaluate::LogicalOperator::Not:
+ llvm_unreachable(".NOT. is not a binary operator");
+ }
+ llvm_unreachable("unhandled logical operation");
+ }
+ // Both operands are i1 (from arithmetic comparisons): use arith ops.
mlir::Type i1Type = builder.getI1Type();
mlir::Value i1Lhs = builder.createConvert(loc, i1Type, lhs);
mlir::Value i1Rhs = builder.createConvert(loc, i1Type, rhs);
@@ -1343,7 +1370,6 @@ struct BinaryOp<Fortran::evaluate::LogicalOperation<KIND>> {
return hlfir::EntityWithAttributes{mlir::arith::CmpIOp::create(
builder, loc, mlir::arith::CmpIPredicate::ne, i1Lhs, i1Rhs)};
case Fortran::evaluate::LogicalOperator::Not:
- // lib/evaluate expression for .NOT. is Fortran::evaluate::Not<KIND>.
llvm_unreachable(".NOT. is not a binary operator");
}
llvm_unreachable("unhandled logical operation");
diff --git a/flang/lib/Lower/Support/ReductionProcessor.cpp b/flang/lib/Lower/Support/ReductionProcessor.cpp
index e0cba4c512258..04efba463de49 100644
--- a/flang/lib/Lower/Support/ReductionProcessor.cpp
+++ b/flang/lib/Lower/Support/ReductionProcessor.cpp
@@ -322,42 +322,27 @@ mlir::Value ReductionProcessor::createScalarCombiner(
fir::MulcOp>(builder, type, loc, op1, op2);
break;
case ReductionIdentifier::AND: {
- mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
- mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
-
- mlir::Value andiOp =
- mlir::arith::AndIOp::create(builder, loc, op1I1, op2I1);
-
- reductionOp = builder.createConvert(loc, type, andiOp);
+ mlir::Value v1 = builder.createConvert(loc, type, op1);
+ mlir::Value v2 = builder.createConvert(loc, type, op2);
+ reductionOp = fir::LogicalAndOp::create(builder, loc, type, v1, v2);
break;
}
case ReductionIdentifier::OR: {
- mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
- mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
-
- mlir::Value oriOp = mlir::arith::OrIOp::create(builder, loc, op1I1, op2I1);
-
- reductionOp = builder.createConvert(loc, type, oriOp);
+ mlir::Value v1 = builder.createConvert(loc, type, op1);
+ mlir::Value v2 = builder.createConvert(loc, type, op2);
+ reductionOp = fir::LogicalOrOp::create(builder, loc, type, v1, v2);
break;
}
case ReductionIdentifier::EQV: {
- mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
- mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
-
- mlir::Value cmpiOp = mlir::arith::CmpIOp::create(
- builder, loc, mlir::arith::CmpIPredicate::eq, op1I1, op2I1);
-
- reductionOp = builder.createConvert(loc, type, cmpiOp);
+ mlir::Value v1 = builder.createConvert(loc, type, op1);
+ mlir::Value v2 = builder.createConvert(loc, type, op2);
+ reductionOp = fir::EqvOp::create(builder, loc, type, v1, v2);
break;
}
case ReductionIdentifier::NEQV: {
- mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
- mlir::Value op2I1 = builder.createConvert(loc, builder.getI1Type(), op2);
-
- mlir::Value cmpiOp = mlir::arith::CmpIOp::create(
- builder, loc, mlir::arith::CmpIPredicate::ne, op1I1, op2I1);
-
- reductionOp = builder.createConvert(loc, type, cmpiOp);
+ mlir::Value v1 = builder.createConvert(loc, type, op1);
+ mlir::Value v2 = builder.createConvert(loc, type, op2);
+ reductionOp = fir::NeqvOp::create(builder, loc, type, v1, v2);
break;
}
default:
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 2d01463cf604d..c2cc82203c495 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -65,6 +65,7 @@
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/CommandLine.h"
namespace fir {
#define GEN_PASS_DEF_FIRTOLLVMLOWERING
@@ -73,6 +74,14 @@ namespace fir {
#define DEBUG_TYPE "flang-codegen"
+static llvm::cl::opt<bool> useNativeLogicalOps(
+ "fir-logical-native-ops",
+ llvm::cl::desc(
+ "Use bitwise operations on the storage type for logical operations "
+ "instead of normalizing to i1. Requires that all logical values "
+ "are in their canonical representation."),
+ llvm::cl::init(false));
+
// TODO: This should really be recovered from the specified target.
static constexpr unsigned defaultAlign = 8;
@@ -4292,6 +4301,115 @@ struct NegcOpConversion : public fir::FIROpConversion<fir::NegcOp> {
}
};
+/// Normalize a logical value to i1 by comparing with zero.
+static mlir::Value
+normalizeLogicalToI1(mlir::ConversionPatternRewriter &rewriter,
+ mlir::Location loc, mlir::Value value) {
+ mlir::Type ty = value.getType();
+ auto i1Ty = mlir::IntegerType::get(rewriter.getContext(), 1);
+ if (ty == i1Ty)
+ return value;
+ mlir::Value zero = fir::genConstantIndex(loc, ty, rewriter, 0);
+ return mlir::LLVM::ICmpOp::create(rewriter, loc,
+ mlir::LLVM::ICmpPredicate::ne, value, zero);
+}
+
+/// Extend an i1 value to the given integer type. Returns the value unchanged
+/// if it is already the target type.
+static mlir::Value extendI1ToType(mlir::ConversionPatternRewriter &rewriter,
+ mlir::Location loc, mlir::Value i1Val,
+ mlir::Type toTy) {
+ auto i1Ty = mlir::IntegerType::get(rewriter.getContext(), 1);
+ if (toTy == i1Ty)
+ return i1Val;
+ return mlir::LLVM::ZExtOp::create(rewriter, loc, toTy, i1Val);
+}
+
+/// Logical AND codegen.
+struct LogicalAndOpConversion : public fir::FIROpConversion<fir::LogicalAndOp> {
+ using FIROpConversion::FIROpConversion;
+
+ llvm::LogicalResult
+ matchAndRewrite(fir::LogicalAndOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Type resTy = convertType(op.getType());
+ auto loc = op.getLoc();
+ if (useNativeLogicalOps) {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(
+ op, resTy, adaptor.getLhs(), adaptor.getRhs());
+ } else {
+ auto lhs = normalizeLogicalToI1(rewriter, loc, adaptor.getLhs());
+ auto rhs = normalizeLogicalToI1(rewriter, loc, adaptor.getRhs());
+ auto res = mlir::LLVM::AndOp::create(rewriter, loc, lhs, rhs);
+ rewriter.replaceOp(op, extendI1ToType(rewriter, loc, res, resTy));
+ }
+ return mlir::success();
+ }
+};
+
+/// Logical OR codegen.
+struct LogicalOrOpConversion : public fir::FIROpConversion<fir::LogicalOrOp> {
+ using FIROpConversion::FIROpConversion;
+
+ llvm::LogicalResult
+ matchAndRewrite(fir::LogicalOrOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Type resTy = convertType(op.getType());
+ auto loc = op.getLoc();
+ if (useNativeLogicalOps) {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, resTy, adaptor.getLhs(),
+ adaptor.getRhs());
+ } else {
+ auto lhs = normalizeLogicalToI1(rewriter, loc, adaptor.getLhs());
+ auto rhs = normalizeLogicalToI1(rewriter, loc, adaptor.getRhs());
+ auto res = mlir::LLVM::OrOp::create(rewriter, loc, lhs, rhs);
+ rewriter.replaceOp(op, extendI1ToType(rewriter, loc, res, resTy));
+ }
+ return mlir::success();
+ }
+};
+
+/// Logical equivalence codegen.
+struct EqvOpConversion : public fir::FIROpConversion<fir::EqvOp> {
+ using FIROpConversion::FIROpConversion;
+
+ llvm::LogicalResult
+ matchAndRewrite(fir::EqvOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Type resTy = convertType(op.getType());
+ auto loc = op.getLoc();
+ auto lhs = normalizeLogicalToI1(rewriter, loc, adaptor.getLhs());
+ auto rhs = normalizeLogicalToI1(rewriter, loc, adaptor.getRhs());
+ auto res = mlir::LLVM::ICmpOp::create(
+ rewriter, loc, mlir::LLVM::ICmpPredicate::eq, lhs, rhs);
+ rewriter.replaceOp(op, extendI1ToType(rewriter, loc, res, resTy));
+ return mlir::success();
+ }
+};
+
+/// Logical non-equivalence codegen.
+struct NeqvOpConversion : public fir::FIROpConversion<fir::NeqvOp> {
+ using FIROpConversion::FIROpConversion;
+
+ llvm::LogicalResult
+ matchAndRewrite(fir::NeqvOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Type resTy = convertType(op.getType());
+ auto loc = op.getLoc();
+ if (useNativeLogicalOps) {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(
+ op, resTy, adaptor.getLhs(), adaptor.getRhs());
+ } else {
+ auto lhs = normalizeLogicalToI1(rewriter, loc, adaptor.getLhs());
+ auto rhs = normalizeLogicalToI1(rewriter, loc, adaptor.getRhs());
+ auto res = mlir::LLVM::ICmpOp::create(
+ rewriter, loc, mlir::LLVM::ICmpPredicate::ne, lhs, rhs);
+ rewriter.replaceOp(op, extendI1ToType(rewriter, loc, res, resTy));
+ }
+ return mlir::success();
+ }
+};
+
struct BoxOffsetOpConversion : public fir::FIROpConversion<fir::BoxOffsetOp> {
using FIROpConversion::FIROpConversion;
@@ -4641,19 +4759,20 @@ void fir::populateFIRToLLVMConversionPatterns(
DoConcurrentSpecifierOpConversion<fir::LocalitySpecifierOp>,
DoConcurrentSpecifierOpConversion<fir::DeclareReductionOp>,
DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
- EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
- FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion,
- GlobalOpConversion, InsertOnRangeOpConversion, IsPresentOpConversion,
- LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
- NegcOpConversion, NoReassocOpConversion, PrefetchOpConversion,
- SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
- SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
- ShiftOpConversion, SliceOpConversion, StoreOpConversion,
- StringLitOpConversion, SubcOpConversion, TypeDescOpConversion,
- TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
- UndefOpConversion, UnreachableOpConversion, UseStmtOpConversion,
- XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion,
- ZeroOpConversion>(converter, options);
+ EmboxProcOpConversion, EqvOpConversion, ExtractValueOpConversion,
+ FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion,
+ GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
+ IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
+ LogicalAndOpConversion, LogicalOrOpConversion, MulcOpConversion,
+ NegcOpConversion, NeqvOpConversion, NoReassocOpConversion,
+ PrefetchOpConversion, SelectCaseOpConversion, SelectOpConversion,
+ SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
+ ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
+ StoreOpConversion, StringLitOpConversion, SubcOpConversion,
+ TypeDescOpConversion, TypeInfoOpConversion, UnboxCharOpConversion,
+ UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
+ UseStmtOpConversion, XArrayCoorOpConversion, XEmboxOpConversion,
+ XReboxOpConversion, ZeroOpConversion>(converter, options);
// Patterns that are populated without a type converter do not trigger
// target materializations for the operands of the root op.
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 93a141da111a2..cf0ceed7fbb39 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1639,6 +1639,82 @@ mlir::OpFoldResult fir::ConvertOp::fold(FoldAdaptor adaptor) {
return {};
}
+//===----------------------------------------------------------------------===//
+// Logical binary operations fold helpers
+//===----------------------------------------------------------------------===//
+
+/// If \p value is a fir.convert of an arith.constant i1, return the i1 value.
+static std::optional<bool> getLogicalConstant(mlir::Value value) {
+ auto convertOp = value.getDefiningOp<fir::ConvertOp>();
+ if (!convertOp)
+ return std::nullopt;
+ if (auto cst = fir::getIntIfConstant(convertOp.getValue()))
+ return *cst != 0;
+ return std::nullopt;
+}
+
+/// Build a logical constant: fir.convert(arith.constant) if the result type
+/// is fir.logical, or arith.constant if it is an integer type.
+static mlir::OpFoldResult logicalConstantFoldResult(mlir::Type resTy,
+ bool value) {
+ if (mlir::isa<fir::LogicalType>(resTy))
+ return {};
+ auto intTy = mlir::cast<mlir::IntegerType>(resTy);
+ return mlir::IntegerAttr::get(intTy, value ? 1 : 0);
+}
+
+mlir::OpFoldResult fir::LogicalAndOp::fold(FoldAdaptor adaptor) {
+ auto lhsCst = getLogicalConstant(getLhs());
+ auto rhsCst = getLogicalConstant(getRhs());
+ if (lhsCst && rhsCst)
+ return logicalConstantFoldResult(getType(), *lhsCst && *rhsCst);
+ // land(x, true) -> x
+ if (rhsCst && *rhsCst)
+ return getLhs();
+ if (lhsCst && *lhsCst)
+ return getRhs();
+ return {};
+}
+
+mlir::OpFoldResult fir::LogicalOrOp::fold(FoldAdaptor adaptor) {
+ auto lhsCst = getLogicalConstant(getLhs());
+ auto rhsCst = getLogicalConstant(getRhs());
+ if (lhsCst && rhsCst)
+ return logicalConstantFoldResult(getType(), *lhsCst || *rhsCst);
+ // lor(x, false) -> x
+ if (rhsCst && !*rhsCst)
+ return getLhs();
+ if (lhsCst && !*lhsCst)
+ return getRhs();
+ return {};
+}
+
+mlir::OpFoldResult fir::EqvOp::fold(FoldAdaptor adaptor) {
+ auto lhsCst = getLogicalConstant(getLhs());
+ auto rhsCst = getLogicalConstant(getRhs());
+ if (lhsCst && rhsCst)
+ return logicalConstantFoldResult(getType(), *lhsCst == *rhsCst);
+ // eqv(x, true) -> x
+ if (rhsCst && *rhsCst)
+ return getLhs();
+ if (lhsCst && *lhsCst)
+ return getRhs();
+ return {};
+}
+
+mlir::OpFoldResult fir::NeqvOp::fold(FoldAdaptor adaptor) {
+ auto lhsCst = getLogicalConstant(getLhs());
+ auto rhsCst = getLogicalConstant(getRhs());
+ if (lhsCst && rhsCst)
+ return logicalConstantFoldResult(getType(), *lhsCst != *rhsCst);
+ // neqv(x, false) -> x
+ if (rhsCst && !*rhsCst)
+ return getLhs();
+ if (lhsCst && !*lhsCst)
+ return getRhs();
+ return {};
+}
+
bool fir::ConvertOp::isInteger(mlir::Type ty) {
return mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType>(ty);
}
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index 25af35513d18d..28d46774b3d10 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -1012,23 +1012,9 @@ template <typename Op>
static mlir::Value genLogicalCombiner(fir::FirOpBuilder &builder,
mlir::Location loc, mlir::Value value1,
mlir::Value value2) {
- mlir::Type i1 = builder.getI1Type();
- mlir::Value v1 ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/190771
More information about the flang-commits
mailing list