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