From 178273a174cc22d7f5d23dbe83c697efeb52a1de Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 5 Sep 2013 10:36:45 +0000 Subject: [SystemZ] Add NC, OC and XC For now these are just used to handle scalar ANDs, ORs and XORs in which all operands are memory. llvm-svn: 190041 --- llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 69 ++++++++++++++++++------- llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 15 ++++++ llvm/lib/Target/SystemZ/SystemZISelLowering.h | 8 +++ llvm/lib/Target/SystemZ/SystemZInstrFP.td | 6 +-- llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 42 ++++++++++----- llvm/lib/Target/SystemZ/SystemZOperators.td | 37 +++++++++++++ llvm/lib/Target/SystemZ/SystemZPatterns.td | 39 ++++++++++---- 7 files changed, 170 insertions(+), 46 deletions(-) (limited to 'llvm/lib/Target/SystemZ') diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index e0d543791b0..9d71c3948d6 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -290,8 +290,15 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { SDNode *splitLargeImmediate(unsigned Opcode, SDNode *Node, SDValue Op0, uint64_t UpperVal, uint64_t LowerVal); + // 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), @@ -925,34 +932,27 @@ 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()); +// Return true if Load and Store: +// - are loads and stores of the same size; +// - do not partially overlap; and +// - can be decomposed into what are logically individual character accesses +// without changing the semantics. +static bool canUseBlockOperation(StoreSDNode *Store, LoadSDNode *Load, + AliasAnalysis *AA) { + // 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; - // 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) - return false; - // Prefer STHRL, STRL and STGRL. - if (Store->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) - 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. + uint64_t Size = Load->getMemoryVT().getStoreSize(); if (Load->getAlignment() >= Size && Store->getAlignment() >= Size) return true; @@ -968,6 +968,37 @@ bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { AliasAnalysis::Location(V2, End2, Store->getTBAAInfo())); } +bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { + StoreSDNode *Store = cast(N); + LoadSDNode *Load = cast(Store->getValue()); + + // Prefer not to use MVC if either address can use ... RELATIVE LONG + // instructions. + uint64_t Size = Load->getMemoryVT().getStoreSize(); + if (Size > 1 && Size <= 8) { + // Prefer LHRL, LRL and LGRL. + if (Load->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) + return false; + // Prefer STHRL, STRL and STGRL. + if (Store->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) + return false; + } + + return canUseBlockOperation(Store, Load, AA); +} + +bool SystemZDAGToDAGISel::storeLoadCanUseBlockBinary(SDNode *N, + unsigned I) const { + StoreSDNode *StoreA = cast(N); + LoadSDNode *LoadA = cast(StoreA->getValue().getOperand(1 - I)); + LoadSDNode *LoadB = cast(StoreA->getValue().getOperand(I)); + if (LoadA->isVolatile() || + LoadA->getMemoryVT() != StoreA->getMemoryVT() || + LoadA->getBasePtr() != StoreA->getBasePtr()) + return false; + return canUseBlockOperation(StoreA, LoadB, AA); +} + SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { // Dump information about the Node being selected DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 13d5604be13..180c631ce13 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -2054,6 +2054,12 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(UDIVREM64); OPCODE(MVC); OPCODE(MVC_LOOP); + OPCODE(NC); + OPCODE(NC_LOOP); + OPCODE(OC); + OPCODE(OC_LOOP); + OPCODE(XC); + OPCODE(XC_LOOP); OPCODE(CLC); OPCODE(CLC_LOOP); OPCODE(STRCMP); @@ -3077,6 +3083,15 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const { case SystemZ::MVCSequence: case SystemZ::MVCLoop: return emitMemMemWrapper(MI, MBB, SystemZ::MVC); + case SystemZ::NCSequence: + case SystemZ::NCLoop: + return emitMemMemWrapper(MI, MBB, SystemZ::NC); + case SystemZ::OCSequence: + case SystemZ::OCLoop: + return emitMemMemWrapper(MI, MBB, SystemZ::OC); + case SystemZ::XCSequence: + case SystemZ::XCLoop: + return emitMemMemWrapper(MI, MBB, SystemZ::XC); case SystemZ::CLCSequence: case SystemZ::CLCLoop: return emitMemMemWrapper(MI, MBB, SystemZ::CLC); diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index ec5051f3e6e..8b2d19a1d2d 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -93,6 +93,14 @@ namespace SystemZISD { // The value of X is passed as an additional operand. MVC_LOOP, + // Similar to MVC and MVC_LOOP, but for logic operations (AND, OR, XOR). + NC, + NC_LOOP, + OC, + OC_LOOP, + XC, + XC_LOOP, + // Use CLC to compare two blocks of memory, with the same comments // as for MVC and MVC_LOOP. CLC, diff --git a/llvm/lib/Target/SystemZ/SystemZInstrFP.td b/llvm/lib/Target/SystemZ/SystemZInstrFP.td index 8d0dcb673fc..24adaeec0cd 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrFP.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrFP.td @@ -86,9 +86,9 @@ def : CopySign128; -defm LoadStoreF32 : MVCLoadStore; -defm LoadStoreF64 : MVCLoadStore; -defm LoadStoreF128 : MVCLoadStore; +defm LoadStoreF32 : MVCLoadStore; +defm LoadStoreF64 : MVCLoadStore; +defm LoadStoreF128 : MVCLoadStore; //===----------------------------------------------------------------------===// // Load instructions diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index 7793818b796..abe28a57ec4 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -350,20 +350,6 @@ let mayLoad = 1, mayStore = 1 in let mayLoad = 1, mayStore = 1, Defs = [CC], Uses = [R0W] in defm MVST : StringRRE<"mvst", 0xB255, z_stpcpy>; -defm LoadStore8_32 : MVCLoadStore; -defm LoadStore16_32 : MVCLoadStore; -defm LoadStore32_32 : MVCLoadStore; - -defm LoadStore8 : MVCLoadStore; -defm LoadStore16 : MVCLoadStore; -defm LoadStore32 : MVCLoadStore; -defm LoadStore64 : MVCLoadStore; - //===----------------------------------------------------------------------===// // Sign extensions //===----------------------------------------------------------------------===// @@ -770,6 +756,10 @@ let Defs = [CC] in { // AND to memory defm NI : BinarySIPair<"ni", 0x94, 0xEB54, null_frag, uimm8>; + + // Block AND. + let mayLoad = 1, mayStore = 1 in + defm NC : MemorySS<"nc", 0xD4, z_nc, z_nc_loop>; } defm : RMWIByte; defm : RMWIByte; @@ -812,6 +802,10 @@ let Defs = [CC] in { // OR to memory defm OI : BinarySIPair<"oi", 0x96, 0xEB56, null_frag, uimm8>; + + // Block OR. + let mayLoad = 1, mayStore = 1 in + defm OC : MemorySS<"oc", 0xD6, z_oc, z_oc_loop>; } defm : RMWIByte; defm : RMWIByte; @@ -843,6 +837,10 @@ let Defs = [CC] in { // XOR to memory defm XI : BinarySIPair<"xi", 0x97, 0xEB57, null_frag, uimm8>; + + // Block XOR. + let mayLoad = 1, mayStore = 1 in + defm XC : MemorySS<"xc", 0xD7, z_xc, z_xc_loop>; } defm : RMWIByte; defm : RMWIByte; @@ -1246,3 +1244,19 @@ def : Pat<(sra (shl (i64 (anyext (i32 (z_select_ccmask 1, 0, uimm8zx4:$valid, (i32 63)), (i32 63)), (Select64 (LGHI -1), (LGHI 0), uimm8zx4:$valid, uimm8zx4:$cc)>; + +// Peepholes for turning scalar operations into block operations. +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td index 822195c02a5..c89e31548b9 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -131,6 +131,18 @@ def z_mvc : SDNode<"SystemZISD::MVC", SDT_ZMemMemLength, [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; def z_mvc_loop : SDNode<"SystemZISD::MVC_LOOP", SDT_ZMemMemLoop, [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_nc : SDNode<"SystemZISD::NC", SDT_ZMemMemLength, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_nc_loop : SDNode<"SystemZISD::NC_LOOP", SDT_ZMemMemLoop, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_oc : SDNode<"SystemZISD::OC", SDT_ZMemMemLength, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_oc_loop : SDNode<"SystemZISD::OC_LOOP", SDT_ZMemMemLoop, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_xc : SDNode<"SystemZISD::XC", SDT_ZMemMemLength, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_xc_loop : SDNode<"SystemZISD::XC_LOOP", SDT_ZMemMemLoop, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; def z_clc : SDNode<"SystemZISD::CLC", SDT_ZMemMemLength, [SDNPHasChain, SDNPOutGlue, SDNPMayLoad]>; def z_clc_loop : SDNode<"SystemZISD::CLC_LOOP", SDT_ZMemMemLoop, @@ -224,6 +236,31 @@ def nonvolatile_truncstorei8 : NonvolatileStore; def nonvolatile_truncstorei16 : NonvolatileStore; def nonvolatile_truncstorei32 : NonvolatileStore; +// A store of a load that can be implemented using MVC. +def mvc_store : PatFrag<(ops node:$value, node:$addr), + (unindexedstore node:$value, node:$addr), + [{ return storeLoadCanUseMVC(N); }]>; + +// Binary read-modify-write operations on memory in which the other +// operand is also memory and for which block operations like NC can +// be used. There are two patterns for each operator, depending on +// which operand contains the "other" load. +multiclass block_op { + def "1" : PatFrag<(ops node:$value, node:$addr), + (unindexedstore (operator node:$value, + (unindexedload node:$addr)), + node:$addr), + [{ return storeLoadCanUseBlockBinary(N, 0); }]>; + def "2" : PatFrag<(ops node:$value, node:$addr), + (unindexedstore (operator (unindexedload node:$addr), + node:$value), + node:$addr), + [{ return storeLoadCanUseBlockBinary(N, 1); }]>; +} +defm block_and : block_op; +defm block_or : block_op; +defm block_xor : block_op; + // Insertions. def inserti8 : PatFrag<(ops node:$src1, node:$src2), (or (and node:$src1, -256), node:$src2)>; diff --git a/llvm/lib/Target/SystemZ/SystemZPatterns.td b/llvm/lib/Target/SystemZ/SystemZPatterns.td index c442ae0d95d..bc3775f2795 100644 --- a/llvm/lib/Target/SystemZ/SystemZPatterns.td +++ b/llvm/lib/Target/SystemZ/SystemZPatterns.td @@ -66,20 +66,39 @@ multiclass InsertMem; } -// Use MVC instruction INSN for a load of type LOAD followed by a store -// of type STORE. VT is the type of the intermediate register and LENGTH -// is the number of bytes to copy (which may be smaller than VT). -multiclass MVCLoadStore length> { - def Pat : PatFrag<(ops node:$dest, node:$src), - (store (vt (load node:$src)), node:$dest), - [{ return storeLoadCanUseMVC(N); }]>; +// Try to use MVC instruction INSN for a load of type LOAD followed by a store +// of the same size. VT is the type of the intermediate (legalized) value and +// LENGTH is the number of bytes loaded by LOAD. +multiclass MVCLoadStore length> { + def : Pat<(mvc_store (vt (load bdaddr12only:$src)), bdaddr12only:$dest), + (insn bdaddr12only:$dest, bdaddr12only:$src, length)>; +} - def : Pat<(!cast(NAME##"Pat") bdaddr12only:$dest, - bdaddr12only:$src), +// Use NC-like instruction INSN for block_op operation OPERATOR. +// The other operand is a load of type LOAD, which accesses LENGTH bytes. +// VT is the intermediate legalized type in which the binary operation +// is actually done. +multiclass BinaryLoadStore length> { + def : Pat<(operator (vt (load bdaddr12only:$src)), bdaddr12only:$dest), (insn bdaddr12only:$dest, bdaddr12only:$src, length)>; } +// A convenient way of generating all block peepholes for a particular +// LOAD/VT/LENGTH combination. +multiclass BlockLoadStore length> { + defm : MVCLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; +} + // Record that INSN is a LOAD AND TEST that can be used to compare // registers in CLS against zero. The instruction has separate R1 and R2 // operands, but they must be the same when the instruction is used like this. -- cgit v1.2.3