LLVM 24.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/// Helper function for matchINS.
81///
82/// \returns a value when \p M is an ins mask for \p NumInputElements.
83///
84/// First element of the returned pair is true when the produced
85/// G_INSERT_VECTOR_ELT destination should be the LHS of the G_SHUFFLE_VECTOR.
86///
87/// Second element is the destination lane for the G_INSERT_VECTOR_ELT.
88std::optional<std::pair<bool, int>> isINSMask(ArrayRef<int> M,
89 int NumInputElements) {
90 if (M.size() != static_cast<size_t>(NumInputElements))
91 return std::nullopt;
92 int NumLHSMatch = 0, NumRHSMatch = 0;
93 int LastLHSMismatch = -1, LastRHSMismatch = -1;
94 for (int Idx = 0; Idx < NumInputElements; ++Idx) {
95 if (M[Idx] == -1) {
96 ++NumLHSMatch;
97 ++NumRHSMatch;
98 continue;
99 }
100 M[Idx] == Idx ? ++NumLHSMatch : LastLHSMismatch = Idx;
101 M[Idx] == Idx + NumInputElements ? ++NumRHSMatch : LastRHSMismatch = Idx;
102 }
103 const int NumNeededToMatch = NumInputElements - 1;
104 if (NumLHSMatch == NumNeededToMatch)
105 return std::make_pair(true, LastLHSMismatch);
106 if (NumRHSMatch == NumNeededToMatch)
107 return std::make_pair(false, LastRHSMismatch);
108 return std::nullopt;
109}
110
111/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with a
112/// G_REV instruction. Returns the appropriate G_REV opcode in \p Opc.
113bool matchREV(MachineInstr &MI, MachineRegisterInfo &MRI,
114 ShuffleVectorPseudo &MatchInfo) {
115 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
116 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
117 Register Dst = MI.getOperand(0).getReg();
118 Register Src = MI.getOperand(1).getReg();
119 LLT Ty = MRI.getType(Dst);
120 unsigned EltSize = Ty.getScalarSizeInBits();
121
122 // Element size for a rev cannot be 64.
123 if (EltSize == 64)
124 return false;
125
126 unsigned NumElts = Ty.getNumElements();
127
128 // Try to produce a G_REV instruction
129 for (unsigned LaneSize : {64U, 32U, 16U}) {
130 if (isREVMask(ShuffleMask, EltSize, NumElts, LaneSize)) {
131 unsigned Opcode;
132 if (LaneSize == 64U)
133 Opcode = AArch64::G_REV64;
134 else if (LaneSize == 32U)
135 Opcode = AArch64::G_REV32;
136 else
137 Opcode = AArch64::G_BSWAP;
138
139 MatchInfo = ShuffleVectorPseudo(Opcode, Dst, {Src});
140 return true;
141 }
142 }
143
144 return false;
145}
146
147/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
148/// a G_TRN1 or G_TRN2 instruction.
149bool matchTRN(MachineInstr &MI, MachineRegisterInfo &MRI,
150 ShuffleVectorPseudo &MatchInfo) {
151 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
152 unsigned WhichResult;
153 unsigned OperandOrder = 0;
154 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
155 Register Dst = MI.getOperand(0).getReg();
156 unsigned NumElts = MRI.getType(Dst).getNumElements();
157 bool TRNMask = isTRNMask(ShuffleMask, NumElts, WhichResult, OperandOrder);
158 if (!TRNMask && !isTRN_v_undef_Mask(ShuffleMask, NumElts, WhichResult))
159 return false;
160 unsigned Opc = (WhichResult == 0) ? AArch64::G_TRN1 : AArch64::G_TRN2;
161 Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
162 Register V2 = MI.getOperand(OperandOrder == 0 && TRNMask ? 2 : 1).getReg();
163 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
164 return true;
165}
166
167/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
168/// a G_UZP1 or G_UZP2 instruction.
169///
170/// \param [in] MI - The shuffle vector instruction.
171/// \param [out] MatchInfo - Either G_UZP1 or G_UZP2 on success.
172bool matchUZP(MachineInstr &MI, MachineRegisterInfo &MRI,
173 ShuffleVectorPseudo &MatchInfo) {
174 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
175 unsigned WhichResult;
176 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
177 Register Dst = MI.getOperand(0).getReg();
178 unsigned NumElts = MRI.getType(Dst).getNumElements();
179 bool UZPMask = isUZPMask(ShuffleMask, NumElts, WhichResult);
180 if (!UZPMask && !isUZP_v_undef_Mask(ShuffleMask, NumElts, WhichResult))
181 return false;
182 unsigned Opc = (WhichResult == 0) ? AArch64::G_UZP1 : AArch64::G_UZP2;
183 Register V1 = MI.getOperand(1).getReg();
184 Register V2 = MI.getOperand(UZPMask ? 2 : 1).getReg();
185 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
186 return true;
187}
188
189bool matchZip(MachineInstr &MI, MachineRegisterInfo &MRI,
190 ShuffleVectorPseudo &MatchInfo) {
191 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
192 unsigned WhichResult;
193 unsigned OperandOrder = 0;
194 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
195 Register Dst = MI.getOperand(0).getReg();
196 unsigned NumElts = MRI.getType(Dst).getNumElements();
197 bool ZIPMask = isZIPMask(ShuffleMask, NumElts, WhichResult, OperandOrder);
198 if (!ZIPMask && !isZIP_v_undef_Mask(ShuffleMask, NumElts, WhichResult))
199 return false;
200 unsigned Opc = (WhichResult == 0) ? AArch64::G_ZIP1 : AArch64::G_ZIP2;
201 Register V1 = MI.getOperand(OperandOrder == 0 ? 1 : 2).getReg();
202 Register V2 = MI.getOperand(OperandOrder == 0 && ZIPMask ? 2 : 1).getReg();
203 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
204 return true;
205}
206
207/// Helper function for matchDup.
208bool matchDupFromInsertVectorElt(int Lane, MachineInstr &MI,
210 ShuffleVectorPseudo &MatchInfo) {
211 if (Lane != 0)
212 return false;
213
214 // Try to match a vector splat operation into a dup instruction.
215 // We're looking for this pattern:
216 //
217 // %scalar:gpr(s64) = COPY $x0
218 // %undef:fpr(<2 x s64>) = G_IMPLICIT_DEF
219 // %cst0:gpr(s32) = G_CONSTANT i32 0
220 // %zerovec:fpr(<2 x s32>) = G_BUILD_VECTOR %cst0(s32), %cst0(s32)
221 // %ins:fpr(<2 x s64>) = G_INSERT_VECTOR_ELT %undef, %scalar(s64), %cst0(s32)
222 // %splat:fpr(<2 x s64>) = G_SHUFFLE_VECTOR %ins(<2 x s64>), %undef,
223 // %zerovec(<2 x s32>)
224 //
225 // ...into:
226 // %splat = G_SPLAT_VECTOR %scalar
227
228 // Begin matching the insert.
229 auto *InsMI = getOpcodeDef(TargetOpcode::G_INSERT_VECTOR_ELT,
230 MI.getOperand(1).getReg(), MRI);
231 if (!InsMI)
232 return false;
233 // Match the undef vector operand.
234 if (!getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, InsMI->getOperand(1).getReg(),
235 MRI))
236 return false;
237
238 // Match the index constant 0.
239 if (!mi_match(InsMI->getOperand(3).getReg(), MRI, m_ZeroInt()))
240 return false;
241
242 MatchInfo = ShuffleVectorPseudo(TargetOpcode::G_SPLAT_VECTOR,
243 MI.getOperand(0).getReg(),
244 {InsMI->getOperand(2).getReg()});
245 return true;
246}
247
248/// Helper function for matchDup.
249bool matchDupFromBuildVector(int Lane, MachineInstr &MI,
251 ShuffleVectorPseudo &MatchInfo) {
252 assert(Lane >= 0 && "Expected positive lane?");
253 int NumElements = MRI.getType(MI.getOperand(1).getReg()).getNumElements();
254 // Test if the LHS is a BUILD_VECTOR. If it is, then we can just reference the
255 // lane's definition directly.
256 auto *BuildVecMI =
257 getOpcodeDef(TargetOpcode::G_BUILD_VECTOR,
258 MI.getOperand(Lane < NumElements ? 1 : 2).getReg(), MRI);
259 // If Lane >= NumElements then it is point to RHS, just check from RHS
260 if (NumElements <= Lane)
261 Lane -= NumElements;
262
263 if (!BuildVecMI)
264 return false;
265 Register Reg = BuildVecMI->getOperand(Lane + 1).getReg();
266 MatchInfo = ShuffleVectorPseudo(TargetOpcode::G_SPLAT_VECTOR,
267 MI.getOperand(0).getReg(), {Reg});
268 return true;
269}
270
271bool matchDup(MachineInstr &MI, MachineRegisterInfo &MRI,
272 ShuffleVectorPseudo &MatchInfo) {
273 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
274 auto MaybeLane = getSplatIndex(MI);
275 if (!MaybeLane)
276 return false;
277 int Lane = *MaybeLane;
278 // If this is undef splat, generate it via "just" vdup, if possible.
279 if (Lane < 0)
280 Lane = 0;
281 if (matchDupFromInsertVectorElt(Lane, MI, MRI, MatchInfo))
282 return true;
283 if (matchDupFromBuildVector(Lane, MI, MRI, MatchInfo))
284 return true;
285 return false;
286}
287
288bool matchEXT(MachineInstr &MI, MachineRegisterInfo &MRI,
289 ShuffleVectorPseudo &MatchInfo) {
290 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
291 Register Dst = MI.getOperand(0).getReg();
292 LLT DstTy = MRI.getType(Dst);
293 Register V1 = MI.getOperand(1).getReg();
294 Register V2 = MI.getOperand(2).getReg();
295 auto Mask = MI.getOperand(3).getShuffleMask();
296 uint64_t ExtFactor = MRI.getType(V1).getScalarSizeInBits() / 8;
297
298 unsigned Imm;
299 bool ReverseExt;
300 if (isEXTMask(Mask, DstTy.getNumElements(), ReverseExt, Imm)) {
301 if (ReverseExt)
302 std::swap(V1, V2);
303 Imm *= ExtFactor;
304 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
305 {V1, V2, static_cast<uint64_t>(Imm)});
306 return true;
307 }
308
309 if (!getOpcodeDef<GImplicitDef>(V2, MRI) ||
310 !isSingletonEXTMask(Mask, DstTy.getNumElements(), Imm))
311 return false;
312
313 Imm = Mask[0] * ExtFactor;
314 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
315 {V1, V1, static_cast<uint64_t>(Imm)});
316 return true;
317}
318
319/// Replace a G_SHUFFLE_VECTOR instruction with a pseudo.
320/// \p Opc is the opcode to use. \p MI is the G_SHUFFLE_VECTOR.
321void applyShuffleVectorPseudo(MachineInstr &MI, MachineRegisterInfo &MRI,
322 ShuffleVectorPseudo &MatchInfo) {
323 MachineIRBuilder MIRBuilder(MI);
324 if (MatchInfo.Opc == TargetOpcode::G_BSWAP) {
325 assert(MatchInfo.SrcOps.size() == 1);
326 LLT DstTy = MRI.getType(MatchInfo.Dst);
327 assert(DstTy == LLT::fixed_vector(8, 8) ||
328 DstTy == LLT::fixed_vector(16, 8));
329 LLT BSTy = DstTy == LLT::fixed_vector(8, 8)
332 // FIXME: NVCAST
333 auto BS1 = MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {BSTy},
334 MatchInfo.SrcOps[0]);
335 auto BS2 = MIRBuilder.buildInstr(MatchInfo.Opc, {BSTy}, {BS1});
336 MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {MatchInfo.Dst}, {BS2});
337 } else
338 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
339 MI.eraseFromParent();
340}
341
342/// Replace a G_SHUFFLE_VECTOR instruction with G_EXT.
343/// Special-cased because the constant operand must be emitted as a G_CONSTANT
344/// for the imported tablegen patterns to work.
345void applyEXT(MachineInstr &MI, ShuffleVectorPseudo &MatchInfo) {
346 MachineIRBuilder MIRBuilder(MI);
347 if (MatchInfo.SrcOps[2].getImm() == 0)
348 MIRBuilder.buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
349 else {
350 // Tablegen patterns expect an i32 G_CONSTANT as the final op.
351 auto Cst = MIRBuilder.buildConstant(LLT::integer(32),
352 MatchInfo.SrcOps[2].getImm());
353 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
354 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
355 }
356 MI.eraseFromParent();
357}
358
359static bool preferTBLToMultiInstrShuffle(MachineBasicBlock *MBB) {
360 if (MBB->getParent()->getFunction().hasOptSize())
361 return false;
362 // Look for a simple single block loop.
363 return is_contained(successors(MBB), MBB);
364}
365
366bool matchFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
367 if (preferTBLToMultiInstrShuffle(MI.getParent()))
368 return false;
369
370 auto &Shuf = cast<GShuffleVector>(MI);
371 ArrayRef<int> Mask = Shuf.getMask();
372 return mi_match(Shuf.getSrc2Reg(), MRI, m_GImplicitDef()) &&
373 ShuffleVectorInst::isReverseMask(Mask, Mask.size());
374}
375
376void applyFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
377 Register Dst = MI.getOperand(0).getReg();
378 Register Src = MI.getOperand(1).getReg();
379 LLT DstTy = MRI.getType(Dst);
380 assert(DstTy.getSizeInBits() == 128 &&
381 "Expected 128bit vector in applyFullRev");
382 MachineIRBuilder MIRBuilder(MI);
383 auto Cst = MIRBuilder.buildConstant(LLT::integer(32), 8);
384 auto Rev = MIRBuilder.buildInstr(AArch64::G_REV64, {DstTy}, {Src});
385 MIRBuilder.buildInstr(AArch64::G_EXT, {Dst}, {Rev, Rev, Cst});
386 MI.eraseFromParent();
387}
388
389bool matchNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI) {
390 assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
391
392 auto ValAndVReg =
393 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
394 return !ValAndVReg;
395}
396
397void applyNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI,
398 MachineIRBuilder &Builder) {
399 auto &Insert = cast<GInsertVectorElement>(MI);
400 Builder.setInstrAndDebugLoc(Insert);
401
402 Register Offset = Insert.getIndexReg();
403 LLT VecTy = MRI.getType(Insert.getReg(0));
404 LLT EltTy = MRI.getType(Insert.getElementReg());
405 LLT IdxTy = MRI.getType(Insert.getIndexReg());
406
407 if (VecTy.isScalableVector())
408 return;
409
410 // Create a stack slot and store the vector into it
411 MachineFunction &MF = Builder.getMF();
412 Align Alignment(
413 std::min<uint64_t>(VecTy.getSizeInBytes().getKnownMinValue(), 16));
414 int FrameIdx = MF.getFrameInfo().CreateStackObject(VecTy.getSizeInBytes(),
415 Alignment, false);
416 LLT FramePtrTy = LLT::pointer(0, 64);
418 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
419
420 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo, Align(8));
421
422 // Get the pointer to the element, and be sure not to hit undefined behavior
423 // if the index is out of bounds.
425 "Expected a power-2 vector size");
426 auto Mask = Builder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
427 Register And = Builder.buildAnd(IdxTy, Offset, Mask).getReg(0);
428 auto EltSize = Builder.buildConstant(IdxTy, EltTy.getSizeInBytes());
429 Register Mul = Builder.buildMul(IdxTy, And, EltSize).getReg(0);
430 Register EltPtr =
431 Builder.buildPtrAdd(MRI.getType(StackTemp.getReg(0)), StackTemp, Mul)
432 .getReg(0);
433
434 // Write the inserted element
435 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo, Align(1));
436 // Reload the whole vector.
437 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo, Align(8));
438 Insert.eraseFromParent();
439}
440
441/// Match a G_SHUFFLE_VECTOR with a mask which corresponds to a
442/// G_INSERT_VECTOR_ELT and G_EXTRACT_VECTOR_ELT pair.
443///
444/// e.g.
445/// %shuf = G_SHUFFLE_VECTOR %left, %right, shufflemask(0, 0)
446///
447/// Can be represented as
448///
449/// %extract = G_EXTRACT_VECTOR_ELT %left, 0
450/// %ins = G_INSERT_VECTOR_ELT %left, %extract, 1
451///
452bool matchINS(MachineInstr &MI, MachineRegisterInfo &MRI,
453 std::tuple<Register, int, Register, int> &MatchInfo) {
454 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
455 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
456 Register Dst = MI.getOperand(0).getReg();
457 int NumElts = MRI.getType(Dst).getNumElements();
458 auto DstIsLeftAndDstLane = isINSMask(ShuffleMask, NumElts);
459 if (!DstIsLeftAndDstLane)
460 return false;
461 bool DstIsLeft;
462 int DstLane;
463 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
464 Register Left = MI.getOperand(1).getReg();
465 Register Right = MI.getOperand(2).getReg();
466 Register DstVec = DstIsLeft ? Left : Right;
467 Register SrcVec = Left;
468
469 int SrcLane = ShuffleMask[DstLane];
470 if (SrcLane >= NumElts) {
471 SrcVec = Right;
472 SrcLane -= NumElts;
473 }
474
475 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
476 return true;
477}
478
479void applyINS(MachineInstr &MI, MachineRegisterInfo &MRI,
480 MachineIRBuilder &Builder,
481 std::tuple<Register, int, Register, int> &MatchInfo) {
482 Builder.setInstrAndDebugLoc(MI);
483 Register Dst = MI.getOperand(0).getReg();
484 auto ScalarTy = MRI.getType(Dst).getElementType();
485 Register DstVec, SrcVec;
486 int DstLane, SrcLane;
487 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
488 auto SrcCst = Builder.buildConstant(LLT::integer(64), SrcLane);
489 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
490 auto DstCst = Builder.buildConstant(LLT::integer(64), DstLane);
491 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
492 MI.eraseFromParent();
493}
494
495/// isVShiftRImm - Check if this is a valid vector for the immediate
496/// operand of a vector shift right operation. The value must be in the range:
497/// 1 <= Value <= ElementBits for a right shift.
499 int64_t &Cnt) {
500 assert(Ty.isVector() && "vector shift count is not a vector type");
501 int64_t ElementBits = Ty.getScalarSizeInBits();
502 assert(ElementBits <= 64 && "expected <= 64bit shift type");
504 std::optional<Register> Splat = getVectorSplat(*MI, MRI);
505 if (!Splat)
506 return false;
507 std::optional<APInt> C = getIConstantVRegVal(*Splat, MRI);
508 if (!C)
509 return false;
510 Cnt = C->getSExtValue();
511 return Cnt >= 1 && Cnt <= ElementBits;
512}
513
514/// Match a vector G_ASHR or G_LSHR with a valid immediate shift.
515bool matchVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
516 int64_t &Imm) {
517 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
518 MI.getOpcode() == TargetOpcode::G_LSHR);
519 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
520 if (!Ty.isVector())
521 return false;
522 return isVShiftRImm(MI.getOperand(2).getReg(), MRI, Ty, Imm);
523}
524
525void applyVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
526 int64_t &Imm) {
527 unsigned Opc = MI.getOpcode();
528 assert(Opc == TargetOpcode::G_ASHR || Opc == TargetOpcode::G_LSHR);
529 unsigned NewOpc =
530 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
531 MachineIRBuilder MIB(MI);
532 MIB.buildInstr(NewOpc, {MI.getOperand(0)}, {MI.getOperand(1)}).addImm(Imm);
533 MI.eraseFromParent();
534}
535
536/// Determine whether an integer G_ICMP against 1 or -1 can compare
537/// against 0 instead.
538///
539/// AArch64 can fold a compare-with-zero more cheaply than some non-arithmetic
540/// immediates (SUBS/ADDS, or TST when the LHS is an AND). When the predicate
541/// can be adjusted without changing semantics, the RHS may become 0.
542///
543/// Supported transforms (signed predicates only):
544/// (and X, Y) slt 1 => (and X, Y) sle 0
545/// (and X, Y) sge 1 => (and X, Y) sgt 0
546/// X sle -1 => X slt 0
547/// X sgt -1 => X sge 0
548///
549/// The compare-against-1 cases require the LHS to be G_AND because the
550/// compare-with-zero path enables ANDS (TST) selection, and ANDS flags are
551/// only reliable for those signed comparisons. This mirrors SelectionDAG
552/// emitComparison().
553///
554/// For compare-against--1 on a non-AND LHS, \p LHS must have a single
555/// non-debug use so other users are not left with a different immediate.
556///
557/// \param LHS The compare LHS register.
558/// \param C The constant RHS (only 1 or all-ones are considered).
559/// \param P In/out predicate; updated when a transform applies.
560/// \param MRI Used to inspect the LHS definition and use count.
561/// \returns true if \p P was updated and comparing against 0 is equivalent.
562static bool shouldBeAdjustedToZero(Register LHS, const APInt &C,
564 const MachineRegisterInfo &MRI) {
565 const bool IsAndLHS = getOpcodeDef<GAnd>(LHS, MRI) != nullptr;
566
567 if (C.isOne() && (P == CmpInst::ICMP_SLT || P == CmpInst::ICMP_SGE) &&
568 IsAndLHS) {
570 return true;
571 }
572
573 if (!IsAndLHS && !MRI.hasOneNonDBGUse(LHS))
574 return false;
575
576 if (C.isAllOnes() && (P == CmpInst::ICMP_SLE || P == CmpInst::ICMP_SGT)) {
578 return true;
579 }
580 return false;
581}
582
583/// Determine if it is possible to modify the \p RHS and predicate \p P of a
584/// G_ICMP instruction such that the right-hand side is an arithmetic immediate.
585///
586/// \returns A pair containing the updated immediate and predicate which may
587/// be used to optimize the instruction.
588///
589/// \note This assumes that the comparison has been legalized.
590std::optional<std::pair<uint64_t, CmpInst::Predicate>>
591tryAdjustICmpImmAndPred(Register LHS, Register RHS, CmpInst::Predicate P,
592 const MachineRegisterInfo &MRI) {
593 const auto &Ty = MRI.getType(RHS);
594 if (Ty.isVector())
595 return std::nullopt;
596 assert((Ty.getSizeInBits() == 32 || Ty.getSizeInBits() == 64) &&
597 "Expected 32 or 64 bit compare only?");
598
599 // If the RHS is not a constant, or the RHS is already a valid arithmetic
600 // immediate, then there is nothing to change.
601 auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS, MRI);
602 if (!ValAndVReg)
603 return std::nullopt;
604 APInt C = ValAndVReg->Value;
605 if (shouldBeAdjustedToZero(LHS, C, P, MRI))
606 return {{0, P}};
607
609 return std::nullopt;
610
611 uint64_t OriginalC = C.getZExtValue();
612
613 // We have a non-arithmetic immediate. Check if adjusting the immediate and
614 // adjusting the predicate will result in a legal arithmetic immediate.
615 switch (P) {
616 default:
617 return std::nullopt;
620 // Check for
621 //
622 // x slt c => x sle c - 1
623 // x sge c => x sgt c - 1
624 //
625 // When c is not the smallest possible negative number.
626 if (C.isMinSignedValue())
627 return std::nullopt;
629 C = C - 1;
630 break;
633 // Check for
634 //
635 // x ult c => x ule c - 1
636 // x uge c => x ugt c - 1
637 //
638 // When c is not zero.
639 assert(!C.isZero() && "C should not be zero here!");
641 C = C - 1;
642 break;
645 // Check for
646 //
647 // x sle c => x slt c + 1
648 // x sgt c => s sge c + 1
649 //
650 // When c is not the largest possible signed integer.
651 if (C.isMaxSignedValue())
652 return std::nullopt;
654 C = C + 1;
655 break;
658 // Check for
659 //
660 // x ule c => x ult c + 1
661 // x ugt c => s uge c + 1
662 //
663 // When c is not the largest possible unsigned integer.
664 if (C.isAllOnes())
665 return std::nullopt;
667 C = C + 1;
668 break;
669 }
670
671 // Check if the new constant is valid, and return the updated constant and
672 // predicate if it is.
673 uint64_t NewC = C.getZExtValue();
675 return {{NewC, P}};
676
677 auto NumberOfInstrToLoadImm = [=](uint64_t Imm) {
680 return Insn.size();
681 };
682
683 if (NumberOfInstrToLoadImm(OriginalC) > NumberOfInstrToLoadImm(NewC))
684 return {{NewC, P}};
685
686 return std::nullopt;
687}
688
689/// Determine whether or not it is possible to update the RHS and predicate of
690/// a G_ICMP instruction such that the RHS will be selected as an arithmetic
691/// immediate.
692///
693/// \p MI - The G_ICMP instruction
694/// \p MatchInfo - The new RHS immediate and predicate on success
695///
696/// See tryAdjustICmpImmAndPred for valid transformations.
697bool matchAdjustICmpImmAndPred(
699 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
700 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
701 Register LHS = MI.getOperand(2).getReg();
702 Register RHS = MI.getOperand(3).getReg();
703 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
704 if (auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(LHS, RHS, Pred, MRI)) {
705 MatchInfo = *MaybeNewImmAndPred;
706 return true;
707 }
708 return false;
709}
710
711void applyAdjustICmpImmAndPred(
712 MachineInstr &MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
713 MachineIRBuilder &MIB, GISelChangeObserver &Observer) {
715 MachineOperand &RHS = MI.getOperand(3);
716 MachineRegisterInfo &MRI = *MIB.getMRI();
717 auto Cst = MIB.buildConstant(MRI.cloneVirtualRegister(RHS.getReg()),
718 MatchInfo.first);
719 Observer.changingInstr(MI);
720 RHS.setReg(Cst->getOperand(0).getReg());
721 MI.getOperand(1).setPredicate(MatchInfo.second);
722 Observer.changedInstr(MI);
723}
724
725bool matchDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
726 std::pair<unsigned, int> &MatchInfo) {
727 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
728 Register Src1Reg = MI.getOperand(1).getReg();
729 const LLT SrcTy = MRI.getType(Src1Reg);
730 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
731
732 auto LaneIdx = getSplatIndex(MI);
733 if (!LaneIdx)
734 return false;
735
736 // The lane idx should be within the first source vector.
737 if (*LaneIdx >= SrcTy.getNumElements())
738 return false;
739
740 if (DstTy != SrcTy)
741 return false;
742
743 LLT ScalarTy = SrcTy.getElementType();
744 unsigned ScalarSize = ScalarTy.getSizeInBits();
745
746 unsigned Opc = 0;
747 switch (SrcTy.getNumElements()) {
748 case 2:
749 if (ScalarSize == 64)
750 Opc = AArch64::G_DUPLANE64;
751 else if (ScalarSize == 32)
752 Opc = AArch64::G_DUPLANE32;
753 break;
754 case 4:
755 if (ScalarSize == 32)
756 Opc = AArch64::G_DUPLANE32;
757 else if (ScalarSize == 16)
758 Opc = AArch64::G_DUPLANE16;
759 break;
760 case 8:
761 if (ScalarSize == 8)
762 Opc = AArch64::G_DUPLANE8;
763 else if (ScalarSize == 16)
764 Opc = AArch64::G_DUPLANE16;
765 break;
766 case 16:
767 if (ScalarSize == 8)
768 Opc = AArch64::G_DUPLANE8;
769 break;
770 default:
771 break;
772 }
773 if (!Opc)
774 return false;
775
776 MatchInfo.first = Opc;
777 MatchInfo.second = *LaneIdx;
778 return true;
779}
780
781void applyDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
782 MachineIRBuilder &B, std::pair<unsigned, int> &MatchInfo) {
783 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
784 Register Src1Reg = MI.getOperand(1).getReg();
785 const LLT SrcTy = MRI.getType(Src1Reg);
786
787 B.setInstrAndDebugLoc(MI);
788 auto Lane = B.buildConstant(LLT::integer(64), MatchInfo.second);
789
790 Register DupSrc = MI.getOperand(1).getReg();
791 // For types like <2 x s32>, we can use G_DUPLANE32, with a <4 x s32> source.
792 // To do this, we can use a G_CONCAT_VECTORS to do the widening.
793 if (SrcTy.getSizeInBits() == 64) {
794 auto Undef = B.buildUndef(SrcTy);
795 DupSrc = B.buildConcatVectors(SrcTy.multiplyElements(2),
796 {Src1Reg, Undef.getReg(0)})
797 .getReg(0);
798 }
799 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
800 MI.eraseFromParent();
801}
802
803bool matchScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI) {
804 auto &Unmerge = cast<GUnmerge>(MI);
805 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
806 const LLT SrcTy = MRI.getType(Src1Reg);
807 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
808 return false;
809 return SrcTy.isVector() && !SrcTy.isScalable() &&
810 (Unmerge.getNumOperands() == (unsigned)SrcTy.getNumElements() + 1 ||
811 (Unmerge.getNumDefs() == 2 && SrcTy.getSizeInBits() == 128 &&
812 MRI.getType(Unmerge.getReg(0)).getSizeInBits() == 64));
813}
814
815void applyScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
817 auto &Unmerge = cast<GUnmerge>(MI);
818 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
819 const LLT SrcTy = MRI.getType(Src1Reg);
820 const LLT DstTy = MRI.getType(Unmerge.getReg(0));
821 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
822 "Expected a fixed length vector");
823
824 if (DstTy.isVector()) {
825 assert(Unmerge.getNumDefs() == 2);
826 if (!MRI.use_nodbg_empty(Unmerge.getReg(0)))
827 B.buildExtractSubvector(Unmerge.getReg(0), Src1Reg, 0);
828 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
829 B.buildExtractSubvector(Unmerge.getReg(1), Src1Reg,
830 SrcTy.getNumElements() / 2);
831 } else {
832 for (int I = 0; I < SrcTy.getNumElements(); ++I)
833 if (!MRI.use_nodbg_empty(Unmerge.getReg(I)))
834 B.buildExtractVectorElementConstant(Unmerge.getReg(I), Src1Reg, I);
835 }
836 MI.eraseFromParent();
837}
838
839bool matchBuildVectorToDup(MachineInstr &MI, Register &Src,
840 MachineRegisterInfo &MRI) {
841 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
842
843 // Later, during selection, we'll try to match imported patterns using
844 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
845 // G_BUILD_VECTORs which could match those patterns.
847 return false;
848
849 // Find buildvector which always uses the same register or undef. Return true
850 // so long as at least 2 registers were found (not all-undef or only 1
851 // non-undef entry).
852 Register Reg = 0;
853 unsigned NumNonUndef = 0;
854 for (const MachineOperand &Op : drop_begin(MI.operands())) {
855 if (getOpcodeDef<GImplicitDef>(Op.getReg(), MRI))
856 continue;
857
858 if (!Reg)
859 Reg = Op.getReg();
860 else if (Op.getReg() != Reg)
861 return false;
862 NumNonUndef++;
863 }
864
865 Src = Reg;
866 return Reg && NumNonUndef > 1;
867}
868
869void applyBuildVectorToDup(MachineInstr &MI, Register Src,
871 B.setInstrAndDebugLoc(MI);
872 B.buildInstr(TargetOpcode::G_SPLAT_VECTOR, {MI.getOperand(0).getReg()},
873 {Src});
874 MI.eraseFromParent();
875}
876
877/// \returns how many instructions would be saved by folding a G_ICMP's shift
878/// and/or extension operations.
879static unsigned getCmpOperandFoldingProfit(Register CmpOp,
880 MachineRegisterInfo &MRI) {
881 // FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
882 auto IsSupportedExtend = [&](const MachineInstr &MI) {
883 if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
884 return true;
885 if (MI.getOpcode() == TargetOpcode::G_AND) {
886 auto ValAndVReg =
887 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
888 if (ValAndVReg) {
889 uint64_t Mask = ValAndVReg->Value.getZExtValue();
890 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
891 }
892 }
893 return false;
894 };
895
896 // No instructions to save if there's more than one use or no uses.
897 if (!MRI.hasOneNonDBGUse(CmpOp))
898 return 0;
899
900 MachineInstr *Def = getDefIgnoringCopies(CmpOp, MRI);
901 if (IsSupportedExtend(*Def))
902 return 1;
903
904 unsigned Opc = Def->getOpcode();
905 if (Opc == TargetOpcode::G_SHL || Opc == TargetOpcode::G_LSHR ||
906 Opc == TargetOpcode::G_ASHR) {
907 auto MaybeShiftAmt =
908 getIConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
909 if (MaybeShiftAmt) {
910 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
911 MachineInstr *ShiftLHS =
912 getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
913 if (IsSupportedExtend(*ShiftLHS))
914 return (ShiftAmt <= 4) ? 2 : 1;
915 LLT Ty = MRI.getType(Def->getOperand(0).getReg());
916 if (Ty.isVector())
917 return 0;
918 unsigned ShiftSize = Ty.getSizeInBits();
919 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
920 (ShiftSize == 64 && ShiftAmt <= 63))
921 return 1;
922 }
923 }
924
925 return 0;
926}
927
928/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
929/// instruction \p MI.
930bool trySwapICmpOperands(MachineInstr &MI, MachineRegisterInfo &MRI) {
931 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
932 // Swap the operands if it would introduce a profitable folding opportunity.
933 // (e.g. a shift + extend).
934 //
935 // For example:
936 // lsl w13, w11, #1
937 // cmp w13, w12
938 // can be turned into:
939 // cmp w12, w11, lsl #1
940
941 // Don't swap if there's a constant on the RHS and it is a legal compare
942 // immediate, because we know we can fold that.
943 Register RHS = MI.getOperand(3).getReg();
944 auto RHSCst = getIConstantVRegValWithLookThrough(RHS, MRI);
945 if (RHSCst && AArch64_AM::isLegalCmpImmed(RHSCst->Value))
946 return false;
947
948 Register LHS = MI.getOperand(2).getReg();
949 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
950 auto GetRegForProfit = [&](Register Reg) {
952 return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
953 };
954
955 // Don't have a constant on the RHS. If we swap the LHS and RHS of the
956 // compare, would we be able to fold more instructions?
957 Register TheLHS = GetRegForProfit(LHS);
958 Register TheRHS = GetRegForProfit(RHS);
959
960 // If the LHS is more likely to give us a folding opportunity, then swap the
961 // LHS and RHS.
962 return (getCmpOperandFoldingProfit(TheLHS, MRI) >
963 getCmpOperandFoldingProfit(TheRHS, MRI));
964}
965
966void applySwapICmpOperands(MachineInstr &MI, GISelChangeObserver &Observer) {
967 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
968 Register LHS = MI.getOperand(2).getReg();
969 Register RHS = MI.getOperand(3).getReg();
970 Observer.changingInstr(MI);
971 MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
972 MI.getOperand(2).setReg(RHS);
973 MI.getOperand(3).setReg(LHS);
974 Observer.changedInstr(MI);
975}
976
977/// \returns a function which builds a vector floating point compare instruction
978/// for a condition code \p CC.
979/// \param [in] NoNans - True if the instruction has nnan flag.
980std::function<Register(MachineIRBuilder &)>
981getVectorFCMP(AArch64CC::CondCode CC, Register LHS, Register RHS, bool NoNans,
982 MachineRegisterInfo &MRI) {
983 LLT OldTy = MRI.getType(LHS);
984 LLT DstTy = LLT::fixed_vector(OldTy.getNumElements(),
986 assert(DstTy.isVector() && "Expected vector types only?");
987 switch (CC) {
988 default:
989 llvm_unreachable("Unexpected condition code!");
990 case AArch64CC::NE:
991 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
992 auto FCmp = MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS});
993 return MIB.buildNot(DstTy, FCmp).getReg(0);
994 };
995 case AArch64CC::EQ:
996 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
997 return MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS}).getReg(0);
998 };
999 case AArch64CC::GE:
1000 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1001 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {LHS, RHS}).getReg(0);
1002 };
1003 case AArch64CC::GT:
1004 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1005 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {LHS, RHS}).getReg(0);
1006 };
1007 case AArch64CC::LS:
1008 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1009 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {RHS, LHS}).getReg(0);
1010 };
1011 case AArch64CC::MI:
1012 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1013 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {RHS, LHS}).getReg(0);
1014 };
1015 }
1016}
1017
1018/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1019bool matchLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1020 MachineIRBuilder &MIB) {
1021 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1022 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
1023
1024 Register Dst = MI.getOperand(0).getReg();
1025 LLT DstTy = MRI.getType(Dst);
1026 if (!DstTy.isVector() || !ST.hasNEON())
1027 return false;
1028 Register LHS = MI.getOperand(2).getReg();
1029 unsigned EltSize = MRI.getType(LHS).getScalarSizeInBits();
1030 if (EltSize == 16 && !ST.hasFullFP16())
1031 return false;
1032 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
1033 return false;
1034
1035 return true;
1036}
1037
1038/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1039void applyLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1040 MachineIRBuilder &MIB) {
1041 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1042
1043 const auto &CmpMI = cast<GFCmp>(MI);
1044
1045 Register Dst = CmpMI.getReg(0);
1046 CmpInst::Predicate Pred = CmpMI.getCond();
1047 Register LHS = CmpMI.getLHSReg();
1048 Register RHS = CmpMI.getRHSReg();
1049
1050 LLT DstTy = MRI.getType(Dst);
1051
1052 bool Invert = false;
1054 if ((Pred == CmpInst::Predicate::FCMP_ORD ||
1056 isBuildVectorAllZeros(*MRI.getVRegDef(RHS), MRI)) {
1057 // The special case "fcmp ord %a, 0" is the canonical check that LHS isn't
1058 // NaN, so equivalent to a == a and doesn't need the two comparisons an
1059 // "ord" normally would.
1060 // Similarly, "fcmp uno %a, 0" is the canonical check that LHS is NaN and is
1061 // thus equivalent to a != a.
1062 RHS = LHS;
1064 } else
1065 changeVectorFCMPPredToAArch64CC(Pred, CC, CC2, Invert);
1066
1067 // Instead of having an apply function, just build here to simplify things.
1069
1070 // TODO: Also consider GISelValueTracking result if eligible.
1071 const bool NoNans = MI.getFlag(MachineInstr::FmNoNans);
1072
1073 auto Cmp = getVectorFCMP(CC, LHS, RHS, NoNans, MRI);
1074 Register CmpRes;
1075 if (CC2 == AArch64CC::AL)
1076 CmpRes = Cmp(MIB);
1077 else {
1078 auto Cmp2 = getVectorFCMP(CC2, LHS, RHS, NoNans, MRI);
1079 auto Cmp2Dst = Cmp2(MIB);
1080 auto Cmp1Dst = Cmp(MIB);
1081 CmpRes = MIB.buildOr(DstTy, Cmp1Dst, Cmp2Dst).getReg(0);
1082 }
1083 if (Invert)
1084 CmpRes = MIB.buildNot(DstTy, CmpRes).getReg(0);
1085 MRI.replaceRegWith(Dst, CmpRes);
1086 MI.eraseFromParent();
1087}
1088
1089// Matches G_BUILD_VECTOR where at least one source operand is not a constant
1090bool matchLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI) {
1091 auto *GBuildVec = cast<GBuildVector>(&MI);
1092
1093 // Check if the values are all constants
1094 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1095 auto ConstVal =
1096 getAnyConstantVRegValWithLookThrough(GBuildVec->getSourceReg(I), MRI);
1097
1098 if (!ConstVal.has_value())
1099 return true;
1100 }
1101
1102 return false;
1103}
1104
1105void applyLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI,
1107 auto *GBuildVec = cast<GBuildVector>(&MI);
1108 LLT DstTy = MRI.getType(GBuildVec->getReg(0));
1109 Register DstReg = B.buildUndef(DstTy).getReg(0);
1110
1111 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1112 Register SrcReg = GBuildVec->getSourceReg(I);
1113 if (mi_match(SrcReg, MRI, m_GImplicitDef()))
1114 continue;
1115 auto IdxReg = B.buildConstant(LLT::integer(64), I);
1116 DstReg =
1117 B.buildInsertVectorElement(DstTy, DstReg, SrcReg, IdxReg).getReg(0);
1118 }
1119 B.buildCopy(GBuildVec->getReg(0), DstReg);
1120 GBuildVec->eraseFromParent();
1121}
1122
1123// Detect vector constants that cannot be natively represent, but can be
1124// represented as fneg(constant). For example the constant
1125// <0x800000000000000, 0x800000000000000> can be represented as fneg(<0, 0>).
1126bool matchConstBuildVectorToFNeg(MachineInstr &MI, MachineRegisterInfo &MRI,
1127 const AArch64Subtarget &ST,
1128 std::pair<APInt, unsigned> &MatchInfo) {
1129 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
1130 if (!ST.isNeonAvailable())
1131 return false;
1132 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1133 // Limit to fneg of v2f32, v4f32, f64, v2f64 or v4f16 and v8f16 with fullfp16.
1134 if (Ty.getSizeInBits() != 64 && Ty.getSizeInBits() != 128)
1135 return false;
1136 unsigned EltSize = Ty.getScalarSizeInBits();
1137
1138 APInt Imm(Ty.getSizeInBits(), 0);
1139 for (unsigned Idx = 1; Idx < MI.getNumOperands(); Idx++) {
1140 auto C =
1141 getAnyConstantVRegValWithLookThrough(MI.getOperand(Idx).getReg(), MRI);
1142 if (!C)
1143 return false;
1144 Imm |= C->Value.trunc(EltSize)
1145 .zext(Ty.getSizeInBits())
1146 .shl((Idx - 1) * EltSize);
1147 }
1148
1150 if (AArch64_IMM::expandVectorMOVImm(Imm, Insns, ST))
1151 return false;
1152
1153 auto Check = [&](APInt &Imm, unsigned Size) {
1154 APInt NImm = Imm ^ APInt::getSplat(Imm.getBitWidth(),
1157 MatchInfo.first = NImm;
1158 MatchInfo.second = Size;
1159 return AArch64_IMM::expandVectorMOVImm(NImm, Insns, ST);
1160 };
1161
1162 return Check(Imm, 64) || Check(Imm, 32) ||
1163 (ST.hasFullFP16() && Check(Imm, 16));
1164}
1165
1166void applyConstBuildVectorToFNeg(MachineInstr &MI, MachineRegisterInfo &MRI,
1168 std::pair<APInt, unsigned> &MatchInfo) {
1169 B.setInstrAndDebugLoc(MI);
1170 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1171 // Extract the Immediate into chunks of size EltSize
1172 unsigned EltSize = MatchInfo.second;
1173 unsigned NumLanes = Ty.getSizeInBits() / EltSize;
1174 LLT VTy = NumLanes == 1
1175 ? LLT::floatIEEE(EltSize)
1176 : LLT::fixed_vector(NumLanes, LLT::floatIEEE(EltSize));
1177 SmallVector<APInt> Imms;
1178 for (unsigned I = 0; I < NumLanes; I++)
1179 Imms.push_back(MatchInfo.first.extractBits(EltSize, I * EltSize));
1180 // Build the new BV and FNeg of it.
1181 auto BV = NumLanes == 1 ? B.buildFConstant(VTy, APFloat(APFloat::IEEEdouble(),
1182 MatchInfo.first))
1183 : B.buildBuildVectorConstant(VTy, Imms);
1184 auto FNeg = B.buildFNeg(Ty == VTy ? DstOp(MI.getOperand(0)) : DstOp(VTy), BV);
1185 if (Ty != VTy)
1186 B.buildBitcast(MI.getOperand(0), FNeg);
1187 MI.eraseFromParent();
1188}
1189
1190bool matchFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1191 Register &SrcReg) {
1192 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1193 Register DstReg = MI.getOperand(0).getReg();
1194 if (cast<GLoadStore>(MI).isAtomic())
1195 return false;
1196 if (MRI.getType(DstReg).isVector())
1197 return false;
1198 // Match a store of a truncate.
1199 if (!mi_match(DstReg, MRI, m_GTrunc(m_Reg(SrcReg))))
1200 return false;
1201 // Only form truncstores for value types of max 64b.
1202 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1203}
1204
1205void applyFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1207 Register &SrcReg) {
1208 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1209 Observer.changingInstr(MI);
1210 MI.getOperand(0).setReg(SrcReg);
1211 Observer.changedInstr(MI);
1212}
1213
1214// Lower vector G_SEXT_INREG back to shifts for selection. We allowed them to
1215// form in the first place for combine opportunities, so any remaining ones
1216// at this stage need be lowered back.
1217bool matchVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI) {
1218 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1219 Register DstReg = MI.getOperand(0).getReg();
1220 LLT DstTy = MRI.getType(DstReg);
1221 return DstTy.isVector();
1222}
1223
1224void applyVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI,
1226 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1227 B.setInstrAndDebugLoc(MI);
1228 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1229 Helper.lower(MI, 0, /* Unused hint type */ LLT());
1230}
1231
1232/// Combine <N x t>, unused = unmerge(G_EXT <2*N x t> v, undef, N)
1233/// => unused, <N x t> = unmerge v
1234bool matchUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1235 Register &MatchInfo) {
1236 auto &Unmerge = cast<GUnmerge>(MI);
1237 if (Unmerge.getNumDefs() != 2)
1238 return false;
1239 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
1240 return false;
1241
1242 LLT DstTy = MRI.getType(Unmerge.getReg(0));
1243 if (!DstTy.isVector())
1244 return false;
1245
1246 MachineInstr *Ext = getOpcodeDef(AArch64::G_EXT, Unmerge.getSourceReg(), MRI);
1247 if (!Ext)
1248 return false;
1249
1250 Register ExtSrc1 = Ext->getOperand(1).getReg();
1251 Register ExtSrc2 = Ext->getOperand(2).getReg();
1252 auto LowestVal =
1254 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.getSizeInBytes())
1255 return false;
1256
1257 if (!getOpcodeDef<GImplicitDef>(ExtSrc2, MRI))
1258 return false;
1259
1260 MatchInfo = ExtSrc1;
1261 return true;
1262}
1263
1264void applyUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1266 GISelChangeObserver &Observer, Register &SrcReg) {
1267 Observer.changingInstr(MI);
1268 // Swap dst registers.
1269 Register Dst1 = MI.getOperand(0).getReg();
1270 MI.getOperand(0).setReg(MI.getOperand(1).getReg());
1271 MI.getOperand(1).setReg(Dst1);
1272 MI.getOperand(2).setReg(SrcReg);
1273 Observer.changedInstr(MI);
1274}
1275
1276// Match mul({z/s}ext , {z/s}ext) => {u/s}mull OR
1277// Match v2s64 mul instructions, which will then be scalarised later on
1278// Doing these two matches in one function to ensure that the order of matching
1279// will always be the same.
1280// Try lowering MUL to MULL before trying to scalarize if needed.
1281bool matchMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI) {
1282 // Get the instructions that defined the source operand
1283 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1284 return DstTy == LLT::fixed_vector(2, 64);
1285}
1286
1287void applyMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI,
1289 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
1290 "Expected a G_MUL instruction");
1291
1292 // Get the instructions that defined the source operand
1293 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1294 assert(DstTy == LLT::fixed_vector(2, 64) && "Expected v2s64 Mul");
1295 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1296 Helper.fewerElementsVector(
1297 MI, 0,
1299}
1300
1301class AArch64PostLegalizerLoweringImpl : public Combiner {
1302protected:
1303 const CombinerHelper Helper;
1304 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1305 const AArch64Subtarget &STI;
1306
1307public:
1308 AArch64PostLegalizerLoweringImpl(
1309 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1310 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1311 const AArch64Subtarget &STI);
1312
1313 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
1314
1315 bool tryCombineAll(MachineInstr &I) const override;
1316
1317private:
1318#define GET_GICOMBINER_CLASS_MEMBERS
1319#include "AArch64GenPostLegalizeGILowering.inc"
1320#undef GET_GICOMBINER_CLASS_MEMBERS
1321};
1322
1323#define GET_GICOMBINER_IMPL
1324#include "AArch64GenPostLegalizeGILowering.inc"
1325#undef GET_GICOMBINER_IMPL
1326
1327AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1328 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1329 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1330 const AArch64Subtarget &STI)
1331 : Combiner(MF, CInfo, /*VT*/ nullptr, CSEInfo),
1332 Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
1333 STI(STI),
1335#include "AArch64GenPostLegalizeGILowering.inc"
1337{
1338}
1339
1340bool runPostLegalizerLowering(
1341 MachineFunction &MF,
1342 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig) {
1343 if (MF.getProperties().hasFailedISel())
1344 return false;
1345 const Function &F = MF.getFunction();
1346
1348 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
1349 /*LegalizerInfo=*/nullptr, /*OptEnabled=*/true,
1350 F.hasOptSize(), F.hasMinSize());
1351 // Disable fixed-point iteration to reduce compile-time
1352 CInfo.MaxIterations = 1;
1353 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
1354 // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
1355 CInfo.EnableFullDCE = false;
1356 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo, /*CSEInfo=*/nullptr,
1357 RuleConfig, ST);
1358 return Impl.combineMachineInstrs();
1359}
1360
1361class AArch64PostLegalizerLoweringLegacy : public MachineFunctionPass {
1362public:
1363 static char ID;
1364
1365 AArch64PostLegalizerLoweringLegacy();
1366
1367 StringRef getPassName() const override {
1368 return "AArch64PostLegalizerLowering";
1369 }
1370
1371 bool runOnMachineFunction(MachineFunction &MF) override;
1372 void getAnalysisUsage(AnalysisUsage &AU) const override;
1373
1374private:
1375 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1376};
1377} // end anonymous namespace
1378
1379void AArch64PostLegalizerLoweringLegacy::getAnalysisUsage(
1380 AnalysisUsage &AU) const {
1381 AU.setPreservesCFG();
1384}
1385
1386AArch64PostLegalizerLoweringLegacy::AArch64PostLegalizerLoweringLegacy()
1387 : MachineFunctionPass(ID) {
1388 if (!RuleConfig.parseCommandLineOption())
1389 report_fatal_error("Invalid rule identifier");
1390}
1391
1392bool AArch64PostLegalizerLoweringLegacy::runOnMachineFunction(
1393 MachineFunction &MF) {
1394 assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
1395 return runPostLegalizerLowering(MF, RuleConfig);
1396}
1397
1398char AArch64PostLegalizerLoweringLegacy::ID = 0;
1399INITIALIZE_PASS_BEGIN(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1400 "Lower AArch64 MachineInstrs after legalization", false,
1401 false)
1402INITIALIZE_PASS_END(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1403 "Lower AArch64 MachineInstrs after legalization", false,
1404 false)
1405
1407 : RuleConfig(
1408 std::make_unique<AArch64PostLegalizerLoweringImplRuleConfig>()) {
1409 if (!RuleConfig->parseCommandLineOption())
1410 reportFatalUsageError("invalid rule identifier");
1411}
1412
1415
1417
1421 MFPropsModifier _(*this, MF);
1422 const bool Changed = runPostLegalizerLowering(MF, *RuleConfig);
1423
1424 if (!Changed)
1425 return PreservedAnalyses::all();
1426
1429 return PA;
1430}
1431
1432namespace llvm {
1434 return new AArch64PostLegalizerLoweringLegacy();
1435}
1436} // 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, bool AllowExtend)
Returns how profitable it is to fold a comparison's operand's shift and/or extension operations.
static bool shouldBeAdjustedToZero(SDValue LHS, const APInt &C, ISD::CondCode &CC)
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
unsigned Imm
unsigned uint64_t
MachineBasicBlock & MBB
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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 Check(C,...)
#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)
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
Class for arbitrary precision integers.
Definition APInt.h:78
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
Definition APInt.cpp:648
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition APInt.h:292
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:278
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:740
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Definition InstrTypes.h:890
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.
static LLT floatIEEE(unsigned SizeInBits)
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 LLVM_READONLY 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.
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
static LLVM_ABI bool isReverseMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask swaps the order of elements from exactly one source vector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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 llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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)
static bool isLegalCmpImmed(const APInt &C)
isLegalCmpImmed -
bool expandVectorMOVImm(APInt Imm, SmallVectorImpl< ImmInsnModel > &Insn, const AArch64Subtarget &ST)
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...
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.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
Definition Utils.cpp:1434
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:656
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,...
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:297
@ Undef
Value of the register doesn't matter.
bool isEXTMask(ArrayRef< int > M, unsigned NumElts, bool &ReverseEXT, unsigned &Imm)
Check if an EXT instruction can handle the shuffle mask when the vector sources of the shuffle are di...
auto successors(const MachineBasicBlock *BB)
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition Utils.cpp:497
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64PostLegalizerLowering()
bool isSingletonEXTMask(ArrayRef< int > M, unsigned NumElts, unsigned &Imm)
check if an EXT instruction can handle the shuffle mask when the vector sources of the shuffle are th...
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.
bool isUZP_v_undef_Mask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
isUZP_v_undef_Mask - Special case of isUZPMask for canonical form of "vector_shuffle v,...
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:442
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:1440
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1137
bool isZIP_v_undef_Mask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
isZIP_v_undef_Mask - Special case of isZIPMask for canonical form of "vector_shuffle v,...
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool isTRN_v_undef_Mask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
isTRN_v_undef_Mask - Special case of isTRNMask for canonical form of "vector_shuffle v,...
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
LLVM_ABI std::optional< Register > getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Definition Utils.cpp:1446
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:878
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
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.