Home | History | Annotate | Download | only in RISCV
      1 //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines an instruction selector for the RISCV target.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "RISCV.h"
     15 #include "MCTargetDesc/RISCVMCTargetDesc.h"
     16 #include "RISCVTargetMachine.h"
     17 #include "llvm/CodeGen/MachineFrameInfo.h"
     18 #include "llvm/CodeGen/SelectionDAGISel.h"
     19 #include "llvm/Support/Debug.h"
     20 #include "llvm/Support/MathExtras.h"
     21 #include "llvm/Support/raw_ostream.h"
     22 using namespace llvm;
     23 
     24 #define DEBUG_TYPE "riscv-isel"
     25 
     26 // RISCV-specific code to select RISCV machine instructions for
     27 // SelectionDAG operations.
     28 namespace {
     29 class RISCVDAGToDAGISel final : public SelectionDAGISel {
     30   const RISCVSubtarget *Subtarget;
     31 
     32 public:
     33   explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine)
     34       : SelectionDAGISel(TargetMachine) {}
     35 
     36   StringRef getPassName() const override {
     37     return "RISCV DAG->DAG Pattern Instruction Selection";
     38   }
     39 
     40   bool runOnMachineFunction(MachineFunction &MF) override {
     41     Subtarget = &MF.getSubtarget<RISCVSubtarget>();
     42     return SelectionDAGISel::runOnMachineFunction(MF);
     43   }
     44 
     45   void PostprocessISelDAG() override;
     46 
     47   void Select(SDNode *Node) override;
     48 
     49   bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
     50                                     std::vector<SDValue> &OutOps) override;
     51 
     52   bool SelectAddrFI(SDValue Addr, SDValue &Base);
     53 
     54 // Include the pieces autogenerated from the target description.
     55 #include "RISCVGenDAGISel.inc"
     56 
     57 private:
     58   void doPeepholeLoadStoreADDI();
     59   void doPeepholeBuildPairF64SplitF64();
     60 };
     61 }
     62 
     63 void RISCVDAGToDAGISel::PostprocessISelDAG() {
     64   doPeepholeLoadStoreADDI();
     65   doPeepholeBuildPairF64SplitF64();
     66 }
     67 
     68 void RISCVDAGToDAGISel::Select(SDNode *Node) {
     69   unsigned Opcode = Node->getOpcode();
     70   MVT XLenVT = Subtarget->getXLenVT();
     71 
     72   // If we have a custom node, we have already selected
     73   if (Node->isMachineOpcode()) {
     74     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
     75     Node->setNodeId(-1);
     76     return;
     77   }
     78 
     79   // Instruction Selection not handled by the auto-generated tablegen selection
     80   // should be handled here.
     81   EVT VT = Node->getValueType(0);
     82   if (Opcode == ISD::Constant && VT == XLenVT) {
     83     auto *ConstNode = cast<ConstantSDNode>(Node);
     84     // Materialize zero constants as copies from X0. This allows the coalescer
     85     // to propagate these into other instructions.
     86     if (ConstNode->isNullValue()) {
     87       SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
     88                                            RISCV::X0, XLenVT);
     89       ReplaceNode(Node, New.getNode());
     90       return;
     91     }
     92   }
     93   if (Opcode == ISD::FrameIndex) {
     94     SDLoc DL(Node);
     95     SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
     96     int FI = cast<FrameIndexSDNode>(Node)->getIndex();
     97     EVT VT = Node->getValueType(0);
     98     SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
     99     ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
    100     return;
    101   }
    102 
    103   // Select the default instruction.
    104   SelectCode(Node);
    105 }
    106 
    107 bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
    108     const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
    109   switch (ConstraintID) {
    110   case InlineAsm::Constraint_i:
    111   case InlineAsm::Constraint_m:
    112     // We just support simple memory operands that have a single address
    113     // operand and need no special handling.
    114     OutOps.push_back(Op);
    115     return false;
    116   default:
    117     break;
    118   }
    119 
    120   return true;
    121 }
    122 
    123 bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
    124   if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
    125     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
    126     return true;
    127   }
    128   return false;
    129 }
    130 
    131 // Merge an ADDI into the offset of a load/store instruction where possible.
    132 // (load (add base, off), 0) -> (load base, off)
    133 // (store val, (add base, off)) -> (store val, base, off)
    134 void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
    135   SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
    136   ++Position;
    137 
    138   while (Position != CurDAG->allnodes_begin()) {
    139     SDNode *N = &*--Position;
    140     // Skip dead nodes and any non-machine opcodes.
    141     if (N->use_empty() || !N->isMachineOpcode())
    142       continue;
    143 
    144     int OffsetOpIdx;
    145     int BaseOpIdx;
    146 
    147     // Only attempt this optimisation for I-type loads and S-type stores.
    148     switch (N->getMachineOpcode()) {
    149     default:
    150       continue;
    151     case RISCV::LB:
    152     case RISCV::LH:
    153     case RISCV::LW:
    154     case RISCV::LBU:
    155     case RISCV::LHU:
    156     case RISCV::LWU:
    157     case RISCV::LD:
    158     case RISCV::FLW:
    159     case RISCV::FLD:
    160       BaseOpIdx = 0;
    161       OffsetOpIdx = 1;
    162       break;
    163     case RISCV::SB:
    164     case RISCV::SH:
    165     case RISCV::SW:
    166     case RISCV::SD:
    167     case RISCV::FSW:
    168     case RISCV::FSD:
    169       BaseOpIdx = 1;
    170       OffsetOpIdx = 2;
    171       break;
    172     }
    173 
    174     // Currently, the load/store offset must be 0 to be considered for this
    175     // peephole optimisation.
    176     if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)) ||
    177         N->getConstantOperandVal(OffsetOpIdx) != 0)
    178       continue;
    179 
    180     SDValue Base = N->getOperand(BaseOpIdx);
    181 
    182     // If the base is an ADDI, we can merge it in to the load/store.
    183     if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
    184       continue;
    185 
    186     SDValue ImmOperand = Base.getOperand(1);
    187 
    188     if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
    189       ImmOperand = CurDAG->getTargetConstant(
    190           Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType());
    191     } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
    192       ImmOperand = CurDAG->getTargetGlobalAddress(
    193           GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
    194           GA->getOffset(), GA->getTargetFlags());
    195     } else {
    196       continue;
    197     }
    198 
    199     LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase:    ");
    200     LLVM_DEBUG(Base->dump(CurDAG));
    201     LLVM_DEBUG(dbgs() << "\nN: ");
    202     LLVM_DEBUG(N->dump(CurDAG));
    203     LLVM_DEBUG(dbgs() << "\n");
    204 
    205     // Modify the offset operand of the load/store.
    206     if (BaseOpIdx == 0) // Load
    207       CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
    208                                  N->getOperand(2));
    209     else // Store
    210       CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
    211                                  ImmOperand, N->getOperand(3));
    212 
    213     // The add-immediate may now be dead, in which case remove it.
    214     if (Base.getNode()->use_empty())
    215       CurDAG->RemoveDeadNode(Base.getNode());
    216   }
    217 }
    218 
    219 // Remove redundant BuildPairF64+SplitF64 pairs. i.e. cases where an f64 is
    220 // built of two i32 values, only to be split apart again. This must be done
    221 // here as a peephole optimisation as the DAG has not been fully legalized at
    222 // the point BuildPairF64/SplitF64 nodes are created in RISCVISelLowering, so
    223 // some nodes would not yet have been replaced with libcalls.
    224 void RISCVDAGToDAGISel::doPeepholeBuildPairF64SplitF64() {
    225   SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
    226   ++Position;
    227 
    228   while (Position != CurDAG->allnodes_begin()) {
    229     SDNode *N = &*--Position;
    230     // Skip dead nodes and any nodes other than SplitF64Pseudo.
    231     if (N->use_empty() || !N->isMachineOpcode() ||
    232         !(N->getMachineOpcode() == RISCV::SplitF64Pseudo))
    233       continue;
    234 
    235     // If the operand to SplitF64 is a BuildPairF64, the split operation is
    236     // redundant. Just use the operands to BuildPairF64 as the result.
    237     SDValue F64Val = N->getOperand(0);
    238     if (F64Val.isMachineOpcode() &&
    239         F64Val.getMachineOpcode() == RISCV::BuildPairF64Pseudo) {
    240       LLVM_DEBUG(
    241           dbgs() << "Removing redundant SplitF64Pseudo and replacing uses "
    242                     "with BuildPairF64Pseudo operands:\n");
    243       LLVM_DEBUG(dbgs() << "N:    ");
    244       LLVM_DEBUG(N->dump(CurDAG));
    245       LLVM_DEBUG(dbgs() << "F64Val: ");
    246       LLVM_DEBUG(F64Val->dump(CurDAG));
    247       LLVM_DEBUG(dbgs() << "\n");
    248       SDValue From[] = {SDValue(N, 0), SDValue(N, 1)};
    249       SDValue To[] = {F64Val.getOperand(0), F64Val.getOperand(1)};
    250       CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
    251     }
    252   }
    253   CurDAG->RemoveDeadNodes();
    254 }
    255 
    256 // This pass converts a legalized DAG into a RISCV-specific DAG, ready
    257 // for instruction scheduling.
    258 FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
    259   return new RISCVDAGToDAGISel(TM);
    260 }
    261