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