Skip to content

Commit

Permalink
[SystemZ] Do not use glue to represent condition code dependencies
Browse files Browse the repository at this point in the history
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
  • Loading branch information
uweigand committed Apr 30, 2018
1 parent 2de9d4a commit b32f365
Show file tree
Hide file tree
Showing 15 changed files with 540 additions and 249 deletions.
51 changes: 49 additions & 2 deletions llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
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.
Expand Down Expand Up @@ -1445,6 +1446,52 @@ SelectInlineAsmMemoryOperand(const SDValue &Op,
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)
Expand Down Expand Up @@ -1543,9 +1590,9 @@ SDValue SystemZDAGToDAGISel::expandSelectBoolean(SDNode *Node) {
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,
Expand Down
Loading

0 comments on commit b32f365

Please sign in to comment.