diff options
Diffstat (limited to 'lib/Target/SystemZ/SystemZISelDAGToDAG.cpp')
-rw-r--r-- | lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 266 |
1 files changed, 170 insertions, 96 deletions
diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index a9093094d8849..cd7fcc3070a45 100644 --- a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -113,7 +113,8 @@ static uint64_t allOnes(unsigned int Count) { // (and (rotl Input, Rotate), Mask) // // otherwise. The output value has BitSize bits, although Input may be -// narrower (in which case the upper bits are don't care). +// narrower (in which case the upper bits are don't care), or wider (in which +// case the result will be truncated as part of the operation). struct RxSBGOperands { RxSBGOperands(unsigned Op, SDValue N) : Opcode(Op), BitSize(N.getValueType().getSizeInBits()), @@ -279,18 +280,18 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { bool expandRxSBG(RxSBGOperands &RxSBG) const; // Return an undefined value of type VT. - SDValue getUNDEF(SDLoc DL, EVT VT) const; + SDValue getUNDEF(const SDLoc &DL, EVT VT) const; // Convert N to VT, if it isn't already. - SDValue convertTo(SDLoc DL, EVT VT, SDValue N) const; + SDValue convertTo(const SDLoc &DL, EVT VT, SDValue N) const; // Try to implement AND or shift node N using RISBG with the zero flag set. // Return the selected node on success, otherwise return null. - SDNode *tryRISBGZero(SDNode *N); + bool tryRISBGZero(SDNode *N); // Try to use RISBG or Opcode to implement OR or XOR node N. // Return the selected node on success, otherwise return null. - SDNode *tryRxSBG(SDNode *N, unsigned Opcode); + bool tryRxSBG(SDNode *N, unsigned Opcode); // If Op0 is null, then Node is a constant that can be loaded using: // @@ -299,14 +300,14 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { // If Op0 is nonnull, then Node can be implemented using: // // (Opcode (Opcode Op0 UpperVal) LowerVal) - SDNode *splitLargeImmediate(unsigned Opcode, SDNode *Node, SDValue Op0, - uint64_t UpperVal, uint64_t LowerVal); + void splitLargeImmediate(unsigned Opcode, SDNode *Node, SDValue Op0, + uint64_t UpperVal, uint64_t LowerVal); // Try to use gather instruction Opcode to implement vector insertion N. - SDNode *tryGather(SDNode *N, unsigned Opcode); + bool tryGather(SDNode *N, unsigned Opcode); // Try to use scatter instruction Opcode to implement store Store. - SDNode *tryScatter(StoreSDNode *Store, unsigned Opcode); + bool tryScatter(StoreSDNode *Store, unsigned Opcode); // Return true if Load and Store are loads and stores of the same size // and are guaranteed not to overlap. Such operations can be implemented @@ -343,7 +344,7 @@ public: } // Override SelectionDAGISel. - SDNode *Select(SDNode *Node) override; + void Select(SDNode *Node) override; bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) override; @@ -554,6 +555,10 @@ bool SystemZDAGToDAGISel::selectAddress(SDValue Addr, expandDisp(AM, true, SDValue(), cast<ConstantSDNode>(Addr)->getSExtValue())) ; + // Also see if it's a bare ADJDYNALLOC. + else if (Addr.getOpcode() == SystemZISD::ADJDYNALLOC && + expandAdjDynAlloc(AM, true, SDValue())) + ; else // Otherwise try expanding each component. while (expandAddress(AM, true) || @@ -741,6 +746,16 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const { SDValue N = RxSBG.Input; unsigned Opcode = N.getOpcode(); switch (Opcode) { + case ISD::TRUNCATE: { + if (RxSBG.Opcode == SystemZ::RNSBG) + return false; + uint64_t BitSize = N.getValueType().getSizeInBits(); + uint64_t Mask = allOnes(BitSize); + if (!refineRxSBGMask(RxSBG, Mask)) + return false; + RxSBG.Input = N.getOperand(0); + return true; + } case ISD::AND: { if (RxSBG.Opcode == SystemZ::RNSBG) return false; @@ -888,12 +903,13 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const { } } -SDValue SystemZDAGToDAGISel::getUNDEF(SDLoc DL, EVT VT) const { +SDValue SystemZDAGToDAGISel::getUNDEF(const SDLoc &DL, EVT VT) const { SDNode *N = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT); return SDValue(N, 0); } -SDValue SystemZDAGToDAGISel::convertTo(SDLoc DL, EVT VT, SDValue N) const { +SDValue SystemZDAGToDAGISel::convertTo(const SDLoc &DL, EVT VT, + SDValue N) const { if (N.getValueType() == MVT::i32 && VT == MVT::i64) return CurDAG->getTargetInsertSubreg(SystemZ::subreg_l32, DL, VT, getUNDEF(DL, MVT::i64), N); @@ -903,23 +919,27 @@ SDValue SystemZDAGToDAGISel::convertTo(SDLoc DL, EVT VT, SDValue N) const { return N; } -SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { +bool SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { SDLoc DL(N); EVT VT = N->getValueType(0); if (!VT.isInteger() || VT.getSizeInBits() > 64) - return nullptr; + return false; RxSBGOperands RISBG(SystemZ::RISBG, SDValue(N, 0)); unsigned Count = 0; while (expandRxSBG(RISBG)) - if (RISBG.Input.getOpcode() != ISD::ANY_EXTEND) + // The widening or narrowing is expected to be free. + // Counting widening or narrowing as a saved operation will result in + // preferring an R*SBG over a simple shift/logical instruction. + if (RISBG.Input.getOpcode() != ISD::ANY_EXTEND && + RISBG.Input.getOpcode() != ISD::TRUNCATE) Count += 1; if (Count == 0) - return nullptr; + return false; if (Count == 1) { // Prefer to use normal shift instructions over RISBG, since they can handle // all cases and are sometimes shorter. if (N->getOpcode() != ISD::AND) - return nullptr; + return false; // Prefer register extensions like LLC over RISBG. Also prefer to start // out with normal ANDs if one instruction would be enough. We can convert @@ -934,9 +954,10 @@ SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { if (MaskN->getZExtValue() != RISBG.Mask) { SDValue NewMask = CurDAG->getConstant(RISBG.Mask, DL, VT); N = CurDAG->UpdateNodeOperands(N, N->getOperand(0), NewMask); - return SelectCode(N); + SelectCode(N); + return true; } - return nullptr; + return false; } } @@ -952,8 +973,11 @@ SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { } SDValue In = convertTo(DL, VT, RISBG.Input); - N = CurDAG->getMachineNode(OpCode, DL, VT, In); - return convertTo(DL, VT, SDValue(N, 0)).getNode(); + SDValue New = convertTo( + DL, VT, SDValue(CurDAG->getMachineNode(OpCode, DL, VT, In), 0)); + ReplaceUses(N, New.getNode()); + CurDAG->RemoveDeadNode(N); + return true; } unsigned Opcode = SystemZ::RISBG; @@ -974,15 +998,18 @@ SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { CurDAG->getTargetConstant(RISBG.End | 128, DL, MVT::i32), CurDAG->getTargetConstant(RISBG.Rotate, DL, MVT::i32) }; - N = CurDAG->getMachineNode(Opcode, DL, OpcodeVT, Ops); - return convertTo(DL, VT, SDValue(N, 0)).getNode(); + SDValue New = convertTo( + DL, VT, SDValue(CurDAG->getMachineNode(Opcode, DL, OpcodeVT, Ops), 0)); + ReplaceUses(N, New.getNode()); + CurDAG->RemoveDeadNode(N); + return true; } -SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { +bool SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { SDLoc DL(N); EVT VT = N->getValueType(0); if (!VT.isInteger() || VT.getSizeInBits() > 64) - return nullptr; + return false; // Try treating each operand of N as the second operand of the RxSBG // and see which goes deepest. RxSBGOperands RxSBG[] = { @@ -992,12 +1019,16 @@ SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { unsigned Count[] = { 0, 0 }; for (unsigned I = 0; I < 2; ++I) while (expandRxSBG(RxSBG[I])) - if (RxSBG[I].Input.getOpcode() != ISD::ANY_EXTEND) + // The widening or narrowing is expected to be free. + // Counting widening or narrowing as a saved operation will result in + // preferring an R*SBG over a simple shift/logical instruction. + if (RxSBG[I].Input.getOpcode() != ISD::ANY_EXTEND && + RxSBG[I].Input.getOpcode() != ISD::TRUNCATE) Count[I] += 1; // Do nothing if neither operand is suitable. if (Count[0] == 0 && Count[1] == 0) - return nullptr; + return false; // Pick the deepest second operand. unsigned I = Count[0] > Count[1] ? 0 : 1; @@ -1007,7 +1038,7 @@ SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { if (Opcode == SystemZ::ROSBG && (RxSBG[I].Mask & 0xff) == 0) if (auto *Load = dyn_cast<LoadSDNode>(Op0.getNode())) if (Load->getMemoryVT() == MVT::i8) - return nullptr; + return false; // See whether we can avoid an AND in the first operand by converting // ROSBG to RISBG. @@ -1025,47 +1056,70 @@ SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { CurDAG->getTargetConstant(RxSBG[I].End, DL, MVT::i32), CurDAG->getTargetConstant(RxSBG[I].Rotate, DL, MVT::i32) }; - N = CurDAG->getMachineNode(Opcode, DL, MVT::i64, Ops); - return convertTo(DL, VT, SDValue(N, 0)).getNode(); + SDValue New = convertTo( + DL, VT, SDValue(CurDAG->getMachineNode(Opcode, DL, MVT::i64, Ops), 0)); + ReplaceNode(N, New.getNode()); + return true; } -SDNode *SystemZDAGToDAGISel::splitLargeImmediate(unsigned Opcode, SDNode *Node, - SDValue Op0, uint64_t UpperVal, - uint64_t LowerVal) { +void SystemZDAGToDAGISel::splitLargeImmediate(unsigned Opcode, SDNode *Node, + SDValue Op0, uint64_t UpperVal, + uint64_t LowerVal) { EVT VT = Node->getValueType(0); SDLoc DL(Node); SDValue Upper = CurDAG->getConstant(UpperVal, DL, VT); if (Op0.getNode()) Upper = CurDAG->getNode(Opcode, DL, VT, Op0, Upper); - Upper = SDValue(Select(Upper.getNode()), 0); + + { + // When we haven't passed in Op0, Upper will be a constant. In order to + // prevent folding back to the large immediate in `Or = getNode(...)` we run + // SelectCode first and end up with an opaque machine node. This means that + // we need to use a handle to keep track of Upper in case it gets CSE'd by + // SelectCode. + // + // Note that in the case where Op0 is passed in we could just call + // SelectCode(Upper) later, along with the SelectCode(Or), and avoid needing + // the handle at all, but it's fine to do it here. + // + // TODO: This is a pretty hacky way to do this. Can we do something that + // doesn't require a two paragraph explanation? + HandleSDNode Handle(Upper); + SelectCode(Upper.getNode()); + Upper = Handle.getValue(); + } SDValue Lower = CurDAG->getConstant(LowerVal, DL, VT); SDValue Or = CurDAG->getNode(Opcode, DL, VT, Upper, Lower); - return Or.getNode(); + + ReplaceUses(Node, Or.getNode()); + CurDAG->RemoveDeadNode(Node); + + SelectCode(Or.getNode()); } -SDNode *SystemZDAGToDAGISel::tryGather(SDNode *N, unsigned Opcode) { +bool SystemZDAGToDAGISel::tryGather(SDNode *N, unsigned Opcode) { SDValue ElemV = N->getOperand(2); auto *ElemN = dyn_cast<ConstantSDNode>(ElemV); if (!ElemN) - return 0; + return false; unsigned Elem = ElemN->getZExtValue(); EVT VT = N->getValueType(0); if (Elem >= VT.getVectorNumElements()) - return 0; + return false; auto *Load = dyn_cast<LoadSDNode>(N->getOperand(1)); if (!Load || !Load->hasOneUse()) - return 0; + return false; if (Load->getMemoryVT().getSizeInBits() != Load->getValueType(0).getSizeInBits()) - return 0; + return false; SDValue Base, Disp, Index; if (!selectBDVAddr12Only(Load->getBasePtr(), ElemV, Base, Disp, Index) || Index.getValueType() != VT.changeVectorElementTypeToInteger()) - return 0; + return false; SDLoc DL(Load); SDValue Ops[] = { @@ -1074,39 +1128,41 @@ SDNode *SystemZDAGToDAGISel::tryGather(SDNode *N, unsigned Opcode) { }; SDNode *Res = CurDAG->getMachineNode(Opcode, DL, VT, MVT::Other, Ops); ReplaceUses(SDValue(Load, 1), SDValue(Res, 1)); - return Res; + ReplaceNode(N, Res); + return true; } -SDNode *SystemZDAGToDAGISel::tryScatter(StoreSDNode *Store, unsigned Opcode) { +bool SystemZDAGToDAGISel::tryScatter(StoreSDNode *Store, unsigned Opcode) { SDValue Value = Store->getValue(); if (Value.getOpcode() != ISD::EXTRACT_VECTOR_ELT) - return 0; + return false; if (Store->getMemoryVT().getSizeInBits() != Value.getValueType().getSizeInBits()) - return 0; + return false; SDValue ElemV = Value.getOperand(1); auto *ElemN = dyn_cast<ConstantSDNode>(ElemV); if (!ElemN) - return 0; + return false; SDValue Vec = Value.getOperand(0); EVT VT = Vec.getValueType(); unsigned Elem = ElemN->getZExtValue(); if (Elem >= VT.getVectorNumElements()) - return 0; + return false; SDValue Base, Disp, Index; if (!selectBDVAddr12Only(Store->getBasePtr(), ElemV, Base, Disp, Index) || Index.getValueType() != VT.changeVectorElementTypeToInteger()) - return 0; + return false; SDLoc DL(Store); SDValue Ops[] = { Vec, Base, Disp, Index, CurDAG->getTargetConstant(Elem, DL, MVT::i32), Store->getChain() }; - return CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops); + ReplaceNode(Store, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops)); + return true; } bool SystemZDAGToDAGISel::canUseBlockOperation(StoreSDNode *Store, @@ -1167,7 +1223,7 @@ bool SystemZDAGToDAGISel::storeLoadCanUseBlockBinary(SDNode *N, return !LoadA->isVolatile() && canUseBlockOperation(StoreA, LoadB); } -SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { +void SystemZDAGToDAGISel::Select(SDNode *Node) { // Dump information about the Node being selected DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); @@ -1175,43 +1231,47 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { if (Node->isMachineOpcode()) { DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); Node->setNodeId(-1); - return nullptr; + return; } unsigned Opcode = Node->getOpcode(); - SDNode *ResNode = nullptr; switch (Opcode) { case ISD::OR: if (Node->getOperand(1).getOpcode() != ISD::Constant) - ResNode = tryRxSBG(Node, SystemZ::ROSBG); + if (tryRxSBG(Node, SystemZ::ROSBG)) + return; goto or_xor; case ISD::XOR: if (Node->getOperand(1).getOpcode() != ISD::Constant) - ResNode = tryRxSBG(Node, SystemZ::RXSBG); + if (tryRxSBG(Node, SystemZ::RXSBG)) + return; // Fall through. or_xor: // If this is a 64-bit operation in which both 32-bit halves are nonzero, // split the operation into two. - if (!ResNode && Node->getValueType(0) == MVT::i64) + if (Node->getValueType(0) == MVT::i64) if (auto *Op1 = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { uint64_t Val = Op1->getZExtValue(); - if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val)) - Node = splitLargeImmediate(Opcode, Node, Node->getOperand(0), - Val - uint32_t(Val), uint32_t(Val)); + if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val)) { + splitLargeImmediate(Opcode, Node, Node->getOperand(0), + Val - uint32_t(Val), uint32_t(Val)); + return; + } } break; case ISD::AND: if (Node->getOperand(1).getOpcode() != ISD::Constant) - ResNode = tryRxSBG(Node, SystemZ::RNSBG); + if (tryRxSBG(Node, SystemZ::RNSBG)) + return; // Fall through. case ISD::ROTL: case ISD::SHL: case ISD::SRL: case ISD::ZERO_EXTEND: - if (!ResNode) - ResNode = tryRISBGZero(Node); + if (tryRISBGZero(Node)) + return; break; case ISD::Constant: @@ -1219,9 +1279,11 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { // LLIHF and LGFI, split it into two 32-bit pieces. if (Node->getValueType(0) == MVT::i64) { uint64_t Val = cast<ConstantSDNode>(Node)->getZExtValue(); - if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val) && !isInt<32>(Val)) - Node = splitLargeImmediate(ISD::OR, Node, SDValue(), - Val - uint32_t(Val), uint32_t(Val)); + if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val) && !isInt<32>(Val)) { + splitLargeImmediate(ISD::OR, Node, SDValue(), Val - uint32_t(Val), + uint32_t(Val)); + return; + } } break; @@ -1249,63 +1311,75 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { case ISD::INSERT_VECTOR_ELT: { EVT VT = Node->getValueType(0); unsigned ElemBitSize = VT.getVectorElementType().getSizeInBits(); - if (ElemBitSize == 32) - ResNode = tryGather(Node, SystemZ::VGEF); - else if (ElemBitSize == 64) - ResNode = tryGather(Node, SystemZ::VGEG); + if (ElemBitSize == 32) { + if (tryGather(Node, SystemZ::VGEF)) + return; + } else if (ElemBitSize == 64) { + if (tryGather(Node, SystemZ::VGEG)) + return; + } break; } case ISD::STORE: { auto *Store = cast<StoreSDNode>(Node); unsigned ElemBitSize = Store->getValue().getValueType().getSizeInBits(); - if (ElemBitSize == 32) - ResNode = tryScatter(Store, SystemZ::VSCEF); - else if (ElemBitSize == 64) - ResNode = tryScatter(Store, SystemZ::VSCEG); + if (ElemBitSize == 32) { + if (tryScatter(Store, SystemZ::VSCEF)) + return; + } else if (ElemBitSize == 64) { + if (tryScatter(Store, SystemZ::VSCEG)) + return; + } break; } } - // Select the default instruction - if (!ResNode) - ResNode = SelectCode(Node); - - DEBUG(errs() << "=> "; - if (ResNode == nullptr || ResNode == Node) - Node->dump(CurDAG); - else - ResNode->dump(CurDAG); - errs() << "\n"; - ); - return ResNode; + SelectCode(Node); } bool SystemZDAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { + SystemZAddressingMode::AddrForm Form; + SystemZAddressingMode::DispRange DispRange; + SDValue Base, Disp, Index; + switch(ConstraintID) { default: llvm_unreachable("Unexpected asm memory constraint"); case InlineAsm::Constraint_i: - case InlineAsm::Constraint_m: case InlineAsm::Constraint_Q: + // Accept an address with a short displacement, but no index. + Form = SystemZAddressingMode::FormBD; + DispRange = SystemZAddressingMode::Disp12Only; + break; case InlineAsm::Constraint_R: + // Accept an address with a short displacement and an index. + Form = SystemZAddressingMode::FormBDXNormal; + DispRange = SystemZAddressingMode::Disp12Only; + break; case InlineAsm::Constraint_S: + // Accept an address with a long displacement, but no index. + Form = SystemZAddressingMode::FormBD; + DispRange = SystemZAddressingMode::Disp20Only; + break; case InlineAsm::Constraint_T: - // Accept addresses with short displacements, which are compatible - // with Q, R, S and T. But keep the index operand for future expansion. - SDValue Base, Disp, Index; - if (selectBDXAddr(SystemZAddressingMode::FormBD, - SystemZAddressingMode::Disp12Only, - Op, Base, Disp, Index)) { - OutOps.push_back(Base); - OutOps.push_back(Disp); - OutOps.push_back(Index); - return false; - } + case InlineAsm::Constraint_m: + // Accept an address with a long displacement and an index. + // m works the same as T, as this is the most general case. + Form = SystemZAddressingMode::FormBDXNormal; + DispRange = SystemZAddressingMode::Disp20Only; break; } + + if (selectBDXAddr(Form, DispRange, Op, Base, Disp, Index)) { + OutOps.push_back(Base); + OutOps.push_back(Disp); + OutOps.push_back(Index); + return false; + } + return true; } |