[clang] [CIR] Upstream ThreeWayCmpOp (PR #169963)

Hendrik Hübner via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 10 12:01:34 PDT 2026


https://github.com/HendrikHuebner updated https://github.com/llvm/llvm-project/pull/169963

>From 0302328f37711e64d7ca4b5473ddb48c6719e076 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 01/14] [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    |  40 +++
 .../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, 759 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 b1be1d5daf4e0..ae6e40da5bec3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -573,6 +573,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 2c109eaeb392e..7d98142a06691 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1279,6 +1279,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 7cd1bdcf491be..88ad81414d0b2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -716,6 +716,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 &ltRes,
+                                             const llvm::APSInt &eqRes,
+                                             const llvm::APSInt &gtRes) {
+    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 &ltRes, const llvm::APSInt &eqRes,
+                           const llvm::APSInt &gtRes,
+                           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 9f390fec97613..4da2f82055ccc 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 4cd2073bf49aa..8b465236e0310 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -349,6 +349,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 8d2990af5de8c..455cbc920b8c9 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;
   }
 };
@@ -1527,6 +1532,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 232d320d71f37..d52a0e2b8bc37 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1262,6 +1262,46 @@ 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::eq, op.getLhs(), op.getRhs());
+
+  mlir::Value transformedResult;
+  if (cmpInfo.getOrdering() != CmpOrdering::Partial) {
+    // Total 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 selectOnEq = builder.createSelect(loc, eq, eqRes, unorderedRes);
+    mlir::Value gt =
+        builder.createCompare(loc, CmpOpKind::gt, op.getLhs(), op.getRhs());
+    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,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index b996a05782370..a9df770f9ec2f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1633,6 +1633,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 108c668ec392846f6ded8d0272e84b4eb2897fc4 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 02/14] 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 -
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp |  4 ++++
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp  |  7 ++++---
 6 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 88ad81414d0b2..0796b6c8db1fe 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -726,7 +726,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);
   }
@@ -742,7 +743,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 4da2f82055ccc..c06fe73e457c6 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 8b465236e0310..9e5c42518bf17 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -349,7 +349,6 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
   return success();
 }
 
-
 //===----------------------------------------------------------------------===//
 // CmpThreeWayInfoAttr definitions
 //===----------------------------------------------------------------------===//
@@ -402,7 +401,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 455cbc920b8c9..f88384e72c671 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1532,7 +1532,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 d52a0e2b8bc37..ce5811bfa1397 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1613,7 +1613,11 @@ void LoweringPreparePass::runOnOperation() {
     if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
                   cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
                   cir::FuncOp, cir::CallOp, cir::GetGlobalOp, cir::GlobalOp,
+<<<<<<< HEAD
                   cir::StoreOp, cir::UnaryOp>(op))
+=======
+                  cir::UnaryOp, cir::CmpThreeWayOp>(op))
+>>>>>>> 041cf9ff6b44 (fmt)
       opsToTransform.push_back(op);
   });
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index a9df770f9ec2f..e572b2c850ea0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1633,8 +1633,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>`
 
@@ -1676,7 +1677,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 4855681be0f9596ac2514a63ff076de4c367917d 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 03/14] fix tests

---
 clang/test/CIR/CodeGen/three-way-cmp.cpp | 82 ++++++++++++++----------
 1 file changed, 48 insertions(+), 34 deletions(-)

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 83a75d3fa311426aaa47b15816e87fb85c74156b 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 04/14] 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 ae6e40da5bec3..9202b3f7913e4 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -585,10 +585,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
@@ -599,6 +599,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 7d98142a06691..b5699024af2d0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1303,16 +1303,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
     ```
   }];
 
