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 doPeepholeGlobalAddiLuiOffset();
60   void doPeepholeBuildPairF64SplitF64();
61 };
62 }
63 
64 void RISCVDAGToDAGISel::PostprocessISelDAG() {
65   doPeepholeLoadStoreADDI();
66   doPeepholeGlobalAddiLuiOffset();
67   doPeepholeBuildPairF64SplitF64();
68 }
69 
70 void RISCVDAGToDAGISel::Select(SDNode *Node) {
71   unsigned Opcode = Node->getOpcode();
72   MVT XLenVT = Subtarget->getXLenVT();
73 
74   // If we have a custom node, we have already selected
75   if (Node->isMachineOpcode()) {
76     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
77     Node->setNodeId(-1);
78     return;
79   }
80 
81   // Instruction Selection not handled by the auto-generated tablegen selection
82   // should be handled here.
83   EVT VT = Node->getValueType(0);
84   if (Opcode == ISD::Constant && VT == XLenVT) {
85     auto *ConstNode = cast<ConstantSDNode>(Node);
86     // Materialize zero constants as copies from X0. This allows the coalescer
87     // to propagate these into other instructions.
88     if (ConstNode->isNullValue()) {
89       SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
90                                            RISCV::X0, XLenVT);
91       ReplaceNode(Node, New.getNode());
92       return;
93     }
94   }
95   if (Opcode == ISD::FrameIndex) {
96     SDLoc DL(Node);
97     SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
98     int FI = cast<FrameIndexSDNode>(Node)->getIndex();
99     EVT VT = Node->getValueType(0);
100     SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
101     ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
102     return;
103   }
104 
105   // Select the default instruction.
106   SelectCode(Node);
107 }
108 
109 bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
110     const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
111   switch (ConstraintID) {
112   case InlineAsm::Constraint_i:
113   case InlineAsm::Constraint_m:
114     // We just support simple memory operands that have a single address
115     // operand and need no special handling.
116     OutOps.push_back(Op);
117     return false;
118   default:
119     break;
120   }
121 
122   return true;
123 }
124 
125 bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
126   if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
127     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
128     return true;
129   }
130   return false;
131 }
132 
133 // Detect the pattern lui %hi(global) --> ADDI %lo(global)
134 //                          HiLUI          LoADDI
135 static bool detectLuiAddiGlobal(SDNode *Tail, unsigned &Idx, SDValue &LoADDI,
136                                 SDValue &HiLUI, GlobalAddressSDNode *&GAlo,
137                                 GlobalAddressSDNode *&GAhi) {
138   // Try to detect the pattern on every operand of the tail instruction.
139   for (Idx = 0; Idx < Tail->getNumOperands(); Idx++) {
140     LoADDI = Tail->getOperand(Idx);
141     // LoADDI should only be used by one instruction (Tail).
142     if (!LoADDI->isMachineOpcode() ||
143         !(LoADDI->getMachineOpcode() == RISCV::ADDI) ||
144         !isa<GlobalAddressSDNode>(LoADDI->getOperand(1)) ||
145         !LoADDI->hasOneUse())
146       continue;
147     // Check for existence of %lo target flag.
148     GAlo = cast<GlobalAddressSDNode>(LoADDI->getOperand(1));
149     if (!(GAlo->getTargetFlags() == RISCVII::MO_LO) ||
150         !(GAlo->getOffset() == 0))
151       return false;
152     // Check for existence of %hi target flag.
153     HiLUI = LoADDI->getOperand(0);
154     if (!HiLUI->isMachineOpcode() ||
155         !(HiLUI->getMachineOpcode() == RISCV::LUI) ||
156         !isa<GlobalAddressSDNode>(HiLUI->getOperand(0)) || !HiLUI->hasOneUse())
157       return false;
158     GAhi = cast<GlobalAddressSDNode>(HiLUI->getOperand(0));
159     if (!(GAhi->getTargetFlags() == RISCVII::MO_HI) ||
160         !(GAhi->getOffset() == 0))
161       return false;
162     return true;
163   }
164   return false;
165 }
166 
167 static bool matchLuiOffset(SDValue &OffsetLUI, int64_t &Offset) {
168   if (!OffsetLUI->isMachineOpcode() ||
169       !(OffsetLUI->getMachineOpcode() == RISCV::LUI) ||
170       !isa<ConstantSDNode>(OffsetLUI->getOperand(0)))
171     return false;
172   Offset = cast<ConstantSDNode>(OffsetLUI->getOperand(0))->getSExtValue();
173   Offset = Offset << 12;
174   LLVM_DEBUG(dbgs() << " Detected \" LUI Offset_hi\"\n");
175   return true;
176 }
177 
178 static bool matchAddiLuiOffset(SDValue &OffsetLoADDI, int64_t &Offset) {
179   // LoADDI should only be used by the tail instruction only.
180   if (!OffsetLoADDI->isMachineOpcode() ||
181       !(OffsetLoADDI->getMachineOpcode() == RISCV::ADDI) ||
182       !isa<ConstantSDNode>(OffsetLoADDI->getOperand(1)) ||
183       !OffsetLoADDI->hasOneUse())
184     return false;
185   int64_t OffLo =
186       cast<ConstantSDNode>(OffsetLoADDI->getOperand(1))->getZExtValue();
187   // HiLUI should only be used by the loADDI.
188   SDValue OffsetHiLUI = (OffsetLoADDI->getOperand(0));
189   if (!OffsetHiLUI->isMachineOpcode() ||
190       !(OffsetHiLUI->getMachineOpcode() == RISCV::LUI) ||
191       !isa<ConstantSDNode>(OffsetHiLUI->getOperand(0)) ||
192       !OffsetHiLUI->hasOneUse())
193     return false;
194   int64_t OffHi =
195       cast<ConstantSDNode>(OffsetHiLUI->getOperand(0))->getSExtValue();
196   Offset = (OffHi << 12) + OffLo;
197   LLVM_DEBUG(dbgs() << " Detected \" ADDI (LUI Offset_hi), Offset_lo\"\n");
198   return true;
199 }
200 
201 static void updateTailInstrUsers(SDNode *Tail, SelectionDAG *CurDAG,
202                                  GlobalAddressSDNode *GAhi,
203                                  GlobalAddressSDNode *GAlo,
204                                  SDValue &GlobalHiLUI, SDValue &GlobalLoADDI,
205                                  int64_t Offset) {
206   // Update the offset in GAhi and GAlo.
207   SDLoc DL(Tail->getOperand(1));
208   SDValue GAHiNew = CurDAG->getTargetGlobalAddress(GAhi->getGlobal(), DL,
209                                                    GlobalHiLUI.getValueType(),
210                                                    Offset, RISCVII::MO_HI);
211   SDValue GALoNew = CurDAG->getTargetGlobalAddress(GAlo->getGlobal(), DL,
212                                                    GlobalLoADDI.getValueType(),
213                                                    Offset, RISCVII::MO_LO);
214   CurDAG->UpdateNodeOperands(GlobalHiLUI.getNode(), GAHiNew);
215   CurDAG->UpdateNodeOperands(GlobalLoADDI.getNode(), GlobalHiLUI, GALoNew);
216   // Update all uses of the Tail with the GlobalLoADDI. After
217   // this Tail will be a dead node.
218   SDValue From = SDValue(Tail, 0);
219   CurDAG->ReplaceAllUsesOfValuesWith(&From, &GlobalLoADDI, 1);
220 }
221 
222 // TODO: This transformation might be better implemeted in a Machine Funtion
223 // Pass as discussed here: https://reviews.llvm.org/D45748.
224 //
225 // Merge the offset of address calculation into the offset field
226 // of a global address node in a global address lowering sequence ("LUI
227 // %hi(global) --> add %lo(global)") under the following conditions: 1) The
228 // offset field in the global address lowering sequence is zero. 2) The lowered
229 // global address is only used in one node, referred to as "Tail".
230 
231 // This peephole does the following transformations to merge the offset:
232 
233 // 1) ADDI (ADDI (LUI %hi(global)) %lo(global)), offset
234 //     --->
235 //      ADDI (LUI %hi(global + offset)) %lo(global + offset).
236 //
237 //  This generates:
238 //  lui a0, hi (global + offset)
239 //  add a0, a0, lo (global + offset)
240 //  Instead of
241 //  lui a0, hi (global)
242 //  addi a0, hi (global)
243 //  addi a0, offset
244 // This pattern is for cases when the offset is small enough to fit in the
245 // immediate filed of ADDI (less than 12 bits).
246 
247 // 2) ADD ((ADDI (LUI %hi(global)) %lo(global)), (LUI hi_offset))
248 //   --->
249 //    offset = hi_offset << 12
250 //    ADDI (LUI %hi(global + offset)) %lo(global + offset)
251 
252 //  Which generates the ASM:
253 //  lui  a0, hi(global + offset)
254 //  addi a0, lo(global + offset)
255 // Instead of:
256 //  lui  a0, hi(global)
257 //  addi a0, lo(global)
258 //  lui a1, (offset)
259 //  add a0, a0, a1
260 
261 // This pattern is for cases when the offset doesn't fit in an immediate field
262 // of ADDI but the lower 12 bits are all zeros.
263 
264 // 3) ADD ((ADDI (LUI %hi(global)) %lo(global)), (ADDI lo_offset, (LUI
265 // hi_offset)))
266 //     --->
267 //        ADDI (LUI %hi(global + offset)) %lo(global + offset)
268 // Which generates the ASM:
269 // lui  a1, %hi(global + offhi20<<12 + offlo12)
270 // addi a1, %lo(global + offhi20<<12 + offlo12)
271 // Instead of:
272 //  lui  a0, hi(global)
273 //  addi a0, lo(global)
274 //  lui a1, (offhi20)
275 //  addi a1, (offlo12)
276 //  add a0, a0, a1
277 // This pattern is for cases when the offset doesn't fit in an immediate field
278 // of ADDI and both the lower 1 bits and high 20 bits are non zero.
279 void RISCVDAGToDAGISel::doPeepholeGlobalAddiLuiOffset() {
280   SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
281   ++Position;
282   SelectionDAG::allnodes_iterator Begin(CurDAG->allnodes_begin());
283   while (Position != Begin) {
284     SDNode *Tail = &*--Position;
285     // Skip dead nodes and any non-machine opcodes.
286     if (Tail->use_empty() || !Tail->isMachineOpcode())
287       continue;
288     // The tail instruction can be an ADD or an ADDI.
289     if (!Tail->isMachineOpcode() || !(Tail->getMachineOpcode() == RISCV::ADD ||
290                                       Tail->getMachineOpcode() == RISCV::ADDI))
291       continue;
292     // First detect the global address part of pattern:
293     // (lui %hi(global) --> Addi %lo(global))
294     unsigned GlobalLoADDiIdx;
295     SDValue GlobalLoADDI;
296     SDValue GlobalHiLUI;
297     GlobalAddressSDNode *GAhi;
298     GlobalAddressSDNode *GAlo;
299     if (!detectLuiAddiGlobal(Tail, GlobalLoADDiIdx, GlobalLoADDI, GlobalHiLUI,
300                              GAlo, GAhi))
301       continue;
302     LLVM_DEBUG(dbgs() << " Detected \"ADDI LUI %hi(global), %lo(global)\n");
303     // Detect the offset part for the address calculation by looking at the
304     // other operand of the tail instruction:
305     int64_t Offset;
306     if (Tail->getMachineOpcode() == RISCV::ADD) {
307       // If the Tail is an ADD instruction, the offset can be in two forms:
308       // 1) LUI hi_Offset followed by:
309       //    ADDI lo_offset
310       //    This happens in case the offset has non zero bits in
311       //    both hi 20 and lo 12 bits.
312       // 2) LUI (offset20)
313       //    This happens in case the lower 12 bits of the offset are zeros.
314       SDValue OffsetVal = Tail->getOperand(1 - GlobalLoADDiIdx);
315       if (!matchAddiLuiOffset(OffsetVal, Offset) &&
316           !matchLuiOffset(OffsetVal, Offset))
317         continue;
318     } else
319       // The Tail is an ADDI instruction:
320       Offset = cast<ConstantSDNode>(Tail->getOperand(1 - GlobalLoADDiIdx))
321                    ->getSExtValue();
322 
323     LLVM_DEBUG(
324         dbgs()
325         << " Fold offset value into global offset of LUI %hi and ADDI %lo\n");
326     LLVM_DEBUG(dbgs() << "\tTail:");
327     LLVM_DEBUG(Tail->dump(CurDAG));
328     LLVM_DEBUG(dbgs() << "\tGlobalHiLUI:");
329     LLVM_DEBUG(GlobalHiLUI->dump(CurDAG));
330     LLVM_DEBUG(dbgs() << "\tGlobalLoADDI:");
331     LLVM_DEBUG(GlobalLoADDI->dump(CurDAG));
332     LLVM_DEBUG(dbgs() << "\n");
333     updateTailInstrUsers(Tail, CurDAG, GAhi, GAlo, GlobalHiLUI, GlobalLoADDI,
334                          Offset);
335   }
336   CurDAG->RemoveDeadNodes();
337 }
338 
339 // Merge an ADDI into the offset of a load/store instruction where possible.
340 // (load (add base, off), 0) -> (load base, off)
341 // (store val, (add base, off)) -> (store val, base, off)
342 void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
343   SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
344   ++Position;
345 
346   while (Position != CurDAG->allnodes_begin()) {
347     SDNode *N = &*--Position;
348     // Skip dead nodes and any non-machine opcodes.
349     if (N->use_empty() || !N->isMachineOpcode())
350       continue;
351 
352     int OffsetOpIdx;
353     int BaseOpIdx;
354 
355     // Only attempt this optimisation for I-type loads and S-type stores.
356     switch (N->getMachineOpcode()) {
357     default:
358       continue;
359     case RISCV::LB:
360     case RISCV::LH:
361     case RISCV::LW:
362     case RISCV::LBU:
363     case RISCV::LHU:
364     case RISCV::LWU:
365     case RISCV::LD:
366     case RISCV::FLW:
367     case RISCV::FLD:
368       BaseOpIdx = 0;
369       OffsetOpIdx = 1;
370       break;
371     case RISCV::SB:
372     case RISCV::SH:
373     case RISCV::SW:
374     case RISCV::SD:
375     case RISCV::FSW:
376     case RISCV::FSD:
377       BaseOpIdx = 1;
378       OffsetOpIdx = 2;
379       break;
380     }
381 
382     // Currently, the load/store offset must be 0 to be considered for this
383     // peephole optimisation.
384     if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)) ||
385         N->getConstantOperandVal(OffsetOpIdx) != 0)
386       continue;
387 
388     SDValue Base = N->getOperand(BaseOpIdx);
389 
390     // If the base is an ADDI, we can merge it in to the load/store.
391     if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
392       continue;
393 
394     SDValue ImmOperand = Base.getOperand(1);
395 
396     if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
397       ImmOperand = CurDAG->getTargetConstant(
398           Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType());
399     } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
400       ImmOperand = CurDAG->getTargetGlobalAddress(
401           GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
402           GA->getOffset(), GA->getTargetFlags());
403     } else {
404       continue;
405     }
406 
407     LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase:    ");
408     LLVM_DEBUG(Base->dump(CurDAG));
409     LLVM_DEBUG(dbgs() << "\nN: ");
410     LLVM_DEBUG(N->dump(CurDAG));
411     LLVM_DEBUG(dbgs() << "\n");
412 
413     // Modify the offset operand of the load/store.
414     if (BaseOpIdx == 0) // Load
415       CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
416                                  N->getOperand(2));
417     else // Store
418       CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
419                                  ImmOperand, N->getOperand(3));
420 
421     // The add-immediate may now be dead, in which case remove it.
422     if (Base.getNode()->use_empty())
423       CurDAG->RemoveDeadNode(Base.getNode());
424   }
425 }
426 
427 // Remove redundant BuildPairF64+SplitF64 pairs. i.e. cases where an f64 is
428 // built of two i32 values, only to be split apart again. This must be done
429 // here as a peephole optimisation as the DAG has not been fully legalized at
430 // the point BuildPairF64/SplitF64 nodes are created in RISCVISelLowering, so
431 // some nodes would not yet have been replaced with libcalls.
432 void RISCVDAGToDAGISel::doPeepholeBuildPairF64SplitF64() {
433   SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
434   ++Position;
435 
436   while (Position != CurDAG->allnodes_begin()) {
437     SDNode *N = &*--Position;
438     // Skip dead nodes and any nodes other than SplitF64Pseudo.
439     if (N->use_empty() || !N->isMachineOpcode() ||
440         !(N->getMachineOpcode() == RISCV::SplitF64Pseudo))
441       continue;
442 
443     // If the operand to SplitF64 is a BuildPairF64, the split operation is
444     // redundant. Just use the operands to BuildPairF64 as the result.
445     SDValue F64Val = N->getOperand(0);
446     if (F64Val.isMachineOpcode() &&
447         F64Val.getMachineOpcode() == RISCV::BuildPairF64Pseudo) {
448       LLVM_DEBUG(
449           dbgs() << "Removing redundant SplitF64Pseudo and replacing uses "
450                     "with BuildPairF64Pseudo operands:\n");
451       LLVM_DEBUG(dbgs() << "N:    ");
452       LLVM_DEBUG(N->dump(CurDAG));
453       LLVM_DEBUG(dbgs() << "F64Val: ");
454       LLVM_DEBUG(F64Val->dump(CurDAG));
455       LLVM_DEBUG(dbgs() << "\n");
456       SDValue From[] = {SDValue(N, 0), SDValue(N, 1)};
457       SDValue To[] = {F64Val.getOperand(0), F64Val.getOperand(1)};
458       CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
459     }
460   }
461   CurDAG->RemoveDeadNodes();
462 }
463 
464 // This pass converts a legalized DAG into a RISCV-specific DAG, ready
465 // for instruction scheduling.
466 FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
467   return new RISCVDAGToDAGISel(TM);
468 }
469