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