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