[Mlir-commits] [mlir] [mlir][emitc] arith.cmpf to EmitC conversion (PR #93671)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed May 29 05:14:24 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-emitc
Author: Tina Jung (TinaAMD)
<details>
<summary>Changes</summary>
Convert all arith.cmpf on floats (not vectors/tensors thereof) to EmitC.
---
Full diff: https://github.com/llvm/llvm-project/pull/93671.diff
3 Files Affected:
- (modified) mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp (+160-1)
- (modified) mlir/test/Conversion/ArithToEmitC/arith-to-emitc-unsupported.mlir (+16)
- (modified) mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir (+228)
``````````diff
diff --git a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
index 388794ec122d2..71e3e48e8d185 100644
--- a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
+++ b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
@@ -15,7 +15,9 @@
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
-#include "mlir/Tools/PDLL/AST/Types.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/Support/LogicalResult.h"
#include "mlir/Transforms/DialectConversion.h"
using namespace mlir;
@@ -40,6 +42,162 @@ class ArithConstantOpConversionPattern
}
};
+class CmpFOpConversion : public OpConversionPattern<arith::CmpFOp> {
+public:
+ using OpConversionPattern::OpConversionPattern;
+
+ LogicalResult
+ matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+
+ if (!isa<FloatType>(adaptor.getRhs().getType())) {
+ return rewriter.notifyMatchFailure(op.getLoc(),
+ "cmpf currently only supported on "
+ "floats, not tensors/vectors thereof");
+ }
+
+ bool unordered = false;
+ emitc::CmpPredicate predicate;
+ switch (op.getPredicate()) {
+ case arith::CmpFPredicate::AlwaysFalse: {
+ auto constant = rewriter.create<emitc::ConstantOp>(
+ op.getLoc(), rewriter.getI1Type(),
+ rewriter.getBoolAttr(/*value=*/false));
+ rewriter.replaceOp(op, constant);
+ return success();
+ }
+ case arith::CmpFPredicate::OEQ:
+ unordered = false;
+ predicate = emitc::CmpPredicate::eq;
+ break;
+ case arith::CmpFPredicate::OGT:
+ unordered = false;
+ predicate = emitc::CmpPredicate::gt;
+ break;
+ case arith::CmpFPredicate::OGE:
+ unordered = false;
+ predicate = emitc::CmpPredicate::ge;
+ break;
+ case arith::CmpFPredicate::OLT:
+ unordered = false;
+ predicate = emitc::CmpPredicate::lt;
+ break;
+ case arith::CmpFPredicate::OLE:
+ unordered = false;
+ predicate = emitc::CmpPredicate::le;
+ break;
+ case arith::CmpFPredicate::ONE:
+ unordered = false;
+ predicate = emitc::CmpPredicate::ne;
+ break;
+ case arith::CmpFPredicate::ORD: {
+ // ordered, i.e. none of the operands is NaN
+ auto cmp = createCheckIsOrdered(rewriter, op.getLoc(), adaptor.getLhs(),
+ adaptor.getRhs());
+ rewriter.replaceOp(op, cmp);
+ return success();
+ }
+ case arith::CmpFPredicate::UEQ:
+ unordered = true;
+ predicate = emitc::CmpPredicate::eq;
+ break;
+ case arith::CmpFPredicate::UGT:
+ unordered = true;
+ predicate = emitc::CmpPredicate::gt;
+ break;
+ case arith::CmpFPredicate::UGE:
+ unordered = true;
+ predicate = emitc::CmpPredicate::ge;
+ break;
+ case arith::CmpFPredicate::ULT:
+ unordered = true;
+ predicate = emitc::CmpPredicate::lt;
+ break;
+ case arith::CmpFPredicate::ULE:
+ unordered = true;
+ predicate = emitc::CmpPredicate::le;
+ break;
+ case arith::CmpFPredicate::UNE:
+ unordered = true;
+ predicate = emitc::CmpPredicate::ne;
+ break;
+ case arith::CmpFPredicate::UNO: {
+ // unordered, i.e. either operand is nan
+ auto cmp = createCheckIsUnordered(rewriter, op.getLoc(), adaptor.getLhs(),
+ adaptor.getRhs());
+ rewriter.replaceOp(op, cmp);
+ return success();
+ }
+ case arith::CmpFPredicate::AlwaysTrue: {
+ auto constant = rewriter.create<emitc::ConstantOp>(
+ op.getLoc(), rewriter.getI1Type(),
+ rewriter.getBoolAttr(/*value=*/true));
+ rewriter.replaceOp(op, constant);
+ return success();
+ }
+ }
+
+ // Compare the values naively
+ auto cmpResult =
+ rewriter.create<emitc::CmpOp>(op.getLoc(), op.getType(), predicate,
+ adaptor.getLhs(), adaptor.getRhs());
+
+ // Adjust the results for unordered/ordered semantics
+ if (unordered) {
+ auto isUnordered = createCheckIsUnordered(
+ rewriter, op.getLoc(), adaptor.getLhs(), adaptor.getRhs());
+ rewriter.replaceOpWithNewOp<emitc::LogicalOrOp>(
+ op, op.getType(), isUnordered.getResult(), cmpResult);
+ return success();
+ }
+
+ auto isOrdered = createCheckIsOrdered(rewriter, op.getLoc(),
+ adaptor.getLhs(), adaptor.getRhs());
+ rewriter.replaceOpWithNewOp<emitc::LogicalAndOp>(op, op.getType(),
+ isOrdered, cmpResult);
+ return success();
+ }
+
+private:
+ /// Return an operation that returns true (in i1) when \p operand is NaN.
+ emitc::CmpOp isNan(ConversionPatternRewriter &rewriter, Location loc,
+ Value operand) const {
+ // A value is NaN exactly when it compares unequal to itself.
+ return rewriter.create<emitc::CmpOp>(
+ loc, rewriter.getI1Type(), emitc::CmpPredicate::ne, operand, operand);
+ }
+
+ /// Return an operation that returns true (in i1) when \p operand is not NaN.
+ emitc::CmpOp isNotNan(ConversionPatternRewriter &rewriter, Location loc,
+ Value operand) const {
+ // A value is not NaN exactly when it compares equal to itself.
+ return rewriter.create<emitc::CmpOp>(
+ loc, rewriter.getI1Type(), emitc::CmpPredicate::eq, operand, operand);
+ }
+
+ /// Return an op that return true (in i1) if the operands \p first and
+ /// \p second are unordered (i.e., at least one of them is NaN).
+ emitc::LogicalOrOp createCheckIsUnordered(ConversionPatternRewriter &rewriter,
+ Location loc, Value first,
+ Value second) const {
+ auto firstIsNaN = isNan(rewriter, loc, first);
+ auto secondIsNaN = isNan(rewriter, loc, second);
+ return rewriter.create<emitc::LogicalOrOp>(loc, rewriter.getI1Type(),
+ firstIsNaN, secondIsNaN);
+ }
+
+ /// Return an op that return true (in i1) if the operands \p first and
+ /// \p second are both ordered (i.e., none one of them is NaN).
+ emitc::LogicalAndOp createCheckIsOrdered(ConversionPatternRewriter &rewriter,
+ Location loc, Value first,
+ Value second) const {
+ auto firstIsNaN = isNotNan(rewriter, loc, first);
+ auto secondIsNaN = isNotNan(rewriter, loc, second);
+ return rewriter.create<emitc::LogicalAndOp>(loc, rewriter.getI1Type(),
+ firstIsNaN, secondIsNaN);
+ }
+};
+
class CmpIOpConversion : public OpConversionPattern<arith::CmpIOp> {
public:
using OpConversionPattern::OpConversionPattern;
@@ -401,6 +559,7 @@ void mlir::populateArithToEmitCPatterns(TypeConverter &typeConverter,
IntegerOpConversion<arith::AddIOp, emitc::AddOp>,
IntegerOpConversion<arith::MulIOp, emitc::MulOp>,
IntegerOpConversion<arith::SubIOp, emitc::SubOp>,
+ CmpFOpConversion,
CmpIOpConversion,
SelectOpConversion,
// Truncation is guaranteed for unsigned types.
diff --git a/mlir/test/Conversion/ArithToEmitC/arith-to-emitc-unsupported.mlir b/mlir/test/Conversion/ArithToEmitC/arith-to-emitc-unsupported.mlir
index 97e4593f97b90..c07289109e6dd 100644
--- a/mlir/test/Conversion/ArithToEmitC/arith-to-emitc-unsupported.mlir
+++ b/mlir/test/Conversion/ArithToEmitC/arith-to-emitc-unsupported.mlir
@@ -65,6 +65,22 @@ func.func @arith_cast_fptoui_i1(%arg0: f32) -> i1 {
// -----
+func.func @arith_cmpf_vector(%arg0: vector<5xf32>, %arg1: vector<5xf32>) -> vector<5xi1> {
+ // expected-error @+1 {{failed to legalize operation 'arith.cmpf'}}
+ %t = arith.cmpf uno, %arg0, %arg1 : vector<5xf32>
+ return %t: vector<5xi1>
+}
+
+// -----
+
+func.func @arith_cmpf_tensor(%arg0: tensor<5xf32>, %arg1: tensor<5xf32>) -> tensor<5xi1> {
+ // expected-error @+1 {{failed to legalize operation 'arith.cmpf'}}
+ %t = arith.cmpf uno, %arg0, %arg1 : tensor<5xf32>
+ return %t: tensor<5xi1>
+}
+
+// -----
+
func.func @arith_extsi_i1_to_i32(%arg0: i1) {
// expected-error @+1 {{failed to legalize operation 'arith.extsi'}}
%idx = arith.extsi %arg0 : i1 to i32
diff --git a/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir b/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir
index dac3fd99b607c..cf6ba2f3febde 100644
--- a/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir
+++ b/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir
@@ -107,6 +107,234 @@ func.func @arith_select(%arg0: i1, %arg1: tensor<8xi32>, %arg2: tensor<8xi32>) -
// -----
+func.func @arith_cmpf_false(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_false
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[False:[^ ]*]] = "emitc.constant"() <{value = false}> : () -> i1
+ %false = arith.cmpf false, %arg0, %arg1 : f32
+ // CHECK: return [[False]]
+ return %false: i1
+}
+
+// -----
+
+func.func @arith_cmpf_oeq(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_oeq
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[EQ:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[OEQ:[^ ]*]] = emitc.logical_and [[Ordered]], [[EQ]] : i1, i1
+ %oeq = arith.cmpf oeq, %arg0, %arg1 : f32
+ // CHECK: return [[OEQ]]
+ return %oeq: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ogt(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ogt
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[GT:[^ ]*]] = emitc.cmp gt, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[OrderedArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[OrderedArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[OrderedArg0]], [[OrderedArg1]] : i1, i1
+ // CHECK-DAG: [[OGT:[^ ]*]] = emitc.logical_and [[Ordered]], [[GT]] : i1, i1
+ %ogt = arith.cmpf ogt, %arg0, %arg1 : f32
+ // CHECK: return [[OGT]]
+ return %ogt: i1
+}
+
+// -----
+
+func.func @arith_cmpf_oge(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_oge
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[GE:[^ ]*]] = emitc.cmp ge, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[OGE:[^ ]*]] = emitc.logical_and [[Ordered]], [[GE]] : i1, i1
+ %oge = arith.cmpf oge, %arg0, %arg1 : f32
+ // CHECK: return [[OGE]]
+ return %oge: i1
+}
+
+// -----
+
+func.func @arith_cmpf_olt(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_olt
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[LT:[^ ]*]] = emitc.cmp lt, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[OLT:[^ ]*]] = emitc.logical_and [[Ordered]], [[LT]] : i1, i1
+ %olt = arith.cmpf olt, %arg0, %arg1 : f32
+ // CHECK: return [[OLT]]
+ return %olt: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ole(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ole
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[LT:[^ ]*]] = emitc.cmp le, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[OLE:[^ ]*]] = emitc.logical_and [[Ordered]], [[LT]] : i1, i1
+ %ole = arith.cmpf ole, %arg0, %arg1 : f32
+ // CHECK: return [[OLE]]
+ return %ole: i1
+}
+
+// -----
+
+func.func @arith_cmpf_one(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_one
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[NEQ:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[ONE:[^ ]*]] = emitc.logical_and [[Ordered]], [[NEQ]] : i1, i1
+ %one = arith.cmpf one, %arg0, %arg1 : f32
+ // CHECK: return [[ONE]]
+ return %one: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ord(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ord
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NaNArg0]], [[NaNArg1]] : i1, i1
+ %ord = arith.cmpf ord, %arg0, %arg1 : f32
+ // CHECK: return [[Ordered]]
+ return %ord: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ueq(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ueq
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[EQ:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[UEQ:[^ ]*]] = emitc.logical_or [[Unordered]], [[EQ]] : i1, i1
+ %ueq = arith.cmpf ueq, %arg0, %arg1 : f32
+ // CHECK: return [[UEQ]]
+ return %ueq: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ugt(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ugt
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[GT:[^ ]*]] = emitc.cmp gt, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[UGT:[^ ]*]] = emitc.logical_or [[Unordered]], [[GT]] : i1, i1
+ %ugt = arith.cmpf ugt, %arg0, %arg1 : f32
+ // CHECK: return [[UGT]]
+ return %ugt: i1
+}
+
+// -----
+
+func.func @arith_cmpf_uge(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_uge
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[GE:[^ ]*]] = emitc.cmp ge, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[UGE:[^ ]*]] = emitc.logical_or [[Unordered]], [[GE]] : i1, i1
+ %uge = arith.cmpf uge, %arg0, %arg1 : f32
+ // CHECK: return [[UGE]]
+ return %uge: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ult(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ult
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[LT:[^ ]*]] = emitc.cmp lt, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[ULT:[^ ]*]] = emitc.logical_or [[Unordered]], [[LT]] : i1, i1
+ %ult = arith.cmpf ult, %arg0, %arg1 : f32
+ // CHECK: return [[ULT]]
+ return %ult: i1
+}
+
+// -----
+
+func.func @arith_cmpf_ule(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_ule
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[LE:[^ ]*]] = emitc.cmp le, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[ULE:[^ ]*]] = emitc.logical_or [[Unordered]], [[LE]] : i1, i1
+ %ule = arith.cmpf ule, %arg0, %arg1 : f32
+ // CHECK: return [[ULE]]
+ return %ule: i1
+}
+
+// -----
+
+func.func @arith_cmpf_une(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_une
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[NEQ:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ // CHECK-DAG: [[UNE:[^ ]*]] = emitc.logical_or [[Unordered]], [[NEQ]] : i1, i1
+ %une = arith.cmpf une, %arg0, %arg1 : f32
+ // CHECK: return [[UNE]]
+ return %une: i1
+}
+
+// -----
+
+func.func @arith_cmpf_uno(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_uno
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[NaNArg0:[^ ]*]] = emitc.cmp ne, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NaNArg1:[^ ]*]] = emitc.cmp ne, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Unordered:[^ ]*]] = emitc.logical_or [[NaNArg0]], [[NaNArg1]] : i1, i1
+ %uno = arith.cmpf uno, %arg0, %arg1 : f32
+ // CHECK: return [[Unordered]]
+ return %uno: i1
+}
+
+// -----
+
+func.func @arith_cmpf_true(%arg0: f32, %arg1: f32) -> i1 {
+ // CHECK-LABEL: arith_cmpf_true
+ // CHECK-SAME: ([[Arg0:[^ ]*]]: f32, [[Arg1:[^ ]*]]: f32)
+ // CHECK-DAG: [[True:[^ ]*]] = "emitc.constant"() <{value = true}> : () -> i1
+ %ueq = arith.cmpf true, %arg0, %arg1 : f32
+ // CHECK: return [[True]]
+ return %ueq: i1
+}
+
+// -----
+
func.func @arith_cmpi_eq(%arg0: i32, %arg1: i32) -> i1 {
// CHECK-LABEL: arith_cmpi_eq
// CHECK-SAME: ([[Arg0:[^ ]*]]: i32, [[Arg1:[^ ]*]]: i32)
``````````
</details>
https://github.com/llvm/llvm-project/pull/93671
More information about the Mlir-commits
mailing list