summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp')
-rw-r--r--llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp51
1 files changed, 49 insertions, 2 deletions
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 59dd46c0697..26af3f4ebcc 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -351,6 +351,7 @@ public:
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 @@ 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)
@@ -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,
OpenPOWER on IntegriCloud