[clang] [llvm] Add support for flag output operand "=@cc" for SystemZ. (PR #125970)
Ulrich Weigand via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 14 07:45:25 PDT 2025
================
@@ -8703,51 +8738,256 @@ SDValue SystemZTargetLowering::combineSETCC(
}
static bool combineCCMask(SDValue &CCReg, int &CCValid, int &CCMask) {
- // We have a SELECT_CCMASK or BR_CCMASK comparing the condition code
- // set by the CCReg instruction using the CCValid / CCMask masks,
- // If the CCReg instruction is itself a ICMP testing the condition
+ // CCMask for ICmp is equal to 0, 1, 2 or 3.
+ const auto CCMaskForICmpEQCCVal = [](unsigned CC) {
+ assert(CC < 4 && "CC out of range");
+ return 1 << (3 - CC);
+ };
+ // Convert CCVal to CCMask based on CCMask and update it.
+ const auto convertCCValToCCMask = [&](int CCVal) {
+ bool Invert = false;
+ if (CCMask == SystemZ::CCMASK_CMP_NE)
+ Invert = !Invert;
+ if (CCMask == SystemZ::CCMASK_CMP_EQ || CCMask == SystemZ::CCMASK_CMP_NE) {
+ CCMask = CCMaskForICmpEQCCVal(CCVal);
+ if (Invert)
+ CCMask ^= SystemZ::CCMASK_ANY;
+ return true;
+ } else if (CCMask == SystemZ::CCMASK_CMP_LT) {
+ // CC in range [0, CCVal).
+ CCMask = ((~0U << (4 - CCVal)) & SystemZ::CCMASK_ANY);
+ return true;
+ } else if (CCMask == SystemZ::CCMASK_CMP_GT) {
+ // CC in range (CCVal, 3].
+ CCMask = (~(~0U << (3 - CCVal))) & SystemZ::CCMASK_ANY;
+ return true;
+ }
+ return false;
+ };
+ // Check (SRL (IPM (CC))) and update CCReg to combine.
+ const auto isSRL_IPM_CCSequence = [&CCReg](SDNode *N) {
+ if (!N || N->getOpcode() != ISD::SRL)
+ return false;
+ auto *SRLCount = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (!SRLCount || SRLCount->getZExtValue() != SystemZ::IPM_CC)
+ return false;
+ auto *IPM = N->getOperand(0).getNode();
+ if (!IPM || IPM->getOpcode() != SystemZISD::IPM)
+ return false;
+ CCReg = IPM->getOperand(0);
+ return true;
+ };
+ const auto isOneBitSet = [](int Mask) {
+ return Mask && !(Mask & (Mask - 1));
+ };
+
+ // Only one-bit set.
+ const auto log2CCMaskToCCVal = [](int Mask) {
+ size_t Pos = 0;
+ while (!(Mask & 1)) {
+ Mask >>= 1;
+ ++Pos;
+ };
+ assert(Pos < 4 && "CC out of range");
+ return (3 - Pos);
+ };
+
+ auto *CCNode = CCReg.getNode();
+ if (!CCNode)
+ return false;
+
+ // Optimize (TM (IPM (CC)))
+ if (CCNode->getOpcode() == SystemZISD::TM) {
+ bool Invert = false;
+ if (CCValid != SystemZ::CCMASK_TM)
+ return false;
+ if (CCMask == SystemZ::CCMASK_TM_SOME_1)
+ Invert = !Invert;
+ else if (CCMask != SystemZ::CCMASK_TM_ALL_0)
+ return false;
+ auto *N = CCNode->getOperand(0).getNode();
+ auto *TMOp1Const = dyn_cast<ConstantSDNode>(CCNode->getOperand(1));
+ if (!N || !TMOp1Const)
+ return false;
+ auto TMConstVal = TMOp1Const->getZExtValue();
+ if (N->getOpcode() == SystemZISD::IPM) {
+ if (TMConstVal == (1 << SystemZ::IPM_CC))
+ CCMask = SystemZ::CCMASK_CMP_GE;
+ else if (TMConstVal == (1 << (SystemZ::IPM_CC + 1)))
+ CCMask = SystemZ::CCMASK_CMP_LE;
+ else
+ return false;
+ if (Invert)
+ CCMask ^= CCValid;
+ // Return the updated CCReg link.
+ CCReg = N->getOperand(0);
+ return true;
+ }
+ }
+
+ // Rest of the code has sequence starting with opcode SystemZISD::ICMP.
+ // or SystemZISD::TM. We have a SELECT_CCMASK or BR_CCMASK comparing the
+ // condition code set by the CCReg instruction using the CCValid / CCMask
+ // masks, If the CCReg instruction is itself a ICMP testing the condition
// code set by some other instruction, see whether we can directly
// use that condition code.
// Verify that we have an ICMP against some constant.
- if (CCValid != SystemZ::CCMASK_ICMP)
+ if (CCValid != SystemZ::CCMASK_ICMP && CCValid != SystemZ::CCMASK_TM)
return false;
- auto *ICmp = CCReg.getNode();
- if (ICmp->getOpcode() != SystemZISD::ICMP)
+ if (CCNode->getOpcode() != SystemZISD::ICMP &&
+ CCNode->getOpcode() != SystemZISD::TM)
return false;
- auto *CompareLHS = ICmp->getOperand(0).getNode();
- auto *CompareRHS = dyn_cast<ConstantSDNode>(ICmp->getOperand(1));
+ auto *CompareLHS = CCNode->getOperand(0).getNode();
+ auto *CompareRHS = dyn_cast<ConstantSDNode>(CCNode->getOperand(1));
if (!CompareRHS)
return false;
+ // Optimize (ICMP (SRL (IPM))).
+ int CmpVal = CompareRHS->getZExtValue();
+ if (isSRL_IPM_CCSequence(CompareLHS)) {
+ if (convertCCValToCCMask(CmpVal)) {
+ CCValid = SystemZ::CCMASK_ANY;
+ return true;
+ }
+ return false;
+ }
+
+ // Optimize (ICMP (OR (SRL (IPM (CC))))).
+ // t24: i32 = or disjoint t21, Constant:i32<-4>
+ // t40: i32 = SystemZISD::ICMP t24, Constant:i32<-2>, TargetConstant:i32<1>
+ if (CompareLHS->getOpcode() == ISD::OR) {
+ SDValue OrOp0 = CompareLHS->getOperand(0);
+ SDValue OrOp1 = CompareLHS->getOperand(1);
+
+ // Op0 is (SRL (IPM (CC)). Op1 is const.
+ if (isSRL_IPM_CCSequence(OrOp0.getNode())) {
+ // Op1 is Constant:i32<-4>.
+ auto *OrConst = dyn_cast<ConstantSDNode>(OrOp1);
+ if (!OrConst || (OrConst->getZExtValue() & 0x3))
+ return false;
+
+ // Try combining and Compute effective CC mask.
+ // setullt -2 or inverted 'setugt -3' => CC != 2 && CC != 3.
+ CmpVal &= 0x3;
+ if (convertCCValToCCMask(CmpVal)) {
+ CCValid = SystemZ::CCMASK_ANY;
+ return true;
+ }
+ }
+ }
+
+ // Optimize (ICMP (ADD (SRL (IPM (CC))))).
+ if (CompareLHS->getOpcode() == ISD::ADD) {
+ if (isSRL_IPM_CCSequence(CompareLHS->getOperand(0).getNode())) {
+ // (unsigned)(CmpVal - 1) or (unsigned)(CmpVal - 3) Inverted.
+ // CmpVal <= 2 => CC == 1 || CC == 2.
+ // CmpVal <= 3 => CC == 1 || CC == 2 || CC == 3.
+ auto *AddConstOp = dyn_cast<ConstantSDNode>((CompareLHS->getOperand(1)));
+ int AddConst = AddConstOp->getZExtValue();
+ if ((AddConst != -1) && (AddConst != -3))
+ return false;
+ bool Invert = false;
+ if (CmpVal < 0) {
+ Invert = !Invert;
+ AddConst = AddConst & 0x3;
+ } else
+ AddConst = ~AddConst + 1;
+
+ // Try combining and Compute effective CC mask.
+ CmpVal &= 0x3;
+ CmpVal += AddConst;
+ if (convertCCValToCCMask(CmpVal)) {
+ // CCVal > 0.
+ CCMask ^= SystemZ::CCMASK_CMP_EQ;
+ if (Invert)
+ CCMask ^= SystemZ::CCMASK_ANY;
+ CCValid = SystemZ::CCMASK_ANY;
+ return true;
+ }
+ }
+ return false;
+ }
+
// Optimize the case where CompareLHS is a SELECT_CCMASK.
if (CompareLHS->getOpcode() == SystemZISD::SELECT_CCMASK) {
// Verify that we have an appropriate mask for a EQ or NE comparison.
bool Invert = false;
- if (CCMask == SystemZ::CCMASK_CMP_NE)
+ if (CCMask == SystemZ::CCMASK_CMP_NE || CCMask == SystemZ::CCMASK_TM_SOME_1)
Invert = !Invert;
- else if (CCMask != SystemZ::CCMASK_CMP_EQ)
+ else if (CCMask != SystemZ::CCMASK_CMP_EQ &&
+ CCMask != SystemZ::CCMASK_TM_ALL_0)
return false;
- // Verify that the ICMP compares against one of select values.
auto *TrueVal = dyn_cast<ConstantSDNode>(CompareLHS->getOperand(0));
- if (!TrueVal)
- return false;
auto *FalseVal = dyn_cast<ConstantSDNode>(CompareLHS->getOperand(1));
- if (!FalseVal)
- return false;
- if (CompareRHS->getAPIntValue() == FalseVal->getAPIntValue())
- Invert = !Invert;
- else if (CompareRHS->getAPIntValue() != TrueVal->getAPIntValue())
- return false;
-
// Compute the effective CC mask for the new branch or select.
auto *NewCCValid = dyn_cast<ConstantSDNode>(CompareLHS->getOperand(2));
auto *NewCCMask = dyn_cast<ConstantSDNode>(CompareLHS->getOperand(3));
if (!NewCCValid || !NewCCMask)
return false;
CCValid = NewCCValid->getZExtValue();
CCMask = NewCCMask->getZExtValue();
+ if (TrueVal && isSRL_IPM_CCSequence(CompareLHS->getOperand(1).getNode())) {
----------------
uweigand wrote:
It's really confusing how `CCReg` is treated as somewhat of a global variable here; it is implictly set by `isSRL_IPM_CCSequence`, which is overwritten below, and there's a check here to verify that the two values are the same ... that's probably correct as-is, but confusing and prone to errors with future modifications. I'd much prefer if `isSRL_IPM_CCSequence` would *not* modify `CCReg`.
https://github.com/llvm/llvm-project/pull/125970
More information about the llvm-commits
mailing list