[clang] [CIR] Upstream ThreeWayCmpOp (PR #169963)
Hendrik Hübner via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 15 09:16:22 PST 2026
https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/169963
>From 12b9415d7ac61a52bd3849ea69c8907ac5316596 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Fri, 28 Nov 2025 23:41:30 +0100
Subject: [PATCH 1/5] [CIR] Upstream three way compare op
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 62 ++++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 64 ++++
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 31 ++
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 58 +++-
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 54 +++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 20 ++
.../Dialect/Transforms/LoweringPrepare.cpp | 42 +++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 52 +++
clang/test/CIR/CodeGen/Inputs/std-compare.h | 307 ++++++++++++++++++
clang/test/CIR/CodeGen/three-way-cmp.cpp | 72 ++++
10 files changed, 761 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CIR/CodeGen/Inputs/std-compare.h
create mode 100644 clang/test/CIR/CodeGen/three-way-cmp.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 15c2c6e034af9..e85283a0f3dd8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -572,6 +572,68 @@ def CIR_MethodAttr : CIR_Attr<"Method", "method", [TypedAttrInterface]> {
}];
}
+//===----------------------------------------------------------------------===//
+// CmpThreeWayInfoAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_CmpOrdering : CIR_I32EnumAttr<
+ "CmpOrdering", "three-way comparison ordering kind", [
+ I32EnumAttrCase<"Strong", 0, "strong">,
+ I32EnumAttrCase<"Partial", 1, "partial">
+]> {
+ let genSpecializedAttr = 0;
+}
+
+def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
+ let summary = "Holds information about a three-way comparison operation";
+ let description = [{
+ The `#cmp3way_info` attribute contains information about a three-way
+ comparison operation `cir.cmp3way`.
+
+ The `ordering` parameter gives the ordering kind of the three-way comparison
+ operation. It may be either strong ordering or partial ordering.
+
+ Given the two input operands of the three-way comparison operation `lhs` and
+ `rhs`, the `lt`, `eq`, `gt`, and `unordered` parameters gives the result
+ value that should be produced by the three-way comparison operation when the
+ ordering between `lhs` and `rhs` is `lhs < rhs`, `lhs == rhs`, `lhs > rhs`,
+ or neither, respectively.
+ }];
+
+ let parameters = (ins
+ EnumParameter<CIR_CmpOrdering>:$ordering,
+ "int64_t":$lt, "int64_t":$eq, "int64_t":$gt,
+ OptionalParameter<"std::optional<int64_t>">:$unordered
+ );
+
+ let builders = [
+ AttrBuilder<(ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt), [{
+ return $_get($_ctxt, CmpOrdering::Strong, lt, eq, gt, std::nullopt);
+ }]>,
+ AttrBuilder<(ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt,
+ "int64_t":$unordered), [{
+ return $_get($_ctxt, CmpOrdering::Partial, lt, eq, gt, unordered);
+ }]>,
+ ];
+
+ let extraClassDeclaration = [{
+ /// Get attribute alias name for this attribute.
+ std::string getAlias() const;
+ }];
+
+ let assemblyFormat = [{
+ `<`
+ $ordering `,`
+ `lt` `=` $lt `,`
+ `eq` `=` $eq `,`
+ `gt` `=` $gt
+ (`,` `unordered` `=` $unordered^)?
+ `>`
+ }];
+
+ let genVerifyDecl = 1;
+}
+
//===----------------------------------------------------------------------===//
// GlobalViewAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7085580d99718..5fc3acd2a2145 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1243,6 +1243,70 @@ def CIR_CleanupScopeOp : CIR_Op<"cleanup.scope", [
let hasLLVMLowering = false;
}
+//===----------------------------------------------------------------------===//
+// CmpThreeWayOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
+ let summary = "Compare two values with C++ three-way comparison semantics";
+ let description = [{
+ The `cir.cmp3way` operation models the `<=>` operator in C++20. It takes two
+ operands with the same type and produces a result indicating the ordering
+ between the two input operands.
+
+ The result of the operation is a signed integer that indicates the ordering
+ between the two input operands.
+
+ There are two kinds of ordering: strong ordering and partial ordering.
+ Comparing different types of values yields different kinds of orderings.
+ The `info` parameter gives the ordering kind and other necessary information
+ about the comparison.
+
+ Example:
+
+ ```mlir
+ !s32i = !cir.int<s, 32>
+
+ #cmp3way_strong = #cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
+ #cmp3way_partial = #cmp3way_info<strong, lt = -1, eq = 0, gt = 1, unordered = 2>
+
+ %0 = cir.const #cir.int<0> : !s32i
+ %1 = cir.const #cir.int<1> : !s32i
+ %2 = cir.cmp3way(%0 : !s32i, %1, #cmp3way_strong) : !s8i
+
+ %3 = cir.const #cir.fp<0.0> : !cir.float
+ %4 = cir.const #cir.fp<1.0> : !cir.float
+ %5 = cir.cmp3way(%3 : !cir.float, %4, #cmp3way_partial) : !s8i
+ ```
+ }];
+
+ 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
+ }];
+
+ let extraClassDeclaration = [{
+ /// Determine whether this three-way comparison produces a strong ordering.
+ bool isStrongOrdering() {
+ return getInfo().getOrdering() == cir::CmpOrdering::Strong;
+ }
+
+ /// Determine whether this three-way comparison compares integral operands.
+ bool isIntegralComparison() {
+ return mlir::isa<cir::IntType>(getLhs().getType());
+ }
+ }];
+
+ let hasVerifier = 1;
+}
//===----------------------------------------------------------------------===//
// SwitchOp
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index debd2faa29ef3..df85edbfb3c3a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -655,6 +655,37 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::StackRestoreOp::create(*this, loc, v);
}
+ cir::CmpThreeWayOp createThreeWayCmpStrong(mlir::Location loc,
+ mlir::Value lhs, mlir::Value rhs,
+ const llvm::APSInt <Res,
+ const llvm::APSInt &eqRes,
+ const llvm::APSInt >Res) {
+ assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
+ ltRes.getBitWidth() == gtRes.getBitWidth() &&
+ "the three comparison results must have the same bit width");
+ cir::IntType cmpResultTy = getSIntNTy(ltRes.getBitWidth());
+ auto infoAttr = cir::CmpThreeWayInfoAttr::get(
+ getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(), gtRes.getSExtValue());
+ return cir::CmpThreeWayOp::create(*this, loc, cmpResultTy, lhs, rhs,
+ infoAttr);
+ }
+
+ cir::CmpThreeWayOp
+ createThreeWayCmpPartial(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
+ const llvm::APSInt <Res, const llvm::APSInt &eqRes,
+ const llvm::APSInt >Res,
+ const llvm::APSInt &unorderedRes) {
+ assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
+ ltRes.getBitWidth() == gtRes.getBitWidth() &&
+ ltRes.getBitWidth() == unorderedRes.getBitWidth() &&
+ "the four comparison results must have the same bit width");
+ auto cmpResultTy = getSIntNTy(ltRes.getBitWidth());
+ auto infoAttr = cir::CmpThreeWayInfoAttr::get(
+ getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(), gtRes.getSExtValue(), unorderedRes.getSExtValue());
+ return cir::CmpThreeWayOp::create(*this, loc, cmpResultTy, lhs, rhs,
+ infoAttr);
+ }
+
mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
Address dstAddr, mlir::Type storageType,
mlir::Value src, const CIRGenBitFieldInfo &info,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index f5f3655802915..bc01604eb3293 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/IR/Value.h"
#include <cstdint>
using namespace clang;
@@ -326,8 +327,63 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
Visit(e->getRHS());
}
void VisitBinCmp(const BinaryOperator *e) {
- cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp");
+ assert(cgf.getContext().hasSameType(e->getLHS()->getType(),
+ e->getRHS()->getType()));
+ const ComparisonCategoryInfo &cmpInfo =
+ cgf.getContext().CompCategories.getInfoForType(e->getType());
+ assert(cmpInfo.Record->isTriviallyCopyable() &&
+ "cannot copy non-trivially copyable aggregate");
+
+ QualType argTy = e->getLHS()->getType();
+
+ if (!argTy->isIntegralOrEnumerationType() && !argTy->isRealFloatingType() &&
+ !argTy->isNullPtrType() && !argTy->isPointerType() &&
+ !argTy->isMemberPointerType() && !argTy->isAnyComplexType())
+ llvm_unreachable("aggregate three-way comparison");
+
+ mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ CIRGenBuilderTy builder = cgf.getBuilder();
+
+ if (e->getType()->isAnyComplexType())
+ llvm_unreachable("NYI");
+
+ mlir::Value lhs = cgf.emitAnyExpr(e->getLHS()).getValue();
+ mlir::Value rhs = cgf.emitAnyExpr(e->getRHS()).getValue();
+
+ mlir::Value resultScalar;
+ if (argTy->isNullPtrType()) {
+ resultScalar =
+ builder.getConstInt(loc, cmpInfo.getEqualOrEquiv()->getIntValue());
+ } else {
+ llvm::APSInt ltRes = cmpInfo.getLess()->getIntValue();
+ llvm::APSInt eqRes = cmpInfo.getEqualOrEquiv()->getIntValue();
+ llvm::APSInt gtRes = cmpInfo.getGreater()->getIntValue();
+ if (!cmpInfo.isPartial()) {
+ // Strong ordering.
+ resultScalar = builder.createThreeWayCmpStrong(loc, lhs, rhs, ltRes,
+ eqRes, gtRes);
+ } else {
+ // Partial ordering.
+ llvm::APSInt unorderedRes = cmpInfo.getUnordered()->getIntValue();
+ resultScalar = builder.createThreeWayCmpPartial(
+ loc, lhs, rhs, ltRes, eqRes, gtRes, unorderedRes);
+ }
+ }
+
+ // Create the return value in the destination slot.
+ ensureDest(loc, e->getType());
+ LValue destLVal = cgf.makeAddrLValue(dest.getAddress(), e->getType());
+
+ // Emit the address of the first (and only) field in the comparison category
+ // type, and initialize it from the constant integer value produced above.
+ const FieldDecl *resultField = *cmpInfo.Record->field_begin();
+ LValue fieldLVal = cgf.emitLValueForFieldInitialization(destLVal, resultField,
+ resultField->getName());
+ cgf.emitStoreThroughLValue(RValue::get(resultScalar), fieldLVal);
+
+ // All done! The result is in the dest slot.
}
+
void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCXXRewrittenBinaryOperator");
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 43bd33759fba9..ed0d4af8c80da 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -249,6 +249,60 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return success();
}
+
+//===----------------------------------------------------------------------===//
+// CmpThreeWayInfoAttr definitions
+//===----------------------------------------------------------------------===//
+
+std::string CmpThreeWayInfoAttr::getAlias() const {
+ std::string alias = "cmp3way_info";
+
+ if (getOrdering() == CmpOrdering::Strong)
+ alias.append("_strong_");
+ else
+ alias.append("_partial_");
+
+ auto appendInt = [&](int64_t value) {
+ if (value < 0) {
+ alias.push_back('n');
+ value = -value;
+ }
+ alias.append(std::to_string(value));
+ };
+
+ alias.append("lt");
+ appendInt(getLt());
+ alias.append("eq");
+ appendInt(getEq());
+ alias.append("gt");
+ appendInt(getGt());
+
+ if (std::optional<int> unordered = getUnordered()) {
+ alias.append("un");
+ appendInt(unordered.value());
+ }
+
+ return alias;
+}
+
+LogicalResult
+CmpThreeWayInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ CmpOrdering ordering, int64_t lt, int64_t eq,
+ int64_t gt, std::optional<int64_t> unordered) {
+ // The presense of unordered must match the value of ordering.
+ if (ordering == CmpOrdering::Strong && unordered) {
+ emitError() << "strong ordering does not include unordered ordering";
+ return failure();
+ }
+ if (ordering == CmpOrdering::Partial && !unordered) {
+ emitError() << "partial ordering lacks unordered ordering";
+ return failure();
+ }
+
+ return success();
+}
+
+
//===----------------------------------------------------------------------===//
// ConstComplexAttr definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 4a25407d0f3cf..966ebdb5ff78d 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -80,6 +80,11 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface {
os << dynCastInfoAttr.getAlias();
return AliasResult::FinalAlias;
}
+ if (auto cmpThreeWayInfoAttr =
+ mlir::dyn_cast<cir::CmpThreeWayInfoAttr>(attr)) {
+ os << cmpThreeWayInfoAttr.getAlias();
+ return AliasResult::FinalAlias;
+ }
return AliasResult::NoAlias;
}
};
@@ -1471,6 +1476,21 @@ Block *cir::BrCondOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {
return nullptr;
}
+
+//===----------------------------------------------------------------------===//
+// CmpThreeWayOp
+//===----------------------------------------------------------------------===//
+
+mlir::LogicalResult CmpThreeWayOp::verify() {
+ // Type of the result must be a signed integer type.
+ if (!getType().isSigned()) {
+ emitOpError() << "result type of cir.cmp3way must be a signed integer type";
+ return failure();
+ }
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// CaseOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 688dfdc29e850..2ae4b158aefd2 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -75,6 +75,8 @@ struct LoweringPreparePass
void lowerComplexMulOp(cir::ComplexMulOp op);
void lowerUnaryOp(cir::UnaryOp op);
void lowerGlobalOp(cir::GlobalOp op);
+ void lowerThreeWayCmpOp(cir::CmpThreeWayOp op);
+ void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
void lowerTrivialCopyCall(cir::CallOp op);
@@ -1280,6 +1282,40 @@ void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
assert(!cir::MissingFeatures::opGlobalAnnotations());
}
+void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
+ CIRBaseBuilderTy builder(getContext());
+ builder.setInsertionPointAfter(op);
+
+ mlir::Location loc = op->getLoc();
+ cir::CmpThreeWayInfoAttr cmpInfo = op.getInfo();
+
+ mlir::Value ltRes = builder.getConstantInt(loc, op.getType(), cmpInfo.getLt());
+ mlir::Value eqRes = builder.getConstantInt(loc, op.getType(), cmpInfo.getEq());
+ mlir::Value gtRes = builder.getConstantInt(loc, op.getType(), cmpInfo.getGt());
+
+ mlir::Value lt = builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ mlir::Value eq = builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+
+ mlir::Value transformedResult;
+ if (cmpInfo.getOrdering() == CmpOrdering::Strong) {
+ // Strong ordering.
+ mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, gtRes);
+ transformedResult = builder.createSelect(loc, lt, ltRes, selectOnEq);
+ } else {
+ // Partial ordering.
+ cir::ConstantOp unorderedRes =
+ builder.getConstantInt(loc, op.getType(), cmpInfo.getUnordered().value());
+
+ mlir::Value gt = builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, unorderedRes);
+ mlir::Value selectOnGt = builder.createSelect(loc, gt, gtRes, selectOnEq);
+ transformedResult = builder.createSelect(loc, lt, ltRes, selectOnGt);
+ }
+
+ op.replaceAllUsesWith(transformedResult);
+ op.erase();
+}
+
template <typename AttributeTy>
static llvm::SmallVector<mlir::Attribute>
prepareCtorDtorAttrList(mlir::MLIRContext *context,
@@ -1500,6 +1536,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
else if (auto globalDtor = fnOp.getGlobalDtorPriority())
globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
+ } else if (auto threeWayCmp = dyn_cast<CmpThreeWayOp>(op)) {
+ lowerThreeWayCmpOp(threeWayCmp);
}
}
@@ -1513,8 +1551,12 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
+<<<<<<< HEAD
cir::FuncOp, cir::CallOp, cir::GetGlobalOp, cir::GlobalOp,
cir::UnaryOp>(op))
+=======
+ cir::FuncOp, cir::GlobalOp, cir::UnaryOp, cir::CmpThreeWayOp>(op))
+>>>>>>> 32285f45356c ([CIR] Upstream three way compare op)
opsToTransform.push_back(op);
});
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 28b3454d20613..824eb98add218 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1575,6 +1575,58 @@ mlir::LogicalResult CIRToLLVMGetElementOpLowering::matchAndRewrite(
return mlir::failure();
}
+static std::string getThreeWayCmpIntrinsicName(
+ bool signedCmp, unsigned operandWidth, unsigned resultWidth) {
+ // The intrinsic's name takes the form:
+ // `llvm.<scmp|ucmp>.i<resultWidth>.i<operandWidth>`
+
+ std::string result = "llvm.";
+
+ if (signedCmp)
+ result.append("scmp.");
+ else
+ result.append("ucmp.");
+
+ // Result type part.
+ result.push_back('i');
+ result.append(std::to_string(resultWidth));
+ result.push_back('.');
+
+ // Operand type part.
+ result.push_back('i');
+ result.append(std::to_string(operandWidth));
+
+ return result;
+}
+
+mlir::LogicalResult CIRToLLVMCmpThreeWayOpLowering::matchAndRewrite(
+ cir::CmpThreeWayOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ if (!op.isIntegralComparison() || !op.isStrongOrdering()) {
+ op.emitError() << "unsupported three-way comparison type";
+ return mlir::failure();
+ }
+
+ cir::CmpThreeWayInfoAttr cmpInfo = op.getInfo();
+ assert(cmpInfo.getLt() == -1 && cmpInfo.getEq() == 0 && cmpInfo.getGt() == 1);
+
+ auto operandTy = mlir::cast<cir::IntType>(op.getLhs().getType());
+ cir::IntType resultTy = op.getType();
+ std::string llvmIntrinsicName = getThreeWayCmpIntrinsicName(
+ operandTy.isSigned(), operandTy.getWidth(), resultTy.getWidth());
+
+ rewriter.setInsertionPoint(op);
+
+ mlir::Value llvmLhs = adaptor.getLhs();
+ mlir::Value llvmRhs = adaptor.getRhs();
+ mlir::Type llvmResultTy = getTypeConverter()->convertType(resultTy);
+ mlir::LLVM::CallIntrinsicOp callIntrinsicOp =
+ createCallLLVMIntrinsicOp(rewriter, op.getLoc(), llvmIntrinsicName,
+ llvmResultTy, {llvmLhs, llvmRhs});
+
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/Inputs/std-compare.h b/clang/test/CIR/CodeGen/Inputs/std-compare.h
new file mode 100644
index 0000000000000..eaf7951edf79c
--- /dev/null
+++ b/clang/test/CIR/CodeGen/Inputs/std-compare.h
@@ -0,0 +1,307 @@
+#ifndef STD_COMPARE_H
+#define STD_COMPARE_H
+
+namespace std {
+inline namespace __1 {
+
+// exposition only
+enum class _EqResult : unsigned char {
+ __equal = 0,
+ __equiv = __equal,
+};
+
+enum class _OrdResult : signed char {
+ __less = -1,
+ __greater = 1
+};
+
+enum class _NCmpResult : signed char {
+ __unordered = -127
+};
+
+struct _CmpUnspecifiedType;
+using _CmpUnspecifiedParam = void (_CmpUnspecifiedType::*)();
+
+class partial_ordering {
+ using _ValueT = signed char;
+ explicit constexpr partial_ordering(_EqResult __v) noexcept
+ : __value_(_ValueT(__v)) {}
+ explicit constexpr partial_ordering(_OrdResult __v) noexcept
+ : __value_(_ValueT(__v)) {}
+ explicit constexpr partial_ordering(_NCmpResult __v) noexcept
+ : __value_(_ValueT(__v)) {}
+
+ constexpr bool __is_ordered() const noexcept {
+ return __value_ != _ValueT(_NCmpResult::__unordered);
+ }
+
+public:
+ // valid values
+ static const partial_ordering less;
+ static const partial_ordering equivalent;
+ static const partial_ordering greater;
+ static const partial_ordering unordered;
+
+ // comparisons
+ friend constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator!=(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator<(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator<=(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator>(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator>=(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator==(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+ friend constexpr bool operator!=(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+ friend constexpr bool operator<(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+ friend constexpr bool operator<=(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+ friend constexpr bool operator>(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+ friend constexpr bool operator>=(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+
+ friend constexpr partial_ordering operator<=>(partial_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr partial_ordering operator<=>(_CmpUnspecifiedParam, partial_ordering __v) noexcept;
+
+ // test helper
+ constexpr bool test_eq(partial_ordering const &other) const noexcept {
+ return __value_ == other.__value_;
+ }
+
+private:
+ _ValueT __value_;
+};
+
+inline constexpr partial_ordering partial_ordering::less(_OrdResult::__less);
+inline constexpr partial_ordering partial_ordering::equivalent(_EqResult::__equiv);
+inline constexpr partial_ordering partial_ordering::greater(_OrdResult::__greater);
+inline constexpr partial_ordering partial_ordering::unordered(_NCmpResult ::__unordered);
+constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__is_ordered() && __v.__value_ == 0;
+}
+constexpr bool operator<(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__is_ordered() && __v.__value_ < 0;
+}
+constexpr bool operator<=(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__is_ordered() && __v.__value_ <= 0;
+}
+constexpr bool operator>(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__is_ordered() && __v.__value_ > 0;
+}
+constexpr bool operator>=(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__is_ordered() && __v.__value_ >= 0;
+}
+constexpr bool operator==(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return __v.__is_ordered() && 0 == __v.__value_;
+}
+constexpr bool operator<(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return __v.__is_ordered() && 0 < __v.__value_;
+}
+constexpr bool operator<=(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return __v.__is_ordered() && 0 <= __v.__value_;
+}
+constexpr bool operator>(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return __v.__is_ordered() && 0 > __v.__value_;
+}
+constexpr bool operator>=(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return __v.__is_ordered() && 0 >= __v.__value_;
+}
+constexpr bool operator!=(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return !__v.__is_ordered() || __v.__value_ != 0;
+}
+constexpr bool operator!=(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return !__v.__is_ordered() || __v.__value_ != 0;
+}
+
+constexpr partial_ordering operator<=>(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v;
+}
+constexpr partial_ordering operator<=>(_CmpUnspecifiedParam, partial_ordering __v) noexcept {
+ return __v < 0 ? partial_ordering::greater : (__v > 0 ? partial_ordering::less : __v);
+}
+
+class weak_ordering {
+ using _ValueT = signed char;
+ explicit constexpr weak_ordering(_EqResult __v) noexcept : __value_(_ValueT(__v)) {}
+ explicit constexpr weak_ordering(_OrdResult __v) noexcept : __value_(_ValueT(__v)) {}
+
+public:
+ static const weak_ordering less;
+ static const weak_ordering equivalent;
+ static const weak_ordering greater;
+
+ // conversions
+ constexpr operator partial_ordering() const noexcept {
+ return __value_ == 0 ? partial_ordering::equivalent
+ : (__value_ < 0 ? partial_ordering::less : partial_ordering::greater);
+ }
+
+ // comparisons
+ friend constexpr bool operator==(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator!=(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator<(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator<=(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator>(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator>=(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator==(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+ friend constexpr bool operator!=(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+ friend constexpr bool operator<(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+ friend constexpr bool operator<=(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+ friend constexpr bool operator>(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+ friend constexpr bool operator>=(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+
+ friend constexpr weak_ordering operator<=>(weak_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr weak_ordering operator<=>(_CmpUnspecifiedParam, weak_ordering __v) noexcept;
+
+ // test helper
+ constexpr bool test_eq(weak_ordering const &other) const noexcept {
+ return __value_ == other.__value_;
+ }
+
+private:
+ _ValueT __value_;
+};
+
+inline constexpr weak_ordering weak_ordering::less(_OrdResult::__less);
+inline constexpr weak_ordering weak_ordering::equivalent(_EqResult::__equiv);
+inline constexpr weak_ordering weak_ordering::greater(_OrdResult::__greater);
+constexpr bool operator==(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ == 0;
+}
+constexpr bool operator!=(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ != 0;
+}
+constexpr bool operator<(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ < 0;
+}
+constexpr bool operator<=(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ <= 0;
+}
+constexpr bool operator>(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ > 0;
+}
+constexpr bool operator>=(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ >= 0;
+}
+constexpr bool operator==(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return 0 == __v.__value_;
+}
+constexpr bool operator!=(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return 0 != __v.__value_;
+}
+constexpr bool operator<(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return 0 < __v.__value_;
+}
+constexpr bool operator<=(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return 0 <= __v.__value_;
+}
+constexpr bool operator>(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return 0 > __v.__value_;
+}
+constexpr bool operator>=(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return 0 >= __v.__value_;
+}
+
+constexpr weak_ordering operator<=>(weak_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v;
+}
+constexpr weak_ordering operator<=>(_CmpUnspecifiedParam, weak_ordering __v) noexcept {
+ return __v < 0 ? weak_ordering::greater : (__v > 0 ? weak_ordering::less : __v);
+}
+
+class strong_ordering {
+ using _ValueT = signed char;
+ explicit constexpr strong_ordering(_EqResult __v) noexcept : __value_(static_cast<signed char>(__v)) {}
+ explicit constexpr strong_ordering(_OrdResult __v) noexcept : __value_(static_cast<signed char>(__v)) {}
+
+public:
+ static const strong_ordering less;
+ static const strong_ordering equal;
+ static const strong_ordering equivalent;
+ static const strong_ordering greater;
+
+ // conversions
+ constexpr operator partial_ordering() const noexcept {
+ return __value_ == 0 ? partial_ordering::equivalent
+ : (__value_ < 0 ? partial_ordering::less : partial_ordering::greater);
+ }
+ constexpr operator weak_ordering() const noexcept {
+ return __value_ == 0 ? weak_ordering::equivalent
+ : (__value_ < 0 ? weak_ordering::less : weak_ordering::greater);
+ }
+
+ // comparisons
+ friend constexpr bool operator==(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator!=(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator<(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator<=(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator>(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator>=(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr bool operator==(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+ friend constexpr bool operator!=(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+ friend constexpr bool operator<(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+ friend constexpr bool operator<=(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+ friend constexpr bool operator>(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+ friend constexpr bool operator>=(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+
+ friend constexpr strong_ordering operator<=>(strong_ordering __v, _CmpUnspecifiedParam) noexcept;
+ friend constexpr strong_ordering operator<=>(_CmpUnspecifiedParam, strong_ordering __v) noexcept;
+
+ // test helper
+ constexpr bool test_eq(strong_ordering const &other) const noexcept {
+ return __value_ == other.__value_;
+ }
+
+private:
+ _ValueT __value_;
+};
+
+inline constexpr strong_ordering strong_ordering::less(_OrdResult::__less);
+inline constexpr strong_ordering strong_ordering::equal(_EqResult::__equal);
+inline constexpr strong_ordering strong_ordering::equivalent(_EqResult::__equiv);
+inline constexpr strong_ordering strong_ordering::greater(_OrdResult::__greater);
+
+constexpr bool operator==(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ == 0;
+}
+constexpr bool operator!=(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ != 0;
+}
+constexpr bool operator<(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ < 0;
+}
+constexpr bool operator<=(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ <= 0;
+}
+constexpr bool operator>(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ > 0;
+}
+constexpr bool operator>=(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v.__value_ >= 0;
+}
+constexpr bool operator==(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return 0 == __v.__value_;
+}
+constexpr bool operator!=(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return 0 != __v.__value_;
+}
+constexpr bool operator<(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return 0 < __v.__value_;
+}
+constexpr bool operator<=(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return 0 <= __v.__value_;
+}
+constexpr bool operator>(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return 0 > __v.__value_;
+}
+constexpr bool operator>=(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return 0 >= __v.__value_;
+}
+
+constexpr strong_ordering operator<=>(strong_ordering __v, _CmpUnspecifiedParam) noexcept {
+ return __v;
+}
+constexpr strong_ordering operator<=>(_CmpUnspecifiedParam, strong_ordering __v) noexcept {
+ return __v < 0 ? strong_ordering::greater : (__v > 0 ? strong_ordering::less : __v);
+}
+
+} // namespace __1
+} // end namespace std
+
+#endif // STD_COMPARE_H
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
new file mode 100644
index 0000000000000..b1fa0d1469824
--- /dev/null
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER
+
+#include "Inputs/std-compare.h"
+
+// BEFORE: #cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
+// BEFORE: #cmp3way_info_strong_ltn1eq0gt1 = #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
+// BEFORE: !rec_std3A3A__13A3Apartial_ordering = !cir.record<class "std::__1::partial_ordering" {!s8i}
+// BEFORE: !rec_std3A3A__13A3Astrong_ordering = !cir.record<class "std::__1::strong_ordering" {!s8i}
+
+auto three_way_strong(int x, int y) {
+ return x <=> y;
+}
+
+// BEFORE: cir.func {{.*}} @_Z16three_way_strongii
+// BEFORE: %{{.+}} = cir.cmp3way(%{{.+}} : !s32i, %{{.+}}, #cmp3way_info_strong_ltn1eq0gt1) : !s8i
+// BEFORE: }
+
+// AFTER: cir.func {{.*}} @_Z16three_way_strongii
+// AFTER: %[[#LHS:]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
+// AFTER-NEXT: %[[#RHS:]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
+// AFTER-NEXT: %[[#LT:]] = cir.const(#cir.int<-1> : !s8i) : !s8i
+// AFTER-NEXT: %[[#EQ:]] = cir.const(#cir.int<0> : !s8i) : !s8i
+// AFTER-NEXT: %[[#GT:]] = cir.const(#cir.int<1> : !s8i) : !s8i
+// AFTER-NEXT: %[[#CMP_LT:]] = cir.cmp(lt, %[[#LHS]], %[[#RHS]]) : !s32i, !cir.bool
+// AFTER-NEXT: %[[#CMP_EQ:]] = cir.cmp(eq, %[[#LHS]], %[[#RHS]]) : !s32i, !cir.bool
+// AFTER-NEXT: %[[#CMP_EQ_RES:]] = cir.ternary(%[[#CMP_EQ]], true {
+// AFTER-NEXT: cir.yield %[[#EQ]] : !s8i
+// AFTER-NEXT: }, false {
+// AFTER-NEXT: cir.yield %[[#GT]] : !s8i
+// AFTER-NEXT: }) : (!cir.bool) -> !s8i
+// AFTER-NEXT: %{{.+}} = cir.ternary(%[[#CMP_LT]], true {
+// AFTER-NEXT: cir.yield %[[#LT]] : !s8i
+// AFTER-NEXT: }, false {
+// AFTER-NEXT: cir.yield %[[#CMP_EQ_RES]] : !s8i
+// AFTER-NEXT: }) : (!cir.bool) -> !s8i
+// AFTER: }
+
+auto three_way_weak(float x, float y) {
+ return x <=> y;
+}
+
+// BEFORE: cir.func {{.*}} @_Z14three_way_weakff
+// BEFORE: %{{.+}} = cir.cmp3way(%{{.+}} : !cir.float, %{{.+}}, #cmp3way_info_partial_ltn1eq0gt1unn127) : !s8i
+// BEFORE: }
+
+// AFTER: cir.func {{.*}} @_Z14three_way_weakff
+// AFTER: %[[#LHS:]] = cir.load {{.*}} %0 : !cir.ptr<!cir.float>, !cir.float
+// AFTER-NEXT: %[[#RHS:]] = cir.load {{.*}} %1 : !cir.ptr<!cir.float>, !cir.float
+// AFTER-NEXT: %[[#LT:]] = cir.const(#cir.int<-1> : !s8i) : !s8i
+// AFTER-NEXT: %[[#EQ:]] = cir.const(#cir.int<0> : !s8i) : !s8i
+// AFTER-NEXT: %[[#GT:]] = cir.const(#cir.int<1> : !s8i) : !s8i
+// AFTER-NEXT: %[[#UNORDERED:]] = cir.const(#cir.int<-127> : !s8i) : !s8i
+// AFTER-NEXT: %[[#CMP_LT:]] = cir.cmp(lt, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[#CMP_EQ:]] = cir.cmp(eq, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[#CMP_GT:]] = cir.cmp(gt, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[#CMP_EQ_RES:]] = cir.ternary(%[[#CMP_EQ]], true {
+// AFTER-NEXT: cir.yield %[[#EQ]] : !s8i
+// AFTER-NEXT: }, false {
+// AFTER-NEXT: cir.yield %[[#UNORDERED]] : !s8i
+// AFTER-NEXT: }) : (!cir.bool) -> !s8i
+// AFTER-NEXT: %[[#CMP_GT_RES:]] = cir.ternary(%[[#CMP_GT]], true {
+// AFTER-NEXT: cir.yield %[[#GT]] : !s8i
+// AFTER-NEXT: }, false {
+// AFTER-NEXT: cir.yield %[[#CMP_EQ_RES]] : !s8i
+// AFTER-NEXT: }) : (!cir.bool) -> !s8i
+// AFTER-NEXT: %{{.+}} = cir.ternary(%[[#CMP_LT]], true {
+// AFTER-NEXT: cir.yield %[[#LT]] : !s8i
+// AFTER-NEXT: }, false {
+// AFTER-NEXT: cir.yield %[[#CMP_GT_RES]] : !s8i
+// AFTER-NEXT: }) : (!cir.bool) -> !s8i
+// AFTER: }
>From 041cf9ff6b4428ee20dbc867324526ebaeb63619 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Fri, 28 Nov 2025 23:42:51 +0100
Subject: [PATCH 2/5] fmt
---
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 6 ++--
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 12 ++++----
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 2 --
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 1 -
.../Dialect/Transforms/LoweringPrepare.cpp | 30 ++++++++++---------
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 7 +++--
6 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index df85edbfb3c3a..12845f85d291c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -665,7 +665,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
"the three comparison results must have the same bit width");
cir::IntType cmpResultTy = getSIntNTy(ltRes.getBitWidth());
auto infoAttr = cir::CmpThreeWayInfoAttr::get(
- getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(), gtRes.getSExtValue());
+ getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(),
+ gtRes.getSExtValue());
return cir::CmpThreeWayOp::create(*this, loc, cmpResultTy, lhs, rhs,
infoAttr);
}
@@ -681,7 +682,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
"the four comparison results must have the same bit width");
auto cmpResultTy = getSIntNTy(ltRes.getBitWidth());
auto infoAttr = cir::CmpThreeWayInfoAttr::get(
- getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(), gtRes.getSExtValue(), unorderedRes.getSExtValue());
+ getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(),
+ gtRes.getSExtValue(), unorderedRes.getSExtValue());
return cir::CmpThreeWayOp::create(*this, loc, cmpResultTy, lhs, rhs,
infoAttr);
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index bc01604eb3293..5ad731a9be4d2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -332,7 +332,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
const ComparisonCategoryInfo &cmpInfo =
cgf.getContext().CompCategories.getInfoForType(e->getType());
assert(cmpInfo.Record->isTriviallyCopyable() &&
- "cannot copy non-trivially copyable aggregate");
+ "cannot copy non-trivially copyable aggregate");
QualType argTy = e->getLHS()->getType();
@@ -353,15 +353,15 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
mlir::Value resultScalar;
if (argTy->isNullPtrType()) {
resultScalar =
- builder.getConstInt(loc, cmpInfo.getEqualOrEquiv()->getIntValue());
+ builder.getConstInt(loc, cmpInfo.getEqualOrEquiv()->getIntValue());
} else {
llvm::APSInt ltRes = cmpInfo.getLess()->getIntValue();
llvm::APSInt eqRes = cmpInfo.getEqualOrEquiv()->getIntValue();
llvm::APSInt gtRes = cmpInfo.getGreater()->getIntValue();
if (!cmpInfo.isPartial()) {
// Strong ordering.
- resultScalar = builder.createThreeWayCmpStrong(loc, lhs, rhs, ltRes,
- eqRes, gtRes);
+ resultScalar =
+ builder.createThreeWayCmpStrong(loc, lhs, rhs, ltRes, eqRes, gtRes);
} else {
// Partial ordering.
llvm::APSInt unorderedRes = cmpInfo.getUnordered()->getIntValue();
@@ -377,8 +377,8 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
// Emit the address of the first (and only) field in the comparison category
// type, and initialize it from the constant integer value produced above.
const FieldDecl *resultField = *cmpInfo.Record->field_begin();
- LValue fieldLVal = cgf.emitLValueForFieldInitialization(destLVal, resultField,
- resultField->getName());
+ LValue fieldLVal = cgf.emitLValueForFieldInitialization(
+ destLVal, resultField, resultField->getName());
cgf.emitStoreThroughLValue(RValue::get(resultScalar), fieldLVal);
// All done! The result is in the dest slot.
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index ed0d4af8c80da..b490336d4f3fd 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -249,7 +249,6 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return success();
}
-
//===----------------------------------------------------------------------===//
// CmpThreeWayInfoAttr definitions
//===----------------------------------------------------------------------===//
@@ -302,7 +301,6 @@ CmpThreeWayInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return success();
}
-
//===----------------------------------------------------------------------===//
// ConstComplexAttr definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 966ebdb5ff78d..e150b3ce8f550 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1476,7 +1476,6 @@ Block *cir::BrCondOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {
return nullptr;
}
-
//===----------------------------------------------------------------------===//
// CmpThreeWayOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 2ae4b158aefd2..7dc0f132afcf0 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1289,12 +1289,17 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
mlir::Location loc = op->getLoc();
cir::CmpThreeWayInfoAttr cmpInfo = op.getInfo();
- mlir::Value ltRes = builder.getConstantInt(loc, op.getType(), cmpInfo.getLt());
- mlir::Value eqRes = builder.getConstantInt(loc, op.getType(), cmpInfo.getEq());
- mlir::Value gtRes = builder.getConstantInt(loc, op.getType(), cmpInfo.getGt());
-
- mlir::Value lt = builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
- mlir::Value eq = builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ mlir::Value ltRes =
+ builder.getConstantInt(loc, op.getType(), cmpInfo.getLt());
+ mlir::Value eqRes =
+ builder.getConstantInt(loc, op.getType(), cmpInfo.getEq());
+ mlir::Value gtRes =
+ builder.getConstantInt(loc, op.getType(), cmpInfo.getGt());
+
+ mlir::Value lt =
+ builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ mlir::Value eq =
+ builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
mlir::Value transformedResult;
if (cmpInfo.getOrdering() == CmpOrdering::Strong) {
@@ -1303,10 +1308,11 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
transformedResult = builder.createSelect(loc, lt, ltRes, selectOnEq);
} else {
// Partial ordering.
- cir::ConstantOp unorderedRes =
- builder.getConstantInt(loc, op.getType(), cmpInfo.getUnordered().value());
+ cir::ConstantOp unorderedRes = builder.getConstantInt(
+ loc, op.getType(), cmpInfo.getUnordered().value());
- mlir::Value gt = builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ mlir::Value gt =
+ builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, unorderedRes);
mlir::Value selectOnGt = builder.createSelect(loc, gt, gtRes, selectOnEq);
transformedResult = builder.createSelect(loc, lt, ltRes, selectOnGt);
@@ -1551,12 +1557,8 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
-<<<<<<< HEAD
cir::FuncOp, cir::CallOp, cir::GetGlobalOp, cir::GlobalOp,
- cir::UnaryOp>(op))
-=======
- cir::FuncOp, cir::GlobalOp, cir::UnaryOp, cir::CmpThreeWayOp>(op))
->>>>>>> 32285f45356c ([CIR] Upstream three way compare op)
+ cir::UnaryOp, cir::CmpThreeWayOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 824eb98add218..3ffa2c62936bd 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1575,8 +1575,9 @@ mlir::LogicalResult CIRToLLVMGetElementOpLowering::matchAndRewrite(
return mlir::failure();
}
-static std::string getThreeWayCmpIntrinsicName(
- bool signedCmp, unsigned operandWidth, unsigned resultWidth) {
+static std::string getThreeWayCmpIntrinsicName(bool signedCmp,
+ unsigned operandWidth,
+ unsigned resultWidth) {
// The intrinsic's name takes the form:
// `llvm.<scmp|ucmp>.i<resultWidth>.i<operandWidth>`
@@ -1618,7 +1619,7 @@ mlir::LogicalResult CIRToLLVMCmpThreeWayOpLowering::matchAndRewrite(
rewriter.setInsertionPoint(op);
mlir::Value llvmLhs = adaptor.getLhs();
- mlir::Value llvmRhs = adaptor.getRhs();
+ mlir::Value llvmRhs = adaptor.getRhs();
mlir::Type llvmResultTy = getTypeConverter()->convertType(resultTy);
mlir::LLVM::CallIntrinsicOp callIntrinsicOp =
createCallLLVMIntrinsicOp(rewriter, op.getLoc(), llvmIntrinsicName,
>From b3dcc821759d18d7da7cf14a2c6c339f41813fbb Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sat, 29 Nov 2025 21:45:43 +0100
Subject: [PATCH 3/5] fix tests
---
.../Dialect/Transforms/LoweringPrepare.cpp | 4 +-
clang/test/CIR/CodeGen/three-way-cmp.cpp | 82 +++++++++++--------
2 files changed, 50 insertions(+), 36 deletions(-)
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 7dc0f132afcf0..8ed80bf1bb446 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1299,7 +1299,7 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
mlir::Value lt =
builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
mlir::Value eq =
- builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ builder.createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
mlir::Value transformedResult;
if (cmpInfo.getOrdering() == CmpOrdering::Strong) {
@@ -1312,7 +1312,7 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
loc, op.getType(), cmpInfo.getUnordered().value());
mlir::Value gt =
- builder.createCompare(loc, CmpOpKind::lt, op.getLhs(), op.getRhs());
+ builder.createCompare(loc, CmpOpKind::gt, op.getLhs(), op.getRhs());
mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, unorderedRes);
mlir::Value selectOnGt = builder.createSelect(loc, gt, gtRes, selectOnEq);
transformedResult = builder.createSelect(loc, lt, ltRes, selectOnGt);
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index b1fa0d1469824..a18b83fecee68 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t.ll 2>&1 | FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o - | FileCheck %s -check-prefix=OGCG
+
#include "Inputs/std-compare.h"
// BEFORE: #cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
@@ -19,22 +23,27 @@ auto three_way_strong(int x, int y) {
// AFTER: cir.func {{.*}} @_Z16three_way_strongii
// AFTER: %[[#LHS:]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// AFTER-NEXT: %[[#RHS:]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
-// AFTER-NEXT: %[[#LT:]] = cir.const(#cir.int<-1> : !s8i) : !s8i
-// AFTER-NEXT: %[[#EQ:]] = cir.const(#cir.int<0> : !s8i) : !s8i
-// AFTER-NEXT: %[[#GT:]] = cir.const(#cir.int<1> : !s8i) : !s8i
+// AFTER-NEXT: %[[#LT:]] = cir.const #cir.int<-1> : !s8i
+// AFTER-NEXT: %[[#EQ:]] = cir.const #cir.int<0> : !s8i
+// AFTER-NEXT: %[[#GT:]] = cir.const #cir.int<1> : !s8i
// AFTER-NEXT: %[[#CMP_LT:]] = cir.cmp(lt, %[[#LHS]], %[[#RHS]]) : !s32i, !cir.bool
// AFTER-NEXT: %[[#CMP_EQ:]] = cir.cmp(eq, %[[#LHS]], %[[#RHS]]) : !s32i, !cir.bool
-// AFTER-NEXT: %[[#CMP_EQ_RES:]] = cir.ternary(%[[#CMP_EQ]], true {
-// AFTER-NEXT: cir.yield %[[#EQ]] : !s8i
-// AFTER-NEXT: }, false {
-// AFTER-NEXT: cir.yield %[[#GT]] : !s8i
-// AFTER-NEXT: }) : (!cir.bool) -> !s8i
-// AFTER-NEXT: %{{.+}} = cir.ternary(%[[#CMP_LT]], true {
-// AFTER-NEXT: cir.yield %[[#LT]] : !s8i
-// AFTER-NEXT: }, false {
-// AFTER-NEXT: cir.yield %[[#CMP_EQ_RES]] : !s8i
-// AFTER-NEXT: }) : (!cir.bool) -> !s8i
-// AFTER: }
+// AFTER-NEXT: %[[#SELECT_1:]] = cir.select if %[[#CMP_EQ]] then %[[#EQ]] else %[[#GT]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER-NEXT: %[[#SELECT_2:]] = cir.select if %[[#CMP_LT]] then %[[#LT]] else %[[#SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
+
+// LLVM: %[[#LHS:]] = load i32, ptr %{{.*}}, align 4
+// LLVM-NEXT: %[[#RHS:]] = load i32, ptr %{{.*}}, align 4
+// LLVM-NEXT: %[[#CMP_LT:]] = icmp slt i32 %[[#LHS]], %[[#RHS]]
+// LLVM-NEXT: %[[#CMP_EQ:]] = icmp eq i32 %[[#LHS]], %[[#RHS]]
+// LLVM-NEXT: %[[#SEL_EQ_GT:]] = select i1 %[[#CMP_EQ]], i8 0, i8 1
+// LLVM-NEXT: %[[#RES:]] = select i1 %[[#CMP_LT]], i8 -1, i8 %[[#SEL_EQ_GT]]
+
+// OGCG: %[[#LHS:]] = load i32, ptr %{{.*}}, align 4
+// OGCG-NEXT: %[[#RHS:]] = load i32, ptr %{{.*}}, align 4
+// OGCG-NEXT: %[[CMP_LT:.*]] = icmp slt i32 %[[#LHS]], %[[#RHS]]
+// OGCG-NEXT: %[[SEL_EQ_LT:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 1
+// OGCG-NEXT: %[[CMP_EQ:.*]] = icmp eq i32 %[[#LHS]], %[[#RHS]]
+// OGCG-NEXT: %[[RES:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 %[[SEL_EQ_LT]]
auto three_way_weak(float x, float y) {
return x <=> y;
@@ -47,26 +56,31 @@ auto three_way_weak(float x, float y) {
// AFTER: cir.func {{.*}} @_Z14three_way_weakff
// AFTER: %[[#LHS:]] = cir.load {{.*}} %0 : !cir.ptr<!cir.float>, !cir.float
// AFTER-NEXT: %[[#RHS:]] = cir.load {{.*}} %1 : !cir.ptr<!cir.float>, !cir.float
-// AFTER-NEXT: %[[#LT:]] = cir.const(#cir.int<-1> : !s8i) : !s8i
-// AFTER-NEXT: %[[#EQ:]] = cir.const(#cir.int<0> : !s8i) : !s8i
-// AFTER-NEXT: %[[#GT:]] = cir.const(#cir.int<1> : !s8i) : !s8i
-// AFTER-NEXT: %[[#UNORDERED:]] = cir.const(#cir.int<-127> : !s8i) : !s8i
+// AFTER-NEXT: %[[#LT:]] = cir.const #cir.int<-1> : !s8i
+// AFTER-NEXT: %[[#EQ:]] = cir.const #cir.int<0> : !s8i
+// AFTER-NEXT: %[[#GT:]] = cir.const #cir.int<1> : !s8i
// AFTER-NEXT: %[[#CMP_LT:]] = cir.cmp(lt, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
// AFTER-NEXT: %[[#CMP_EQ:]] = cir.cmp(eq, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[#UNORDERED:]] = cir.const #cir.int<-127> : !s8i
// AFTER-NEXT: %[[#CMP_GT:]] = cir.cmp(gt, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[#CMP_EQ_RES:]] = cir.ternary(%[[#CMP_EQ]], true {
-// AFTER-NEXT: cir.yield %[[#EQ]] : !s8i
-// AFTER-NEXT: }, false {
-// AFTER-NEXT: cir.yield %[[#UNORDERED]] : !s8i
-// AFTER-NEXT: }) : (!cir.bool) -> !s8i
-// AFTER-NEXT: %[[#CMP_GT_RES:]] = cir.ternary(%[[#CMP_GT]], true {
-// AFTER-NEXT: cir.yield %[[#GT]] : !s8i
-// AFTER-NEXT: }, false {
-// AFTER-NEXT: cir.yield %[[#CMP_EQ_RES]] : !s8i
-// AFTER-NEXT: }) : (!cir.bool) -> !s8i
-// AFTER-NEXT: %{{.+}} = cir.ternary(%[[#CMP_LT]], true {
-// AFTER-NEXT: cir.yield %[[#LT]] : !s8i
-// AFTER-NEXT: }, false {
-// AFTER-NEXT: cir.yield %[[#CMP_GT_RES]] : !s8i
-// AFTER-NEXT: }) : (!cir.bool) -> !s8i
-// AFTER: }
+// AFTER-NEXT: %[[#SELECT_1:]] = cir.select if %[[#CMP_EQ]] then %[[#EQ]] else %[[#UNORDERED]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER-NEXT: %[[#SELECT_2:]] = cir.select if %[[#CMP_GT]] then %[[#GT]] else %[[#SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER-NEXT: %[[#SELECT_3:]] = cir.select if %[[#CMP_LT]] then %[[#LT]] else %[[#SELECT_2]] : (!cir.bool, !s8i, !s8i) -> !s8i
+
+// LLVM: %[[#LHS:]] = load float, ptr %{{.*}}, align 4
+// LLVM: %[[#RHS:]] = load float, ptr %{{.*}}, align 4
+// LLVM: %[[#CMP_LT:]] = fcmp olt float %[[#LHS]], %[[#RHS]]
+// LLVM: %[[#CMP_EQ:]] = fcmp oeq float %[[#LHS]], %[[#RHS]]
+// LLVM: %[[#CMP_GT:]] = fcmp ogt float %[[#LHS]], %[[#RHS]]
+// LLVM: %[[#SEL_EQ_UN:]] = select i1 %[[#CMP_EQ]], i8 0, i8 -127
+// LLVM: %[[#SEL_GT_EQUN:]] = select i1 %[[#CMP_GT]], i8 1, i8 %[[#SEL_EQ_UN]]
+// LLVM: %[[#RES:]] = select i1 %[[#CMP_LT]], i8 -1, i8 %[[#SEL_GT_EQUN]]
+
+// OGCG: %[[#LHS:]] = load float, ptr %{{.*}}, align 4
+// OGCG: %[[#RHS:]] = load float, ptr %{{.*}}, align 4
+// OGCG: %[[CMP_EQ:.*]] = fcmp oeq float %[[#LHS]], %[[#RHS]]
+// OGCG: %[[SEL_EQ_UN:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 -127
+// OGCG: %[[CMP_GT:.*]] = fcmp ogt float %[[#LHS]], %[[#RHS]]
+// OGCG: %[[SEL_GT_EQUN:.*]] = select i1 %[[CMP_GT]], i8 1, i8 %[[SEL_EQ_UN]]
+// OGCG: %[[CMP_LT:.*]] = fcmp olt float %[[#LHS]], %[[#RHS]]
+// OGCG: %[[RES:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_GT_EQUN]]
>From 51e0dca5e04527763c006f0121d1d40a0bf103ee Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sun, 14 Dec 2025 14:58:01 +0100
Subject: [PATCH 4/5] WIP
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 21 +++-
clang/include/clang/CIR/Dialect/IR/CIROps.td | 16 +--
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 3 +-
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 4 +-
clang/test/CIR/CodeGen/three-way-cmp.cpp | 111 ++++++++++--------
5 files changed, 91 insertions(+), 64 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index e85283a0f3dd8..625e08fa4adac 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -584,10 +584,10 @@ def CIR_CmpOrdering : CIR_I32EnumAttr<
let genSpecializedAttr = 0;
}
-def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
+def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmpinfo"> {
let summary = "Holds information about a three-way comparison operation";
let description = [{
- The `#cmp3way_info` attribute contains information about a three-way
+ The `#cmpinfo` attribute contains information about a three-way
comparison operation `cir.cmp3way`.
The `ordering` parameter gives the ordering kind of the three-way comparison
@@ -598,6 +598,23 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
value that should be produced by the three-way comparison operation when the
ordering between `lhs` and `rhs` is `lhs < rhs`, `lhs == rhs`, `lhs > rhs`,
or neither, respectively.
+
+ Example:
+
+ ```mlir
+ !s32i = !cir.int<s, 32>
+
+ #cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
+ #cmp3way_info_strong_ltn1eq0gt1 = #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
+
+ %0 = cir.const #cir.int<0> : !s32i
+ %1 = cir.const #cir.int<1> : !s32i
+ %2 = cir.cmp3way(%0 : !s32i, %1, #cmp3way_info_strong_ltn1eq0gt1) : !s8i
+
+ %3 = cir.const #cir.fp<0.0> : !cir.float
+ %4 = cir.const #cir.fp<1.0> : !cir.float
+ %5 = cir.cmp3way(%3 : !cir.float, %4, #cmp3way_info_partial_ltn1eq0gt1unn127) : !s8
+ ```
}];
let parameters = (ins
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5fc3acd2a2145..d79ae2f7fda84 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1267,16 +1267,18 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
```mlir
!s32i = !cir.int<s, 32>
- #cmp3way_strong = #cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
- #cmp3way_partial = #cmp3way_info<strong, lt = -1, eq = 0, gt = 1, unordered = 2>
+ #cmp3way_info_partial_ltn1eq0gt1unn127 =
+ #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
+ #cmp3way_info_strong_ltn1eq0gt1 =
+ #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
%0 = cir.const #cir.int<0> : !s32i
%1 = cir.const #cir.int<1> : !s32i
- %2 = cir.cmp3way(%0 : !s32i, %1, #cmp3way_strong) : !s8i
+ %2 = cir.cmp3way #cmp3way_info_strong_ltn1eq0gt1 %0, %1 : !s32i -> !s8i
%3 = cir.const #cir.fp<0.0> : !cir.float
%4 = cir.const #cir.fp<1.0> : !cir.float
- %5 = cir.cmp3way(%3 : !cir.float, %4, #cmp3way_partial) : !s8i
+ %5 = cir.cmp3way #cmp3way_info_partial_ltn1eq0gt1unn127 %3, %4 : !cir.float -> !s8i
```
}];
@@ -1289,8 +1291,8 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
let results = (outs CIR_AnySIntType:$result);
let assemblyFormat = [{
- `(` $lhs `:` type($lhs) `,` $rhs `,` qualified($info) `)`
- `:` type($result) attr-dict
+ qualified($info) $lhs, $rhs `:` qualified(type($lhs))
+ `->` qualified(type($result)) attr-dict
}];
let extraClassDeclaration = [{
@@ -1304,8 +1306,6 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
return mlir::isa<cir::IntType>(getLhs().getType());
}
}];
-
- let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 12845f85d291c..2f23b538a8b16 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -13,6 +13,7 @@
#include "CIRGenRecordLayout.h"
#include "CIRGenTypeCache.h"
#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/Support/LLVM.h"
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
@@ -680,7 +681,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
ltRes.getBitWidth() == gtRes.getBitWidth() &&
ltRes.getBitWidth() == unorderedRes.getBitWidth() &&
"the four comparison results must have the same bit width");
- auto cmpResultTy = getSIntNTy(ltRes.getBitWidth());
+ cir::IntType cmpResultTy = getSIntNTy(ltRes.getBitWidth());
auto infoAttr = cir::CmpThreeWayInfoAttr::get(
getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(),
gtRes.getSExtValue(), unorderedRes.getSExtValue());
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 5ad731a9be4d2..ee8a883de8b0a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -339,13 +339,13 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
if (!argTy->isIntegralOrEnumerationType() && !argTy->isRealFloatingType() &&
!argTy->isNullPtrType() && !argTy->isPointerType() &&
!argTy->isMemberPointerType() && !argTy->isAnyComplexType())
- llvm_unreachable("aggregate three-way comparison");
+ cgf.cgm.errorNYI(e->getBeginLoc(), "aggregate three-way comparison");
mlir::Location loc = cgf.getLoc(e->getSourceRange());
CIRGenBuilderTy builder = cgf.getBuilder();
if (e->getType()->isAnyComplexType())
- llvm_unreachable("NYI");
+ cgf.cgm.errorNYI(e->getBeginLoc(), "VisitBinCmp: complex type");
mlir::Value lhs = cgf.emitAnyExpr(e->getLHS()).getValue();
mlir::Value rhs = cgf.emitAnyExpr(e->getRHS()).getValue();
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index a18b83fecee68..2373c9d4f5d6d 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -1,11 +1,14 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
+// RUN: FileCheck %s --input-file=%t-before.cir --check-prefix=BEFORE
+// RUN: FileCheck: %s --input-file=%t.cir --check-prefix=AFTER
+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t.ll 2>&1 | FileCheck --input-file=%t.ll %s -check-prefix=LLVM
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o - | FileCheck %s -check-prefix=OGCG
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o %t.ll 2>&1 | FileCheck --input-file=%t.ll %s -check-prefix=OGCG
-#include "Inputs/std-compare.h"
+#include "../../CodeGenCXX/Inputs/std-compare.h"
// BEFORE: #cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
// BEFORE: #cmp3way_info_strong_ltn1eq0gt1 = #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
@@ -21,28 +24,28 @@ auto three_way_strong(int x, int y) {
// BEFORE: }
// AFTER: cir.func {{.*}} @_Z16three_way_strongii
-// AFTER: %[[#LHS:]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
-// AFTER-NEXT: %[[#RHS:]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
-// AFTER-NEXT: %[[#LT:]] = cir.const #cir.int<-1> : !s8i
-// AFTER-NEXT: %[[#EQ:]] = cir.const #cir.int<0> : !s8i
-// AFTER-NEXT: %[[#GT:]] = cir.const #cir.int<1> : !s8i
-// AFTER-NEXT: %[[#CMP_LT:]] = cir.cmp(lt, %[[#LHS]], %[[#RHS]]) : !s32i, !cir.bool
-// AFTER-NEXT: %[[#CMP_EQ:]] = cir.cmp(eq, %[[#LHS]], %[[#RHS]]) : !s32i, !cir.bool
-// AFTER-NEXT: %[[#SELECT_1:]] = cir.select if %[[#CMP_EQ]] then %[[#EQ]] else %[[#GT]] : (!cir.bool, !s8i, !s8i) -> !s8i
-// AFTER-NEXT: %[[#SELECT_2:]] = cir.select if %[[#CMP_LT]] then %[[#LT]] else %[[#SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
-
-// LLVM: %[[#LHS:]] = load i32, ptr %{{.*}}, align 4
-// LLVM-NEXT: %[[#RHS:]] = load i32, ptr %{{.*}}, align 4
-// LLVM-NEXT: %[[#CMP_LT:]] = icmp slt i32 %[[#LHS]], %[[#RHS]]
-// LLVM-NEXT: %[[#CMP_EQ:]] = icmp eq i32 %[[#LHS]], %[[#RHS]]
-// LLVM-NEXT: %[[#SEL_EQ_GT:]] = select i1 %[[#CMP_EQ]], i8 0, i8 1
-// LLVM-NEXT: %[[#RES:]] = select i1 %[[#CMP_LT]], i8 -1, i8 %[[#SEL_EQ_GT]]
-
-// OGCG: %[[#LHS:]] = load i32, ptr %{{.*}}, align 4
-// OGCG-NEXT: %[[#RHS:]] = load i32, ptr %{{.*}}, align 4
-// OGCG-NEXT: %[[CMP_LT:.*]] = icmp slt i32 %[[#LHS]], %[[#RHS]]
+// AFTER: %[[LHS:.*]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
+// AFTER-NEXT: %[[RHS:.*]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
+// AFTER-NEXT: %[[LT:.*]] = cir.const #cir.int<-1> : !s8i
+// AFTER-NEXT: %[[EQ:.*]] = cir.const #cir.int<0> : !s8i
+// AFTER-NEXT: %[[GT:.*]] = cir.const #cir.int<1> : !s8i
+// AFTER-NEXT: %[[CMP_LT:.*]] = cir.cmp(lt, %[[LHS]], %[[RHS]]) : !s32i, !cir.bool
+// AFTER-NEXT: %[[CMP_EQ:.*]] = cir.cmp(eq, %[[LHS]], %[[RHS]]) : !s32i, !cir.bool
+// AFTER-NEXT: %[[SELECT_1:.*]] = cir.select if %[[CMP_EQ]] then %[[EQ]] else %[[GT]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER-NEXT: %[[SELECT_2:.*]] = cir.select if %[[CMP_LT]] then %[[LT]] else %[[SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
+
+// LLVM: %[[LHS:.*]] = load i32, ptr %{{.*}}, align 4
+// LLVM-NEXT: %[[RHS:.*]] = load i32, ptr %{{.*}}, align 4
+// LLVM-NEXT: %[[CMP_LT:.*]] = icmp slt i32 %[[LHS]], %[[RHS]]
+// LLVM-NEXT: %[[CMP_EQ:.*]] = icmp eq i32 %[[LHS]], %[[RHS]]
+// LLVM-NEXT: %[[SEL_EQ_GT:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 1
+// LLVM-NEXT: %[[RES:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_EQ_GT]]
+
+// OGCG: %[[LHS:.*]] = load i32, ptr %{{.*}}, align 4
+// OGCG-NEXT: %[[RHS:.*]] = load i32, ptr %{{.*}}, align 4
+// OGCG-NEXT: %[[CMP_LT:.*]] = icmp slt i32 %[[LHS]], %[[RHS]]
// OGCG-NEXT: %[[SEL_EQ_LT:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 1
-// OGCG-NEXT: %[[CMP_EQ:.*]] = icmp eq i32 %[[#LHS]], %[[#RHS]]
+// OGCG-NEXT: %[[CMP_EQ:.*]] = icmp eq i32 %[[LHS]], %[[RHS]]
// OGCG-NEXT: %[[RES:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 %[[SEL_EQ_LT]]
auto three_way_weak(float x, float y) {
@@ -54,33 +57,39 @@ auto three_way_weak(float x, float y) {
// BEFORE: }
// AFTER: cir.func {{.*}} @_Z14three_way_weakff
-// AFTER: %[[#LHS:]] = cir.load {{.*}} %0 : !cir.ptr<!cir.float>, !cir.float
-// AFTER-NEXT: %[[#RHS:]] = cir.load {{.*}} %1 : !cir.ptr<!cir.float>, !cir.float
-// AFTER-NEXT: %[[#LT:]] = cir.const #cir.int<-1> : !s8i
-// AFTER-NEXT: %[[#EQ:]] = cir.const #cir.int<0> : !s8i
-// AFTER-NEXT: %[[#GT:]] = cir.const #cir.int<1> : !s8i
-// AFTER-NEXT: %[[#CMP_LT:]] = cir.cmp(lt, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[#CMP_EQ:]] = cir.cmp(eq, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[#UNORDERED:]] = cir.const #cir.int<-127> : !s8i
-// AFTER-NEXT: %[[#CMP_GT:]] = cir.cmp(gt, %[[#LHS]], %[[#RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[#SELECT_1:]] = cir.select if %[[#CMP_EQ]] then %[[#EQ]] else %[[#UNORDERED]] : (!cir.bool, !s8i, !s8i) -> !s8i
-// AFTER-NEXT: %[[#SELECT_2:]] = cir.select if %[[#CMP_GT]] then %[[#GT]] else %[[#SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
-// AFTER-NEXT: %[[#SELECT_3:]] = cir.select if %[[#CMP_LT]] then %[[#LT]] else %[[#SELECT_2]] : (!cir.bool, !s8i, !s8i) -> !s8i
-
-// LLVM: %[[#LHS:]] = load float, ptr %{{.*}}, align 4
-// LLVM: %[[#RHS:]] = load float, ptr %{{.*}}, align 4
-// LLVM: %[[#CMP_LT:]] = fcmp olt float %[[#LHS]], %[[#RHS]]
-// LLVM: %[[#CMP_EQ:]] = fcmp oeq float %[[#LHS]], %[[#RHS]]
-// LLVM: %[[#CMP_GT:]] = fcmp ogt float %[[#LHS]], %[[#RHS]]
-// LLVM: %[[#SEL_EQ_UN:]] = select i1 %[[#CMP_EQ]], i8 0, i8 -127
-// LLVM: %[[#SEL_GT_EQUN:]] = select i1 %[[#CMP_GT]], i8 1, i8 %[[#SEL_EQ_UN]]
-// LLVM: %[[#RES:]] = select i1 %[[#CMP_LT]], i8 -1, i8 %[[#SEL_GT_EQUN]]
-
-// OGCG: %[[#LHS:]] = load float, ptr %{{.*}}, align 4
-// OGCG: %[[#RHS:]] = load float, ptr %{{.*}}, align 4
-// OGCG: %[[CMP_EQ:.*]] = fcmp oeq float %[[#LHS]], %[[#RHS]]
+// AFTER: %[[LHS:.*]] = cir.load {{.*}} %0 : !cir.ptr<!cir.float>, !cir.float
+// AFTER-NEXT: %[[RHS:.*]] = cir.load {{.*}} %1 : !cir.ptr<!cir.float>, !cir.float
+// AFTER-NEXT: %[[LT:.*]] = cir.const #cir.int<-1> : !s8i
+// AFTER-NEXT: %[[EQ:.*]] = cir.const #cir.int<0> : !s8i
+// AFTER-NEXT: %[[GT:.*]] = cir.const #cir.int<1> : !s8i
+// AFTER-NEXT: %[[CMP_LT:.*]] = cir.cmp(lt, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[CMP_EQ:.*]] = cir.cmp(eq, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[UNORDERED:.*]] = cir.const #cir.int<-127> : !s8i
+// AFTER-NEXT: %[[CMP_GT:.*]] = cir.cmp(gt, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool
+// AFTER-NEXT: %[[SELECT_1:.*]] = cir.select if %[[CMP_EQ]] then %[[EQ]] else %[[UNORDERED]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER-NEXT: %[[SELECT_2:.*]] = cir.select if %[[CMP_GT]] then %[[GT]] else %[[SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER-NEXT: %[[SELECT_3:.*]] = cir.select if %[[CMP_LT]] then %[[LT]] else %[[SELECT_2]] : (!cir.bool, !s8i, !s8i) -> !s8i
+
+// LLVM: %[[LHS:.*]] = load float, ptr %{{.*}}, align 4
+// LLVM: %[[RHS:.*]] = load float, ptr %{{.*}}, align 4
+// LLVM: %[[CMP_LT:.*]] = fcmp olt float %[[LHS]], %[[RHS]]
+// LLVM: %[[CMP_EQ:.*]] = fcmp oeq float %[[LHS]], %[[RHS]]
+// LLVM: %[[CMP_GT:.*]] = fcmp ogt float %[[LHS]], %[[RHS]]
+// LLVM: %[[SEL_EQ_UN:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 -127
+// LLVM: %[[SEL_GT_EQUN:.*]] = select i1 %[[CMP_GT]], i8 1, i8 %[[SEL_EQ_UN]]
+// LLVM: %[[RES:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_GT_EQUN]]
+
+// OGCG: %[[LHS:.*]] = load float, ptr %{{.*}}, align 4
+// OGCG: %[[RHS:.*]] = load float, ptr %{{.*}}, align 4
+// OGCG: %[[CMP_EQ:.*]] = fcmp oeq float %[[LHS]], %[[RHS]]
// OGCG: %[[SEL_EQ_UN:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 -127
-// OGCG: %[[CMP_GT:.*]] = fcmp ogt float %[[#LHS]], %[[#RHS]]
+// OGCG: %[[CMP_GT:.*]] = fcmp ogt float %[[LHS]], %[[RHS]]
// OGCG: %[[SEL_GT_EQUN:.*]] = select i1 %[[CMP_GT]], i8 1, i8 %[[SEL_EQ_UN]]
-// OGCG: %[[CMP_LT:.*]] = fcmp olt float %[[#LHS]], %[[#RHS]]
+// OGCG: %[[CMP_LT:.*]] = fcmp olt float %[[LHS]], %[[RHS]]
// OGCG: %[[RES:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_GT_EQUN]]
+
+auto nullptr_compare() {
+ int* x = 0;
+ return nullptr <=> 0;
+}
+ // TODO: assertions: should be equal
\ No newline at end of file
>From a4d65d53bde8710869c6dda0f7c64cf5cab891a5 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sun, 15 Feb 2026 18:16:04 +0100
Subject: [PATCH 5/5] feedback
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 15 ++--
clang/include/clang/CIR/Dialect/IR/CIROps.td | 16 ++--
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 2 +-
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 4 +-
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 8 +-
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 14 ---
.../Dialect/Transforms/LoweringPrepare.cpp | 6 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 53 ------------
clang/test/CIR/CodeGen/three-way-cmp.cpp | 86 ++++++++++---------
clang/test/CIR/IR/invalid-cmp3way.cir | 27 ++++++
10 files changed, 99 insertions(+), 132 deletions(-)
create mode 100644 clang/test/CIR/IR/invalid-cmp3way.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 625e08fa4adac..3e8ddd4e209e8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -578,20 +578,21 @@ def CIR_MethodAttr : CIR_Attr<"Method", "method", [TypedAttrInterface]> {
def CIR_CmpOrdering : CIR_I32EnumAttr<
"CmpOrdering", "three-way comparison ordering kind", [
- I32EnumAttrCase<"Strong", 0, "strong">,
+ I32EnumAttrCase<"Total", 0, "total">,
I32EnumAttrCase<"Partial", 1, "partial">
]> {
let genSpecializedAttr = 0;
}
-def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmpinfo"> {
+def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
let summary = "Holds information about a three-way comparison operation";
let description = [{
- The `#cmpinfo` attribute contains information about a three-way
+ The `#cmp3way_info` attribute contains information about a three-way
comparison operation `cir.cmp3way`.
The `ordering` parameter gives the ordering kind of the three-way comparison
- operation. It may be either strong ordering or partial ordering.
+ operation. It may be either total ordering (which includes both strong and
+ weak orderings) or partial ordering.
Given the two input operands of the three-way comparison operation `lhs` and
`rhs`, the `lt`, `eq`, `gt`, and `unordered` parameters gives the result
@@ -605,11 +606,11 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmpinfo"> {
!s32i = !cir.int<s, 32>
#cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
- #cmp3way_info_strong_ltn1eq0gt1 = #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
+ #cmp3way_info_total_ltn1eq0gt1 = #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1>
%0 = cir.const #cir.int<0> : !s32i
%1 = cir.const #cir.int<1> : !s32i
- %2 = cir.cmp3way(%0 : !s32i, %1, #cmp3way_info_strong_ltn1eq0gt1) : !s8i
+ %2 = cir.cmp3way(%0 : !s32i, %1, #cmp3way_info_total_ltn1eq0gt1) : !s8i
%3 = cir.const #cir.fp<0.0> : !cir.float
%4 = cir.const #cir.fp<1.0> : !cir.float
@@ -625,7 +626,7 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmpinfo"> {
let builders = [
AttrBuilder<(ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt), [{
- return $_get($_ctxt, CmpOrdering::Strong, lt, eq, gt, std::nullopt);
+ return $_get($_ctxt, CmpOrdering::Total, lt, eq, gt, std::nullopt);
}]>,
AttrBuilder<(ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt,
"int64_t":$unordered), [{
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d79ae2f7fda84..2f29e2417bb69 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1269,12 +1269,12 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
#cmp3way_info_partial_ltn1eq0gt1unn127 =
#cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
- #cmp3way_info_strong_ltn1eq0gt1 =
- #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
+ #cmp3way_info_total_ltn1eq0gt1 =
+ #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1>
%0 = cir.const #cir.int<0> : !s32i
%1 = cir.const #cir.int<1> : !s32i
- %2 = cir.cmp3way #cmp3way_info_strong_ltn1eq0gt1 %0, %1 : !s32i -> !s8i
+ %2 = cir.cmp3way #cmp3way_info_total_ltn1eq0gt1 %0, %1 : !s32i -> !s8i
%3 = cir.const #cir.fp<0.0> : !cir.float
%4 = cir.const #cir.fp<1.0> : !cir.float
@@ -1291,14 +1291,14 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
let results = (outs CIR_AnySIntType:$result);
let assemblyFormat = [{
- qualified($info) $lhs, $rhs `:` qualified(type($lhs))
+ qualified($info) $lhs `,` $rhs `:` qualified(type($lhs))
`->` qualified(type($result)) attr-dict
}];
let extraClassDeclaration = [{
- /// Determine whether this three-way comparison produces a strong ordering.
- bool isStrongOrdering() {
- return getInfo().getOrdering() == cir::CmpOrdering::Strong;
+ /// Determine whether this three-way comparison produces a total ordering.
+ bool isTotalOrdering() {
+ return getInfo().getOrdering() == cir::CmpOrdering::Total;
}
/// Determine whether this three-way comparison compares integral operands.
@@ -1306,6 +1306,8 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
return mlir::isa<cir::IntType>(getLhs().getType());
}
}];
+
+ let hasLLVMLowering = false;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 2f23b538a8b16..3716621291b5a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -656,7 +656,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::StackRestoreOp::create(*this, loc, v);
}
- cir::CmpThreeWayOp createThreeWayCmpStrong(mlir::Location loc,
+ cir::CmpThreeWayOp createThreeWayCmpTotal(mlir::Location loc,
mlir::Value lhs, mlir::Value rhs,
const llvm::APSInt <Res,
const llvm::APSInt &eqRes,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index ee8a883de8b0a..cf958cf8aacda 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -359,9 +359,9 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
llvm::APSInt eqRes = cmpInfo.getEqualOrEquiv()->getIntValue();
llvm::APSInt gtRes = cmpInfo.getGreater()->getIntValue();
if (!cmpInfo.isPartial()) {
- // Strong ordering.
+ // Total ordering.
resultScalar =
- builder.createThreeWayCmpStrong(loc, lhs, rhs, ltRes, eqRes, gtRes);
+ builder.createThreeWayCmpTotal(loc, lhs, rhs, ltRes, eqRes, gtRes);
} else {
// Partial ordering.
llvm::APSInt unorderedRes = cmpInfo.getUnordered()->getIntValue();
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index b490336d4f3fd..bb88fc2a342be 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -256,8 +256,8 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
std::string CmpThreeWayInfoAttr::getAlias() const {
std::string alias = "cmp3way_info";
- if (getOrdering() == CmpOrdering::Strong)
- alias.append("_strong_");
+ if (getOrdering() == CmpOrdering::Total)
+ alias.append("_total_");
else
alias.append("_partial_");
@@ -289,8 +289,8 @@ CmpThreeWayInfoAttr::verify(function_ref<InFlightDiagnostic()> emitError,
CmpOrdering ordering, int64_t lt, int64_t eq,
int64_t gt, std::optional<int64_t> unordered) {
// The presense of unordered must match the value of ordering.
- if (ordering == CmpOrdering::Strong && unordered) {
- emitError() << "strong ordering does not include unordered ordering";
+ if (ordering == CmpOrdering::Total && unordered) {
+ emitError() << "total ordering does not include unordered ordering";
return failure();
}
if (ordering == CmpOrdering::Partial && !unordered) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index e150b3ce8f550..d4e5c585c8481 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1476,20 +1476,6 @@ Block *cir::BrCondOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {
return nullptr;
}
-//===----------------------------------------------------------------------===//
-// CmpThreeWayOp
-//===----------------------------------------------------------------------===//
-
-mlir::LogicalResult CmpThreeWayOp::verify() {
- // Type of the result must be a signed integer type.
- if (!getType().isSigned()) {
- emitOpError() << "result type of cir.cmp3way must be a signed integer type";
- return failure();
- }
-
- return success();
-}
-
//===----------------------------------------------------------------------===//
// CaseOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 8ed80bf1bb446..37a1c44ac06ce 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1302,8 +1302,8 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
builder.createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
mlir::Value transformedResult;
- if (cmpInfo.getOrdering() == CmpOrdering::Strong) {
- // Strong ordering.
+ if (cmpInfo.getOrdering() == CmpOrdering::Total) {
+ // Total ordering.
mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, gtRes);
transformedResult = builder.createSelect(loc, lt, ltRes, selectOnEq);
} else {
@@ -1542,7 +1542,7 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
else if (auto globalDtor = fnOp.getGlobalDtorPriority())
globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
- } else if (auto threeWayCmp = dyn_cast<CmpThreeWayOp>(op)) {
+ } else if (auto threeWayCmp = dyn_cast<cir::CmpThreeWayOp>(op)) {
lowerThreeWayCmpOp(threeWayCmp);
}
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 3ffa2c62936bd..28b3454d20613 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1575,59 +1575,6 @@ mlir::LogicalResult CIRToLLVMGetElementOpLowering::matchAndRewrite(
return mlir::failure();
}
-static std::string getThreeWayCmpIntrinsicName(bool signedCmp,
- unsigned operandWidth,
- unsigned resultWidth) {
- // The intrinsic's name takes the form:
- // `llvm.<scmp|ucmp>.i<resultWidth>.i<operandWidth>`
-
- std::string result = "llvm.";
-
- if (signedCmp)
- result.append("scmp.");
- else
- result.append("ucmp.");
-
- // Result type part.
- result.push_back('i');
- result.append(std::to_string(resultWidth));
- result.push_back('.');
-
- // Operand type part.
- result.push_back('i');
- result.append(std::to_string(operandWidth));
-
- return result;
-}
-
-mlir::LogicalResult CIRToLLVMCmpThreeWayOpLowering::matchAndRewrite(
- cir::CmpThreeWayOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const {
- if (!op.isIntegralComparison() || !op.isStrongOrdering()) {
- op.emitError() << "unsupported three-way comparison type";
- return mlir::failure();
- }
-
- cir::CmpThreeWayInfoAttr cmpInfo = op.getInfo();
- assert(cmpInfo.getLt() == -1 && cmpInfo.getEq() == 0 && cmpInfo.getGt() == 1);
-
- auto operandTy = mlir::cast<cir::IntType>(op.getLhs().getType());
- cir::IntType resultTy = op.getType();
- std::string llvmIntrinsicName = getThreeWayCmpIntrinsicName(
- operandTy.isSigned(), operandTy.getWidth(), resultTy.getWidth());
-
- rewriter.setInsertionPoint(op);
-
- mlir::Value llvmLhs = adaptor.getLhs();
- mlir::Value llvmRhs = adaptor.getRhs();
- mlir::Type llvmResultTy = getTypeConverter()->convertType(resultTy);
- mlir::LLVM::CallIntrinsicOp callIntrinsicOp =
- createCallLLVMIntrinsicOp(rewriter, op.getLoc(), llvmIntrinsicName,
- llvmResultTy, {llvmLhs, llvmRhs});
-
- return mlir::success();
-}
-
mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index 2373c9d4f5d6d..da3d505a10ecb 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -1,38 +1,44 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
// RUN: FileCheck %s --input-file=%t-before.cir --check-prefix=BEFORE
-// RUN: FileCheck: %s --input-file=%t.cir --check-prefix=AFTER
+// RUN: FileCheck %s --input-file=%t.cir --check-prefix=AFTER
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t.ll 2>&1 | FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t.ll 2>&1
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o %t.ll 2>&1 | FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm %s -o %t-og.ll 2>&1
+// RUN: FileCheck --input-file=%t-og.ll %s -check-prefix=OGCG
#include "../../CodeGenCXX/Inputs/std-compare.h"
// BEFORE: #cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
-// BEFORE: #cmp3way_info_strong_ltn1eq0gt1 = #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1>
-// BEFORE: !rec_std3A3A__13A3Apartial_ordering = !cir.record<class "std::__1::partial_ordering" {!s8i}
-// BEFORE: !rec_std3A3A__13A3Astrong_ordering = !cir.record<class "std::__1::strong_ordering" {!s8i}
+// BEFORE: #cmp3way_info_total_ltn1eq0gt1 = #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1>
+// BEFORE: !rec_std3A3A__13A3Apartial_ordering = !cir.record<class "std::__1::partial_ordering" {!s8i}>
+// BEFORE: !rec_std3A3A__13A3Astrong_ordering = !cir.record<class "std::__1::strong_ordering" {!s8i}>
-auto three_way_strong(int x, int y) {
+auto three_way_total(int x, int y) {
return x <=> y;
}
-// BEFORE: cir.func {{.*}} @_Z16three_way_strongii
-// BEFORE: %{{.+}} = cir.cmp3way(%{{.+}} : !s32i, %{{.+}}, #cmp3way_info_strong_ltn1eq0gt1) : !s8i
+// BEFORE: cir.func {{.*}} @_Z15three_way_totalii
+// BEFORE: %{{.+}} = cir.cmp3way #cmp3way_info_total_ltn1eq0gt1 %{{.+}}, %{{.+}} : !s32i -> !s8i
// BEFORE: }
-// AFTER: cir.func {{.*}} @_Z16three_way_strongii
-// AFTER: %[[LHS:.*]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
-// AFTER-NEXT: %[[RHS:.*]] = cir.load {{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
-// AFTER-NEXT: %[[LT:.*]] = cir.const #cir.int<-1> : !s8i
-// AFTER-NEXT: %[[EQ:.*]] = cir.const #cir.int<0> : !s8i
-// AFTER-NEXT: %[[GT:.*]] = cir.const #cir.int<1> : !s8i
-// AFTER-NEXT: %[[CMP_LT:.*]] = cir.cmp(lt, %[[LHS]], %[[RHS]]) : !s32i, !cir.bool
-// AFTER-NEXT: %[[CMP_EQ:.*]] = cir.cmp(eq, %[[LHS]], %[[RHS]]) : !s32i, !cir.bool
-// AFTER-NEXT: %[[SELECT_1:.*]] = cir.select if %[[CMP_EQ]] then %[[EQ]] else %[[GT]] : (!cir.bool, !s8i, !s8i) -> !s8i
-// AFTER-NEXT: %[[SELECT_2:.*]] = cir.select if %[[CMP_LT]] then %[[LT]] else %[[SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER: cir.func {{.*}} @_Z15three_way_totalii{{.*}}
+// AFTER: %[[LHS:.*]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i{{.*}}
+// AFTER-NEXT: %[[RHS:.*]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i{{.*}}
+// AFTER-NEXT: %[[LT:.*]] = cir.const #cir.int<-1> : !s8i{{.*}}
+// AFTER-NEXT: %[[EQ:.*]] = cir.const #cir.int<0> : !s8i{{.*}}
+// AFTER-NEXT: %[[GT:.*]] = cir.const #cir.int<1> : !s8i{{.*}}
+// AFTER-NEXT: %[[CMP_LT:.*]] = cir.cmp(lt, %[[LHS]], %[[RHS]]) : !s32i, !cir.bool{{.*}}
+// AFTER-NEXT: %[[CMP_EQ:.*]] = cir.cmp(eq, %[[LHS]], %[[RHS]]) : !s32i, !cir.bool{{.*}}
+// AFTER-NEXT: %[[SELECT_1:.*]] = cir.select if %[[CMP_EQ]] then %[[EQ]] else %[[GT]] : (!cir.bool, !s8i, !s8i) -> !s8i{{.*}}
+// AFTER-NEXT: %[[SELECT_2:.*]] = cir.select if %[[CMP_LT]] then %[[LT]] else %[[SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i{{.*}}
+// AFTER-NEXT: %{{.+}} = cir.get_member %{{.+}}[0] {{.*}} "__value_"{{.*}}
+// AFTER-NEXT: cir.store align(1) %[[SELECT_2]], %{{.+}} : !s8i, !cir.ptr<!s8i>{{.*}}
+// AFTER-NEXT: %{{.+}} = cir.load %{{.+}} : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, !rec_std3A3A__13A3Astrong_ordering{{.*}}
+// AFTER-NEXT: cir.return %{{.+}} : !rec_std3A3A__13A3Astrong_ordering{{.*}}
// LLVM: %[[LHS:.*]] = load i32, ptr %{{.*}}, align 4
// LLVM-NEXT: %[[RHS:.*]] = load i32, ptr %{{.*}}, align 4
@@ -48,27 +54,31 @@ auto three_way_strong(int x, int y) {
// OGCG-NEXT: %[[CMP_EQ:.*]] = icmp eq i32 %[[LHS]], %[[RHS]]
// OGCG-NEXT: %[[RES:.*]] = select i1 %[[CMP_EQ]], i8 0, i8 %[[SEL_EQ_LT]]
-auto three_way_weak(float x, float y) {
+auto three_way_partial(float x, float y) {
return x <=> y;
}
-// BEFORE: cir.func {{.*}} @_Z14three_way_weakff
-// BEFORE: %{{.+}} = cir.cmp3way(%{{.+}} : !cir.float, %{{.+}}, #cmp3way_info_partial_ltn1eq0gt1unn127) : !s8i
+// BEFORE: cir.func {{.*}} @_Z17three_way_partialff
+// BEFORE: %{{.+}} = cir.cmp3way #cmp3way_info_partial_ltn1eq0gt1unn127 %{{.+}}, %{{.+}} : !cir.float -> !s8i
// BEFORE: }
-// AFTER: cir.func {{.*}} @_Z14three_way_weakff
-// AFTER: %[[LHS:.*]] = cir.load {{.*}} %0 : !cir.ptr<!cir.float>, !cir.float
-// AFTER-NEXT: %[[RHS:.*]] = cir.load {{.*}} %1 : !cir.ptr<!cir.float>, !cir.float
-// AFTER-NEXT: %[[LT:.*]] = cir.const #cir.int<-1> : !s8i
-// AFTER-NEXT: %[[EQ:.*]] = cir.const #cir.int<0> : !s8i
-// AFTER-NEXT: %[[GT:.*]] = cir.const #cir.int<1> : !s8i
-// AFTER-NEXT: %[[CMP_LT:.*]] = cir.cmp(lt, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[CMP_EQ:.*]] = cir.cmp(eq, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[UNORDERED:.*]] = cir.const #cir.int<-127> : !s8i
-// AFTER-NEXT: %[[CMP_GT:.*]] = cir.cmp(gt, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool
-// AFTER-NEXT: %[[SELECT_1:.*]] = cir.select if %[[CMP_EQ]] then %[[EQ]] else %[[UNORDERED]] : (!cir.bool, !s8i, !s8i) -> !s8i
-// AFTER-NEXT: %[[SELECT_2:.*]] = cir.select if %[[CMP_GT]] then %[[GT]] else %[[SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i
-// AFTER-NEXT: %[[SELECT_3:.*]] = cir.select if %[[CMP_LT]] then %[[LT]] else %[[SELECT_2]] : (!cir.bool, !s8i, !s8i) -> !s8i
+// AFTER: cir.func {{.*}} @_Z17three_way_partialff{{.*}}
+// AFTER: %[[LHS:.*]] = cir.load align(4) %{{.+}} : !cir.ptr<!cir.float>, !cir.float{{.*}}
+// AFTER-NEXT: %[[RHS:.*]] = cir.load align(4) %{{.+}} : !cir.ptr<!cir.float>, !cir.float{{.*}}
+// AFTER-NEXT: %[[LT:.*]] = cir.const #cir.int<-1> : !s8i{{.*}}
+// AFTER-NEXT: %[[EQ:.*]] = cir.const #cir.int<0> : !s8i{{.*}}
+// AFTER-NEXT: %[[GT:.*]] = cir.const #cir.int<1> : !s8i{{.*}}
+// AFTER-NEXT: %[[CMP_LT:.*]] = cir.cmp(lt, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool{{.*}}
+// AFTER-NEXT: %[[CMP_EQ:.*]] = cir.cmp(eq, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool{{.*}}
+// AFTER-NEXT: %[[UNORDERED:.*]] = cir.const #cir.int<-127> : !s8i{{.*}}
+// AFTER-NEXT: %[[CMP_GT:.*]] = cir.cmp(gt, %[[LHS]], %[[RHS]]) : !cir.float, !cir.bool{{.*}}
+// AFTER-NEXT: %[[SELECT_1:.*]] = cir.select if %[[CMP_EQ]] then %[[EQ]] else %[[UNORDERED]] : (!cir.bool, !s8i, !s8i) -> !s8i{{.*}}
+// AFTER-NEXT: %[[SELECT_2:.*]] = cir.select if %[[CMP_GT]] then %[[GT]] else %[[SELECT_1]] : (!cir.bool, !s8i, !s8i) -> !s8i{{.*}}
+// AFTER-NEXT: %[[SELECT_3:.*]] = cir.select if %[[CMP_LT]] then %[[LT]] else %[[SELECT_2]] : (!cir.bool, !s8i, !s8i) -> !s8i{{.*}}
+// AFTER-NEXT: %{{.+}} = cir.get_member %{{.+}}[0] {{.*}} "__value_"{{.*}}
+// AFTER-NEXT: cir.store align(1) %[[SELECT_3]], %{{.+}} : !s8i, !cir.ptr<!s8i>{{.*}}
+// AFTER-NEXT: %{{.+}} = cir.load %{{.+}} : !cir.ptr<!rec_std3A3A__13A3Apartial_ordering>, !rec_std3A3A__13A3Apartial_ordering{{.*}}
+// AFTER-NEXT: cir.return %{{.+}} : !rec_std3A3A__13A3Apartial_ordering{{.*}}
// LLVM: %[[LHS:.*]] = load float, ptr %{{.*}}, align 4
// LLVM: %[[RHS:.*]] = load float, ptr %{{.*}}, align 4
@@ -87,9 +97,3 @@ auto three_way_weak(float x, float y) {
// OGCG: %[[SEL_GT_EQUN:.*]] = select i1 %[[CMP_GT]], i8 1, i8 %[[SEL_EQ_UN]]
// OGCG: %[[CMP_LT:.*]] = fcmp olt float %[[LHS]], %[[RHS]]
// OGCG: %[[RES:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_GT_EQUN]]
-
-auto nullptr_compare() {
- int* x = 0;
- return nullptr <=> 0;
-}
- // TODO: assertions: should be equal
\ No newline at end of file
diff --git a/clang/test/CIR/IR/invalid-cmp3way.cir b/clang/test/CIR/IR/invalid-cmp3way.cir
new file mode 100644
index 0000000000000..240177bbac7f2
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-cmp3way.cir
@@ -0,0 +1,27 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!s32i = !cir.int<s, 32>
+!s8i = !cir.int<s, 8>
+
+module {
+ // Total ordering must not include unordered.
+ cir.func @cmp3way_total_with_unordered(%arg0 : !s32i, %arg1 : !s32i) -> !s8i {
+ // expected-error at +1 {{total ordering does not include unordered ordering}}
+ %0 = cir.cmp3way #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1, unordered = -127> %arg0, %arg1 : !s32i -> !s8i
+ cir.return %0 : !s8i
+ }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!s8i = !cir.int<s, 8>
+
+module {
+ // Partial ordering must include unordered.
+ cir.func @cmp3way_partial_without_unordered(%arg0 : !s32i, %arg1 : !s32i) -> !s8i {
+ // expected-error at +1 {{partial ordering lacks unordered ordering}}
+ %0 = cir.cmp3way #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1> %arg0, %arg1 : !s32i -> !s8i
+ cir.return %0 : !s8i
+ }
+}
More information about the cfe-commits
mailing list