1 | //===-- MipsISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips --------===// |
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 MIPS target. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "MipsISelDAGToDAG.h" |
14 | #include "MCTargetDesc/MipsBaseInfo.h" |
15 | #include "Mips.h" |
16 | #include "Mips16ISelDAGToDAG.h" |
17 | #include "MipsMachineFunction.h" |
18 | #include "MipsRegisterInfo.h" |
19 | #include "MipsSEISelDAGToDAG.h" |
20 | #include "llvm/CodeGen/MachineConstantPool.h" |
21 | #include "llvm/CodeGen/MachineFrameInfo.h" |
22 | #include "llvm/CodeGen/MachineFunction.h" |
23 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
24 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
25 | #include "llvm/CodeGen/SelectionDAG.h" |
26 | #include "llvm/CodeGen/SelectionDAGNodes.h" |
27 | #include "llvm/CodeGen/StackProtector.h" |
28 | #include "llvm/IR/CFG.h" |
29 | #include "llvm/IR/GlobalValue.h" |
30 | #include "llvm/IR/Instructions.h" |
31 | #include "llvm/IR/Intrinsics.h" |
32 | #include "llvm/IR/Type.h" |
33 | #include "llvm/Support/Debug.h" |
34 | #include "llvm/Support/ErrorHandling.h" |
35 | #include "llvm/Support/KnownBits.h" |
36 | #include "llvm/Support/raw_ostream.h" |
37 | #include "llvm/Target/TargetMachine.h" |
38 | using namespace llvm; |
39 | |
40 | #define DEBUG_TYPE "mips-isel" |
41 | #define PASS_NAME "MIPS DAG->DAG Pattern Instruction Selection" |
42 | |
43 | //===----------------------------------------------------------------------===// |
44 | // Instruction Selector Implementation |
45 | //===----------------------------------------------------------------------===// |
46 | |
47 | //===----------------------------------------------------------------------===// |
48 | // MipsDAGToDAGISel - MIPS specific code to select MIPS machine |
49 | // instructions for SelectionDAG operations. |
50 | //===----------------------------------------------------------------------===// |
51 | |
52 | void MipsDAGToDAGISelLegacy::getAnalysisUsage(AnalysisUsage &AU) const { |
53 | // There are multiple MipsDAGToDAGISel instances added to the pass pipeline. |
54 | // We need to preserve StackProtector for the next one. |
55 | AU.addPreserved<StackProtector>(); |
56 | SelectionDAGISelLegacy::getAnalysisUsage(AU); |
57 | } |
58 | |
59 | bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { |
60 | Subtarget = &MF.getSubtarget<MipsSubtarget>(); |
61 | bool Ret = SelectionDAGISel::runOnMachineFunction(mf&: MF); |
62 | |
63 | processFunctionAfterISel(MF); |
64 | |
65 | return Ret; |
66 | } |
67 | |
68 | /// getGlobalBaseReg - Output the instructions required to put the |
69 | /// GOT address into a register. |
70 | SDNode *MipsDAGToDAGISel::getGlobalBaseReg() { |
71 | Register GlobalBaseReg = MF->getInfo<MipsFunctionInfo>()->getGlobalBaseReg(MF&: *MF); |
72 | return CurDAG->getRegister(Reg: GlobalBaseReg, VT: getTargetLowering()->getPointerTy( |
73 | DL: CurDAG->getDataLayout())) |
74 | .getNode(); |
75 | } |
76 | |
77 | /// ComplexPattern used on MipsInstrInfo |
78 | /// Used on Mips Load/Store instructions |
79 | bool MipsDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base, |
80 | SDValue &Offset) const { |
81 | llvm_unreachable("Unimplemented function." ); |
82 | return false; |
83 | } |
84 | |
85 | bool MipsDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base, |
86 | SDValue &Offset) const { |
87 | llvm_unreachable("Unimplemented function." ); |
88 | return false; |
89 | } |
90 | |
91 | bool MipsDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base, |
92 | SDValue &Offset) const { |
93 | llvm_unreachable("Unimplemented function." ); |
94 | return false; |
95 | } |
96 | |
97 | bool MipsDAGToDAGISel::selectIntAddr11MM(SDValue Addr, SDValue &Base, |
98 | SDValue &Offset) const { |
99 | llvm_unreachable("Unimplemented function." ); |
100 | return false; |
101 | } |
102 | |
103 | bool MipsDAGToDAGISel::selectIntAddr12MM(SDValue Addr, SDValue &Base, |
104 | SDValue &Offset) const { |
105 | llvm_unreachable("Unimplemented function." ); |
106 | return false; |
107 | } |
108 | |
109 | bool MipsDAGToDAGISel::selectIntAddr16MM(SDValue Addr, SDValue &Base, |
110 | SDValue &Offset) const { |
111 | llvm_unreachable("Unimplemented function." ); |
112 | return false; |
113 | } |
114 | |
115 | bool MipsDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base, |
116 | SDValue &Offset) const { |
117 | llvm_unreachable("Unimplemented function." ); |
118 | return false; |
119 | } |
120 | |
121 | bool MipsDAGToDAGISel::selectIntAddrSImm10(SDValue Addr, SDValue &Base, |
122 | SDValue &Offset) const { |
123 | llvm_unreachable("Unimplemented function." ); |
124 | return false; |
125 | } |
126 | |
127 | bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl1(SDValue Addr, SDValue &Base, |
128 | SDValue &Offset) const { |
129 | llvm_unreachable("Unimplemented function." ); |
130 | return false; |
131 | } |
132 | |
133 | bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl2(SDValue Addr, SDValue &Base, |
134 | SDValue &Offset) const { |
135 | llvm_unreachable("Unimplemented function." ); |
136 | return false; |
137 | } |
138 | |
139 | bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl3(SDValue Addr, SDValue &Base, |
140 | SDValue &Offset) const { |
141 | llvm_unreachable("Unimplemented function." ); |
142 | return false; |
143 | } |
144 | |
145 | bool MipsDAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base, |
146 | SDValue &Offset) { |
147 | llvm_unreachable("Unimplemented function." ); |
148 | return false; |
149 | } |
150 | |
151 | bool MipsDAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base, |
152 | SDValue &Offset) { |
153 | llvm_unreachable("Unimplemented function." ); |
154 | return false; |
155 | } |
156 | |
157 | bool MipsDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm, |
158 | unsigned MinSizeInBits) const { |
159 | llvm_unreachable("Unimplemented function." ); |
160 | return false; |
161 | } |
162 | |
163 | bool MipsDAGToDAGISel::selectVSplatUimm1(SDValue N, SDValue &Imm) const { |
164 | llvm_unreachable("Unimplemented function." ); |
165 | return false; |
166 | } |
167 | |
168 | bool MipsDAGToDAGISel::selectVSplatUimm2(SDValue N, SDValue &Imm) const { |
169 | llvm_unreachable("Unimplemented function." ); |
170 | return false; |
171 | } |
172 | |
173 | bool MipsDAGToDAGISel::selectVSplatUimm3(SDValue N, SDValue &Imm) const { |
174 | llvm_unreachable("Unimplemented function." ); |
175 | return false; |
176 | } |
177 | |
178 | bool MipsDAGToDAGISel::selectVSplatUimm4(SDValue N, SDValue &Imm) const { |
179 | llvm_unreachable("Unimplemented function." ); |
180 | return false; |
181 | } |
182 | |
183 | bool MipsDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &Imm) const { |
184 | llvm_unreachable("Unimplemented function." ); |
185 | return false; |
186 | } |
187 | |
188 | bool MipsDAGToDAGISel::selectVSplatUimm6(SDValue N, SDValue &Imm) const { |
189 | llvm_unreachable("Unimplemented function." ); |
190 | return false; |
191 | } |
192 | |
193 | bool MipsDAGToDAGISel::selectVSplatUimm8(SDValue N, SDValue &Imm) const { |
194 | llvm_unreachable("Unimplemented function." ); |
195 | return false; |
196 | } |
197 | |
198 | bool MipsDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &Imm) const { |
199 | llvm_unreachable("Unimplemented function." ); |
200 | return false; |
201 | } |
202 | |
203 | bool MipsDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const { |
204 | llvm_unreachable("Unimplemented function." ); |
205 | return false; |
206 | } |
207 | |
208 | bool MipsDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const { |
209 | llvm_unreachable("Unimplemented function." ); |
210 | return false; |
211 | } |
212 | |
213 | bool MipsDAGToDAGISel::selectVSplatMaskL(SDValue N, SDValue &Imm) const { |
214 | llvm_unreachable("Unimplemented function." ); |
215 | return false; |
216 | } |
217 | |
218 | bool MipsDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const { |
219 | llvm_unreachable("Unimplemented function." ); |
220 | return false; |
221 | } |
222 | |
223 | /// Convert vector addition with vector subtraction if that allows to encode |
224 | /// constant as an immediate and thus avoid extra 'ldi' instruction. |
225 | /// add X, <-1, -1...> --> sub X, <1, 1...> |
226 | bool MipsDAGToDAGISel::selectVecAddAsVecSubIfProfitable(SDNode *Node) { |
227 | assert(Node->getOpcode() == ISD::ADD && "Should only get 'add' here." ); |
228 | |
229 | EVT VT = Node->getValueType(ResNo: 0); |
230 | assert(VT.isVector() && "Should only be called for vectors." ); |
231 | |
232 | SDValue X = Node->getOperand(Num: 0); |
233 | SDValue C = Node->getOperand(Num: 1); |
234 | |
235 | auto *BVN = dyn_cast<BuildVectorSDNode>(Val&: C); |
236 | if (!BVN) |
237 | return false; |
238 | |
239 | APInt SplatValue, SplatUndef; |
240 | unsigned SplatBitSize; |
241 | bool HasAnyUndefs; |
242 | |
243 | if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, |
244 | MinSplatBits: 8, isBigEndian: !Subtarget->isLittle())) |
245 | return false; |
246 | |
247 | auto IsInlineConstant = [](const APInt &Imm) { return Imm.isIntN(N: 5); }; |
248 | |
249 | if (IsInlineConstant(SplatValue)) |
250 | return false; // Can already be encoded as an immediate. |
251 | |
252 | APInt NegSplatValue = 0 - SplatValue; |
253 | if (!IsInlineConstant(NegSplatValue)) |
254 | return false; // Even if we negate it it won't help. |
255 | |
256 | SDLoc DL(Node); |
257 | |
258 | SDValue NegC = CurDAG->FoldConstantArithmetic( |
259 | Opcode: ISD::SUB, DL, VT, Ops: {CurDAG->getConstant(Val: 0, DL, VT), C}); |
260 | assert(NegC && "Constant-folding failed!" ); |
261 | SDValue NewNode = CurDAG->getNode(Opcode: ISD::SUB, DL, VT, N1: X, N2: NegC); |
262 | |
263 | ReplaceNode(F: Node, T: NewNode.getNode()); |
264 | SelectCode(N: NewNode.getNode()); |
265 | return true; |
266 | } |
267 | |
268 | /// Select instructions not customized! Used for |
269 | /// expanded, promoted and normal instructions |
270 | void MipsDAGToDAGISel::Select(SDNode *Node) { |
271 | unsigned Opcode = Node->getOpcode(); |
272 | |
273 | // If we have a custom node, we already have selected! |
274 | if (Node->isMachineOpcode()) { |
275 | LLVM_DEBUG(errs() << "== " ; Node->dump(CurDAG); errs() << "\n" ); |
276 | Node->setNodeId(-1); |
277 | return; |
278 | } |
279 | |
280 | // See if subclasses can handle this node. |
281 | if (trySelect(Node)) |
282 | return; |
283 | |
284 | switch(Opcode) { |
285 | default: break; |
286 | |
287 | case ISD::ADD: |
288 | if (Node->getSimpleValueType(ResNo: 0).isVector() && |
289 | selectVecAddAsVecSubIfProfitable(Node)) |
290 | return; |
291 | break; |
292 | |
293 | // Get target GOT address. |
294 | case ISD::GLOBAL_OFFSET_TABLE: |
295 | ReplaceNode(F: Node, T: getGlobalBaseReg()); |
296 | return; |
297 | |
298 | #ifndef NDEBUG |
299 | case ISD::LOAD: |
300 | case ISD::STORE: |
301 | assert((Subtarget->systemSupportsUnalignedAccess() || |
302 | cast<MemSDNode>(Node)->getAlign() >= |
303 | cast<MemSDNode>(Node)->getMemoryVT().getStoreSize()) && |
304 | "Unexpected unaligned loads/stores." ); |
305 | break; |
306 | #endif |
307 | } |
308 | |
309 | // Select the default instruction |
310 | SelectCode(N: Node); |
311 | } |
312 | |
313 | bool MipsDAGToDAGISel::SelectInlineAsmMemoryOperand( |
314 | const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, |
315 | std::vector<SDValue> &OutOps) { |
316 | // All memory constraints can at least accept raw pointers. |
317 | switch(ConstraintID) { |
318 | default: |
319 | llvm_unreachable("Unexpected asm memory constraint" ); |
320 | case InlineAsm::ConstraintCode::m: |
321 | case InlineAsm::ConstraintCode::R: |
322 | case InlineAsm::ConstraintCode::ZC: |
323 | OutOps.push_back(x: Op); |
324 | return false; |
325 | } |
326 | return true; |
327 | } |
328 | |
329 | bool MipsDAGToDAGISel::isUnneededShiftMask(SDNode *N, |
330 | unsigned ShAmtBits) const { |
331 | assert(N->getOpcode() == ISD::AND && "Unexpected opcode" ); |
332 | |
333 | const APInt &RHS = N->getConstantOperandAPInt(Num: 1); |
334 | if (RHS.countr_one() >= ShAmtBits) { |
335 | LLVM_DEBUG( |
336 | dbgs() |
337 | << DEBUG_TYPE |
338 | << " Need optimize 'and & shl/srl/sra' and operand value bits is " |
339 | << RHS.countr_one() << "\n" ); |
340 | return true; |
341 | } |
342 | |
343 | KnownBits Known = CurDAG->computeKnownBits(Op: N->getOperand(Num: 0)); |
344 | return (Known.Zero | RHS).countr_one() >= ShAmtBits; |
345 | } |
346 | |
347 | char MipsDAGToDAGISelLegacy::ID = 0; |
348 | |
349 | MipsDAGToDAGISelLegacy::MipsDAGToDAGISelLegacy( |
350 | std::unique_ptr<SelectionDAGISel> S) |
351 | : SelectionDAGISelLegacy(ID, std::move(S)) {} |
352 | |
353 | INITIALIZE_PASS(MipsDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) |
354 | |