LLVM 23.0.0git
AArch64PostLegalizerLowering.cpp
Go to the documentation of this file.
1//=== AArch64PostLegalizerLowering.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 lowering for instructions.
11///
12/// This is used to offload pattern matching from the selector.
13///
14/// For example, this combiner will notice that a G_SHUFFLE_VECTOR is actually
15/// a G_ZIP, G_UZP, etc.
16///
17/// General optimization combines should be handled by either the
18/// AArch64PostLegalizerCombiner or the AArch64PreLegalizerCombiner.
19///
20//===----------------------------------------------------------------------===//
21
22#include "AArch64.h"
23#include "AArch64ExpandImm.h"
26#include "AArch64Subtarget.h"
47#include "llvm/IR/InstrTypes.h"
49#include <optional>
50
51#define GET_GICOMBINER_DEPS
52#include "AArch64GenPostLegalizeGILowering.inc"
53#undef GET_GICOMBINER_DEPS
54
55#define DEBUG_TYPE "aarch64-postlegalizer-lowering"
56
57using namespace llvm;
58using namespace MIPatternMatch;
59using namespace AArch64GISelUtils;
60
61#define GET_GICOMBINER_TYPES
62#include "AArch64GenPostLegalizeGILowering.inc"
63#undef GET_GICOMBINER_TYPES
64
65namespace {
66
67/// Represents a pseudo instruction which replaces a G_SHUFFLE_VECTOR.
68///
69/// Used for matching target-supported shuffles before codegen.
70struct ShuffleVectorPseudo {
71 unsigned Opc; ///< Opcode for the instruction. (E.g. G_ZIP1)
72 Register Dst; ///< Destination register.
73 SmallVector<SrcOp, 2> SrcOps; ///< Source registers.
74 ShuffleVectorPseudo(unsigned Opc, Register Dst,
75 std::initializer_list<SrcOp> SrcOps)
76 : Opc(Opc), Dst(Dst), SrcOps(SrcOps){};
77 ShuffleVectorPseudo() = default;
78};
79
80/// Return true if a G_FCONSTANT instruction is known to be better-represented
81/// as a G_CONSTANT.
82bool matchFConstantToConstant(MachineInstr &MI, MachineRegisterInfo &MRI) {
83 assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT);
84 Register DstReg = MI.getOperand(0).getReg();
85 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
86 if (DstSize != 16 && DstSize != 32 && DstSize != 64)
87 return false;
88
89 // When we're storing a value, it doesn't matter what register bank it's on.
90 // Since not all floating point constants can be materialized using a fmov,
91 // it makes more sense to just use a GPR.
92 return all_of(MRI.use_nodbg_instructions(DstReg),
93 [](const MachineInstr &Use) { return Use.mayStore(); });
94}
95
96/// Change a G_FCONSTANT into a G_CONSTANT.
97void applyFConstantToConstant(MachineInstr &MI) {
98 assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT);
100 const APFloat &ImmValAPF = MI.getOperand(1).getFPImm()->getValueAPF();
101 MIB.buildConstant(MI.getOperand(0).getReg(), ImmValAPF.bitcastToAPInt());
102 MI.eraseFromParent();
103}
104
105/// Check if a G_EXT instruction can handle a shuffle mask \p M when the vector
106/// sources of the shuffle are different.
107std::optional<std::pair<bool, uint64_t>> getExtMask(ArrayRef<int> M,
108 unsigned NumElts) {
109 // Look for the first non-undef element.
110 auto FirstRealElt = find_if(M, [](int Elt) { return Elt >= 0; });
111 if (FirstRealElt == M.end())
112 return std::nullopt;
113
114 // Use APInt to handle overflow when calculating expected element.
115 unsigned MaskBits = APInt(32, NumElts * 2).logBase2();
116 APInt ExpectedElt = APInt(MaskBits, *FirstRealElt + 1, false, true);
117
118 // The following shuffle indices must be the successive elements after the
119 // first real element.
120 if (any_of(
121 make_range(std::next(FirstRealElt), M.end()),
122 [&ExpectedElt](int Elt) { return Elt != ExpectedElt++ && Elt >= 0; }))
123 return std::nullopt;
124
125 // The index of an EXT is the first element if it is not UNDEF.
126 // Watch out for the beginning UNDEFs. The EXT index should be the expected
127 // value of the first element. E.g.
128 // <-1, -1, 3, ...> is treated as <1, 2, 3, ...>.
129 // <-1, -1, 0, 1, ...> is treated as <2*NumElts-2, 2*NumElts-1, 0, 1, ...>.
130 // ExpectedElt is the last mask index plus 1.
131 uint64_t Imm = ExpectedElt.getZExtValue();
132 bool ReverseExt = false;
133
134 // There are two difference cases requiring to reverse input vectors.
135 // For example, for vector <4 x i32> we have the following cases,
136 // Case 1: shufflevector(<4 x i32>,<4 x i32>,<-1, -1, -1, 0>)
137 // Case 2: shufflevector(<4 x i32>,<4 x i32>,<-1, -1, 7, 0>)
138 // For both cases, we finally use mask <5, 6, 7, 0>, which requires
139 // to reverse two input vectors.
140 if (Imm < NumElts)
141 ReverseExt = true;
142 else
143 Imm -= NumElts;
144 return std::make_pair(ReverseExt, Imm);
145}
146
147/// Helper function for matchINS.
148///
149/// \returns a value when \p M is an ins mask for \p NumInputElements.
150///
151/// First element of the returned pair is true when the produced
152/// G_INSERT_VECTOR_ELT destination should be the LHS of the G_SHUFFLE_VECTOR.
153///
154/// Second element is the destination lane for the G_INSERT_VECTOR_ELT.
155std::optional<std::pair<bool, int>> isINSMask(ArrayRef<int> M,
156 int NumInputElements) {
157 if (M.size() != static_cast<size_t>(NumInputElements))
158 return std::nullopt;
159 int NumLHSMatch = 0, NumRHSMatch = 0;
160 int LastLHSMismatch = -1, LastRHSMismatch = -1;
161 for (int Idx = 0; Idx < NumInputElements; ++Idx) {
162 if (M[Idx] == -1) {
163 ++NumLHSMatch;
164 ++NumRHSMatch;
165 continue;
166 }
167 M[Idx] == Idx ? ++NumLHSMatch : LastLHSMismatch = Idx;
168 M[Idx] == Idx + NumInputElements ? ++NumRHSMatch : LastRHSMismatch = Idx;
169 }
170 const int NumNeededToMatch = NumInputElements - 1;
171 if (NumLHSMatch == NumNeededToMatch)
172 return std::make_pair(true, LastLHSMismatch);
173 if (NumRHSMatch == NumNeededToMatch)
174 return std::make_pair(false, LastRHSMismatch);
175 return std::nullopt;
176}
177
178/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with a
179/// G_REV instruction. Returns the appropriate G_REV opcode in \p Opc.
180bool matchREV(MachineInstr &MI, MachineRegisterInfo &MRI,
181 ShuffleVectorPseudo &MatchInfo) {
182 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
183 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
184 Register Dst = MI.getOperand(0).getReg();
185 Register Src = MI.getOperand(1).getReg();
186 LLT Ty = MRI.getType(Dst);
187 unsigned EltSize = Ty.getScalarSizeInBits();
188
189 // Element size for a rev cannot be 64.
190 if (EltSize == 64)
191 return false;
192
193 unsigned NumElts = Ty.getNumElements();
194
195 // Try to produce a G_REV instruction
196 for (unsigned LaneSize : {64U, 32U, 16U}) {
197 if (isREVMask(ShuffleMask, EltSize, NumElts, LaneSize)) {
198 unsigned Opcode;
199 if (LaneSize == 64U)
200 Opcode = AArch64::G_REV64;
201 else if (LaneSize == 32U)
202 Opcode = AArch64::G_REV32;
203 else
204 Opcode = AArch64::G_BSWAP;
205
206 MatchInfo = ShuffleVectorPseudo(Opcode, Dst, {Src});
207 return true;
208 }
209 }
210
211 return false;
212}
213
214/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
215/// a G_TRN1 or G_TRN2 instruction.
216bool matchTRN(MachineInstr &MI, MachineRegisterInfo &MRI,
217 ShuffleVectorPseudo &MatchInfo) {
218 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
219 unsigned WhichResult;
220 unsigned OperandOrder;
221 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
222 Register Dst = MI.getOperand(0).getReg();
223 unsigned NumElts = MRI.getType(Dst).getNumElements();
224 if (!isTRNMask(ShuffleMask, NumElts, WhichResult, OperandOrder))
225 return false;
226 unsigned Opc = (WhichResult == 0) ? AArch64::G_TRN1 : AArch64::G_TRN2;
227 Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
228 Register V2 = MI.getOperand(OperandOrder == 0 ? 2 : 1).getReg();
229 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
230 return true;
231}
232
233/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
234/// a G_UZP1 or G_UZP2 instruction.
235///
236/// \param [in] MI - The shuffle vector instruction.
237/// \param [out] MatchInfo - Either G_UZP1 or G_UZP2 on success.
238bool matchUZP(MachineInstr &MI, MachineRegisterInfo &MRI,
239 ShuffleVectorPseudo &MatchInfo) {
240 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
241 unsigned WhichResult;
242 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
243 Register Dst = MI.getOperand(0).getReg();
244 unsigned NumElts = MRI.getType(Dst).getNumElements();
245 if (!isUZPMask(ShuffleMask, NumElts, WhichResult))
246 return false;
247 unsigned Opc = (WhichResult == 0) ? AArch64::G_UZP1 : AArch64::G_UZP2;
248 Register V1 = MI.getOperand(1).getReg();
249 Register V2 = MI.getOperand(2).getReg();
250 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
251 return true;
252}
253
254bool matchZip(MachineInstr &MI, MachineRegisterInfo &MRI,
255 ShuffleVectorPseudo &MatchInfo) {
256 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
257 unsigned WhichResult;
258 unsigned OperandOrder;
259 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
260 Register Dst = MI.getOperand(0).getReg();
261 unsigned NumElts = MRI.getType(Dst).getNumElements();
262 if (!isZIPMask(ShuffleMask, NumElts, WhichResult, OperandOrder))
263 return false;
264 unsigned Opc = (WhichResult == 0) ? AArch64::G_ZIP1 : AArch64::G_ZIP2;
265 Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
266 Register V2 = MI.getOperand(OperandOrder == 0 ? 2 : 1).getReg();
267 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
268 return true;
269}
270
271/// Helper function for matchDup.
272bool matchDupFromInsertVectorElt(int Lane, MachineInstr &MI,
274 ShuffleVectorPseudo &MatchInfo) {
275 if (Lane != 0)
276 return false;
277
278 // Try to match a vector splat operation into a dup instruction.
279 // We're looking for this pattern:
280 //
281 // %scalar:gpr(s64) = COPY $x0
282 // %undef:fpr(<2 x s64>) = G_IMPLICIT_DEF
283 // %cst0:gpr(s32) = G_CONSTANT i32 0
284 // %zerovec:fpr(<2 x s32>) = G_BUILD_VECTOR %cst0(s32), %cst0(s32)
285 // %ins:fpr(<2 x s64>) = G_INSERT_VECTOR_ELT %undef, %scalar(s64), %cst0(s32)
286 // %splat:fpr(<2 x s64>) = G_SHUFFLE_VECTOR %ins(<2 x s64>), %undef,
287 // %zerovec(<2 x s32>)
288 //
289 // ...into:
290 // %splat = G_DUP %scalar
291
292 // Begin matching the insert.
293 auto *InsMI = getOpcodeDef(TargetOpcode::G_INSERT_VECTOR_ELT,
294 MI.getOperand(1).getReg(), MRI);
295 if (!InsMI)
296 return false;
297 // Match the undef vector operand.
298 if (!getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, InsMI->getOperand(1).getReg(),
299 MRI))
300 return false;
301
302 // Match the index constant 0.
303 if (!mi_match(InsMI->getOperand(3).getReg(), MRI, m_ZeroInt()))
304 return false;
305
306 MatchInfo = ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(),
307 {InsMI->getOperand(2).getReg()});
308 return true;
309}
310
311/// Helper function for matchDup.
312bool matchDupFromBuildVector(int Lane, MachineInstr &MI,
314 ShuffleVectorPseudo &MatchInfo) {
315 assert(Lane >= 0 && "Expected positive lane?");
316 int NumElements = MRI.getType(MI.getOperand(1).getReg()).getNumElements();
317 // Test if the LHS is a BUILD_VECTOR. If it is, then we can just reference the
318 // lane's definition directly.
319 auto *BuildVecMI =
320 getOpcodeDef(TargetOpcode::G_BUILD_VECTOR,
321 MI.getOperand(Lane < NumElements ? 1 : 2).getReg(), MRI);
322 // If Lane >= NumElements then it is point to RHS, just check from RHS
323 if (NumElements <= Lane)
324 Lane -= NumElements;
325
326 if (!BuildVecMI)
327 return false;
328 Register Reg = BuildVecMI->getOperand(Lane + 1).getReg();
329 MatchInfo =
330 ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(), {Reg});
331 return true;
332}
333
334bool matchDup(MachineInstr &MI, MachineRegisterInfo &MRI,
335 ShuffleVectorPseudo &MatchInfo) {
336 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
337 auto MaybeLane = getSplatIndex(MI);
338 if (!MaybeLane)
339 return false;
340 int Lane = *MaybeLane;
341 // If this is undef splat, generate it via "just" vdup, if possible.
342 if (Lane < 0)
343 Lane = 0;
344 if (matchDupFromInsertVectorElt(Lane, MI, MRI, MatchInfo))
345 return true;
346 if (matchDupFromBuildVector(Lane, MI, MRI, MatchInfo))
347 return true;
348 return false;
349}
350
351// Check if an EXT instruction can handle the shuffle mask when the vector
352// sources of the shuffle are the same.
353bool isSingletonExtMask(ArrayRef<int> M, LLT Ty) {
354 unsigned NumElts = Ty.getNumElements();
355
356 // Assume that the first shuffle index is not UNDEF. Fail if it is.
357 if (M[0] < 0)
358 return false;
359
360 // If this is a VEXT shuffle, the immediate value is the index of the first
361 // element. The other shuffle indices must be the successive elements after
362 // the first one.
363 unsigned ExpectedElt = M[0];
364 for (unsigned I = 1; I < NumElts; ++I) {
365 // Increment the expected index. If it wraps around, just follow it
366 // back to index zero and keep going.
367 ++ExpectedElt;
368 if (ExpectedElt == NumElts)
369 ExpectedElt = 0;
370
371 if (M[I] < 0)
372 continue; // Ignore UNDEF indices.
373 if (ExpectedElt != static_cast<unsigned>(M[I]))
374 return false;
375 }
376
377 return true;
378}
379
380bool matchEXT(MachineInstr &MI, MachineRegisterInfo &MRI,
381 ShuffleVectorPseudo &MatchInfo) {
382 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
383 Register Dst = MI.getOperand(0).getReg();
384 LLT DstTy = MRI.getType(Dst);
385 Register V1 = MI.getOperand(1).getReg();
386 Register V2 = MI.getOperand(2).getReg();
387 auto Mask = MI.getOperand(3).getShuffleMask();
388 uint64_t Imm;
389 auto ExtInfo = getExtMask(Mask, DstTy.getNumElements());
390 uint64_t ExtFactor = MRI.getType(V1).getScalarSizeInBits() / 8;
391
392 if (!ExtInfo) {
393 if (!getOpcodeDef<GImplicitDef>(V2, MRI) ||
394 !isSingletonExtMask(Mask, DstTy))
395 return false;
396
397 Imm = Mask[0] * ExtFactor;
398 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst, {V1, V1, Imm});
399 return true;
400 }
401 bool ReverseExt;
402 std::tie(ReverseExt, Imm) = *ExtInfo;
403 if (ReverseExt)
404 std::swap(V1, V2);
405 Imm *= ExtFactor;
406 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst, {V1, V2, Imm});
407 return true;
408}
409
410/// Replace a G_SHUFFLE_VECTOR instruction with a pseudo.
411/// \p Opc is the opcode to use. \p MI is the G_SHUFFLE_VECTOR.
412void applyShuffleVectorPseudo(MachineInstr &MI, MachineRegisterInfo &MRI,
413 ShuffleVectorPseudo &MatchInfo) {
414 MachineIRBuilder MIRBuilder(MI);
415 if (MatchInfo.Opc == TargetOpcode::G_BSWAP) {
416 assert(MatchInfo.SrcOps.size() == 1);
417 LLT DstTy = MRI.getType(MatchInfo.Dst);
418 assert(DstTy == LLT::fixed_vector(8, 8) ||
419 DstTy == LLT::fixed_vector(16, 8));
420 LLT BSTy = DstTy == LLT::fixed_vector(8, 8) ? LLT::fixed_vector(4, 16)
421 : LLT::fixed_vector(8, 16);
422 // FIXME: NVCAST
423 auto BS1 = MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {BSTy},
424 MatchInfo.SrcOps[0]);
425 auto BS2 = MIRBuilder.buildInstr(MatchInfo.Opc, {BSTy}, {BS1});
426 MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {MatchInfo.Dst}, {BS2});
427 } else
428 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
429 MI.eraseFromParent();
430}
431
432/// Replace a G_SHUFFLE_VECTOR instruction with G_EXT.
433/// Special-cased because the constant operand must be emitted as a G_CONSTANT
434/// for the imported tablegen patterns to work.
435void applyEXT(MachineInstr &MI, ShuffleVectorPseudo &MatchInfo) {
436 MachineIRBuilder MIRBuilder(MI);
437 if (MatchInfo.SrcOps[2].getImm() == 0)
438 MIRBuilder.buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
439 else {
440 // Tablegen patterns expect an i32 G_CONSTANT as the final op.
441 auto Cst =
442 MIRBuilder.buildConstant(LLT::scalar(32), MatchInfo.SrcOps[2].getImm());
443 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
444 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
445 }
446 MI.eraseFromParent();
447}
448
449void applyFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
450 Register Dst = MI.getOperand(0).getReg();
451 Register Src = MI.getOperand(1).getReg();
452 LLT DstTy = MRI.getType(Dst);
453 assert(DstTy.getSizeInBits() == 128 &&
454 "Expected 128bit vector in applyFullRev");
455 MachineIRBuilder MIRBuilder(MI);
456 auto Cst = MIRBuilder.buildConstant(LLT::scalar(32), 8);
457 auto Rev = MIRBuilder.buildInstr(AArch64::G_REV64, {DstTy}, {Src});
458 MIRBuilder.buildInstr(AArch64::G_EXT, {Dst}, {Rev, Rev, Cst});
459 MI.eraseFromParent();
460}
461
462bool matchNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI) {
463 assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
464
465 auto ValAndVReg =
466 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
467 return !ValAndVReg;
468}
469
470void applyNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI,
471 MachineIRBuilder &Builder) {
472 auto &Insert = cast<GInsertVectorElement>(MI);
473 Builder.setInstrAndDebugLoc(Insert);
474
475 Register Offset = Insert.getIndexReg();
476 LLT VecTy = MRI.getType(Insert.getReg(0));
477 LLT EltTy = MRI.getType(Insert.getElementReg());
478 LLT IdxTy = MRI.getType(Insert.getIndexReg());
479
480 if (VecTy.isScalableVector())
481 return;
482
483 // Create a stack slot and store the vector into it
484 MachineFunction &MF = Builder.getMF();
485 Align Alignment(
486 std::min<uint64_t>(VecTy.getSizeInBytes().getKnownMinValue(), 16));
487 int FrameIdx = MF.getFrameInfo().CreateStackObject(VecTy.getSizeInBytes(),
488 Alignment, false);
489 LLT FramePtrTy = LLT::pointer(0, 64);
491 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
492
493 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo, Align(8));
494
495 // Get the pointer to the element, and be sure not to hit undefined behavior
496 // if the index is out of bounds.
498 "Expected a power-2 vector size");
499 auto Mask = Builder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
500 Register And = Builder.buildAnd(IdxTy, Offset, Mask).getReg(0);
501 auto EltSize = Builder.buildConstant(IdxTy, EltTy.getSizeInBytes());
502 Register Mul = Builder.buildMul(IdxTy, And, EltSize).getReg(0);
503 Register EltPtr =
504 Builder.buildPtrAdd(MRI.getType(StackTemp.getReg(0)), StackTemp, Mul)
505 .getReg(0);
506
507 // Write the inserted element
508 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo, Align(1));
509 // Reload the whole vector.
510 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo, Align(8));
511 Insert.eraseFromParent();
512}
513
514/// Match a G_SHUFFLE_VECTOR with a mask which corresponds to a
515/// G_INSERT_VECTOR_ELT and G_EXTRACT_VECTOR_ELT pair.
516///
517/// e.g.
518/// %shuf = G_SHUFFLE_VECTOR %left, %right, shufflemask(0, 0)
519///
520/// Can be represented as
521///
522/// %extract = G_EXTRACT_VECTOR_ELT %left, 0
523/// %ins = G_INSERT_VECTOR_ELT %left, %extract, 1
524///
525bool matchINS(MachineInstr &MI, MachineRegisterInfo &MRI,
526 std::tuple<Register, int, Register, int> &MatchInfo) {
527 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
528 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
529 Register Dst = MI.getOperand(0).getReg();
530 int NumElts = MRI.getType(Dst).getNumElements();
531 auto DstIsLeftAndDstLane = isINSMask(ShuffleMask, NumElts);
532 if (!DstIsLeftAndDstLane)
533 return false;
534 bool DstIsLeft;
535 int DstLane;
536 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
537 Register Left = MI.getOperand(1).getReg();
538 Register Right = MI.getOperand(2).getReg();
539 Register DstVec = DstIsLeft ? Left : Right;
540 Register SrcVec = Left;
541
542 int SrcLane = ShuffleMask[DstLane];
543 if (SrcLane >= NumElts) {
544 SrcVec = Right;
545 SrcLane -= NumElts;
546 }
547
548 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
549 return true;
550}
551
552void applyINS(MachineInstr &MI, MachineRegisterInfo &MRI,
553 MachineIRBuilder &Builder,
554 std::tuple<Register, int, Register, int> &MatchInfo) {
555 Builder.setInstrAndDebugLoc(MI);
556 Register Dst = MI.getOperand(0).getReg();
557 auto ScalarTy = MRI.getType(Dst).getElementType();
558 Register DstVec, SrcVec;
559 int DstLane, SrcLane;
560 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
561 auto SrcCst = Builder.buildConstant(LLT::scalar(64), SrcLane);
562 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
563 auto DstCst = Builder.buildConstant(LLT::scalar(64), DstLane);
564 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
565 MI.eraseFromParent();
566}
567
568/// isVShiftRImm - Check if this is a valid vector for the immediate
569/// operand of a vector shift right operation. The value must be in the range:
570/// 1 <= Value <= ElementBits for a right shift.
572 int64_t &Cnt) {
573 assert(Ty.isVector() && "vector shift count is not a vector type");
575 auto Cst = getAArch64VectorSplatScalar(*MI, MRI);
576 if (!Cst)
577 return false;
578 Cnt = *Cst;
579 int64_t ElementBits = Ty.getScalarSizeInBits();
580 return Cnt >= 1 && Cnt <= ElementBits;
581}
582
583/// Match a vector G_ASHR or G_LSHR with a valid immediate shift.
584bool matchVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
585 int64_t &Imm) {
586 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
587 MI.getOpcode() == TargetOpcode::G_LSHR);
588 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
589 if (!Ty.isVector())
590 return false;
591 return isVShiftRImm(MI.getOperand(2).getReg(), MRI, Ty, Imm);
592}
593
594void applyVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
595 int64_t &Imm) {
596 unsigned Opc = MI.getOpcode();
597 assert(Opc == TargetOpcode::G_ASHR || Opc == TargetOpcode::G_LSHR);
598 unsigned NewOpc =
599 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
600 MachineIRBuilder MIB(MI);
601 MIB.buildInstr(NewOpc, {MI.getOperand(0)}, {MI.getOperand(1)}).addImm(Imm);
602 MI.eraseFromParent();
603}
604
605/// Determine if it is possible to modify the \p RHS and predicate \p P of a
606/// G_ICMP instruction such that the right-hand side is an arithmetic immediate.
607///
608/// \returns A pair containing the updated immediate and predicate which may
609/// be used to optimize the instruction.
610///
611/// \note This assumes that the comparison has been legalized.
612std::optional<std::pair<uint64_t, CmpInst::Predicate>>
613tryAdjustICmpImmAndPred(Register RHS, CmpInst::Predicate P,
614 const MachineRegisterInfo &MRI) {
615 const auto &Ty = MRI.getType(RHS);
616 if (Ty.isVector())
617 return std::nullopt;
618 unsigned Size = Ty.getSizeInBits();
619 assert((Size == 32 || Size == 64) && "Expected 32 or 64 bit compare only?");
620
621 // If the RHS is not a constant, or the RHS is already a valid arithmetic
622 // immediate, then there is nothing to change.
623 auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS, MRI);
624 if (!ValAndVReg)
625 return std::nullopt;
626 uint64_t OriginalC = ValAndVReg->Value.getZExtValue();
627 uint64_t C = OriginalC;
628 if (isLegalArithImmed(C))
629 return std::nullopt;
630
631 // We have a non-arithmetic immediate. Check if adjusting the immediate and
632 // adjusting the predicate will result in a legal arithmetic immediate.
633 switch (P) {
634 default:
635 return std::nullopt;
638 // Check for
639 //
640 // x slt c => x sle c - 1
641 // x sge c => x sgt c - 1
642 //
643 // When c is not the smallest possible negative number.
644 if ((Size == 64 && static_cast<int64_t>(C) == INT64_MIN) ||
645 (Size == 32 && static_cast<int32_t>(C) == INT32_MIN))
646 return std::nullopt;
648 C -= 1;
649 break;
652 // Check for
653 //
654 // x ult c => x ule c - 1
655 // x uge c => x ugt c - 1
656 //
657 // When c is not zero.
658 assert(C != 0 && "C should not be zero here!");
660 C -= 1;
661 break;
664 // Check for
665 //
666 // x sle c => x slt c + 1
667 // x sgt c => s sge c + 1
668 //
669 // When c is not the largest possible signed integer.
670 if ((Size == 32 && static_cast<int32_t>(C) == INT32_MAX) ||
671 (Size == 64 && static_cast<int64_t>(C) == INT64_MAX))
672 return std::nullopt;
674 C += 1;
675 break;
678 // Check for
679 //
680 // x ule c => x ult c + 1
681 // x ugt c => s uge c + 1
682 //
683 // When c is not the largest possible unsigned integer.
684 if ((Size == 32 && static_cast<uint32_t>(C) == UINT32_MAX) ||
685 (Size == 64 && C == UINT64_MAX))
686 return std::nullopt;
688 C += 1;
689 break;
690 }
691
692 // Check if the new constant is valid, and return the updated constant and
693 // predicate if it is.
694 if (Size == 32)
695 C = static_cast<uint32_t>(C);
696 if (isLegalArithImmed(C))
697 return {{C, P}};
698
699 auto NumberOfInstrToLoadImm = [=](uint64_t Imm) {
701 AArch64_IMM::expandMOVImm(Imm, 32, Insn);
702 return Insn.size();
703 };
704
705 if (NumberOfInstrToLoadImm(OriginalC) > NumberOfInstrToLoadImm(C))
706 return {{C, P}};
707
708 return std::nullopt;
709}
710
711/// Determine whether or not it is possible to update the RHS and predicate of
712/// a G_ICMP instruction such that the RHS will be selected as an arithmetic
713/// immediate.
714///
715/// \p MI - The G_ICMP instruction
716/// \p MatchInfo - The new RHS immediate and predicate on success
717///
718/// See tryAdjustICmpImmAndPred for valid transformations.
719bool matchAdjustICmpImmAndPred(
721 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
722 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
723 Register RHS = MI.getOperand(3).getReg();
724 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
725 if (auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(RHS, Pred, MRI)) {
726 MatchInfo = *MaybeNewImmAndPred;
727 return true;
728 }
729 return false;
730}
731
732void applyAdjustICmpImmAndPred(
733 MachineInstr &MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
734 MachineIRBuilder &MIB, GISelChangeObserver &Observer) {
736 MachineOperand &RHS = MI.getOperand(3);
737 MachineRegisterInfo &MRI = *MIB.getMRI();
738 auto Cst = MIB.buildConstant(MRI.cloneVirtualRegister(RHS.getReg()),
739 MatchInfo.first);
740 Observer.changingInstr(MI);
741 RHS.setReg(Cst->getOperand(0).getReg());
742 MI.getOperand(1).setPredicate(MatchInfo.second);
743 Observer.changedInstr(MI);
744}
745
746bool matchDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
747 std::pair<unsigned, int> &MatchInfo) {
748 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
749 Register Src1Reg = MI.getOperand(1).getReg();
750 const LLT SrcTy = MRI.getType(Src1Reg);
751 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
752
753 auto LaneIdx = getSplatIndex(MI);
754 if (!LaneIdx)
755 return false;
756
757 // The lane idx should be within the first source vector.
758 if (*LaneIdx >= SrcTy.getNumElements())
759 return false;
760
761 if (DstTy != SrcTy)
762 return false;
763
764 LLT ScalarTy = SrcTy.getElementType();
765 unsigned ScalarSize = ScalarTy.getSizeInBits();
766
767 unsigned Opc = 0;
768 switch (SrcTy.getNumElements()) {
769 case 2:
770 if (ScalarSize == 64)
771 Opc = AArch64::G_DUPLANE64;
772 else if (ScalarSize == 32)
773 Opc = AArch64::G_DUPLANE32;
774 break;
775 case 4:
776 if (ScalarSize == 32)
777 Opc = AArch64::G_DUPLANE32;
778 else if (ScalarSize == 16)
779 Opc = AArch64::G_DUPLANE16;
780 break;
781 case 8:
782 if (ScalarSize == 8)
783 Opc = AArch64::G_DUPLANE8;
784 else if (ScalarSize == 16)
785 Opc = AArch64::G_DUPLANE16;
786 break;
787 case 16:
788 if (ScalarSize == 8)
789 Opc = AArch64::G_DUPLANE8;
790 break;
791 default:
792 break;
793 }
794 if (!Opc)
795 return false;
796
797 MatchInfo.first = Opc;
798 MatchInfo.second = *LaneIdx;
799 return true;
800}
801
802void applyDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
803 MachineIRBuilder &B, std::pair<unsigned, int> &MatchInfo) {
804 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
805 Register Src1Reg = MI.getOperand(1).getReg();
806 const LLT SrcTy = MRI.getType(Src1Reg);
807
808 B.setInstrAndDebugLoc(MI);
809 auto Lane = B.buildConstant(LLT::scalar(64), MatchInfo.second);
810
811 Register DupSrc = MI.getOperand(1).getReg();
812 // For types like <2 x s32>, we can use G_DUPLANE32, with a <4 x s32> source.
813 // To do this, we can use a G_CONCAT_VECTORS to do the widening.
814 if (SrcTy.getSizeInBits() == 64) {
815 auto Undef = B.buildUndef(SrcTy);
816 DupSrc = B.buildConcatVectors(SrcTy.multiplyElements(2),
817 {Src1Reg, Undef.getReg(0)})
818 .getReg(0);
819 }
820 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
821 MI.eraseFromParent();
822}
823
824bool matchScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI) {
825 auto &Unmerge = cast<GUnmerge>(MI);
826 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
827 const LLT SrcTy = MRI.getType(Src1Reg);
828 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
829 return false;
830 return SrcTy.isVector() && !SrcTy.isScalable() &&
831 Unmerge.getNumOperands() == (unsigned)SrcTy.getNumElements() + 1;
832}
833
834void applyScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
836 auto &Unmerge = cast<GUnmerge>(MI);
837 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
838 const LLT SrcTy = MRI.getType(Src1Reg);
839 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
840 "Expected a fixed length vector");
841
842 for (int I = 0; I < SrcTy.getNumElements(); ++I)
843 B.buildExtractVectorElementConstant(Unmerge.getReg(I), Src1Reg, I);
844 MI.eraseFromParent();
845}
846
847bool matchBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI) {
848 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
849
850 // Later, during selection, we'll try to match imported patterns using
851 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
852 // G_BUILD_VECTORs which could match those patterns.
854 return false;
855
856 return getAArch64VectorSplat(MI, MRI).has_value();
857}
858
859void applyBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI,
861 B.setInstrAndDebugLoc(MI);
862 B.buildInstr(AArch64::G_DUP, {MI.getOperand(0).getReg()},
863 {MI.getOperand(1).getReg()});
864 MI.eraseFromParent();
865}
866
867/// \returns how many instructions would be saved by folding a G_ICMP's shift
868/// and/or extension operations.
870 // No instructions to save if there's more than one use or no uses.
871 if (!MRI.hasOneNonDBGUse(CmpOp))
872 return 0;
873
874 // FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
875 auto IsSupportedExtend = [&](const MachineInstr &MI) {
876 if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
877 return true;
878 if (MI.getOpcode() != TargetOpcode::G_AND)
879 return false;
880 auto ValAndVReg =
881 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
882 if (!ValAndVReg)
883 return false;
884 uint64_t Mask = ValAndVReg->Value.getZExtValue();
885 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
886 };
887
888 MachineInstr *Def = getDefIgnoringCopies(CmpOp, MRI);
889 if (IsSupportedExtend(*Def))
890 return 1;
891
892 unsigned Opc = Def->getOpcode();
893 if (Opc != TargetOpcode::G_SHL && Opc != TargetOpcode::G_ASHR &&
894 Opc != TargetOpcode::G_LSHR)
895 return 0;
896
897 auto MaybeShiftAmt =
898 getIConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
899 if (!MaybeShiftAmt)
900 return 0;
901 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
902 MachineInstr *ShiftLHS =
903 getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
904
905 // Check if we can fold an extend and a shift.
906 // FIXME: This is duplicated with the selector. (See:
907 // selectArithExtendedRegister)
908 if (IsSupportedExtend(*ShiftLHS))
909 return (ShiftAmt <= 4) ? 2 : 1;
910
911 LLT Ty = MRI.getType(Def->getOperand(0).getReg());
912 if (Ty.isVector())
913 return 0;
914 unsigned ShiftSize = Ty.getSizeInBits();
915 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
916 (ShiftSize == 64 && ShiftAmt <= 63))
917 return 1;
918 return 0;
919}
920
921/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
922/// instruction \p MI.
923bool trySwapICmpOperands(MachineInstr &MI, MachineRegisterInfo &MRI) {
924 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
925 // Swap the operands if it would introduce a profitable folding opportunity.
926 // (e.g. a shift + extend).
927 //
928 // For example:
929 // lsl w13, w11, #1
930 // cmp w13, w12
931 // can be turned into:
932 // cmp w12, w11, lsl #1
933
934 // Don't swap if there's a constant on the RHS, because we know we can fold
935 // that.
936 Register RHS = MI.getOperand(3).getReg();
937 auto RHSCst = getIConstantVRegValWithLookThrough(RHS, MRI);
938 if (RHSCst && isLegalArithImmed(RHSCst->Value.getSExtValue()))
939 return false;
940
941 Register LHS = MI.getOperand(2).getReg();
942 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
943 auto GetRegForProfit = [&](Register Reg) {
945 return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
946 };
947
948 // Don't have a constant on the RHS. If we swap the LHS and RHS of the
949 // compare, would we be able to fold more instructions?
950 Register TheLHS = GetRegForProfit(LHS);
951 Register TheRHS = GetRegForProfit(RHS);
952
953 // If the LHS is more likely to give us a folding opportunity, then swap the
954 // LHS and RHS.
955 return (getCmpOperandFoldingProfit(TheLHS, MRI) >
956 getCmpOperandFoldingProfit(TheRHS, MRI));
957}
958
959void applySwapICmpOperands(MachineInstr &MI, GISelChangeObserver &Observer) {
960 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
961 Register LHS = MI.getOperand(2).getReg();
962 Register RHS = MI.getOperand(3).getReg();
963 Observer.changedInstr(MI);
964 MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
965 MI.getOperand(2).setReg(RHS);
966 MI.getOperand(3).setReg(LHS);
967 Observer.changedInstr(MI);
968}
969
970/// \returns a function which builds a vector floating point compare instruction
971/// for a condition code \p CC.
972/// \param [in] NoNans - True if the instruction has nnan flag.
973std::function<Register(MachineIRBuilder &)>
974getVectorFCMP(AArch64CC::CondCode CC, Register LHS, Register RHS, bool NoNans,
975 MachineRegisterInfo &MRI) {
976 LLT DstTy = MRI.getType(LHS);
977 assert(DstTy.isVector() && "Expected vector types only?");
978 assert(DstTy == MRI.getType(RHS) && "Src and Dst types must match!");
979 switch (CC) {
980 default:
981 llvm_unreachable("Unexpected condition code!");
982 case AArch64CC::NE:
983 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
984 auto FCmp = MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS});
985 return MIB.buildNot(DstTy, FCmp).getReg(0);
986 };
987 case AArch64CC::EQ:
988 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
989 return MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS}).getReg(0);
990 };
991 case AArch64CC::GE:
992 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
993 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {LHS, RHS}).getReg(0);
994 };
995 case AArch64CC::GT:
996 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
997 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {LHS, RHS}).getReg(0);
998 };
999 case AArch64CC::LS:
1000 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1001 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {RHS, LHS}).getReg(0);
1002 };
1003 case AArch64CC::MI:
1004 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1005 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {RHS, LHS}).getReg(0);
1006 };
1007 }
1008}
1009
1010/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1011bool matchLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1012 MachineIRBuilder &MIB) {
1013 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1014 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
1015
1016 Register Dst = MI.getOperand(0).getReg();
1017 LLT DstTy = MRI.getType(Dst);
1018 if (!DstTy.isVector() || !ST.hasNEON())
1019 return false;
1020 Register LHS = MI.getOperand(2).getReg();
1021 unsigned EltSize = MRI.getType(LHS).getScalarSizeInBits();
1022 if (EltSize == 16 && !ST.hasFullFP16())
1023 return false;
1024 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
1025 return false;
1026
1027 return true;
1028}
1029
1030/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1031void applyLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1032 MachineIRBuilder &MIB) {
1033 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1034
1035 const auto &CmpMI = cast<GFCmp>(MI);
1036
1037 Register Dst = CmpMI.getReg(0);
1038 CmpInst::Predicate Pred = CmpMI.getCond();
1039 Register LHS = CmpMI.getLHSReg();
1040 Register RHS = CmpMI.getRHSReg();
1041
1042 LLT DstTy = MRI.getType(Dst);
1043
1044 bool Invert = false;
1046 if ((Pred == CmpInst::Predicate::FCMP_ORD ||
1048 isBuildVectorAllZeros(*MRI.getVRegDef(RHS), MRI)) {
1049 // The special case "fcmp ord %a, 0" is the canonical check that LHS isn't
1050 // NaN, so equivalent to a == a and doesn't need the two comparisons an
1051 // "ord" normally would.
1052 // Similarly, "fcmp uno %a, 0" is the canonical check that LHS is NaN and is
1053 // thus equivalent to a != a.
1054 RHS = LHS;
1056 } else
1057 changeVectorFCMPPredToAArch64CC(Pred, CC, CC2, Invert);
1058
1059 // Instead of having an apply function, just build here to simplify things.
1061
1062 // TODO: Also consider GISelValueTracking result if eligible.
1063 const bool NoNans = MI.getFlag(MachineInstr::FmNoNans);
1064
1065 auto Cmp = getVectorFCMP(CC, LHS, RHS, NoNans, MRI);
1066 Register CmpRes;
1067 if (CC2 == AArch64CC::AL)
1068 CmpRes = Cmp(MIB);
1069 else {
1070 auto Cmp2 = getVectorFCMP(CC2, LHS, RHS, NoNans, MRI);
1071 auto Cmp2Dst = Cmp2(MIB);
1072 auto Cmp1Dst = Cmp(MIB);
1073 CmpRes = MIB.buildOr(DstTy, Cmp1Dst, Cmp2Dst).getReg(0);
1074 }
1075 if (Invert)
1076 CmpRes = MIB.buildNot(DstTy, CmpRes).getReg(0);
1077 MRI.replaceRegWith(Dst, CmpRes);
1078 MI.eraseFromParent();
1079}
1080
1081// Matches G_BUILD_VECTOR where at least one source operand is not a constant
1082bool matchLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI) {
1083 auto *GBuildVec = cast<GBuildVector>(&MI);
1084
1085 // Check if the values are all constants
1086 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1087 auto ConstVal =
1088 getAnyConstantVRegValWithLookThrough(GBuildVec->getSourceReg(I), MRI);
1089
1090 if (!ConstVal.has_value())
1091 return true;
1092 }
1093
1094 return false;
1095}
1096
1097void applyLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI,
1099 auto *GBuildVec = cast<GBuildVector>(&MI);
1100 LLT DstTy = MRI.getType(GBuildVec->getReg(0));
1101 Register DstReg = B.buildUndef(DstTy).getReg(0);
1102
1103 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1104 Register SrcReg = GBuildVec->getSourceReg(I);
1105 if (mi_match(SrcReg, MRI, m_GImplicitDef()))
1106 continue;
1107 auto IdxReg = B.buildConstant(LLT::scalar(64), I);
1108 DstReg =
1109 B.buildInsertVectorElement(DstTy, DstReg, SrcReg, IdxReg).getReg(0);
1110 }
1111 B.buildCopy(GBuildVec->getReg(0), DstReg);
1112 GBuildVec->eraseFromParent();
1113}
1114
1115bool matchFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1116 Register &SrcReg) {
1117 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1118 Register DstReg = MI.getOperand(0).getReg();
1119 if (MRI.getType(DstReg).isVector())
1120 return false;
1121 // Match a store of a truncate.
1122 if (!mi_match(DstReg, MRI, m_GTrunc(m_Reg(SrcReg))))
1123 return false;
1124 // Only form truncstores for value types of max 64b.
1125 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1126}
1127
1128void applyFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1130 Register &SrcReg) {
1131 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1132 Observer.changingInstr(MI);
1133 MI.getOperand(0).setReg(SrcReg);
1134 Observer.changedInstr(MI);
1135}
1136
1137// Lower vector G_SEXT_INREG back to shifts for selection. We allowed them to
1138// form in the first place for combine opportunities, so any remaining ones
1139// at this stage need be lowered back.
1140bool matchVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI) {
1141 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1142 Register DstReg = MI.getOperand(0).getReg();
1143 LLT DstTy = MRI.getType(DstReg);
1144 return DstTy.isVector();
1145}
1146
1147void applyVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI,
1149 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1150 B.setInstrAndDebugLoc(MI);
1151 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1152 Helper.lower(MI, 0, /* Unused hint type */ LLT());
1153}
1154
1155/// Combine <N x t>, unused = unmerge(G_EXT <2*N x t> v, undef, N)
1156/// => unused, <N x t> = unmerge v
1157bool matchUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1158 Register &MatchInfo) {
1159 auto &Unmerge = cast<GUnmerge>(MI);
1160 if (Unmerge.getNumDefs() != 2)
1161 return false;
1162 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
1163 return false;
1164
1165 LLT DstTy = MRI.getType(Unmerge.getReg(0));
1166 if (!DstTy.isVector())
1167 return false;
1168
1169 MachineInstr *Ext = getOpcodeDef(AArch64::G_EXT, Unmerge.getSourceReg(), MRI);
1170 if (!Ext)
1171 return false;
1172
1173 Register ExtSrc1 = Ext->getOperand(1).getReg();
1174 Register ExtSrc2 = Ext->getOperand(2).getReg();
1175 auto LowestVal =
1177 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.getSizeInBytes())
1178 return false;
1179
1180 if (!getOpcodeDef<GImplicitDef>(ExtSrc2, MRI))
1181 return false;
1182
1183 MatchInfo = ExtSrc1;
1184 return true;
1185}
1186
1187void applyUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1189 GISelChangeObserver &Observer, Register &SrcReg) {
1190 Observer.changingInstr(MI);
1191 // Swap dst registers.
1192 Register Dst1 = MI.getOperand(0).getReg();
1193 MI.getOperand(0).setReg(MI.getOperand(1).getReg());
1194 MI.getOperand(1).setReg(Dst1);
1195 MI.getOperand(2).setReg(SrcReg);
1196 Observer.changedInstr(MI);
1197}
1198
1199// Match mul({z/s}ext , {z/s}ext) => {u/s}mull OR
1200// Match v2s64 mul instructions, which will then be scalarised later on
1201// Doing these two matches in one function to ensure that the order of matching
1202// will always be the same.
1203// Try lowering MUL to MULL before trying to scalarize if needed.
1204bool matchMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI) {
1205 // Get the instructions that defined the source operand
1206 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1207 return DstTy == LLT::fixed_vector(2, 64);
1208}
1209
1210void applyMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI,
1212 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
1213 "Expected a G_MUL instruction");
1214
1215 // Get the instructions that defined the source operand
1216 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1217 assert(DstTy == LLT::fixed_vector(2, 64) && "Expected v2s64 Mul");
1218 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1219 Helper.fewerElementsVector(
1220 MI, 0,
1222}
1223
1224class AArch64PostLegalizerLoweringImpl : public Combiner {
1225protected:
1226 const CombinerHelper Helper;
1227 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1228 const AArch64Subtarget &STI;
1229
1230public:
1231 AArch64PostLegalizerLoweringImpl(
1232 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1233 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1234 const AArch64Subtarget &STI);
1235
1236 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
1237
1238 bool tryCombineAll(MachineInstr &I) const override;
1239
1240private:
1241#define GET_GICOMBINER_CLASS_MEMBERS
1242#include "AArch64GenPostLegalizeGILowering.inc"
1243#undef GET_GICOMBINER_CLASS_MEMBERS
1244};
1245
1246#define GET_GICOMBINER_IMPL
1247#include "AArch64GenPostLegalizeGILowering.inc"
1248#undef GET_GICOMBINER_IMPL
1249
1250AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1251 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1252 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1253 const AArch64Subtarget &STI)
1254 : Combiner(MF, CInfo, /*VT*/ nullptr, CSEInfo),
1255 Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
1256 STI(STI),
1258#include "AArch64GenPostLegalizeGILowering.inc"
1260{
1261}
1262
1263bool runPostLegalizerLowering(
1264 MachineFunction &MF,
1265 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig) {
1266 if (MF.getProperties().hasFailedISel())
1267 return false;
1268 const Function &F = MF.getFunction();
1269
1271 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
1272 /*LegalizerInfo=*/nullptr, /*OptEnabled=*/true,
1273 F.hasOptSize(), F.hasMinSize());
1274 // Disable fixed-point iteration to reduce compile-time
1275 CInfo.MaxIterations = 1;
1276 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
1277 // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
1278 CInfo.EnableFullDCE = false;
1279 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo, /*CSEInfo=*/nullptr,
1280 RuleConfig, ST);
1281 return Impl.combineMachineInstrs();
1282}
1283
1284class AArch64PostLegalizerLoweringLegacy : public MachineFunctionPass {
1285public:
1286 static char ID;
1287
1288 AArch64PostLegalizerLoweringLegacy();
1289
1290 StringRef getPassName() const override {
1291 return "AArch64PostLegalizerLowering";
1292 }
1293
1294 bool runOnMachineFunction(MachineFunction &MF) override;
1295 void getAnalysisUsage(AnalysisUsage &AU) const override;
1296
1297private:
1298 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1299};
1300} // end anonymous namespace
1301
1302void AArch64PostLegalizerLoweringLegacy::getAnalysisUsage(
1303 AnalysisUsage &AU) const {
1304 AU.setPreservesCFG();
1307}
1308
1309AArch64PostLegalizerLoweringLegacy::AArch64PostLegalizerLoweringLegacy()
1310 : MachineFunctionPass(ID) {
1311 if (!RuleConfig.parseCommandLineOption())
1312 report_fatal_error("Invalid rule identifier");
1313}
1314
1315bool AArch64PostLegalizerLoweringLegacy::runOnMachineFunction(
1316 MachineFunction &MF) {
1317 assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
1318 return runPostLegalizerLowering(MF, RuleConfig);
1319}
1320
1321char AArch64PostLegalizerLoweringLegacy::ID = 0;
1322INITIALIZE_PASS_BEGIN(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1323 "Lower AArch64 MachineInstrs after legalization", false,
1324 false)
1325INITIALIZE_PASS_END(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1326 "Lower AArch64 MachineInstrs after legalization", false,
1327 false)
1328
1330 : RuleConfig(
1331 std::make_unique<AArch64PostLegalizerLoweringImplRuleConfig>()) {
1332 if (!RuleConfig->parseCommandLineOption())
1333 reportFatalUsageError("invalid rule identifier");
1334}
1335
1338
1340
1344 MFPropsModifier _(*this, MF);
1345 const bool Changed = runPostLegalizerLowering(MF, *RuleConfig);
1346
1347 if (!Changed)
1348 return PreservedAnalyses::all();
1349
1352 return PA;
1353}
1354
1355namespace llvm {
1357 return new AArch64PostLegalizerLoweringLegacy();
1358}
1359} // end namespace llvm
static bool isVShiftRImm(SDValue Op, EVT VT, bool isNarrow, int64_t &Cnt)
isVShiftRImm - Check if this is a valid build_vector for the immediate operand of a vector shift righ...
static bool isINSMask(ArrayRef< int > M, int NumInputElements, bool &DstIsLeft, int &Anomaly)
static unsigned getCmpOperandFoldingProfit(SDValue Op)
Returns how profitable it is to fold a comparison's operand's shift and/or extension operations.
This file declares the targeting of the Machinelegalizer class for AArch64.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define GET_GICOMBINER_CONSTRUCTOR_INITS
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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.
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
#define _
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.
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define P(N)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static StringRef getName(Value *V)
Value * RHS
Value * LHS
BinaryOperator * Mul
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
APInt bitcastToAPInt() const
Definition APFloat.h:1408
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1555
unsigned logBase2() const
Definition APInt.h:1776
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:270
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:676
@ ICMP_SLT
signed less than
Definition InstrTypes.h:705
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:706
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:700
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:699
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:703
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:701
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:685
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:704
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:702
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:686
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Definition InstrTypes.h:827
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.
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
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
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
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.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LLVM_ABI LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by splitting it into simpler parts, hopefully understood by the target.
LLVM_ABI LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize a vector instruction by splitting into multiple components, each acting on the same scalar t...
An RAII based helper class to modify MachineFunctionProperties when running pass.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
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.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Helper class to build MachineInstr.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
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 MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
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
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const
We do not provide the '/' operator here because division for polynomial types does not work in the sa...
Definition TypeSize.h:252
Changed
#define UINT64_MAX
Definition DataTypes.h:77
#define INT64_MIN
Definition DataTypes.h:74
#define INT64_MAX
Definition DataTypes.h:71
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::optional< RegOrConstant > getAArch64VectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
constexpr bool isLegalArithImmed(const uint64_t C)
void changeVectorFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2, bool &Invert)
Find the AArch64 condition codes necessary to represent P for a vector floating point comparison.
bool isCMN(const MachineInstr *MaybeSub, const CmpInst::Predicate &Pred, const MachineRegisterInfo &MRI)
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
operand_type_match m_Reg()
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
ImplicitDefMatch m_GImplicitDef()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
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:1423
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
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:652
bool isZIPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut, unsigned &OperandOrderOut)
Return true for zip1 or zip2 masks of the form: <0, 8, 1, 9, 2, 10, 3, 11> (WhichResultOut = 0,...
@ Undef
Value of the register doesn't matter.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:284
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:493
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64PostLegalizerLowering()
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool isUZPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut)
Return true for uzp1 or uzp2 masks of the form: <0, 2, 4, 6, 8, 10, 12, 14> or <1,...
bool isREVMask(ArrayRef< int > M, unsigned EltSize, unsigned NumElts, unsigned BlockSize)
isREVMask - Check if a vector shuffle corresponds to a REV instruction with the specified blocksize.
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
Definition Utils.cpp:438
LLVM_ABI bool isBuildVectorAllOnes(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:1429
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1126
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:432
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1772
bool isTRNMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut, unsigned &OperandOrderOut)
Return true for trn1 or trn2 masks of the form: <0, 8, 2, 10, 4, 12, 6, 14> (WhichResultOut = 0,...
LLVM_ABI int getSplatIndex(ArrayRef< int > Mask)
If all non-negative Mask elements are the same value, return that value.
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:870
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:872
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
@ SinglePass
Enables Observer-based DCE and additional heuristics that retry combining defined and used instructio...
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.