1//===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an instruction selector for the Lanai target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "LanaiAluCode.h"
14#include "LanaiMachineFunctionInfo.h"
15#include "LanaiRegisterInfo.h"
16#include "LanaiSubtarget.h"
17#include "LanaiTargetMachine.h"
18#include "llvm/CodeGen/MachineConstantPool.h"
19#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineFunction.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
22#include "llvm/CodeGen/MachineRegisterInfo.h"
23#include "llvm/CodeGen/SelectionDAGISel.h"
24#include "llvm/IR/CFG.h"
25#include "llvm/IR/GlobalValue.h"
26#include "llvm/IR/Instructions.h"
27#include "llvm/IR/Intrinsics.h"
28#include "llvm/IR/Type.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/raw_ostream.h"
32#include "llvm/Target/TargetMachine.h"
33
34using namespace llvm;
35
36#define DEBUG_TYPE "lanai-isel"
37
38//===----------------------------------------------------------------------===//
39// Instruction Selector Implementation
40//===----------------------------------------------------------------------===//
41
42//===----------------------------------------------------------------------===//
43// LanaiDAGToDAGISel - Lanai specific code to select Lanai machine
44// instructions for SelectionDAG operations.
45//===----------------------------------------------------------------------===//
46namespace {
47
48class LanaiDAGToDAGISel : public SelectionDAGISel {
49public:
50  explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
51      : SelectionDAGISel(TargetMachine) {}
52
53  bool runOnMachineFunction(MachineFunction &MF) override {
54    return SelectionDAGISel::runOnMachineFunction(MF);
55  }
56
57  // Pass Name
58  StringRef getPassName() const override {
59    return "Lanai DAG->DAG Pattern Instruction Selection";
60  }
61
62  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
63                                    std::vector<SDValue> &OutOps) override;
64
65private:
66// Include the pieces autogenerated from the target description.
67#include "LanaiGenDAGISel.inc"
68
69  // Instruction Selection not handled by the auto-generated tablgen
70  void Select(SDNode *N) override;
71
72  // Support functions for the opcodes of Instruction Selection
73  // not handled by the auto-generated tablgen
74  void selectFrameIndex(SDNode *N);
75
76  // Complex Pattern for address selection.
77  bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset,
78                    SDValue &AluOp);
79  bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp);
80  bool selectAddrSls(SDValue Addr, SDValue &Offset);
81  bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
82                      SDValue &AluOp);
83
84  // getI32Imm - Return a target constant with the specified value, of type i32.
85  inline SDValue getI32Imm(unsigned Imm, const SDLoc &DL) {
86    return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
87  }
88
89private:
90  bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
91                        SDValue &AluOp, bool RiMode);
92};
93
94bool canBeRepresentedAsSls(const ConstantSDNode &CN) {
95  // Fits in 21-bit signed immediate and two low-order bits are zero.
96  return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0);
97}
98
99} // namespace
100
101// Helper functions for ComplexPattern used on LanaiInstrInfo
102// Used on Lanai Load/Store instructions.
103bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
104  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
105    SDLoc DL(Addr);
106    // Loading from a constant address.
107    if (canBeRepresentedAsSls(*CN)) {
108      int32_t Imm = CN->getSExtValue();
109      Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
110      return true;
111    }
112  }
113  if (Addr.getOpcode() == ISD::OR &&
114      Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
115    Offset = Addr.getOperand(1).getOperand(0);
116    return true;
117  }
118  return false;
119}
120
121bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base,
122                                         SDValue &Offset, SDValue &AluOp,
123                                         bool RiMode) {
124  SDLoc DL(Addr);
125
126  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
127    if (RiMode) {
128      // Fits in 16-bit signed immediate.
129      if (isInt<16>(CN->getSExtValue())) {
130        int16_t Imm = CN->getSExtValue();
131        Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
132        Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
133        AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
134        return true;
135      }
136      // Allow SLS to match if the constant doesn't fit in 16 bits but can be
137      // represented as an SLS.
138      if (canBeRepresentedAsSls(*CN))
139        return false;
140    } else {
141      // Fits in 10-bit signed immediate.
142      if (isInt<10>(CN->getSExtValue())) {
143        int16_t Imm = CN->getSExtValue();
144        Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
145        Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
146        AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
147        return true;
148      }
149    }
150  }
151
152  // if Address is FI, get the TargetFrameIndex.
153  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
154    Base = CurDAG->getTargetFrameIndex(
155        FIN->getIndex(),
156        getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
157    Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
158    AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
159    return true;
160  }
161
162  // Skip direct calls
163  if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
164       Addr.getOpcode() == ISD::TargetGlobalAddress))
165    return false;
166
167  // Address of the form imm + reg
168  ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
169  if (AluOperator == ISD::ADD) {
170    AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
171    // Addresses of the form FI+const
172    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
173      if ((RiMode && isInt<16>(CN->getSExtValue())) ||
174          (!RiMode && isInt<10>(CN->getSExtValue()))) {
175        // If the first operand is a FI, get the TargetFI Node
176        if (FrameIndexSDNode *FIN =
177                dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
178          Base = CurDAG->getTargetFrameIndex(
179              FIN->getIndex(),
180              getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
181        } else {
182          Base = Addr.getOperand(0);
183        }
184
185        Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i32);
186        return true;
187      }
188  }
189
190  // Let SLS match SMALL instead of RI.
191  if (AluOperator == ISD::OR && RiMode &&
192      Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
193    return false;
194
195  Base = Addr;
196  Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
197  AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
198  return true;
199}
200
201bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
202                                     SDValue &Offset, SDValue &AluOp) {
203  return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true);
204}
205
206bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
207                                       SDValue &Offset, SDValue &AluOp) {
208  return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
209}
210
211bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2,
212                                     SDValue &AluOp) {
213  // if Address is FI, get the TargetFrameIndex.
214  if (Addr.getOpcode() == ISD::FrameIndex)
215    return false;
216
217  // Skip direct calls
218  if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
219       Addr.getOpcode() == ISD::TargetGlobalAddress))
220    return false;
221
222  // Address of the form OP + OP
223  ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
224  LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(AluOperator);
225  if (AluCode != LPAC::UNKNOWN) {
226    // Skip addresses of the form FI OP const
227    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
228      if (isInt<16>(CN->getSExtValue()))
229        return false;
230
231    // Skip addresses with hi/lo operands
232    if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
233        Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
234        Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
235        Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
236        Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
237        Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
238      return false;
239
240    // Addresses of the form register OP register
241    R1 = Addr.getOperand(0);
242    R2 = Addr.getOperand(1);
243    AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32);
244    return true;
245  }
246
247  // Skip addresses with zero offset
248  return false;
249}
250
251bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand(
252    const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) {
253  SDValue Op0, Op1, AluOp;
254  switch (ConstraintCode) {
255  default:
256    return true;
257  case InlineAsm::Constraint_m: // memory
258    if (!selectAddrRr(Op, Op0, Op1, AluOp) &&
259        !selectAddrRi(Op, Op0, Op1, AluOp))
260      return true;
261    break;
262  }
263
264  OutOps.push_back(Op0);
265  OutOps.push_back(Op1);
266  OutOps.push_back(AluOp);
267  return false;
268}
269
270// Select instructions not customized! Used for
271// expanded, promoted and normal instructions
272void LanaiDAGToDAGISel::Select(SDNode *Node) {
273  unsigned Opcode = Node->getOpcode();
274
275  // If we have a custom node, we already have selected!
276  if (Node->isMachineOpcode()) {
277    LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
278    return;
279  }
280
281  // Instruction Selection not handled by the auto-generated tablegen selection
282  // should be handled here.
283  EVT VT = Node->getValueType(0);
284  switch (Opcode) {
285  case ISD::Constant:
286    if (VT == MVT::i32) {
287      ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node);
288      // Materialize zero constants as copies from R0. This allows the coalescer
289      // to propagate these into other instructions.
290      if (ConstNode->isNullValue()) {
291        SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
292                                             SDLoc(Node), Lanai::R0, MVT::i32);
293        return ReplaceNode(Node, New.getNode());
294      }
295      // Materialize all ones constants as copies from R1. This allows the
296      // coalescer to propagate these into other instructions.
297      if (ConstNode->isAllOnesValue()) {
298        SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
299                                             SDLoc(Node), Lanai::R1, MVT::i32);
300        return ReplaceNode(Node, New.getNode());
301      }
302    }
303    break;
304  case ISD::FrameIndex:
305    selectFrameIndex(Node);
306    return;
307  default:
308    break;
309  }
310
311  // Select the default instruction
312  SelectCode(Node);
313}
314
315void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
316  SDLoc DL(Node);
317  SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
318  int FI = cast<FrameIndexSDNode>(Node)->getIndex();
319  EVT VT = Node->getValueType(0);
320  SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
321  unsigned Opc = Lanai::ADD_I_LO;
322  if (Node->hasOneUse()) {
323    CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
324    return;
325  }
326  ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm));
327}
328
329// createLanaiISelDag - This pass converts a legalized DAG into a
330// Lanai-specific DAG, ready for instruction scheduling.
331FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) {
332  return new LanaiDAGToDAGISel(TM);
333}
334