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