[SystemZ] Do not use glue to represent condition code dependencies
Currently, an instruction setting the condition code is linked to
the instruction using the condition code via a "glue" link in the
SelectionDAG. This has a number of drawbacks; in particular, it
means the same CC cannot be used by multiple users. It also makes
it more difficult to efficiently implement SADDO et. al.
This patch changes the back-end to represent CC dependencies as
normal values during SelectionDAG matching, along the lines of
how this is handled in the X86 back-end already.
In addition to the core mechanics of updating all relevant patterns,
this requires a number of additional changes:
- We now need to be able to spill/restore a CC value into a GPR
if necessary. This means providing a copyPhysReg implementation
for moves involving CC, and defining getCrossCopyRegClass.
- Since we still prefer to avoid such spills, we provide an override
for IsProfitableToFold to avoid creating a merged LOAD / ICMP if
this would result in multiple users of the CC.
- combineCCMask no longer requires a single CC user, and no longer
need to be careful about preventing invalid glue/chain cycles.
- emitSelect needs to be more careful in marking CC live-in to
the basic block it generates. Also, we can now optimize the
case of multiple subsequent selects with the same condition
just like X86 does.
llvm-svn: 331202
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 59dd46c..26af3f4 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -351,6 +351,7 @@
void Select(SDNode *Node) override;
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
std::vector<SDValue> &OutOps) override;
+ bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const override;
void PreprocessISelDAG() override;
// Include the pieces autogenerated from the target description.
@@ -1445,6 +1446,52 @@
return true;
}
+// IsProfitableToFold - Returns true if is profitable to fold the specific
+// operand node N of U during instruction selection that starts at Root.
+bool
+SystemZDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U,
+ SDNode *Root) const {
+ // We want to avoid folding a LOAD into an ICMP node if as a result
+ // we would be forced to spill the condition code into a GPR.
+ if (N.getOpcode() == ISD::LOAD && U->getOpcode() == SystemZISD::ICMP) {
+ if (!N.hasOneUse() || !U->hasOneUse())
+ return false;
+
+ // The user of the CC value will usually be a CopyToReg into the
+ // physical CC register, which in turn is glued and chained to the
+ // actual instruction that uses the CC value. Bail out if we have
+ // anything else than that.
+ SDNode *CCUser = *U->use_begin();
+ SDNode *CCRegUser = nullptr;
+ if (CCUser->getOpcode() == ISD::CopyToReg ||
+ cast<RegisterSDNode>(CCUser->getOperand(1))->getReg() == SystemZ::CC) {
+ for (auto *U : CCUser->uses()) {
+ if (CCRegUser == nullptr)
+ CCRegUser = U;
+ else if (CCRegUser != U)
+ return false;
+ }
+ }
+ if (CCRegUser == nullptr)
+ return false;
+
+ // If the actual instruction is a branch, the only thing that remains to be
+ // checked is whether the CCUser chain is a predecessor of the load.
+ if (CCRegUser->isMachineOpcode() &&
+ CCRegUser->getMachineOpcode() == SystemZ::BRC)
+ return !N->isPredecessorOf(CCUser->getOperand(0).getNode());
+
+ // Otherwise, the instruction may have multiple operands, and we need to
+ // verify that none of them are a predecessor of the load. This is exactly
+ // the same check that would be done by common code if the CC setter were
+ // glued to the CC user, so simply invoke that check here.
+ if (!IsLegalToFold(N, U, CCRegUser, OptLevel, false))
+ return false;
+ }
+
+ return true;
+}
+
namespace {
// Represents a sequence for extracting a 0/1 value from an IPM result:
// (((X ^ XORValue) + AddValue) >> Bit)
@@ -1543,9 +1590,9 @@
int CCMask = CCMaskOp->getZExtValue();
SDLoc DL(Node);
- SDValue Glue = Node->getOperand(4);
+ SDValue CCReg = Node->getOperand(4);
IPMConversion IPM = getIPMConversion(CCValid, CCMask);
- SDValue Result = CurDAG->getNode(SystemZISD::IPM, DL, MVT::i32, Glue);
+ SDValue Result = CurDAG->getNode(SystemZISD::IPM, DL, MVT::i32, CCReg);
if (IPM.XORValue)
Result = CurDAG->getNode(ISD::XOR, DL, MVT::i32, Result,