LLVM 24.0.0git
AArch64PostLegalizerCombiner.cpp
Go to the documentation of this file.
1//=== AArch64PostLegalizerCombiner.cpp --------------------------*- C++ -*-===//
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/// \file
10/// Post-legalization combines on generic MachineInstrs.
11///
12/// The combines here must preserve instruction legality.
13///
14/// Lowering combines (e.g. pseudo matching) should be handled by
15/// AArch64PostLegalizerLowering.
16///
17/// Combines which don't rely on instruction legality should go in the
18/// AArch64PreLegalizerCombiner.
19///
20//===----------------------------------------------------------------------===//
21
22#include "AArch64.h"
24#include "llvm/ADT/STLExtras.h"
43#include "llvm/Support/Debug.h"
44
45#define GET_GICOMBINER_DEPS
46#include "AArch64GenPostLegalizeGICombiner.inc"
47#undef GET_GICOMBINER_DEPS
48
49#define DEBUG_TYPE "aarch64-postlegalizer-combiner"
50
51using namespace llvm;
52using namespace MIPatternMatch;
53
54#define GET_GICOMBINER_TYPES
55#include "AArch64GenPostLegalizeGICombiner.inc"
56#undef GET_GICOMBINER_TYPES
57
58namespace {
59
60/// This combine tries do what performExtractVectorEltCombine does in SDAG.
61/// Rewrite for pairwise fadd pattern
62/// (s32 (g_extract_vector_elt
63/// (g_fadd (vXs32 Other)
64/// (g_vector_shuffle (vXs32 Other) undef <1,X,...> )) 0))
65/// ->
66/// (s32 (g_fadd (g_extract_vector_elt (vXs32 Other) 0)
67/// (g_extract_vector_elt (vXs32 Other) 1))
68bool matchExtractVecEltPairwiseAdd(
70 std::tuple<unsigned, LLT, Register> &MatchInfo) {
71 Register Src1 = MI.getOperand(1).getReg();
72 Register Src2 = MI.getOperand(2).getReg();
73 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
74
75 auto Cst = getIConstantVRegValWithLookThrough(Src2, MRI);
76 if (!Cst || Cst->Value != 0)
77 return false;
78 // SDAG also checks for FullFP16, but this looks to be beneficial anyway.
79
80 // Now check for an fadd operation. TODO: expand this for integer add?
81 auto *FAddMI = getOpcodeDef(TargetOpcode::G_FADD, Src1, MRI);
82 if (!FAddMI)
83 return false;
84
85 // If we add support for integer add, must restrict these types to just s64.
86 unsigned DstSize = DstTy.getSizeInBits();
87 if (DstSize != 16 && DstSize != 32 && DstSize != 64)
88 return false;
89
90 Register Src1Op1 = FAddMI->getOperand(1).getReg();
91 Register Src1Op2 = FAddMI->getOperand(2).getReg();
92 MachineInstr *Shuffle =
93 getOpcodeDef(TargetOpcode::G_SHUFFLE_VECTOR, Src1Op2, MRI);
94 MachineInstr *Other = MRI.getVRegDef(Src1Op1);
95 if (!Shuffle) {
96 Shuffle = getOpcodeDef(TargetOpcode::G_SHUFFLE_VECTOR, Src1Op1, MRI);
97 Other = MRI.getVRegDef(Src1Op2);
98 }
99
100 // We're looking for a shuffle that moves the second element to index 0.
101 if (Shuffle && Shuffle->getOperand(3).getShuffleMask()[0] == 1 &&
102 Other == MRI.getVRegDef(Shuffle->getOperand(1).getReg())) {
103 std::get<0>(MatchInfo) = TargetOpcode::G_FADD;
104 std::get<1>(MatchInfo) = DstTy;
105 std::get<2>(MatchInfo) = Other->getOperand(0).getReg();
106 return true;
107 }
108 return false;
109}
110
111void applyExtractVecEltPairwiseAdd(
113 std::tuple<unsigned, LLT, Register> &MatchInfo) {
114 unsigned Opc = std::get<0>(MatchInfo);
115 assert(Opc == TargetOpcode::G_FADD && "Unexpected opcode!");
116 // We want to generate two extracts of elements 0 and 1, and add them.
117 LLT Ty = std::get<1>(MatchInfo);
118 Register Src = std::get<2>(MatchInfo);
119 LLT s64 = LLT::integer(64);
120 B.setInstrAndDebugLoc(MI);
121 auto Elt0 = B.buildExtractVectorElement(Ty, Src, B.buildConstant(s64, 0));
122 auto Elt1 = B.buildExtractVectorElement(Ty, Src, B.buildConstant(s64, 1));
123 B.buildInstr(Opc, {MI.getOperand(0).getReg()}, {Elt0, Elt1});
124 MI.eraseFromParent();
125}
126
128 // TODO: check if extended build vector as well.
129 return mi_match(R, MRI, m_GSExt(m_Reg())) ||
130 mi_match(R, MRI, m_GSExtInReg(m_Reg()));
131}
132
134 // TODO: check if extended build vector as well.
135 return mi_match(R, MRI, m_GZExt(m_Reg()));
136}
137
138bool matchAArch64MulConstCombine(
140 std::function<void(MachineIRBuilder &B, Register DstReg)> &ApplyFn) {
141 assert(MI.getOpcode() == TargetOpcode::G_MUL);
142 Register LHS = MI.getOperand(1).getReg();
143 Register RHS = MI.getOperand(2).getReg();
144 Register Dst = MI.getOperand(0).getReg();
145 const LLT Ty = MRI.getType(LHS);
146
147 // The below optimizations require a constant RHS.
148 auto Const = getIConstantVRegValWithLookThrough(RHS, MRI);
149 if (!Const)
150 return false;
151
152 APInt ConstValue = Const->Value.sext(Ty.getSizeInBits());
153 // The following code is ported from AArch64ISelLowering.
154 // Multiplication of a power of two plus/minus one can be done more
155 // cheaply as shift+add/sub. For now, this is true unilaterally. If
156 // future CPUs have a cheaper MADD instruction, this may need to be
157 // gated on a subtarget feature. For Cyclone, 32-bit MADD is 4 cycles and
158 // 64-bit is 5 cycles, so this is always a win.
159 // More aggressively, some multiplications N0 * C can be lowered to
160 // shift+add+shift if the constant C = A * B where A = 2^N + 1 and B = 2^M,
161 // e.g. 6=3*2=(2+1)*2.
162 // TODO: consider lowering more cases, e.g. C = 14, -6, -14 or even 45
163 // which equals to (1+2)*16-(1+2).
164 // TrailingZeroes is used to test if the mul can be lowered to
165 // shift+add+shift.
166 unsigned TrailingZeroes = ConstValue.countr_zero();
167 if (TrailingZeroes) {
168 // Conservatively do not lower to shift+add+shift if the mul might be
169 // folded into smul or umul.
170 if (MRI.hasOneNonDBGUse(LHS) &&
171 (isSignExtended(LHS, MRI) || isZeroExtended(LHS, MRI)))
172 return false;
173 // Conservatively do not lower to shift+add+shift if the mul might be
174 // folded into madd or msub.
175 if (MRI.hasOneNonDBGUse(Dst)) {
177 unsigned UseOpc = UseMI.getOpcode();
178 if (UseOpc == TargetOpcode::G_ADD || UseOpc == TargetOpcode::G_PTR_ADD ||
179 UseOpc == TargetOpcode::G_SUB)
180 return false;
181 }
182 }
183 // Use ShiftedConstValue instead of ConstValue to support both shift+add/sub
184 // and shift+add+shift.
185 APInt ShiftedConstValue = ConstValue.ashr(TrailingZeroes);
186
187 unsigned ShiftAmt, AddSubOpc;
188 // Is the shifted value the LHS operand of the add/sub?
189 bool ShiftValUseIsLHS = true;
190 // Do we need to negate the result?
191 bool NegateResult = false;
192
193 if (ConstValue.isNonNegative()) {
194 // (mul x, 2^N + 1) => (add (shl x, N), x)
195 // (mul x, 2^N - 1) => (sub (shl x, N), x)
196 // (mul x, (2^N + 1) * 2^M) => (shl (add (shl x, N), x), M)
197 APInt SCVMinus1 = ShiftedConstValue - 1;
198 APInt CVPlus1 = ConstValue + 1;
199 if (SCVMinus1.isPowerOf2()) {
200 ShiftAmt = SCVMinus1.logBase2();
201 AddSubOpc = TargetOpcode::G_ADD;
202 } else if (CVPlus1.isPowerOf2()) {
203 ShiftAmt = CVPlus1.logBase2();
204 AddSubOpc = TargetOpcode::G_SUB;
205 } else
206 return false;
207 } else {
208 // (mul x, -(2^N - 1)) => (sub x, (shl x, N))
209 // (mul x, -(2^N + 1)) => - (add (shl x, N), x)
210 APInt CVNegPlus1 = -ConstValue + 1;
211 APInt CVNegMinus1 = -ConstValue - 1;
212 if (CVNegPlus1.isPowerOf2()) {
213 ShiftAmt = CVNegPlus1.logBase2();
214 AddSubOpc = TargetOpcode::G_SUB;
215 ShiftValUseIsLHS = false;
216 } else if (CVNegMinus1.isPowerOf2()) {
217 ShiftAmt = CVNegMinus1.logBase2();
218 AddSubOpc = TargetOpcode::G_ADD;
219 NegateResult = true;
220 } else
221 return false;
222 }
223
224 if (NegateResult && TrailingZeroes)
225 return false;
226
227 ApplyFn = [=](MachineIRBuilder &B, Register DstReg) {
228 auto Shift = B.buildConstant(LLT::integer(64), ShiftAmt);
229 auto ShiftedVal = B.buildShl(Ty, LHS, Shift);
230
231 Register AddSubLHS = ShiftValUseIsLHS ? ShiftedVal.getReg(0) : LHS;
232 Register AddSubRHS = ShiftValUseIsLHS ? LHS : ShiftedVal.getReg(0);
233 auto Res = B.buildInstr(AddSubOpc, {Ty}, {AddSubLHS, AddSubRHS});
234 assert(!(NegateResult && TrailingZeroes) &&
235 "NegateResult and TrailingZeroes cannot both be true for now.");
236 // Negate the result.
237 if (NegateResult) {
238 B.buildSub(DstReg, B.buildConstant(Ty, 0), Res);
239 return;
240 }
241 // Shift the result.
242 if (TrailingZeroes) {
243 B.buildShl(DstReg, Res,
244 B.buildConstant(LLT::integer(64), TrailingZeroes));
245 return;
246 }
247 B.buildCopy(DstReg, Res.getReg(0));
248 };
249 return true;
250}
251
252void applyAArch64MulConstCombine(
254 std::function<void(MachineIRBuilder &B, Register DstReg)> &ApplyFn) {
255 B.setInstrAndDebugLoc(MI);
256 ApplyFn(B, MI.getOperand(0).getReg());
257 MI.eraseFromParent();
258}
259
260/// Try to fold a G_MERGE_VALUES of 2 s32 sources, where the second source
261/// is a zero, into a G_ZEXT of the first.
262bool matchFoldMergeToZext(MachineInstr &MI, MachineRegisterInfo &MRI) {
263 auto &Merge = cast<GMerge>(MI);
264 LLT SrcTy = MRI.getType(Merge.getSourceReg(0));
265 if (SrcTy != LLT::scalar(32) || Merge.getNumSources() != 2)
266 return false;
267 return mi_match(Merge.getSourceReg(1), MRI, m_SpecificICst(0));
268}
269
270void applyFoldMergeToZext(MachineInstr &MI, MachineRegisterInfo &MRI,
272 // Mutate %d(s64) = G_MERGE_VALUES %a(s32), 0(s32)
273 // ->
274 // %d(s64) = G_ZEXT %a(s32)
275 Observer.changingInstr(MI);
276 MI.setDesc(B.getTII().get(TargetOpcode::G_ZEXT));
277 MI.removeOperand(2);
278 Observer.changedInstr(MI);
279}
280
281/// \returns True if a G_ANYEXT instruction \p MI should be mutated to a G_ZEXT
282/// instruction.
283bool matchMutateAnyExtToZExt(MachineInstr &MI, MachineRegisterInfo &MRI) {
284 // If this is coming from a scalar compare then we can use a G_ZEXT instead of
285 // a G_ANYEXT:
286 //
287 // %cmp:_(s32) = G_[I|F]CMP ... <-- produces 0/1.
288 // %ext:_(s64) = G_ANYEXT %cmp(s32)
289 //
290 // By doing this, we can leverage more KnownBits combines.
291 assert(MI.getOpcode() == TargetOpcode::G_ANYEXT);
292 Register Dst = MI.getOperand(0).getReg();
293 Register Src = MI.getOperand(1).getReg();
294 return MRI.getType(Dst).isScalar() &&
295 mi_match(Src, MRI,
297 m_GFCmp(m_Pred(), m_Reg(), m_Reg())));
298}
299
300void applyMutateAnyExtToZExt(MachineInstr &MI, MachineRegisterInfo &MRI,
302 GISelChangeObserver &Observer) {
303 Observer.changingInstr(MI);
304 MI.setDesc(B.getTII().get(TargetOpcode::G_ZEXT));
305 Observer.changedInstr(MI);
306}
307
308/// Match a 128b store of zero and split it into two 64 bit stores, for
309/// size/performance reasons.
310bool matchSplitStoreZero128(MachineInstr &MI, MachineRegisterInfo &MRI) {
312 if (!Store.isSimple())
313 return false;
314 LLT ValTy = MRI.getType(Store.getValueReg());
315 if (ValTy.isScalableVector())
316 return false;
317 if (!ValTy.isVector() || ValTy.getSizeInBits() != 128)
318 return false;
319 if (Store.getMemSizeInBits() != ValTy.getSizeInBits())
320 return false; // Don't split truncating stores.
321 if (!MRI.hasOneNonDBGUse(Store.getValueReg()))
322 return false;
323 auto MaybeCst = isConstantOrConstantSplatVector(Store.getValueReg(), MRI);
324 return MaybeCst && MaybeCst->isZero();
325}
326
327void applySplitStoreZero128(MachineInstr &MI, MachineRegisterInfo &MRI,
329 GISelChangeObserver &Observer) {
330 B.setInstrAndDebugLoc(MI);
332 assert(MRI.getType(Store.getValueReg()).isVector() &&
333 "Expected a vector store value");
334 LLT NewTy = LLT::integer(64);
335 Register PtrReg = Store.getPointerReg();
336 auto Zero = B.buildConstant(NewTy, 0);
337 auto HighPtr =
338 B.buildPtrAdd(MRI.getType(PtrReg), PtrReg, B.buildConstant(NewTy, 8));
339 auto &MF = *MI.getMF();
340 auto *LowMMO = MF.getMachineMemOperand(&Store.getMMO(), 0, NewTy);
341 auto *HighMMO = MF.getMachineMemOperand(&Store.getMMO(), 8, NewTy);
342 B.buildStore(Zero, PtrReg, *LowMMO);
343 B.buildStore(Zero, HighPtr, *HighMMO);
344 Store.eraseFromParent();
345}
346
347bool matchOrToBSP(MachineInstr &MI, MachineRegisterInfo &MRI,
348 std::tuple<Register, Register, Register> &MatchInfo) {
349 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
350 if (!DstTy.isVector())
351 return false;
352
353 Register AO1, AO2, BVO1, BVO2;
354 if (!mi_match(MI, MRI,
355 m_GOr(m_GAnd(m_Reg(AO1), m_Reg(BVO1)),
356 m_GAnd(m_Reg(AO2), m_Reg(BVO2)))))
357 return false;
358
359 auto *BV1 = getOpcodeDef<GBuildVector>(BVO1, MRI);
360 auto *BV2 = getOpcodeDef<GBuildVector>(BVO2, MRI);
361 if (!BV1 || !BV2)
362 return false;
363
364 for (int I = 0, E = DstTy.getNumElements(); I < E; I++) {
365 auto ValAndVReg1 =
366 getIConstantVRegValWithLookThrough(BV1->getSourceReg(I), MRI);
367 auto ValAndVReg2 =
368 getIConstantVRegValWithLookThrough(BV2->getSourceReg(I), MRI);
369 if (!ValAndVReg1 || !ValAndVReg2 ||
370 ValAndVReg1->Value != ~ValAndVReg2->Value)
371 return false;
372 }
373
374 MatchInfo = {AO1, AO2, BVO1};
375 return true;
376}
377
378void applyOrToBSP(MachineInstr &MI, MachineRegisterInfo &MRI,
380 std::tuple<Register, Register, Register> &MatchInfo) {
381 B.setInstrAndDebugLoc(MI);
382 B.buildInstr(
383 AArch64::G_BSP, {MI.getOperand(0).getReg()},
384 {std::get<2>(MatchInfo), std::get<0>(MatchInfo), std::get<1>(MatchInfo)});
385 MI.eraseFromParent();
386}
387
388/// Match G_TRUNC (G_OR X, Y) => G_ADDHN X, Y when both inputs are sign
389/// extended from the result element type. The high half of the addition then
390/// equals the truncation of the OR.
391bool matchTruncOrToADDHN(MachineInstr &MI, MachineRegisterInfo &MRI,
393 Register Src0, Register Src1) {
394 if (!MRI.hasOneUse(Or))
395 return false;
396
397 LLT DstTy = MRI.getType(Dst);
398 LLT SrcTy = MRI.getType(Or);
399 if (!((DstTy == LLT::fixed_vector(8, 8) &&
400 SrcTy == LLT::fixed_vector(8, 16)) ||
401 (DstTy == LLT::fixed_vector(4, 16) &&
402 SrcTy == LLT::fixed_vector(4, 32)) ||
403 (DstTy == LLT::fixed_vector(2, 32) &&
404 SrcTy == LLT::fixed_vector(2, 64))))
405 return false;
406
407 // If the narrow result is immediately any-extended back to the original type,
408 // the G_OR is cheaper than G_ADDHN followed by a vector widen.
409 if (MRI.hasOneNonDBGUse(Dst)) {
410 MachineInstr &UseMI = *MRI.use_nodbg_instructions(Dst).begin();
411 if (UseMI.getOpcode() == TargetOpcode::G_ANYEXT &&
412 MRI.getType(UseMI.getOperand(0).getReg()) == SrcTy)
413 return false;
414 }
415
416 unsigned EltSize = SrcTy.getScalarSizeInBits();
417 if (VT->computeNumSignBits(Src0) != EltSize ||
418 VT->computeNumSignBits(Src1) != EltSize)
419 return false;
420
421 return true;
422}
423
424// Combines Mul(And(Srl(X, 15), 0x10001), 0xffff) into CMLTz
425bool matchCombineMulCMLT(MachineInstr &MI, MachineRegisterInfo &MRI,
426 Register &SrcReg) {
427 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
428
429 if (DstTy != LLT::fixed_vector(2, 64) && DstTy != LLT::fixed_vector(2, 32) &&
430 DstTy != LLT::fixed_vector(4, 32) && DstTy != LLT::fixed_vector(4, 16) &&
431 DstTy != LLT::fixed_vector(8, 16))
432 return false;
433
434 auto AndMI = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
435 if (AndMI->getOpcode() != TargetOpcode::G_AND)
436 return false;
437 auto LShrMI = getDefIgnoringCopies(AndMI->getOperand(1).getReg(), MRI);
438 if (LShrMI->getOpcode() != TargetOpcode::G_LSHR)
439 return false;
440
441 // Check the constant splat values
442 auto V1 = isConstantOrConstantSplatVector(MI.getOperand(2).getReg(), MRI);
443 auto V2 = isConstantOrConstantSplatVector(AndMI->getOperand(2).getReg(), MRI);
444 auto V3 =
445 isConstantOrConstantSplatVector(LShrMI->getOperand(2).getReg(), MRI);
446 if (!V1.has_value() || !V2.has_value() || !V3.has_value())
447 return false;
448 unsigned HalfSize = DstTy.getScalarSizeInBits() / 2;
449 if (!V1.value().isMask(HalfSize) || V2.value() != (1ULL | 1ULL << HalfSize) ||
450 V3 != (HalfSize - 1))
451 return false;
452
453 SrcReg = LShrMI->getOperand(1).getReg();
454
455 return true;
456}
457
458void applyCombineMulCMLT(MachineInstr &MI, MachineRegisterInfo &MRI,
459 MachineIRBuilder &B, Register &SrcReg) {
460 Register DstReg = MI.getOperand(0).getReg();
461 LLT DstTy = MRI.getType(DstReg);
462 LLT HalfTy = DstTy.changeElementCount(DstTy.getElementCount() * 2)
464
465 Register ZeroVec = B.buildConstant(HalfTy, 0).getReg(0);
466 Register CastReg =
467 B.buildInstr(TargetOpcode::G_BITCAST, {HalfTy}, {SrcReg}).getReg(0);
468 Register CMLTReg =
469 B.buildICmp(CmpInst::Predicate::ICMP_SLT, HalfTy, CastReg, ZeroVec)
470 .getReg(0);
471
472 B.buildInstr(TargetOpcode::G_BITCAST, {DstReg}, {CMLTReg}).getReg(0);
473 MI.eraseFromParent();
474}
475
476// Match mul({z/s}ext , {z/s}ext) => {u/s}mull
477bool matchExtMulToMULL(MachineInstr &MI, MachineRegisterInfo &MRI,
479 std::tuple<bool, Register, Register> &MatchInfo) {
480 // Get the instructions that defined the source operand
481 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
482 MachineInstr *I1 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
483 MachineInstr *I2 = getDefIgnoringCopies(MI.getOperand(2).getReg(), MRI);
484 unsigned I1Opc = I1->getOpcode();
485 unsigned I2Opc = I2->getOpcode();
486 unsigned EltSize = DstTy.getScalarSizeInBits();
487
488 if (!DstTy.isVector() || I1->getNumOperands() < 2 || I2->getNumOperands() < 2)
489 return false;
490
491 auto IsAtLeastDoubleExtend = [&](Register R) {
492 LLT Ty = MRI.getType(R);
493 return EltSize >= Ty.getScalarSizeInBits() * 2;
494 };
495
496 // If the source operands were EXTENDED before, then {U/S}MULL can be used
497 bool IsZExt1 =
498 I1Opc == TargetOpcode::G_ZEXT || I1Opc == TargetOpcode::G_ANYEXT;
499 bool IsZExt2 =
500 I2Opc == TargetOpcode::G_ZEXT || I2Opc == TargetOpcode::G_ANYEXT;
501 if (IsZExt1 && IsZExt2 && IsAtLeastDoubleExtend(I1->getOperand(1).getReg()) &&
502 IsAtLeastDoubleExtend(I2->getOperand(1).getReg())) {
503 get<0>(MatchInfo) = true;
504 get<1>(MatchInfo) = I1->getOperand(1).getReg();
505 get<2>(MatchInfo) = I2->getOperand(1).getReg();
506 return true;
507 }
508
509 bool IsSExt1 =
510 I1Opc == TargetOpcode::G_SEXT || I1Opc == TargetOpcode::G_ANYEXT;
511 bool IsSExt2 =
512 I2Opc == TargetOpcode::G_SEXT || I2Opc == TargetOpcode::G_ANYEXT;
513 if (IsSExt1 && IsSExt2 && IsAtLeastDoubleExtend(I1->getOperand(1).getReg()) &&
514 IsAtLeastDoubleExtend(I2->getOperand(1).getReg())) {
515 get<0>(MatchInfo) = false;
516 get<1>(MatchInfo) = I1->getOperand(1).getReg();
517 get<2>(MatchInfo) = I2->getOperand(1).getReg();
518 return true;
519 }
520
521 // Select UMULL if we can replace the other operand with an extend.
522 APInt Mask = APInt::getHighBitsSet(EltSize, EltSize / 2);
523 if (KB && (IsZExt1 || IsZExt2) &&
524 IsAtLeastDoubleExtend(IsZExt1 ? I1->getOperand(1).getReg()
525 : I2->getOperand(1).getReg())) {
526 Register ZExtOp =
527 IsZExt1 ? MI.getOperand(2).getReg() : MI.getOperand(1).getReg();
528 if (KB->maskedValueIsZero(ZExtOp, Mask)) {
529 get<0>(MatchInfo) = true;
530 get<1>(MatchInfo) = IsZExt1 ? I1->getOperand(1).getReg() : ZExtOp;
531 get<2>(MatchInfo) = IsZExt1 ? ZExtOp : I2->getOperand(1).getReg();
532 return true;
533 }
534 } else if (KB && DstTy == LLT::fixed_vector(2, 64) &&
535 KB->maskedValueIsZero(MI.getOperand(1).getReg(), Mask) &&
536 KB->maskedValueIsZero(MI.getOperand(2).getReg(), Mask)) {
537 get<0>(MatchInfo) = true;
538 get<1>(MatchInfo) = MI.getOperand(1).getReg();
539 get<2>(MatchInfo) = MI.getOperand(2).getReg();
540 return true;
541 }
542
543 if (KB && (IsSExt1 || IsSExt2) &&
544 IsAtLeastDoubleExtend(IsSExt1 ? I1->getOperand(1).getReg()
545 : I2->getOperand(1).getReg())) {
546 Register SExtOp =
547 IsSExt1 ? MI.getOperand(2).getReg() : MI.getOperand(1).getReg();
548 if (KB->computeNumSignBits(SExtOp) > EltSize / 2) {
549 get<0>(MatchInfo) = false;
550 get<1>(MatchInfo) = IsSExt1 ? I1->getOperand(1).getReg() : SExtOp;
551 get<2>(MatchInfo) = IsSExt1 ? SExtOp : I2->getOperand(1).getReg();
552 return true;
553 }
554 } else if (KB && DstTy == LLT::fixed_vector(2, 64) &&
555 KB->computeNumSignBits(MI.getOperand(1).getReg()) > EltSize / 2 &&
556 KB->computeNumSignBits(MI.getOperand(2).getReg()) > EltSize / 2) {
557 get<0>(MatchInfo) = false;
558 get<1>(MatchInfo) = MI.getOperand(1).getReg();
559 get<2>(MatchInfo) = MI.getOperand(2).getReg();
560 return true;
561 }
562
563 return false;
564}
565
566void applyExtMulToMULL(MachineInstr &MI, MachineRegisterInfo &MRI,
568 std::tuple<bool, Register, Register> &MatchInfo) {
569 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
570 "Expected a G_MUL instruction");
571
572 // Get the instructions that defined the source operand
573 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
574 bool IsZExt = get<0>(MatchInfo);
575 Register Src1Reg = get<1>(MatchInfo);
576 Register Src2Reg = get<2>(MatchInfo);
577 LLT Src1Ty = MRI.getType(Src1Reg);
578 LLT Src2Ty = MRI.getType(Src2Reg);
579 LLT HalfDstTy = DstTy.changeElementSize(DstTy.getScalarSizeInBits() / 2);
580 unsigned ExtOpc = IsZExt ? TargetOpcode::G_ZEXT : TargetOpcode::G_SEXT;
581
582 if (Src1Ty.getScalarSizeInBits() * 2 != DstTy.getScalarSizeInBits())
583 Src1Reg = B.buildExtOrTrunc(ExtOpc, {HalfDstTy}, {Src1Reg}).getReg(0);
584 if (Src2Ty.getScalarSizeInBits() * 2 != DstTy.getScalarSizeInBits())
585 Src2Reg = B.buildExtOrTrunc(ExtOpc, {HalfDstTy}, {Src2Reg}).getReg(0);
586
587 B.buildInstr(IsZExt ? AArch64::G_UMULL : AArch64::G_SMULL,
588 {MI.getOperand(0).getReg()}, {Src1Reg, Src2Reg});
589 MI.eraseFromParent();
590}
591
592static bool matchSubAddMulReassoc(Register Mul1, Register Mul2, Register Sub,
593 Register Src, MachineRegisterInfo &MRI) {
594 if (!MRI.hasOneUse(Sub))
595 return false;
597 return false;
599 if (M1->getOpcode() != AArch64::G_MUL &&
600 M1->getOpcode() != AArch64::G_SMULL &&
601 M1->getOpcode() != AArch64::G_UMULL)
602 return false;
603 MachineInstr *M2 = getDefIgnoringCopies(Mul2, MRI);
604 if (M2->getOpcode() != AArch64::G_MUL &&
605 M2->getOpcode() != AArch64::G_SMULL &&
606 M2->getOpcode() != AArch64::G_UMULL)
607 return false;
608 return true;
609}
610
611static void applySubAddMulReassoc(MachineInstr &MI, MachineInstr &Sub,
613 GISelChangeObserver &Observer) {
614 Register Src = MI.getOperand(1).getReg();
615 Register Tmp = MI.getOperand(2).getReg();
616 Register Mul1 = Sub.getOperand(1).getReg();
617 Register Mul2 = Sub.getOperand(2).getReg();
618 Observer.changingInstr(MI);
619 B.buildInstr(AArch64::G_SUB, {Tmp}, {Src, Mul1});
620 MI.getOperand(1).setReg(Tmp);
621 MI.getOperand(2).setReg(Mul2);
622 Sub.eraseFromParent();
623 Observer.changedInstr(MI);
624}
625
626class AArch64PostLegalizerCombinerImpl : public Combiner {
627protected:
628 const CombinerHelper Helper;
629 const AArch64PostLegalizerCombinerImplRuleConfig &RuleConfig;
630 const AArch64Subtarget &STI;
631
632public:
633 AArch64PostLegalizerCombinerImpl(
635 GISelCSEInfo *CSEInfo,
636 const AArch64PostLegalizerCombinerImplRuleConfig &RuleConfig,
637 const AArch64Subtarget &STI, MachineDominatorTree *MDT,
638 const LegalizerInfo *LI);
639
640 static const char *getName() { return "AArch64PostLegalizerCombiner"; }
641
642 bool tryCombineAll(MachineInstr &I) const override;
643
644private:
645#define GET_GICOMBINER_CLASS_MEMBERS
646#include "AArch64GenPostLegalizeGICombiner.inc"
647#undef GET_GICOMBINER_CLASS_MEMBERS
648};
649
650#define GET_GICOMBINER_IMPL
651#include "AArch64GenPostLegalizeGICombiner.inc"
652#undef GET_GICOMBINER_IMPL
653
654AArch64PostLegalizerCombinerImpl::AArch64PostLegalizerCombinerImpl(
656 GISelCSEInfo *CSEInfo,
657 const AArch64PostLegalizerCombinerImplRuleConfig &RuleConfig,
658 const AArch64Subtarget &STI, MachineDominatorTree *MDT,
659 const LegalizerInfo *LI)
660 : Combiner(MF, CInfo, &VT, CSEInfo),
661 Helper(Observer, B, /*IsPreLegalize*/ false, &VT, MDT, LI),
662 RuleConfig(RuleConfig), STI(STI),
664#include "AArch64GenPostLegalizeGICombiner.inc"
666{
667}
668
669struct StoreInfo {
670 GStore *St = nullptr;
671 // The G_PTR_ADD that's used by the store. We keep this to cache the
672 // MachineInstr def.
673 GPtrAdd *Ptr = nullptr;
674 // The signed offset to the Ptr instruction.
675 int64_t Offset = 0;
676 LLT StoredType;
677};
678
679static bool tryOptimizeConsecStores(SmallVectorImpl<StoreInfo> &Stores,
680 CSEMIRBuilder &MIB) {
681 if (Stores.size() <= 2)
682 return false;
683
684 // Profitabity checks:
685 int64_t BaseOffset = Stores[0].Offset;
686 unsigned NumPairsExpected = Stores.size() / 2;
687 unsigned TotalInstsExpected = NumPairsExpected + (Stores.size() % 2);
688 // Size savings will depend on whether we can fold the offset, as an
689 // immediate of an ADD.
690 auto &TLI = *MIB.getMF().getSubtarget().getTargetLowering();
691 if (!TLI.isLegalAddImmediate(BaseOffset))
692 TotalInstsExpected++;
693 int SavingsExpected = Stores.size() - TotalInstsExpected;
694 if (SavingsExpected <= 0)
695 return false;
696
697 auto &MRI = MIB.getMF().getRegInfo();
698
699 // We have a series of consecutive stores. Factor out the common base
700 // pointer and rewrite the offsets.
701 Register NewBase = Stores[0].Ptr->getReg(0);
702 for (auto &SInfo : Stores) {
703 // Compute a new pointer with the new base ptr and adjusted offset.
704 MIB.setInstrAndDebugLoc(*SInfo.St);
705 auto NewOff =
706 MIB.buildConstant(LLT::integer(64), SInfo.Offset - BaseOffset);
707 auto NewPtr = MIB.buildPtrAdd(MRI.getType(SInfo.St->getPointerReg()),
708 NewBase, NewOff);
709 if (MIB.getObserver())
710 MIB.getObserver()->changingInstr(*SInfo.St);
711 SInfo.St->getOperand(1).setReg(NewPtr.getReg(0));
712 if (MIB.getObserver())
713 MIB.getObserver()->changedInstr(*SInfo.St);
714 }
715 LLVM_DEBUG(dbgs() << "Split a series of " << Stores.size()
716 << " stores into a base pointer and offsets.\n");
717 return true;
718}
719
720static cl::opt<bool>
721 EnableConsecutiveMemOpOpt("aarch64-postlegalizer-consecutive-memops",
722 cl::init(true), cl::Hidden,
723 cl::desc("Enable consecutive memop optimization "
724 "in AArch64PostLegalizerCombiner"));
725
726static bool optimizeConsecutiveMemOpAddressing(MachineFunction &MF,
727 CSEMIRBuilder &MIB) {
728 // This combine needs to run after all reassociations/folds on pointer
729 // addressing have been done, specifically those that combine two G_PTR_ADDs
730 // with constant offsets into a single G_PTR_ADD with a combined offset.
731 // The goal of this optimization is to undo that combine in the case where
732 // doing so has prevented the formation of pair stores due to illegal
733 // addressing modes of STP. The reason that we do it here is because
734 // it's much easier to undo the transformation of a series consecutive
735 // mem ops, than it is to detect when doing it would be a bad idea looking
736 // at a single G_PTR_ADD in the reassociation/ptradd_immed_chain combine.
737 //
738 // An example:
739 // G_STORE %11:_(<2 x s64>), %base:_(p0) :: (store (<2 x s64>), align 1)
740 // %off1:_(s64) = G_CONSTANT i64 4128
741 // %p1:_(p0) = G_PTR_ADD %0:_, %off1:_(s64)
742 // G_STORE %11:_(<2 x s64>), %p1:_(p0) :: (store (<2 x s64>), align 1)
743 // %off2:_(s64) = G_CONSTANT i64 4144
744 // %p2:_(p0) = G_PTR_ADD %0:_, %off2:_(s64)
745 // G_STORE %11:_(<2 x s64>), %p2:_(p0) :: (store (<2 x s64>), align 1)
746 // %off3:_(s64) = G_CONSTANT i64 4160
747 // %p3:_(p0) = G_PTR_ADD %0:_, %off3:_(s64)
748 // G_STORE %11:_(<2 x s64>), %17:_(p0) :: (store (<2 x s64>), align 1)
749 bool Changed = false;
750 auto &MRI = MF.getRegInfo();
751
752 if (!EnableConsecutiveMemOpOpt)
753 return Changed;
754
756 // If we see a load, then we keep track of any values defined by it.
757 // In the following example, STP formation will fail anyway because
758 // the latter store is using a load result that appears after the
759 // the prior store. In this situation if we factor out the offset then
760 // we increase code size for no benefit.
761 // G_STORE %v1:_(s64), %base:_(p0) :: (store (s64))
762 // %v2:_(s64) = G_LOAD %ldptr:_(p0) :: (load (s64))
763 // G_STORE %v2:_(s64), %base:_(p0) :: (store (s64))
764 SmallVector<Register> LoadValsSinceLastStore;
765
766 auto storeIsValid = [&](StoreInfo &Last, StoreInfo New) {
767 // Check if this store is consecutive to the last one.
768 if (Last.Ptr->getBaseReg() != New.Ptr->getBaseReg() ||
769 (Last.Offset + static_cast<int64_t>(Last.StoredType.getSizeInBytes()) !=
770 New.Offset) ||
771 Last.StoredType != New.StoredType)
772 return false;
773
774 // Check if this store is using a load result that appears after the
775 // last store. If so, bail out.
776 if (any_of(LoadValsSinceLastStore, [&](Register LoadVal) {
777 return New.St->getValueReg() == LoadVal;
778 }))
779 return false;
780
781 // Check if the current offset would be too large for STP.
782 // If not, then STP formation should be able to handle it, so we don't
783 // need to do anything.
784 int64_t MaxLegalOffset;
785 switch (New.StoredType.getSizeInBits()) {
786 case 32:
787 MaxLegalOffset = 252;
788 break;
789 case 64:
790 MaxLegalOffset = 504;
791 break;
792 case 128:
793 MaxLegalOffset = 1008;
794 break;
795 default:
796 llvm_unreachable("Unexpected stored type size");
797 }
798 if (New.Offset < MaxLegalOffset)
799 return false;
800
801 // If factoring it out still wouldn't help then don't bother.
802 return New.Offset - Stores[0].Offset <= MaxLegalOffset;
803 };
804
805 auto resetState = [&]() {
806 Stores.clear();
807 LoadValsSinceLastStore.clear();
808 };
809
810 for (auto &MBB : MF) {
811 // We're looking inside a single BB at a time since the memset pattern
812 // should only be in a single block.
813 resetState();
814 for (auto &MI : MBB) {
815 // Skip for scalable vectors
816 if (auto *LdSt = dyn_cast<GLoadStore>(&MI);
817 LdSt && MRI.getType(LdSt->getOperand(0).getReg()).isScalableVector())
818 continue;
819
820 if (auto *St = dyn_cast<GStore>(&MI)) {
821 Register PtrBaseReg;
823 LLT StoredValTy = MRI.getType(St->getValueReg());
824 unsigned ValSize = StoredValTy.getSizeInBits();
825 if (ValSize < 32 || St->getMMO().getSizeInBits() != ValSize)
826 continue;
827
828 Register PtrReg = St->getPointerReg();
829 if (mi_match(
830 PtrReg, MRI,
831 m_OneNonDBGUse(m_GPtrAdd(m_Reg(PtrBaseReg), m_ICst(Offset))))) {
832 GPtrAdd *PtrAdd = cast<GPtrAdd>(MRI.getVRegDef(PtrReg));
833 StoreInfo New = {St, PtrAdd, Offset.getSExtValue(), StoredValTy};
834
835 if (Stores.empty()) {
836 Stores.push_back(New);
837 continue;
838 }
839
840 // Check if this store is a valid continuation of the sequence.
841 auto &Last = Stores.back();
842 if (storeIsValid(Last, New)) {
843 Stores.push_back(New);
844 LoadValsSinceLastStore.clear(); // Reset the load value tracking.
845 } else {
846 // The store isn't a valid to consider for the prior sequence,
847 // so try to optimize what we have so far and start a new sequence.
848 Changed |= tryOptimizeConsecStores(Stores, MIB);
849 resetState();
850 Stores.push_back(New);
851 }
852 }
853 } else if (auto *Ld = dyn_cast<GLoad>(&MI)) {
854 LoadValsSinceLastStore.push_back(Ld->getDstReg());
855 }
856 }
857 Changed |= tryOptimizeConsecStores(Stores, MIB);
858 resetState();
859 }
860
861 return Changed;
862}
863
864bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo,
866 const AArch64PostLegalizerCombinerImplRuleConfig &RuleConfig,
867 bool EnableOpt, bool IsOptNone) {
868 if (MF.getProperties().hasFailedISel())
869 return false;
870 const Function &F = MF.getFunction();
871
873 const LegalizerInfo *LI = ST.getLegalizerInfo();
874
875 CombinerInfo CInfo(/*AllowIllegalOps=*/false, /*ShouldLegalizeIllegal=*/false,
876 /*LegalizerInfo=*/LI, EnableOpt, F.hasOptSize(),
877 F.hasMinSize());
878 // Disable fixed-point iteration to reduce compile-time
879 CInfo.MaxIterations = 1;
880 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
881 // Legalizer performs DCE, so a full DCE pass is unnecessary.
882 CInfo.EnableFullDCE = false;
883 AArch64PostLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST,
884 MDT, LI);
885 bool Changed = Impl.combineMachineInstrs();
886
887 CSEMIRBuilder MIB(MF);
888 MIB.setCSEInfo(CSEInfo);
889 Changed |= optimizeConsecutiveMemOpAddressing(MF, MIB);
890 return Changed;
891}
892
893class AArch64PostLegalizerCombinerLegacy : public MachineFunctionPass {
894public:
895 static char ID;
896
897 AArch64PostLegalizerCombinerLegacy(bool IsOptNone = false);
898
899 StringRef getPassName() const override {
900 return "AArch64PostLegalizerCombiner";
901 }
902
903 bool runOnMachineFunction(MachineFunction &MF) override;
904 void getAnalysisUsage(AnalysisUsage &AU) const override;
905
906 MachineFunctionProperties getRequiredProperties() const override {
907 return MachineFunctionProperties().set(
908 MachineFunctionProperties::Property::Legalized);
909 }
910
911private:
912 bool IsOptNone;
913 AArch64PostLegalizerCombinerImplRuleConfig RuleConfig;
914};
915} // end anonymous namespace
916
917void AArch64PostLegalizerCombinerLegacy::getAnalysisUsage(
918 AnalysisUsage &AU) const {
919 AU.setPreservesCFG();
921 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
922 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
923 if (!IsOptNone) {
924 AU.addRequired<MachineDominatorTreeWrapperPass>();
925 AU.addRequired<GISelCSEAnalysisWrapperPass>();
926 AU.addPreserved<GISelCSEAnalysisWrapperPass>();
927 }
929}
930
931AArch64PostLegalizerCombinerLegacy::AArch64PostLegalizerCombinerLegacy(
932 bool IsOptNone)
933 : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
934 if (!RuleConfig.parseCommandLineOption())
935 reportFatalUsageError("Invalid rule identifier");
936}
937
938bool AArch64PostLegalizerCombinerLegacy::runOnMachineFunction(
939 MachineFunction &MF) {
940 if (MF.getProperties().hasFailedISel())
941 return false;
942
943 GISelValueTracking *VT =
944 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
945 MachineDominatorTree *MDT =
946 IsOptNone ? nullptr
947 : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
948 GISelCSEAnalysisWrapper &Wrapper =
949 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
950 auto *CSEInfo =
952
953 bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None &&
954 !skipFunction(MF.getFunction());
955
956 return runCombiner(MF, CSEInfo, VT, MDT, RuleConfig, EnableOpt, IsOptNone);
957}
958
959char AArch64PostLegalizerCombinerLegacy::ID = 0;
960INITIALIZE_PASS_BEGIN(AArch64PostLegalizerCombinerLegacy, DEBUG_TYPE,
961 "Combine AArch64 MachineInstrs after legalization", false,
962 false)
964INITIALIZE_PASS_END(AArch64PostLegalizerCombinerLegacy, DEBUG_TYPE,
965 "Combine AArch64 MachineInstrs after legalization", false,
966 false)
967
970 : RuleConfig(
971 std::make_unique<AArch64PostLegalizerCombinerImplRuleConfig>()),
972 TM(TM) {
973 if (!RuleConfig->parseCommandLineOption())
974 reportFatalUsageError("invalid rule identifier");
975}
976
979
981
985 if (MF.getProperties().hasFailedISel())
986 return PreservedAnalyses::all();
987
988 const bool IsOptNone = TM->isGlobalISelOptNone();
989 bool EnableOpt = !IsOptNone;
990
993 IsOptNone ? nullptr : &MFAM.getResult<MachineDominatorTreeAnalysis>(MF);
994 GISelCSEInfo *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(MF).get();
995
996 if (!runCombiner(MF, CSEInfo, VT, MDT, *RuleConfig, EnableOpt, IsOptNone))
997 return PreservedAnalyses::all();
998
1003 return PA;
1004}
1005
1006namespace llvm {
1008 return new AArch64PostLegalizerCombinerLegacy(IsOptNone);
1009}
1010} // end namespace llvm
MachineInstrBuilder & UseMI
static bool isZeroExtended(SDValue N, SelectionDAG &DAG)
static bool isSignExtended(SDValue N, SelectionDAG &DAG)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define GET_GICOMBINER_CONSTRUCTOR_INITS
aarch64 promote const
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
MachineBasicBlock & MBB
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Provides analysis for continuously CSEing during GISel passes.
This file implements a version of MachineIRBuilder which CSEs insts within a MachineBasicBlock.
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.
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
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.
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)
R600 Clause Merge
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Value * RHS
Value * LHS
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
AArch64PostLegalizerCombinerPass(const AArch64TargetMachine *TM)
Class for arbitrary precision integers.
Definition APInt.h:78
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1660
unsigned logBase2() const
Definition APInt.h:1782
APInt ashr(unsigned ShiftAmt) const
Arithmetic right-shift function.
Definition APInt.h:830
bool isNonNegative() const
Determine if this APInt Value is non-negative (>= 0)
Definition APInt.h:331
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
Definition APInt.h:437
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition APInt.h:293
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
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:278
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Defines a builder that does CSE of MachineInstructions using GISelCSEInfo.
MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val) override
Build and insert Res = G_CONSTANT Val.
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
Combiner implementation.
Definition Combiner.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
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.
To use KnownBitsInfo analysis in a pass, KnownBitsInfo &Info = getAnalysis<GISelValueTrackingInfoAnal...
bool maskedValueIsZero(Register Val, const APInt &Mask)
unsigned computeNumSignBits(Register R, const APInt &DemandedElts, unsigned Depth=0)
Represents a G_PTR_ADD.
Represents a G_STORE.
LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
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.
constexpr ElementCount getElementCount() const
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.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
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.
GISelChangeObserver * getObserver()
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
void setCSEInfo(GISelCSEInfo *Info)
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
ArrayRef< int > getShuffleMask() const
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.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
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
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
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.
virtual const TargetLowering * getTargetLowering() const
Changed
#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.
operand_type_match m_Pred()
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP > m_GICmp(const Pred &P, const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
SrcImmOp_match< SrcTy, AnyImmMatch, TargetOpcode::G_SEXT_INREG > m_GSExtInReg(const SrcTy &Src)
Matches a G_SEXT_INREG, binding its source and immediate width.
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
Definition Utils.cpp:1517
@ Offset
Definition DWP.cpp:577
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:656
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Store
The extracted value is stored (ExtractElement only).
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
FunctionPass * createAArch64PostLegalizerCombinerLegacy(bool IsOptNone)
LLVM_ABI std::unique_ptr< CSEConfigBase > getStandardCSEConfigForOpt(CodeGenOptLevel Level)
Definition CSEInfo.cpp:85
unsigned M1(unsigned Val)
Definition VE.h:377
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
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
@ Other
Any other memory.
Definition ModRef.h:68
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1137
@ Sub
Subtraction of integers.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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
@ SinglePass
Enables Observer-based DCE and additional heuristics that retry combining defined and used instructio...