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"
28using 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
42void 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
49bool 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.
60SDNode *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
69bool MipsDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base,
70 SDValue &Offset) const {
71 llvm_unreachable("Unimplemented function.");
72 return false;
73}
74
75bool MipsDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base,
76 SDValue &Offset) const {
77 llvm_unreachable("Unimplemented function.");
78 return false;
79}
80
81bool MipsDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base,
82 SDValue &Offset) const {
83 llvm_unreachable("Unimplemented function.");
84 return false;
85}
86
87bool MipsDAGToDAGISel::selectIntAddr11MM(SDValue Addr, SDValue &Base,
88 SDValue &Offset) const {
89 llvm_unreachable("Unimplemented function.");
90 return false;
91}
92
93bool MipsDAGToDAGISel::selectIntAddr12MM(SDValue Addr, SDValue &Base,
94 SDValue &Offset) const {
95 llvm_unreachable("Unimplemented function.");
96 return false;
97}
98
99bool MipsDAGToDAGISel::selectIntAddr16MM(SDValue Addr, SDValue &Base,
100 SDValue &Offset) const {
101 llvm_unreachable("Unimplemented function.");
102 return false;
103}
104
105bool MipsDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base,
106 SDValue &Offset) const {
107 llvm_unreachable("Unimplemented function.");
108 return false;
109}
110
111bool MipsDAGToDAGISel::selectIntAddrSImm10(SDValue Addr, SDValue &Base,
112 SDValue &Offset) const {
113 llvm_unreachable("Unimplemented function.");
114 return false;
115}
116
117bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl1(SDValue Addr, SDValue &Base,
118 SDValue &Offset) const {
119 llvm_unreachable("Unimplemented function.");
120 return false;
121}
122
123bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl2(SDValue Addr, SDValue &Base,
124 SDValue &Offset) const {
125 llvm_unreachable("Unimplemented function.");
126 return false;
127}
128
129bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl3(SDValue Addr, SDValue &Base,
130 SDValue &Offset) const {
131 llvm_unreachable("Unimplemented function.");
132 return false;
133}
134
135bool MipsDAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base,
136 SDValue &Offset) {
137 llvm_unreachable("Unimplemented function.");
138 return false;
139}
140
141bool MipsDAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base,
142 SDValue &Offset) {
143 llvm_unreachable("Unimplemented function.");
144 return false;
145}
146
147bool MipsDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
148 unsigned MinSizeInBits) const {
149 llvm_unreachable("Unimplemented function.");
150 return false;
151}
152
153bool MipsDAGToDAGISel::selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed,
154 unsigned ImmBitSize) const {
155 llvm_unreachable("Unimplemented function.");
156}
157
158bool MipsDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const {
159 llvm_unreachable("Unimplemented function.");
160 return false;
161}
162
163bool MipsDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const {
164 llvm_unreachable("Unimplemented function.");
165 return false;
166}
167
168bool MipsDAGToDAGISel::selectVSplatMaskL(SDValue N, SDValue &Imm) const {
169 llvm_unreachable("Unimplemented function.");
170 return false;
171}
172
173bool MipsDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const {
174 llvm_unreachable("Unimplemented function.");
175 return false;
176}
177
178bool 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...>
185bool 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
229void 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
272bool 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
288bool 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
306char MipsDAGToDAGISelLegacy::ID = 0;
307
308MipsDAGToDAGISelLegacy::MipsDAGToDAGISelLegacy(
309 std::unique_ptr<SelectionDAGISel> S)
310 : SelectionDAGISelLegacy(ID, std::move(S)) {}
311
312INITIALIZE_PASS(MipsDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
313