[clang] [llvm] Add support for flag output operand "=@cc" for SystemZ. (PR #125970)
Ulrich Weigand via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 25 07:30:34 PDT 2025
================
@@ -8694,66 +8726,455 @@ SDValue SystemZTargetLowering::combineSETCC(
return SDValue();
}
+// Combine IPM sequence for flag output operands.
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
- // 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)
- return false;
- auto *ICmp = CCReg.getNode();
- if (ICmp->getOpcode() != SystemZISD::ICMP)
+ // 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 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;
- auto *CompareLHS = ICmp->getOperand(0).getNode();
- auto *CompareRHS = dyn_cast<ConstantSDNode>(ICmp->getOperand(1));
- if (!CompareRHS)
+ };
+ // 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;
+ };
+ // Check if select_cc has already been combined and uses the same ipm/cc
+ // as CCOp and return evaluated mask CCMaskVal. (SELECT_CCMASK (CC)).
+ const auto isSameCCIPMOp = [](SDValue &CCOp, SDNode *N, int &CCValidVal,
+ int &CCMaskVal) {
+ if (!N || N->getOpcode() != SystemZISD::SELECT_CCMASK)
+ return false;
+ auto *CCValidNode = dyn_cast<ConstantSDNode>(N->getOperand(2));
+ auto *CCMaskNode = dyn_cast<ConstantSDNode>(N->getOperand(3));
+ if (!CCValidNode || !CCMaskNode)
+ return false;
+
+ CCValidVal = CCValidNode->getZExtValue();
+ // Already been combined.
+ if (CCValidVal != SystemZ::CCMASK_ANY)
+ return false;
+ CCMaskVal = CCMaskNode->getZExtValue();
+ SDValue CCRegOp = N->getOperand(4);
+ auto *CCOpNode = CCOp.getNode(), *CCRegOpNode = CCRegOp.getNode();
+ // Uses the same ipm/cc.
+ return CCOpNode && CCRegOpNode && CCOpNode == CCRegOpNode;
+ };
+ auto *CCNode = CCReg.getNode();
+ if (!CCNode)
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.
+ // Optimize (TM (IPM (CC)))
+ if (CCNode->getOpcode() == SystemZISD::TM) {
bool Invert = false;
- if (CCMask == SystemZ::CCMASK_CMP_NE)
+ if (CCMask == SystemZ::CCMASK_TM_SOME_1)
Invert = !Invert;
- else if (CCMask != SystemZ::CCMASK_CMP_EQ)
+ auto *N = CCNode->getOperand(0).getNode();
+ auto Shift = dyn_cast<ConstantSDNode>(CCNode->getOperand(1));
+ if (!N || !Shift)
return false;
-
- // Verify that the ICMP compares against one of select values.
- auto *TrueVal = dyn_cast<ConstantSDNode>(CompareLHS->getOperand(0));
- if (!TrueVal)
+ if (N->getOpcode() == SystemZISD::IPM) {
+ auto ShiftVal = Shift->getZExtValue();
+ if (ShiftVal == (1 << SystemZ::IPM_CC))
+ CCMask = SystemZ::CCMASK_CMP_GE;
+ if (Invert)
+ CCMask ^= CCValid;
+ // Return the updated CCReg link.
+ CCReg = N->getOperand(0);
+ return true;
+ } else if (N->getOpcode() == ISD::XOR) {
+ // Optimize (TM (XOR (OP1 OP2))).
+ auto *XOROp1 = N->getOperand(0).getNode();
+ auto *XOROp2 = N->getOperand(1).getNode();
+ if (!XOROp1 || !XOROp2)
+ return false;
+ // OP1. (SELECT_CCMASK (ICMP (SRL (IPM (CC))))).
+ // OP2. (SRL (IPM (CC))).
+ if (XOROp1->getOpcode() == SystemZISD::SELECT_CCMASK /*&&
+ isSRL_IPM_CCSequence(XOROp2)*/) {
+ auto *CCValid1 = dyn_cast<ConstantSDNode>(XOROp1->getOperand(2));
+ auto *CCMask1 = dyn_cast<ConstantSDNode>(XOROp1->getOperand(3));
+ SDValue XORReg = XOROp1->getOperand(4);
+ if (!CCValid1 || !CCMask1)
+ return false;
+ int CCValidVal = CCValid1->getZExtValue();
+ int CCMaskVal = CCMask1->getZExtValue();
+ if (combineCCMask(XORReg, CCValidVal, CCMaskVal)) {
+ // CC == 0 || CC == 2 for bit 28 Test Under Mask.
+ CCMask = SystemZ::CCMASK_CMP_GE;
+ CCMask ^= CCMaskVal;
+ if (Invert)
+ CCMask ^= CCValid;
+ CCReg = XORReg;
+ return true;
+ }
+ }
+ }
+ }
+ // Optimize (AND (SRL (IPM (CC)))).
+ if (CCNode->getOpcode() == ISD::AND) {
+ auto *N = CCNode->getOperand(0).getNode();
+ if (!isSRL_IPM_CCSequence(N))
return false;
- auto *FalseVal = dyn_cast<ConstantSDNode>(CompareLHS->getOperand(1));
- if (!FalseVal)
+ auto *ANDConst = dyn_cast<ConstantSDNode>(CCNode->getOperand(1));
+ if (!ANDConst)
return false;
- if (CompareRHS->getAPIntValue() == FalseVal->getAPIntValue())
- Invert = !Invert;
- else if (CompareRHS->getAPIntValue() != TrueVal->getAPIntValue())
+ // Bit 28 false (CC == 0) || (CC == 2).
+ // Caller can invert it depending on CCmask there.
+ if (ANDConst->getZExtValue() == 1) {
+ CCMask = SystemZ::CCMASK_0 | SystemZ::CCMASK_2;
+ CCValid = SystemZ::CCMASK_ANY;
+ return true;
+ }
+ return false;
+ }
+ // (SELECT_CCMASK (ICMP (SRL (IPM (CC)))))
+ if (CCNode->getOpcode() == SystemZISD::SELECT_CCMASK) {
----------------
uweigand wrote:
The same comment as above - SELECT_CCMASK (while at least a Z specific opcode) does not itself set the condition code (it *uses* it, of course), and so it cannot be an input to combineCCMask either.
https://github.com/llvm/llvm-project/pull/125970
More information about the cfe-commits
mailing list