blob: 9e64007dd81b9cae50bf3b1ee21384e43f537610 [file] [log] [blame]
Alex Bradbury89718422017-10-19 21:37:38 +00001//===-- 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"
Alex Bradbury660bcce2017-12-11 11:53:54 +000017#include "llvm/CodeGen/MachineFrameInfo.h"
Alex Bradbury89718422017-10-19 21:37:38 +000018#include "llvm/CodeGen/SelectionDAGISel.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/MathExtras.h"
21#include "llvm/Support/raw_ostream.h"
22using namespace llvm;
23
24#define DEBUG_TYPE "riscv-isel"
25
26// RISCV-specific code to select RISCV machine instructions for
27// SelectionDAG operations.
28namespace {
29class RISCVDAGToDAGISel final : public SelectionDAGISel {
Alex Bradbury0c7b3642017-11-21 08:23:08 +000030 const RISCVSubtarget *Subtarget;
31
Alex Bradbury89718422017-10-19 21:37:38 +000032public:
33 explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine)
34 : SelectionDAGISel(TargetMachine) {}
35
36 StringRef getPassName() const override {
37 return "RISCV DAG->DAG Pattern Instruction Selection";
38 }
39
Alex Bradbury0c7b3642017-11-21 08:23:08 +000040 bool runOnMachineFunction(MachineFunction &MF) override {
41 Subtarget = &MF.getSubtarget<RISCVSubtarget>();
42 return SelectionDAGISel::runOnMachineFunction(MF);
43 }
44
Alex Bradbury0171a9f2018-03-19 11:54:28 +000045 void PostprocessISelDAG() override;
46
Alex Bradbury89718422017-10-19 21:37:38 +000047 void Select(SDNode *Node) override;
48
Alex Bradbury9330e642018-01-10 20:05:09 +000049 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
50 std::vector<SDValue> &OutOps) override;
51
Alex Bradbury660bcce2017-12-11 11:53:54 +000052 bool SelectAddrFI(SDValue Addr, SDValue &Base);
53
Alex Bradbury89718422017-10-19 21:37:38 +000054// Include the pieces autogenerated from the target description.
55#include "RISCVGenDAGISel.inc"
Alex Bradbury0171a9f2018-03-19 11:54:28 +000056
57private:
58 void doPeepholeLoadStoreADDI();
Alex Bradbury89718422017-10-19 21:37:38 +000059};
60}
61
Alex Bradbury0171a9f2018-03-19 11:54:28 +000062void RISCVDAGToDAGISel::PostprocessISelDAG() { doPeepholeLoadStoreADDI(); }
63
Alex Bradbury89718422017-10-19 21:37:38 +000064void RISCVDAGToDAGISel::Select(SDNode *Node) {
Alex Bradbury0c7b3642017-11-21 08:23:08 +000065 unsigned Opcode = Node->getOpcode();
66 MVT XLenVT = Subtarget->getXLenVT();
67
Alex Bradbury89718422017-10-19 21:37:38 +000068 // If we have a custom node, we have already selected
69 if (Node->isMachineOpcode()) {
70 DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
71 Node->setNodeId(-1);
72 return;
73 }
74
Alex Bradbury0c7b3642017-11-21 08:23:08 +000075 // Instruction Selection not handled by the auto-generated tablegen selection
76 // should be handled here.
77 EVT VT = Node->getValueType(0);
Alex Bradbury9caefe32017-11-21 12:00:19 +000078 if (Opcode == ISD::Constant && VT == XLenVT) {
79 auto *ConstNode = cast<ConstantSDNode>(Node);
80 // Materialize zero constants as copies from X0. This allows the coalescer
81 // to propagate these into other instructions.
82 if (ConstNode->isNullValue()) {
83 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
84 RISCV::X0, XLenVT);
85 ReplaceNode(Node, New.getNode());
86 return;
Alex Bradbury0c7b3642017-11-21 08:23:08 +000087 }
Alex Bradbury0c7b3642017-11-21 08:23:08 +000088 }
Alex Bradbury660bcce2017-12-11 11:53:54 +000089 if (Opcode == ISD::FrameIndex) {
90 SDLoc DL(Node);
91 SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
92 int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
93 EVT VT = Node->getValueType(0);
94 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
95 ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
96 return;
97 }
Alex Bradbury0c7b3642017-11-21 08:23:08 +000098
Alex Bradbury89718422017-10-19 21:37:38 +000099 // Select the default instruction.
100 SelectCode(Node);
101}
102
Alex Bradbury9330e642018-01-10 20:05:09 +0000103bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
104 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
105 switch (ConstraintID) {
106 case InlineAsm::Constraint_i:
107 case InlineAsm::Constraint_m:
108 // We just support simple memory operands that have a single address
109 // operand and need no special handling.
110 OutOps.push_back(Op);
111 return false;
112 default:
113 break;
114 }
115
116 return true;
117}
118
Alex Bradbury660bcce2017-12-11 11:53:54 +0000119bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
120 if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
121 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
122 return true;
123 }
124 return false;
125}
126
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000127// Merge an ADDI into the offset of a load/store instruction where possible.
128// (load (add base, off), 0) -> (load base, off)
129// (store val, (add base, off)) -> (store val, base, off)
130void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
131 SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
132 ++Position;
133
134 while (Position != CurDAG->allnodes_begin()) {
135 SDNode *N = &*--Position;
136 // Skip dead nodes and any non-machine opcodes.
137 if (N->use_empty() || !N->isMachineOpcode())
138 continue;
139
140 int OffsetOpIdx;
141 int BaseOpIdx;
142
143 // Only attempt this optimisation for I-type loads and S-type stores.
144 switch (N->getMachineOpcode()) {
145 default:
146 continue;
147 case RISCV::LB:
148 case RISCV::LH:
149 case RISCV::LW:
150 case RISCV::LBU:
151 case RISCV::LHU:
152 case RISCV::LWU:
153 case RISCV::LD:
154 case RISCV::FLW:
155 case RISCV::FLD:
156 BaseOpIdx = 0;
157 OffsetOpIdx = 1;
158 break;
159 case RISCV::SB:
160 case RISCV::SH:
161 case RISCV::SW:
162 case RISCV::SD:
163 case RISCV::FSW:
164 case RISCV::FSD:
165 BaseOpIdx = 1;
166 OffsetOpIdx = 2;
167 break;
168 }
169
170 // Currently, the load/store offset must be 0 to be considered for this
171 // peephole optimisation.
172 if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)) ||
173 N->getConstantOperandVal(OffsetOpIdx) != 0)
174 continue;
175
176 SDValue Base = N->getOperand(BaseOpIdx);
177
178 // If the base is an ADDI, we can merge it in to the load/store.
179 if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
180 continue;
181
182 SDValue ImmOperand = Base.getOperand(1);
183
184 if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
185 ImmOperand = CurDAG->getTargetConstant(
186 Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType());
187 } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
188 ImmOperand = CurDAG->getTargetGlobalAddress(
189 GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
190 GA->getOffset(), GA->getTargetFlags());
191 } else {
192 continue;
193 }
194
195 DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: ");
196 DEBUG(Base->dump(CurDAG));
197 DEBUG(dbgs() << "\nN: ");
198 DEBUG(N->dump(CurDAG));
199 DEBUG(dbgs() << "\n");
200
201 // Modify the offset operand of the load/store.
202 if (BaseOpIdx == 0) // Load
203 CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
204 N->getOperand(2));
205 else // Store
206 CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
207 ImmOperand, N->getOperand(3));
208
209 // The add-immediate may now be dead, in which case remove it.
210 if (Base.getNode()->use_empty())
211 CurDAG->RemoveDeadNode(Base.getNode());
212 }
213}
214
Alex Bradbury89718422017-10-19 21:37:38 +0000215// This pass converts a legalized DAG into a RISCV-specific DAG, ready
216// for instruction scheduling.
217FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
218 return new RISCVDAGToDAGISel(TM);
219}