[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)
----------------
uweigand wrote:

Again those masks need to match the operation (ICMP vs. TM).

https://github.com/llvm/llvm-project/pull/125970


More information about the llvm-commits mailing list