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_DUP %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(AArch64::G_DUP, MI.getOperand(0).getReg(),
243 {InsMI->getOperand(2).getReg()});
244 return true;
245}
246
247/// Helper function for matchDup.
248bool matchDupFromBuildVector(int Lane, MachineInstr &MI,
250 ShuffleVectorPseudo &MatchInfo) {
251 assert(Lane >= 0 && "Expected positive lane?");
252 int NumElements = MRI.getType(MI.getOperand(1).getReg()).getNumElements();
253 // Test if the LHS is a BUILD_VECTOR. If it is, then we can just reference the
254 // lane's definition directly.
255 auto *BuildVecMI =
256 getOpcodeDef(TargetOpcode::G_BUILD_VECTOR,
257 MI.getOperand(Lane < NumElements ? 1 : 2).getReg(), MRI);
258 // If Lane >= NumElements then it is point to RHS, just check from RHS
259 if (NumElements <= Lane)
260 Lane -= NumElements;
261
262 if (!BuildVecMI)
263 return false;
264 Register Reg = BuildVecMI->getOperand(Lane + 1).getReg();
265 MatchInfo =
266 ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(), {Reg});
267 return true;
268}
269
270bool matchDup(MachineInstr &MI, MachineRegisterInfo &MRI,
271 ShuffleVectorPseudo &MatchInfo) {
272 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
273 auto MaybeLane = getSplatIndex(MI);
274 if (!MaybeLane)
275 return false;
276 int Lane = *MaybeLane;
277 // If this is undef splat, generate it via "just" vdup, if possible.
278 if (Lane < 0)
279 Lane = 0;
280 if (matchDupFromInsertVectorElt(Lane, MI, MRI, MatchInfo))
281 return true;
282 if (matchDupFromBuildVector(Lane, MI, MRI, MatchInfo))
283 return true;
284 return false;
285}
286
287bool matchEXT(MachineInstr &MI, MachineRegisterInfo &MRI,
288 ShuffleVectorPseudo &MatchInfo) {
289 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
290 Register Dst = MI.getOperand(0).getReg();
291 LLT DstTy = MRI.getType(Dst);
292 Register V1 = MI.getOperand(1).getReg();
293 Register V2 = MI.getOperand(2).getReg();
294 auto Mask = MI.getOperand(3).getShuffleMask();
295 uint64_t ExtFactor = MRI.getType(V1).getScalarSizeInBits() / 8;
296
297 unsigned Imm;
298 bool ReverseExt;
299 if (isEXTMask(Mask, DstTy.getNumElements(), ReverseExt, Imm)) {
300 if (ReverseExt)
301 std::swap(V1, V2);
302 Imm *= ExtFactor;
303 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
304 {V1, V2, static_cast<uint64_t>(Imm)});
305 return true;
306 }
307
308 if (!getOpcodeDef<GImplicitDef>(V2, MRI) ||
309 !isSingletonEXTMask(Mask, DstTy.getNumElements(), Imm))
310 return false;
311
312 Imm = Mask[0] * ExtFactor;
313 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
314 {V1, V1, static_cast<uint64_t>(Imm)});
315 return true;
316}
317
318/// Replace a G_SHUFFLE_VECTOR instruction with a pseudo.
319/// \p Opc is the opcode to use. \p MI is the G_SHUFFLE_VECTOR.
320void applyShuffleVectorPseudo(MachineInstr &MI, MachineRegisterInfo &MRI,
321 ShuffleVectorPseudo &MatchInfo) {
322 MachineIRBuilder MIRBuilder(MI);
323 if (MatchInfo.Opc == TargetOpcode::G_BSWAP) {
324 assert(MatchInfo.SrcOps.size() == 1);
325 LLT DstTy = MRI.getType(MatchInfo.Dst);
326 assert(DstTy == LLT::fixed_vector(8, 8) ||
327 DstTy == LLT::fixed_vector(16, 8));
328 LLT BSTy = DstTy == LLT::fixed_vector(8, 8)
331 // FIXME: NVCAST
332 auto BS1 = MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {BSTy},
333 MatchInfo.SrcOps[0]);
334 auto BS2 = MIRBuilder.buildInstr(MatchInfo.Opc, {BSTy}, {BS1});
335 MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {MatchInfo.Dst}, {BS2});
336 } else
337 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
338 MI.eraseFromParent();
339}
340
341/// Replace a G_SHUFFLE_VECTOR instruction with G_EXT.
342/// Special-cased because the constant operand must be emitted as a G_CONSTANT
343/// for the imported tablegen patterns to work.
344void applyEXT(MachineInstr &MI, ShuffleVectorPseudo &MatchInfo) {
345 MachineIRBuilder MIRBuilder(MI);
346 if (MatchInfo.SrcOps[2].getImm() == 0)
347 MIRBuilder.buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
348 else {
349 // Tablegen patterns expect an i32 G_CONSTANT as the final op.
350 auto Cst = MIRBuilder.buildConstant(LLT::integer(32),
351 MatchInfo.SrcOps[2].getImm());
352 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
353 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
354 }
355 MI.eraseFromParent();
356}
357
358void applyFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
359 Register Dst = MI.getOperand(0).getReg();
360 Register Src = MI.getOperand(1).getReg();
361 LLT DstTy = MRI.getType(Dst);
362 assert(DstTy.getSizeInBits() == 128 &&
363 "Expected 128bit vector in applyFullRev");
364 MachineIRBuilder MIRBuilder(MI);
365 auto Cst = MIRBuilder.buildConstant(LLT::integer(32), 8);
366 auto Rev = MIRBuilder.buildInstr(AArch64::G_REV64, {DstTy}, {Src});
367 MIRBuilder.buildInstr(AArch64::G_EXT, {Dst}, {Rev, Rev, Cst});
368 MI.eraseFromParent();
369}
370
371bool matchNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI) {
372 assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
373
374 auto ValAndVReg =
375 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
376 return !ValAndVReg;
377}
378
379void applyNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI,
380 MachineIRBuilder &Builder) {
381 auto &Insert = cast<GInsertVectorElement>(MI);
382 Builder.setInstrAndDebugLoc(Insert);
383
384 Register Offset = Insert.getIndexReg();
385 LLT VecTy = MRI.getType(Insert.getReg(0));
386 LLT EltTy = MRI.getType(Insert.getElementReg());
387 LLT IdxTy = MRI.getType(Insert.getIndexReg());
388
389 if (VecTy.isScalableVector())
390 return;
391
392 // Create a stack slot and store the vector into it
393 MachineFunction &MF = Builder.getMF();
394 Align Alignment(
395 std::min<uint64_t>(VecTy.getSizeInBytes().getKnownMinValue(), 16));
396 int FrameIdx = MF.getFrameInfo().CreateStackObject(VecTy.getSizeInBytes(),
397 Alignment, false);
398 LLT FramePtrTy = LLT::pointer(0, 64);
400 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
401
402 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo, Align(8));
403
404 // Get the pointer to the element, and be sure not to hit undefined behavior
405 // if the index is out of bounds.
407 "Expected a power-2 vector size");
408 auto Mask = Builder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
409 Register And = Builder.buildAnd(IdxTy, Offset, Mask).getReg(0);
410 auto EltSize = Builder.buildConstant(IdxTy, EltTy.getSizeInBytes());
411 Register Mul = Builder.buildMul(IdxTy, And, EltSize).getReg(0);
412 Register EltPtr =
413 Builder.buildPtrAdd(MRI.getType(StackTemp.getReg(0)), StackTemp, Mul)
414 .getReg(0);
415
416 // Write the inserted element
417 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo, Align(1));
418 // Reload the whole vector.
419 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo, Align(8));
420 Insert.eraseFromParent();
421}
422
423/// Match a G_SHUFFLE_VECTOR with a mask which corresponds to a
424/// G_INSERT_VECTOR_ELT and G_EXTRACT_VECTOR_ELT pair.
425///
426/// e.g.
427/// %shuf = G_SHUFFLE_VECTOR %left, %right, shufflemask(0, 0)
428///
429/// Can be represented as
430///
431/// %extract = G_EXTRACT_VECTOR_ELT %left, 0
432/// %ins = G_INSERT_VECTOR_ELT %left, %extract, 1
433///
434bool matchINS(MachineInstr &MI, MachineRegisterInfo &MRI,
435 std::tuple<Register, int, Register, int> &MatchInfo) {
436 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
437 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
438 Register Dst = MI.getOperand(0).getReg();
439 int NumElts = MRI.getType(Dst).getNumElements();
440 auto DstIsLeftAndDstLane = isINSMask(ShuffleMask, NumElts);
441 if (!DstIsLeftAndDstLane)
442 return false;
443 bool DstIsLeft;
444 int DstLane;
445 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
446 Register Left = MI.getOperand(1).getReg();
447 Register Right = MI.getOperand(2).getReg();
448 Register DstVec = DstIsLeft ? Left : Right;
449 Register SrcVec = Left;
450
451 int SrcLane = ShuffleMask[DstLane];
452 if (SrcLane >= NumElts) {
453 SrcVec = Right;
454 SrcLane -= NumElts;
455 }
456
457 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
458 return true;
459}
460
461void applyINS(MachineInstr &MI, MachineRegisterInfo &MRI,
462 MachineIRBuilder &Builder,
463 std::tuple<Register, int, Register, int> &MatchInfo) {
464 Builder.setInstrAndDebugLoc(MI);
465 Register Dst = MI.getOperand(0).getReg();
466 auto ScalarTy = MRI.getType(Dst).getElementType();
467 Register DstVec, SrcVec;
468 int DstLane, SrcLane;
469 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
470 auto SrcCst = Builder.buildConstant(LLT::integer(64), SrcLane);
471 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
472 auto DstCst = Builder.buildConstant(LLT::integer(64), DstLane);
473 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
474 MI.eraseFromParent();
475}
476
477/// isVShiftRImm - Check if this is a valid vector for the immediate
478/// operand of a vector shift right operation. The value must be in the range:
479/// 1 <= Value <= ElementBits for a right shift.
481 int64_t &Cnt) {
482 assert(Ty.isVector() && "vector shift count is not a vector type");
484 auto Cst = getAArch64VectorSplatScalar(*MI, MRI);
485 if (!Cst)
486 return false;
487 Cnt = *Cst;
488 int64_t ElementBits = Ty.getScalarSizeInBits();
489 return Cnt >= 1 && Cnt <= ElementBits;
490}
491
492/// Match a vector G_ASHR or G_LSHR with a valid immediate shift.
493bool matchVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
494 int64_t &Imm) {
495 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
496 MI.getOpcode() == TargetOpcode::G_LSHR);
497 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
498 if (!Ty.isVector())
499 return false;
500 return isVShiftRImm(MI.getOperand(2).getReg(), MRI, Ty, Imm);
501}
502
503void applyVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
504 int64_t &Imm) {
505 unsigned Opc = MI.getOpcode();
506 assert(Opc == TargetOpcode::G_ASHR || Opc == TargetOpcode::G_LSHR);
507 unsigned NewOpc =
508 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
509 MachineIRBuilder MIB(MI);
510 MIB.buildInstr(NewOpc, {MI.getOperand(0)}, {MI.getOperand(1)}).addImm(Imm);
511 MI.eraseFromParent();
512}
513
514/// Determine whether an integer G_ICMP against 1 or -1 can compare
515/// against 0 instead.
516///
517/// AArch64 can fold a compare-with-zero more cheaply than some non-arithmetic
518/// immediates (SUBS/ADDS, or TST when the LHS is an AND). When the predicate
519/// can be adjusted without changing semantics, the RHS may become 0.
520///
521/// Supported transforms (signed predicates only):
522/// (and X, Y) slt 1 => (and X, Y) sle 0
523/// (and X, Y) sge 1 => (and X, Y) sgt 0
524/// X sle -1 => X slt 0
525/// X sgt -1 => X sge 0
526///
527/// The compare-against-1 cases require the LHS to be G_AND because the
528/// compare-with-zero path enables ANDS (TST) selection, and ANDS flags are
529/// only reliable for those signed comparisons. This mirrors SelectionDAG
530/// emitComparison().
531///
532/// For compare-against--1 on a non-AND LHS, \p LHS must have a single
533/// non-debug use so other users are not left with a different immediate.
534///
535/// \param LHS The compare LHS register.
536/// \param C The constant RHS (only 1 or all-ones are considered).
537/// \param P In/out predicate; updated when a transform applies.
538/// \param MRI Used to inspect the LHS definition and use count.
539/// \returns true if \p P was updated and comparing against 0 is equivalent.
540static bool shouldBeAdjustedToZero(Register LHS, const APInt &C,
542 const MachineRegisterInfo &MRI) {
543 const bool IsAndLHS = getOpcodeDef<GAnd>(LHS, MRI) != nullptr;
544
545 if (C.isOne() && (P == CmpInst::ICMP_SLT || P == CmpInst::ICMP_SGE) &&
546 IsAndLHS) {
548 return true;
549 }
550
551 if (!IsAndLHS && !MRI.hasOneNonDBGUse(LHS))
552 return false;
553
554 if (C.isAllOnes() && (P == CmpInst::ICMP_SLE || P == CmpInst::ICMP_SGT)) {
556 return true;
557 }
558 return false;
559}
560
561/// Determine if it is possible to modify the \p RHS and predicate \p P of a
562/// G_ICMP instruction such that the right-hand side is an arithmetic immediate.
563///
564/// \returns A pair containing the updated immediate and predicate which may
565/// be used to optimize the instruction.
566///
567/// \note This assumes that the comparison has been legalized.
568std::optional<std::pair<uint64_t, CmpInst::Predicate>>
569tryAdjustICmpImmAndPred(Register LHS, Register RHS, CmpInst::Predicate P,
570 const MachineRegisterInfo &MRI) {
571 const auto &Ty = MRI.getType(RHS);
572 if (Ty.isVector())
573 return std::nullopt;
574 assert((Ty.getSizeInBits() == 32 || Ty.getSizeInBits() == 64) &&
575 "Expected 32 or 64 bit compare only?");
576
577 // If the RHS is not a constant, or the RHS is already a valid arithmetic
578 // immediate, then there is nothing to change.
579 auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS, MRI);
580 if (!ValAndVReg)
581 return std::nullopt;
582 APInt C = ValAndVReg->Value;
583 if (shouldBeAdjustedToZero(LHS, C, P, MRI))
584 return {{0, P}};
585
587 return std::nullopt;
588
589 uint64_t OriginalC = C.getZExtValue();
590
591 // We have a non-arithmetic immediate. Check if adjusting the immediate and
592 // adjusting the predicate will result in a legal arithmetic immediate.
593 switch (P) {
594 default:
595 return std::nullopt;
598 // Check for
599 //
600 // x slt c => x sle c - 1
601 // x sge c => x sgt c - 1
602 //
603 // When c is not the smallest possible negative number.
604 if (C.isMinSignedValue())
605 return std::nullopt;
607 C = C - 1;
608 break;
611 // Check for
612 //
613 // x ult c => x ule c - 1
614 // x uge c => x ugt c - 1
615 //
616 // When c is not zero.
617 assert(!C.isZero() && "C should not be zero here!");
619 C = C - 1;
620 break;
623 // Check for
624 //
625 // x sle c => x slt c + 1
626 // x sgt c => s sge c + 1
627 //
628 // When c is not the largest possible signed integer.
629 if (C.isMaxSignedValue())
630 return std::nullopt;
632 C = C + 1;
633 break;
636 // Check for
637 //
638 // x ule c => x ult c + 1
639 // x ugt c => s uge c + 1
640 //
641 // When c is not the largest possible unsigned integer.
642 if (C.isAllOnes())
643 return std::nullopt;
645 C = C + 1;
646 break;
647 }
648
649 // Check if the new constant is valid, and return the updated constant and
650 // predicate if it is.
651 uint64_t NewC = C.getZExtValue();
653 return {{NewC, P}};
654
655 auto NumberOfInstrToLoadImm = [=](uint64_t Imm) {
658 return Insn.size();
659 };
660
661 if (NumberOfInstrToLoadImm(OriginalC) > NumberOfInstrToLoadImm(NewC))
662 return {{NewC, P}};
663
664 return std::nullopt;
665}
666
667/// Determine whether or not it is possible to update the RHS and predicate of
668/// a G_ICMP instruction such that the RHS will be selected as an arithmetic
669/// immediate.
670///
671/// \p MI - The G_ICMP instruction
672/// \p MatchInfo - The new RHS immediate and predicate on success
673///
674/// See tryAdjustICmpImmAndPred for valid transformations.
675bool matchAdjustICmpImmAndPred(
677 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
678 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
679 Register LHS = MI.getOperand(2).getReg();
680 Register RHS = MI.getOperand(3).getReg();
681 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
682 if (auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(LHS, RHS, Pred, MRI)) {
683 MatchInfo = *MaybeNewImmAndPred;
684 return true;
685 }
686 return false;
687}
688
689void applyAdjustICmpImmAndPred(
690 MachineInstr &MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
691 MachineIRBuilder &MIB, GISelChangeObserver &Observer) {
693 MachineOperand &RHS = MI.getOperand(3);
694 MachineRegisterInfo &MRI = *MIB.getMRI();
695 auto Cst = MIB.buildConstant(MRI.cloneVirtualRegister(RHS.getReg()),
696 MatchInfo.first);
697 Observer.changingInstr(MI);
698 RHS.setReg(Cst->getOperand(0).getReg());
699 MI.getOperand(1).setPredicate(MatchInfo.second);
700 Observer.changedInstr(MI);
701}
702
703bool matchDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
704 std::pair<unsigned, int> &MatchInfo) {
705 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
706 Register Src1Reg = MI.getOperand(1).getReg();
707 const LLT SrcTy = MRI.getType(Src1Reg);
708 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
709
710 auto LaneIdx = getSplatIndex(MI);
711 if (!LaneIdx)
712 return false;
713
714 // The lane idx should be within the first source vector.
715 if (*LaneIdx >= SrcTy.getNumElements())
716 return false;
717
718 if (DstTy != SrcTy)
719 return false;
720
721 LLT ScalarTy = SrcTy.getElementType();
722 unsigned ScalarSize = ScalarTy.getSizeInBits();
723
724 unsigned Opc = 0;
725 switch (SrcTy.getNumElements()) {
726 case 2:
727 if (ScalarSize == 64)
728 Opc = AArch64::G_DUPLANE64;
729 else if (ScalarSize == 32)
730 Opc = AArch64::G_DUPLANE32;
731 break;
732 case 4:
733 if (ScalarSize == 32)
734 Opc = AArch64::G_DUPLANE32;
735 else if (ScalarSize == 16)
736 Opc = AArch64::G_DUPLANE16;
737 break;
738 case 8:
739 if (ScalarSize == 8)
740 Opc = AArch64::G_DUPLANE8;
741 else if (ScalarSize == 16)
742 Opc = AArch64::G_DUPLANE16;
743 break;
744 case 16:
745 if (ScalarSize == 8)
746 Opc = AArch64::G_DUPLANE8;
747 break;
748 default:
749 break;
750 }
751 if (!Opc)
752 return false;
753
754 MatchInfo.first = Opc;
755 MatchInfo.second = *LaneIdx;
756 return true;
757}
758
759void applyDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
760 MachineIRBuilder &B, std::pair<unsigned, int> &MatchInfo) {
761 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
762 Register Src1Reg = MI.getOperand(1).getReg();
763 const LLT SrcTy = MRI.getType(Src1Reg);
764
765 B.setInstrAndDebugLoc(MI);
766 auto Lane = B.buildConstant(LLT::integer(64), MatchInfo.second);
767
768 Register DupSrc = MI.getOperand(1).getReg();
769 // For types like <2 x s32>, we can use G_DUPLANE32, with a <4 x s32> source.
770 // To do this, we can use a G_CONCAT_VECTORS to do the widening.
771 if (SrcTy.getSizeInBits() == 64) {
772 auto Undef = B.buildUndef(SrcTy);
773 DupSrc = B.buildConcatVectors(SrcTy.multiplyElements(2),
774 {Src1Reg, Undef.getReg(0)})
775 .getReg(0);
776 }
777 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
778 MI.eraseFromParent();
779}
780
781bool matchScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI) {
782 auto &Unmerge = cast<GUnmerge>(MI);
783 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
784 const LLT SrcTy = MRI.getType(Src1Reg);
785 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
786 return false;
787 return SrcTy.isVector() && !SrcTy.isScalable() &&
788 (Unmerge.getNumOperands() == (unsigned)SrcTy.getNumElements() + 1 ||
789 (Unmerge.getNumDefs() == 2 && SrcTy.getSizeInBits() == 128 &&
790 MRI.getType(Unmerge.getReg(0)).getSizeInBits() == 64));
791}
792
793void applyScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
795 auto &Unmerge = cast<GUnmerge>(MI);
796 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
797 const LLT SrcTy = MRI.getType(Src1Reg);
798 const LLT DstTy = MRI.getType(Unmerge.getReg(0));
799 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
800 "Expected a fixed length vector");
801
802 if (DstTy.isVector()) {
803 assert(Unmerge.getNumDefs() == 2);
804 if (!MRI.use_nodbg_empty(Unmerge.getReg(0)))
805 B.buildExtractSubvector(Unmerge.getReg(0), Src1Reg, 0);
806 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
807 B.buildExtractSubvector(Unmerge.getReg(1), Src1Reg,
808 SrcTy.getNumElements() / 2);
809 } else {
810 for (int I = 0; I < SrcTy.getNumElements(); ++I)
811 if (!MRI.use_nodbg_empty(Unmerge.getReg(I)))
812 B.buildExtractVectorElementConstant(Unmerge.getReg(I), Src1Reg, I);
813 }
814 MI.eraseFromParent();
815}
816
817bool matchBuildVectorToDup(MachineInstr &MI, Register &Src,
818 MachineRegisterInfo &MRI) {
819 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
820
821 // Later, during selection, we'll try to match imported patterns using
822 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
823 // G_BUILD_VECTORs which could match those patterns.
825 return false;
826
827 // Find buildvector which always uses the same register or undef. Return true
828 // so long as at least 2 registers were found (not all-undef or only 1
829 // non-undef entry).
830 Register Reg = 0;
831 unsigned NumNonUndef = 0;
832 for (const MachineOperand &Op : drop_begin(MI.operands())) {
833 if (getOpcodeDef<GImplicitDef>(Op.getReg(), MRI))
834 continue;
835
836 if (!Reg)
837 Reg = Op.getReg();
838 else if (Op.getReg() != Reg)
839 return false;
840 NumNonUndef++;
841 }
842
843 Src = Reg;
844 return Reg && NumNonUndef > 1;
845}
846
847void applyBuildVectorToDup(MachineInstr &MI, Register Src,
849 B.setInstrAndDebugLoc(MI);
850 B.buildInstr(AArch64::G_DUP, {MI.getOperand(0).getReg()}, {Src});
851 MI.eraseFromParent();
852}
853
854/// \returns how many instructions would be saved by folding a G_ICMP's shift
855/// and/or extension operations.
856static unsigned getCmpOperandFoldingProfit(Register CmpOp,
857 MachineRegisterInfo &MRI) {
858 // FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
859 auto IsSupportedExtend = [&](const MachineInstr &MI) {
860 if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
861 return true;
862 if (MI.getOpcode() == TargetOpcode::G_AND) {
863 auto ValAndVReg =
864 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
865 if (ValAndVReg) {
866 uint64_t Mask = ValAndVReg->Value.getZExtValue();
867 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
868 }
869 }
870 return false;
871 };
872
873 // No instructions to save if there's more than one use or no uses.
874 if (!MRI.hasOneNonDBGUse(CmpOp))
875 return 0;
876
877 MachineInstr *Def = getDefIgnoringCopies(CmpOp, MRI);
878 if (IsSupportedExtend(*Def))
879 return 1;
880
881 unsigned Opc = Def->getOpcode();
882 if (Opc == TargetOpcode::G_SHL || Opc == TargetOpcode::G_LSHR ||
883 Opc == TargetOpcode::G_ASHR) {
884 auto MaybeShiftAmt =
885 getIConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
886 if (MaybeShiftAmt) {
887 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
888 MachineInstr *ShiftLHS =
889 getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
890 if (IsSupportedExtend(*ShiftLHS))
891 return (ShiftAmt <= 4) ? 2 : 1;
892 LLT Ty = MRI.getType(Def->getOperand(0).getReg());
893 if (Ty.isVector())
894 return 0;
895 unsigned ShiftSize = Ty.getSizeInBits();
896 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
897 (ShiftSize == 64 && ShiftAmt <= 63))
898 return 1;
899 }
900 }
901
902 return 0;
903}
904
905/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
906/// instruction \p MI.
907bool trySwapICmpOperands(MachineInstr &MI, MachineRegisterInfo &MRI) {
908 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
909 // Swap the operands if it would introduce a profitable folding opportunity.
910 // (e.g. a shift + extend).
911 //
912 // For example:
913 // lsl w13, w11, #1
914 // cmp w13, w12
915 // can be turned into:
916 // cmp w12, w11, lsl #1
917
918 // Don't swap if there's a constant on the RHS and it is a legal compare
919 // immediate, because we know we can fold that.
920 Register RHS = MI.getOperand(3).getReg();
921 auto RHSCst = getIConstantVRegValWithLookThrough(RHS, MRI);
922 if (RHSCst && AArch64_AM::isLegalCmpImmed(RHSCst->Value))
923 return false;
924
925 Register LHS = MI.getOperand(2).getReg();
926 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
927 auto GetRegForProfit = [&](Register Reg) {
929 return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
930 };
931
932 // Don't have a constant on the RHS. If we swap the LHS and RHS of the
933 // compare, would we be able to fold more instructions?
934 Register TheLHS = GetRegForProfit(LHS);
935 Register TheRHS = GetRegForProfit(RHS);
936
937 // If the LHS is more likely to give us a folding opportunity, then swap the
938 // LHS and RHS.
939 return (getCmpOperandFoldingProfit(TheLHS, MRI) >
940 getCmpOperandFoldingProfit(TheRHS, MRI));
941}
942
943void applySwapICmpOperands(MachineInstr &MI, GISelChangeObserver &Observer) {
944 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
945 Register LHS = MI.getOperand(2).getReg();
946 Register RHS = MI.getOperand(3).getReg();
947 Observer.changingInstr(MI);
948 MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
949 MI.getOperand(2).setReg(RHS);
950 MI.getOperand(3).setReg(LHS);
951 Observer.changedInstr(MI);
952}
953
954/// \returns a function which builds a vector floating point compare instruction
955/// for a condition code \p CC.
956/// \param [in] NoNans - True if the instruction has nnan flag.
957std::function<Register(MachineIRBuilder &)>
958getVectorFCMP(AArch64CC::CondCode CC, Register LHS, Register RHS, bool NoNans,
959 MachineRegisterInfo &MRI) {
960 LLT OldTy = MRI.getType(LHS);
961 LLT DstTy = LLT::fixed_vector(OldTy.getNumElements(),
963 assert(DstTy.isVector() && "Expected vector types only?");
964 switch (CC) {
965 default:
966 llvm_unreachable("Unexpected condition code!");
967 case AArch64CC::NE:
968 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
969 auto FCmp = MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS});
970 return MIB.buildNot(DstTy, FCmp).getReg(0);
971 };
972 case AArch64CC::EQ:
973 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
974 return MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS}).getReg(0);
975 };
976 case AArch64CC::GE:
977 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
978 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {LHS, RHS}).getReg(0);
979 };
980 case AArch64CC::GT:
981 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
982 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {LHS, RHS}).getReg(0);
983 };
984 case AArch64CC::LS:
985 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
986 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {RHS, LHS}).getReg(0);
987 };
988 case AArch64CC::MI:
989 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
990 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {RHS, LHS}).getReg(0);
991 };
992 }
993}
994
995/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
996bool matchLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
997 MachineIRBuilder &MIB) {
998 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
999 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
1000
1001 Register Dst = MI.getOperand(0).getReg();
1002 LLT DstTy = MRI.getType(Dst);
1003 if (!DstTy.isVector() || !ST.hasNEON())
1004 return false;
1005 Register LHS = MI.getOperand(2).getReg();
1006 unsigned EltSize = MRI.getType(LHS).getScalarSizeInBits();
1007 if (EltSize == 16 && !ST.hasFullFP16())
1008 return false;
1009 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
1010 return false;
1011
1012 return true;
1013}
1014
1015/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1016void applyLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1017 MachineIRBuilder &MIB) {
1018 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1019
1020 const auto &CmpMI = cast<GFCmp>(MI);
1021
1022 Register Dst = CmpMI.getReg(0);
1023 CmpInst::Predicate Pred = CmpMI.getCond();
1024 Register LHS = CmpMI.getLHSReg();
1025 Register RHS = CmpMI.getRHSReg();
1026
1027 LLT DstTy = MRI.getType(Dst);
1028
1029 bool Invert = false;
1031 if ((Pred == CmpInst::Predicate::FCMP_ORD ||
1033 isBuildVectorAllZeros(*MRI.getVRegDef(RHS), MRI)) {
1034 // The special case "fcmp ord %a, 0" is the canonical check that LHS isn't
1035 // NaN, so equivalent to a == a and doesn't need the two comparisons an
1036 // "ord" normally would.
1037 // Similarly, "fcmp uno %a, 0" is the canonical check that LHS is NaN and is
1038 // thus equivalent to a != a.
1039 RHS = LHS;
1041 } else
1042 changeVectorFCMPPredToAArch64CC(Pred, CC, CC2, Invert);
1043
1044 // Instead of having an apply function, just build here to simplify things.
1046
1047 // TODO: Also consider GISelValueTracking result if eligible.
1048 const bool NoNans = MI.getFlag(MachineInstr::FmNoNans);
1049
1050 auto Cmp = getVectorFCMP(CC, LHS, RHS, NoNans, MRI);
1051 Register CmpRes;
1052 if (CC2 == AArch64CC::AL)
1053 CmpRes = Cmp(MIB);
1054 else {
1055 auto Cmp2 = getVectorFCMP(CC2, LHS, RHS, NoNans, MRI);
1056 auto Cmp2Dst = Cmp2(MIB);
1057 auto Cmp1Dst = Cmp(MIB);
1058 CmpRes = MIB.buildOr(DstTy, Cmp1Dst, Cmp2Dst).getReg(0);
1059 }
1060 if (Invert)
1061 CmpRes = MIB.buildNot(DstTy, CmpRes).getReg(0);
1062 MRI.replaceRegWith(Dst, CmpRes);
1063 MI.eraseFromParent();
1064}
1065
1066// Matches G_BUILD_VECTOR where at least one source operand is not a constant
1067bool matchLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI) {
1068 auto *GBuildVec = cast<GBuildVector>(&MI);
1069
1070 // Check if the values are all constants
1071 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1072 auto ConstVal =
1073 getAnyConstantVRegValWithLookThrough(GBuildVec->getSourceReg(I), MRI);
1074
1075 if (!ConstVal.has_value())
1076 return true;
1077 }
1078
1079 return false;
1080}
1081
1082void applyLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI,
1084 auto *GBuildVec = cast<GBuildVector>(&MI);
1085 LLT DstTy = MRI.getType(GBuildVec->getReg(0));
1086 Register DstReg = B.buildUndef(DstTy).getReg(0);
1087
1088 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1089 Register SrcReg = GBuildVec->getSourceReg(I);
1090 if (mi_match(SrcReg, MRI, m_GImplicitDef()))
1091 continue;
1092 auto IdxReg = B.buildConstant(LLT::integer(64), I);
1093 DstReg =
1094 B.buildInsertVectorElement(DstTy, DstReg, SrcReg, IdxReg).getReg(0);
1095 }
1096 B.buildCopy(GBuildVec->getReg(0), DstReg);
1097 GBuildVec->eraseFromParent();
1098}
1099
1100bool matchFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1101 Register &SrcReg) {
1102 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1103 Register DstReg = MI.getOperand(0).getReg();
1104 if (cast<GLoadStore>(MI).isAtomic())
1105 return false;
1106 if (MRI.getType(DstReg).isVector())
1107 return false;
1108 // Match a store of a truncate.
1109 if (!mi_match(DstReg, MRI, m_GTrunc(m_Reg(SrcReg))))
1110 return false;
1111 // Only form truncstores for value types of max 64b.
1112 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1113}
1114
1115void applyFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1117 Register &SrcReg) {
1118 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1119 Observer.changingInstr(MI);
1120 MI.getOperand(0).setReg(SrcReg);
1121 Observer.changedInstr(MI);
1122}
1123
1124// Lower vector G_SEXT_INREG back to shifts for selection. We allowed them to
1125// form in the first place for combine opportunities, so any remaining ones
1126// at this stage need be lowered back.
1127bool matchVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI) {
1128 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1129 Register DstReg = MI.getOperand(0).getReg();
1130 LLT DstTy = MRI.getType(DstReg);
1131 return DstTy.isVector();
1132}
1133
1134void applyVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI,
1136 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1137 B.setInstrAndDebugLoc(MI);
1138 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1139 Helper.lower(MI, 0, /* Unused hint type */ LLT());
1140}
1141
1142/// Combine <N x t>, unused = unmerge(G_EXT <2*N x t> v, undef, N)
1143/// => unused, <N x t> = unmerge v
1144bool matchUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1145 Register &MatchInfo) {
1146 auto &Unmerge = cast<GUnmerge>(MI);
1147 if (Unmerge.getNumDefs() != 2)
1148 return false;
1149 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
1150 return false;
1151
1152 LLT DstTy = MRI.getType(Unmerge.getReg(0));
1153 if (!DstTy.isVector())
1154 return false;
1155
1156 MachineInstr *Ext = getOpcodeDef(AArch64::G_EXT, Unmerge.getSourceReg(), MRI);
1157 if (!Ext)
1158 return false;
1159
1160 Register ExtSrc1 = Ext->getOperand(1).getReg();
1161 Register ExtSrc2 = Ext->getOperand(2).getReg();
1162 auto LowestVal =
1164 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.getSizeInBytes())
1165 return false;
1166
1167 if (!getOpcodeDef<GImplicitDef>(ExtSrc2, MRI))
1168 return false;
1169
1170 MatchInfo = ExtSrc1;
1171 return true;
1172}
1173
1174void applyUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1176 GISelChangeObserver &Observer, Register &SrcReg) {
1177 Observer.changingInstr(MI);
1178 // Swap dst registers.
1179 Register Dst1 = MI.getOperand(0).getReg();
1180 MI.getOperand(0).setReg(MI.getOperand(1).getReg());
1181 MI.getOperand(1).setReg(Dst1);
1182 MI.getOperand(2).setReg(SrcReg);
1183 Observer.changedInstr(MI);
1184}
1185
1186// Match mul({z/s}ext , {z/s}ext) => {u/s}mull OR
1187// Match v2s64 mul instructions, which will then be scalarised later on
1188// Doing these two matches in one function to ensure that the order of matching
1189// will always be the same.
1190// Try lowering MUL to MULL before trying to scalarize if needed.
1191bool matchMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI) {
1192 // Get the instructions that defined the source operand
1193 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1194 return DstTy == LLT::fixed_vector(2, 64);
1195}
1196
1197void applyMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI,
1199 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
1200 "Expected a G_MUL instruction");
1201
1202 // Get the instructions that defined the source operand
1203 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1204 assert(DstTy == LLT::fixed_vector(2, 64) && "Expected v2s64 Mul");
1205 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1206 Helper.fewerElementsVector(
1207 MI, 0,
1209}
1210
1211class AArch64PostLegalizerLoweringImpl : public Combiner {
1212protected:
1213 const CombinerHelper Helper;
1214 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1215 const AArch64Subtarget &STI;
1216
1217public:
1218 AArch64PostLegalizerLoweringImpl(
1219 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1220 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1221 const AArch64Subtarget &STI);
1222
1223 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
1224
1225 bool tryCombineAll(MachineInstr &I) const override;
1226
1227private:
1228#define GET_GICOMBINER_CLASS_MEMBERS
1229#include "AArch64GenPostLegalizeGILowering.inc"
1230#undef GET_GICOMBINER_CLASS_MEMBERS
1231};
1232
1233#define GET_GICOMBINER_IMPL
1234#include "AArch64GenPostLegalizeGILowering.inc"
1235#undef GET_GICOMBINER_IMPL
1236
1237AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1238 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1239 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1240 const AArch64Subtarget &STI)
1241 : Combiner(MF, CInfo, /*VT*/ nullptr, CSEInfo),
1242 Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
1243 STI(STI),
1245#include "AArch64GenPostLegalizeGILowering.inc"
1247{
1248}
1249
1250bool runPostLegalizerLowering(
1251 MachineFunction &MF,
1252 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig) {
1253 if (MF.getProperties().hasFailedISel())
1254 return false;
1255 const Function &F = MF.getFunction();
1256
1258 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
1259 /*LegalizerInfo=*/nullptr, /*OptEnabled=*/true,
1260 F.hasOptSize(), F.hasMinSize());
1261 // Disable fixed-point iteration to reduce compile-time
1262 CInfo.MaxIterations = 1;
1263 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
1264 // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
1265 CInfo.EnableFullDCE = false;
1266 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo, /*CSEInfo=*/nullptr,
1267 RuleConfig, ST);
1268 return Impl.combineMachineInstrs();
1269}
1270
1271class AArch64PostLegalizerLoweringLegacy : public MachineFunctionPass {
1272public:
1273 static char ID;
1274
1275 AArch64PostLegalizerLoweringLegacy();
1276
1277 StringRef getPassName() const override {
1278 return "AArch64PostLegalizerLowering";
1279 }
1280
1281 bool runOnMachineFunction(MachineFunction &MF) override;
1282 void getAnalysisUsage(AnalysisUsage &AU) const override;
1283
1284private:
1285 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1286};
1287} // end anonymous namespace
1288
1289void AArch64PostLegalizerLoweringLegacy::getAnalysisUsage(
1290 AnalysisUsage &AU) const {
1291 AU.setPreservesCFG();
1294}
1295
1296AArch64PostLegalizerLoweringLegacy::AArch64PostLegalizerLoweringLegacy()
1297 : MachineFunctionPass(ID) {
1298 if (!RuleConfig.parseCommandLineOption())
1299 report_fatal_error("Invalid rule identifier");
1300}
1301
1302bool AArch64PostLegalizerLoweringLegacy::runOnMachineFunction(
1303 MachineFunction &MF) {
1304 assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
1305 return runPostLegalizerLowering(MF, RuleConfig);
1306}
1307
1308char AArch64PostLegalizerLoweringLegacy::ID = 0;
1309INITIALIZE_PASS_BEGIN(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1310 "Lower AArch64 MachineInstrs after legalization", false,
1311 false)
1312INITIALIZE_PASS_END(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1313 "Lower AArch64 MachineInstrs after legalization", false,
1314 false)
1315
1317 : RuleConfig(
1318 std::make_unique<AArch64PostLegalizerLoweringImplRuleConfig>()) {
1319 if (!RuleConfig->parseCommandLineOption())
1320 reportFatalUsageError("invalid rule identifier");
1321}
1322
1325
1327
1331 MFPropsModifier _(*this, MF);
1332 const bool Changed = runPostLegalizerLowering(MF, *RuleConfig);
1333
1334 if (!Changed)
1335 return PreservedAnalyses::all();
1336
1339 return PA;
1340}
1341
1342namespace llvm {
1344 return new AArch64PostLegalizerLoweringLegacy();
1345}
1346} // 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
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 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)
Class for arbitrary precision integers.
Definition APInt.h:78
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.
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
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)
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
static bool isLegalCmpImmed(const APInt &C)
isLegalCmpImmed -
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,...
@ 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...
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 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.