1 //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===//
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 ARC target.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "ARC.h"
14 #include "ARCTargetMachine.h"
15 #include "llvm/CodeGen/MachineFrameInfo.h"
16 #include "llvm/CodeGen/MachineFunction.h"
17 #include "llvm/CodeGen/MachineInstrBuilder.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19 #include "llvm/CodeGen/SelectionDAG.h"
20 #include "llvm/CodeGen/SelectionDAGISel.h"
21 #include "llvm/CodeGen/TargetLowering.h"
22 #include "llvm/IR/CallingConv.h"
23 #include "llvm/IR/Constants.h"
24 #include "llvm/IR/DerivedTypes.h"
25 #include "llvm/IR/Function.h"
26 #include "llvm/IR/Intrinsics.h"
27 #include "llvm/IR/LLVMContext.h"
28 #include "llvm/Support/Compiler.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/raw_ostream.h"
32
33 using namespace llvm;
34
35 #define DEBUG_TYPE "arc-isel"
36 #define PASS_NAME "ARC DAG->DAG Pattern Instruction Selection"
37
38 /// ARCDAGToDAGISel - ARC specific code to select ARC machine
39 /// instructions for SelectionDAG operations.
40 namespace {
41
42 class ARCDAGToDAGISel : public SelectionDAGISel {
43 public:
44 ARCDAGToDAGISel() = delete;
45
ARCDAGToDAGISel(ARCTargetMachine & TM,CodeGenOptLevel OptLevel)46 ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
47 : SelectionDAGISel(TM, OptLevel) {}
48
49 void Select(SDNode *N) override;
50
51 // Complex Pattern Selectors.
52 bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
53 bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
54 bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
55 bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
56
57 // Include the pieces autogenerated from the target description.
58 #include "ARCGenDAGISel.inc"
59 };
60
61 class ARCDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
62 public:
63 static char ID;
ARCDAGToDAGISelLegacy(ARCTargetMachine & TM,CodeGenOptLevel OptLevel)64 explicit ARCDAGToDAGISelLegacy(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
65 : SelectionDAGISelLegacy(
66 ID, std::make_unique<ARCDAGToDAGISel>(TM, OptLevel)) {}
67 };
68
69 char ARCDAGToDAGISelLegacy::ID;
70
71 } // end anonymous namespace
72
INITIALIZE_PASS(ARCDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)73 INITIALIZE_PASS(ARCDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
74
75 /// This pass converts a legalized DAG into a ARC-specific DAG, ready for
76 /// instruction scheduling.
77 FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
78 CodeGenOptLevel OptLevel) {
79 return new ARCDAGToDAGISelLegacy(TM, OptLevel);
80 }
81
SelectAddrModeImm(SDValue Addr,SDValue & Base,SDValue & Offset)82 bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
83 SDValue &Offset) {
84 if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
85 Base = Addr.getOperand(0);
86 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
87 return true;
88 }
89 return false;
90 }
91
SelectAddrModeS9(SDValue Addr,SDValue & Base,SDValue & Offset)92 bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
93 SDValue &Offset) {
94 if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
95 return false;
96 }
97
98 if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
99 !CurDAG->isBaseWithConstantOffset(Addr)) {
100 if (Addr.getOpcode() == ISD::FrameIndex) {
101 // Match frame index.
102 int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
103 Base = CurDAG->getTargetFrameIndex(
104 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
105 } else {
106 Base = Addr;
107 }
108 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
109 return true;
110 }
111
112 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
113 int32_t RHSC = RHS->getSExtValue();
114 if (Addr.getOpcode() == ISD::SUB)
115 RHSC = -RHSC;
116
117 // Do we need more than 9 bits to encode?
118 if (!isInt<9>(RHSC))
119 return false;
120 Base = Addr.getOperand(0);
121 if (Base.getOpcode() == ISD::FrameIndex) {
122 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
123 Base = CurDAG->getTargetFrameIndex(
124 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
125 }
126 Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
127 return true;
128 }
129 Base = Addr;
130 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
131 return true;
132 }
133
SelectAddrModeFar(SDValue Addr,SDValue & Base,SDValue & Offset)134 bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
135 SDValue &Offset) {
136 if (SelectAddrModeS9(Addr, Base, Offset))
137 return false;
138 if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
139 return false;
140 }
141 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
142 int32_t RHSC = RHS->getSExtValue();
143 if (Addr.getOpcode() == ISD::SUB)
144 RHSC = -RHSC;
145 Base = Addr.getOperand(0);
146 Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
147 return true;
148 }
149 return false;
150 }
151
152 // Is this a legal frame index addressing expression.
SelectFrameADDR_ri(SDValue Addr,SDValue & Base,SDValue & Offset)153 bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
154 SDValue &Offset) {
155 FrameIndexSDNode *FIN = nullptr;
156 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
157 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
158 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
159 return true;
160 }
161 if (Addr.getOpcode() == ISD::ADD) {
162 ConstantSDNode *CN = nullptr;
163 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
164 (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
165 (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
166 // Constant positive word offset from frame index
167 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
168 Offset =
169 CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
170 return true;
171 }
172 }
173 return false;
174 }
175
Select(SDNode * N)176 void ARCDAGToDAGISel::Select(SDNode *N) {
177 switch (N->getOpcode()) {
178 case ISD::Constant: {
179 uint64_t CVal = N->getAsZExtVal();
180 ReplaceNode(N, CurDAG->getMachineNode(
181 isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
182 SDLoc(N), MVT::i32,
183 CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
184 return;
185 }
186 }
187 SelectCode(N);
188 }
189