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:
RISCVDAGToDAGISel(RISCVTargetMachine & TargetMachine)33 explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine)
34 : SelectionDAGISel(TargetMachine) {}
35
getPassName() const36 StringRef getPassName() const override {
37 return "RISCV DAG->DAG Pattern Instruction Selection";
38 }
39
runOnMachineFunction(MachineFunction & MF)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
PostprocessISelDAG()63 void RISCVDAGToDAGISel::PostprocessISelDAG() {
64 doPeepholeLoadStoreADDI();
65 doPeepholeBuildPairF64SplitF64();
66 }
67
Select(SDNode * Node)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
SelectInlineAsmMemoryOperand(const SDValue & Op,unsigned ConstraintID,std::vector<SDValue> & OutOps)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
SelectAddrFI(SDValue Addr,SDValue & Base)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)
doPeepholeLoadStoreADDI()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.
doPeepholeBuildPairF64SplitF64()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.
createRISCVISelDag(RISCVTargetMachine & TM)258 FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
259 return new RISCVDAGToDAGISel(TM);
260 }
261