diff options
Diffstat (limited to 'llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp')
-rw-r--r-- | llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 107 |
1 files changed, 59 insertions, 48 deletions
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index f66d06c20e377..a0ae05081adcb 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -10,55 +10,19 @@ // //===----------------------------------------------------------------------===// +#include "RISCVISelDAGToDAG.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" -#include "RISCV.h" -#include "RISCVTargetMachine.h" #include "Utils/RISCVMatInt.h" #include "llvm/CodeGen/MachineFrameInfo.h" -#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; #define DEBUG_TYPE "riscv-isel" -// RISCV-specific code to select RISCV machine instructions for -// SelectionDAG operations. -namespace { -class RISCVDAGToDAGISel final : public SelectionDAGISel { - const RISCVSubtarget *Subtarget = nullptr; - -public: - explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine) - : SelectionDAGISel(TargetMachine) {} - - StringRef getPassName() const override { - return "RISCV DAG->DAG Pattern Instruction Selection"; - } - - bool runOnMachineFunction(MachineFunction &MF) override { - Subtarget = &MF.getSubtarget<RISCVSubtarget>(); - return SelectionDAGISel::runOnMachineFunction(MF); - } - - void PostprocessISelDAG() override; - - void Select(SDNode *Node) override; - - bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, - std::vector<SDValue> &OutOps) override; - - bool SelectAddrFI(SDValue Addr, SDValue &Base); - -// Include the pieces autogenerated from the target description. -#include "RISCVGenDAGISel.inc" - -private: - void doPeepholeLoadStoreADDI(); -}; -} - void RISCVDAGToDAGISel::PostprocessISelDAG() { doPeepholeLoadStoreADDI(); } @@ -111,6 +75,30 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { EVT VT = Node->getValueType(0); switch (Opcode) { + case ISD::ADD: { + // Optimize (add r, imm) to (addi (addi r, imm0) imm1) if applicable. The + // immediate must be in specific ranges and have a single use. + if (auto *ConstOp = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { + if (!(ConstOp->hasOneUse())) + break; + // The imm must be in range [-4096,-2049] or [2048,4094]. + int64_t Imm = ConstOp->getSExtValue(); + if (!(-4096 <= Imm && Imm <= -2049) && !(2048 <= Imm && Imm <= 4094)) + break; + // Break the imm to imm0+imm1. + SDLoc DL(Node); + EVT VT = Node->getValueType(0); + const SDValue ImmOp0 = CurDAG->getTargetConstant(Imm - Imm / 2, DL, VT); + const SDValue ImmOp1 = CurDAG->getTargetConstant(Imm / 2, DL, VT); + auto *NodeAddi0 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, + Node->getOperand(0), ImmOp0); + auto *NodeAddi1 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, + SDValue(NodeAddi0, 0), ImmOp1); + ReplaceNode(Node, NodeAddi1); + return; + } + break; + } case ISD::Constant: { auto ConstNode = cast<ConstantSDNode>(Node); if (VT == XLenVT && ConstNode->isNullValue()) { @@ -197,8 +185,9 @@ bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { } // 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) +// (load (addi base, off1), off2) -> (load base, off1+off2) +// (store val, (addi base, off1), off2) -> (store val, base, off1+off2) +// This is possible when off1+off2 fits a 12-bit immediate. void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode()); ++Position; @@ -239,10 +228,7 @@ void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { 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) + if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx))) continue; SDValue Base = N->getOperand(BaseOpIdx); @@ -252,14 +238,39 @@ void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { continue; SDValue ImmOperand = Base.getOperand(1); + uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx); if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) { - ImmOperand = CurDAG->getTargetConstant( - Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType()); + int64_t Offset1 = Const->getSExtValue(); + int64_t CombinedOffset = Offset1 + Offset2; + if (!isInt<12>(CombinedOffset)) + continue; + ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand), + ImmOperand.getValueType()); } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) { + // If the off1 in (addi base, off1) is a global variable's address (its + // low part, really), then we can rely on the alignment of that variable + // to provide a margin of safety before off1 can overflow the 12 bits. + // Check if off2 falls within that margin; if so off1+off2 can't overflow. + const DataLayout &DL = CurDAG->getDataLayout(); + Align Alignment = GA->getGlobal()->getPointerAlignment(DL); + if (Offset2 != 0 && Alignment <= Offset2) + continue; + int64_t Offset1 = GA->getOffset(); + int64_t CombinedOffset = Offset1 + Offset2; ImmOperand = CurDAG->getTargetGlobalAddress( GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), - GA->getOffset(), GA->getTargetFlags()); + CombinedOffset, GA->getTargetFlags()); + } else if (auto CP = dyn_cast<ConstantPoolSDNode>(ImmOperand)) { + // Ditto. + Align Alignment = CP->getAlign(); + if (Offset2 != 0 && Alignment <= Offset2) + continue; + int64_t Offset1 = CP->getOffset(); + int64_t CombinedOffset = Offset1 + Offset2; + ImmOperand = CurDAG->getTargetConstantPool( + CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(), + CombinedOffset, CP->getTargetFlags()); } else { continue; } |