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 const Register DstReg = MI.getOperand(0).getReg();
102 MIB.buildConstant(DstReg, ImmValAPF.bitcastToAPInt());
103 MI.eraseFromParent();
104}
105
106/// Check if a G_EXT instruction can handle a shuffle mask \p M when the vector
107/// sources of the shuffle are different.
108std::optional<std::pair<bool, uint64_t>> getExtMask(ArrayRef<int> M,
109 unsigned NumElts) {
110 // Look for the first non-undef element.
111 auto FirstRealElt = find_if(M, [](int Elt) { return Elt >= 0; });
112 if (FirstRealElt == M.end())
113 return std::nullopt;
114
115 // Use APInt to handle overflow when calculating expected element.
116 unsigned MaskBits = APInt(32, NumElts * 2).logBase2();
117 APInt ExpectedElt = APInt(MaskBits, *FirstRealElt + 1, false, true);
118
119 // The following shuffle indices must be the successive elements after the
120 // first real element.
121 if (any_of(
122 make_range(std::next(FirstRealElt), M.end()),
123 [&ExpectedElt](int Elt) { return Elt != ExpectedElt++ && Elt >= 0; }))
124 return std::nullopt;
125
126 // The index of an EXT is the first element if it is not UNDEF.
127 // Watch out for the beginning UNDEFs. The EXT index should be the expected
128 // value of the first element. E.g.
129 // <-1, -1, 3, ...> is treated as <1, 2, 3, ...>.
130 // <-1, -1, 0, 1, ...> is treated as <2*NumElts-2, 2*NumElts-1, 0, 1, ...>.
131 // ExpectedElt is the last mask index plus 1.
132 uint64_t Imm = ExpectedElt.getZExtValue();
133 bool ReverseExt = false;
134
135 // There are two difference cases requiring to reverse input vectors.
136 // For example, for vector <4 x i32> we have the following cases,
137 // Case 1: shufflevector(<4 x i32>,<4 x i32>,<-1, -1, -1, 0>)
138 // Case 2: shufflevector(<4 x i32>,<4 x i32>,<-1, -1, 7, 0>)
139 // For both cases, we finally use mask <5, 6, 7, 0>, which requires
140 // to reverse two input vectors.
141 if (Imm < NumElts)
142 ReverseExt = true;
143 else
144 Imm -= NumElts;
145 return std::make_pair(ReverseExt, Imm);
146}
147
148/// Helper function for matchINS.
149///
150/// \returns a value when \p M is an ins mask for \p NumInputElements.
151///
152/// First element of the returned pair is true when the produced
153/// G_INSERT_VECTOR_ELT destination should be the LHS of the G_SHUFFLE_VECTOR.
154///
155/// Second element is the destination lane for the G_INSERT_VECTOR_ELT.
156std::optional<std::pair<bool, int>> isINSMask(ArrayRef<int> M,
157 int NumInputElements) {
158 if (M.size() != static_cast<size_t>(NumInputElements))
159 return std::nullopt;
160 int NumLHSMatch = 0, NumRHSMatch = 0;
161 int LastLHSMismatch = -1, LastRHSMismatch = -1;
162 for (int Idx = 0; Idx < NumInputElements; ++Idx) {
163 if (M[Idx] == -1) {
164 ++NumLHSMatch;
165 ++NumRHSMatch;
166 continue;
167 }
168 M[Idx] == Idx ? ++NumLHSMatch : LastLHSMismatch = Idx;
169 M[Idx] == Idx + NumInputElements ? ++NumRHSMatch : LastRHSMismatch = Idx;
170 }
171 const int NumNeededToMatch = NumInputElements - 1;
172 if (NumLHSMatch == NumNeededToMatch)
173 return std::make_pair(true, LastLHSMismatch);
174 if (NumRHSMatch == NumNeededToMatch)
175 return std::make_pair(false, LastRHSMismatch);
176 return std::nullopt;
177}
178
179/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with a
180/// G_REV instruction. Returns the appropriate G_REV opcode in \p Opc.
181bool matchREV(MachineInstr &MI, MachineRegisterInfo &MRI,
182 ShuffleVectorPseudo &MatchInfo) {
183 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
184 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
185 Register Dst = MI.getOperand(0).getReg();
186 Register Src = MI.getOperand(1).getReg();
187 LLT Ty = MRI.getType(Dst);
188 unsigned EltSize = Ty.getScalarSizeInBits();
189
190 // Element size for a rev cannot be 64.
191 if (EltSize == 64)
192 return false;
193
194 unsigned NumElts = Ty.getNumElements();
195
196 // Try to produce a G_REV instruction
197 for (unsigned LaneSize : {64U, 32U, 16U}) {
198 if (isREVMask(ShuffleMask, EltSize, NumElts, LaneSize)) {
199 unsigned Opcode;
200 if (LaneSize == 64U)
201 Opcode = AArch64::G_REV64;
202 else if (LaneSize == 32U)
203 Opcode = AArch64::G_REV32;
204 else
205 Opcode = AArch64::G_BSWAP;
206
207 MatchInfo = ShuffleVectorPseudo(Opcode, Dst, {Src});
208 return true;
209 }
210 }
211
212 return false;
213}
214
215/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
216/// a G_TRN1 or G_TRN2 instruction.
217bool matchTRN(MachineInstr &MI, MachineRegisterInfo &MRI,
218 ShuffleVectorPseudo &MatchInfo) {
219 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
220 unsigned WhichResult;
221 unsigned OperandOrder;
222 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
223 Register Dst = MI.getOperand(0).getReg();
224 unsigned NumElts = MRI.getType(Dst).getNumElements();
225 if (!isTRNMask(ShuffleMask, NumElts, WhichResult, OperandOrder))
226 return false;
227 unsigned Opc = (WhichResult == 0) ? AArch64::G_TRN1 : AArch64::G_TRN2;
228 Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
229 Register V2 = MI.getOperand(OperandOrder == 0 ? 2 : 1).getReg();
230 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
231 return true;
232}
233
234/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
235/// a G_UZP1 or G_UZP2 instruction.
236///
237/// \param [in] MI - The shuffle vector instruction.
238/// \param [out] MatchInfo - Either G_UZP1 or G_UZP2 on success.
239bool matchUZP(MachineInstr &MI, MachineRegisterInfo &MRI,
240 ShuffleVectorPseudo &MatchInfo) {
241 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
242 unsigned WhichResult;
243 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
244 Register Dst = MI.getOperand(0).getReg();
245 unsigned NumElts = MRI.getType(Dst).getNumElements();
246 if (!isUZPMask(ShuffleMask, NumElts, WhichResult))
247 return false;
248 unsigned Opc = (WhichResult == 0) ? AArch64::G_UZP1 : AArch64::G_UZP2;
249 Register V1 = MI.getOperand(1).getReg();
250 Register V2 = MI.getOperand(2).getReg();
251 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
252 return true;
253}
254
255bool matchZip(MachineInstr &MI, MachineRegisterInfo &MRI,
256 ShuffleVectorPseudo &MatchInfo) {
257 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
258 unsigned WhichResult;
259 unsigned OperandOrder;
260 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
261 Register Dst = MI.getOperand(0).getReg();
262 unsigned NumElts = MRI.getType(Dst).getNumElements();
263 if (!isZIPMask(ShuffleMask, NumElts, WhichResult, OperandOrder))
264 return false;
265 unsigned Opc = (WhichResult == 0) ? AArch64::G_ZIP1 : AArch64::G_ZIP2;
266 Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
267 Register V2 = MI.getOperand(OperandOrder == 0 ? 2 : 1).getReg();
268 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
269 return true;
270}
271
272/// Helper function for matchDup.
273bool matchDupFromInsertVectorElt(int Lane, MachineInstr &MI,
275 ShuffleVectorPseudo &MatchInfo) {
276 if (Lane != 0)
277 return false;
278
279 // Try to match a vector splat operation into a dup instruction.
280 // We're looking for this pattern:
281 //
282 // %scalar:gpr(s64) = COPY $x0
283 // %undef:fpr(<2 x s64>) = G_IMPLICIT_DEF
284 // %cst0:gpr(s32) = G_CONSTANT i32 0
285 // %zerovec:fpr(<2 x s32>) = G_BUILD_VECTOR %cst0(s32), %cst0(s32)
286 // %ins:fpr(<2 x s64>) = G_INSERT_VECTOR_ELT %undef, %scalar(s64), %cst0(s32)
287 // %splat:fpr(<2 x s64>) = G_SHUFFLE_VECTOR %ins(<2 x s64>), %undef,
288 // %zerovec(<2 x s32>)
289 //
290 // ...into:
291 // %splat = G_DUP %scalar
292
293 // Begin matching the insert.
294 auto *InsMI = getOpcodeDef(TargetOpcode::G_INSERT_VECTOR_ELT,
295 MI.getOperand(1).getReg(), MRI);
296 if (!InsMI)
297 return false;
298 // Match the undef vector operand.
299 if (!getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, InsMI->getOperand(1).getReg(),
300 MRI))
301 return false;
302
303 // Match the index constant 0.
304 if (!mi_match(InsMI->getOperand(3).getReg(), MRI, m_ZeroInt()))
305 return false;
306
307 MatchInfo = ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(),
308 {InsMI->getOperand(2).getReg()});
309 return true;
310}
311
312/// Helper function for matchDup.
313bool matchDupFromBuildVector(int Lane, MachineInstr &MI,
315 ShuffleVectorPseudo &MatchInfo) {
316 assert(Lane >= 0 && "Expected positive lane?");
317 int NumElements = MRI.getType(MI.getOperand(1).getReg()).getNumElements();
318 // Test if the LHS is a BUILD_VECTOR. If it is, then we can just reference the
319 // lane's definition directly.
320 auto *BuildVecMI =
321 getOpcodeDef(TargetOpcode::G_BUILD_VECTOR,
322 MI.getOperand(Lane < NumElements ? 1 : 2).getReg(), MRI);
323 // If Lane >= NumElements then it is point to RHS, just check from RHS
324 if (NumElements <= Lane)
325 Lane -= NumElements;
326
327 if (!BuildVecMI)
328 return false;
329 Register Reg = BuildVecMI->getOperand(Lane + 1).getReg();
330 MatchInfo =
331 ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(), {Reg});
332 return true;
333}
334
335bool matchDup(MachineInstr &MI, MachineRegisterInfo &MRI,
336 ShuffleVectorPseudo &MatchInfo) {
337 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
338 auto MaybeLane = getSplatIndex(MI);
339 if (!MaybeLane)
340 return false;
341 int Lane = *MaybeLane;
342 // If this is undef splat, generate it via "just" vdup, if possible.
343 if (Lane < 0)
344 Lane = 0;
345 if (matchDupFromInsertVectorElt(Lane, MI, MRI, MatchInfo))
346 return true;
347 if (matchDupFromBuildVector(Lane, MI, MRI, MatchInfo))
348 return true;
349 return false;
350}
351
352// Check if an EXT instruction can handle the shuffle mask when the vector
353// sources of the shuffle are the same.
354bool isSingletonExtMask(ArrayRef<int> M, LLT Ty) {
355 unsigned NumElts = Ty.getNumElements();
356
357 // Assume that the first shuffle index is not UNDEF. Fail if it is.
358 if (M[0] < 0)
359 return false;
360
361 // If this is a VEXT shuffle, the immediate value is the index of the first
362 // element. The other shuffle indices must be the successive elements after
363 // the first one.
364 unsigned ExpectedElt = M[0];
365 for (unsigned I = 1; I < NumElts; ++I) {
366 // Increment the expected index. If it wraps around, just follow it
367 // back to index zero and keep going.
368 ++ExpectedElt;
369 if (ExpectedElt == NumElts)
370 ExpectedElt = 0;
371
372 if (M[I] < 0)
373 continue; // Ignore UNDEF indices.
374 if (ExpectedElt != static_cast<unsigned>(M[I]))
375 return false;
376 }
377
378 return true;
379}
380
381bool matchEXT(MachineInstr &MI, MachineRegisterInfo &MRI,
382 ShuffleVectorPseudo &MatchInfo) {
383 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
384 Register Dst = MI.getOperand(0).getReg();
385 LLT DstTy = MRI.getType(Dst);
386 Register V1 = MI.getOperand(1).getReg();
387 Register V2 = MI.getOperand(2).getReg();
388 auto Mask = MI.getOperand(3).getShuffleMask();
389 uint64_t Imm;
390 auto ExtInfo = getExtMask(Mask, DstTy.getNumElements());
391 uint64_t ExtFactor = MRI.getType(V1).getScalarSizeInBits() / 8;
392
393 if (!ExtInfo) {
394 if (!getOpcodeDef<GImplicitDef>(V2, MRI) ||
395 !isSingletonExtMask(Mask, DstTy))
396 return false;
397
398 Imm = Mask[0] * ExtFactor;
399 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst, {V1, V1, Imm});
400 return true;
401 }
402 bool ReverseExt;
403 std::tie(ReverseExt, Imm) = *ExtInfo;
404 if (ReverseExt)
405 std::swap(V1, V2);
406 Imm *= ExtFactor;
407 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst, {V1, V2, Imm});
408 return true;
409}
410
411/// Replace a G_SHUFFLE_VECTOR instruction with a pseudo.
412/// \p Opc is the opcode to use. \p MI is the G_SHUFFLE_VECTOR.
413void applyShuffleVectorPseudo(MachineInstr &MI, MachineRegisterInfo &MRI,
414 ShuffleVectorPseudo &MatchInfo) {
415 MachineIRBuilder MIRBuilder(MI);
416 if (MatchInfo.Opc == TargetOpcode::G_BSWAP) {
417 assert(MatchInfo.SrcOps.size() == 1);
418 LLT DstTy = MRI.getType(MatchInfo.Dst);
419 assert(DstTy == LLT::fixed_vector(8, 8) ||
420 DstTy == LLT::fixed_vector(16, 8));
421 LLT BSTy = DstTy == LLT::fixed_vector(8, 8)
424 // FIXME: NVCAST
425 auto BS1 = MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {BSTy},
426 MatchInfo.SrcOps[0]);
427 auto BS2 = MIRBuilder.buildInstr(MatchInfo.Opc, {BSTy}, {BS1});
428 MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {MatchInfo.Dst}, {BS2});
429 } else
430 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
431 MI.eraseFromParent();
432}
433
434/// Replace a G_SHUFFLE_VECTOR instruction with G_EXT.
435/// Special-cased because the constant operand must be emitted as a G_CONSTANT
436/// for the imported tablegen patterns to work.
437void applyEXT(MachineInstr &MI, ShuffleVectorPseudo &MatchInfo) {
438 MachineIRBuilder MIRBuilder(MI);
439 if (MatchInfo.SrcOps[2].getImm() == 0)
440 MIRBuilder.buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
441 else {
442 // Tablegen patterns expect an i32 G_CONSTANT as the final op.
443 auto Cst = MIRBuilder.buildConstant(LLT::integer(32),
444 MatchInfo.SrcOps[2].getImm());
445 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
446 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
447 }
448 MI.eraseFromParent();
449}
450
451void applyFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
452 Register Dst = MI.getOperand(0).getReg();
453 Register Src = MI.getOperand(1).getReg();
454 LLT DstTy = MRI.getType(Dst);
455 assert(DstTy.getSizeInBits() == 128 &&
456 "Expected 128bit vector in applyFullRev");
457 MachineIRBuilder MIRBuilder(MI);
458 auto Cst = MIRBuilder.buildConstant(LLT::integer(32), 8);
459 auto Rev = MIRBuilder.buildInstr(AArch64::G_REV64, {DstTy}, {Src});
460 MIRBuilder.buildInstr(AArch64::G_EXT, {Dst}, {Rev, Rev, Cst});
461 MI.eraseFromParent();
462}
463
464bool matchNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI) {
465 assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
466
467 auto ValAndVReg =
468 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
469 return !ValAndVReg;
470}
471
472void applyNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI,
473 MachineIRBuilder &Builder) {
474 auto &Insert = cast<GInsertVectorElement>(MI);
475 Builder.setInstrAndDebugLoc(Insert);
476
477 Register Offset = Insert.getIndexReg();
478 LLT VecTy = MRI.getType(Insert.getReg(0));
479 LLT EltTy = MRI.getType(Insert.getElementReg());
480 LLT IdxTy = MRI.getType(Insert.getIndexReg());
481
482 if (VecTy.isScalableVector())
483 return;
484
485 // Create a stack slot and store the vector into it
486 MachineFunction &MF = Builder.getMF();
487 Align Alignment(
488 std::min<uint64_t>(VecTy.getSizeInBytes().getKnownMinValue(), 16));
489 int FrameIdx = MF.getFrameInfo().CreateStackObject(VecTy.getSizeInBytes(),
490 Alignment, false);
491 LLT FramePtrTy = LLT::pointer(0, 64);
493 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
494
495 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo, Align(8));
496
497 // Get the pointer to the element, and be sure not to hit undefined behavior
498 // if the index is out of bounds.
500 "Expected a power-2 vector size");
501 auto Mask = Builder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
502 Register And = Builder.buildAnd(IdxTy, Offset, Mask).getReg(0);
503 auto EltSize = Builder.buildConstant(IdxTy, EltTy.getSizeInBytes());
504 Register Mul = Builder.buildMul(IdxTy, And, EltSize).getReg(0);
505 Register EltPtr =
506 Builder.buildPtrAdd(MRI.getType(StackTemp.getReg(0)), StackTemp, Mul)
507 .getReg(0);
508
509 // Write the inserted element
510 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo, Align(1));
511 // Reload the whole vector.
512 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo, Align(8));
513 Insert.eraseFromParent();
514}
515
516/// Match a G_SHUFFLE_VECTOR with a mask which corresponds to a
517/// G_INSERT_VECTOR_ELT and G_EXTRACT_VECTOR_ELT pair.
518///
519/// e.g.
520/// %shuf = G_SHUFFLE_VECTOR %left, %right, shufflemask(0, 0)
521///
522/// Can be represented as
523///
524/// %extract = G_EXTRACT_VECTOR_ELT %left, 0
525/// %ins = G_INSERT_VECTOR_ELT %left, %extract, 1
526///
527bool matchINS(MachineInstr &MI, MachineRegisterInfo &MRI,
528 std::tuple<Register, int, Register, int> &MatchInfo) {
529 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
530 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
531 Register Dst = MI.getOperand(0).getReg();
532 int NumElts = MRI.getType(Dst).getNumElements();
533 auto DstIsLeftAndDstLane = isINSMask(ShuffleMask, NumElts);
534 if (!DstIsLeftAndDstLane)
535 return false;
536 bool DstIsLeft;
537 int DstLane;
538 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
539 Register Left = MI.getOperand(1).getReg();
540 Register Right = MI.getOperand(2).getReg();
541 Register DstVec = DstIsLeft ? Left : Right;
542 Register SrcVec = Left;
543
544 int SrcLane = ShuffleMask[DstLane];
545 if (SrcLane >= NumElts) {
546 SrcVec = Right;
547 SrcLane -= NumElts;
548 }
549
550 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
551 return true;
552}
553
554void applyINS(MachineInstr &MI, MachineRegisterInfo &MRI,
555 MachineIRBuilder &Builder,
556 std::tuple<Register, int, Register, int> &MatchInfo) {
557 Builder.setInstrAndDebugLoc(MI);
558 Register Dst = MI.getOperand(0).getReg();
559 auto ScalarTy = MRI.getType(Dst).getElementType();
560 Register DstVec, SrcVec;
561 int DstLane, SrcLane;
562 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
563 auto SrcCst = Builder.buildConstant(LLT::integer(64), SrcLane);
564 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
565 auto DstCst = Builder.buildConstant(LLT::integer(64), DstLane);
566 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
567 MI.eraseFromParent();
568}
569
570/// isVShiftRImm - Check if this is a valid vector for the immediate
571/// operand of a vector shift right operation. The value must be in the range:
572/// 1 <= Value <= ElementBits for a right shift.
574 int64_t &Cnt) {
575 assert(Ty.isVector() && "vector shift count is not a vector type");
577 auto Cst = getAArch64VectorSplatScalar(*MI, MRI);
578 if (!Cst)
579 return false;
580 Cnt = *Cst;
581 int64_t ElementBits = Ty.getScalarSizeInBits();
582 return Cnt >= 1 && Cnt <= ElementBits;
583}
584
585/// Match a vector G_ASHR or G_LSHR with a valid immediate shift.
586bool matchVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
587 int64_t &Imm) {
588 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
589 MI.getOpcode() == TargetOpcode::G_LSHR);
590 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
591 if (!Ty.isVector())
592 return false;
593 return isVShiftRImm(MI.getOperand(2).getReg(), MRI, Ty, Imm);
594}
595
596void applyVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
597 int64_t &Imm) {
598 unsigned Opc = MI.getOpcode();
599 assert(Opc == TargetOpcode::G_ASHR || Opc == TargetOpcode::G_LSHR);
600 unsigned NewOpc =
601 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
602 MachineIRBuilder MIB(MI);
603 MIB.buildInstr(NewOpc, {MI.getOperand(0)}, {MI.getOperand(1)}).addImm(Imm);
604 MI.eraseFromParent();
605}
606
607/// Determine if it is possible to modify the \p RHS and predicate \p P of a
608/// G_ICMP instruction such that the right-hand side is an arithmetic immediate.
609///
610/// \returns A pair containing the updated immediate and predicate which may
611/// be used to optimize the instruction.
612///
613/// \note This assumes that the comparison has been legalized.
614std::optional<std::pair<uint64_t, CmpInst::Predicate>>
615tryAdjustICmpImmAndPred(Register RHS, CmpInst::Predicate P,
616 const MachineRegisterInfo &MRI) {
617 const auto &Ty = MRI.getType(RHS);
618 if (Ty.isVector())
619 return std::nullopt;
620 unsigned Size = Ty.getSizeInBits();
621 assert((Size == 32 || Size == 64) && "Expected 32 or 64 bit compare only?");
622
623 // If the RHS is not a constant, or the RHS is already a valid arithmetic
624 // immediate, then there is nothing to change.
625 auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS, MRI);
626 if (!ValAndVReg)
627 return std::nullopt;
628 uint64_t OriginalC = ValAndVReg->Value.getZExtValue();
629 uint64_t C = OriginalC;
630 if (isLegalArithImmed(C))
631 return std::nullopt;
632
633 // We have a non-arithmetic immediate. Check if adjusting the immediate and
634 // adjusting the predicate will result in a legal arithmetic immediate.
635 switch (P) {
636 default:
637 return std::nullopt;
640 // Check for
641 //
642 // x slt c => x sle c - 1
643 // x sge c => x sgt c - 1
644 //
645 // When c is not the smallest possible negative number.
646 if ((Size == 64 && static_cast<int64_t>(C) == INT64_MIN) ||
647 (Size == 32 && static_cast<int32_t>(C) == INT32_MIN))
648 return std::nullopt;
650 C -= 1;
651 break;
654 // Check for
655 //
656 // x ult c => x ule c - 1
657 // x uge c => x ugt c - 1
658 //
659 // When c is not zero.
660 assert(C != 0 && "C should not be zero here!");
662 C -= 1;
663 break;
666 // Check for
667 //
668 // x sle c => x slt c + 1
669 // x sgt c => s sge c + 1
670 //
671 // When c is not the largest possible signed integer.
672 if ((Size == 32 && static_cast<int32_t>(C) == INT32_MAX) ||
673 (Size == 64 && static_cast<int64_t>(C) == INT64_MAX))
674 return std::nullopt;
676 C += 1;
677 break;
680 // Check for
681 //
682 // x ule c => x ult c + 1
683 // x ugt c => s uge c + 1
684 //
685 // When c is not the largest possible unsigned integer.
686 if ((Size == 32 && static_cast<uint32_t>(C) == UINT32_MAX) ||
687 (Size == 64 && C == UINT64_MAX))
688 return std::nullopt;
690 C += 1;
691 break;
692 }
693
694 // Check if the new constant is valid, and return the updated constant and
695 // predicate if it is.
696 if (Size == 32)
697 C = static_cast<uint32_t>(C);
698 if (isLegalArithImmed(C))
699 return {{C, P}};
700
701 auto NumberOfInstrToLoadImm = [=](uint64_t Imm) {
703 AArch64_IMM::expandMOVImm(Imm, 32, Insn);
704 return Insn.size();
705 };
706
707 if (NumberOfInstrToLoadImm(OriginalC) > NumberOfInstrToLoadImm(C))
708 return {{C, P}};
709
710 return std::nullopt;
711}
712
713/// Determine whether or not it is possible to update the RHS and predicate of
714/// a G_ICMP instruction such that the RHS will be selected as an arithmetic
715/// immediate.
716///
717/// \p MI - The G_ICMP instruction
718/// \p MatchInfo - The new RHS immediate and predicate on success
719///
720/// See tryAdjustICmpImmAndPred for valid transformations.
721bool matchAdjustICmpImmAndPred(
723 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
724 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
725 Register RHS = MI.getOperand(3).getReg();
726 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
727 if (auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(RHS, Pred, MRI)) {
728 MatchInfo = *MaybeNewImmAndPred;
729 return true;
730 }
731 return false;
732}
733
734void applyAdjustICmpImmAndPred(
735 MachineInstr &MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
736 MachineIRBuilder &MIB, GISelChangeObserver &Observer) {
738 MachineOperand &RHS = MI.getOperand(3);
739 MachineRegisterInfo &MRI = *MIB.getMRI();
740 auto Cst = MIB.buildConstant(MRI.cloneVirtualRegister(RHS.getReg()),
741 MatchInfo.first);
742 Observer.changingInstr(MI);
743 RHS.setReg(Cst->getOperand(0).getReg());
744 MI.getOperand(1).setPredicate(MatchInfo.second);
745 Observer.changedInstr(MI);
746}
747
748bool matchDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
749 std::pair<unsigned, int> &MatchInfo) {
750 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
751 Register Src1Reg = MI.getOperand(1).getReg();
752 const LLT SrcTy = MRI.getType(Src1Reg);
753 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
754
755 auto LaneIdx = getSplatIndex(MI);
756 if (!LaneIdx)
757 return false;
758
759 // The lane idx should be within the first source vector.
760 if (*LaneIdx >= SrcTy.getNumElements())
761 return false;
762
763 if (DstTy != SrcTy)
764 return false;
765
766 LLT ScalarTy = SrcTy.getElementType();
767 unsigned ScalarSize = ScalarTy.getSizeInBits();
768
769 unsigned Opc = 0;
770 switch (SrcTy.getNumElements()) {
771 case 2:
772 if (ScalarSize == 64)
773 Opc = AArch64::G_DUPLANE64;
774 else if (ScalarSize == 32)
775 Opc = AArch64::G_DUPLANE32;
776 break;
777 case 4:
778 if (ScalarSize == 32)
779 Opc = AArch64::G_DUPLANE32;
780 else if (ScalarSize == 16)
781 Opc = AArch64::G_DUPLANE16;
782 break;
783 case 8:
784 if (ScalarSize == 8)
785 Opc = AArch64::G_DUPLANE8;
786 else if (ScalarSize == 16)
787 Opc = AArch64::G_DUPLANE16;
788 break;
789 case 16:
790 if (ScalarSize == 8)
791 Opc = AArch64::G_DUPLANE8;
792 break;
793 default:
794 break;
795 }
796 if (!Opc)
797 return false;
798
799 MatchInfo.first = Opc;
800 MatchInfo.second = *LaneIdx;
801 return true;
802}
803
804void applyDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
805 MachineIRBuilder &B, std::pair<unsigned, int> &MatchInfo) {
806 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
807 Register Src1Reg = MI.getOperand(1).getReg();
808 const LLT SrcTy = MRI.getType(Src1Reg);
809
810 B.setInstrAndDebugLoc(MI);
811 auto Lane = B.buildConstant(LLT::integer(64), MatchInfo.second);
812
813 Register DupSrc = MI.getOperand(1).getReg();
814 // For types like <2 x s32>, we can use G_DUPLANE32, with a <4 x s32> source.
815 // To do this, we can use a G_CONCAT_VECTORS to do the widening.
816 if (SrcTy.getSizeInBits() == 64) {
817 auto Undef = B.buildUndef(SrcTy);
818 DupSrc = B.buildConcatVectors(SrcTy.multiplyElements(2),
819 {Src1Reg, Undef.getReg(0)})
820 .getReg(0);
821 }
822 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
823 MI.eraseFromParent();
824}
825
826bool matchScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI) {
827 auto &Unmerge = cast<GUnmerge>(MI);
828 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
829 const LLT SrcTy = MRI.getType(Src1Reg);
830 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
831 return false;
832 return SrcTy.isVector() && !SrcTy.isScalable() &&
833 Unmerge.getNumOperands() == (unsigned)SrcTy.getNumElements() + 1;
834}
835
836void applyScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
838 auto &Unmerge = cast<GUnmerge>(MI);
839 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
840 const LLT SrcTy = MRI.getType(Src1Reg);
841 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
842 "Expected a fixed length vector");
843
844 for (int I = 0; I < SrcTy.getNumElements(); ++I)
845 B.buildExtractVectorElementConstant(Unmerge.getReg(I), Src1Reg, I);
846 MI.eraseFromParent();
847}
848
849bool matchBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI) {
850 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
851
852 // Later, during selection, we'll try to match imported patterns using
853 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
854 // G_BUILD_VECTORs which could match those patterns.
856 return false;
857
858 return getAArch64VectorSplat(MI, MRI).has_value();
859}
860
861void applyBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI,
863 B.setInstrAndDebugLoc(MI);
864 B.buildInstr(AArch64::G_DUP, {MI.getOperand(0).getReg()},
865 {MI.getOperand(1).getReg()});
866 MI.eraseFromParent();
867}
868
869/// \returns how many instructions would be saved by folding a G_ICMP's shift
870/// and/or extension operations.
872 // No instructions to save if there's more than one use or no uses.
873 if (!MRI.hasOneNonDBGUse(CmpOp))
874 return 0;
875
876 // FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
877 auto IsSupportedExtend = [&](const MachineInstr &MI) {
878 if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
879 return true;
880 if (MI.getOpcode() != TargetOpcode::G_AND)
881 return false;
882 auto ValAndVReg =
883 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
884 if (!ValAndVReg)
885 return false;
886 uint64_t Mask = ValAndVReg->Value.getZExtValue();
887 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
888 };
889
890 MachineInstr *Def = getDefIgnoringCopies(CmpOp, MRI);
891 if (IsSupportedExtend(*Def))
892 return 1;
893
894 unsigned Opc = Def->getOpcode();
895 if (Opc != TargetOpcode::G_SHL && Opc != TargetOpcode::G_ASHR &&
896 Opc != TargetOpcode::G_LSHR)
897 return 0;
898
899 auto MaybeShiftAmt =
900 getIConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
901 if (!MaybeShiftAmt)
902 return 0;
903 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
904 MachineInstr *ShiftLHS =
905 getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
906
907 // Check if we can fold an extend and a shift.
908 // FIXME: This is duplicated with the selector. (See:
909 // selectArithExtendedRegister)
910 if (IsSupportedExtend(*ShiftLHS))
911 return (ShiftAmt <= 4) ? 2 : 1;
912
913 LLT Ty = MRI.getType(Def->getOperand(0).getReg());
914 if (Ty.isVector())
915 return 0;
916 unsigned ShiftSize = Ty.getSizeInBits();
917 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
918 (ShiftSize == 64 && ShiftAmt <= 63))
919 return 1;
920 return 0;
921}
922
923/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
924/// instruction \p MI.
925bool trySwapICmpOperands(MachineInstr &MI, MachineRegisterInfo &MRI) {
926 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
927 // Swap the operands if it would introduce a profitable folding opportunity.
928 // (e.g. a shift + extend).
929 //
930 // For example:
931 // lsl w13, w11, #1
932 // cmp w13, w12
933 // can be turned into:
934 // cmp w12, w11, lsl #1
935
936 // Don't swap if there's a constant on the RHS, because we know we can fold
937 // that.
938 Register RHS = MI.getOperand(3).getReg();
939 auto RHSCst = getIConstantVRegValWithLookThrough(RHS, MRI);
940 if (RHSCst && isLegalArithImmed(RHSCst->Value.getSExtValue()))
941 return false;
942
943 Register LHS = MI.getOperand(2).getReg();
944 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
945 auto GetRegForProfit = [&](Register Reg) {
947 return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
948 };
949
950 // Don't have a constant on the RHS. If we swap the LHS and RHS of the
951 // compare, would we be able to fold more instructions?
952 Register TheLHS = GetRegForProfit(LHS);
953 Register TheRHS = GetRegForProfit(RHS);
954
955 // If the LHS is more likely to give us a folding opportunity, then swap the
956 // LHS and RHS.
957 return (getCmpOperandFoldingProfit(TheLHS, MRI) >
958 getCmpOperandFoldingProfit(TheRHS, MRI));
959}
960
961void applySwapICmpOperands(MachineInstr &MI, GISelChangeObserver &Observer) {
962 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
963 Register LHS = MI.getOperand(2).getReg();
964 Register RHS = MI.getOperand(3).getReg();
965 Observer.changedInstr(MI);
966 MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
967 MI.getOperand(2).setReg(RHS);
968 MI.getOperand(3).setReg(LHS);
969 Observer.changedInstr(MI);
970}
971
972/// \returns a function which builds a vector floating point compare instruction
973/// for a condition code \p CC.
974/// \param [in] NoNans - True if the instruction has nnan flag.
975std::function<Register(MachineIRBuilder &)>
976getVectorFCMP(AArch64CC::CondCode CC, Register LHS, Register RHS, bool NoNans,
977 MachineRegisterInfo &MRI) {
978 LLT OldTy = MRI.getType(LHS);
979 LLT DstTy = LLT::fixed_vector(OldTy.getNumElements(),
981 assert(DstTy.isVector() && "Expected vector types only?");
982 switch (CC) {
983 default:
984 llvm_unreachable("Unexpected condition code!");
985 case AArch64CC::NE:
986 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
987 auto FCmp = MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS});
988 return MIB.buildNot(DstTy, FCmp).getReg(0);
989 };
990 case AArch64CC::EQ:
991 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
992 return MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS}).getReg(0);
993 };
994 case AArch64CC::GE:
995 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
996 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {LHS, RHS}).getReg(0);
997 };
998 case AArch64CC::GT:
999 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1000 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {LHS, RHS}).getReg(0);
1001 };
1002 case AArch64CC::LS:
1003 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1004 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {RHS, LHS}).getReg(0);
1005 };
1006 case AArch64CC::MI:
1007 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1008 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {RHS, LHS}).getReg(0);
1009 };
1010 }
1011}
1012
1013/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1014bool matchLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1015 MachineIRBuilder &MIB) {
1016 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1017 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
1018
1019 Register Dst = MI.getOperand(0).getReg();
1020 LLT DstTy = MRI.getType(Dst);
1021 if (!DstTy.isVector() || !ST.hasNEON())
1022 return false;
1023 Register LHS = MI.getOperand(2).getReg();
1024 unsigned EltSize = MRI.getType(LHS).getScalarSizeInBits();
1025 if (EltSize == 16 && !ST.hasFullFP16())
1026 return false;
1027 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
1028 return false;
1029
1030 return true;
1031}
1032
1033/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1034void applyLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1035 MachineIRBuilder &MIB) {
1036 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1037
1038 const auto &CmpMI = cast<GFCmp>(MI);
1039
1040 Register Dst = CmpMI.getReg(0);
1041 CmpInst::Predicate Pred = CmpMI.getCond();
1042 Register LHS = CmpMI.getLHSReg();
1043 Register RHS = CmpMI.getRHSReg();
1044
1045 LLT DstTy = MRI.getType(Dst);
1046
1047 bool Invert = false;
1049 if ((Pred == CmpInst::Predicate::FCMP_ORD ||
1051 isBuildVectorAllZeros(*MRI.getVRegDef(RHS), MRI)) {
1052 // The special case "fcmp ord %a, 0" is the canonical check that LHS isn't
1053 // NaN, so equivalent to a == a and doesn't need the two comparisons an
1054 // "ord" normally would.
1055 // Similarly, "fcmp uno %a, 0" is the canonical check that LHS is NaN and is
1056 // thus equivalent to a != a.
1057 RHS = LHS;
1059 } else
1060 changeVectorFCMPPredToAArch64CC(Pred, CC, CC2, Invert);
1061
1062 // Instead of having an apply function, just build here to simplify things.
1064
1065 // TODO: Also consider GISelValueTracking result if eligible.
1066 const bool NoNans = MI.getFlag(MachineInstr::FmNoNans);
1067
1068 auto Cmp = getVectorFCMP(CC, LHS, RHS, NoNans, MRI);
1069 Register CmpRes;
1070 if (CC2 == AArch64CC::AL)
1071 CmpRes = Cmp(MIB);
1072 else {
1073 auto Cmp2 = getVectorFCMP(CC2, LHS, RHS, NoNans, MRI);
1074 auto Cmp2Dst = Cmp2(MIB);
1075 auto Cmp1Dst = Cmp(MIB);
1076 CmpRes = MIB.buildOr(DstTy, Cmp1Dst, Cmp2Dst).getReg(0);
1077 }
1078 if (Invert)
1079 CmpRes = MIB.buildNot(DstTy, CmpRes).getReg(0);
1080 MRI.replaceRegWith(Dst, CmpRes);
1081 MI.eraseFromParent();
1082}
1083
1084// Matches G_BUILD_VECTOR where at least one source operand is not a constant
1085bool matchLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI) {
1086 auto *GBuildVec = cast<GBuildVector>(&MI);
1087
1088 // Check if the values are all constants
1089 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1090 auto ConstVal =
1091 getAnyConstantVRegValWithLookThrough(GBuildVec->getSourceReg(I), MRI);
1092
1093 if (!ConstVal.has_value())
1094 return true;
1095 }
1096
1097 return false;
1098}
1099
1100void applyLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI,
1102 auto *GBuildVec = cast<GBuildVector>(&MI);
1103 LLT DstTy = MRI.getType(GBuildVec->getReg(0));
1104 Register DstReg = B.buildUndef(DstTy).getReg(0);
1105
1106 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1107 Register SrcReg = GBuildVec->getSourceReg(I);
1108 if (mi_match(SrcReg, MRI, m_GImplicitDef()))
1109 continue;
1110 auto IdxReg = B.buildConstant(LLT::integer(64), I);
1111 DstReg =
1112 B.buildInsertVectorElement(DstTy, DstReg, SrcReg, IdxReg).getReg(0);
1113 }
1114 B.buildCopy(GBuildVec->getReg(0), DstReg);
1115 GBuildVec->eraseFromParent();
1116}
1117
1118bool matchFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1119 Register &SrcReg) {
1120 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1121 Register DstReg = MI.getOperand(0).getReg();
1122 if (MRI.getType(DstReg).isVector())
1123 return false;
1124 // Match a store of a truncate.
1125 if (!mi_match(DstReg, MRI, m_GTrunc(m_Reg(SrcReg))))
1126 return false;
1127 // Only form truncstores for value types of max 64b.
1128 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1129}
1130
1131void applyFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1133 Register &SrcReg) {
1134 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1135 Observer.changingInstr(MI);
1136 MI.getOperand(0).setReg(SrcReg);
1137 Observer.changedInstr(MI);
1138}
1139
1140// Lower vector G_SEXT_INREG back to shifts for selection. We allowed them to
1141// form in the first place for combine opportunities, so any remaining ones
1142// at this stage need be lowered back.
1143bool matchVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI) {
1144 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1145 Register DstReg = MI.getOperand(0).getReg();
1146 LLT DstTy = MRI.getType(DstReg);
1147 return DstTy.isVector();
1148}
1149
1150void applyVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI,
1152 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1153 B.setInstrAndDebugLoc(MI);
1154 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1155 Helper.lower(MI, 0, /* Unused hint type */ LLT());
1156}
1157
1158/// Combine <N x t>, unused = unmerge(G_EXT <2*N x t> v, undef, N)
1159/// => unused, <N x t> = unmerge v
1160bool matchUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1161 Register &MatchInfo) {
1162 auto &Unmerge = cast<GUnmerge>(MI);
1163 if (Unmerge.getNumDefs() != 2)
1164 return false;
1165 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
1166 return false;
1167
1168 LLT DstTy = MRI.getType(Unmerge.getReg(0));
1169 if (!DstTy.isVector())
1170 return false;
1171
1172 MachineInstr *Ext = getOpcodeDef(AArch64::G_EXT, Unmerge.getSourceReg(), MRI);
1173 if (!Ext)
1174 return false;
1175
1176 Register ExtSrc1 = Ext->getOperand(1).getReg();
1177 Register ExtSrc2 = Ext->getOperand(2).getReg();
1178 auto LowestVal =
1180 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.getSizeInBytes())
1181 return false;
1182
1183 if (!getOpcodeDef<GImplicitDef>(ExtSrc2, MRI))
1184 return false;
1185
1186 MatchInfo = ExtSrc1;
1187 return true;
1188}
1189
1190void applyUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1192 GISelChangeObserver &Observer, Register &SrcReg) {
1193 Observer.changingInstr(MI);
1194 // Swap dst registers.
1195 Register Dst1 = MI.getOperand(0).getReg();
1196 MI.getOperand(0).setReg(MI.getOperand(1).getReg());
1197 MI.getOperand(1).setReg(Dst1);
1198 MI.getOperand(2).setReg(SrcReg);
1199 Observer.changedInstr(MI);
1200}
1201
1202// Match mul({z/s}ext , {z/s}ext) => {u/s}mull OR
1203// Match v2s64 mul instructions, which will then be scalarised later on
1204// Doing these two matches in one function to ensure that the order of matching
1205// will always be the same.
1206// Try lowering MUL to MULL before trying to scalarize if needed.
1207bool matchMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI) {
1208 // Get the instructions that defined the source operand
1209 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1210 return DstTy == LLT::fixed_vector(2, 64);
1211}
1212
1213void applyMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI,
1215 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
1216 "Expected a G_MUL instruction");
1217
1218 // Get the instructions that defined the source operand
1219 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1220 assert(DstTy == LLT::fixed_vector(2, 64) && "Expected v2s64 Mul");
1221 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1222 Helper.fewerElementsVector(
1223 MI, 0,
1225}
1226
1227class AArch64PostLegalizerLoweringImpl : public Combiner {
1228protected:
1229 const CombinerHelper Helper;
1230 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1231 const AArch64Subtarget &STI;
1232
1233public:
1234 AArch64PostLegalizerLoweringImpl(
1235 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1236 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1237 const AArch64Subtarget &STI);
1238
1239 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
1240
1241 bool tryCombineAll(MachineInstr &I) const override;
1242
1243private:
1244#define GET_GICOMBINER_CLASS_MEMBERS
1245#include "AArch64GenPostLegalizeGILowering.inc"
1246#undef GET_GICOMBINER_CLASS_MEMBERS
1247};
1248
1249#define GET_GICOMBINER_IMPL
1250#include "AArch64GenPostLegalizeGILowering.inc"
1251#undef GET_GICOMBINER_IMPL
1252
1253AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1254 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1255 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1256 const AArch64Subtarget &STI)
1257 : Combiner(MF, CInfo, /*VT*/ nullptr, CSEInfo),
1258 Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
1259 STI(STI),
1261#include "AArch64GenPostLegalizeGILowering.inc"
1263{
1264}
1265
1266bool runPostLegalizerLowering(
1267 MachineFunction &MF,
1268 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig) {
1269 if (MF.getProperties().hasFailedISel())
1270 return false;
1271 const Function &F = MF.getFunction();
1272
1274 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
1275 /*LegalizerInfo=*/nullptr, /*OptEnabled=*/true,
1276 F.hasOptSize(), F.hasMinSize());
1277 // Disable fixed-point iteration to reduce compile-time
1278 CInfo.MaxIterations = 1;
1279 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
1280 // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
1281 CInfo.EnableFullDCE = false;
1282 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo, /*CSEInfo=*/nullptr,
1283 RuleConfig, ST);
1284 return Impl.combineMachineInstrs();
1285}
1286
1287class AArch64PostLegalizerLoweringLegacy : public MachineFunctionPass {
1288public:
1289 static char ID;
1290
1291 AArch64PostLegalizerLoweringLegacy();
1292
1293 StringRef getPassName() const override {
1294 return "AArch64PostLegalizerLowering";
1295 }
1296
1297 bool runOnMachineFunction(MachineFunction &MF) override;
1298 void getAnalysisUsage(AnalysisUsage &AU) const override;
1299
1300private:
1301 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1302};
1303} // end anonymous namespace
1304
1305void AArch64PostLegalizerLoweringLegacy::getAnalysisUsage(
1306 AnalysisUsage &AU) const {
1307 AU.setPreservesCFG();
1310}
1311
1312AArch64PostLegalizerLoweringLegacy::AArch64PostLegalizerLoweringLegacy()
1313 : MachineFunctionPass(ID) {
1314 if (!RuleConfig.parseCommandLineOption())
1315 report_fatal_error("Invalid rule identifier");
1316}
1317
1318bool AArch64PostLegalizerLoweringLegacy::runOnMachineFunction(
1319 MachineFunction &MF) {
1320 assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
1321 return runPostLegalizerLowering(MF, RuleConfig);
1322}
1323
1324char AArch64PostLegalizerLoweringLegacy::ID = 0;
1325INITIALIZE_PASS_BEGIN(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1326 "Lower AArch64 MachineInstrs after legalization", false,
1327 false)
1328INITIALIZE_PASS_END(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1329 "Lower AArch64 MachineInstrs after legalization", false,
1330 false)
1331
1333 : RuleConfig(
1334 std::make_unique<AArch64PostLegalizerLoweringImplRuleConfig>()) {
1335 if (!RuleConfig->parseCommandLineOption())
1336 reportFatalUsageError("invalid rule identifier");
1337}
1338
1341
1343
1347 MFPropsModifier _(*this, MF);
1348 const bool Changed = runPostLegalizerLowering(MF, *RuleConfig);
1349
1350 if (!Changed)
1351 return PreservedAnalyses::all();
1352
1355 return PA;
1356}
1357
1358namespace llvm {
1360 return new AArch64PostLegalizerLoweringLegacy();
1361}
1362} // 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:1563
unsigned logBase2() const
Definition APInt.h:1784
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
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.
static LLT integer(unsigned SizeInBits)
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.