[Mlir-commits] [mlir] [mlir][emitc] arith.cmpf to EmitC conversion (PR #93671)
Tina Jung
llvmlistbot at llvm.org
Wed May 29 08:00:15 PDT 2024
https://github.com/TinaAMD updated https://github.com/llvm/llvm-project/pull/93671
>From 89afb2b3b930362c7d0d27fd80911c9422506063 Mon Sep 17 00:00:00 2001
From: Tina Jung <tinamaria.jung at amd.com>
Date: Tue, 26 Mar 2024 12:38:02 +0100
Subject: [PATCH 1/3] [mlir][emitc] arith.cmpf to EmitC conversion
Convert all arith.cmpf on floats (not vectors/tensors thereof) to EmitC.
Co-authored-by: Matthias Gehre <matthias.gehre at amd.com>
Co-authored-by: Jose Lopes <jose.lopes at amd.com>
---
.../Conversion/ArithToEmitC/ArithToEmitC.cpp | 161 ++++++++++++-
.../arith-to-emitc-unsupported.mlir | 16 ++
.../ArithToEmitC/arith-to-emitc.mlir | 228 ++++++++++++++++++
3 files changed, 404 insertions(+), 1 deletion(-)
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)
>From ffd688698559735c180c1e33d909c89aa43db17e Mon Sep 17 00:00:00 2001
From: Tina Jung <tina.maria.jung at xilinx.com>
Date: Wed, 29 May 2024 15:56:00 +0100
Subject: [PATCH 2/3] Rename functions/variable; change return types
* Rename functions from Nan to NaN
* Add missing `Not` in variable name
* Change return type of private function to Value + adapt documentation to reflect this
---
.../Conversion/ArithToEmitC/ArithToEmitC.cpp | 44 +++++++++----------
1 file changed, 21 insertions(+), 23 deletions(-)
diff --git a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
index 71e3e48e8d185..aa1f7c5952832 100644
--- a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
+++ b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
@@ -146,8 +146,8 @@ class CmpFOpConversion : public OpConversionPattern<arith::CmpFOp> {
if (unordered) {
auto isUnordered = createCheckIsUnordered(
rewriter, op.getLoc(), adaptor.getLhs(), adaptor.getRhs());
- rewriter.replaceOpWithNewOp<emitc::LogicalOrOp>(
- op, op.getType(), isUnordered.getResult(), cmpResult);
+ rewriter.replaceOpWithNewOp<emitc::LogicalOrOp>(op, op.getType(),
+ isUnordered, cmpResult);
return success();
}
@@ -159,42 +159,40 @@ class CmpFOpConversion : public OpConversionPattern<arith::CmpFOp> {
}
private:
- /// Return an operation that returns true (in i1) when \p operand is NaN.
- emitc::CmpOp isNan(ConversionPatternRewriter &rewriter, Location loc,
- Value operand) const {
+ /// Return a value that is true iff \p operand is NaN.
+ Value 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 {
+ /// Return a value that is true iff \p operand is not NaN.
+ Value 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 a value that is true iff the operands \p first and \p second are
+ /// unordered (i.e., at least one of them is NaN).
+ Value 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 a value that is true iff the operands \p first and \p second are
+ /// both ordered (i.e., none one of them is NaN).
+ Value createCheckIsOrdered(ConversionPatternRewriter &rewriter, Location loc,
+ Value first, Value second) const {
+ auto firstIsNotNaN = isNotNaN(rewriter, loc, first);
+ auto secondIsNotNaN = isNotNaN(rewriter, loc, second);
return rewriter.create<emitc::LogicalAndOp>(loc, rewriter.getI1Type(),
- firstIsNaN, secondIsNaN);
+ firstIsNotNaN, secondIsNotNaN);
}
};
>From 2bcae1f2620165718d4f6f81a1daa57fb1640064 Mon Sep 17 00:00:00 2001
From: Tina Jung <tina.maria.jung at xilinx.com>
Date: Wed, 29 May 2024 15:59:15 +0100
Subject: [PATCH 3/3] Fix naming of captures for ordered comparisons
---
.../ArithToEmitC/arith-to-emitc.mlir | 42 +++++++++----------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir b/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir
index cf6ba2f3febde..23dfb64567209 100644
--- a/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir
+++ b/mlir/test/Conversion/ArithToEmitC/arith-to-emitc.mlir
@@ -122,9 +122,9 @@ 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: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
// CHECK-DAG: [[OEQ:[^ ]*]] = emitc.logical_and [[Ordered]], [[EQ]] : i1, i1
%oeq = arith.cmpf oeq, %arg0, %arg1 : f32
// CHECK: return [[OEQ]]
@@ -137,9 +137,9 @@ 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: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
// CHECK-DAG: [[OGT:[^ ]*]] = emitc.logical_and [[Ordered]], [[GT]] : i1, i1
%ogt = arith.cmpf ogt, %arg0, %arg1 : f32
// CHECK: return [[OGT]]
@@ -152,9 +152,9 @@ 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: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
// CHECK-DAG: [[OGE:[^ ]*]] = emitc.logical_and [[Ordered]], [[GE]] : i1, i1
%oge = arith.cmpf oge, %arg0, %arg1 : f32
// CHECK: return [[OGE]]
@@ -167,9 +167,9 @@ 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: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
// CHECK-DAG: [[OLT:[^ ]*]] = emitc.logical_and [[Ordered]], [[LT]] : i1, i1
%olt = arith.cmpf olt, %arg0, %arg1 : f32
// CHECK: return [[OLT]]
@@ -182,9 +182,9 @@ 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: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
// CHECK-DAG: [[OLE:[^ ]*]] = emitc.logical_and [[Ordered]], [[LT]] : i1, i1
%ole = arith.cmpf ole, %arg0, %arg1 : f32
// CHECK: return [[OLE]]
@@ -197,9 +197,9 @@ 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: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
// CHECK-DAG: [[ONE:[^ ]*]] = emitc.logical_and [[Ordered]], [[NEQ]] : i1, i1
%one = arith.cmpf one, %arg0, %arg1 : f32
// CHECK: return [[ONE]]
@@ -211,9 +211,9 @@ func.func @arith_cmpf_one(%arg0: f32, %arg1: f32) -> 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
+ // CHECK-DAG: [[NotNaNArg0:[^ ]*]] = emitc.cmp eq, [[Arg0]], [[Arg0]] : (f32, f32) -> i1
+ // CHECK-DAG: [[NotNaNArg1:[^ ]*]] = emitc.cmp eq, [[Arg1]], [[Arg1]] : (f32, f32) -> i1
+ // CHECK-DAG: [[Ordered:[^ ]*]] = emitc.logical_and [[NotNaNArg0]], [[NotNaNArg1]] : i1, i1
%ord = arith.cmpf ord, %arg0, %arg1 : f32
// CHECK: return [[Ordered]]
return %ord: i1
More information about the Mlir-commits
mailing list