blob: 630439bb53c240bd0c707367ffa390343395ecf6 [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 Bradbury0b4175f2018-04-12 05:34:25 +000059 void doPeepholeBuildPairF64SplitF64();
Alex Bradbury89718422017-10-19 21:37:38 +000060};
61}
62
Alex Bradbury0b4175f2018-04-12 05:34:25 +000063void RISCVDAGToDAGISel::PostprocessISelDAG() {
64 doPeepholeLoadStoreADDI();
65 doPeepholeBuildPairF64SplitF64();
66}
Alex Bradbury0171a9f2018-03-19 11:54:28 +000067
Alex Bradbury89718422017-10-19 21:37:38 +000068void RISCVDAGToDAGISel::Select(SDNode *Node) {
Alex Bradbury0c7b3642017-11-21 08:23:08 +000069 unsigned Opcode = Node->getOpcode();
70 MVT XLenVT = Subtarget->getXLenVT();
71
Alex Bradbury89718422017-10-19 21:37:38 +000072 // If we have a custom node, we have already selected
73 if (Node->isMachineOpcode()) {
74 DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
75 Node->setNodeId(-1);
76 return;
77 }
78
Alex Bradbury0c7b3642017-11-21 08:23:08 +000079 // Instruction Selection not handled by the auto-generated tablegen selection
80 // should be handled here.
81 EVT VT = Node->getValueType(0);
Alex Bradbury9caefe32017-11-21 12:00:19 +000082 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;
Alex Bradbury0c7b3642017-11-21 08:23:08 +000091 }
Alex Bradbury0c7b3642017-11-21 08:23:08 +000092 }
Alex Bradbury660bcce2017-12-11 11:53:54 +000093 if (Opcode == ISD::FrameIndex) {
94 SDLoc DL(Node);
95 SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
96 int FI = dyn_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 }
Alex Bradbury0c7b3642017-11-21 08:23:08 +0000102
Alex Bradbury89718422017-10-19 21:37:38 +0000103 // Select the default instruction.
104 SelectCode(Node);
105}
106
Alex Bradbury9330e642018-01-10 20:05:09 +0000107bool 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
Alex Bradbury660bcce2017-12-11 11:53:54 +0000123bool 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
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000131// 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)
134void 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
Alex Bradbury099c7202018-04-18 19:02:31 +0000182 // If the base is an ADDI, we can merge it in to the load/store.
183 if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000184 continue;
185
Alex Bradbury099c7202018-04-18 19:02:31 +0000186 SDValue ImmOperand = Base.getOperand(1);
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000187
Alex Bradbury099c7202018-04-18 19:02:31 +0000188 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());
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000195 } else {
Alex Bradbury099c7202018-04-18 19:02:31 +0000196 continue;
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000197 }
198
Alex Bradbury099c7202018-04-18 19:02:31 +0000199 DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: ");
200 DEBUG(Base->dump(CurDAG));
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000201 DEBUG(dbgs() << "\nN: ");
202 DEBUG(N->dump(CurDAG));
203 DEBUG(dbgs() << "\n");
204
205 // Modify the offset operand of the load/store.
206 if (BaseOpIdx == 0) // Load
Alex Bradbury099c7202018-04-18 19:02:31 +0000207 CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
208 N->getOperand(2));
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000209 else // Store
Alex Bradbury099c7202018-04-18 19:02:31 +0000210 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());
Alex Bradbury0171a9f2018-03-19 11:54:28 +0000216 }
217}
218
Alex Bradbury0b4175f2018-04-12 05:34:25 +0000219// 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.
224void 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 DEBUG(dbgs() << "Removing redundant SplitF64Pseudo and replacing uses "
241 "with BuildPairF64Pseudo operands:\n");
242 DEBUG(dbgs() << "N: ");
243 DEBUG(N->dump(CurDAG));
244 DEBUG(dbgs() << "F64Val: ");
245 DEBUG(F64Val->dump(CurDAG));
246 DEBUG(dbgs() << "\n");
247 SDValue From[] = {SDValue(N, 0), SDValue(N, 1)};
248 SDValue To[] = {F64Val.getOperand(0), F64Val.getOperand(1)};
249 CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
250 }
251 }
252 CurDAG->RemoveDeadNodes();
253}
254
Alex Bradbury89718422017-10-19 21:37:38 +0000255// This pass converts a legalized DAG into a RISCV-specific DAG, ready
256// for instruction scheduling.
257FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
258 return new RISCVDAGToDAGISel(TM);
259}