LLVM 24.0.0git
AArch64PreLegalizerCombiner.cpp
Go to the documentation of this file.
1//=== lib/CodeGen/GlobalISel/AArch64PreLegalizerCombiner.cpp --------------===//
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 pass does combining of machine instructions at the generic MI level,
10// before the legalizer.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AArch64.h"
34#include <memory>
35
36#define GET_GICOMBINER_DEPS
37#include "AArch64GenPreLegalizeGICombiner.inc"
38#undef GET_GICOMBINER_DEPS
39
40#define DEBUG_TYPE "aarch64-prelegalizer-combiner"
41
42using namespace llvm;
43using namespace MIPatternMatch;
44
45#define GET_GICOMBINER_TYPES
46#include "AArch64GenPreLegalizeGICombiner.inc"
47#undef GET_GICOMBINER_TYPES
48
49namespace {
50
51/// Try to match a G_ICMP of a G_TRUNC with zero, in which the truncated bits
52/// are sign bits. In this case, we can transform the G_ICMP to directly compare
53/// the wide value with a zero.
54bool matchICmpRedundantTrunc(MachineInstr &MI, MachineRegisterInfo &MRI,
55 GISelValueTracking *VT, Register &MatchInfo) {
56 assert(MI.getOpcode() == TargetOpcode::G_ICMP && VT);
57
58 auto Pred = (CmpInst::Predicate)MI.getOperand(1).getPredicate();
59 if (!ICmpInst::isEquality(Pred))
60 return false;
61
62 Register LHS = MI.getOperand(2).getReg();
63 LLT LHSTy = MRI.getType(LHS);
64 if (!LHSTy.isScalar())
65 return false;
66
67 Register RHS = MI.getOperand(3).getReg();
68 Register WideReg;
69
70 if (!mi_match(LHS, MRI, m_GTrunc(m_Reg(WideReg))) ||
71 !mi_match(RHS, MRI, m_SpecificICst(0)))
72 return false;
73
74 LLT WideTy = MRI.getType(WideReg);
75 if (VT->computeNumSignBits(WideReg) <=
76 WideTy.getSizeInBits() - LHSTy.getSizeInBits())
77 return false;
78
79 MatchInfo = WideReg;
80 return true;
81}
82
83void applyICmpRedundantTrunc(MachineInstr &MI, MachineRegisterInfo &MRI,
84 MachineIRBuilder &Builder,
85 GISelChangeObserver &Observer, Register &WideReg) {
86 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
87
88 LLT WideTy = MRI.getType(WideReg);
89 // We're going to directly use the wide register as the LHS, and then use an
90 // equivalent size zero for RHS.
91 Builder.setInstrAndDebugLoc(MI);
92 auto WideZero = Builder.buildConstant(WideTy, 0);
93 Observer.changingInstr(MI);
94 MI.getOperand(2).setReg(WideReg);
95 MI.getOperand(3).setReg(WideZero.getReg(0));
96 Observer.changedInstr(MI);
97}
98
99/// \returns true if it is possible to fold a constant into a G_GLOBAL_VALUE.
100///
101/// e.g.
102///
103/// %g = G_GLOBAL_VALUE @x -> %g = G_GLOBAL_VALUE @x + cst
104bool matchFoldGlobalOffset(MachineInstr &MI, MachineRegisterInfo &MRI,
105 std::pair<uint64_t, uint64_t> &MatchInfo) {
106 assert(MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
107 MachineFunction &MF = *MI.getMF();
108 auto &GlobalOp = MI.getOperand(1);
109 auto *GV = GlobalOp.getGlobal();
110 if (GV->isThreadLocal())
111 return false;
112
113 // Don't allow anything that could represent offsets etc.
115 GV, MF.getTarget()) != AArch64II::MO_NO_FLAG)
116 return false;
117
118 // Look for a G_GLOBAL_VALUE only used by G_PTR_ADDs against constants:
119 //
120 // %g = G_GLOBAL_VALUE @x
121 // %ptr1 = G_PTR_ADD %g, cst1
122 // %ptr2 = G_PTR_ADD %g, cst2
123 // ...
124 // %ptrN = G_PTR_ADD %g, cstN
125 //
126 // Identify the *smallest* constant. We want to be able to form this:
127 //
128 // %offset_g = G_GLOBAL_VALUE @x + min_cst
129 // %g = G_PTR_ADD %offset_g, -min_cst
130 // %ptr1 = G_PTR_ADD %g, cst1
131 // ...
132 Register Dst = MI.getOperand(0).getReg();
133 uint64_t MinOffset = -1ull;
134 for (auto &UseInstr : MRI.use_nodbg_instructions(Dst)) {
135 if (UseInstr.getOpcode() != TargetOpcode::G_PTR_ADD)
136 return false;
138 UseInstr.getOperand(2).getReg(), MRI);
139 if (!Cst)
140 return false;
141 MinOffset = std::min(MinOffset, Cst->Value.getZExtValue());
142 }
143
144 // Require that the new offset is larger than the existing one to avoid
145 // infinite loops.
146 uint64_t CurrOffset = GlobalOp.getOffset();
147 uint64_t NewOffset = MinOffset + CurrOffset;
148 if (NewOffset <= CurrOffset)
149 return false;
150
151 // Check whether folding this offset is legal. It must not go out of bounds of
152 // the referenced object to avoid violating the code model, and must be
153 // smaller than 2^20 because this is the largest offset expressible in all
154 // object formats. (The IMAGE_REL_ARM64_PAGEBASE_REL21 relocation in COFF
155 // stores an immediate signed 21 bit offset.)
156 //
157 // This check also prevents us from folding negative offsets, which will end
158 // up being treated in the same way as large positive ones. They could also
159 // cause code model violations, and aren't really common enough to matter.
160 if (NewOffset >= (1 << 20))
161 return false;
162
163 Type *T = GV->getValueType();
164 if (!T->isSized() ||
165 NewOffset > GV->getDataLayout().getTypeAllocSize(T))
166 return false;
167 MatchInfo = std::make_pair(NewOffset, MinOffset);
168 return true;
169}
170
171void applyFoldGlobalOffset(MachineInstr &MI, MachineRegisterInfo &MRI,
173 std::pair<uint64_t, uint64_t> &MatchInfo) {
174 // Change:
175 //
176 // %g = G_GLOBAL_VALUE @x
177 // %ptr1 = G_PTR_ADD %g, cst1
178 // %ptr2 = G_PTR_ADD %g, cst2
179 // ...
180 // %ptrN = G_PTR_ADD %g, cstN
181 //
182 // To:
183 //
184 // %offset_g = G_GLOBAL_VALUE @x + min_cst
185 // %g = G_PTR_ADD %offset_g, -min_cst
186 // %ptr1 = G_PTR_ADD %g, cst1
187 // ...
188 // %ptrN = G_PTR_ADD %g, cstN
189 //
190 // Then, the original G_PTR_ADDs should be folded later on so that they look
191 // like this:
192 //
193 // %ptrN = G_PTR_ADD %offset_g, cstN - min_cst
194 uint64_t Offset, MinOffset;
195 std::tie(Offset, MinOffset) = MatchInfo;
196 B.setInstrAndDebugLoc(*std::next(MI.getIterator()));
197 Observer.changingInstr(MI);
198 auto &GlobalOp = MI.getOperand(1);
199 auto *GV = GlobalOp.getGlobal();
200 GlobalOp.ChangeToGA(GV, Offset, GlobalOp.getTargetFlags());
201 Register Dst = MI.getOperand(0).getReg();
202 Register NewGVDst = MRI.cloneVirtualRegister(Dst);
203 MI.getOperand(0).setReg(NewGVDst);
204 Observer.changedInstr(MI);
205 B.buildPtrAdd(
206 Dst, NewGVDst,
207 B.buildConstant(LLT::scalar(64), -static_cast<int64_t>(MinOffset)));
208}
209
210// Combines vecreduce_add(mul(ext(x), ext(y))) -> vecreduce_add([us]dot(x, y))
211// Or vecreduce_add(ext(mul(ext(x), ext(y)))) -> vecreduce_add([us]dot(x, y))
212// Or vecreduce_add(ext(x)) -> vecreduce_add([us]dot(x, 1))
213// Similar to performVecReduceAddCombine in SelectionDAG
214bool matchExtAddvToDotAddv(MachineInstr &MI, MachineRegisterInfo &MRI,
215 const AArch64Subtarget &STI,
216 std::tuple<Register, Register, bool> &MatchInfo) {
217 assert(MI.getOpcode() == TargetOpcode::G_VECREDUCE_ADD &&
218 "Expected a G_VECREDUCE_ADD instruction");
219 assert(STI.hasDotProd() && "Target should have Dot Product feature");
220
221 MachineInstr *I1 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
222 Register DstReg = MI.getOperand(0).getReg();
223 Register MidReg = I1->getOperand(0).getReg();
224 LLT DstTy = MRI.getType(DstReg);
225 LLT MidTy = MRI.getType(MidReg);
226 if (DstTy.getScalarSizeInBits() != 32 || MidTy.getScalarSizeInBits() != 32)
227 return false;
228
229 // Detect mul(ext, ext) with symmetric ext's. If I1Opc is G_ZEXT or G_SEXT
230 // then the ext's must match the same opcode. It is set to the ext opcode on
231 // output.
232 auto tryMatchingMulOfExt = [&MRI](MachineInstr *MI, Register &Out1,
233 Register &Out2, unsigned &I1Opc) {
234 // If result of this has more than 1 use, then there is no point in creating
235 // a dot instruction
236 if (!MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))
237 return false;
238
239 MachineInstr *ExtMI1 =
240 getDefIgnoringCopies(MI->getOperand(1).getReg(), MRI);
241 MachineInstr *ExtMI2 =
242 getDefIgnoringCopies(MI->getOperand(2).getReg(), MRI);
243 LLT Ext1DstTy = MRI.getType(ExtMI1->getOperand(0).getReg());
244 LLT Ext2DstTy = MRI.getType(ExtMI2->getOperand(0).getReg());
245
246 if (ExtMI1->getOpcode() != ExtMI2->getOpcode() || Ext1DstTy != Ext2DstTy)
247 return false;
248 if ((I1Opc == TargetOpcode::G_ZEXT || I1Opc == TargetOpcode::G_SEXT) &&
249 I1Opc != ExtMI1->getOpcode())
250 return false;
251 Out1 = ExtMI1->getOperand(1).getReg();
252 Out2 = ExtMI2->getOperand(1).getReg();
253 I1Opc = ExtMI1->getOpcode();
254 return true;
255 };
256
257 LLT SrcTy;
258 unsigned I1Opc = I1->getOpcode();
259 if (I1Opc == TargetOpcode::G_MUL) {
260 Register Out1, Out2;
261 if (!tryMatchingMulOfExt(I1, Out1, Out2, I1Opc))
262 return false;
263 SrcTy = MRI.getType(Out1);
264 std::get<0>(MatchInfo) = Out1;
265 std::get<1>(MatchInfo) = Out2;
266 } else if (I1Opc == TargetOpcode::G_ZEXT || I1Opc == TargetOpcode::G_SEXT) {
267 Register I1Op = I1->getOperand(1).getReg();
268 MachineInstr *M = getDefIgnoringCopies(I1Op, MRI);
269 Register Out1, Out2;
270 if (M->getOpcode() == TargetOpcode::G_MUL &&
271 tryMatchingMulOfExt(M, Out1, Out2, I1Opc)) {
272 SrcTy = MRI.getType(Out1);
273 std::get<0>(MatchInfo) = Out1;
274 std::get<1>(MatchInfo) = Out2;
275 } else {
276 SrcTy = MRI.getType(I1Op);
277 std::get<0>(MatchInfo) = I1Op;
278 std::get<1>(MatchInfo) = 0;
279 }
280 } else {
281 return false;
282 }
283
284 if (I1Opc == TargetOpcode::G_ZEXT)
285 std::get<2>(MatchInfo) = 0;
286 else if (I1Opc == TargetOpcode::G_SEXT)
287 std::get<2>(MatchInfo) = 1;
288 else
289 return false;
290
291 if (SrcTy.getScalarSizeInBits() != 8 || SrcTy.getNumElements() % 8 != 0)
292 return false;
293
294 return true;
295}
296
297void applyExtAddvToDotAddv(MachineInstr &MI, MachineRegisterInfo &MRI,
298 MachineIRBuilder &Builder,
299 GISelChangeObserver &Observer,
300 const AArch64Subtarget &STI,
301 std::tuple<Register, Register, bool> &MatchInfo) {
302 assert(MI.getOpcode() == TargetOpcode::G_VECREDUCE_ADD &&
303 "Expected a G_VECREDUCE_ADD instruction");
304 assert(STI.hasDotProd() && "Target should have Dot Product feature");
305
306 // Initialise the variables
307 unsigned DotOpcode =
308 std::get<2>(MatchInfo) ? AArch64::G_SDOT : AArch64::G_UDOT;
309 Register Ext1SrcReg = std::get<0>(MatchInfo);
310
311 // If there is one source register, create a vector of 0s as the second
312 // source register
313 Register Ext2SrcReg;
314 if (std::get<1>(MatchInfo) == 0)
315 Ext2SrcReg = Builder.buildConstant(MRI.getType(Ext1SrcReg), 1)
316 ->getOperand(0)
317 .getReg();
318 else
319 Ext2SrcReg = std::get<1>(MatchInfo);
320
321 // Find out how many DOT instructions are needed
322 LLT SrcTy = MRI.getType(Ext1SrcReg);
323 LLT MidTy;
324 unsigned NumOfDotMI;
325 if (SrcTy.getNumElements() % 16 == 0) {
326 NumOfDotMI = SrcTy.getNumElements() / 16;
327 MidTy = LLT::fixed_vector(4, LLT::integer(32));
328 } else if (SrcTy.getNumElements() % 8 == 0) {
329 NumOfDotMI = SrcTy.getNumElements() / 8;
330 MidTy = LLT::fixed_vector(2, LLT::integer(32));
331 } else {
332 llvm_unreachable("Source type number of elements is not multiple of 8");
333 }
334
335 // Handle case where one DOT instruction is needed
336 if (NumOfDotMI == 1) {
337 auto Zeroes = Builder.buildConstant(MidTy, 0)->getOperand(0).getReg();
338 auto Dot = Builder.buildInstr(DotOpcode, {MidTy},
339 {Zeroes, Ext1SrcReg, Ext2SrcReg});
340 Builder.buildVecReduceAdd(MI.getOperand(0), Dot->getOperand(0));
341 } else {
342 // If not pad the last v8 element with 0s to a v16
343 SmallVector<Register, 4> Ext1UnmergeReg;
344 SmallVector<Register, 4> Ext2UnmergeReg;
345 if (SrcTy.getNumElements() % 16 != 0) {
346 SmallVector<Register> Leftover1;
347 SmallVector<Register> Leftover2;
348
349 // Split the elements into v16i8 and v8i8
350 LLT MainTy = LLT::fixed_vector(16, LLT::integer(8));
351 LLT LeftoverTy1, LeftoverTy2;
352 if (!extractParts(Ext1SrcReg, MRI.getType(Ext1SrcReg), MainTy,
353 LeftoverTy1, Ext1UnmergeReg, Leftover1, Builder, MRI) ||
354 !extractParts(Ext2SrcReg, MRI.getType(Ext2SrcReg), MainTy,
355 LeftoverTy2, Ext2UnmergeReg, Leftover2, Builder, MRI)) {
356 llvm_unreachable("Unable to split this vector properly");
357 }
358
359 // Pad the leftover v8i8 vector with register of 0s of type v8i8
360 auto v8Zeroes =
361 Builder.buildConstant(LLT::fixed_vector(8, LLT::integer(8)), 0);
362
363 Ext1UnmergeReg.push_back(
364 Builder
365 .buildMergeLikeInstr(LLT::fixed_vector(16, LLT::integer(8)),
366 {Leftover1[0], v8Zeroes})
367 .getReg(0));
368 Ext2UnmergeReg.push_back(
369 Builder
370 .buildMergeLikeInstr(LLT::fixed_vector(16, LLT::integer(8)),
371 {Leftover2[0], v8Zeroes})
372 .getReg(0));
373
374 } else {
375 // Unmerge the source vectors to v16i8
376 unsigned SrcNumElts = SrcTy.getNumElements();
377 extractParts(Ext1SrcReg, LLT::fixed_vector(16, LLT::integer(8)),
378 SrcNumElts / 16, Ext1UnmergeReg, Builder, MRI);
379 extractParts(Ext2SrcReg, LLT::fixed_vector(16, LLT::integer(8)),
380 SrcNumElts / 16, Ext2UnmergeReg, Builder, MRI);
381 }
382
383 // Build the UDOT instructions
385 unsigned NumElements = 0;
386 for (unsigned i = 0; i < Ext1UnmergeReg.size(); i++) {
387 LLT ZeroesLLT;
388 // Check if it is 16 or 8 elements. Set Zeroes to the according size
389 if (MRI.getType(Ext1UnmergeReg[i]).getNumElements() == 16) {
390 ZeroesLLT = LLT::fixed_vector(4, LLT::integer(32));
391 NumElements += 4;
392 } else {
393 ZeroesLLT = LLT::fixed_vector(2, LLT::integer(32));
394 NumElements += 2;
395 }
396 auto Zeroes = Builder.buildConstant(ZeroesLLT, 0);
397 DotReg.push_back(
398 Builder
399 .buildInstr(DotOpcode, {ZeroesLLT},
400 {Zeroes, Ext1UnmergeReg[i], Ext2UnmergeReg[i]})
401 .getReg(0));
402 }
403
404 // Merge the output
405 auto ConcatMI = Builder.buildConcatVectors(
406 LLT::fixed_vector(NumElements, LLT::integer(32)), DotReg);
407
408 // Put it through a vector reduction
409 Builder.buildVecReduceAdd(MI.getOperand(0).getReg(),
410 ConcatMI->getOperand(0).getReg());
411 }
412
413 // Erase the dead instructions
414 MI.eraseFromParent();
415}
416
417// Matches {U/S}ADDV(ext(x)) => {U/S}ADDLV(x)
418// Ensure that the type coming from the extend instruction is the right size
419bool matchExtUaddvToUaddlv(MachineInstr &MI, MachineRegisterInfo &MRI,
420 std::pair<Register, bool> &MatchInfo) {
421 assert(MI.getOpcode() == TargetOpcode::G_VECREDUCE_ADD &&
422 "Expected G_VECREDUCE_ADD Opcode");
423
424 // Check if the last instruction is an extend
425 MachineInstr *ExtMI = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
426 auto ExtOpc = ExtMI->getOpcode();
427
428 if (ExtOpc == TargetOpcode::G_ZEXT)
429 std::get<1>(MatchInfo) = 0;
430 else if (ExtOpc == TargetOpcode::G_SEXT)
431 std::get<1>(MatchInfo) = 1;
432 else
433 return false;
434
435 // Check if the source register is a valid type
436 Register ExtSrcReg = ExtMI->getOperand(1).getReg();
437 LLT ExtSrcTy = MRI.getType(ExtSrcReg);
438 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
439 if (ExtSrcTy.getScalarSizeInBits() * 2 > DstTy.getScalarSizeInBits())
440 return false;
441 if ((DstTy.getScalarSizeInBits() == 16 &&
442 ExtSrcTy.getNumElements() % 8 == 0 && ExtSrcTy.getNumElements() < 256) ||
443 (DstTy.getScalarSizeInBits() == 32 &&
444 ExtSrcTy.getNumElements() % 4 == 0) ||
445 (DstTy.getScalarSizeInBits() == 64 &&
446 ExtSrcTy.getNumElements() % 4 == 0)) {
447 std::get<0>(MatchInfo) = ExtSrcReg;
448 return true;
449 }
450 return false;
451}
452
453void applyExtUaddvToUaddlv(MachineInstr &MI, MachineRegisterInfo &MRI,
455 std::pair<Register, bool> &MatchInfo) {
456 assert(MI.getOpcode() == TargetOpcode::G_VECREDUCE_ADD &&
457 "Expected G_VECREDUCE_ADD Opcode");
458
459 unsigned Opc = std::get<1>(MatchInfo) ? AArch64::G_SADDLV : AArch64::G_UADDLV;
460 Register SrcReg = std::get<0>(MatchInfo);
461 Register DstReg = MI.getOperand(0).getReg();
462 LLT SrcTy = MRI.getType(SrcReg);
463 LLT DstTy = MRI.getType(DstReg);
464
465 // If SrcTy has more elements than expected, split them into multiple
466 // instructions and sum the results
467 LLT MainTy;
468 SmallVector<Register, 1> WorkingRegisters;
469 unsigned SrcScalSize = SrcTy.getScalarSizeInBits();
470 unsigned SrcNumElem = SrcTy.getNumElements();
471 if ((SrcScalSize == 8 && SrcNumElem > 16) ||
472 (SrcScalSize == 16 && SrcNumElem > 8) ||
473 (SrcScalSize == 32 && SrcNumElem > 4)) {
474
475 LLT LeftoverTy;
476 SmallVector<Register, 4> LeftoverRegs;
477 if (SrcScalSize == 8)
478 MainTy = LLT::fixed_vector(16, LLT::integer(8));
479 else if (SrcScalSize == 16)
480 MainTy = LLT::fixed_vector(8, LLT::integer(16));
481 else if (SrcScalSize == 32)
482 MainTy = LLT::fixed_vector(4, LLT::integer(32));
483 else
484 llvm_unreachable("Source's Scalar Size not supported");
485
486 // Extract the parts and put each extracted sources through U/SADDLV and put
487 // the values inside a small vec
488 extractParts(SrcReg, SrcTy, MainTy, LeftoverTy, WorkingRegisters,
489 LeftoverRegs, B, MRI);
490 llvm::append_range(WorkingRegisters, LeftoverRegs);
491 } else {
492 WorkingRegisters.push_back(SrcReg);
493 MainTy = SrcTy;
494 }
495
496 unsigned MidScalarSize = MainTy.getScalarSizeInBits() * 2;
497 LLT MidScalarLLT = LLT::integer(MidScalarSize);
498 Register ZeroReg = B.buildConstant(LLT::integer(64), 0).getReg(0);
499 for (unsigned I = 0; I < WorkingRegisters.size(); I++) {
500 // If the number of elements is too small to build an instruction, extend
501 // its size before applying addlv
502 LLT WorkingRegTy = MRI.getType(WorkingRegisters[I]);
503 if ((WorkingRegTy.getScalarSizeInBits() == 8) &&
504 (WorkingRegTy.getNumElements() == 4)) {
505 WorkingRegisters[I] =
506 B.buildInstr(std::get<1>(MatchInfo) ? TargetOpcode::G_SEXT
507 : TargetOpcode::G_ZEXT,
509 {WorkingRegisters[I]})
510 .getReg(0);
511 }
512
513 // Generate the {U/S}ADDLV instruction, whose output is always double of the
514 // Src's Scalar size
515 LLT AddlvTy = MidScalarSize <= 32 ? LLT::fixed_vector(4, LLT::integer(32))
517 Register AddlvReg =
518 B.buildInstr(Opc, {AddlvTy}, {WorkingRegisters[I]}).getReg(0);
519
520 // The output from {U/S}ADDLV gets placed in the lowest lane of a v4i32 or
521 // v2i64 register.
522 // i16, i32 results uses v4i32 registers
523 // i64 results uses v2i64 registers
524 // Therefore we have to extract/truncate the the value to the right type
525 if (MidScalarSize == 32 || MidScalarSize == 64) {
526 WorkingRegisters[I] = B.buildInstr(AArch64::G_EXTRACT_VECTOR_ELT,
527 {MidScalarLLT}, {AddlvReg, ZeroReg})
528 .getReg(0);
529 } else {
530 Register ExtractReg =
531 B.buildInstr(AArch64::G_EXTRACT_VECTOR_ELT, {LLT::integer(32)},
532 {AddlvReg, ZeroReg})
533 .getReg(0);
534 WorkingRegisters[I] =
535 B.buildTrunc({MidScalarLLT}, {ExtractReg}).getReg(0);
536 }
537 }
538
539 Register OutReg;
540 if (WorkingRegisters.size() > 1) {
541 OutReg = B.buildAdd(MidScalarLLT, WorkingRegisters[0], WorkingRegisters[1])
542 .getReg(0);
543 for (unsigned I = 2; I < WorkingRegisters.size(); I++) {
544 OutReg = B.buildAdd(MidScalarLLT, OutReg, WorkingRegisters[I]).getReg(0);
545 }
546 } else {
547 OutReg = WorkingRegisters[0];
548 }
549
550 if (DstTy.getScalarSizeInBits() > MidScalarSize) {
551 // Handle the scalar value if the DstTy's Scalar Size is more than double
552 // Src's ScalarType
553 B.buildInstr(std::get<1>(MatchInfo) ? TargetOpcode::G_SEXT
554 : TargetOpcode::G_ZEXT,
555 {DstReg}, {OutReg});
556 } else {
557 B.buildCopy(DstReg, OutReg);
558 }
559
560 MI.eraseFromParent();
561}
562
563// Pushes ADD/SUB/MUL through extend instructions to decrease the number of
564// extend instruction at the end by allowing selection of {s|u}addl sooner
565// i32 add(i32 ext i8, i32 ext i8) => i32 ext(i16 add(i16 ext i8, i16 ext i8))
566bool matchPushAddSubExt(MachineInstr &MI, MachineRegisterInfo &MRI,
567 Register DstReg, Register SrcReg1, Register SrcReg2) {
568 assert((MI.getOpcode() == TargetOpcode::G_ADD ||
569 MI.getOpcode() == TargetOpcode::G_SUB ||
570 MI.getOpcode() == TargetOpcode::G_MUL) &&
571 "Expected a G_ADD, G_SUB or G_MUL instruction\n");
572
573 // Deal with vector types only
574 LLT DstTy = MRI.getType(DstReg);
575 if (!DstTy.isVector())
576 return false;
577
578 // Return true if G_{S|Z}EXT instruction is more than 2* source
579 Register ExtDstReg = MI.getOperand(1).getReg();
580 LLT Ext1SrcTy = MRI.getType(SrcReg1);
581 LLT Ext2SrcTy = MRI.getType(SrcReg2);
582 unsigned ExtDstScal = MRI.getType(ExtDstReg).getScalarSizeInBits();
583 unsigned Ext1SrcScal = Ext1SrcTy.getScalarSizeInBits();
584 if (((Ext1SrcScal == 8 && ExtDstScal == 32) ||
585 ((Ext1SrcScal == 8 || Ext1SrcScal == 16) && ExtDstScal == 64)) &&
586 Ext1SrcTy == Ext2SrcTy)
587 return true;
588
589 return false;
590}
591
592void applyPushAddSubExt(MachineInstr &MI, MachineRegisterInfo &MRI,
593 MachineIRBuilder &B, bool isSExt, Register DstReg,
594 Register SrcReg1, Register SrcReg2) {
595 LLT SrcTy = MRI.getType(SrcReg1);
596 LLT MidTy = SrcTy.changeElementSize(SrcTy.getScalarSizeInBits() * 2);
597 unsigned Opc = isSExt ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
598 Register Ext1Reg = B.buildInstr(Opc, {MidTy}, {SrcReg1}).getReg(0);
599 Register Ext2Reg = B.buildInstr(Opc, {MidTy}, {SrcReg2}).getReg(0);
600 Register AddReg =
601 B.buildInstr(MI.getOpcode(), {MidTy}, {Ext1Reg, Ext2Reg}).getReg(0);
602
603 // G_SUB has to sign-extend the result.
604 // G_ADD needs to sext from sext and can sext or zext from zext, and G_MUL
605 // needs to use the original opcode so the original opcode is used for both.
606 if (MI.getOpcode() == TargetOpcode::G_ADD ||
607 MI.getOpcode() == TargetOpcode::G_MUL)
608 B.buildInstr(Opc, {DstReg}, {AddReg});
609 else
610 B.buildSExt(DstReg, AddReg);
611
612 MI.eraseFromParent();
613}
614
615bool matchSimplifyUADDO(MachineInstr &MI, MachineRegisterInfo &MRI,
616 std::pair<Register, Register> &MatchInfo) {
617 // Try simplify G_UADDO with 8 or 16 bit operands to wide G_ADD and TBNZ if
618 // result is only used in the no-overflow case. It is restricted to cases
619 // where we know that the high-bits of the operands are 0. If there's an
620 // overflow, then the 9th or 17th bit must be set, which can be checked
621 // using TBNZ.
622 //
623 // Change (for UADDOs on 8 and 16 bits):
624 //
625 // %z0 = G_ASSERT_ZEXT _
626 // %op0 = G_TRUNC %z0
627 // %z1 = G_ASSERT_ZEXT _
628 // %op1 = G_TRUNC %z1
629 // %val, %cond = G_UADDO %op0, %op1
630 // G_BRCOND %cond, %error.bb
631 //
632 // error.bb:
633 // (no successors and no uses of %val)
634 //
635 // To:
636 //
637 // %z0 = G_ASSERT_ZEXT _
638 // %z1 = G_ASSERT_ZEXT _
639 // %add = G_ADD %z0, %z1
640 // %val = G_TRUNC %add
641 // %bit = G_AND %add, 1 << scalar-size-in-bits(%op1)
642 // %cond = G_ICMP NE, %bit, 0
643 // G_BRCOND %cond, %error.bb
644
645 MachineOperand *DefOp0 = MRI.getOneDef(MI.getOperand(2).getReg());
646 MachineOperand *DefOp1 = MRI.getOneDef(MI.getOperand(3).getReg());
647 Register Op0Wide;
648 Register Op1Wide;
649 if (!mi_match(DefOp0->getParent(), MRI, m_GTrunc(m_Reg(Op0Wide))) ||
650 !mi_match(DefOp1->getParent(), MRI, m_GTrunc(m_Reg(Op1Wide))))
651 return false;
652 LLT WideTy0 = MRI.getType(Op0Wide);
653 LLT WideTy1 = MRI.getType(Op1Wide);
654 Register ResVal = MI.getOperand(0).getReg();
655 LLT OpTy = MRI.getType(ResVal);
656 unsigned OpTySize = OpTy.getScalarSizeInBits();
657 // First check that the G_TRUNC feeding the G_UADDO are no-ops, because the
658 // inputs have been zero-extended.
659 if (!mi_match(Op0Wide, MRI,
660 m_GAssertZext(m_Reg(), m_SpecificImm(OpTySize))) ||
661 !mi_match(Op1Wide, MRI, m_GAssertZext(m_Reg(), m_SpecificImm(OpTySize))))
662 return false;
663
664 // Only scalar UADDO with either 8 or 16 bit operands are handled.
665 if (!WideTy0.isScalar() || !WideTy1.isScalar() || WideTy0 != WideTy1 ||
666 OpTySize >= WideTy0.getScalarSizeInBits() ||
667 (OpTySize != 8 && OpTySize != 16))
668 return false;
669
670 // The overflow-status result must be used by a branch only.
671 Register ResStatus = MI.getOperand(1).getReg();
672 if (!MRI.hasOneNonDBGUse(ResStatus))
673 return false;
674 MachineInstr *CondUser = &*MRI.use_instr_nodbg_begin(ResStatus);
675 if (CondUser->getOpcode() != TargetOpcode::G_BRCOND)
676 return false;
677
678 // Make sure the computed result is only used in the no-overflow blocks.
679 MachineBasicBlock *CurrentMBB = MI.getParent();
680 MachineBasicBlock *FailMBB = CondUser->getOperand(1).getMBB();
681 if (!FailMBB->succ_empty() || CondUser->getParent() != CurrentMBB)
682 return false;
683 if (any_of(MRI.use_nodbg_instructions(ResVal),
684 [&MI, FailMBB, CurrentMBB](MachineInstr &I) {
685 return &MI != &I &&
686 (I.getParent() == FailMBB || I.getParent() == CurrentMBB);
687 }))
688 return false;
689
690 MatchInfo = {Op0Wide, Op1Wide};
691 return true;
692}
693
694void applySimplifyUADDO(MachineInstr &MI, MachineRegisterInfo &MRI,
696 const CombinerHelper &Helper,
697 const std::pair<Register, Register> &MatchInfo) {
698 Register Op0Wide = MatchInfo.first;
699 Register Op1Wide = MatchInfo.second;
700 Register ResVal = MI.getOperand(0).getReg();
701 Register ResStatus = MI.getOperand(1).getReg();
702 unsigned OpTySize = MRI.getType(ResVal).getScalarSizeInBits();
703
704 // Remove G_UADDO.
705 B.setInstrAndDebugLoc(*MI.getNextNode());
706 MI.eraseFromParent();
707
708 // Emit wide add.
709 Register AddDst = MRI.cloneVirtualRegister(Op0Wide);
710 B.buildInstr(TargetOpcode::G_ADD, {AddDst}, {Op0Wide, Op1Wide});
711
712 // Emit check of the 9th or 17th bit and update users (the branch). This will
713 // later be folded to TBNZ.
714 Register CondBit = MRI.cloneVirtualRegister(Op0Wide);
715 B.buildAnd(
716 CondBit, AddDst,
717 B.buildConstant(LLT::integer(32), OpTySize == 8 ? 1 << 8 : 1 << 16));
718 B.buildICmp(CmpInst::ICMP_NE, ResStatus, CondBit,
719 B.buildConstant(LLT::integer(32), 0));
720
721 // Update ZEXts users of the result value. Because all uses are in the
722 // no-overflow case, we know that the top bits are 0 and we can ignore ZExts.
723 B.buildZExtOrTrunc(ResVal, AddDst);
724 for (MachineOperand &U : make_early_inc_range(MRI.use_operands(ResVal))) {
725 Register WideReg;
726 if (mi_match(U.getParent(), MRI, m_GZExt(m_Reg(WideReg)))) {
727 auto OldR = U.getParent()->getOperand(0).getReg();
728 Observer.erasingInstr(*U.getParent());
729 U.getParent()->eraseFromParent();
730 Helper.replaceRegWith(MRI, OldR, AddDst);
731 }
732 }
733}
734
735class AArch64PreLegalizerCombinerImpl : public Combiner {
736protected:
737 const CombinerHelper Helper;
738 const AArch64PreLegalizerCombinerImplRuleConfig &RuleConfig;
739 const AArch64Subtarget &STI;
740 const LibcallLoweringInfo &Libcalls;
741
742public:
743 AArch64PreLegalizerCombinerImpl(
745 GISelCSEInfo *CSEInfo,
746 const AArch64PreLegalizerCombinerImplRuleConfig &RuleConfig,
747 const AArch64Subtarget &STI, const LibcallLoweringInfo &Libcalls,
748 MachineDominatorTree *MDT, const LegalizerInfo *LI);
749
750 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
751
752 bool tryCombineAll(MachineInstr &I) const override;
753
754 bool tryCombineAllImpl(MachineInstr &I) const;
755
756private:
757#define GET_GICOMBINER_CLASS_MEMBERS
758#include "AArch64GenPreLegalizeGICombiner.inc"
759#undef GET_GICOMBINER_CLASS_MEMBERS
760};
761
762#define GET_GICOMBINER_IMPL
763#include "AArch64GenPreLegalizeGICombiner.inc"
764#undef GET_GICOMBINER_IMPL
765
766AArch64PreLegalizerCombinerImpl::AArch64PreLegalizerCombinerImpl(
768 GISelCSEInfo *CSEInfo,
769 const AArch64PreLegalizerCombinerImplRuleConfig &RuleConfig,
770 const AArch64Subtarget &STI, const LibcallLoweringInfo &Libcalls,
771 MachineDominatorTree *MDT, const LegalizerInfo *LI)
772 : Combiner(MF, CInfo, &VT, CSEInfo),
773 Helper(Observer, B, /*IsPreLegalize*/ true, &VT, MDT, LI),
774 RuleConfig(RuleConfig), STI(STI), Libcalls(Libcalls),
776#include "AArch64GenPreLegalizeGICombiner.inc"
778{
779}
780
781bool AArch64PreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
782 if (tryCombineAllImpl(MI))
783 return true;
784
785 return false;
786}
787
788bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo,
789 GISelValueTracking *VT, MachineDominatorTree *MDT,
790 const LibcallLoweringInfo &Libcalls,
791 const AArch64PreLegalizerCombinerImplRuleConfig &RuleConfig,
792 bool EnableOpt) {
793 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
794 const auto *LI = ST.getLegalizerInfo();
795
796 const Function &F = MF.getFunction();
797
798 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
799 /*LegalizerInfo=*/nullptr, EnableOpt, F.hasOptSize(),
800 F.hasMinSize());
801 // Disable fixed-point iteration to reduce compile-time
802 CInfo.MaxIterations = 1;
803 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
804 // This is the first Combiner, so the input IR might contain dead
805 // instructions.
806 CInfo.EnableFullDCE = true;
807 AArch64PreLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST,
808 Libcalls, MDT, LI);
809 return Impl.combineMachineInstrs();
810}
811
812// Pass boilerplate
813// ================
814
815class AArch64PreLegalizerCombinerLegacy : public MachineFunctionPass {
816public:
817 static char ID;
818
819 AArch64PreLegalizerCombinerLegacy();
820
821 StringRef getPassName() const override {
822 return "AArch64PreLegalizerCombiner";
823 }
824
825 bool runOnMachineFunction(MachineFunction &MF) override;
826
827 void getAnalysisUsage(AnalysisUsage &AU) const override;
828
829private:
830 AArch64PreLegalizerCombinerImplRuleConfig RuleConfig;
831};
832} // end anonymous namespace
833
834void AArch64PreLegalizerCombinerLegacy::getAnalysisUsage(
835 AnalysisUsage &AU) const {
836 AU.setPreservesCFG();
838 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
839 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
840 AU.addRequired<MachineDominatorTreeWrapperPass>();
841 AU.addRequired<GISelCSEAnalysisWrapperPass>();
842 AU.addPreserved<GISelCSEAnalysisWrapperPass>();
843 AU.addRequired<LibcallLoweringInfoWrapper>();
845}
846
847AArch64PreLegalizerCombinerLegacy::AArch64PreLegalizerCombinerLegacy()
848 : MachineFunctionPass(ID) {
849 if (!RuleConfig.parseCommandLineOption())
850 report_fatal_error("Invalid rule identifier");
851}
852
853bool AArch64PreLegalizerCombinerLegacy::runOnMachineFunction(
854 MachineFunction &MF) {
855 if (MF.getProperties().hasFailedISel())
856 return false;
857 // Enable CSE.
858 GISelCSEAnalysisWrapper &Wrapper =
859 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
860 auto *CSEInfo =
862
863 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
864 const LibcallLoweringInfo &Libcalls =
865 getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(
866 *MF.getFunction().getParent(), ST);
867
868 GISelValueTracking *VT =
869 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
870 MachineDominatorTree *MDT =
871 &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
872 bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None &&
873 !skipFunction(MF.getFunction());
874 return runCombiner(MF, CSEInfo, VT, MDT, Libcalls, RuleConfig, EnableOpt);
875}
876
877char AArch64PreLegalizerCombinerLegacy::ID = 0;
878INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombinerLegacy, DEBUG_TYPE,
879 "Combine AArch64 machine instrs before legalization",
880 false, false)
884INITIALIZE_PASS_END(AArch64PreLegalizerCombinerLegacy, DEBUG_TYPE,
885 "Combine AArch64 machine instrs before legalization", false,
886 false)
887
889 : RuleConfig(
890 std::make_unique<AArch64PreLegalizerCombinerImplRuleConfig>()) {
891 if (!RuleConfig->parseCommandLineOption())
892 reportFatalUsageError("invalid rule identifier");
893}
894
897
899
903 if (MF.getProperties().hasFailedISel())
904 return PreservedAnalyses::all();
905
906 auto *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(MF).get();
909
911 auto &MAMProxy =
913 const ModuleLibcallLoweringInfo *LibcallResult =
914 MAMProxy.getCachedResult<LibcallLoweringModuleAnalysis>(
915 *MF.getFunction().getParent());
916 if (!LibcallResult)
917 reportFatalUsageError("LibcallLoweringModuleAnalysis result not available");
918
919 const LibcallLoweringInfo &Libcalls = getLibcallLowering(*LibcallResult, ST);
920
921 bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None;
922
923 if (!runCombiner(MF, CSEInfo, &VT, &MDT, Libcalls, *RuleConfig, EnableOpt))
924 return PreservedAnalyses::all();
925
930 return PA;
931}
932
933namespace llvm {
935 return new AArch64PreLegalizerCombinerLegacy();
936}
937} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define GET_GICOMBINER_CONSTRUCTOR_INITS
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
unsigned uint64_t
static const Function * getParent(const Value *V)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Provides analysis for continuously CSEing during GISel passes.
This contains common combine transformations that may be used in a combine pass,or by the target else...
Option class for Targets to specify which operations are combined how and when.
This contains the base class for all Combiners generated by TableGen.
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
#define T
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static StringRef getName(Value *V)
Value * RHS
Value * LHS
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ ICMP_NE
not equal
Definition InstrTypes.h:762
LLVM_ABI void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
Combiner implementation.
Definition Combiner.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
The actual analysis pass wrapper.
Definition CSEInfo.h:244
The CSE Analysis object.
Definition CSEInfo.h:72
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
virtual void erasingInstr(MachineInstr &MI)=0
An instruction is about to be erased.
To use KnownBitsInfo analysis in a pass, KnownBitsInfo &Info = getAnalysis<GISelValueTrackingInfoAnal...
unsigned computeNumSignBits(Register R, const APInt &DemandedElts, unsigned Depth=0)
Module * getParent()
Get the module that this global value is contained inside of...
static bool isEquality(Predicate P)
Return true if this predicate is either EQ or NE.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
Tracks which library functions to use for a particular subtarget or function.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
MachineBasicBlock * getMBB() const
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
MachineOperand * getOneDef(Register Reg) const
Returns the defining operand if there is exactly one operand defining the specified register,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
iterator_range< use_iterator > use_operands(Register Reg) const
Records a mapping from an opaque lowering context to its LibcallLoweringInfo.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
SrcImmOp_match< SrcTy, AnyImmMatch, TargetOpcode::G_ASSERT_ZEXT > m_GAssertZext(const SrcTy &Src)
Matches a G_ASSERT_ZEXT, binding its source and immediate bit width.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
SpecificImmMatch m_SpecificImm(int64_t RequestedValue)
Matches an immediate operand equal to RequestedValue.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createAArch64PreLegalizerCombiner()
@ Offset
Definition DWP.cpp:577
OuterAnalysisManagerProxy< ModuleAnalysisManager, MachineFunction > ModuleAnalysisManagerMachineFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition Utils.cpp:497
LLVM_ABI std::unique_ptr< CSEConfigBase > getStandardCSEConfigForOpt(CodeGenOptLevel Level)
Definition CSEInfo.cpp:85
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
LLVM_ABI const LibcallLoweringInfo & getLibcallLowering(const ModuleLibcallLoweringInfo &ModuleInfo, const TargetSubtargetInfo &Subtarget)
Resolve the LibcallLoweringInfo for Subtarget from the module-level ModuleInfo, applying the subtarge...
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI void extractParts(Register Reg, LLT Ty, int NumParts, SmallVectorImpl< Register > &VRegs, MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
Helper function to split a wide generic register into bitwise blocks with the given Type (which impli...
Definition Utils.cpp:511
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1137
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878