[clang] [CIR] Implement cir.cmp3way Operation (PR #186294)
Yeongu Choe via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 13 10:19:38 PDT 2026
https://github.com/YeonguChoe updated https://github.com/llvm/llvm-project/pull/186294
>From 3abbe008bd366681146acd530cfd470bf9339c3d Mon Sep 17 00:00:00 2001
From: YeonguChoe <yeongu.choe at icloud.com>
Date: Thu, 12 Mar 2026 22:10:56 -0400
Subject: [PATCH 1/2] [CIR] Implement cir.cmp3way Operation
A three-way comparison operation is an operation that determines ordering of two numbers in a single operation. Implemented it as specified in the CIR documentation.
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 7 ++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 34 ++++++++
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 46 ++++++++++-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 82 +++++++++++++++++++
.../CIR/CodeGenCXX/three-way-comparison.cpp | 22 +++++
clang/test/CIR/Lowering/cmp3way.cir | 32 ++++++++
6 files changed, 219 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CIR/CodeGenCXX/three-way-comparison.cpp
create mode 100644 clang/test/CIR/Lowering/cmp3way.cir
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index e60288c40132f..2a81da408121c 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -669,6 +669,13 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::CmpOp::create(*this, loc, kind, lhs, rhs);
}
+ cir::CmpThreeWayOp createThreeWayComparison(mlir::Location loc,
+ mlir::Type resultTy,
+ mlir::Value lhs, mlir::Value rhs,
+ mlir::Attribute info) {
+ return cir::CmpThreeWayOp::create(*this, loc, resultTy, lhs, rhs, info);
+ }
+
cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind,
mlir::Value lhs, mlir::Value rhs) {
VectorType vecCast = mlir::cast<VectorType>(lhs.getType());
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a9b98b1f43b3f..24758a0c946f6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2071,6 +2071,40 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
let hasCXXABILowering = true;
}
+//===----------------------------------------------------------------------===//
+// CmpThreeWayOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CmpThreeWayStrongInfoAttr
+ : CIR_Attr<"CmpThreeWayStrongInfo", "cmp3way_strong_info"> {
+ let parameters = (ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt);
+ let assemblyFormat =
+ [{`<` `strong` `,` `lt` `=` $lt `,` `eq` `=` $eq `,` `gt` `=` $gt `>`}];
+}
+def CIR_CmpThreeWayPartialInfoAttr
+ : CIR_Attr<"CmpThreeWayPartialInfo", "cmp3way_partial_info"> {
+ let parameters = (ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt,
+ "int64_t":$unordered);
+ let assemblyFormat =
+ [{`<` `partial` `,` `lt` `=` $lt `,` `eq` `=` $eq `,` `gt` `=` $gt `,` `unordered` `=` $unordered `>` }];
+}
+def CIR_CmpThreeWayInfoAttr : AnyAttrOf<[CIR_CmpThreeWayStrongInfoAttr,
+ CIR_CmpThreeWayPartialInfoAttr]>;
+
+def CIR_CmpThreeWayOp
+ : CIR_Op<"cmp3way", [Pure, SameTypeOperands, ConditionallySpeculatable]> {
+ let summary = "Performs three-way comparison.";
+ let description = [{
+ Three-way comparison takes two operands of the same type and determines ordering.
+ }];
+ let arguments = (ins CIR_AnyType:$lhs, CIR_AnyType:$rhs,
+ CIR_CmpThreeWayInfoAttr:$info);
+ let results = (outs CIR_AnySIntType:$result);
+ let assemblyFormat = [{
+ `(` $lhs `:` type($lhs) `,` $rhs `,` qualified($info) `)` `:` type($result) attr-dict
+ }];
+}
+
//===----------------------------------------------------------------------===//
// BinOpOverflowOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 9f390fec97613..19e844664f53c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -301,9 +301,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitSubstNonTypeTemplateParmExpr");
}
- void VisitConstantExpr(ConstantExpr *e) {
- cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr");
- }
+ void VisitConstantExpr(ConstantExpr *e) { return Visit(e->getSubExpr()); }
void VisitMemberExpr(MemberExpr *e) { emitAggLoadOfLValue(e); }
void VisitUnaryDeref(UnaryOperator *e) { emitAggLoadOfLValue(e); }
void VisitStringLiteral(StringLiteral *e) { emitAggLoadOfLValue(e); }
@@ -326,7 +324,47 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
Visit(e->getRHS());
}
void VisitBinCmp(const BinaryOperator *e) {
- cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp");
+ const ComparisonCategoryInfo &CompCategoryInfo =
+ cgf.getContext().CompCategories.getInfoForType(e->getType());
+
+ QualType ArgTy = e->getLHS()->getType();
+ if (ArgTy->isIntegralOrEnumerationType() || ArgTy->isRealFloatingType() ||
+ ArgTy->isNullPtrType() || ArgTy->isPointerType() ||
+ ArgTy->isMemberPointerType()) {
+ mlir::Value lhs = cgf.emitScalarExpr(e->getLHS());
+ mlir::Value rhs = cgf.emitScalarExpr(e->getRHS());
+
+ mlir::Attribute info;
+ if (CompCategoryInfo.isStrong()) {
+ info = cir::CmpThreeWayStrongInfoAttr::get(
+ cgf.getBuilder().getContext(),
+ CompCategoryInfo.getLess()->getIntValue().getSExtValue(),
+ CompCategoryInfo.getEqualOrEquiv()->getIntValue().getSExtValue(),
+ CompCategoryInfo.getGreater()->getIntValue().getSExtValue());
+ } else {
+ info = cir::CmpThreeWayPartialInfoAttr::get(
+ cgf.getBuilder().getContext(),
+ CompCategoryInfo.getLess()->getIntValue().getSExtValue(),
+ CompCategoryInfo.getEqualOrEquiv()->getIntValue().getSExtValue(),
+ CompCategoryInfo.getGreater()->getIntValue().getSExtValue(),
+ CompCategoryInfo.getUnordered()->getIntValue().getSExtValue());
+ }
+ mlir::Type resultTy = cgf.convertType(cgf.getContext().IntTy);
+ mlir::Value result = cgf.getBuilder().createThreeWayComparison(
+ cgf.getLoc(e->getSourceRange()), resultTy, lhs, rhs, info);
+
+ ensureDest(cgf.getLoc(e->getSourceRange()), e->getType());
+ LValue destLValue = cgf.makeAddrLValue(dest.getAddress(), e->getType());
+
+ const FieldDecl *field = *CompCategoryInfo.Record->field_begin();
+ LValue fieldLValue = cgf.emitLValueForFieldInitialization(
+ destLValue, field, field->getName());
+ cgf.emitStoreThroughLValue(RValue::get(result), fieldLValue, true);
+ } else {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: unsupported operand type");
+ return;
+ }
}
void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9c68248d5dede..53086ecb4b669 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3155,6 +3155,88 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
}
+mlir::LogicalResult CIRToLLVMCmpThreeWayOpLowering::matchAndRewrite(
+ cir::CmpThreeWayOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Location loc = op.getLoc();
+ auto info = op.getInfo();
+ mlir::Type resultTy = getTypeConverter()->convertType(op.getType());
+ mlir::Value lhs = adaptor.getLhs();
+ mlir::Value rhs = adaptor.getRhs();
+ mlir::Type operandTy = lhs.getType();
+
+ mlir::Value ltValue, eqValue, gtValue, unorderedValue;
+ if (auto strongInfo = mlir::dyn_cast<cir::CmpThreeWayStrongInfoAttr>(info)) {
+ ltValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(strongInfo.getLt()));
+ eqValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(strongInfo.getEq()));
+ gtValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(strongInfo.getGt()));
+ } else if (auto partialInfo =
+ mlir::dyn_cast<cir::CmpThreeWayPartialInfoAttr>(info)) {
+ ltValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(partialInfo.getLt()));
+ eqValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(partialInfo.getEq()));
+ gtValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(partialInfo.getGt()));
+ unorderedValue = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, resultTy,
+ rewriter.getI64IntegerAttr(partialInfo.getUnordered()));
+ } else {
+ return op.emitError("unsupported comparison info attribute");
+ }
+
+ if (mlir::isa<mlir::IntegerType>(operandTy)) {
+ bool isSigned = true;
+ if (auto cirIntTy = mlir::dyn_cast<cir::IntType>(op.getLhs().getType())) {
+ isSigned = cirIntTy.isSigned();
+ }
+ auto ltPred = isSigned ? mlir::LLVM::ICmpPredicate::slt
+ : mlir::LLVM::ICmpPredicate::ult;
+
+ mlir::Value ltCmp =
+ mlir::LLVM::ICmpOp::create(rewriter, loc, ltPred, lhs, rhs);
+ mlir::Value eqCmp = mlir::LLVM::ICmpOp::create(
+ rewriter, loc, mlir::LLVM::ICmpPredicate::eq, lhs, rhs);
+
+ mlir::Value result = mlir::LLVM::SelectOp::create(
+ rewriter, loc, ltCmp, ltValue,
+ mlir::LLVM::SelectOp::create(rewriter, loc, eqCmp, eqValue, gtValue));
+ rewriter.replaceOp(op, result);
+ return mlir::success();
+ } else if (mlir::isa<mlir::FloatType>(operandTy)) {
+ if (!unorderedValue) {
+ return op.emitError("strong ordering not supported for float operands");
+ }
+
+ mlir::Value ltCmp = mlir::LLVM::FCmpOp::create(
+ rewriter, loc, mlir::LLVM::FCmpPredicate::olt, lhs, rhs);
+ mlir::Value eqCmp = mlir::LLVM::FCmpOp::create(
+ rewriter, loc, mlir::LLVM::FCmpPredicate::oeq, lhs, rhs);
+ mlir::Value orderedResult = mlir::LLVM::SelectOp::create(
+ rewriter, loc, ltCmp, ltValue,
+ mlir::LLVM::SelectOp::create(rewriter, loc, eqCmp, eqValue, gtValue));
+
+ mlir::Value unorderedCmp = mlir::LLVM::FCmpOp::create(
+ rewriter, loc, mlir::LLVM::FCmpPredicate::uno, lhs, rhs);
+
+ mlir::Value result = mlir::LLVM::SelectOp::create(
+ rewriter, loc, unorderedCmp, unorderedValue, orderedResult);
+ rewriter.replaceOp(op, result);
+ return mlir::success();
+ } else {
+ return op.emitError("unsupported operand type for three-way comparison");
+ }
+}
+
mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
cir::BinOpOverflowOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp b/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp
new file mode 100644
index 0000000000000..80c408597f0d2
--- /dev/null
+++ b/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+#include "Inputs/std-compare.h"
+
+int test_int_spaceship(int a, int b) {
+ auto result = a <=> b;
+ // CHECK: cir.cmp3way(%{{.*}} : !s32i, %{{.*}}, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
+ return (result < 0) ? -1 : (result > 0) ? 1 : 0;
+}
+
+unsigned int test_uint_spaceship(unsigned int a, unsigned int b) {
+ auto result = a <=> b;
+ // CHECK: cir.cmp3way(%{{.*}} : !u32i, %{{.*}}, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
+ return (result < 0) ? 0 : (result > 0) ? 2 : 1;
+}
+
+float test_float_spaceship(float a, float b) {
+ auto result = a <=> b;
+ // CHECK: cir.cmp3way(%{{.*}} : !cir.float, %{{.*}}, #cir.cmp3way_partial_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>)
+ return (result < 0) ? -1.0f : (result > 0) ? 1.0f : 0.0f;
+}
\ No newline at end of file
diff --git a/clang/test/CIR/Lowering/cmp3way.cir b/clang/test/CIR/Lowering/cmp3way.cir
new file mode 100644
index 0000000000000..fe3740b6fd30d
--- /dev/null
+++ b/clang/test/CIR/Lowering/cmp3way.cir
@@ -0,0 +1,32 @@
+// RUN: cir-opt %s -cir-to-llvm -o %t.mlir
+// RUN: FileCheck --input-file=%t.mlir %s
+
+!s32i = !cir.int<s, 32>
+!u32i = !cir.int<u, 32>
+module {
+ cir.func @test_signed() -> !s32i {
+ %0 = cir.const #cir.int<5> : !s32i
+ %1 = cir.const #cir.int<3> : !s32i
+ %2 = cir.cmp3way(%0 : !s32i, %1, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
+ // CHECK: llvm.icmp "slt"
+ cir.return %2 : !s32i
+ }
+
+ cir.func @test_unsigned() -> !s32i {
+ %0 = cir.const #cir.int<5> : !u32i
+ %1 = cir.const #cir.int<3> : !u32i
+ %2 = cir.cmp3way(%0 : !u32i, %1, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
+ // CHECK: llvm.icmp "ult"
+ cir.return %2 : !s32i
+ }
+
+ cir.func @test_float() -> !s32i {
+ %0 = cir.const #cir.fp<1.5> : !cir.float
+ %1 = cir.const #cir.fp<2.5> : !cir.float
+ %2 = cir.cmp3way(%0 : !cir.float, %1, #cir.cmp3way_partial_info<partial, lt = -1, eq = 0, gt = 1, unordered = 2>) : !s32i
+ // CHECK: llvm.fcmp "olt"
+ // CHECK: llvm.fcmp "oeq"
+ // CHECK: llvm.fcmp "uno"
+ cir.return %2 : !s32i
+ }
+}
\ No newline at end of file
>From d687aaa6847a81efabee2b1d38933065f22fb255 Mon Sep 17 00:00:00 2001
From: YeonguChoe <yeongu.choe at icloud.com>
Date: Fri, 13 Mar 2026 13:19:11 -0400
Subject: [PATCH 2/2] [CIR] Implement cir.cmp3way Operation
A three-way comparison operation is an operation that determines ordering of two numbers in a single operation. Implemented it as specified in the CIR documentation.
---
.../CIR/CodeGenCXX/three-way-comparison.cpp | 44 ++++++++++--
clang/test/CIR/Lowering/cmp3way.cir | 72 ++++++++++++++++---
2 files changed, 100 insertions(+), 16 deletions(-)
diff --git a/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp b/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp
index 80c408597f0d2..d8ae1cdb67182 100644
--- a/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp
+++ b/clang/test/CIR/CodeGenCXX/three-way-comparison.cpp
@@ -1,22 +1,54 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
-// RUN: FileCheck --input-file=%t.cir %s
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
-#include "Inputs/std-compare.h"
+#include "../../CodeGenCXX/Inputs/std-compare.h"
int test_int_spaceship(int a, int b) {
auto result = a <=> b;
- // CHECK: cir.cmp3way(%{{.*}} : !s32i, %{{.*}}, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
return (result < 0) ? -1 : (result > 0) ? 1 : 0;
+ // CIR: cir.cmp3way(%{{.*}} : !s32i, %{{.*}}, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
+ // LLVM: %[[CMP_LT:.*]] = icmp slt i32 %{{.*}}, %{{.*}}
+ // LLVM: %[[CMP_EQ:.*]] = icmp eq i32 %{{.*}}, %{{.*}}
+ // LLVM: %[[SEL1:.*]] = select i1 %[[CMP_EQ]], i32 0, i32 1
+ // LLVM: %[[SEL2:.*]] = select i1 %[[CMP_LT]], i32 -1, i32 %[[SEL1]]
+ // OGCG: %[[CMP_LT:.*]] = icmp slt i32 %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_LT:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 1
+ // OGCG: %[[CMP_EQ:.*]] = icmp eq i32 %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_EQ:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 %[[SEL_LT]]
}
unsigned int test_uint_spaceship(unsigned int a, unsigned int b) {
auto result = a <=> b;
- // CHECK: cir.cmp3way(%{{.*}} : !u32i, %{{.*}}, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
return (result < 0) ? 0 : (result > 0) ? 2 : 1;
+ // CIR: cir.cmp3way(%{{.*}} : !u32i, %{{.*}}, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
+ // LLVM: %[[CMP_LT:.*]] = icmp ult i32 %{{.*}}, %{{.*}}
+ // LLVM: %[[CMP_EQ:.*]] = icmp eq i32 %{{.*}}, %{{.*}}
+ // LLVM: %[[SEL1:.*]] = select i1 %[[CMP_EQ]], i32 0, i32 1
+ // LLVM: %[[SEL2:.*]] = select i1 %[[CMP_LT]], i32 -1, i32 %[[SEL1]]
+ // OGCG: %[[CMP_LT:.*]] = icmp ult i32 %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_LT:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 1
+ // OGCG: %[[CMP_EQ:.*]] = icmp eq i32 %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_EQ:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 %[[SEL_LT]]
}
float test_float_spaceship(float a, float b) {
auto result = a <=> b;
- // CHECK: cir.cmp3way(%{{.*}} : !cir.float, %{{.*}}, #cir.cmp3way_partial_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>)
return (result < 0) ? -1.0f : (result > 0) ? 1.0f : 0.0f;
-}
\ No newline at end of file
+ // CIR: cir.cmp3way(%{{.*}} : !cir.float, %{{.*}}, #cir.cmp3way_partial_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>)
+ // LLVM: %[[CMP_LT:.*]] = fcmp olt float %{{.*}}, %{{.*}}
+ // LLVM: %[[CMP_EQ:.*]] = fcmp oeq float %{{.*}}, %{{.*}}
+ // LLVM: %[[SEL1:.*]] = select i1 %[[CMP_EQ]], i32 0, i32 1
+ // LLVM: %[[SEL2:.*]] = select i1 %[[CMP_LT]], i32 -1, i32 %[[SEL1]]
+ // LLVM: %[[CMP_UNO:.*]] = fcmp uno float %{{.*}}, %{{.*}}
+ // LLVM: %[[SEL3:.*]] = select i1 %[[CMP_UNO]], i32 -127, i32 %[[SEL2]]
+ // OGCG: %[[CMP_EQ:.*]] = fcmp oeq float %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_EQ:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 -127
+ // OGCG: %[[CMP_GT:.*]] = fcmp ogt float %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_GT:.*]] = select i1 %[[CMP_GT]], i8 1, i8 %[[SEL_EQ]]
+ // OGCG: %[[CMP_LT:.*]] = fcmp olt float %{{.*}}, %{{.*}}
+ // OGCG: %[[SEL_LT:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_GT]]
+}
diff --git a/clang/test/CIR/Lowering/cmp3way.cir b/clang/test/CIR/Lowering/cmp3way.cir
index fe3740b6fd30d..6e82a2ac07593 100644
--- a/clang/test/CIR/Lowering/cmp3way.cir
+++ b/clang/test/CIR/Lowering/cmp3way.cir
@@ -1,14 +1,24 @@
-// RUN: cir-opt %s -cir-to-llvm -o %t.mlir
-// RUN: FileCheck --input-file=%t.mlir %s
+// RUN: cir-opt %s -cir-to-llvm -o %t.cir
+// RUN: FileCheck %s --input-file=%t.cir
!s32i = !cir.int<s, 32>
!u32i = !cir.int<u, 32>
-module {
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
cir.func @test_signed() -> !s32i {
%0 = cir.const #cir.int<5> : !s32i
%1 = cir.const #cir.int<3> : !s32i
%2 = cir.cmp3way(%0 : !s32i, %1, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
- // CHECK: llvm.icmp "slt"
+ // CHECK-LABEL: llvm.func @test_signed() -> i32
+ // CHECK: %[[VAL0:.*]] = llvm.mlir.constant(5 : i32) : i32
+ // CHECK: %[[VAL1:.*]] = llvm.mlir.constant(3 : i32) : i32
+ // CHECK: %[[LT_RESULT:.*]] = llvm.mlir.constant(-1 : i64) : i32
+ // CHECK: %[[EQ_RESULT:.*]] = llvm.mlir.constant(0 : i64) : i32
+ // CHECK: %[[GT_RESULT:.*]] = llvm.mlir.constant(1 : i64) : i32
+ // CHECK: %[[IS_LT:.*]] = llvm.icmp "slt" %[[VAL0]], %[[VAL1]] : i32
+ // CHECK: %[[IS_EQ:.*]] = llvm.icmp "eq" %[[VAL0]], %[[VAL1]] : i32
+ // CHECK: %[[EQ_OR_GT:.*]] = llvm.select %[[IS_EQ]], %[[EQ_RESULT]], %[[GT_RESULT]] : i1, i32
+ // CHECK: %[[FINAL:.*]] = llvm.select %[[IS_LT]], %[[LT_RESULT]], %[[EQ_OR_GT]] : i1, i32
+ // CHECK: llvm.return %[[FINAL]] : i32
cir.return %2 : !s32i
}
@@ -16,17 +26,59 @@ module {
%0 = cir.const #cir.int<5> : !u32i
%1 = cir.const #cir.int<3> : !u32i
%2 = cir.cmp3way(%0 : !u32i, %1, #cir.cmp3way_strong_info<strong, lt = -1, eq = 0, gt = 1>) : !s32i
- // CHECK: llvm.icmp "ult"
+ // CHECK-LABEL: llvm.func @test_unsigned() -> i32
+ // CHECK: %[[VAL0:.*]] = llvm.mlir.constant(5 : i32) : i32
+ // CHECK: %[[VAL1:.*]] = llvm.mlir.constant(3 : i32) : i32
+ // CHECK: %[[LT_RESULT:.*]] = llvm.mlir.constant(-1 : i64) : i32
+ // CHECK: %[[EQ_RESULT:.*]] = llvm.mlir.constant(0 : i64) : i32
+ // CHECK: %[[GT_RESULT:.*]] = llvm.mlir.constant(1 : i64) : i32
+ // CHECK: %[[IS_LT:.*]] = llvm.icmp "ult" %[[VAL0]], %[[VAL1]] : i32
+ // CHECK: %[[IS_EQ:.*]] = llvm.icmp "eq" %[[VAL0]], %[[VAL1]] : i32
+ // CHECK: %[[EQ_OR_GT:.*]] = llvm.select %[[IS_EQ]], %[[EQ_RESULT]], %[[GT_RESULT]] : i1, i32
+ // CHECK: %[[FINAL:.*]] = llvm.select %[[IS_LT]], %[[LT_RESULT]], %[[EQ_OR_GT]] : i1, i32
+ // CHECK: llvm.return %[[FINAL]] : i32
cir.return %2 : !s32i
}
- cir.func @test_float() -> !s32i {
+ cir.func @test_float_non_nan() -> !s32i {
%0 = cir.const #cir.fp<1.5> : !cir.float
%1 = cir.const #cir.fp<2.5> : !cir.float
%2 = cir.cmp3way(%0 : !cir.float, %1, #cir.cmp3way_partial_info<partial, lt = -1, eq = 0, gt = 1, unordered = 2>) : !s32i
- // CHECK: llvm.fcmp "olt"
- // CHECK: llvm.fcmp "oeq"
- // CHECK: llvm.fcmp "uno"
+ // CHECK-LABEL: llvm.func @test_float_non_nan() -> i32
+ // CHECK: %[[VAL0:.*]] = llvm.mlir.constant(1.500000e+00 : f32) : f32
+ // CHECK: %[[VAL1:.*]] = llvm.mlir.constant(2.500000e+00 : f32) : f32
+ // CHECK: %[[LT_RESULT:.*]] = llvm.mlir.constant(-1 : i64) : i32
+ // CHECK: %[[EQ_RESULT:.*]] = llvm.mlir.constant(0 : i64) : i32
+ // CHECK: %[[GT_RESULT:.*]] = llvm.mlir.constant(1 : i64) : i32
+ // CHECK: %[[UNO_RESULT:.*]] = llvm.mlir.constant(2 : i64) : i32
+ // CHECK: %[[IS_LT:.*]] = llvm.fcmp "olt" %[[VAL0]], %[[VAL1]] : f32
+ // CHECK: %[[IS_EQ:.*]] = llvm.fcmp "oeq" %[[VAL0]], %[[VAL1]] : f32
+ // CHECK: %[[EQ_OR_GT:.*]] = llvm.select %[[IS_EQ]], %[[EQ_RESULT]], %[[GT_RESULT]] : i1, i32
+ // CHECK: %[[LT_EQ_OR_GT:.*]] = llvm.select %[[IS_LT]], %[[LT_RESULT]], %[[EQ_OR_GT]] : i1, i32
+ // CHECK: %[[IS_UNO:.*]] = llvm.fcmp "uno" %[[VAL0]], %[[VAL1]] : f32
+ // CHECK: %[[FINAL:.*]] = llvm.select %[[IS_UNO]], %[[UNO_RESULT]], %[[LT_EQ_OR_GT]] : i1, i32
+ // CHECK: llvm.return %[[FINAL]] : i32
cir.return %2 : !s32i
}
-}
\ No newline at end of file
+
+ cir.func @test_float_nan() -> !s32i {
+ %0 = cir.const #cir.fp<0x7FC00000> : !cir.float
+ %1 = cir.const #cir.fp<2.5> : !cir.float
+ %2 = cir.cmp3way(%0 : !cir.float, %1, #cir.cmp3way_partial_info<partial, lt = -1, eq = 0, gt = 1, unordered = 2>) : !s32i
+ // CHECK-LABEL: llvm.func @test_float_nan() -> i32
+ // CHECK: %[[VAL0:.*]] = llvm.mlir.constant(0x7FC00000 : f32) : f32
+ // CHECK: %[[VAL1:.*]] = llvm.mlir.constant(2.500000e+00 : f32) : f32
+ // CHECK: %[[LT_RESULT:.*]] = llvm.mlir.constant(-1 : i64) : i32
+ // CHECK: %[[EQ_RESULT:.*]] = llvm.mlir.constant(0 : i64) : i32
+ // CHECK: %[[GT_RESULT:.*]] = llvm.mlir.constant(1 : i64) : i32
+ // CHECK: %[[UNO_RESULT:.*]] = llvm.mlir.constant(2 : i64) : i32
+ // CHECK: %[[IS_LT:.*]] = llvm.fcmp "olt" %[[VAL0]], %[[VAL1]] : f32
+ // CHECK: %[[IS_EQ:.*]] = llvm.fcmp "oeq" %[[VAL0]], %[[VAL1]] : f32
+ // CHECK: %[[EQ_OR_GT:.*]] = llvm.select %[[IS_EQ]], %[[EQ_RESULT]], %[[GT_RESULT]] : i1, i32
+ // CHECK: %[[LT_EQ_OR_GT:.*]] = llvm.select %[[IS_LT]], %[[LT_RESULT]], %[[EQ_OR_GT]] : i1, i32
+ // CHECK: %[[IS_UNO:.*]] = llvm.fcmp "uno" %[[VAL0]], %[[VAL1]] : f32
+ // CHECK: %[[FINAL:.*]] = llvm.select %[[IS_UNO]], %[[UNO_RESULT]], %[[LT_EQ_OR_GT]] : i1, i32
+ // CHECK: llvm.return %[[FINAL]] : i32
+ cir.return %2 : !s32i
+ }
+}
More information about the cfe-commits
mailing list