X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FSystemZ%2FSystemZISelDAGToDAG.cpp;h=2e77855d932d051db1b37bbae756e31757d2a01e;hb=2c7c54c86c0619a0d3b9e22a6990b075fd174529;hp=f5d5e5a5cc6d7f273990eb250ef3c7d852448f51;hpb=de25544a73acbb1dd99c948ccbea81eedcd34bc9;p=oota-llvm.git diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index f5d5e5a5cc6..2e77855d932 100644 --- a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -19,6 +19,8 @@ using namespace llvm; +#define DEBUG_TYPE "systemz-isel" + namespace { // Used to build addressing modes. struct SystemZAddressingMode { @@ -72,14 +74,14 @@ struct SystemZAddressingMode { errs() << "SystemZAddressingMode " << this << '\n'; errs() << " Base "; - if (Base.getNode() != 0) + if (Base.getNode()) Base.getNode()->dump(); else errs() << "null\n"; if (hasIndexField()) { errs() << " Index "; - if (Index.getNode() != 0) + if (Index.getNode()) Index.getNode()->dump(); else errs() << "null\n"; @@ -97,15 +99,25 @@ static uint64_t allOnes(unsigned int Count) { return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1; } -// Represents operands 2 to 5 of a ROTATE AND ... SELECTED BITS operation. -// The operands are: Input (R2), Start (I3), End (I4) and Rotate (I5). -// The operand value is effectively (and (rotl Input Rotate) Mask) and -// has BitSize bits. -struct RISBGOperands { - RISBGOperands(SDValue N) - : BitSize(N.getValueType().getSizeInBits()), Mask(allOnes(BitSize)), - Input(N), Start(64 - BitSize), End(63), Rotate(0) {} - +// Represents operands 2 to 5 of the ROTATE AND ... SELECTED BITS operation +// given by Opcode. The operands are: Input (R2), Start (I3), End (I4) and +// Rotate (I5). The combined operand value is effectively: +// +// (or (rotl Input, Rotate), ~Mask) +// +// for RNSBG and: +// +// (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). +struct RxSBGOperands { + RxSBGOperands(unsigned Op, SDValue N) + : Opcode(Op), BitSize(N.getValueType().getSizeInBits()), + Mask(allOnes(BitSize)), Input(N), Start(64 - BitSize), End(63), + Rotate(0) {} + + unsigned Opcode; unsigned BitSize; uint64_t Mask; SDValue Input; @@ -119,39 +131,53 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { const SystemZSubtarget &Subtarget; // Used by SystemZOperands.td to create integer constants. - inline SDValue getImm(const SDNode *Node, uint64_t Imm) { + inline SDValue getImm(const SDNode *Node, uint64_t Imm) const { return CurDAG->getTargetConstant(Imm, Node->getValueType(0)); } + const SystemZTargetMachine &getTargetMachine() const { + return static_cast(TM); + } + + const SystemZInstrInfo *getInstrInfo() const { + return getTargetMachine().getInstrInfo(); + } + // Try to fold more of the base or index of AM into AM, where IsBase // selects between the base and index. - bool expandAddress(SystemZAddressingMode &AM, bool IsBase); + bool expandAddress(SystemZAddressingMode &AM, bool IsBase) const; // Try to describe N in AM, returning true on success. - bool selectAddress(SDValue N, SystemZAddressingMode &AM); + bool selectAddress(SDValue N, SystemZAddressingMode &AM) const; // Extract individual target operands from matched address AM. void getAddressOperands(const SystemZAddressingMode &AM, EVT VT, - SDValue &Base, SDValue &Disp); + SDValue &Base, SDValue &Disp) const; void getAddressOperands(const SystemZAddressingMode &AM, EVT VT, - SDValue &Base, SDValue &Disp, SDValue &Index); + SDValue &Base, SDValue &Disp, SDValue &Index) const; // Try to match Addr as a FormBD address with displacement type DR. // Return true on success, storing the base and displacement in // Base and Disp respectively. bool selectBDAddr(SystemZAddressingMode::DispRange DR, SDValue Addr, - SDValue &Base, SDValue &Disp); + SDValue &Base, SDValue &Disp) const; + + // Try to match Addr as a FormBDX address with displacement type DR. + // Return true on success and if the result had no index. Store the + // base and displacement in Base and Disp respectively. + bool selectMVIAddr(SystemZAddressingMode::DispRange DR, SDValue Addr, + SDValue &Base, SDValue &Disp) const; // Try to match Addr as a FormBDX* address of form Form with // displacement type DR. Return true on success, storing the base, // displacement and index in Base, Disp and Index respectively. bool selectBDXAddr(SystemZAddressingMode::AddrForm Form, SystemZAddressingMode::DispRange DR, SDValue Addr, - SDValue &Base, SDValue &Disp, SDValue &Index); + SDValue &Base, SDValue &Disp, SDValue &Index) const; // PC-relative address matching routines used by SystemZOperands.td. - bool selectPCRelAddress(SDValue Addr, SDValue &Target) { - if (Addr.getOpcode() == SystemZISD::PCREL_WRAPPER) { + bool selectPCRelAddress(SDValue Addr, SDValue &Target) const { + if (SystemZISD::isPCREL(Addr.getOpcode())) { Target = Addr.getOperand(0); return true; } @@ -159,64 +185,72 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { } // BD matching routines used by SystemZOperands.td. - bool selectBDAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp) { + bool selectBDAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp) const { return selectBDAddr(SystemZAddressingMode::Disp12Only, Addr, Base, Disp); } - bool selectBDAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) { + bool selectBDAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const { return selectBDAddr(SystemZAddressingMode::Disp12Pair, Addr, Base, Disp); } - bool selectBDAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp) { + bool selectBDAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp) const { return selectBDAddr(SystemZAddressingMode::Disp20Only, Addr, Base, Disp); } - bool selectBDAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) { + bool selectBDAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const { return selectBDAddr(SystemZAddressingMode::Disp20Pair, Addr, Base, Disp); } + // MVI matching routines used by SystemZOperands.td. + bool selectMVIAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const { + return selectMVIAddr(SystemZAddressingMode::Disp12Pair, Addr, Base, Disp); + } + bool selectMVIAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp) const { + return selectMVIAddr(SystemZAddressingMode::Disp20Pair, Addr, Base, Disp); + } + // BDX matching routines used by SystemZOperands.td. bool selectBDXAddr12Only(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, SystemZAddressingMode::Disp12Only, Addr, Base, Disp, Index); } bool selectBDXAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, SystemZAddressingMode::Disp12Pair, Addr, Base, Disp, Index); } bool selectDynAlloc12Only(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXDynAlloc, SystemZAddressingMode::Disp12Only, Addr, Base, Disp, Index); } bool selectBDXAddr20Only(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, SystemZAddressingMode::Disp20Only, Addr, Base, Disp, Index); } bool selectBDXAddr20Only128(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, SystemZAddressingMode::Disp20Only128, Addr, Base, Disp, Index); } bool selectBDXAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXNormal, SystemZAddressingMode::Disp20Pair, Addr, Base, Disp, Index); } bool selectLAAddr12Pair(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXLA, SystemZAddressingMode::Disp12Pair, Addr, Base, Disp, Index); } bool selectLAAddr20Pair(SDValue Addr, SDValue &Base, SDValue &Disp, - SDValue &Index) { + SDValue &Index) const { return selectBDXAddr(SystemZAddressingMode::FormBDXLA, SystemZAddressingMode::Disp20Pair, Addr, Base, Disp, Index); @@ -225,25 +259,29 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { // Check whether (or Op (and X InsertMask)) is effectively an insertion // of X into bits InsertMask of some Y != Op. Return true if so and // set Op to that Y. - bool detectOrAndInsertion(SDValue &Op, uint64_t InsertMask); + bool detectOrAndInsertion(SDValue &Op, uint64_t InsertMask) const; - // Try to fold some of Ops.Input into other fields of Ops. Return true - // on success. - bool expandRISBG(RISBGOperands &Ops); + // Try to update RxSBG so that only the bits of RxSBG.Input in Mask are used. + // Return true on success. + bool refineRxSBGMask(RxSBGOperands &RxSBG, uint64_t Mask) const; - // Return an undefined i64 value. - SDValue getUNDEF64(SDLoc DL); + // Try to fold some of RxSBG.Input into other fields of RxSBG. + // Return true on success. + bool expandRxSBG(RxSBGOperands &RxSBG) const; + + // Return an undefined value of type VT. + SDValue getUNDEF(SDLoc DL, EVT VT) const; // Convert N to VT, if it isn't already. - SDValue convertTo(SDLoc DL, EVT VT, SDValue N); + SDValue convertTo(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); - // Try to use RISBG or ROSBG to implement OR node N. Return the selected - // node on success, otherwise return null. - SDNode *tryRISBGOrROSBG(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); // If Op0 is null, then Node is a constant that can be loaded using: // @@ -255,8 +293,26 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { SDNode *splitLargeImmediate(unsigned Opcode, SDNode *Node, SDValue Op0, uint64_t UpperVal, uint64_t LowerVal); + // 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 + // using block (SS-format) instructions. + // + // Partial overlap would lead to incorrect code, since the block operations + // are logically bytewise, even though they have a fast path for the + // non-overlapping case. We also need to avoid full overlap (i.e. two + // addresses that might be equal at run time) because although that case + // would be handled correctly, it might be implemented by millicode. + bool canUseBlockOperation(StoreSDNode *Store, LoadSDNode *Load) const; + + // N is a (store (load Y), X) pattern. Return true if it can use an MVC + // from Y to X. bool storeLoadCanUseMVC(SDNode *N) const; + // N is a (store (op (load A[0]), (load A[1])), X) pattern. Return true + // if A[1 - I] == X and if N can use a block operation like NC from A[I] + // to X. + bool storeLoadCanUseBlockBinary(SDNode *N, unsigned I) const; + public: SystemZDAGToDAGISel(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel) : SelectionDAGISel(TM, OptLevel), @@ -264,16 +320,14 @@ public: Subtarget(*TM.getSubtargetImpl()) { } // Override MachineFunctionPass. - virtual const char *getPassName() const LLVM_OVERRIDE { + const char *getPassName() const override { return "SystemZ DAG->DAG Pattern Instruction Selection"; } // Override SelectionDAGISel. - virtual SDNode *Select(SDNode *Node) LLVM_OVERRIDE; - virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, - std::vector &OutOps) - LLVM_OVERRIDE; + SDNode *Select(SDNode *Node) override; + bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector &OutOps) override; // Include the pieces autogenerated from the target description. #include "SystemZGenDAGISel.inc" @@ -342,9 +396,9 @@ static bool expandIndex(SystemZAddressingMode &AM, SDValue Base, // The base or index of AM is equivalent to Op0 + Op1, where IsBase selects // between the base and index. Try to fold Op1 into AM's displacement. static bool expandDisp(SystemZAddressingMode &AM, bool IsBase, - SDValue Op0, ConstantSDNode *Op1) { + SDValue Op0, uint64_t Op1) { // First try adjusting the displacement. - int64_t TestDisp = AM.Disp + Op1->getSExtValue(); + int64_t TestDisp = AM.Disp + Op1; if (selectDisp(AM.DR, TestDisp)) { changeComponent(AM, IsBase, Op0); AM.Disp = TestDisp; @@ -357,7 +411,7 @@ static bool expandDisp(SystemZAddressingMode &AM, bool IsBase, } bool SystemZDAGToDAGISel::expandAddress(SystemZAddressingMode &AM, - bool IsBase) { + bool IsBase) const { SDValue N = IsBase ? AM.Base : AM.Index; unsigned Opcode = N.getOpcode(); if (Opcode == ISD::TRUNCATE) { @@ -377,13 +431,23 @@ bool SystemZDAGToDAGISel::expandAddress(SystemZAddressingMode &AM, return expandAdjDynAlloc(AM, IsBase, Op0); if (Op0Code == ISD::Constant) - return expandDisp(AM, IsBase, Op1, cast(Op0)); + return expandDisp(AM, IsBase, Op1, + cast(Op0)->getSExtValue()); if (Op1Code == ISD::Constant) - return expandDisp(AM, IsBase, Op0, cast(Op1)); + return expandDisp(AM, IsBase, Op0, + cast(Op1)->getSExtValue()); if (IsBase && expandIndex(AM, Op0, Op1)) return true; } + if (Opcode == SystemZISD::PCREL_OFFSET) { + SDValue Full = N.getOperand(0); + SDValue Base = N.getOperand(1); + SDValue Anchor = Base.getOperand(0); + uint64_t Offset = (cast(Full)->getOffset() - + cast(Anchor)->getOffset()); + return expandDisp(AM, IsBase, Base, Offset); + } return false; } @@ -462,14 +526,15 @@ static bool shouldUseLA(SDNode *Base, int64_t Disp, SDNode *Index) { // Return true if Addr is suitable for AM, updating AM if so. bool SystemZDAGToDAGISel::selectAddress(SDValue Addr, - SystemZAddressingMode &AM) { + SystemZAddressingMode &AM) const { // Start out assuming that the address will need to be loaded separately, // then try to extend it as much as we can. AM.Base = Addr; // First try treating the address as a constant. if (Addr.getOpcode() == ISD::Constant && - expandDisp(AM, true, SDValue(), cast(Addr))) + expandDisp(AM, true, SDValue(), + cast(Addr)->getSExtValue())) ; else // Otherwise try expanding each component. @@ -509,7 +574,7 @@ static void insertDAGNode(SelectionDAG *DAG, SDNode *Pos, SDValue N) { void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM, EVT VT, SDValue &Base, - SDValue &Disp) { + SDValue &Disp) const { Base = AM.Base; if (!Base.getNode()) // Register 0 means "no base". This is mostly useful for shifts. @@ -534,7 +599,8 @@ void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM, void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM, EVT VT, SDValue &Base, - SDValue &Disp, SDValue &Index) { + SDValue &Disp, + SDValue &Index) const { getAddressOperands(AM, VT, Base, Disp); Index = AM.Index; @@ -545,7 +611,7 @@ void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM, bool SystemZDAGToDAGISel::selectBDAddr(SystemZAddressingMode::DispRange DR, SDValue Addr, SDValue &Base, - SDValue &Disp) { + SDValue &Disp) const { SystemZAddressingMode AM(SystemZAddressingMode::FormBD, DR); if (!selectAddress(Addr, AM)) return false; @@ -554,10 +620,21 @@ bool SystemZDAGToDAGISel::selectBDAddr(SystemZAddressingMode::DispRange DR, return true; } +bool SystemZDAGToDAGISel::selectMVIAddr(SystemZAddressingMode::DispRange DR, + SDValue Addr, SDValue &Base, + SDValue &Disp) const { + SystemZAddressingMode AM(SystemZAddressingMode::FormBDXNormal, DR); + if (!selectAddress(Addr, AM) || AM.Index.getNode()) + return false; + + getAddressOperands(AM, Addr.getValueType(), Base, Disp); + return true; +} + bool SystemZDAGToDAGISel::selectBDXAddr(SystemZAddressingMode::AddrForm Form, SystemZAddressingMode::DispRange DR, SDValue Addr, SDValue &Base, - SDValue &Disp, SDValue &Index) { + SDValue &Disp, SDValue &Index) const { SystemZAddressingMode AM(Form, DR); if (!selectAddress(Addr, AM)) return false; @@ -567,15 +644,14 @@ bool SystemZDAGToDAGISel::selectBDXAddr(SystemZAddressingMode::AddrForm Form, } bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op, - uint64_t InsertMask) { + uint64_t InsertMask) const { // We're only interested in cases where the insertion is into some operand // of Op, rather than into Op itself. The only useful case is an AND. if (Op.getOpcode() != ISD::AND) return false; // We need a constant mask. - ConstantSDNode *MaskNode = - dyn_cast(Op.getOperand(1).getNode()); + auto *MaskNode = dyn_cast(Op.getOperand(1).getNode()); if (!MaskNode) return false; @@ -589,7 +665,7 @@ bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op, uint64_t Used = allOnes(Op.getValueType().getSizeInBits()); if (Used != (AndMask | InsertMask)) { APInt KnownZero, KnownOne; - CurDAG->ComputeMaskedBits(Op.getOperand(0), KnownZero, KnownOne); + CurDAG->computeKnownBits(Op.getOperand(0), KnownZero, KnownOne); if (Used != (AndMask | InsertMask | KnownZero.getZExtValue())) return false; } @@ -598,151 +674,171 @@ bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op, return true; } -// Return true if Mask matches the regexp 0*1+0*, given that zero masks -// have already been filtered out. Store the first set bit in LSB and -// the number of set bits in Length if so. -static bool isStringOfOnes(uint64_t Mask, unsigned &LSB, unsigned &Length) { - unsigned First = findFirstSet(Mask); - uint64_t Top = (Mask >> First) + 1; - if ((Top & -Top) == Top) - { - LSB = First; - Length = findFirstSet(Top); - return true; - } +bool SystemZDAGToDAGISel::refineRxSBGMask(RxSBGOperands &RxSBG, + uint64_t Mask) const { + const SystemZInstrInfo *TII = getInstrInfo(); + if (RxSBG.Rotate != 0) + Mask = (Mask << RxSBG.Rotate) | (Mask >> (64 - RxSBG.Rotate)); + Mask &= RxSBG.Mask; + if (TII->isRxSBGMask(Mask, RxSBG.BitSize, RxSBG.Start, RxSBG.End)) { + RxSBG.Mask = Mask; + return true; + } return false; } -// Try to update RISBG so that only the bits of Ops.Input in Mask are used. -// Return true on success. -static bool refineRISBGMask(RISBGOperands &RISBG, uint64_t Mask) { - if (RISBG.Rotate != 0) - Mask = (Mask << RISBG.Rotate) | (Mask >> (64 - RISBG.Rotate)); - Mask &= RISBG.Mask; - - // Reject trivial all-zero masks. - if (Mask == 0) - return false; - - // Handle the 1+0+ or 0+1+0* cases. Start then specifies the index of - // the msb and End specifies the index of the lsb. - unsigned LSB, Length; - if (isStringOfOnes(Mask, LSB, Length)) - { - RISBG.Mask = Mask; - RISBG.Start = 63 - (LSB + Length - 1); - RISBG.End = 63 - LSB; - return true; - } - - // Handle the wrap-around 1+0+1+ cases. Start then specifies the msb - // of the low 1s and End specifies the lsb of the high 1s. - if (isStringOfOnes(Mask ^ allOnes(RISBG.BitSize), LSB, Length)) - { - assert(LSB > 0 && "Bottom bit must be set"); - assert(LSB + Length < RISBG.BitSize && "Top bit must be set"); - RISBG.Mask = Mask; - RISBG.Start = 63 - (LSB - 1); - RISBG.End = 63 - (LSB + Length); - return true; - } - - return false; +// Return true if any bits of (RxSBG.Input & Mask) are significant. +static bool maskMatters(RxSBGOperands &RxSBG, uint64_t Mask) { + // Rotate the mask in the same way as RxSBG.Input is rotated. + if (RxSBG.Rotate != 0) + Mask = ((Mask << RxSBG.Rotate) | (Mask >> (64 - RxSBG.Rotate))); + return (Mask & RxSBG.Mask) != 0; } -bool SystemZDAGToDAGISel::expandRISBG(RISBGOperands &RISBG) { - SDValue N = RISBG.Input; - switch (N.getOpcode()) { +bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const { + SDValue N = RxSBG.Input; + unsigned Opcode = N.getOpcode(); + switch (Opcode) { case ISD::AND: { - ConstantSDNode *MaskNode = - dyn_cast(N.getOperand(1).getNode()); + if (RxSBG.Opcode == SystemZ::RNSBG) + return false; + + auto *MaskNode = dyn_cast(N.getOperand(1).getNode()); if (!MaskNode) return false; SDValue Input = N.getOperand(0); uint64_t Mask = MaskNode->getZExtValue(); - if (!refineRISBGMask(RISBG, Mask)) { + if (!refineRxSBGMask(RxSBG, Mask)) { // If some bits of Input are already known zeros, those bits will have // been removed from the mask. See if adding them back in makes the // mask suitable. APInt KnownZero, KnownOne; - CurDAG->ComputeMaskedBits(Input, KnownZero, KnownOne); + CurDAG->computeKnownBits(Input, KnownZero, KnownOne); Mask |= KnownZero.getZExtValue(); - if (!refineRISBGMask(RISBG, Mask)) + if (!refineRxSBGMask(RxSBG, Mask)) return false; } - RISBG.Input = Input; + RxSBG.Input = Input; + return true; + } + + case ISD::OR: { + if (RxSBG.Opcode != SystemZ::RNSBG) + return false; + + auto *MaskNode = dyn_cast(N.getOperand(1).getNode()); + if (!MaskNode) + return false; + + SDValue Input = N.getOperand(0); + uint64_t Mask = ~MaskNode->getZExtValue(); + if (!refineRxSBGMask(RxSBG, Mask)) { + // If some bits of Input are already known ones, those bits will have + // been removed from the mask. See if adding them back in makes the + // mask suitable. + APInt KnownZero, KnownOne; + CurDAG->computeKnownBits(Input, KnownZero, KnownOne); + Mask &= ~KnownOne.getZExtValue(); + if (!refineRxSBGMask(RxSBG, Mask)) + return false; + } + RxSBG.Input = Input; return true; } case ISD::ROTL: { - // Any 64-bit rotate left can be merged into the RISBG. - if (RISBG.BitSize != 64) + // Any 64-bit rotate left can be merged into the RxSBG. + if (RxSBG.BitSize != 64 || N.getValueType() != MVT::i64) return false; - ConstantSDNode *CountNode - = dyn_cast(N.getOperand(1).getNode()); + auto *CountNode = dyn_cast(N.getOperand(1).getNode()); if (!CountNode) return false; - RISBG.Rotate = (RISBG.Rotate + CountNode->getZExtValue()) & 63; - RISBG.Input = N.getOperand(0); + RxSBG.Rotate = (RxSBG.Rotate + CountNode->getZExtValue()) & 63; + RxSBG.Input = N.getOperand(0); return true; } - case ISD::SHL: { - // Treat (shl X, count) as (and (rotl X, count), ~0<(N.getOperand(1).getNode()); - if (!CountNode) - return false; + case ISD::ANY_EXTEND: + // Bits above the extended operand are don't-care. + RxSBG.Input = N.getOperand(0); + return true; - uint64_t Count = CountNode->getZExtValue(); - if (Count < 1 || - Count >= RISBG.BitSize || - !refineRISBGMask(RISBG, allOnes(RISBG.BitSize - Count) << Count)) + case ISD::ZERO_EXTEND: + if (RxSBG.Opcode != SystemZ::RNSBG) { + // Restrict the mask to the extended operand. + unsigned InnerBitSize = N.getOperand(0).getValueType().getSizeInBits(); + if (!refineRxSBGMask(RxSBG, allOnes(InnerBitSize))) + return false; + + RxSBG.Input = N.getOperand(0); + return true; + } + // Fall through. + + case ISD::SIGN_EXTEND: { + // Check that the extension bits are don't-care (i.e. are masked out + // by the final mask). + unsigned InnerBitSize = N.getOperand(0).getValueType().getSizeInBits(); + if (maskMatters(RxSBG, allOnes(RxSBG.BitSize) - allOnes(InnerBitSize))) return false; - RISBG.Rotate = (RISBG.Rotate + Count) & 63; - RISBG.Input = N.getOperand(0); + RxSBG.Input = N.getOperand(0); return true; } - case ISD::SRL: { - // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count), - // which is similar to SLL above. - ConstantSDNode *CountNode = - dyn_cast(N.getOperand(1).getNode()); + case ISD::SHL: { + auto *CountNode = dyn_cast(N.getOperand(1).getNode()); if (!CountNode) return false; uint64_t Count = CountNode->getZExtValue(); - if (Count < 1 || - Count >= RISBG.BitSize || - !refineRISBGMask(RISBG, allOnes(RISBG.BitSize - Count))) + unsigned BitSize = N.getValueType().getSizeInBits(); + if (Count < 1 || Count >= BitSize) return false; - RISBG.Rotate = (RISBG.Rotate - Count) & 63; - RISBG.Input = N.getOperand(0); + if (RxSBG.Opcode == SystemZ::RNSBG) { + // Treat (shl X, count) as (rotl X, size-count) as long as the bottom + // count bits from RxSBG.Input are ignored. + if (maskMatters(RxSBG, allOnes(Count))) + return false; + } else { + // Treat (shl X, count) as (and (rotl X, count), ~0<(N.getOperand(1).getNode()); + auto *CountNode = dyn_cast(N.getOperand(1).getNode()); if (!CountNode) return false; uint64_t Count = CountNode->getZExtValue(); - if (RISBG.Rotate != 0 || - Count < 1 || - Count >= RISBG.BitSize || - RISBG.Start < 64 - (RISBG.BitSize - Count)) + unsigned BitSize = N.getValueType().getSizeInBits(); + if (Count < 1 || Count >= BitSize) return false; - RISBG.Rotate = -Count & 63; - RISBG.Input = N.getOperand(0); + if (RxSBG.Opcode == SystemZ::RNSBG || Opcode == ISD::SRA) { + // Treat (srl|sra X, count) as (rotl X, size-count) as long as the top + // count bits from RxSBG.Input are ignored. + if (maskMatters(RxSBG, allOnes(Count) << (BitSize - Count))) + return false; + } else { + // Treat (srl X, count), mask) as (and (rotl X, size-count), ~0>>count), + // which is similar to SLL above. + if (!refineRxSBGMask(RxSBG, allOnes(BitSize - Count))) + return false; + } + + RxSBG.Rotate = (RxSBG.Rotate - Count) & 63; + RxSBG.Input = N.getOperand(0); return true; } default: @@ -750,94 +846,113 @@ bool SystemZDAGToDAGISel::expandRISBG(RISBGOperands &RISBG) { } } -SDValue SystemZDAGToDAGISel::getUNDEF64(SDLoc DL) { - SDNode *N = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i64); +SDValue SystemZDAGToDAGISel::getUNDEF(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) { - if (N.getValueType() == MVT::i32 && VT == MVT::i64) { - SDValue Index = CurDAG->getTargetConstant(SystemZ::subreg_32bit, MVT::i64); - SDNode *Insert = CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, - DL, VT, getUNDEF64(DL), N, Index); - return SDValue(Insert, 0); - } - if (N.getValueType() == MVT::i64 && VT == MVT::i32) { - SDValue Index = CurDAG->getTargetConstant(SystemZ::subreg_32bit, MVT::i64); - SDNode *Extract = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, - DL, VT, N, Index); - return SDValue(Extract, 0); - } +SDValue SystemZDAGToDAGISel::convertTo(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); + if (N.getValueType() == MVT::i64 && VT == MVT::i32) + return CurDAG->getTargetExtractSubreg(SystemZ::subreg_l32, DL, VT, N); assert(N.getValueType() == VT && "Unexpected value types"); return N; } SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { - RISBGOperands RISBG(SDValue(N, 0)); - unsigned Count = 0; - while (expandRISBG(RISBG)) - Count += 1; - // Prefer to use normal shift instructions over RISBG, since they can handle - // all cases and are sometimes shorter. Prefer to use RISBG for ANDs though, - // since it is effectively a three-operand instruction in this case, - // and since it can handle some masks that AND IMMEDIATE can't. - if (Count < (N->getOpcode() == ISD::AND ? 1 : 2)) - return 0; - - // Prefer register extensions like LLC over RISBG. - if (RISBG.Rotate == 0 && - (RISBG.Start == 32 || RISBG.Start == 48 || RISBG.Start == 56) && - RISBG.End == 63) - return 0; - EVT VT = N->getValueType(0); + RxSBGOperands RISBG(SystemZ::RISBG, SDValue(N, 0)); + unsigned Count = 0; + while (expandRxSBG(RISBG)) + if (RISBG.Input.getOpcode() != ISD::ANY_EXTEND) + Count += 1; + if (Count == 0) + return nullptr; + 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; + + // Prefer register extensions like LLC over RISBG. Also prefer to start + // out with normal ANDs if one instruction would be enough. We can convert + // these ANDs into an RISBG later if a three-address instruction is useful. + if (VT == MVT::i32 || + RISBG.Mask == 0xff || + RISBG.Mask == 0xffff || + SystemZ::isImmLF(~RISBG.Mask) || + SystemZ::isImmHF(~RISBG.Mask)) { + // Force the new mask into the DAG, since it may include known-one bits. + auto *MaskN = cast(N->getOperand(1).getNode()); + if (MaskN->getZExtValue() != RISBG.Mask) { + SDValue NewMask = CurDAG->getConstant(RISBG.Mask, VT); + N = CurDAG->UpdateNodeOperands(N, N->getOperand(0), NewMask); + return SelectCode(N); + } + return nullptr; + } + } + + unsigned Opcode = SystemZ::RISBG; + EVT OpcodeVT = MVT::i64; + if (VT == MVT::i32 && Subtarget.hasHighWord()) { + Opcode = SystemZ::RISBMux; + OpcodeVT = MVT::i32; + RISBG.Start &= 31; + RISBG.End &= 31; + } SDValue Ops[5] = { - getUNDEF64(SDLoc(N)), - convertTo(SDLoc(N), MVT::i64, RISBG.Input), + getUNDEF(SDLoc(N), OpcodeVT), + convertTo(SDLoc(N), OpcodeVT, RISBG.Input), CurDAG->getTargetConstant(RISBG.Start, MVT::i32), CurDAG->getTargetConstant(RISBG.End | 128, MVT::i32), CurDAG->getTargetConstant(RISBG.Rotate, MVT::i32) }; - N = CurDAG->getMachineNode(SystemZ::RISBG, SDLoc(N), MVT::i64, Ops); + N = CurDAG->getMachineNode(Opcode, SDLoc(N), OpcodeVT, Ops); return convertTo(SDLoc(N), VT, SDValue(N, 0)).getNode(); } -SDNode *SystemZDAGToDAGISel::tryRISBGOrROSBG(SDNode *N) { - // Try treating each operand of N as the second operand of RISBG or ROSBG +SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { + // Try treating each operand of N as the second operand of the RxSBG // and see which goes deepest. - RISBGOperands RISBG[] = { N->getOperand(0), N->getOperand(1) }; + RxSBGOperands RxSBG[] = { + RxSBGOperands(Opcode, N->getOperand(0)), + RxSBGOperands(Opcode, N->getOperand(1)) + }; unsigned Count[] = { 0, 0 }; for (unsigned I = 0; I < 2; ++I) - while (expandRISBG(RISBG[I])) - Count[I] += 1; + while (expandRxSBG(RxSBG[I])) + if (RxSBG[I].Input.getOpcode() != ISD::ANY_EXTEND) + Count[I] += 1; // Do nothing if neither operand is suitable. if (Count[0] == 0 && Count[1] == 0) - return 0; + return nullptr; // Pick the deepest second operand. unsigned I = Count[0] > Count[1] ? 0 : 1; SDValue Op0 = N->getOperand(I ^ 1); // Prefer IC for character insertions from memory. - if ((RISBG[I].Mask & 0xff) == 0) - if (LoadSDNode *Load = dyn_cast(Op0.getNode())) + if (Opcode == SystemZ::ROSBG && (RxSBG[I].Mask & 0xff) == 0) + if (auto *Load = dyn_cast(Op0.getNode())) if (Load->getMemoryVT() == MVT::i8) - return 0; + return nullptr; // See whether we can avoid an AND in the first operand by converting // ROSBG to RISBG. - unsigned Opcode = SystemZ::ROSBG; - if (detectOrAndInsertion(Op0, RISBG[I].Mask)) + if (Opcode == SystemZ::ROSBG && detectOrAndInsertion(Op0, RxSBG[I].Mask)) Opcode = SystemZ::RISBG; EVT VT = N->getValueType(0); SDValue Ops[5] = { convertTo(SDLoc(N), MVT::i64, Op0), - convertTo(SDLoc(N), MVT::i64, RISBG[I].Input), - CurDAG->getTargetConstant(RISBG[I].Start, MVT::i32), - CurDAG->getTargetConstant(RISBG[I].End, MVT::i32), - CurDAG->getTargetConstant(RISBG[I].Rotate, MVT::i32) + convertTo(SDLoc(N), MVT::i64, RxSBG[I].Input), + CurDAG->getTargetConstant(RxSBG[I].Start, MVT::i32), + CurDAG->getTargetConstant(RxSBG[I].End, MVT::i32), + CurDAG->getTargetConstant(RxSBG[I].Rotate, MVT::i32) }; N = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i64, Ops); return convertTo(SDLoc(N), VT, SDValue(N, 0)).getNode(); @@ -858,47 +973,62 @@ SDNode *SystemZDAGToDAGISel::splitLargeImmediate(unsigned Opcode, SDNode *Node, return Or.getNode(); } -// N is a (store (load ...), ...) pattern. Return true if it can use MVC. -bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { - StoreSDNode *Store = cast(N); - LoadSDNode *Load = cast(Store->getValue().getNode()); +bool SystemZDAGToDAGISel::canUseBlockOperation(StoreSDNode *Store, + LoadSDNode *Load) const { + // Check that the two memory operands have the same size. + if (Load->getMemoryVT() != Store->getMemoryVT()) + return false; - // MVC is logically a bytewise copy, so can't be used for volatile accesses. + // Volatility stops an access from being decomposed. if (Load->isVolatile() || Store->isVolatile()) return false; + // There's no chance of overlap if the load is invariant. + if (Load->isInvariant()) + return true; + + // Otherwise we need to check whether there's an alias. + const Value *V1 = Load->getMemOperand()->getValue(); + const Value *V2 = Store->getMemOperand()->getValue(); + if (!V1 || !V2) + return false; + + // Reject equality. + uint64_t Size = Load->getMemoryVT().getStoreSize(); + int64_t End1 = Load->getSrcValueOffset() + Size; + int64_t End2 = Store->getSrcValueOffset() + Size; + if (V1 == V2 && End1 == End2) + return false; + + return !AA->alias(AliasAnalysis::Location(V1, End1, Load->getAAInfo()), + AliasAnalysis::Location(V2, End2, Store->getAAInfo())); +} + +bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { + auto *Store = cast(N); + auto *Load = cast(Store->getValue()); + // Prefer not to use MVC if either address can use ... RELATIVE LONG // instructions. - assert(Load->getMemoryVT() == Store->getMemoryVT() && - "Should already have checked that the types match"); uint64_t Size = Load->getMemoryVT().getStoreSize(); if (Size > 1 && Size <= 8) { // Prefer LHRL, LRL and LGRL. - if (Load->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) + if (SystemZISD::isPCREL(Load->getBasePtr().getOpcode())) return false; // Prefer STHRL, STRL and STGRL. - if (Store->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) + if (SystemZISD::isPCREL(Store->getBasePtr().getOpcode())) return false; } - // There's no chance of overlap if the load is invariant. - if (Load->isInvariant()) - return true; - - // If both operands are aligned, they must be equal or not overlap. - if (Load->getAlignment() >= Size && Store->getAlignment() >= Size) - return true; - - // Otherwise we need to check whether there's an alias. - const Value *V1 = Load->getSrcValue(); - const Value *V2 = Store->getSrcValue(); - if (!V1 || !V2) - return false; + return canUseBlockOperation(Store, Load); +} - int64_t End1 = Load->getSrcValueOffset() + Size; - int64_t End2 = Store->getSrcValueOffset() + Size; - return !AA->alias(AliasAnalysis::Location(V1, End1, Load->getTBAAInfo()), - AliasAnalysis::Location(V2, End2, Store->getTBAAInfo())); +bool SystemZDAGToDAGISel::storeLoadCanUseBlockBinary(SDNode *N, + unsigned I) const { + auto *StoreA = cast(N); + auto *LoadA = cast(StoreA->getValue().getOperand(1 - I)); + auto *LoadB = cast(StoreA->getValue().getOperand(I)); + return !LoadA->isVolatile() && canUseBlockOperation(StoreA, LoadB); } SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { @@ -908,21 +1038,27 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { // If we have a custom node, we already have selected! if (Node->isMachineOpcode()) { DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); - return 0; + Node->setNodeId(-1); + return nullptr; } unsigned Opcode = Node->getOpcode(); - SDNode *ResNode = 0; + SDNode *ResNode = nullptr; switch (Opcode) { case ISD::OR: if (Node->getOperand(1).getOpcode() != ISD::Constant) - ResNode = tryRISBGOrROSBG(Node); - // Fall through. + ResNode = tryRxSBG(Node, SystemZ::ROSBG); + goto or_xor; + case ISD::XOR: + if (Node->getOperand(1).getOpcode() != ISD::Constant) + ResNode = tryRxSBG(Node, SystemZ::RXSBG); + // 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 (ConstantSDNode *Op1 = dyn_cast(Node->getOperand(1))) { + if (auto *Op1 = dyn_cast(Node->getOperand(1))) { uint64_t Val = Op1->getZExtValue(); if (!SystemZ::isImmLF(Val) && !SystemZ::isImmHF(Val)) Node = splitLargeImmediate(Opcode, Node, Node->getOperand(0), @@ -931,10 +1067,15 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { break; case ISD::AND: + if (Node->getOperand(1).getOpcode() != ISD::Constant) + ResNode = tryRxSBG(Node, SystemZ::RNSBG); + // Fall through. case ISD::ROTL: case ISD::SHL: case ISD::SRL: - ResNode = tryRISBGZero(Node); + case ISD::ZERO_EXTEND: + if (!ResNode) + ResNode = tryRISBGZero(Node); break; case ISD::Constant: @@ -948,27 +1089,34 @@ SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { } break; - case ISD::ATOMIC_LOAD_SUB: - // Try to convert subtractions of constants to additions. - if (ConstantSDNode *Op2 = dyn_cast(Node->getOperand(2))) { - uint64_t Value = -Op2->getZExtValue(); - EVT VT = Node->getValueType(0); - if (VT == MVT::i32 || isInt<32>(Value)) { - SDValue Ops[] = { Node->getOperand(0), Node->getOperand(1), - CurDAG->getConstant(int32_t(Value), VT) }; - Node = CurDAG->MorphNodeTo(Node, ISD::ATOMIC_LOAD_ADD, - Node->getVTList(), Ops, array_lengthof(Ops)); - } + case SystemZISD::SELECT_CCMASK: { + SDValue Op0 = Node->getOperand(0); + SDValue Op1 = Node->getOperand(1); + // Prefer to put any load first, so that it can be matched as a + // conditional load. + if (Op1.getOpcode() == ISD::LOAD && Op0.getOpcode() != ISD::LOAD) { + SDValue CCValid = Node->getOperand(2); + SDValue CCMask = Node->getOperand(3); + uint64_t ConstCCValid = + cast(CCValid.getNode())->getZExtValue(); + uint64_t ConstCCMask = + cast(CCMask.getNode())->getZExtValue(); + // Invert the condition. + CCMask = CurDAG->getConstant(ConstCCValid ^ ConstCCMask, + CCMask.getValueType()); + SDValue Op4 = Node->getOperand(4); + Node = CurDAG->UpdateNodeOperands(Node, Op1, Op0, CCValid, CCMask, Op4); } break; } + } // Select the default instruction if (!ResNode) ResNode = SelectCode(Node); DEBUG(errs() << "=> "; - if (ResNode == NULL || ResNode == Node) + if (ResNode == nullptr || ResNode == Node) Node->dump(CurDAG); else ResNode->dump(CurDAG);