@@ -1325,8 +1327,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 = [{
@@ -1340,8 +1342,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 0796b6c8db1fe..c25211af32de1 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"
@@ -741,7 +742,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 c06fe73e457c6..874b0b7cb5bed 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 b14d92eaf2dab45f09e0585e8b1f88d4e3e02381 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 05/14] 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    |  9 +-
 .../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, 103 insertions(+), 131 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 9202b3f7913e4..ef206488ebec3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -579,20 +579,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
@@ -606,11 +607,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
@@ -626,7 +627,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 b5699024af2d0..b944f27c3bc31 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1305,12 +1305,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
@@ -1327,14 +1327,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.
@@ -1342,6 +1342,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 c25211af32de1..00fd8aafcf5a3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -717,7 +717,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 &ltRes,
                                              const llvm::APSInt &eqRes,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 874b0b7cb5bed..7829ef253118f 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 9e5c42518bf17..e3a45e0b6ec29 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -356,8 +356,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_");
 
@@ -389,8 +389,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 f88384e72c671..b5e4a8cad59c5 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1532,20 +1532,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 ce5811bfa1397..5f0c7ccf9ffca 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1282,8 +1282,8 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
       builder.createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
 
   mlir::Value transformedResult;
-  if (cmpInfo.getOrdering() != CmpOrdering::Partial) {
-    // Total 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 {
@@ -1599,6 +1599,11 @@ 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());
+<<<<<<< HEAD
+=======
+  } else if (auto threeWayCmp = dyn_cast<cir::CmpThreeWayOp>(op)) {
+    lowerThreeWayCmpOp(threeWayCmp);
+>>>>>>> a4d65d53bde8 (feedback)
   }
 }
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index e572b2c850ea0..b996a05782370 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1633,59 +1633,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
+  }
+}

>From 793e5c925764390a83fb794f4438ee32f379c01c Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sun, 15 Feb 2026 18:16:34 +0100
Subject: [PATCH 06/14] fmt

---
 clang/lib/CIR/CodeGen/CIRGenBuilder.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 00fd8aafcf5a3..c43dbb2124519 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -717,11 +717,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return cir::StackRestoreOp::create(*this, loc, v);
   }
 
