From 426ad3ae76c80252bd8aa59ba2a6361b6967c163 Mon Sep 17 00:00:00 2001 From: zhijian Date: Mon, 17 Nov 2025 15:17:57 +0000 Subject: [PATCH] convert (setcc (and X, 1), 0, eq) --> XORI (and X, 1), 1 --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 71 +++++++++++++++++++ .../memCmpUsedInZeroEqualityComparison.ll | 3 +- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index f55336bafd251..ea0e31ae47082 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -15775,11 +15775,82 @@ SDValue convertTwoLoadsAndCmpToVCMPEQUB(SelectionDAG &DAG, SDNode *N, CC == ISD::SETNE ? ISD::SETEQ : ISD::SETNE); } +// Detect whether there is a pattern like (setcc (and X, 1), 0, eq). +// If it is , return true; otherwise return false. +static bool canConvertSETCCToXori(SDNode *N) { + if (N->getOpcode() != ISD::SETCC) + return false; + + ISD::CondCode CC = cast(N->getOperand(2))->get(); + if (CC != ISD::SETEQ) + return false; + + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + + // Check the `SDValue &V` is from `and` with `1`. + auto IsAndWithOne = [](SDValue &V) { + if (V.getOpcode() == ISD::AND) { + SDNode *AndNode = V.getNode(); + for (const SDValue &Op : AndNode->ops()) + if (auto *C = dyn_cast(Op)) + if (C->isOne()) + return true; + } + return false; + }; + + // Check whether the SETCC compare with zero. + auto IsCompareWithZero = [](SDValue &V) { + if (auto *C = dyn_cast(V)) + if (C->isZero()) + return true; + return false; + }; + + return (IsAndWithOne(LHS) && IsCompareWithZero(RHS)) || + (IsAndWithOne(RHS) && IsCompareWithZero(LHS)); +} + +// You must check whether the `SDNode* N` can be converted to Xori using +// the function `static bool canConvertSETCCToXori(SDNode *N)` +// before calling the function; otherwise, it may produce incorrect results. +static SDValue ConvertSETCCToXori(SDNode *N, SelectionDAG &DAG) { + + assert(N->getOpcode() == ISD::SETCC && "Should SETCC SDNode here."); + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + SDLoc DL(N); + + ISD::CondCode CC = cast(N->getOperand(2))->get(); + assert((CC == ISD::SETEQ) && "CC must be ISD::SETEQ."); + // Rewrite it as XORI (and X, 1), 1. + auto MakeXor1 = [&](SDValue V) { + EVT VT = V.getValueType(); + SDValue One = DAG.getConstant(1, DL, VT); + SDValue Xor = DAG.getNode(ISD::XOR, DL, VT, V, One); + return DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, Xor); + }; + + if (LHS.getOpcode() == ISD::AND && RHS.getOpcode() != ISD::AND) + return MakeXor1(LHS); + + if (RHS.getOpcode() == ISD::AND && LHS.getOpcode() != ISD::AND) + return MakeXor1(RHS); + + llvm_unreachable("Should not reach here."); +} + SDValue PPCTargetLowering::combineSetCC(SDNode *N, DAGCombinerInfo &DCI) const { assert(N->getOpcode() == ISD::SETCC && "Should be called with a SETCC node"); + // Check if the pattern (setcc (and X, 1), 0, eq) is present. + // If it is, rewrite it as XORI (and X, 1), 1. + if (canConvertSETCCToXori(N)) + return ConvertSETCCToXori(N, DCI.DAG); + ISD::CondCode CC = cast(N->getOperand(2))->get(); if (CC == ISD::SETNE || CC == ISD::SETEQ) { SDValue LHS = N->getOperand(0); diff --git a/llvm/test/CodeGen/PowerPC/memCmpUsedInZeroEqualityComparison.ll b/llvm/test/CodeGen/PowerPC/memCmpUsedInZeroEqualityComparison.ll index bf86695818689..8d4dce122a437 100644 --- a/llvm/test/CodeGen/PowerPC/memCmpUsedInZeroEqualityComparison.ll +++ b/llvm/test/CodeGen/PowerPC/memCmpUsedInZeroEqualityComparison.ll @@ -39,9 +39,8 @@ define signext i32 @zeroEqualityTest01(ptr %x, ptr %y) { ; CHECK-NEXT: lxvd2x 35, 0, 3 ; CHECK-NEXT: vcmpequb. 2, 3, 2 ; CHECK-NEXT: mfocrf 3, 2 +; CHECK-NEXT: not 3, 3 ; CHECK-NEXT: rlwinm 3, 3, 25, 31, 31 -; CHECK-NEXT: cntlzw 3, 3 -; CHECK-NEXT: srwi 3, 3, 5 ; CHECK-NEXT: blr %call = tail call signext i32 @memcmp(ptr %x, ptr %y, i64 16) %not.tobool = icmp ne i32 %call, 0