1 //===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
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 XCore target.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "XCore.h"
14 #include "XCoreTargetMachine.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/IntrinsicsXCore.h"
28 #include "llvm/IR/LLVMContext.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/raw_ostream.h"
32 using namespace llvm;
33
34 #define DEBUG_TYPE "xcore-isel"
35 #define PASS_NAME "XCore DAG->DAG Pattern Instruction Selection"
36
37 /// XCoreDAGToDAGISel - XCore specific code to select XCore machine
38 /// instructions for SelectionDAG operations.
39 ///
40 namespace {
41 class XCoreDAGToDAGISel : public SelectionDAGISel {
42
43 public:
44 XCoreDAGToDAGISel() = delete;
45
XCoreDAGToDAGISel(XCoreTargetMachine & TM,CodeGenOptLevel OptLevel)46 XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOptLevel OptLevel)
47 : SelectionDAGISel(TM, OptLevel) {}
48
49 void Select(SDNode *N) override;
50 bool tryBRIND(SDNode *N);
51
52 /// getI32Imm - Return a target constant with the specified value, of type
53 /// i32.
getI32Imm(unsigned Imm,const SDLoc & dl)54 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
55 return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
56 }
57
immMskBitp(SDNode * inN) const58 inline bool immMskBitp(SDNode *inN) const {
59 ConstantSDNode *N = cast<ConstantSDNode>(inN);
60 uint32_t value = (uint32_t)N->getZExtValue();
61 if (!isMask_32(value)) {
62 return false;
63 }
64 int msksize = llvm::bit_width(value);
65 return (msksize >= 1 && msksize <= 8) ||
66 msksize == 16 || msksize == 24 || msksize == 32;
67 }
68
69 // Complex Pattern Selectors.
70 bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
71
72 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
73 InlineAsm::ConstraintCode ConstraintID,
74 std::vector<SDValue> &OutOps) override;
75
76 // Include the pieces autogenerated from the target description.
77 #include "XCoreGenDAGISel.inc"
78 };
79
80 class XCoreDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
81 public:
82 static char ID;
XCoreDAGToDAGISelLegacy(XCoreTargetMachine & TM,CodeGenOptLevel OptLevel)83 explicit XCoreDAGToDAGISelLegacy(XCoreTargetMachine &TM,
84 CodeGenOptLevel OptLevel)
85 : SelectionDAGISelLegacy(
86 ID, std::make_unique<XCoreDAGToDAGISel>(TM, OptLevel)) {}
87 };
88 } // end anonymous namespace
89
90 char XCoreDAGToDAGISelLegacy::ID = 0;
91
INITIALIZE_PASS(XCoreDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)92 INITIALIZE_PASS(XCoreDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
93
94 /// createXCoreISelDag - This pass converts a legalized DAG into a
95 /// XCore-specific DAG, ready for instruction scheduling.
96 ///
97 FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
98 CodeGenOptLevel OptLevel) {
99 return new XCoreDAGToDAGISelLegacy(TM, OptLevel);
100 }
101
SelectADDRspii(SDValue Addr,SDValue & Base,SDValue & Offset)102 bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
103 SDValue &Offset) {
104 FrameIndexSDNode *FIN = nullptr;
105 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
106 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
107 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
108 return true;
109 }
110 if (Addr.getOpcode() == ISD::ADD) {
111 ConstantSDNode *CN = nullptr;
112 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
113 && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
114 && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
115 // Constant positive word offset from frame index
116 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
117 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr),
118 MVT::i32);
119 return true;
120 }
121 }
122 return false;
123 }
124
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)125 bool XCoreDAGToDAGISel::SelectInlineAsmMemoryOperand(
126 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
127 std::vector<SDValue> &OutOps) {
128 SDValue Reg;
129 switch (ConstraintID) {
130 default: return true;
131 case InlineAsm::ConstraintCode::m: // Memory.
132 switch (Op.getOpcode()) {
133 default: return true;
134 case XCoreISD::CPRelativeWrapper:
135 Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
136 break;
137 case XCoreISD::DPRelativeWrapper:
138 Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
139 break;
140 }
141 }
142 OutOps.push_back(Reg);
143 OutOps.push_back(Op.getOperand(0));
144 return false;
145 }
146
Select(SDNode * N)147 void XCoreDAGToDAGISel::Select(SDNode *N) {
148 SDLoc dl(N);
149 switch (N->getOpcode()) {
150 default: break;
151 case ISD::Constant: {
152 uint64_t Val = N->getAsZExtVal();
153 if (immMskBitp(N)) {
154 // Transformation function: get the size of a mask
155 // Look for the first non-zero bit
156 SDValue MskSize = getI32Imm(llvm::bit_width((uint32_t)Val), dl);
157 ReplaceNode(
158 N, CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize));
159 return;
160 }
161 else if (!isUInt<16>(Val)) {
162 SDValue CPIdx = CurDAG->getTargetConstantPool(
163 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
164 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
165 SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
166 MVT::Other, CPIdx,
167 CurDAG->getEntryNode());
168 MachineMemOperand *MemOp =
169 MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF),
170 MachineMemOperand::MOLoad, 4, Align(4));
171 CurDAG->setNodeMemRefs(cast<MachineSDNode>(node), {MemOp});
172 ReplaceNode(N, node);
173 return;
174 }
175 break;
176 }
177 case XCoreISD::LADD: {
178 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
179 N->getOperand(2) };
180 ReplaceNode(N, CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32,
181 MVT::i32, Ops));
182 return;
183 }
184 case XCoreISD::LSUB: {
185 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
186 N->getOperand(2) };
187 ReplaceNode(N, CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32,
188 MVT::i32, Ops));
189 return;
190 }
191 case XCoreISD::MACCU: {
192 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
193 N->getOperand(2), N->getOperand(3) };
194 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32,
195 MVT::i32, Ops));
196 return;
197 }
198 case XCoreISD::MACCS: {
199 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
200 N->getOperand(2), N->getOperand(3) };
201 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32,
202 MVT::i32, Ops));
203 return;
204 }
205 case XCoreISD::LMUL: {
206 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
207 N->getOperand(2), N->getOperand(3) };
208 ReplaceNode(N, CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32,
209 MVT::i32, Ops));
210 return;
211 }
212 case XCoreISD::CRC8: {
213 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
214 ReplaceNode(N, CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32,
215 MVT::i32, Ops));
216 return;
217 }
218 case ISD::BRIND:
219 if (tryBRIND(N))
220 return;
221 break;
222 // Other cases are autogenerated.
223 }
224 SelectCode(N);
225 }
226
227 /// Given a chain return a new chain where any appearance of Old is replaced
228 /// by New. There must be at most one instruction between Old and Chain and
229 /// this instruction must be a TokenFactor. Returns an empty SDValue if
230 /// these conditions don't hold.
231 static SDValue
replaceInChain(SelectionDAG * CurDAG,SDValue Chain,SDValue Old,SDValue New)232 replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
233 {
234 if (Chain == Old)
235 return New;
236 if (Chain->getOpcode() != ISD::TokenFactor)
237 return SDValue();
238 SmallVector<SDValue, 8> Ops;
239 bool found = false;
240 for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
241 if (Chain->getOperand(i) == Old) {
242 Ops.push_back(New);
243 found = true;
244 } else {
245 Ops.push_back(Chain->getOperand(i));
246 }
247 }
248 if (!found)
249 return SDValue();
250 return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
251 }
252
tryBRIND(SDNode * N)253 bool XCoreDAGToDAGISel::tryBRIND(SDNode *N) {
254 SDLoc dl(N);
255 // (brind (int_xcore_checkevent (addr)))
256 SDValue Chain = N->getOperand(0);
257 SDValue Addr = N->getOperand(1);
258 if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
259 return false;
260 unsigned IntNo = Addr->getConstantOperandVal(1);
261 if (IntNo != Intrinsic::xcore_checkevent)
262 return false;
263 SDValue nextAddr = Addr->getOperand(2);
264 SDValue CheckEventChainOut(Addr.getNode(), 1);
265 if (!CheckEventChainOut.use_empty()) {
266 // If the chain out of the checkevent intrinsic is an operand of the
267 // indirect branch or used in a TokenFactor which is the operand of the
268 // indirect branch then build a new chain which uses the chain coming into
269 // the checkevent intrinsic instead.
270 SDValue CheckEventChainIn = Addr->getOperand(0);
271 SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
272 CheckEventChainIn);
273 if (!NewChain.getNode())
274 return false;
275 Chain = NewChain;
276 }
277 // Enable events on the thread using setsr 1 and then disable them immediately
278 // after with clrsr 1. If any resources owned by the thread are ready an event
279 // will be taken. If no resource is ready we branch to the address which was
280 // the operand to the checkevent intrinsic.
281 SDValue constOne = getI32Imm(1, dl);
282 SDValue Glue =
283 SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
284 constOne, Chain), 0);
285 Glue =
286 SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
287 constOne, Glue), 0);
288 if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
289 nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
290 CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
291 nextAddr->getOperand(0), Glue);
292 return true;
293 }
294 CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
295 return true;
296 }
297