-  cir::CmpThreeWayOp createThreeWayCmpTotal(mlir::Location loc,
-                                             mlir::Value lhs, mlir::Value rhs,
-                                             const llvm::APSInt &ltRes,
-                                             const llvm::APSInt &eqRes,
-                                             const llvm::APSInt &gtRes) {
+  cir::CmpThreeWayOp createThreeWayCmpTotal(mlir::Location loc, mlir::Value lhs,
+                                            mlir::Value rhs,
+                                            const llvm::APSInt &ltRes,
+                                            const llvm::APSInt &eqRes,
+                                            const llvm::APSInt &gtRes) {
     assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
            ltRes.getBitWidth() == gtRes.getBitWidth() &&
            "the three comparison results must have the same bit width");

>From deff59d73c91bb223684efb73dc130bcb9073368 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sun, 15 Feb 2026 23:38:18 +0100
Subject: [PATCH 07/14] weak attribute

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 17 ++++++-------
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 22 +++++++++--------
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         | 23 +++++++++---------
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 10 ++++----
 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp         | 22 +++++++++++------
 .../Dialect/Transforms/LoweringPrepare.cpp    |  4 ++--
 clang/test/CIR/CodeGen/three-way-cmp.cpp      |  4 ++--
 clang/test/CIR/IR/invalid-cmp3way.cir         | 24 +++++++++++++++----
 8 files changed, 77 insertions(+), 49 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index ef206488ebec3..41db6f2b8abbd 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -579,8 +579,9 @@ def CIR_MethodAttr : CIR_Attr<"Method", "method", [TypedAttrInterface]> {
 
 def CIR_CmpOrdering : CIR_I32EnumAttr<
   "CmpOrdering", "three-way comparison ordering kind", [
-    I32EnumAttrCase<"Total", 0, "total">,
-    I32EnumAttrCase<"Partial", 1, "partial">
+    I32EnumAttrCase<"Strong", 0, "strong">,
+    I32EnumAttrCase<"Weak", 1, "weak">,
+    I32EnumAttrCase<"Partial", 2, "partial">
 ]> {
   let genSpecializedAttr = 0;
 }
@@ -592,8 +593,7 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
     comparison operation `cir.cmp3way`.
 
     The `ordering` parameter gives the ordering kind of the three-way comparison
-    operation. It may be either total ordering (which includes both strong and
-    weak orderings) or partial ordering.
+    operation: strong ordering, weak 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
@@ -607,11 +607,11 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
     !s32i = !cir.int<s, 32>
 
     #cmp3way_info_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
-    #cmp3way_info_total_ltn1eq0gt1 = #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1>
+    #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_total_ltn1eq0gt1) : !s8i
+    %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
@@ -626,8 +626,9 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
   );
 
   let builders = [
-    AttrBuilder<(ins "int64_t":$lt, "int64_t":$eq, "int64_t":$gt), [{
-      return $_get($_ctxt, CmpOrdering::Total, lt, eq, gt, std::nullopt);
+    AttrBuilder<(ins "CmpOrdering":$ordering, "int64_t":$lt, "int64_t":$eq,
+                     "int64_t":$gt), [{
+      return $_get($_ctxt, ordering, 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 b944f27c3bc31..0031a830a530d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1279,6 +1279,7 @@ def CIR_CleanupScopeOp : CIR_Op<"cleanup.scope", [
 
   let hasLLVMLowering = false;
 }
+
 //===----------------------------------------------------------------------===//
 // CmpThreeWayOp
 //===----------------------------------------------------------------------===//
@@ -1286,14 +1287,14 @@ def CIR_CleanupScopeOp : CIR_Op<"cleanup.scope", [
 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 `cir.cmp3way` operation models the builtin `<=>` 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.
+    There are three kinds of ordering: strong, weak 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.
@@ -1305,12 +1306,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_total_ltn1eq0gt1 =
-      #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1>
+    #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 #cmp3way_info_total_ltn1eq0gt1 %0, %1 : !s32i -> !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
@@ -1332,9 +1333,10 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
   }];
 
   let extraClassDeclaration = [{
-    /// Determine whether this three-way comparison produces a total ordering.
-    bool isTotalOrdering() {
-      return getInfo().getOrdering() == cir::CmpOrdering::Total;
+    /// Determine whether this three-way comparison produces a partial ordering
+    bool isPartialOrdering() {
+      cir::CmpOrdering o = getInfo().getOrdering();
+      return o == cir::CmpOrdering::Partial;
     }
 
     /// Determine whether this three-way comparison compares integral operands.
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index c43dbb2124519..a073178e78cd5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -717,27 +717,28 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return cir::StackRestoreOp::create(*this, loc, v);
   }
 
-  cir::CmpThreeWayOp createThreeWayCmpTotal(mlir::Location loc, mlir::Value lhs,
-                                            mlir::Value rhs,
-                                            const llvm::APSInt &ltRes,
-                                            const llvm::APSInt &eqRes,
-                                            const llvm::APSInt &gtRes) {
+  cir::CmpThreeWayOp createThreeWayCmpTotalOrdering(
+      mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
+      const llvm::APSInt &ltRes, const llvm::APSInt &eqRes,
+      const llvm::APSInt &gtRes, cir::CmpOrdering ordering) {
     assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
            ltRes.getBitWidth() == gtRes.getBitWidth() &&
            "the three comparison results must have the same bit width");
+    assert((ordering == cir::CmpOrdering::Strong ||
+            ordering == cir::CmpOrdering::Weak) &&
+           "total ordering must be strong or weak");
     cir::IntType cmpResultTy = getSIntNTy(ltRes.getBitWidth());
     auto infoAttr = cir::CmpThreeWayInfoAttr::get(
-        getContext(), ltRes.getSExtValue(), eqRes.getSExtValue(),
+        getContext(), ordering, 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 &ltRes, const llvm::APSInt &eqRes,
-                           const llvm::APSInt &gtRes,
-                           const llvm::APSInt &unorderedRes) {
+  cir::CmpThreeWayOp createThreeWayCmpPartialOrdering(
+      mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
+      const llvm::APSInt &ltRes, const llvm::APSInt &eqRes,
+      const llvm::APSInt &gtRes, const llvm::APSInt &unorderedRes) {
     assert(ltRes.getBitWidth() == eqRes.getBitWidth() &&
            ltRes.getBitWidth() == gtRes.getBitWidth() &&
            ltRes.getBitWidth() == unorderedRes.getBitWidth() &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 7829ef253118f..3222581865fab 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -359,13 +359,15 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
       llvm::APSInt eqRes = cmpInfo.getEqualOrEquiv()->getIntValue();
       llvm::APSInt gtRes = cmpInfo.getGreater()->getIntValue();
       if (!cmpInfo.isPartial()) {
-        // Total ordering.
-        resultScalar =
-            builder.createThreeWayCmpTotal(loc, lhs, rhs, ltRes, eqRes, gtRes);
+        cir::CmpOrdering ordering = cmpInfo.isStrong()
+                                        ? cir::CmpOrdering::Strong
+                                        : cir::CmpOrdering::Weak;
+        resultScalar = builder.createThreeWayCmpTotalOrdering(
+            loc, lhs, rhs, ltRes, eqRes, gtRes, ordering);
       } else {
         // Partial ordering.
         llvm::APSInt unorderedRes = cmpInfo.getUnordered()->getIntValue();
-        resultScalar = builder.createThreeWayCmpPartial(
+        resultScalar = builder.createThreeWayCmpPartialOrdering(
             loc, lhs, rhs, ltRes, eqRes, gtRes, unorderedRes);
       }
     }
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index e3a45e0b6ec29..07f1648440993 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -356,10 +356,17 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
 std::string CmpThreeWayInfoAttr::getAlias() const {
   std::string alias = "cmp3way_info";
 
-  if (getOrdering() == CmpOrdering::Total)
-    alias.append("_total_");
-  else
+  switch (getOrdering()) {
+  case CmpOrdering::Strong:
+    alias.append("_strong_");
+    break;
+  case CmpOrdering::Weak:
+    alias.append("_weak_");
+    break;
+  case CmpOrdering::Partial:
     alias.append("_partial_");
+    break;
+  }
 
   auto appendInt = [&](int64_t value) {
     if (value < 0) {
@@ -388,13 +395,14 @@ 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::Total && unordered) {
-    emitError() << "total ordering does not include unordered ordering";
+  // The presence of unordered must match the value of ordering.
+  if ((ordering == CmpOrdering::Strong || ordering == CmpOrdering::Weak) &&
+      unordered) {
+    emitError() << "strong and weak ordering do not include unordered";
     return failure();
   }
   if (ordering == CmpOrdering::Partial && !unordered) {
-    emitError() << "partial ordering lacks unordered ordering";
+    emitError() << "partial ordering requires unordered value";
     return failure();
   }
 
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 5f0c7ccf9ffca..d74c2490ed44c 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1282,8 +1282,8 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
       builder.createCompare(loc, CmpOpKind::eq, op.getLhs(), op.getRhs());
 
   mlir::Value transformedResult;
-  if (cmpInfo.getOrdering() == CmpOrdering::Total) {
-    // Total ordering.
+  if (cmpInfo.getOrdering() != CmpOrdering::Partial) {
+    // Total ordering
     mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, gtRes);
     transformedResult = builder.createSelect(loc, lt, ltRes, selectOnEq);
   } else {
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index da3d505a10ecb..57915bc00a478 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -13,7 +13,7 @@
 #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_total_ltn1eq0gt1 = #cir.cmp3way_info<total, lt = -1, eq = 0, gt = 1>
+// 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}>
 
@@ -22,7 +22,7 @@ auto three_way_total(int x, int y) {
 }
 
 // BEFORE: cir.func {{.*}} @_Z15three_way_totalii
-// BEFORE:   %{{.+}} = cir.cmp3way #cmp3way_info_total_ltn1eq0gt1 %{{.+}}, %{{.+}} : !s32i -> !s8i
+// BEFORE:   %{{.+}} = cir.cmp3way #cmp3way_info_strong_ltn1eq0gt1 %{{.+}}, %{{.+}} : !s32i -> !s8i
 // BEFORE: }
 
 //      AFTER:   cir.func {{.*}} @_Z15three_way_totalii{{.*}}
diff --git a/clang/test/CIR/IR/invalid-cmp3way.cir b/clang/test/CIR/IR/invalid-cmp3way.cir
index 240177bbac7f2..3691f245a6ff8 100644
--- a/clang/test/CIR/IR/invalid-cmp3way.cir
+++ b/clang/test/CIR/IR/invalid-cmp3way.cir
@@ -4,10 +4,24 @@
 !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
+  // Strong ordering must not include unordered.
+  cir.func @cmp3way_strong_with_unordered(%arg0 : !s32i, %arg1 : !s32i) -> !s8i {
+    // expected-error at +1 {{strong and weak ordering do not include unordered}}
+    %0 = cir.cmp3way #cir.cmp3way_info<strong, 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 {
+  // Weak ordering must not include unordered.
+  cir.func @cmp3way_weak_with_unordered(%arg0 : !s32i, %arg1 : !s32i) -> !s8i {
+    // expected-error at +1 {{strong and weak ordering do not include unordered}}
+    %0 = cir.cmp3way #cir.cmp3way_info<weak, lt = -1, eq = 0, gt = 1, unordered = -127> %arg0, %arg1 : !s32i -> !s8i
     cir.return %0 : !s8i
   }
 }
@@ -20,7 +34,7 @@ module {
 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}}
+    // expected-error at +1 {{partial ordering requires unordered value}}
     %0 = cir.cmp3way #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1> %arg0, %arg1 : !s32i -> !s8i
     cir.return %0 : !s8i
   }

>From 7b579b545056189bea8c8700ba7067b465651cec Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Sun, 15 Feb 2026 23:40:35 +0100
Subject: [PATCH 08/14] weak attribute

---
 clang/test/CIR/CodeGen/three-way-cmp.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index 57915bc00a478..9be0cca905456 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -14,8 +14,10 @@
 
 // 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: #cmp3way_info_weak_ltn1eq0gt1 = #cir.cmp3way_info<weak, 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: !rec_std3A3A__13A3Aweak_ordering = !cir.record<class "std::__1::weak_ordering" {!s8i}>
 
 auto three_way_total(int x, int y) {
   return x <=> y;

>From dab9fa6461160bc439a72249c88153f392bc4940 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Mon, 16 Feb 2026 00:22:26 +0100
Subject: [PATCH 09/14] remove weak test

---
 clang/test/CIR/CodeGen/three-way-cmp.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index 9be0cca905456..e11bcc8cdb634 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -14,20 +14,18 @@
 
 // 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: #cmp3way_info_weak_ltn1eq0gt1 = #cir.cmp3way_info<weak, 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: !rec_std3A3A__13A3Aweak_ordering = !cir.record<class "std::__1::weak_ordering" {!s8i}>
 
-auto three_way_total(int x, int y) {
+auto three_way_strong(int x, int y) {
   return x <=> y;
 }
 
-// BEFORE: cir.func {{.*}} @_Z15three_way_totalii
+// BEFORE: cir.func {{.*}} @_Z16three_way_strongii
 // BEFORE:   %{{.+}} = cir.cmp3way #cmp3way_info_strong_ltn1eq0gt1 %{{.+}}, %{{.+}} : !s32i -> !s8i
 // BEFORE: }
 
-//      AFTER:   cir.func {{.*}} @_Z15three_way_totalii{{.*}}
+//      AFTER:   cir.func {{.*}} @_Z16three_way_strongii{{.*}}
 //      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{{.*}}

>From 507311d3f676f802a3d1786cb5a7ce1beee2ebd4 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Mon, 16 Feb 2026 01:05:43 +0100
Subject: [PATCH 10/14] descriptions

---
 clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 4 +++-
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp  | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 41db6f2b8abbd..df1a66d9eac85 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -593,7 +593,9 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
     comparison operation `cir.cmp3way`.
 
     The `ordering` parameter gives the ordering kind of the three-way comparison
-    operation: strong ordering, weak ordering, or partial ordering.
+    operation: strong ordering, weak ordering, or partial ordering. Strong and
+    weak orderings are both total orderings (i.e. every two elements are comparable),
+    while partial orderings can have incomparable elements.
 
     Given the two input operands of the three-way comparison operation `lhs` and
     `rhs`, the `lt`, `eq`, `gt`, and `unordered` parameters gives the result
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 3222581865fab..69dc5f53abc85 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -347,6 +347,9 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
     if (e->getType()->isAnyComplexType())
       cgf.cgm.errorNYI(e->getBeginLoc(), "VisitBinCmp: complex type");
 
+    if (e->getType()->isAggregateType())
+      cgf.cgm.errorNYI(e->getBeginLoc(), "VisitBinCmp: aggregate type");
+
     mlir::Value lhs = cgf.emitAnyExpr(e->getLHS()).getValue();
     mlir::Value rhs = cgf.emitAnyExpr(e->getRHS()).getValue();
 

>From c7a574c5874316f3ef97113f3b87e82b99c56608 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
 <117831077+HendrikHuebner at users.noreply.github.com>
Date: Tue, 24 Feb 2026 23:22:22 +0100
Subject: [PATCH 11/14] Update clang/test/CIR/CodeGen/three-way-cmp.cpp

Co-authored-by: Andy Kaylor <akaylor at nvidia.com>
---
 clang/test/CIR/CodeGen/three-way-cmp.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index e11bcc8cdb634..2f3677d340230 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -10,7 +10,7 @@
 // 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"
+#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>

>From 39aef69af3f764400916d39ca1abb1e3ef220251 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
 <117831077+HendrikHuebner at users.noreply.github.com>
Date: Tue, 24 Feb 2026 23:22:58 +0100
Subject: [PATCH 12/14] Update
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

Co-authored-by: Andy Kaylor <akaylor at nvidia.com>
---
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index d74c2490ed44c..be4d4383077e5 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1284,8 +1284,8 @@ void LoweringPreparePass::lowerThreeWayCmpOp(CmpThreeWayOp op) {
   mlir::Value transformedResult;
   if (cmpInfo.getOrdering() != CmpOrdering::Partial) {
     // Total ordering
-    mlir::Value selectOnEq = builder.createSelect(loc, eq, eqRes, gtRes);
-    transformedResult = builder.createSelect(loc, lt, ltRes, selectOnEq);
+    mlir::Value selectOnLt = builder.createSelect(loc, lt, ltRes, gtRes);
+    transformedResult = builder.createSelect(loc, eq, eqRes, selectOnLt);
   } else {
     // Partial ordering
     cir::ConstantOp unorderedRes = builder.getConstantInt(

>From 700c8d8f78ba8f01c901ad5be01edf560d289564 Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Tue, 24 Feb 2026 23:32:16 +0100
Subject: [PATCH 13/14] Fix path

---
 clang/test/CIR/CodeGen/three-way-cmp.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index 2f3677d340230..d444b771bb1a1 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -10,7 +10,7 @@
 // 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 "../Inputs/std-compare.h"
+#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>

>From 14d21d446b4eccd924fc15d10be81119e896383b Mon Sep 17 00:00:00 2001
From: hhuebner <hendrik.huebner18 at gmail.com>
Date: Tue, 10 Mar 2026 20:01:13 +0100
Subject: [PATCH 14/14] Fix botched merge

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 10 ++---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  8 ++--
 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp         |  2 +-
 .../Dialect/Transforms/LoweringPrepare.cpp    | 12 ++----
 clang/test/CIR/CodeGen/three-way-cmp.cpp      |  8 ++--
 clang/test/CIR/IR/invalid-cmp3way.cir         | 39 +++----------------
 6 files changed, 23 insertions(+), 56 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index df1a66d9eac85..1136d91ee4b0a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -589,7 +589,7 @@ def CIR_CmpOrdering : CIR_I32EnumAttr<
 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
+    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
@@ -608,16 +608,16 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
     ```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>
+    #cmpinfo_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
+    #cmpinfo_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
+    %2 = cir.cmp3way(%0 : !s32i, %1, #cmpinfo_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
+    %5 = cir.cmp3way(%3 : !cir.float, %4, #cmpinfo_partial_ltn1eq0gt1unn127) : !s8
     ```
   }];
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 0031a830a530d..7532f200c98b2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1304,18 +1304,18 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> {
     ```mlir
     !s32i = !cir.int<s, 32>
 
-    #cmp3way_info_partial_ltn1eq0gt1unn127 =
+    #cmpinfo_partial_ltn1eq0gt1unn127 =
       #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
-    #cmp3way_info_strong_ltn1eq0gt1 =
+    #cmpinfo_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 #cmp3way_info_strong_ltn1eq0gt1 %0, %1 : !s32i -> !s8i
+    %2 = cir.cmp3way #cmpinfo_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 #cmp3way_info_partial_ltn1eq0gt1unn127 %3, %4 : !cir.float -> !s8i
+    %5 = cir.cmp3way #cmpinfo_partial_ltn1eq0gt1unn127 %3, %4 : !cir.float -> !s8i
     ```
   }];
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 07f1648440993..d608038dafc5f 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -354,7 +354,7 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
 //===----------------------------------------------------------------------===//
 
 std::string CmpThreeWayInfoAttr::getAlias() const {
-  std::string alias = "cmp3way_info";
+  std::string alias = "cmpinfo";
 
   switch (getOrdering()) {
   case CmpOrdering::Strong:
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index be4d4383077e5..6076a5f085748 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1594,16 +1594,14 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
     lowerTrivialCopyCall(callOp);
   } else if (auto storeOp = dyn_cast<cir::StoreOp>(op)) {
     lowerStoreOfConstAggregate(storeOp);
-  } else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {
+  } else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {=======
+    >>>>>>> 041cf9ff6b44 (fmt)
     if (auto globalCtor = fnOp.getGlobalCtorPriority())
       globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
     else if (auto globalDtor = fnOp.getGlobalDtorPriority())
       globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
-<<<<<<< HEAD
-=======
   } else if (auto threeWayCmp = dyn_cast<cir::CmpThreeWayOp>(op)) {
     lowerThreeWayCmpOp(threeWayCmp);
->>>>>>> a4d65d53bde8 (feedback)
   }
 }
 
@@ -1618,11 +1616,7 @@ void LoweringPreparePass::runOnOperation() {
     if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
                   cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
                   cir::FuncOp, cir::CallOp, cir::GetGlobalOp, cir::GlobalOp,
-<<<<<<< HEAD
-                  cir::StoreOp, cir::UnaryOp>(op))
-=======
-                  cir::UnaryOp, cir::CmpThreeWayOp>(op))
->>>>>>> 041cf9ff6b44 (fmt)
+                  cir::StoreOp, cir::UnaryOp, cir::CmpThreeWayOp>(op))
       opsToTransform.push_back(op);
   });
 
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index d444b771bb1a1..c288d2ae4ccd0 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -12,8 +12,8 @@
 
 #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: #cmpinfo_partial_ltn1eq0gt1unn127 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1, unordered = -127>
+// BEFORE: #cmpinfo_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}>
 
@@ -22,7 +22,7 @@ auto three_way_strong(int x, int y) {
 }
 
 // BEFORE: cir.func {{.*}} @_Z16three_way_strongii
-// BEFORE:   %{{.+}} = cir.cmp3way #cmp3way_info_strong_ltn1eq0gt1 %{{.+}}, %{{.+}} : !s32i -> !s8i
+// BEFORE:   %{{.+}} = cir.cmp3way #cmpinfo_strong_ltn1eq0gt1 %{{.+}}, %{{.+}} : !s32i -> !s8i
 // BEFORE: }
 
 //      AFTER:   cir.func {{.*}} @_Z16three_way_strongii{{.*}}
@@ -59,7 +59,7 @@ auto three_way_partial(float x, float y) {
 }
 
 // BEFORE: cir.func {{.*}} @_Z17three_way_partialff
-// BEFORE:   %{{.+}} = cir.cmp3way #cmp3way_info_partial_ltn1eq0gt1unn127 %{{.+}}, %{{.+}} : !cir.float -> !s8i
+// BEFORE:   %{{.+}} = cir.cmp3way #cmpinfo_partial_ltn1eq0gt1unn127 %{{.+}}, %{{.+}} : !cir.float -> !s8i
 // BEFORE: }
 
 //      AFTER:   cir.func {{.*}} @_Z17three_way_partialff{{.*}}
diff --git a/clang/test/CIR/IR/invalid-cmp3way.cir b/clang/test/CIR/IR/invalid-cmp3way.cir
index 3691f245a6ff8..77a8d8e90e00b 100644
--- a/clang/test/CIR/IR/invalid-cmp3way.cir
+++ b/clang/test/CIR/IR/invalid-cmp3way.cir
@@ -1,41 +1,14 @@
 // RUN: cir-opt %s -verify-diagnostics -split-input-file
 
-!s32i = !cir.int<s, 32>
-!s8i = !cir.int<s, 8>
-
-module {
-  // Strong ordering must not include unordered.
-  cir.func @cmp3way_strong_with_unordered(%arg0 : !s32i, %arg1 : !s32i) -> !s8i {
-    // expected-error at +1 {{strong and weak ordering do not include unordered}}
-    %0 = cir.cmp3way #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1, unordered = -127> %arg0, %arg1 : !s32i -> !s8i
-    cir.return %0 : !s8i
-  }
-}
 
+// expected-error at +1 {{strong and weak ordering do not include unordered}}
+#cmpinfo_strong_ltn1eq0gt1unn127 = #cir.cmp3way_info<strong, lt = -1, eq = 0, gt = 1, unordered = -127>
 // -----
 
-!s32i = !cir.int<s, 32>
-!s8i = !cir.int<s, 8>
-
-module {
-  // Weak ordering must not include unordered.
-  cir.func @cmp3way_weak_with_unordered(%arg0 : !s32i, %arg1 : !s32i) -> !s8i {
-    // expected-error at +1 {{strong and weak ordering do not include unordered}}
-    %0 = cir.cmp3way #cir.cmp3way_info<weak, lt = -1, eq = 0, gt = 1, unordered = -127> %arg0, %arg1 : !s32i -> !s8i
-    cir.return %0 : !s8i
-  }
-}
+// expected-error at +1 {{strong and weak ordering do not include unordered}}
+#cmpinfo_weak_ltn1eq0gt1unn127 = #cir.cmp3way_info<weak, lt = -1, eq = 0, gt = 1, unordered = -127>
 
 // -----
 
-!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 requires unordered value}}
-    %0 = cir.cmp3way #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1> %arg0, %arg1 : !s32i -> !s8i
-    cir.return %0 : !s8i
-  }
-}
+// expected-error at +1 {{partial ordering requires unordered value}}
+#cmp3way_info_partial_ltn1eq0gt1 = #cir.cmp3way_info<partial, lt = -1, eq = 0, gt = 1>



More information about the cfe-commits mailing list