================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits