diff options
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 71 | ||||
| -rw-r--r-- | llvm/lib/Target/SystemZ/SystemZISelLowering.h | 13 | ||||
| -rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 11 | ||||
| -rw-r--r-- | llvm/lib/Target/SystemZ/SystemZOperators.td | 24 |
4 files changed, 114 insertions, 5 deletions
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index f656a2f00ed..2a29190a7f7 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -436,6 +436,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM, setTargetDAGCombine(ISD::STORE); setTargetDAGCombine(ISD::EXTRACT_VECTOR_ELT); setTargetDAGCombine(ISD::FP_ROUND); + setTargetDAGCombine(ISD::BSWAP); // Handle intrinsics. setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); @@ -4676,6 +4677,8 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(ATOMIC_LOADW_UMIN); OPCODE(ATOMIC_LOADW_UMAX); OPCODE(ATOMIC_CMP_SWAPW); + OPCODE(LRV); + OPCODE(STRV); OPCODE(PREFETCH); } return nullptr; @@ -4971,6 +4974,74 @@ SDValue SystemZTargetLowering::PerformDAGCombine(SDNode *N, } } } + + // Combine BSWAP (LOAD) into LRVH/LRV/LRVG + // These loads are allowed to access memory multiple times, and so we must check + // that the loads are not volatile before performing the combine. + if (Opcode == ISD::BSWAP && + ISD::isNON_EXTLoad(N->getOperand(0).getNode()) && + N->getOperand(0).hasOneUse() && + (N->getValueType(0) == MVT::i16 || N->getValueType(0) == MVT::i32 || + N->getValueType(0) == MVT::i64) && + !cast<LoadSDNode>(N->getOperand(0))->isVolatile()) { + SDValue Load = N->getOperand(0); + LoadSDNode *LD = cast<LoadSDNode>(Load); + + // Create the byte-swapping load. + SDValue Ops[] = { + LD->getChain(), // Chain + LD->getBasePtr(), // Ptr + DAG.getValueType(N->getValueType(0)) // VT + }; + SDValue BSLoad = + DAG.getMemIntrinsicNode(SystemZISD::LRV, SDLoc(N), + DAG.getVTList(N->getValueType(0) == MVT::i64 ? + MVT::i64 : MVT::i32, MVT::Other), + Ops, LD->getMemoryVT(), LD->getMemOperand()); + + // If this is an i16 load, insert the truncate. + SDValue ResVal = BSLoad; + if (N->getValueType(0) == MVT::i16) + ResVal = DAG.getNode(ISD::TRUNCATE, SDLoc(N), MVT::i16, BSLoad); + + // First, combine the bswap away. This makes the value produced by the + // load dead. + DCI.CombineTo(N, ResVal); + + // Next, combine the load away, we give it a bogus result value but a real + // chain result. The result value is dead because the bswap is dead. + DCI.CombineTo(Load.getNode(), ResVal, BSLoad.getValue(1)); + + // Return N so it doesn't get rechecked! + return SDValue(N, 0); + } + + // Combine STORE (BSWAP) into STRVH/STRV/STRVG + // See comment above about volatile accesses. + if (Opcode == ISD::STORE && + !cast<StoreSDNode>(N)->isVolatile() && + N->getOperand(1).getOpcode() == ISD::BSWAP && + N->getOperand(1).getNode()->hasOneUse() && + (N->getOperand(1).getValueType() == MVT::i16 || + N->getOperand(1).getValueType() == MVT::i32 || + N->getOperand(1).getValueType() == MVT::i64)) { + + SDValue BSwapOp = N->getOperand(1).getOperand(0); + + if (BSwapOp.getValueType() == MVT::i16) + BSwapOp = DAG.getNode(ISD::ANY_EXTEND, SDLoc(N), MVT::i32, BSwapOp); + + SDValue Ops[] = { + N->getOperand(0), BSwapOp, N->getOperand(2), + DAG.getValueType(N->getOperand(1).getValueType()) + }; + + return + DAG.getMemIntrinsicNode(SystemZISD::STRV, SDLoc(N), DAG.getVTList(MVT::Other), + Ops, cast<StoreSDNode>(N)->getMemoryVT(), + cast<StoreSDNode>(N)->getMemOperand()); + } + return SDValue(); } diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index bfd08543563..598fd48ee61 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -311,6 +311,19 @@ enum NodeType : unsigned { // Operand 5: the width of the field in bits (8 or 16) ATOMIC_CMP_SWAPW, + // Byte swapping load. + // + // Operand 0: the address to load from + // Operand 1: the type of load (i16, i32, i64) + LRV, + + // Byte swapping store. + // + // Operand 0: the value to store + // Operand 1: the address to store to + // Operand 2: the type of store (i16, i32, i64) + STRV, + // Prefetch from the second operand using the 4-bit control code in // the first operand. The code is 1 for a load prefetch and 2 for // a store prefetch. diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index dbe4bfbf900..36e8284c7c9 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -670,13 +670,14 @@ let hasSideEffects = 0 in { // Byte-swapping loads. Unlike normal loads, these instructions are // allowed to access storage more than once. -def LRV : UnaryRXY<"lrv", 0xE31E, loadu<bswap, nonvolatile_load>, GR32, 4>; -def LRVG : UnaryRXY<"lrvg", 0xE30F, loadu<bswap, nonvolatile_load>, GR64, 8>; +def LRVH : UnaryRXY<"lrvh", 0xE31F, z_lrvh, GR32, 2>; +def LRV : UnaryRXY<"lrv", 0xE31E, z_lrv, GR32, 4>; +def LRVG : UnaryRXY<"lrvg", 0xE30F, z_lrvg, GR64, 8>; // Likewise byte-swapping stores. -def STRV : StoreRXY<"strv", 0xE33E, storeu<bswap, nonvolatile_store>, GR32, 4>; -def STRVG : StoreRXY<"strvg", 0xE32F, storeu<bswap, nonvolatile_store>, - GR64, 8>; +def STRVH : StoreRXY<"strvh", 0xE33F, z_strvh, GR32, 2>; +def STRV : StoreRXY<"strv", 0xE33E, z_strv, GR32, 4>; +def STRVG : StoreRXY<"strvg", 0xE32F, z_strvg, GR64, 8>; //===----------------------------------------------------------------------===// // Load address instructions diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td index 730b9b31868..c2039de7913 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -79,6 +79,14 @@ def SDT_ZI32Intrinsic : SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>; def SDT_ZPrefetch : SDTypeProfile<0, 2, [SDTCisVT<0, i32>, SDTCisPtrTy<1>]>; +def SDT_ZLoadBSwap : SDTypeProfile<1, 2, + [SDTCisInt<0>, + SDTCisPtrTy<1>, + SDTCisVT<2, OtherVT>]>; +def SDT_ZStoreBSwap : SDTypeProfile<0, 3, + [SDTCisInt<0>, + SDTCisPtrTy<1>, + SDTCisVT<2, OtherVT>]>; def SDT_ZTBegin : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; @@ -191,6 +199,11 @@ def z_serialize : SDNode<"SystemZISD::SERIALIZE", SDTNone, def z_membarrier : SDNode<"SystemZISD::MEMBARRIER", SDTNone, [SDNPHasChain, SDNPSideEffect]>; +def z_loadbswap : SDNode<"SystemZISD::LRV", SDT_ZLoadBSwap, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def z_storebswap : SDNode<"SystemZISD::STRV", SDT_ZStoreBSwap, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; + // Defined because the index is an i32 rather than a pointer. def z_vector_insert : SDNode<"ISD::INSERT_VECTOR_ELT", SDT_ZInsertVectorElt>; @@ -331,6 +344,17 @@ def z_vsrl : SDNode<"ISD::SRL", SDT_ZVecBinary>; // Pattern fragments //===----------------------------------------------------------------------===// +def z_lrvh : PatFrag<(ops node:$addr), (z_loadbswap node:$addr, i16)>; +def z_lrv : PatFrag<(ops node:$addr), (z_loadbswap node:$addr, i32)>; +def z_lrvg : PatFrag<(ops node:$addr), (z_loadbswap node:$addr, i64)>; + +def z_strvh : PatFrag<(ops node:$src, node:$addr), + (z_storebswap node:$src, node:$addr, i16)>; +def z_strv : PatFrag<(ops node:$src, node:$addr), + (z_storebswap node:$src, node:$addr, i32)>; +def z_strvg : PatFrag<(ops node:$src, node:$addr), + (z_storebswap node:$src, node:$addr, i64)>; + // Signed and unsigned comparisons. def z_scmp : PatFrag<(ops node:$a, node:$b), (z_icmp node:$a, node:$b, imm), [{ unsigned Type = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); |

