[clang] [CIR] Upstream CmpOp (PR #133159)
Morris Hafner via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 8 06:38:43 PDT 2025
https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/133159
>From 57b1d4e30ab61c1723b34fea137e2e900b53e30e Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Tue, 8 Apr 2025 15:02:12 +0200
Subject: [PATCH 1/5] [CIR] Upstream CmpOp
This patch adds support for comparison operators with ClangIR, both integral and floating point.
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 5 +
clang/include/clang/CIR/Dialect/IR/CIROps.td | 44 ++++
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 83 +++++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 82 ++++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 14 ++
clang/test/CIR/CodeGen/cmp.cpp | 233 ++++++++++++++++++
7 files changed, 461 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CIR/CodeGen/cmp.cpp
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index c1e93fe790c08..429d217541e28 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -335,6 +335,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return createAdd(loc, lhs, rhs, OverflowBehavior::NoUnsignedWrap);
}
+ cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
+ mlir::Value lhs, mlir::Value rhs) {
+ return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs);
+ }
+
//
// Block handling helpers
// ----------------------
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 609e60ca74b49..0d9864e1866fc 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1001,6 +1001,50 @@ def ForOp : LoopOpBase<"for"> {
}];
}
+//===----------------------------------------------------------------------===//
+// CmpOp
+//===----------------------------------------------------------------------===//
+
+def CmpOpKind_LT : I32EnumAttrCase<"lt", 1>;
+def CmpOpKind_LE : I32EnumAttrCase<"le", 2>;
+def CmpOpKind_GT : I32EnumAttrCase<"gt", 3>;
+def CmpOpKind_GE : I32EnumAttrCase<"ge", 4>;
+def CmpOpKind_EQ : I32EnumAttrCase<"eq", 5>;
+def CmpOpKind_NE : I32EnumAttrCase<"ne", 6>;
+
+def CmpOpKind : I32EnumAttr<
+ "CmpOpKind",
+ "compare operation kind",
+ [CmpOpKind_LT, CmpOpKind_LE, CmpOpKind_GT,
+ CmpOpKind_GE, CmpOpKind_EQ, CmpOpKind_NE]> {
+ let cppNamespace = "::cir";
+}
+
+def CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
+
+ let summary = "Compare values two values and produce a boolean result";
+ let description = [{
+ `cir.cmp` compares two input operands of the same type and produces a
+ `cir.bool` result. The kinds of comparison available are:
+ [lt,gt,ge,eq,ne]
+
+ ```mlir
+ %7 = cir.cmp(gt, %1, %2) : i32, !cir.bool
+ ```
+ }];
+
+ let results = (outs CIR_BoolType:$result);
+ let arguments = (ins Arg<CmpOpKind, "cmp kind">:$kind,
+ CIR_AnyType:$lhs, CIR_AnyType:$rhs);
+
+ let assemblyFormat = [{
+ `(` $kind `,` $lhs `,` $rhs `)` `:` type($lhs) `,` type($result) attr-dict
+ }];
+
+ // Already covered by the traits
+ let hasVerifier = 0;
+}
+
//===----------------------------------------------------------------------===//
// BinOp
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 86fdaf1ddaf51..c1963b15e3199 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -88,7 +88,6 @@ struct MissingFeatures {
static bool opGlobalViewAttr() { return false; }
static bool lowerModeOptLevel() { return false; }
static bool opTBAA() { return false; }
- static bool opCmp() { return false; }
static bool objCLifetime() { return false; }
static bool emitNullabilityCheck() { return false; }
static bool astVarDeclInterface() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3863d21487531..478234fb579a9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -707,6 +707,89 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
HANDLEBINOP(Xor)
HANDLEBINOP(Or)
#undef HANDLEBINOP
+
+ mlir::Value emitCmp(const BinaryOperator *e) {
+ mlir::Value result;
+ QualType lhsTy = e->getLHS()->getType();
+ QualType rhsTy = e->getRHS()->getType();
+
+ auto clangCmpToCIRCmp =
+ [](clang::BinaryOperatorKind clangCmp) -> cir::CmpOpKind {
+ switch (clangCmp) {
+ case BO_LT:
+ return cir::CmpOpKind::lt;
+ case BO_GT:
+ return cir::CmpOpKind::gt;
+ case BO_LE:
+ return cir::CmpOpKind::le;
+ case BO_GE:
+ return cir::CmpOpKind::ge;
+ case BO_EQ:
+ return cir::CmpOpKind::eq;
+ case BO_NE:
+ return cir::CmpOpKind::ne;
+ default:
+ llvm_unreachable("unsupported comparison kind");
+ }
+ };
+
+ if (lhsTy->getAs<MemberPointerType>()) {
+ assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
+ mlir::Value lhs = cgf.emitScalarExpr(e->getLHS());
+ mlir::Value rhs = cgf.emitScalarExpr(e->getRHS());
+ cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
+ result =
+ builder.createCompare(cgf.getLoc(e->getExprLoc()), kind, lhs, rhs);
+ } else if (!lhsTy->isAnyComplexType() && !rhsTy->isAnyComplexType()) {
+ BinOpInfo boInfo = emitBinOps(e);
+ mlir::Value lhs = boInfo.lhs;
+ mlir::Value rhs = boInfo.rhs;
+
+ if (lhsTy->isVectorType()) {
+ assert(!cir::MissingFeatures::vectorType());
+ cgf.cgm.errorNYI(boInfo.loc, "vector comparisons");
+ result = builder.getBool(false, cgf.getLoc(boInfo.loc));
+ } else if (boInfo.isFixedPointOp()) {
+ assert(!cir::MissingFeatures::fixedPointType());
+ cgf.cgm.errorNYI(boInfo.loc, "fixed point comparisons");
+ result = builder.getBool(false, cgf.getLoc(boInfo.loc));
+ } else if (lhsTy->hasSignedIntegerRepresentation()) {
+ cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
+ result = builder.createCompare(cgf.getLoc(boInfo.loc), kind, lhs, rhs);
+ } else {
+ // Unsigned integers and pointers.
+ if (cgf.cgm.getCodeGenOpts().StrictVTablePointers &&
+ mlir::isa<cir::PointerType>(lhs.getType()) &&
+ mlir::isa<cir::PointerType>(rhs.getType())) {
+ cgf.cgm.errorNYI(boInfo.loc, "strict vtable pointer comparisons");
+ result = builder.getBool(false, cgf.getLoc(boInfo.loc));
+ }
+
+ cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
+ result = builder.createCompare(cgf.getLoc(boInfo.loc), kind, lhs, rhs);
+ }
+ } else {
+ // Complex Comparison: can only be an equality comparison.
+ assert(!cir::MissingFeatures::complexType());
+ const mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ cgf.cgm.errorNYI(loc, "complex comparison");
+ result = builder.getBool(false, loc);
+ }
+
+ return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(),
+ e->getExprLoc());
+ }
+
+// Comparisons.
+#define VISITCOMP(CODE) \
+ mlir::Value VisitBin##CODE(const BinaryOperator *E) { return emitCmp(E); }
+ VISITCOMP(LT)
+ VISITCOMP(GT)
+ VISITCOMP(LE)
+ VISITCOMP(GE)
+ VISITCOMP(EQ)
+ VISITCOMP(NE)
+#undef VISITCOMP
};
LValue ScalarExprEmitter::emitCompoundAssignLValue(
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 81b80e2e4eafb..7ca36409c9cac 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -21,6 +21,7 @@
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Types.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"
@@ -1193,6 +1194,86 @@ mlir::LogicalResult CIRToLLVMBinOpLowering::matchAndRewrite(
return mlir::LogicalResult::success();
}
+/// Convert from a CIR comparison kind to an LLVM IR integral comparison kind.
+static mlir::LLVM::ICmpPredicate
+convertCmpKindToICmpPredicate(cir::CmpOpKind kind, bool isSigned) {
+ using CIR = cir::CmpOpKind;
+ using LLVMICmp = mlir::LLVM::ICmpPredicate;
+ switch (kind) {
+ case CIR::eq:
+ return LLVMICmp::eq;
+ case CIR::ne:
+ return LLVMICmp::ne;
+ case CIR::lt:
+ return (isSigned ? LLVMICmp::slt : LLVMICmp::ult);
+ case CIR::le:
+ return (isSigned ? LLVMICmp::sle : LLVMICmp::ule);
+ case CIR::gt:
+ return (isSigned ? LLVMICmp::sgt : LLVMICmp::ugt);
+ case CIR::ge:
+ return (isSigned ? LLVMICmp::sge : LLVMICmp::uge);
+ }
+ llvm_unreachable("Unknown CmpOpKind");
+}
+
+/// Convert from a CIR comparison kind to an LLVM IR floating-point comparison
+/// kind.
+static mlir::LLVM::FCmpPredicate
+convertCmpKindToFCmpPredicate(cir::CmpOpKind kind) {
+ using CIR = cir::CmpOpKind;
+ using LLVMFCmp = mlir::LLVM::FCmpPredicate;
+ switch (kind) {
+ case CIR::eq:
+ return LLVMFCmp::oeq;
+ case CIR::ne:
+ return LLVMFCmp::une;
+ case CIR::lt:
+ return LLVMFCmp::olt;
+ case CIR::le:
+ return LLVMFCmp::ole;
+ case CIR::gt:
+ return LLVMFCmp::ogt;
+ case CIR::ge:
+ return LLVMFCmp::oge;
+ }
+ llvm_unreachable("Unknown CmpOpKind");
+}
+
+mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
+ cir::CmpOp cmpOp, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type type = cmpOp.getLhs().getType();
+
+ assert(!cir::MissingFeatures::dataMemberType());
+ assert(!cir::MissingFeatures::methodType());
+
+ // Lower to LLVM comparison op.
+ if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) {
+ bool isSigned = mlir::isa<cir::IntType>(type)
+ ? mlir::cast<cir::IntType>(type).isSigned()
+ : mlir::cast<mlir::IntegerType>(type).isSigned();
+ mlir::LLVM::ICmpPredicate kind =
+ convertCmpKindToICmpPredicate(cmpOp.getKind(), isSigned);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
+ cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
+ } else if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type)) {
+ mlir::LLVM::ICmpPredicate kind =
+ convertCmpKindToICmpPredicate(cmpOp.getKind(),
+ /* isSigned=*/false);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
+ cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
+ } else if (mlir::isa<cir::CIRFPTypeInterface>(type)) {
+ mlir::LLVM::FCmpPredicate kind =
+ convertCmpKindToFCmpPredicate(cmpOp.getKind());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(
+ cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
+ } else {
+ return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
+ }
+
+ return mlir::success();
+}
+
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
mlir::DataLayout &dataLayout) {
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
@@ -1334,6 +1415,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMBinOpLowering,
CIRToLLVMBrCondOpLowering,
CIRToLLVMBrOpLowering,
+ CIRToLLVMCmpOpLowering,
CIRToLLVMConstantOpLowering,
CIRToLLVMFuncOpLowering,
CIRToLLVMTrapOpLowering,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 6f489fb49f44f..c85ece32a6349 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -186,6 +186,20 @@ class CIRToLLVMBinOpLowering : public mlir::OpConversionPattern<cir::BinOp> {
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMCmpOpLowering : public mlir::OpConversionPattern<cir::CmpOp> {
+public:
+ CIRToLLVMCmpOpLowering(const mlir::TypeConverter &typeConverter,
+ mlir::MLIRContext *context)
+ : OpConversionPattern(typeConverter, context) {
+ setHasBoundedRewriteRecursion();
+ }
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::CmpOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+
class CIRToLLVMBrOpLowering : public mlir::OpConversionPattern<cir::BrOp> {
public:
using mlir::OpConversionPattern<cir::BrOp>::OpConversionPattern;
diff --git a/clang/test/CIR/CodeGen/cmp.cpp b/clang/test/CIR/CodeGen/cmp.cpp
new file mode 100644
index 0000000000000..57d6b5b411f98
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cmp.cpp
@@ -0,0 +1,233 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -DCIR_ONLY %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+
+void c0(int a, int b) {
+ bool x = a > b;
+ x = a < b;
+ x = a <= b;
+ x = a >= b;
+ x = a != b;
+ x = a == b;
+}
+
+// CIR: cir.func @c0(
+
+// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init]
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]]
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]]
+// CIR: %{{.*}} = cir.cmp(gt, %[[A1]], %[[B1]]) : !s32i, !cir.bool
+// CIR: cir.store {{.*}}, %[[X_PTR]]
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]]
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]]
+// CIR: %{{.*}} = cir.cmp(lt, %[[A2]], %[[B2]]) : !s32i, !cir.bool
+
+// CIR: %[[A3:.*]] = cir.load %[[A_PTR]]
+// CIR: %[[B3:.*]] = cir.load %[[B_PTR]]
+// CIR: %{{.*}} = cir.cmp(le, %[[A3]], %[[B3]]) : !s32i, !cir.bool
+
+// CIR: %[[A4:.*]] = cir.load %[[A_PTR]]
+// CIR: %[[B4:.*]] = cir.load %[[B_PTR]]
+// CIR: %{{.*}} = cir.cmp(ge, %[[A4]], %[[B4]]) : !s32i, !cir.bool
+
+// CIR: %[[A5:.*]] = cir.load %[[A_PTR]]
+// CIR: %[[B5:.*]] = cir.load %[[B_PTR]]
+// CIR: %{{.*}} = cir.cmp(ne, %[[A5]], %[[B5]]) : !s32i, !cir.bool
+
+// CIR: %[[A6:.*]] = cir.load %[[A_PTR]]
+// CIR: %[[B6:.*]] = cir.load %[[B_PTR]]
+// CIR: %{{.*}} = cir.cmp(eq, %[[A6]], %[[B6]]) : !s32i, !cir.bool
+
+// LLVM: define void @c0(i32 %0, i32 %1) {
+// LLVM: %[[PTR1:.*]] = alloca i32, i64 1
+// LLVM: %[[PTR2:.*]] = alloca i32, i64 1
+// LLVM: %[[BOOL_PTR:.*]] = alloca i8, i64 1
+// LLVM: store i32 %0, ptr %[[PTR1]]
+// LLVM: store i32 %1, ptr %[[PTR2]]
+
+// LLVM: %[[A1:.*]] = load i32, ptr %[[PTR1]]
+// LLVM: %[[B1:.*]] = load i32, ptr %[[PTR2]]
+// LLVM: %[[CMP1:.*]] = icmp sgt i32 %[[A1]], %[[B1]]
+// LLVM: %[[ZEXT1:.*]] = zext i1 %[[CMP1]] to i8
+// LLVM: store i8 %[[ZEXT1]], ptr %[[BOOL_PTR]]
+
+// LLVM: %[[A2:.*]] = load i32, ptr %[[PTR1]]
+// LLVM: %[[B2:.*]] = load i32, ptr %[[PTR2]]
+// LLVM: %[[CMP2:.*]] = icmp slt i32 %[[A2]], %[[B2]]
+// LLVM: %[[ZEXT2:.*]] = zext i1 %[[CMP2]] to i8
+// LLVM: store i8 %[[ZEXT2]], ptr %[[BOOL_PTR]]
+
+// LLVM: %[[A3:.*]] = load i32, ptr %[[PTR1]]
+// LLVM: %[[B3:.*]] = load i32, ptr %[[PTR2]]
+// LLVM: %[[CMP3:.*]] = icmp sle i32 %[[A3]], %[[B3]]
+// LLVM: %[[ZEXT3:.*]] = zext i1 %[[CMP3]] to i8
+// LLVM: store i8 %[[ZEXT3]], ptr %[[BOOL_PTR]]
+
+// LLVM: %[[A4:.*]] = load i32, ptr %[[PTR1]]
+// LLVM: %[[B4:.*]] = load i32, ptr %[[PTR2]]
+// LLVM: %[[CMP4:.*]] = icmp sge i32 %[[A4]], %[[B4]]
+// LLVM: %[[ZEXT4:.*]] = zext i1 %[[CMP4]] to i8
+// LLVM: store i8 %[[ZEXT4]], ptr %[[BOOL_PTR]]
+
+// LLVM: %[[A5:.*]] = load i32, ptr %[[PTR1]]
+// LLVM: %[[B5:.*]] = load i32, ptr %[[PTR2]]
+// LLVM: %[[CMP5:.*]] = icmp ne i32 %[[A5]], %[[B5]]
+// LLVM: %[[ZEXT5:.*]] = zext i1 %[[CMP5]] to i8
+// LLVM: store i8 %[[ZEXT5]], ptr %[[BOOL_PTR]]
+
+// LLVM: %[[A6:.*]] = load i32, ptr %[[PTR1]]
+// LLVM: %[[B6:.*]] = load i32, ptr %[[PTR2]]
+// LLVM: %[[CMP6:.*]] = icmp eq i32 %[[A6]], %[[B6]]
+// LLVM: %[[ZEXT6:.*]] = zext i1 %[[CMP6]] to i8
+// LLVM: store i8 %[[ZEXT6]], ptr %[[BOOL_PTR]]
+
+void c0_unsigned(unsigned int a, unsigned int b) {
+ bool x = a > b;
+ x = a < b;
+ x = a <= b;
+ x = a >= b;
+ x = a != b;
+ x = a == b;
+}
+
+// CIR: cir.func @c0_unsigned(
+
+// CIR: %[[U_A_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
+// CIR: %[[U_B_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["b", init]
+// CIR: %[[U_X_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init]
+
+// CIR: %[[UA1:.*]] = cir.load %[[U_A_PTR]]
+// CIR: %[[UB1:.*]] = cir.load %[[U_B_PTR]]
+// CIR: %{{.*}} = cir.cmp(gt, %[[UA1]], %[[UB1]]) : !u32i, !cir.bool
+
+// CIR: %[[UA2:.*]] = cir.load %[[U_A_PTR]]
+// CIR: %[[UB2:.*]] = cir.load %[[U_B_PTR]]
+// CIR: %{{.*}} = cir.cmp(lt, %[[UA2]], %[[UB2]]) : !u32i, !cir.bool
+
+// CIR: %[[UA3:.*]] = cir.load %[[U_A_PTR]]
+// CIR: %[[UB3:.*]] = cir.load %[[U_B_PTR]]
+// CIR: %{{.*}} = cir.cmp(le, %[[UA3]], %[[UB3]]) : !u32i, !cir.bool
+
+// CIR: %[[UA4:.*]] = cir.load %[[U_A_PTR]]
+// CIR: %[[UB4:.*]] = cir.load %[[U_B_PTR]]
+// CIR: %{{.*}} = cir.cmp(ge, %[[UA4]], %[[UB4]]) : !u32i, !cir.bool
+
+// CIR: %[[UA5:.*]] = cir.load %[[U_A_PTR]]
+// CIR: %[[UB5:.*]] = cir.load %[[U_B_PTR]]
+// CIR: %{{.*}} = cir.cmp(ne, %[[UA5]], %[[UB5]]) : !u32i, !cir.bool
+
+// CIR: %[[UA6:.*]] = cir.load %[[U_A_PTR]]
+// CIR: %[[UB6:.*]] = cir.load %[[U_B_PTR]]
+// CIR: %{{.*}} = cir.cmp(eq, %[[UA6]], %[[UB6]]) : !u32i, !cir.bool
+
+// LLVM: define void @c0_unsigned(i32 %0, i32 %1) {
+// LLVM: %[[U_PTR1:.*]] = alloca i32, i64 1
+// LLVM: %[[U_PTR2:.*]] = alloca i32, i64 1
+// LLVM: %[[U_BOOL_PTR:.*]] = alloca i8, i64 1
+// LLVM: store i32 %0, ptr %[[U_PTR1]]
+// LLVM: store i32 %1, ptr %[[U_PTR2]]
+
+// LLVM: %[[UA1:.*]] = load i32, ptr %[[U_PTR1]]
+// LLVM: %[[UB1:.*]] = load i32, ptr %[[U_PTR2]]
+// LLVM: %[[UCMP1:.*]] = icmp ugt i32 %[[UA1]], %[[UB1]]
+// LLVM: %[[UZEXT1:.*]] = zext i1 %[[UCMP1]] to i8
+// LLVM: store i8 %[[UZEXT1]], ptr %[[U_BOOL_PTR]]
+
+// LLVM: %[[UA2:.*]] = load i32, ptr %[[U_PTR1]]
+// LLVM: %[[UB2:.*]] = load i32, ptr %[[U_PTR2]]
+// LLVM: %[[UCMP2:.*]] = icmp ult i32 %[[UA2]], %[[UB2]]
+// LLVM: %[[UZEXT2:.*]] = zext i1 %[[UCMP2]] to i8
+// LLVM: store i8 %[[UZEXT2]], ptr %[[U_BOOL_PTR]]
+
+// LLVM: %[[UA3:.*]] = load i32, ptr %[[U_PTR1]]
+// LLVM: %[[UB3:.*]] = load i32, ptr %[[U_PTR2]]
+// LLVM: %[[UCMP3:.*]] = icmp ule i32 %[[UA3]], %[[UB3]]
+// LLVM: %[[UZEXT3:.*]] = zext i1 %[[UCMP3]] to i8
+// LLVM: store i8 %[[UZEXT3]], ptr %[[U_BOOL_PTR]]
+
+// LLVM: %[[UA4:.*]] = load i32, ptr %[[U_PTR1]]
+// LLVM: %[[UB4:.*]] = load i32, ptr %[[U_PTR2]]
+// LLVM: %[[UCMP4:.*]] = icmp uge i32 %[[UA4]], %[[UB4]]
+// LLVM: %[[UZEXT4:.*]] = zext i1 %[[UCMP4]] to i8
+// LLVM: store i8 %[[UZEXT4]], ptr %[[U_BOOL_PTR]]
+
+// LLVM: %[[UA5:.*]] = load i32, ptr %[[U_PTR1]]
+// LLVM: %[[UB5:.*]] = load i32, ptr %[[U_PTR2]]
+// LLVM: %[[UCMP5:.*]] = icmp ne i32 %[[UA5]], %[[UB5]]
+// LLVM: %[[UZEXT5:.*]] = zext i1 %[[UCMP5]] to i8
+// LLVM: store i8 %[[UZEXT5]], ptr %[[U_BOOL_PTR]]
+
+// LLVM: %[[UA6:.*]] = load i32, ptr %[[U_PTR1]]
+// LLVM: %[[UB6:.*]] = load i32, ptr %[[U_PTR2]]
+// LLVM: %[[UCMP6:.*]] = icmp eq i32 %[[UA6]], %[[UB6]]
+// LLVM: %[[UZEXT6:.*]] = zext i1 %[[UCMP6]] to i8
+// LLVM: store i8 %[[UZEXT6]], ptr %[[U_BOOL_PTR]]
+
+void c0_float(float a, float b) {
+ bool x = a > b;
+ x = a < b;
+ x = a <= b;
+ x = a >= b;
+ x = a != b;
+ x = a == b;
+}
+
+// CIR: cir.func @c0_float(%arg0: !cir.float{{.*}}, %arg1: !cir.float{{.*}}) {
+// CIR: %[[A_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init]
+
+// CIR: cir.store %arg0, %[[A_PTR]] : !cir.float, !cir.ptr<!cir.float>
+// CIR: cir.store %arg1, %[[B_PTR]] : !cir.float, !cir.ptr<!cir.float>
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[CMP1:.*]] = cir.cmp(gt, %[[A1]], %[[B1]]) : !cir.float, !cir.bool
+// CIR: cir.store %[[CMP1]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[CMP2:.*]] = cir.cmp(lt, %[[A2]], %[[B2]]) : !cir.float, !cir.bool
+// CIR: cir.store %[[CMP2]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// CIR: %[[A3:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[B3:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[CMP3:.*]] = cir.cmp(le, %[[A3]], %[[B3]]) : !cir.float, !cir.bool
+// CIR: cir.store %[[CMP3]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// CIR: %[[A4:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[B4:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[CMP4:.*]] = cir.cmp(ge, %[[A4]], %[[B4]]) : !cir.float, !cir.bool
+// CIR: cir.store %[[CMP4]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// CIR: %[[A5:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[B5:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[CMP5:.*]] = cir.cmp(ne, %[[A5]], %[[B5]]) : !cir.float, !cir.bool
+// CIR: cir.store %[[CMP5]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// CIR: %[[A6:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[B6:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[CMP6:.*]] = cir.cmp(eq, %[[A6]], %[[B6]]) : !cir.float, !cir.bool
+// CIR: cir.store %[[CMP6]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// LLVM: define void @c0_float(float %0, float %1) {
+// LLVM: %[[A_PTR:.*]] = alloca float
+// LLVM: %[[B_PTR:.*]] = alloca float
+// LLVM: store float %0, ptr %[[A_PTR]]
+// LLVM: store float %1, ptr %[[B_PTR]]
+
+// LLVM: load float, ptr %[[A_PTR]]
+// LLVM: load float, ptr %[[B_PTR]]
+// LLVM: fcmp ogt float %{{.*}}, %{{.*}}
+// LLVM: zext i1 %{{.*}} to i8
+
+// LLVM: fcmp olt float %{{.*}}, %{{.*}}
+// LLVM: fcmp ole float %{{.*}}, %{{.*}}
+// LLVM: fcmp oge float %{{.*}}, %{{.*}}
+// LLVM: fcmp une float %{{.*}}, %{{.*}}
+// LLVM: fcmp oeq float %{{.*}}, %{{.*}}
>From eecc234d3752a0d43f74ce832776ea8cbe8d3288 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 26 Mar 2025 20:59:04 +0000
Subject: [PATCH 2/5] clang-format
---
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index c85ece32a6349..d53c4b31682bb 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -199,7 +199,6 @@ class CIRToLLVMCmpOpLowering : public mlir::OpConversionPattern<cir::CmpOp> {
mlir::ConversionPatternRewriter &) const override;
};
-
class CIRToLLVMBrOpLowering : public mlir::OpConversionPattern<cir::BrOp> {
public:
using mlir::OpConversionPattern<cir::BrOp>::OpConversionPattern;
>From 6a3216e4536264aecbffa0766e542404fb24197d Mon Sep 17 00:00:00 2001
From: Morris Hafner <mmha at users.noreply.github.com>
Date: Thu, 27 Mar 2025 14:46:17 +0000
Subject: [PATCH 3/5] Apply suggestions from code review
Co-authored-by: Henrich Lauko <xlauko at mail.muni.cz>
Co-authored-by: Andy Kaylor <akaylor at nvidia.com>
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 ---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 0d9864e1866fc..19fa532d151c3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1040,9 +1040,6 @@ def CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
let assemblyFormat = [{
`(` $kind `,` $lhs `,` $rhs `)` `:` type($lhs) `,` type($result) attr-dict
}];
-
- // Already covered by the traits
- let hasVerifier = 0;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 478234fb579a9..3ab7b822c89ad 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -729,7 +729,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
case BO_NE:
return cir::CmpOpKind::ne;
default:
- llvm_unreachable("unsupported comparison kind");
+ llvm_unreachable("unsupported comparison kind for cir.cmp");
}
};
>From 7753dc30b6d7dd857af6f5df62799233c2415047 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Thu, 27 Mar 2025 17:09:04 +0000
Subject: [PATCH 4/5] Address review feedback - Expand testing
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 22 +-
clang/test/CIR/CodeGen/cast.cpp | 23 +-
clang/test/CIR/CodeGen/cmp.cpp | 251 ++++++++++++++++++++-
3 files changed, 268 insertions(+), 28 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3ab7b822c89ad..9660f9b417718 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -709,6 +709,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
#undef HANDLEBINOP
mlir::Value emitCmp(const BinaryOperator *e) {
+ const mlir::Location loc = cgf.getLoc(e->getExprLoc());
mlir::Value result;
QualType lhsTy = e->getLHS()->getType();
QualType rhsTy = e->getRHS()->getType();
@@ -734,12 +735,12 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
};
if (lhsTy->getAs<MemberPointerType>()) {
+ assert(!cir::MissingFeatures::dataMemberType());
assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
mlir::Value lhs = cgf.emitScalarExpr(e->getLHS());
mlir::Value rhs = cgf.emitScalarExpr(e->getRHS());
cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
- result =
- builder.createCompare(cgf.getLoc(e->getExprLoc()), kind, lhs, rhs);
+ result = builder.createCompare(loc, kind, lhs, rhs);
} else if (!lhsTy->isAnyComplexType() && !rhsTy->isAnyComplexType()) {
BinOpInfo boInfo = emitBinOps(e);
mlir::Value lhs = boInfo.lhs;
@@ -747,31 +748,26 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (lhsTy->isVectorType()) {
assert(!cir::MissingFeatures::vectorType());
- cgf.cgm.errorNYI(boInfo.loc, "vector comparisons");
- result = builder.getBool(false, cgf.getLoc(boInfo.loc));
+ cgf.cgm.errorNYI(loc, "vector comparisons");
+ result = builder.getBool(false, loc);
} else if (boInfo.isFixedPointOp()) {
assert(!cir::MissingFeatures::fixedPointType());
- cgf.cgm.errorNYI(boInfo.loc, "fixed point comparisons");
- result = builder.getBool(false, cgf.getLoc(boInfo.loc));
- } else if (lhsTy->hasSignedIntegerRepresentation()) {
- cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
- result = builder.createCompare(cgf.getLoc(boInfo.loc), kind, lhs, rhs);
+ cgf.cgm.errorNYI(loc, "fixed point comparisons");
+ result = builder.getBool(false, loc);
} else {
// Unsigned integers and pointers.
if (cgf.cgm.getCodeGenOpts().StrictVTablePointers &&
mlir::isa<cir::PointerType>(lhs.getType()) &&
mlir::isa<cir::PointerType>(rhs.getType())) {
- cgf.cgm.errorNYI(boInfo.loc, "strict vtable pointer comparisons");
- result = builder.getBool(false, cgf.getLoc(boInfo.loc));
+ cgf.cgm.errorNYI(loc, "strict vtable pointer comparisons");
}
cir::CmpOpKind kind = clangCmpToCIRCmp(e->getOpcode());
- result = builder.createCompare(cgf.getLoc(boInfo.loc), kind, lhs, rhs);
+ result = builder.createCompare(loc, kind, lhs, rhs);
}
} else {
// Complex Comparison: can only be an equality comparison.
assert(!cir::MissingFeatures::complexType());
- const mlir::Location loc = cgf.getLoc(e->getSourceRange());
cgf.cgm.errorNYI(loc, "complex comparison");
result = builder.getBool(false, loc);
}
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
index ceae355a3ae1c..4a880e3479ea2 100644
--- a/clang/test/CIR/CodeGen/cast.cpp
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -DCIR_ONLY %s -o %t.cir
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
@@ -57,16 +57,16 @@ int cStyleCasts_0(unsigned x1, int x2, float x3, short x4, double x5) {
// CIR: %{{[0-9]+}} = cir.cast(bool_to_int, %{{[0-9]+}} : !cir.bool), !s32i
// LLVM: %{{[0-9]+}} = zext i1 %{{[0-9]+}} to i32
- #ifdef CIR_ONLY
bool b2 = x2; // int to bool
// CIR: %{{[0-9]+}} = cir.cast(int_to_bool, %{{[0-9]+}} : !s32i), !cir.bool
- #endif
+ // LLVM: %[[INTTOBOOL:[0-9]+]] = icmp ne i32 %{{[0-9]+}}, 0
+ // LLVM: zext i1 %[[INTTOBOOL]] to i8
- #ifdef CIR_ONLY
void *p;
- bool b3 = p; // ptr to bool
+ bool b3 = p; // ptr to bool
// CIR: %{{[0-9]+}} = cir.cast(ptr_to_bool, %{{[0-9]+}} : !cir.ptr<!void>), !cir.bool
- #endif
+ // LLVM: %[[PTRTOBOOL:[0-9]+]] = icmp ne ptr %{{[0-9]+}}, null
+ // LLVM: zext i1 %[[PTRTOBOOL]] to i8
float f;
bool b4 = f; // float to bool
@@ -77,7 +77,6 @@ int cStyleCasts_0(unsigned x1, int x2, float x3, short x4, double x5) {
return 0;
}
-#ifdef CIR_ONLY
bool cptr(void *d) {
bool x = d;
return x;
@@ -88,7 +87,15 @@ bool cptr(void *d) {
// CIR: %[[DVAL:[0-9]+]] = cir.load %[[DPTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: %{{[0-9]+}} = cir.cast(ptr_to_bool, %[[DVAL]] : !cir.ptr<!void>), !cir.bool
-#endif
+
+// LLVM-LABEL: define i1 @cptr(ptr %0)
+// LLVM: %[[ARG_STORAGE:.*]] = alloca ptr, i64 1
+// LLVM: %[[RETVAL:.*]] = alloca i8, i64 1
+// LLVM: %[[X_STORAGE:.*]] = alloca i8, i64 1
+// LLVM: store ptr %0, ptr %[[ARG_STORAGE]]
+// LLVM: %[[LOADED_PTR:.*]] = load ptr, ptr %[[ARG_STORAGE]]
+// LLVM: %[[NULL_CHECK:.*]] = icmp ne ptr %[[LOADED_PTR]], null
+// LLVM: ret i1
void should_not_cast() {
unsigned x1;
diff --git a/clang/test/CIR/CodeGen/cmp.cpp b/clang/test/CIR/CodeGen/cmp.cpp
index 57d6b5b411f98..a4f273a1d5802 100644
--- a/clang/test/CIR/CodeGen/cmp.cpp
+++ b/clang/test/CIR/CodeGen/cmp.cpp
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -DCIR_ONLY %s -o %t.cir
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
void c0(int a, int b) {
bool x = a > b;
@@ -12,7 +14,7 @@ void c0(int a, int b) {
x = a == b;
}
-// CIR: cir.func @c0(
+// CIR-LABEL: cir.func @c0(
// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CIR: %[[B_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
@@ -43,7 +45,7 @@ void c0(int a, int b) {
// CIR: %[[B6:.*]] = cir.load %[[B_PTR]]
// CIR: %{{.*}} = cir.cmp(eq, %[[A6]], %[[B6]]) : !s32i, !cir.bool
-// LLVM: define void @c0(i32 %0, i32 %1) {
+// LLVM-LABEL: define void @c0(i32 %0, i32 %1) {
// LLVM: %[[PTR1:.*]] = alloca i32, i64 1
// LLVM: %[[PTR2:.*]] = alloca i32, i64 1
// LLVM: %[[BOOL_PTR:.*]] = alloca i8, i64 1
@@ -86,6 +88,49 @@ void c0(int a, int b) {
// LLVM: %[[ZEXT6:.*]] = zext i1 %[[CMP6]] to i8
// LLVM: store i8 %[[ZEXT6]], ptr %[[BOOL_PTR]]
+// OGCG-LABEL: define dso_local void @_Z2c0ii(i32 {{.*}} %a, i32 {{.*}} %b) {{.*}} {
+// OGCG: %[[PTR1:.*]] = alloca i32
+// OGCG: %[[PTR2:.*]] = alloca i32
+// OGCG: %[[BOOL_PTR:.*]] = alloca i8
+// OGCG: store i32 %a, ptr %[[PTR1]]
+// OGCG: store i32 %b, ptr %[[PTR2]]
+
+// OGCO: %[[A1:.*]] = load i32, ptr %[[PTR1]]
+// OGCO: %[[B1:.*]] = load i32, ptr %[[PTR2]]
+// OGCO: %[[CMP1:.*]] = icmp sgt i32 %[[A1]], %[[B1]]
+// OGCO: %[[ZEXT1:.*]] = zext i1 %[[CMP1]] to i8
+// OGCO: store i8 %[[ZEXT1]], ptr %[[BOOL_PTR]]
+
+// OGCO: %[[A2:.*]] = load i32, ptr %[[PTR1]]
+// OGCO: %[[B2:.*]] = load i32, ptr %[[PTR2]]
+// OGCO: %[[CMP2:.*]] = icmp slt i32 %[[A2]], %[[B2]]
+// OGCO: %[[ZEXT2:.*]] = zext i1 %[[CMP2]] to i8
+// OGCO: store i8 %[[ZEXT2]], ptr %[[BOOL_PTR]]
+
+// OGCO: %[[A3:.*]] = load i32, ptr %[[PTR1]]
+// OGCO: %[[B3:.*]] = load i32, ptr %[[PTR2]]
+// OGCO: %[[CMP3:.*]] = icmp sle i32 %[[A3]], %[[B3]]
+// OGCO: %[[ZEXT3:.*]] = zext i1 %[[CMP3]] to i8
+// OGCO: store i8 %[[ZEXT3]], ptr %[[BOOL_PTR]]
+
+// OGCO: %[[A4:.*]] = load i32, ptr %[[PTR1]]
+// OGCO: %[[B4:.*]] = load i32, ptr %[[PTR2]]
+// OGCO: %[[CMP4:.*]] = icmp sge i32 %[[A4]], %[[B4]]
+// OGCO: %[[ZEXT4:.*]] = zext i1 %[[CMP4]] to i8
+// OGCO: store i8 %[[ZEXT4]], ptr %[[BOOL_PTR]]
+
+// OGCO: %[[A5:.*]] = load i32, ptr %[[PTR1]]
+// OGCO: %[[B5:.*]] = load i32, ptr %[[PTR2]]
+// OGCO: %[[CMP5:.*]] = icmp ne i32 %[[A5]], %[[B5]]
+// OGCO: %[[ZEXT5:.*]] = zext i1 %[[CMP5]] to i8
+// OGCO: store i8 %[[ZEXT5]], ptr %[[BOOL_PTR]]
+
+// OGCO: %[[A6:.*]] = load i32, ptr %[[PTR1]]
+// OGCO: %[[B6:.*]] = load i32, ptr %[[PTR2]]
+// OGCO: %[[CMP6:.*]] = icmp eq i32 %[[A6]], %[[B6]]
+// OGCO: %[[ZEXT6:.*]] = zext i1 %[[CMP6]] to i8
+// OGCO: store i8 %[[ZEXT6]], ptr %[[BOOL_PTR]]
+
void c0_unsigned(unsigned int a, unsigned int b) {
bool x = a > b;
x = a < b;
@@ -95,7 +140,7 @@ void c0_unsigned(unsigned int a, unsigned int b) {
x = a == b;
}
-// CIR: cir.func @c0_unsigned(
+// CIR-LABEL: cir.func @c0_unsigned(
// CIR: %[[U_A_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
// CIR: %[[U_B_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["b", init]
@@ -125,7 +170,7 @@ void c0_unsigned(unsigned int a, unsigned int b) {
// CIR: %[[UB6:.*]] = cir.load %[[U_B_PTR]]
// CIR: %{{.*}} = cir.cmp(eq, %[[UA6]], %[[UB6]]) : !u32i, !cir.bool
-// LLVM: define void @c0_unsigned(i32 %0, i32 %1) {
+// LLVM-LABEL: define void @c0_unsigned(i32 %0, i32 %1) {
// LLVM: %[[U_PTR1:.*]] = alloca i32, i64 1
// LLVM: %[[U_PTR2:.*]] = alloca i32, i64 1
// LLVM: %[[U_BOOL_PTR:.*]] = alloca i8, i64 1
@@ -168,6 +213,49 @@ void c0_unsigned(unsigned int a, unsigned int b) {
// LLVM: %[[UZEXT6:.*]] = zext i1 %[[UCMP6]] to i8
// LLVM: store i8 %[[UZEXT6]], ptr %[[U_BOOL_PTR]]
+// OGCG-LABEL: define dso_local void @_Z11c0_unsignedjj(i32 {{.*}} %a, i32 {{.*}} %b) {{.*}} {
+// OGCG: %[[U_PTR1:.*]] = alloca i32
+// OGCG: %[[U_PTR2:.*]] = alloca i32
+// OGCG: %[[U_BOOL_PTR:.*]] = alloca i8
+// OGCG: store i32 %a, ptr %[[U_PTR1]]
+// OGCG: store i32 %b, ptr %[[U_PTR2]]
+
+// OGCG: %[[UA1:.*]] = load i32, ptr %[[U_PTR1]]
+// OGCG: %[[UB1:.*]] = load i32, ptr %[[U_PTR2]]
+// OGCG: %[[UCMP1:.*]] = icmp ugt i32 %[[UA1]], %[[UB1]]
+// OGCG: %[[UZEXT1:.*]] = zext i1 %[[UCMP1]] to i8
+// OGCG: store i8 %[[UZEXT1]], ptr %[[U_BOOL_PTR]]
+
+// OGCG: %[[UA2:.*]] = load i32, ptr %[[U_PTR1]]
+// OGCG: %[[UB2:.*]] = load i32, ptr %[[U_PTR2]]
+// OGCG: %[[UCMP2:.*]] = icmp ult i32 %[[UA2]], %[[UB2]]
+// OGCG: %[[UZEXT2:.*]] = zext i1 %[[UCMP2]] to i8
+// OGCG: store i8 %[[UZEXT2]], ptr %[[U_BOOL_PTR]]
+
+// OGCG: %[[UA3:.*]] = load i32, ptr %[[U_PTR1]]
+// OGCG: %[[UB3:.*]] = load i32, ptr %[[U_PTR2]]
+// OGCG: %[[UCMP3:.*]] = icmp ule i32 %[[UA3]], %[[UB3]]
+// OGCG: %[[UZEXT3:.*]] = zext i1 %[[UCMP3]] to i8
+// OGCG: store i8 %[[UZEXT3]], ptr %[[U_BOOL_PTR]]
+
+// OGCG: %[[UA4:.*]] = load i32, ptr %[[U_PTR1]]
+// OGCG: %[[UB4:.*]] = load i32, ptr %[[U_PTR2]]
+// OGCG: %[[UCMP4:.*]] = icmp uge i32 %[[UA4]], %[[UB4]]
+// OGCG: %[[UZEXT4:.*]] = zext i1 %[[UCMP4]] to i8
+// OGCG: store i8 %[[UZEXT4]], ptr %[[U_BOOL_PTR]]
+
+// OGCG: %[[UA5:.*]] = load i32, ptr %[[U_PTR1]]
+// OGCG: %[[UB5:.*]] = load i32, ptr %[[U_PTR2]]
+// OGCG: %[[UCMP5:.*]] = icmp ne i32 %[[UA5]], %[[UB5]]
+// OGCG: %[[UZEXT5:.*]] = zext i1 %[[UCMP5]] to i8
+// OGCG: store i8 %[[UZEXT5]], ptr %[[U_BOOL_PTR]]
+
+// OGCG: %[[UA6:.*]] = load i32, ptr %[[U_PTR1]]
+// OGCG: %[[UB6:.*]] = load i32, ptr %[[U_PTR2]]
+// OGCG: %[[UCMP6:.*]] = icmp eq i32 %[[UA6]], %[[UB6]]
+// OGCG: %[[UZEXT6:.*]] = zext i1 %[[UCMP6]] to i8
+// OGCG: store i8 %[[UZEXT6]], ptr %[[U_BOOL_PTR]]
+
void c0_float(float a, float b) {
bool x = a > b;
x = a < b;
@@ -177,7 +265,7 @@ void c0_float(float a, float b) {
x = a == b;
}
-// CIR: cir.func @c0_float(%arg0: !cir.float{{.*}}, %arg1: !cir.float{{.*}}) {
+// CIR-LABEL: cir.func @c0_float(%arg0: !cir.float{{.*}}, %arg1: !cir.float{{.*}}) {
// CIR: %[[A_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CIR: %[[B_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init]
// CIR: %[[X_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init]
@@ -215,7 +303,7 @@ void c0_float(float a, float b) {
// CIR: %[[CMP6:.*]] = cir.cmp(eq, %[[A6]], %[[B6]]) : !cir.float, !cir.bool
// CIR: cir.store %[[CMP6]], %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
-// LLVM: define void @c0_float(float %0, float %1) {
+// LLVM-LABEL: define void @c0_float(float %0, float %1) {
// LLVM: %[[A_PTR:.*]] = alloca float
// LLVM: %[[B_PTR:.*]] = alloca float
// LLVM: store float %0, ptr %[[A_PTR]]
@@ -231,3 +319,152 @@ void c0_float(float a, float b) {
// LLVM: fcmp oge float %{{.*}}, %{{.*}}
// LLVM: fcmp une float %{{.*}}, %{{.*}}
// LLVM: fcmp oeq float %{{.*}}, %{{.*}}
+
+// OGCG-LABEL: define dso_local void @_Z8c0_floatff(float {{.*}} %a, float {{.*}} %b) {{.*}} {
+// OGCG: %[[A_PTR:.*]] = alloca float
+// OGCG: %[[B_PTR:.*]] = alloca float
+// OGCG: store float %a, ptr %[[A_PTR]]
+// OGCG: store float %b, ptr %[[B_PTR]]
+
+// OGCG: load float, ptr %[[A_PTR]]
+// OGCG: load float, ptr %[[B_PTR]]
+// OGCG: fcmp ogt float %{{.*}}, %{{.*}}
+// OGCG: zext i1 %{{.*}} to i8
+
+// OGCG: fcmp olt float %{{.*}}, %{{.*}}
+// OGCG: fcmp ole float %{{.*}}, %{{.*}}
+// OGCG: fcmp oge float %{{.*}}, %{{.*}}
+// OGCG: fcmp une float %{{.*}}, %{{.*}}
+// OGCG: fcmp oeq float %{{.*}}, %{{.*}}
+
+void pointer_cmp(int *a, int *b) {
+ bool x = a > b;
+ x = a < b;
+ x = a >= b;
+ x = a <= b;
+ x = a == b;
+ x = a != b;
+}
+
+// CIR-LABEL: cir.func @pointer_cmp(%arg0: !cir.ptr<!s32i>{{.*}}, %arg1: !cir.ptr<!s32i>{{.*}}) {
+// CIR: %[[A_PTR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["b", init]
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %{{.*}} = cir.cmp(gt, %[[A1]], %[[B1]]) : !cir.ptr<!s32i>, !cir.bool
+
+// CIR: cir.cmp(lt, {{.*}}, {{.*}}) : !cir.ptr<!s32i>, !cir.bool
+// CIR: cir.cmp(ge, {{.*}}, {{.*}}) : !cir.ptr<!s32i>, !cir.bool
+// CIR: cir.cmp(le, {{.*}}, {{.*}}) : !cir.ptr<!s32i>, !cir.bool
+// CIR: cir.cmp(eq, {{.*}}, {{.*}}) : !cir.ptr<!s32i>, !cir.bool
+// CIR: cir.cmp(ne, {{.*}}, {{.*}}) : !cir.ptr<!s32i>, !cir.bool
+
+// LLVM-LABEL: define void @pointer_cmp(ptr %0, ptr %1) {
+// LLVM: %[[A_PTR:.*]] = alloca ptr
+// LLVM: %[[B_PTR:.*]] = alloca ptr
+// LLVM: store ptr %0, ptr %[[A_PTR]]
+// LLVM: store ptr %1, ptr %[[B_PTR]]
+
+// LLVM: load ptr, ptr %[[A_PTR]]
+// LLVM: load ptr, ptr %[[B_PTR]]
+// LLVM: icmp ugt ptr %{{.*}}, %{{.*}}
+// LLVM: zext i1 %{{.*}} to i8
+// LLVM: icmp ult ptr %{{.*}}, %{{.*}}
+// LLVM: icmp uge ptr %{{.*}}, %{{.*}}
+// LLVM: icmp ule ptr %{{.*}}, %{{.*}}
+// LLVM: icmp eq ptr %{{.*}}, %{{.*}}
+// LLVM: icmp ne ptr %{{.*}}, %{{.*}}
+
+// OGCG-LABEL: define dso_local void @_Z11pointer_cmpPiS_(ptr {{.*}} %a, ptr {{.*}} %b) {{.*}} {
+// OGCG: %[[A_PTR:.*]] = alloca ptr
+// OGCG: %[[B_PTR:.*]] = alloca ptr
+// OGCG: store ptr %a, ptr %[[A_PTR]]
+// OGCG: store ptr %b, ptr %[[B_PTR]]
+
+// OGCG: load ptr, ptr %[[A_PTR]]
+// OGCG: load ptr, ptr %[[B_PTR]]
+// OGCG: icmp ugt ptr %{{.*}}, %{{.*}}
+// OGCG: zext i1 %{{.*}} to i8
+// OGCG: icmp ult ptr %{{.*}}, %{{.*}}
+// OGCG: icmp uge ptr %{{.*}}, %{{.*}}
+// OGCG: icmp ule ptr %{{.*}}, %{{.*}}
+// OGCG: icmp eq ptr %{{.*}}, %{{.*}}
+// OGCG: icmp ne ptr %{{.*}}, %{{.*}}
+
+void bool_cmp(bool a, bool b) {
+ bool x = a > b;
+ x = a < b;
+ x = a >= b;
+ x = a <= b;
+ x = a == b;
+ x = a != b;
+}
+
+// CIR-LABEL: cir.func @bool_cmp(%arg0: !cir.bool{{.*}}, %arg1: !cir.bool{{.*}}) {
+// CIR: %[[A_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init]
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!cir.bool>, !cir.bool
+// CIR: %[[A1_INT:.*]] = cir.cast(bool_to_int, %[[A1]] : !cir.bool), !s32i
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!cir.bool>, !cir.bool
+// CIR: %[[B1_INT:.*]] = cir.cast(bool_to_int, %[[B1]] : !cir.bool), !s32i
+// CIR: %{{.*}} = cir.cmp(gt, %[[A1_INT]], %[[B1_INT]]) : !s32i, !cir.bool
+// CIR: cir.store {{.*}}, %[[X_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// CIR: cir.cmp(lt
+// CIR: cir.cmp(ge
+// CIR: cir.cmp(le
+// CIR: cir.cmp(eq
+// CIR: cir.cmp(ne
+
+// LLVM-LABEL: define void @bool_cmp(i1 %0, i1 %1) {
+// LLVM: %[[A_PTR:.*]] = alloca i8
+// LLVM: %[[B_PTR:.*]] = alloca i8
+// LLVM: %[[X_PTR:.*]] = alloca i8
+// LLVM: %[[A_INIT:.*]] = zext i1 %0 to i8
+// LLVM: store i8 %[[A_INIT]], ptr %[[A_PTR]]
+// LLVM: %[[B_INIT:.*]] = zext i1 %1 to i8
+// LLVM: store i8 %[[B_INIT]], ptr %[[B_PTR]]
+
+// LLVM: %[[A1:.*]] = load i8, ptr %[[A_PTR]]
+// LLVM: %[[A1_TRUNC:.*]] = trunc i8 %[[A1]] to i1
+// LLVM: %[[A1_EXT:.*]] = zext i1 %[[A1_TRUNC]] to i32
+// LLVM: %[[B1:.*]] = load i8, ptr %[[B_PTR]]
+// LLVM: %[[B1_TRUNC:.*]] = trunc i8 %[[B1]] to i1
+// LLVM: %[[B1_EXT:.*]] = zext i1 %[[B1_TRUNC]] to i32
+// LLVM: %[[CMP1:.*]] = icmp sgt i32 %[[A1_EXT]], %[[B1_EXT]]
+// LLVM: %[[CMP1_BOOL:.*]] = zext i1 %[[CMP1]] to i8
+// LLVM: store i8 %[[CMP1_BOOL]], ptr %[[X_PTR]]
+
+// LLVM: icmp slt
+// LLVM: icmp sge
+// LLVM: icmp sle
+// LLVM: icmp eq
+// LLVM: icmp ne
+
+// OGCG-LABEL: define dso_local void @_Z8bool_cmpbb(i1 {{.*}} %a, i1 {{.*}} %b) {{.*}} {
+// OGCG: %[[A_PTR:.*]] = alloca i8
+// OGCG: %[[B_PTR:.*]] = alloca i8
+// OGCG: %[[X_PTR:.*]] = alloca i8
+// OGCG: %[[A_INIT:.*]] = zext i1 %a to i8
+// OGCG: store i8 %[[A_INIT]], ptr %[[A_PTR]]
+// OGCG: %[[B_INIT:.*]] = zext i1 %b to i8
+// OGCG: store i8 %[[B_INIT]], ptr %[[B_PTR]]
+
+// OGCG: %[[A1:.*]] = load i8, ptr %[[A_PTR]]
+// OGCG: %[[A1_TRUNC:.*]] = trunc i8 %[[A1]] to i1
+// OGCG: %[[A1_EXT:.*]] = zext i1 %[[A1_TRUNC]] to i32
+// OGCG: %[[B1:.*]] = load i8, ptr %[[B_PTR]]
+// OGCG: %[[B1_TRUNC:.*]] = trunc i8 %[[B1]] to i1
+// OGCG: %[[B1_EXT:.*]] = zext i1 %[[B1_TRUNC]] to i32
+// OGCG: %[[CMP1:.*]] = icmp sgt i32 %[[A1_EXT]], %[[B1_EXT]]
+// OGCG: %[[CMP1_BOOL:.*]] = zext i1 %[[CMP1]] to i8
+// OGCG: store i8 %[[CMP1_BOOL]], ptr %[[X_PTR]]
+
+// OGCG: icmp slt
+// OGCG: icmp sge
+// OGCG: icmp sle
+// OGCG: icmp eq
+// OGCG: icmp ne
>From f28235fd5e5a8bc9116f76c165b1ee25b204836d Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Tue, 8 Apr 2025 15:38:22 +0200
Subject: [PATCH 5/5] Review feedback
- Fix comment
- Add roundtrip test
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +-
clang/test/CIR/IR/cmp.cir | 359 +++++++++++++++++++++
2 files changed, 360 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CIR/IR/cmp.cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 9660f9b417718..ed49f395b7d51 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -755,7 +755,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
cgf.cgm.errorNYI(loc, "fixed point comparisons");
result = builder.getBool(false, loc);
} else {
- // Unsigned integers and pointers.
+ // integers and pointers
if (cgf.cgm.getCodeGenOpts().StrictVTablePointers &&
mlir::isa<cir::PointerType>(lhs.getType()) &&
mlir::isa<cir::PointerType>(rhs.getType())) {
diff --git a/clang/test/CIR/IR/cmp.cir b/clang/test/CIR/IR/cmp.cir
new file mode 100644
index 0000000000000..a049dc51f1401
--- /dev/null
+++ b/clang/test/CIR/IR/cmp.cir
@@ -0,0 +1,359 @@
+// RUN: cir-opt %s | cir-opt | FileCheck %s
+!s32i = !cir.int<s, 32>
+!u32i = !cir.int<u, 32>
+
+module {
+ cir.func @c0(%arg0: !s32i, %arg1: !s32i) {
+ %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+ %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] {alignment = 4 : i64}
+ %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+ cir.store %arg1, %1 : !s32i, !cir.ptr<!s32i>
+ %3 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %4 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %5 = cir.cmp(gt, %3, %4) : !s32i, !cir.bool
+ cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %6 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %7 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %8 = cir.cmp(lt, %6, %7) : !s32i, !cir.bool
+ cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %9 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %10 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %11 = cir.cmp(le, %9, %10) : !s32i, !cir.bool
+ cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %12 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %13 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %14 = cir.cmp(ge, %12, %13) : !s32i, !cir.bool
+ cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %15 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %16 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %17 = cir.cmp(ne, %15, %16) : !s32i, !cir.bool
+ cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %18 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %19 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %20 = cir.cmp(eq, %18, %19) : !s32i, !cir.bool
+ cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ cir.return
+ }
+
+ // CHECK: cir.func @c0(%arg0: !s32i, %arg1: !s32i) {
+ // CHECK-NEXT: %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+ // CHECK-NEXT: %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] {alignment = 4 : i64}
+ // CHECK-NEXT: %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ // CHECK-NEXT: cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+ // CHECK-NEXT: cir.store %arg1, %1 : !s32i, !cir.ptr<!s32i>
+ // CHECK-NEXT: %3 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %4 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %5 = cir.cmp(gt, %3, %4) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %6 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %7 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %8 = cir.cmp(lt, %6, %7) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %9 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %10 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %11 = cir.cmp(le, %9, %10) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %12 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %13 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %14 = cir.cmp(ge, %12, %13) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %15 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %16 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %17 = cir.cmp(ne, %15, %16) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %18 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %19 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %20 = cir.cmp(eq, %18, %19) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: cir.return
+ // CHECK-NEXT: }
+
+ cir.func @c0_unsigned(%arg0: !u32i, %arg1: !u32i) {
+ %0 = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init] {alignment = 4 : i64}
+ %1 = cir.alloca !u32i, !cir.ptr<!u32i>, ["b", init] {alignment = 4 : i64}
+ %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ cir.store %arg0, %0 : !u32i, !cir.ptr<!u32i>
+ cir.store %arg1, %1 : !u32i, !cir.ptr<!u32i>
+ %3 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %4 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ %5 = cir.cmp(gt, %3, %4) : !u32i, !cir.bool
+ cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %6 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %7 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ %8 = cir.cmp(lt, %6, %7) : !u32i, !cir.bool
+ cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %9 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %10 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ %11 = cir.cmp(le, %9, %10) : !u32i, !cir.bool
+ cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %12 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %13 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ %14 = cir.cmp(ge, %12, %13) : !u32i, !cir.bool
+ cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %15 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %16 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ %17 = cir.cmp(ne, %15, %16) : !u32i, !cir.bool
+ cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %18 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %19 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ %20 = cir.cmp(eq, %18, %19) : !u32i, !cir.bool
+ cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ cir.return
+ }
+
+ // CHECK: cir.func @c0_unsigned(%arg0: !u32i, %arg1: !u32i) {
+ // CHECK-NEXT: %0 = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init] {alignment = 4 : i64}
+ // CHECK-NEXT: %1 = cir.alloca !u32i, !cir.ptr<!u32i>, ["b", init] {alignment = 4 : i64}
+ // CHECK-NEXT: %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ // CHECK-NEXT: cir.store %arg0, %0 : !u32i, !cir.ptr<!u32i>
+ // CHECK-NEXT: cir.store %arg1, %1 : !u32i, !cir.ptr<!u32i>
+ // CHECK-NEXT: %3 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %4 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %5 = cir.cmp(gt, %3, %4) : !u32i, !cir.bool
+ // CHECK-NEXT: cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %6 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %7 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %8 = cir.cmp(lt, %6, %7) : !u32i, !cir.bool
+ // CHECK-NEXT: cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %9 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %10 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %11 = cir.cmp(le, %9, %10) : !u32i, !cir.bool
+ // CHECK-NEXT: cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %12 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %13 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %14 = cir.cmp(ge, %12, %13) : !u32i, !cir.bool
+ // CHECK-NEXT: cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %15 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %16 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %17 = cir.cmp(ne, %15, %16) : !u32i, !cir.bool
+ // CHECK-NEXT: cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %18 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %19 = cir.load %1 : !cir.ptr<!u32i>, !u32i
+ // CHECK-NEXT: %20 = cir.cmp(eq, %18, %19) : !u32i, !cir.bool
+ // CHECK-NEXT: cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: cir.return
+ // CHECK-NEXT: }
+
+ cir.func @c0_float(%arg0: !cir.float, %arg1: !cir.float) {
+ %0 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init] {alignment = 4 : i64}
+ %1 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] {alignment = 4 : i64}
+ %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ cir.store %arg0, %0 : !cir.float, !cir.ptr<!cir.float>
+ cir.store %arg1, %1 : !cir.float, !cir.ptr<!cir.float>
+ %3 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ %4 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ %5 = cir.cmp(gt, %3, %4) : !cir.float, !cir.bool
+ cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %6 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ %7 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ %8 = cir.cmp(lt, %6, %7) : !cir.float, !cir.bool
+ cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %9 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ %10 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ %11 = cir.cmp(le, %9, %10) : !cir.float, !cir.bool
+ cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %12 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ %13 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ %14 = cir.cmp(ge, %12, %13) : !cir.float, !cir.bool
+ cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %15 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ %16 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ %17 = cir.cmp(ne, %15, %16) : !cir.float, !cir.bool
+ cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %18 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ %19 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ %20 = cir.cmp(eq, %18, %19) : !cir.float, !cir.bool
+ cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ cir.return
+ }
+
+ // CHECK: cir.func @c0_float(%arg0: !cir.float, %arg1: !cir.float) {
+ // CHECK-NEXT: %0 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init] {alignment = 4 : i64}
+ // CHECK-NEXT: %1 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] {alignment = 4 : i64}
+ // CHECK-NEXT: %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ // CHECK-NEXT: cir.store %arg0, %0 : !cir.float, !cir.ptr<!cir.float>
+ // CHECK-NEXT: cir.store %arg1, %1 : !cir.float, !cir.ptr<!cir.float>
+ // CHECK-NEXT: %3 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %4 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %5 = cir.cmp(gt, %3, %4) : !cir.float, !cir.bool
+ // CHECK-NEXT: cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %6 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %7 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %8 = cir.cmp(lt, %6, %7) : !cir.float, !cir.bool
+ // CHECK-NEXT: cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %9 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %10 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %11 = cir.cmp(le, %9, %10) : !cir.float, !cir.bool
+ // CHECK-NEXT: cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %12 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %13 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %14 = cir.cmp(ge, %12, %13) : !cir.float, !cir.bool
+ // CHECK-NEXT: cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %15 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %16 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %17 = cir.cmp(ne, %15, %16) : !cir.float, !cir.bool
+ // CHECK-NEXT: cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %18 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %19 = cir.load %1 : !cir.ptr<!cir.float>, !cir.float
+ // CHECK-NEXT: %20 = cir.cmp(eq, %18, %19) : !cir.float, !cir.bool
+ // CHECK-NEXT: cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: cir.return
+ // CHECK-NEXT: }
+
+ cir.func @pointer_cmp(%arg0: !cir.ptr<!s32i>, %arg1: !cir.ptr<!s32i>) {
+ %0 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["a", init] {alignment = 8 : i64}
+ %1 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["b", init] {alignment = 8 : i64}
+ %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ cir.store %arg0, %0 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+ cir.store %arg1, %1 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+ %3 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %4 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %5 = cir.cmp(gt, %3, %4) : !cir.ptr<!s32i>, !cir.bool
+ cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %6 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %7 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %8 = cir.cmp(lt, %6, %7) : !cir.ptr<!s32i>, !cir.bool
+ cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %9 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %10 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %11 = cir.cmp(ge, %9, %10) : !cir.ptr<!s32i>, !cir.bool
+ cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %12 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %13 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %14 = cir.cmp(le, %12, %13) : !cir.ptr<!s32i>, !cir.bool
+ cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %15 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %16 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %17 = cir.cmp(eq, %15, %16) : !cir.ptr<!s32i>, !cir.bool
+ cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %18 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %19 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ %20 = cir.cmp(ne, %18, %19) : !cir.ptr<!s32i>, !cir.bool
+ cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ cir.return
+ }
+
+ // CHECK: cir.func @pointer_cmp(%arg0: !cir.ptr<!s32i>, %arg1: !cir.ptr<!s32i>) {
+ // CHECK-NEXT: %0 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["a", init] {alignment = 8 : i64}
+ // CHECK-NEXT: %1 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["b", init] {alignment = 8 : i64}
+ // CHECK-NEXT: %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ // CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+ // CHECK-NEXT: cir.store %arg1, %1 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+ // CHECK-NEXT: %3 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %4 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %5 = cir.cmp(gt, %3, %4) : !cir.ptr<!s32i>, !cir.bool
+ // CHECK-NEXT: cir.store %5, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %6 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %7 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %8 = cir.cmp(lt, %6, %7) : !cir.ptr<!s32i>, !cir.bool
+ // CHECK-NEXT: cir.store %8, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %9 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %10 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %11 = cir.cmp(ge, %9, %10) : !cir.ptr<!s32i>, !cir.bool
+ // CHECK-NEXT: cir.store %11, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %12 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %13 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %14 = cir.cmp(le, %12, %13) : !cir.ptr<!s32i>, !cir.bool
+ // CHECK-NEXT: cir.store %14, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %15 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %16 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %17 = cir.cmp(eq, %15, %16) : !cir.ptr<!s32i>, !cir.bool
+ // CHECK-NEXT: cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %18 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %19 = cir.load %1 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CHECK-NEXT: %20 = cir.cmp(ne, %18, %19) : !cir.ptr<!s32i>, !cir.bool
+ // CHECK-NEXT: cir.store %20, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: cir.return
+ // CHECK-NEXT: }
+
+ cir.func @bool_cmp(%arg0: !cir.bool, %arg1: !cir.bool) {
+ %0 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["a", init] {alignment = 1 : i64}
+ %1 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b", init] {alignment = 1 : i64}
+ %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ cir.store %arg0, %0 : !cir.bool, !cir.ptr<!cir.bool>
+ cir.store %arg1, %1 : !cir.bool, !cir.ptr<!cir.bool>
+ %3 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %4 = cir.cast(bool_to_int, %3 : !cir.bool), !s32i
+ %5 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ %6 = cir.cast(bool_to_int, %5 : !cir.bool), !s32i
+ %7 = cir.cmp(gt, %4, %6) : !s32i, !cir.bool
+ cir.store %7, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %8 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %9 = cir.cast(bool_to_int, %8 : !cir.bool), !s32i
+ %10 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ %11 = cir.cast(bool_to_int, %10 : !cir.bool), !s32i
+ %12 = cir.cmp(lt, %9, %11) : !s32i, !cir.bool
+ cir.store %12, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %13 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %14 = cir.cast(bool_to_int, %13 : !cir.bool), !s32i
+ %15 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ %16 = cir.cast(bool_to_int, %15 : !cir.bool), !s32i
+ %17 = cir.cmp(ge, %14, %16) : !s32i, !cir.bool
+ cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %18 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %19 = cir.cast(bool_to_int, %18 : !cir.bool), !s32i
+ %20 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ %21 = cir.cast(bool_to_int, %20 : !cir.bool), !s32i
+ %22 = cir.cmp(le, %19, %21) : !s32i, !cir.bool
+ cir.store %22, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %23 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %24 = cir.cast(bool_to_int, %23 : !cir.bool), !s32i
+ %25 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ %26 = cir.cast(bool_to_int, %25 : !cir.bool), !s32i
+ %27 = cir.cmp(eq, %24, %26) : !s32i, !cir.bool
+ cir.store %27, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ %28 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %29 = cir.cast(bool_to_int, %28 : !cir.bool), !s32i
+ %30 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ %31 = cir.cast(bool_to_int, %30 : !cir.bool), !s32i
+ %32 = cir.cmp(ne, %29, %31) : !s32i, !cir.bool
+ cir.store %32, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ cir.return
+ }
+
+ // CHECK: cir.func @bool_cmp(%arg0: !cir.bool, %arg1: !cir.bool) {
+ // CHECK-NEXT: %0 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["a", init] {alignment = 1 : i64}
+ // CHECK-NEXT: %1 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b", init] {alignment = 1 : i64}
+ // CHECK-NEXT: %2 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["x", init] {alignment = 1 : i64}
+ // CHECK-NEXT: cir.store %arg0, %0 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: cir.store %arg1, %1 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %3 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %4 = cir.cast(bool_to_int, %3 : !cir.bool), !s32i
+ // CHECK-NEXT: %5 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %6 = cir.cast(bool_to_int, %5 : !cir.bool), !s32i
+ // CHECK-NEXT: %7 = cir.cmp(gt, %4, %6) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %7, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %8 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %9 = cir.cast(bool_to_int, %8 : !cir.bool), !s32i
+ // CHECK-NEXT: %10 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %11 = cir.cast(bool_to_int, %10 : !cir.bool), !s32i
+ // CHECK-NEXT: %12 = cir.cmp(lt, %9, %11) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %12, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %13 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %14 = cir.cast(bool_to_int, %13 : !cir.bool), !s32i
+ // CHECK-NEXT: %15 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %16 = cir.cast(bool_to_int, %15 : !cir.bool), !s32i
+ // CHECK-NEXT: %17 = cir.cmp(ge, %14, %16) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %17, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %18 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %19 = cir.cast(bool_to_int, %18 : !cir.bool), !s32i
+ // CHECK-NEXT: %20 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %21 = cir.cast(bool_to_int, %20 : !cir.bool), !s32i
+ // CHECK-NEXT: %22 = cir.cmp(le, %19, %21) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %22, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %23 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %24 = cir.cast(bool_to_int, %23 : !cir.bool), !s32i
+ // CHECK-NEXT: %25 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %26 = cir.cast(bool_to_int, %25 : !cir.bool), !s32i
+ // CHECK-NEXT: %27 = cir.cmp(eq, %24, %26) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %27, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: %28 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %29 = cir.cast(bool_to_int, %28 : !cir.bool), !s32i
+ // CHECK-NEXT: %30 = cir.load %1 : !cir.ptr<!cir.bool>, !cir.bool
+ // CHECK-NEXT: %31 = cir.cast(bool_to_int, %30 : !cir.bool), !s32i
+ // CHECK-NEXT: %32 = cir.cmp(ne, %29, %31) : !s32i, !cir.bool
+ // CHECK-NEXT: cir.store %32, %2 : !cir.bool, !cir.ptr<!cir.bool>
+ // CHECK-NEXT: cir.return
+ // CHECK-NEXT: }
+}
More information about the cfe-commits
mailing list