diff options
| author | Alex Bradbury <asb@lowrisc.org> | 2018-03-19 11:54:28 +0000 |
|---|---|---|
| committer | Alex Bradbury <asb@lowrisc.org> | 2018-03-19 11:54:28 +0000 |
| commit | 0171a9f4eca3fe562e94895e618b1312e2134fcf (patch) | |
| tree | 9ba62b86597d893a0e9866122d36802695eae8ed /llvm/lib | |
| parent | fa0217276a3dd30b745e8306f06c72a91a463ee2 (diff) | |
| download | bcm5719-llvm-0171a9f4eca3fe562e94895e618b1312e2134fcf.tar.gz bcm5719-llvm-0171a9f4eca3fe562e94895e618b1312e2134fcf.zip | |
[RISCV] Peephole optimisation for load/store of global values or constant addresses
(load (add base, off), 0) -> (load base, off)
(store val, (add base, off)) -> (store val, base, off)
This is similar to an equivalent peephole optimisation in PPCISelDAGToDAG.
llvm-svn: 327831
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index d07301df718..9e64007dd81 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -42,6 +42,8 @@ public: return SelectionDAGISel::runOnMachineFunction(MF); } + void PostprocessISelDAG() override; + void Select(SDNode *Node) override; bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, @@ -51,9 +53,14 @@ public: // Include the pieces autogenerated from the target description. #include "RISCVGenDAGISel.inc" + +private: + void doPeepholeLoadStoreADDI(); }; } +void RISCVDAGToDAGISel::PostprocessISelDAG() { doPeepholeLoadStoreADDI(); } + void RISCVDAGToDAGISel::Select(SDNode *Node) { unsigned Opcode = Node->getOpcode(); MVT XLenVT = Subtarget->getXLenVT(); @@ -117,6 +124,94 @@ bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { return false; } +// Merge an ADDI into the offset of a load/store instruction where possible. +// (load (add base, off), 0) -> (load base, off) +// (store val, (add base, off)) -> (store val, base, off) +void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { + SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode()); + ++Position; + + while (Position != CurDAG->allnodes_begin()) { + SDNode *N = &*--Position; + // Skip dead nodes and any non-machine opcodes. + if (N->use_empty() || !N->isMachineOpcode()) + continue; + + int OffsetOpIdx; + int BaseOpIdx; + + // Only attempt this optimisation for I-type loads and S-type stores. + switch (N->getMachineOpcode()) { + default: + continue; + case RISCV::LB: + case RISCV::LH: + case RISCV::LW: + case RISCV::LBU: + case RISCV::LHU: + case RISCV::LWU: + case RISCV::LD: + case RISCV::FLW: + case RISCV::FLD: + BaseOpIdx = 0; + OffsetOpIdx = 1; + break; + case RISCV::SB: + case RISCV::SH: + case RISCV::SW: + case RISCV::SD: + case RISCV::FSW: + case RISCV::FSD: + BaseOpIdx = 1; + OffsetOpIdx = 2; + break; + } + + // Currently, the load/store offset must be 0 to be considered for this + // peephole optimisation. + if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)) || + N->getConstantOperandVal(OffsetOpIdx) != 0) + continue; + + SDValue Base = N->getOperand(BaseOpIdx); + + // If the base is an ADDI, we can merge it in to the load/store. + if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI) + continue; + + SDValue ImmOperand = Base.getOperand(1); + + if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) { + ImmOperand = CurDAG->getTargetConstant( + Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType()); + } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) { + ImmOperand = CurDAG->getTargetGlobalAddress( + GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), + GA->getOffset(), GA->getTargetFlags()); + } else { + continue; + } + + DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: "); + DEBUG(Base->dump(CurDAG)); + DEBUG(dbgs() << "\nN: "); + DEBUG(N->dump(CurDAG)); + DEBUG(dbgs() << "\n"); + + // Modify the offset operand of the load/store. + if (BaseOpIdx == 0) // Load + CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand, + N->getOperand(2)); + else // Store + CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0), + ImmOperand, N->getOperand(3)); + + // The add-immediate may now be dead, in which case remove it. + if (Base.getNode()->use_empty()) + CurDAG->RemoveDeadNode(Base.getNode()); + } +} + // This pass converts a legalized DAG into a RISCV-specific DAG, ready // for instruction scheduling. FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) { |

