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
310 !isSingletonEXTMask(Mask, DstTy.getNumElements(), Imm))
311 return false;
312
313 Imm = Mask[0] * ExtFactor;
314 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst,
315 {V1, V1, static_cast<uint64_t>(Imm)});
316 return true;
317}
318
319/// Replace a G_SHUFFLE_VECTOR instruction with a pseudo.
320/// \p Opc is the opcode to use. \p MI is the G_SHUFFLE_VECTOR.
321void applyShuffleVectorPseudo(MachineInstr &MI, MachineRegisterInfo &MRI,
322 ShuffleVectorPseudo &MatchInfo) {
323 MachineIRBuilder MIRBuilder(MI);
324 if (MatchInfo.Opc == TargetOpcode::G_BSWAP) {
325 assert(MatchInfo.SrcOps.size() == 1);
326 LLT DstTy = MRI.getType(MatchInfo.Dst);
327 assert(DstTy == LLT::fixed_vector(8, 8) ||
328 DstTy == LLT::fixed_vector(16, 8));
329 LLT BSTy = DstTy == LLT::fixed_vector(8, 8)
332 // FIXME: NVCAST
333 auto BS1 = MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {BSTy},
334 MatchInfo.SrcOps[0]);
335 auto BS2 = MIRBuilder.buildInstr(MatchInfo.Opc, {BSTy}, {BS1});
336 MIRBuilder.buildInstr(TargetOpcode::G_BITCAST, {MatchInfo.Dst}, {BS2});
337 } else
338 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
339 MI.eraseFromParent();
340}
341
342/// Replace a G_SHUFFLE_VECTOR instruction with G_EXT.
343/// Special-cased because the constant operand must be emitted as a G_CONSTANT
344/// for the imported tablegen patterns to work.
345void applyEXT(MachineInstr &MI, ShuffleVectorPseudo &MatchInfo) {
346 MachineIRBuilder MIRBuilder(MI);
347 if (MatchInfo.SrcOps[2].getImm() == 0)
348 MIRBuilder.buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
349 else {
350 // Tablegen patterns expect an i32 G_CONSTANT as the final op.
351 auto Cst = MIRBuilder.buildConstant(LLT::integer(32),
352 MatchInfo.SrcOps[2].getImm());
353 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
354 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
355 }
356 MI.eraseFromParent();
357}
358
359static bool preferTBLToMultiInstrShuffle(MachineBasicBlock *MBB) {
360 if (MBB->getParent()->getFunction().hasOptSize())
361 return false;
362 // Look for a simple single block loop.
363 return is_contained(successors(MBB), MBB);
364}
365
366bool matchFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
367 if (preferTBLToMultiInstrShuffle(MI.getParent()))
368 return false;
369
370 auto &Shuf = cast<GShuffleVector>(MI);
371 ArrayRef<int> Mask = Shuf.getMask();
372 return mi_match(Shuf.getSrc2Reg(), MRI, m_GImplicitDef()) &&
373 ShuffleVectorInst::isReverseMask(Mask, Mask.size());
374}
375
376void applyFullRev(MachineInstr &MI, MachineRegisterInfo &MRI) {
377 Register Dst = MI.getOperand(0).getReg();
378 Register Src = MI.getOperand(1).getReg();
379 LLT DstTy = MRI.getType(Dst);
380 assert(DstTy.getSizeInBits() == 128 &&
381 "Expected 128bit vector in applyFullRev");
382 MachineIRBuilder MIRBuilder(MI);
383 auto Cst = MIRBuilder.buildConstant(LLT::integer(32), 8);
384 auto Rev = MIRBuilder.buildInstr(AArch64::G_REV64, {DstTy}, {Src});
385 MIRBuilder.buildInstr(AArch64::G_EXT, {Dst}, {Rev, Rev, Cst});
386 MI.eraseFromParent();
387}
388
389bool matchNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI) {
390 assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
391
392 auto ValAndVReg =
393 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
394 return !ValAndVReg;
395}
396
397void applyNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI,
398 MachineIRBuilder &Builder) {
399 auto &Insert = cast<GInsertVectorElement>(MI);
400 Builder.setInstrAndDebugLoc(Insert);
401
402 Register Offset = Insert.getIndexReg();
403 LLT VecTy = MRI.getType(Insert.getReg(0));
404 LLT EltTy = MRI.getType(Insert.getElementReg());
405 LLT IdxTy = MRI.getType(Insert.getIndexReg());
406
407 if (VecTy.isScalableVector())
408 return;
409
410 // Create a stack slot and store the vector into it
411 MachineFunction &MF = Builder.getMF();
412 Align Alignment(
413 std::min<uint64_t>(VecTy.getSizeInBytes().getKnownMinValue(), 16));
414 int FrameIdx = MF.getFrameInfo().CreateStackObject(VecTy.getSizeInBytes(),
415 Alignment, false);
416 LLT FramePtrTy = LLT::pointer(0, 64);
418 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
419
420 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo, Align(8));
421
422 // Get the pointer to the element, and be sure not to hit undefined behavior
423 // if the index is out of bounds.
425 "Expected a power-2 vector size");
426 auto Mask = Builder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
427 Register And = Builder.buildAnd(IdxTy, Offset, Mask).getReg(0);
428 auto EltSize = Builder.buildConstant(IdxTy, EltTy.getSizeInBytes());
429 Register Mul = Builder.buildMul(IdxTy, And, EltSize).getReg(0);
430 Register EltPtr =
431 Builder.buildPtrAdd(MRI.getType(StackTemp.getReg(0)), StackTemp, Mul)
432 .getReg(0);
433
434 // Write the inserted element
435 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo, Align(1));
436 // Reload the whole vector.
437 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo, Align(8));
438 Insert.eraseFromParent();
439}
440
441/// Match a G_SHUFFLE_VECTOR with a mask which corresponds to a
442/// G_INSERT_VECTOR_ELT and G_EXTRACT_VECTOR_ELT pair.
443///
444/// e.g.
445/// %shuf = G_SHUFFLE_VECTOR %left, %right, shufflemask(0, 0)
446///
447/// Can be represented as
448///
449/// %extract = G_EXTRACT_VECTOR_ELT %left, 0
450/// %ins = G_INSERT_VECTOR_ELT %left, %extract, 1
451///
452bool matchINS(MachineInstr &MI, MachineRegisterInfo &MRI,
453 std::tuple<Register, int, Register, int> &MatchInfo) {
454 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
455 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
456 Register Dst = MI.getOperand(0).getReg();
457 int NumElts = MRI.getType(Dst).getNumElements();
458 auto DstIsLeftAndDstLane = isINSMask(ShuffleMask, NumElts);
459 if (!DstIsLeftAndDstLane)
460 return false;
461 bool DstIsLeft;
462 int DstLane;
463 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
464 Register Left = MI.getOperand(1).getReg();
465 Register Right = MI.getOperand(2).getReg();
466 Register DstVec = DstIsLeft ? Left : Right;
467 Register SrcVec = Left;
468
469 int SrcLane = ShuffleMask[DstLane];
470 if (SrcLane >= NumElts) {
471 SrcVec = Right;
472 SrcLane -= NumElts;
473 }
474
475 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
476 return true;
477}
478
479void applyINS(MachineInstr &MI, MachineRegisterInfo &MRI,
480 MachineIRBuilder &Builder,
481 std::tuple<Register, int, Register, int> &MatchInfo) {
482 Builder.setInstrAndDebugLoc(MI);
483 Register Dst = MI.getOperand(0).getReg();
484 auto ScalarTy = MRI.getType(Dst).getElementType();
485 Register DstVec, SrcVec;
486 int DstLane, SrcLane;
487 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
488 auto SrcCst = Builder.buildConstant(LLT::integer(64), SrcLane);
489 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
490 auto DstCst = Builder.buildConstant(LLT::integer(64), DstLane);
491 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
492 MI.eraseFromParent();
493}
494
495/// Match perfect shuffle entries
496bool matchPerfectShuffle(MachineInstr &MI, MachineRegisterInfo &MRI,
497 SmallVector<ShuffleEntry> &Entries) {
498 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
499 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
500 assert(Ty.getSizeInBits() == 64 || Ty.getSizeInBits() == 128);
501 if (Ty.getNumElements() != 4)
502 return false;
503 if (!generatePerfectShuffle(MI.getOperand(3).getShuffleMask(), 4, Entries))
504 return false;
505 return Entries.size() == 1 || !preferTBLToMultiInstrShuffle(MI.getParent());
506}
507
508void applyPerfectShuffle(MachineInstr &MI, MachineRegisterInfo &MRI,
509 MachineIRBuilder &MIB,
510 SmallVector<ShuffleEntry> &Entries) {
512 auto getValue = [](unsigned Idx, Register LHS, Register RHS,
513 SmallVector<Register> &Vals) {
514 if (Idx == ShuffleEntry::LHS)
515 return LHS;
516 if (Idx == ShuffleEntry::RHS)
517 return RHS;
518 assert(Idx < Vals.size());
519 return Vals[Idx];
520 };
521
522 Register V1 = MI.getOperand(1).getReg();
523 Register V2 = MI.getOperand(2).getReg();
524 LLT VT = MRI.getType(MI.getOperand(0).getReg());
525
526 for (const ShuffleEntry &Entry : Entries) {
527 Register OpLHS = getValue(Entry.LHSID, V1, V2, Vals);
528
529 switch (Entry.Op) {
532 llvm_unreachable("Did not expect a OP_COPY or OP_MOVLANE");
534 unsigned ExtLane = (Entry.RHSID >> 8) & 0xff;
535 unsigned ToLane = Entry.RHSID & 0xff;
536 bool Input2 = Entry.RHSID >> 16;
537
538 Register Input = Input2 ? V2 : V1;
539 assert(
540 (VT.getScalarSizeInBits() == 16 || VT.getScalarSizeInBits() == 32) &&
541 "Expected 16 or 32 bit shuffle elements");
542 LLT ExtTy = VT.getScalarSizeInBits() == 16
545
546 Input = MIB.buildBitcast(ExtTy, Input).getReg(0);
547 OpLHS = MIB.buildBitcast(ExtTy, OpLHS).getReg(0);
549 Input, ExtLane);
550 auto Ins = MIB.buildInsertVectorElement(
551 ExtTy, OpLHS, Ext, MIB.buildConstant(LLT::integer(64), ToLane));
552 Vals.push_back(MIB.buildBitcast(VT, Ins).getReg(0));
553 break;
554 }
556 unsigned ExtLane = (Entry.RHSID >> 8) & 0xff;
557 unsigned ToLane = Entry.RHSID & 0xff;
558 bool Input2 = Entry.RHSID >> 16;
559
560 Register Input = Input2 ? V2 : V1;
562 Input, ExtLane);
563 Vals.push_back(
565 VT, OpLHS, Ext, MIB.buildConstant(LLT::integer(64), ToLane))
566 .getReg(0));
567 break;
568 }
570 // VREV divides the vector in half and swaps within the half.
571 assert(VT.getScalarSizeInBits() == 32 || VT.getScalarSizeInBits() == 16);
572 if (VT.getScalarSizeInBits() == 32) {
573 Vals.push_back(
574 MIB.buildInstr(AArch64::G_REV64, {VT}, {OpLHS}).getReg(0));
575 } else {
576 Vals.push_back(
577 MIB.buildInstr(AArch64::G_REV32, {VT}, {OpLHS}).getReg(0));
578 }
579 break;
580 }
585 unsigned Opcode;
586 if (VT.getScalarSizeInBits() == 8)
587 Opcode = AArch64::G_DUPLANE8;
588 else if (VT.getScalarSizeInBits() == 16)
589 Opcode = AArch64::G_DUPLANE16;
590 else if (VT.getScalarSizeInBits() == 32)
591 Opcode = AArch64::G_DUPLANE32;
592 else if (VT.getScalarSizeInBits() == 64)
593 Opcode = AArch64::G_DUPLANE64;
594 else
595 llvm_unreachable("Invalid vector element type?");
596
597 if (VT.getSizeInBits() == 64) {
598 auto Undef = MIB.buildUndef(VT);
599 OpLHS = MIB.buildConcatVectors(VT.multiplyElements(2),
600 {OpLHS, Undef.getReg(0)})
601 .getReg(0);
602 }
603 auto Lane = MIB.buildConstant(LLT::integer(64),
604 Entry.Op - ShuffleEntry::OP_VDUP0);
605 Vals.push_back(MIB.buildInstr(Opcode, {VT}, {OpLHS, Lane}).getReg(0));
606 break;
607 }
611 unsigned ExtFactor = VT.getScalarSizeInBits() / 8;
612 unsigned Imm = (Entry.Op - ShuffleEntry::OP_VEXT1 + 1) * ExtFactor;
613 Vals.push_back(MIB.buildInstr(AArch64::G_EXT, {VT},
614 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals),
615 MIB.buildConstant(LLT::integer(32), Imm)})
616 .getReg(0));
617 break;
618 }
620 Vals.push_back(
621 MIB.buildInstr(AArch64::G_UZP1, {VT},
622 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
623 .getReg(0));
624 break;
626 Vals.push_back(
627 MIB.buildInstr(AArch64::G_UZP2, {VT},
628 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
629 .getReg(0));
630 break;
632 Vals.push_back(
633 MIB.buildInstr(AArch64::G_ZIP1, {VT},
634 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
635 .getReg(0));
636 break;
638 Vals.push_back(
639 MIB.buildInstr(AArch64::G_ZIP2, {VT},
640 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
641 .getReg(0));
642 break;
644 Vals.push_back(
645 MIB.buildInstr(AArch64::G_TRN1, {VT},
646 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
647 .getReg(0));
648 break;
650 Vals.push_back(
651 MIB.buildInstr(AArch64::G_TRN2, {VT},
652 {OpLHS, getValue(Entry.RHSID, V1, V2, Vals)})
653 .getReg(0));
654 break;
655 }
656 }
657 assert(Vals.size() == Entries.size());
658 MRI.replaceRegWith(MI.getOperand(0).getReg(), Vals.back());
659 MI.eraseFromParent();
660}
661
662/// Match a vector G_ASHR or G_LSHR with a valid immediate shift.
663bool matchVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
664 int64_t &Imm) {
665 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
666 MI.getOpcode() == TargetOpcode::G_LSHR);
667 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
668 if (!Ty.isVector())
669 return false;
670 return isVShiftRImm(MI.getOperand(2).getReg(), MRI, Ty, Imm);
671}
672
673void applyVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
674 int64_t &Imm) {
675 unsigned Opc = MI.getOpcode();
676 assert(Opc == TargetOpcode::G_ASHR || Opc == TargetOpcode::G_LSHR);
677 unsigned NewOpc =
678 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
679 MachineIRBuilder MIB(MI);
680 MIB.buildInstr(NewOpc, {MI.getOperand(0)}, {MI.getOperand(1)}).addImm(Imm);
681 MI.eraseFromParent();
682}
683
684/// Determine whether an integer G_ICMP against 1 or -1 can compare
685/// against 0 instead.
686///
687/// AArch64 can fold a compare-with-zero more cheaply than some non-arithmetic
688/// immediates (SUBS/ADDS, or TST when the LHS is an AND). When the predicate
689/// can be adjusted without changing semantics, the RHS may become 0.
690///
691/// Supported transforms (signed predicates only):
692/// (and X, Y) slt 1 => (and X, Y) sle 0
693/// (and X, Y) sge 1 => (and X, Y) sgt 0
694/// X sle -1 => X slt 0
695/// X sgt -1 => X sge 0
696///
697/// The compare-against-1 cases require the LHS to be G_AND because the
698/// compare-with-zero path enables ANDS (TST) selection, and ANDS flags are
699/// only reliable for those signed comparisons. This mirrors SelectionDAG
700/// emitComparison().
701///
702/// For compare-against--1 on a non-AND LHS, \p LHS must have a single
703/// non-debug use so other users are not left with a different immediate.
704///
705/// \param LHS The compare LHS register.
706/// \param C The constant RHS (only 1 or all-ones are considered).
707/// \param P In/out predicate; updated when a transform applies.
708/// \param MRI Used to inspect the LHS definition and use count.
709/// \returns true if \p P was updated and comparing against 0 is equivalent.
710static bool shouldBeAdjustedToZero(Register LHS, const APInt &C,
712 const MachineRegisterInfo &MRI) {
713 const bool IsAndLHS = getOpcodeDef<GAnd>(LHS, MRI) != nullptr;
714
715 if (C.isOne() && (P == CmpInst::ICMP_SLT || P == CmpInst::ICMP_SGE) &&
716 IsAndLHS) {
718 return true;
719 }
720
721 if (!IsAndLHS && !MRI.hasOneNonDBGUse(LHS))
722 return false;
723
724 if (C.isAllOnes() && (P == CmpInst::ICMP_SLE || P == CmpInst::ICMP_SGT)) {
726 return true;
727 }
728 return false;
729}
730
731/// Determine if it is possible to modify the \p RHS and predicate \p P of a
732/// G_ICMP instruction such that the right-hand side is an arithmetic immediate.
733///
734/// \returns A pair containing the updated immediate and predicate which may
735/// be used to optimize the instruction.
736///
737/// \note This assumes that the comparison has been legalized.
738std::optional<std::pair<uint64_t, CmpInst::Predicate>>
739tryAdjustICmpImmAndPred(Register LHS, Register RHS, CmpInst::Predicate P,
740 const MachineRegisterInfo &MRI) {
741 const auto &Ty = MRI.getType(RHS);
742 if (Ty.isVector())
743 return std::nullopt;
744 assert((Ty.getSizeInBits() == 32 || Ty.getSizeInBits() == 64) &&
745 "Expected 32 or 64 bit compare only?");
746
747 // If the RHS is not a constant, or the RHS is already a valid arithmetic
748 // immediate, then there is nothing to change.
749 auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS, MRI);
750 if (!ValAndVReg)
751 return std::nullopt;
752 APInt C = ValAndVReg->Value;
754 return {{0, P}};
755
757 return std::nullopt;
758
759 uint64_t OriginalC = C.getZExtValue();
760
761 // We have a non-arithmetic immediate. Check if adjusting the immediate and
762 // adjusting the predicate will result in a legal arithmetic immediate.
763 switch (P) {
764 default:
765 return std::nullopt;
768 // Check for
769 //
770 // x slt c => x sle c - 1
771 // x sge c => x sgt c - 1
772 //
773 // When c is not the smallest possible negative number.
774 if (C.isMinSignedValue())
775 return std::nullopt;
777 C = C - 1;
778 break;
781 // Check for
782 //
783 // x ult c => x ule c - 1
784 // x uge c => x ugt c - 1
785 //
786 // When c is not zero.
787 assert(!C.isZero() && "C should not be zero here!");
789 C = C - 1;
790 break;
793 // Check for
794 //
795 // x sle c => x slt c + 1
796 // x sgt c => s sge c + 1
797 //
798 // When c is not the largest possible signed integer.
799 if (C.isMaxSignedValue())
800 return std::nullopt;
802 C = C + 1;
803 break;
806 // Check for
807 //
808 // x ule c => x ult c + 1
809 // x ugt c => s uge c + 1
810 //
811 // When c is not the largest possible unsigned integer.
812 if (C.isAllOnes())
813 return std::nullopt;
815 C = C + 1;
816 break;
817 }
818
819 // Check if the new constant is valid, and return the updated constant and
820 // predicate if it is.
821 uint64_t NewC = C.getZExtValue();
823 return {{NewC, P}};
824
825 auto NumberOfInstrToLoadImm = [=](uint64_t Imm) {
828 return Insn.size();
829 };
830
831 if (NumberOfInstrToLoadImm(OriginalC) > NumberOfInstrToLoadImm(NewC))
832 return {{NewC, P}};
833
834 return std::nullopt;
835}
836
837/// Determine whether or not it is possible to update the RHS and predicate of
838/// a G_ICMP instruction such that the RHS will be selected as an arithmetic
839/// immediate.
840///
841/// \p MI - The G_ICMP instruction
842/// \p MatchInfo - The new RHS immediate and predicate on success
843///
844/// See tryAdjustICmpImmAndPred for valid transformations.
845bool matchAdjustICmpImmAndPred(
847 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
848 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
849 Register LHS = MI.getOperand(2).getReg();
850 Register RHS = MI.getOperand(3).getReg();
851 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
852 if (auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(LHS, RHS, Pred, MRI)) {
853 MatchInfo = *MaybeNewImmAndPred;
854 return true;
855 }
856 return false;
857}
858
859void applyAdjustICmpImmAndPred(
860 MachineInstr &MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
861 MachineIRBuilder &MIB, GISelChangeObserver &Observer) {
863 MachineOperand &RHS = MI.getOperand(3);
865 auto Cst = MIB.buildConstant(MRI.cloneVirtualRegister(RHS.getReg()),
866 MatchInfo.first);
867 Observer.changingInstr(MI);
868 RHS.setReg(Cst->getOperand(0).getReg());
869 MI.getOperand(1).setPredicate(MatchInfo.second);
870 Observer.changedInstr(MI);
871}
872
873bool matchDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
874 std::pair<unsigned, int> &MatchInfo) {
875 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
876 Register Src1Reg = MI.getOperand(1).getReg();
877 const LLT SrcTy = MRI.getType(Src1Reg);
878 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
879
880 auto LaneIdx = getSplatIndex(MI);
881 if (!LaneIdx)
882 return false;
883
884 // The lane idx should be within the first source vector.
885 if (*LaneIdx >= SrcTy.getNumElements())
886 return false;
887
888 if (DstTy != SrcTy)
889 return false;
890
891 LLT ScalarTy = SrcTy.getElementType();
892 unsigned ScalarSize = ScalarTy.getSizeInBits();
893
894 unsigned Opc = 0;
895 switch (SrcTy.getNumElements()) {
896 case 2:
897 if (ScalarSize == 64)
898 Opc = AArch64::G_DUPLANE64;
899 else if (ScalarSize == 32)
900 Opc = AArch64::G_DUPLANE32;
901 break;
902 case 4:
903 if (ScalarSize == 32)
904 Opc = AArch64::G_DUPLANE32;
905 else if (ScalarSize == 16)
906 Opc = AArch64::G_DUPLANE16;
907 break;
908 case 8:
909 if (ScalarSize == 8)
910 Opc = AArch64::G_DUPLANE8;
911 else if (ScalarSize == 16)
912 Opc = AArch64::G_DUPLANE16;
913 break;
914 case 16:
915 if (ScalarSize == 8)
916 Opc = AArch64::G_DUPLANE8;
917 break;
918 default:
919 break;
920 }
921 if (!Opc)
922 return false;
923
924 MatchInfo.first = Opc;
925 MatchInfo.second = *LaneIdx;
926 return true;
927}
928
929void applyDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
930 MachineIRBuilder &B, std::pair<unsigned, int> &MatchInfo) {
931 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
932 Register Src1Reg = MI.getOperand(1).getReg();
933 const LLT SrcTy = MRI.getType(Src1Reg);
934
935 B.setInstrAndDebugLoc(MI);
936 auto Lane = B.buildConstant(LLT::integer(64), MatchInfo.second);
937
938 Register DupSrc = MI.getOperand(1).getReg();
939 // For types like <2 x s32>, we can use G_DUPLANE32, with a <4 x s32> source.
940 // To do this, we can use a G_CONCAT_VECTORS to do the widening.
941 if (SrcTy.getSizeInBits() == 64) {
942 auto Undef = B.buildUndef(SrcTy);
943 DupSrc = B.buildConcatVectors(SrcTy.multiplyElements(2),
944 {Src1Reg, Undef.getReg(0)})
945 .getReg(0);
946 }
947 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
948 MI.eraseFromParent();
949}
950
951bool matchScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI) {
952 auto &Unmerge = cast<GUnmerge>(MI);
953 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
954 const LLT SrcTy = MRI.getType(Src1Reg);
955 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
956 return false;
957 return SrcTy.isVector() && !SrcTy.isScalable() &&
958 (Unmerge.getNumOperands() == (unsigned)SrcTy.getNumElements() + 1 ||
959 (Unmerge.getNumDefs() == 2 && SrcTy.getSizeInBits() == 128 &&
960 MRI.getType(Unmerge.getReg(0)).getSizeInBits() == 64));
961}
962
963void applyScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
965 auto &Unmerge = cast<GUnmerge>(MI);
966 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
967 const LLT SrcTy = MRI.getType(Src1Reg);
968 const LLT DstTy = MRI.getType(Unmerge.getReg(0));
969 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
970 "Expected a fixed length vector");
971
972 if (DstTy.isVector()) {
973 assert(Unmerge.getNumDefs() == 2);
974 if (!MRI.use_nodbg_empty(Unmerge.getReg(0)))
975 B.buildExtractSubvector(Unmerge.getReg(0), Src1Reg, 0);
976 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
977 B.buildExtractSubvector(Unmerge.getReg(1), Src1Reg,
978 SrcTy.getNumElements() / 2);
979 } else {
980 for (int I = 0; I < SrcTy.getNumElements(); ++I)
981 if (!MRI.use_nodbg_empty(Unmerge.getReg(I)))
982 B.buildExtractVectorElementConstant(Unmerge.getReg(I), Src1Reg, I);
983 }
984 MI.eraseFromParent();
985}
986
987bool matchBuildVectorToDup(MachineInstr &MI, Register &Src,
989 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
990
991 // Later, during selection, we'll try to match imported patterns using
992 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
993 // G_BUILD_VECTORs which could match those patterns.
995 return false;
996
997 // Find buildvector which always uses the same register or undef. Return true
998 // so long as at least 2 registers were found (not all-undef or only 1
999 // non-undef entry).
1000 Register Reg = 0;
1001 unsigned NumNonUndef = 0;
1002 for (const MachineOperand &Op : drop_begin(MI.operands())) {
1003 if (getOpcodeDef<GImplicitDef>(Op.getReg(), MRI))
1004 continue;
1005
1006 if (!Reg)
1007 Reg = Op.getReg();
1008 else if (Op.getReg() != Reg)
1009 return false;
1010 NumNonUndef++;
1011 }
1012
1013 Src = Reg;
1014 return Reg && NumNonUndef > 1;
1015}
1016
1017void applyBuildVectorToDup(MachineInstr &MI, Register Src,
1019 B.setInstrAndDebugLoc(MI);
1020 B.buildInstr(TargetOpcode::G_SPLAT_VECTOR, {MI.getOperand(0).getReg()},
1021 {Src});
1022 MI.eraseFromParent();
1023}
1024
1025bool matchBuildVectorToHalfDup(MachineInstr &MI,
1026 std::pair<Register, Register> &Srcs,
1028 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
1029 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1030 if (Ty.getSizeInBits() != 128 || isConstantOrConstantVector(MI, MRI))
1031 return false;
1032
1033 // Later, during selection, we'll try to match imported patterns using
1034 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
1035 // G_BUILD_VECTORs which could match those patterns.
1037 return false;
1038
1039 // Find buildvector which always uses the same register or undef in the first
1040 // and second halves of the register.
1041 Register Reg1;
1042 Register Reg2;
1043 unsigned NumOps = MI.getNumOperands() - 1;
1044 if (NumOps <= 2 || NumOps % 2 != 0)
1045 return false;
1046
1047 unsigned NumNonUndef1 = 0, NumNonUndef2 = 0;
1048 for (unsigned I = 0; I < NumOps / 2; I++) {
1049 Register Src1 = MI.getOperand(I + 1).getReg();
1050 if (!getOpcodeDef<GImplicitDef>(Src1, MRI)) {
1051 if (!Reg1)
1052 Reg1 = Src1;
1053 else if (Src1 != Reg1)
1054 return false;
1055 NumNonUndef1++;
1056 }
1057
1058 Register Src2 = MI.getOperand(NumOps / 2 + I + 1).getReg();
1059 if (!getOpcodeDef<GImplicitDef>(Src2, MRI)) {
1060 if (!Reg2)
1061 Reg2 = Src2;
1062 else if (Src2 != Reg2)
1063 return false;
1064 NumNonUndef2++;
1065 }
1066 }
1067
1068 Srcs = {Reg1, Reg2};
1069 return NumNonUndef1 >= 1 && NumNonUndef2 >= 1 &&
1070 NumNonUndef1 + NumNonUndef2 >= 3 && Reg1 != Reg2;
1071}
1072
1073void applyBuildVectorToHalfDup(MachineInstr &MI,
1074 std::pair<Register, Register> &Srcs,
1076 B.setInstrAndDebugLoc(MI);
1077 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1078 LLT HalfTy = Ty.divide(2);
1079 auto D1 = Srcs.first
1080 ? B.buildInstr(AArch64::G_SPLAT_VECTOR, {HalfTy}, {Srcs.first})
1081 : B.buildUndef(HalfTy);
1082 auto D2 = Srcs.second
1083 ? B.buildInstr(AArch64::G_SPLAT_VECTOR, {HalfTy}, {Srcs.second})
1084 : B.buildUndef(HalfTy);
1085 B.buildConcatVectors(MI.getOperand(0), {D1.getReg(0), D2.getReg(0)});
1086 MI.eraseFromParent();
1087}
1088
1089/// \returns how many instructions would be saved by folding a G_ICMP's shift
1090/// and/or extension operations.
1091static unsigned getCmpOperandFoldingProfit(Register CmpOp,
1093 // FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
1094 auto IsSupportedExtend = [&](const MachineInstr &MI) {
1095 if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
1096 return true;
1097 if (MI.getOpcode() == TargetOpcode::G_AND) {
1098 auto ValAndVReg =
1099 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
1100 if (ValAndVReg) {
1101 uint64_t Mask = ValAndVReg->Value.getZExtValue();
1102 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
1103 }
1104 }
1105 return false;
1106 };
1107
1108 // No instructions to save if there's more than one use or no uses.
1109 if (!MRI.hasOneNonDBGUse(CmpOp))
1110 return 0;
1111
1112 MachineInstr *Def = getDefIgnoringCopies(CmpOp, MRI);
1113 if (IsSupportedExtend(*Def))
1114 return 1;
1115
1116 unsigned Opc = Def->getOpcode();
1117 if (Opc == TargetOpcode::G_SHL || Opc == TargetOpcode::G_LSHR ||
1118 Opc == TargetOpcode::G_ASHR) {
1119 auto MaybeShiftAmt =
1120 getIConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
1121 if (MaybeShiftAmt) {
1122 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
1123 MachineInstr *ShiftLHS =
1124 getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
1125 if (IsSupportedExtend(*ShiftLHS))
1126 return (ShiftAmt <= 4) ? 2 : 1;
1127 LLT Ty = MRI.getType(Def->getOperand(0).getReg());
1128 if (Ty.isVector())
1129 return 0;
1130 unsigned ShiftSize = Ty.getSizeInBits();
1131 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
1132 (ShiftSize == 64 && ShiftAmt <= 63))
1133 return 1;
1134 }
1135 }
1136
1137 return 0;
1138}
1139
1140/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
1141/// instruction \p MI.
1142bool trySwapICmpOperands(MachineInstr &MI, MachineRegisterInfo &MRI) {
1143 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
1144 // Swap the operands if it would introduce a profitable folding opportunity.
1145 // (e.g. a shift + extend).
1146 //
1147 // For example:
1148 // lsl w13, w11, #1
1149 // cmp w13, w12
1150 // can be turned into:
1151 // cmp w12, w11, lsl #1
1152
1153 // Don't swap if there's a constant on the RHS and it is a legal compare
1154 // immediate, because we know we can fold that.
1155 Register RHS = MI.getOperand(3).getReg();
1157 if (RHSCst && AArch64_AM::isLegalCmpImmed(RHSCst->Value))
1158 return false;
1159
1160 Register LHS = MI.getOperand(2).getReg();
1161 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1162 auto GetRegForProfit = [&](Register Reg) {
1164 return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
1165 };
1166
1167 // Don't have a constant on the RHS. If we swap the LHS and RHS of the
1168 // compare, would we be able to fold more instructions?
1169 Register TheLHS = GetRegForProfit(LHS);
1170 Register TheRHS = GetRegForProfit(RHS);
1171
1172 // If the LHS is more likely to give us a folding opportunity, then swap the
1173 // LHS and RHS.
1174 return (getCmpOperandFoldingProfit(TheLHS, MRI) >
1176}
1177
1178void applySwapICmpOperands(MachineInstr &MI, GISelChangeObserver &Observer) {
1179 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1180 Register LHS = MI.getOperand(2).getReg();
1181 Register RHS = MI.getOperand(3).getReg();
1182 Observer.changingInstr(MI);
1183 MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
1184 MI.getOperand(2).setReg(RHS);
1185 MI.getOperand(3).setReg(LHS);
1186 Observer.changedInstr(MI);
1187}
1188
1189/// \returns a function which builds a vector floating point compare instruction
1190/// for a condition code \p CC.
1191/// \param [in] NoNans - True if the instruction has nnan flag.
1192std::function<Register(MachineIRBuilder &)>
1193getVectorFCMP(AArch64CC::CondCode CC, Register LHS, Register RHS, bool NoNans,
1195 LLT OldTy = MRI.getType(LHS);
1196 LLT DstTy = LLT::fixed_vector(OldTy.getNumElements(),
1198 assert(DstTy.isVector() && "Expected vector types only?");
1199 switch (CC) {
1200 default:
1201 llvm_unreachable("Unexpected condition code!");
1202 case AArch64CC::NE:
1203 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1204 auto FCmp = MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS});
1205 return MIB.buildNot(DstTy, FCmp).getReg(0);
1206 };
1207 case AArch64CC::EQ:
1208 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1209 return MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS}).getReg(0);
1210 };
1211 case AArch64CC::GE:
1212 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1213 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {LHS, RHS}).getReg(0);
1214 };
1215 case AArch64CC::GT:
1216 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1217 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {LHS, RHS}).getReg(0);
1218 };
1219 case AArch64CC::LS:
1220 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1221 return MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {RHS, LHS}).getReg(0);
1222 };
1223 case AArch64CC::MI:
1224 return [LHS, RHS, DstTy](MachineIRBuilder &MIB) {
1225 return MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {RHS, LHS}).getReg(0);
1226 };
1227 }
1228}
1229
1230/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1231bool matchLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1232 MachineIRBuilder &MIB) {
1233 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1234 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
1235
1236 Register Dst = MI.getOperand(0).getReg();
1237 LLT DstTy = MRI.getType(Dst);
1238 if (!DstTy.isVector() || !ST.hasNEON())
1239 return false;
1240 Register LHS = MI.getOperand(2).getReg();
1241 unsigned EltSize = MRI.getType(LHS).getScalarSizeInBits();
1242 if (EltSize == 16 && !ST.hasFullFP16())
1243 return false;
1244 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
1245 return false;
1246
1247 return true;
1248}
1249
1250/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
1251void applyLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
1252 MachineIRBuilder &MIB) {
1253 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
1254
1255 const auto &CmpMI = cast<GFCmp>(MI);
1256
1257 Register Dst = CmpMI.getReg(0);
1258 CmpInst::Predicate Pred = CmpMI.getCond();
1259 Register LHS = CmpMI.getLHSReg();
1260 Register RHS = CmpMI.getRHSReg();
1261
1262 LLT DstTy = MRI.getType(Dst);
1263
1264 bool Invert = false;
1268 isBuildVectorAllZeros(*MRI.getVRegDef(RHS), MRI)) {
1269 // The special case "fcmp ord %a, 0" is the canonical check that LHS isn't
1270 // NaN, so equivalent to a == a and doesn't need the two comparisons an
1271 // "ord" normally would.
1272 // Similarly, "fcmp uno %a, 0" is the canonical check that LHS is NaN and is
1273 // thus equivalent to a != a.
1274 RHS = LHS;
1276 } else
1278
1279 // Instead of having an apply function, just build here to simplify things.
1281
1282 // TODO: Also consider GISelValueTracking result if eligible.
1283 const bool NoNans = MI.getFlag(MachineInstr::FmNoNans);
1284
1285 auto Cmp = getVectorFCMP(CC, LHS, RHS, NoNans, MRI);
1286 Register CmpRes;
1287 if (CC2 == AArch64CC::AL)
1288 CmpRes = Cmp(MIB);
1289 else {
1290 auto Cmp2 = getVectorFCMP(CC2, LHS, RHS, NoNans, MRI);
1291 auto Cmp2Dst = Cmp2(MIB);
1292 auto Cmp1Dst = Cmp(MIB);
1293 CmpRes = MIB.buildOr(DstTy, Cmp1Dst, Cmp2Dst).getReg(0);
1294 }
1295 if (Invert)
1296 CmpRes = MIB.buildNot(DstTy, CmpRes).getReg(0);
1297 MRI.replaceRegWith(Dst, CmpRes);
1298 MI.eraseFromParent();
1299}
1300
1301// Matches G_BUILD_VECTOR where at least one source operand is not a constant
1302bool matchLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI) {
1303 auto *GBuildVec = cast<GBuildVector>(&MI);
1304
1305 // Check if the values are all constants
1306 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1307 auto ConstVal =
1308 getAnyConstantVRegValWithLookThrough(GBuildVec->getSourceReg(I), MRI);
1309
1310 if (!ConstVal.has_value())
1311 return true;
1312 }
1313
1314 return false;
1315}
1316
1317void applyLowerBuildToInsertVecElt(MachineInstr &MI, MachineRegisterInfo &MRI,
1319 auto *GBuildVec = cast<GBuildVector>(&MI);
1320 LLT DstTy = MRI.getType(GBuildVec->getReg(0));
1321 Register DstReg = B.buildUndef(DstTy).getReg(0);
1322
1323 for (unsigned I = 0; I < GBuildVec->getNumSources(); ++I) {
1324 Register SrcReg = GBuildVec->getSourceReg(I);
1325 if (mi_match(SrcReg, MRI, m_GImplicitDef()))
1326 continue;
1327 auto IdxReg = B.buildConstant(LLT::integer(64), I);
1328 DstReg =
1329 B.buildInsertVectorElement(DstTy, DstReg, SrcReg, IdxReg).getReg(0);
1330 }
1331 B.buildCopy(GBuildVec->getReg(0), DstReg);
1332 GBuildVec->eraseFromParent();
1333}
1334
1335// Detect vector constants that cannot be natively represent, but can be
1336// represented as fneg(constant). For example the constant
1337// <0x800000000000000, 0x800000000000000> can be represented as fneg(<0, 0>).
1338bool matchConstBuildVectorToFNeg(MachineInstr &MI, MachineRegisterInfo &MRI,
1339 const AArch64Subtarget &ST,
1340 std::pair<APInt, unsigned> &MatchInfo) {
1341 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
1342 if (!ST.isNeonAvailable())
1343 return false;
1344 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1345 // Limit to fneg of v2f32, v4f32, f64, v2f64 or v4f16 and v8f16 with fullfp16.
1346 if (Ty.getSizeInBits() != 64 && Ty.getSizeInBits() != 128)
1347 return false;
1348 unsigned EltSize = Ty.getScalarSizeInBits();
1349
1350 APInt Imm(Ty.getSizeInBits(), 0);
1351 for (unsigned Idx = 1; Idx < MI.getNumOperands(); Idx++) {
1352 auto C =
1353 getAnyConstantVRegValWithLookThrough(MI.getOperand(Idx).getReg(), MRI);
1354 if (!C)
1355 return false;
1356 Imm |= C->Value.trunc(EltSize)
1357 .zext(Ty.getSizeInBits())
1358 .shl((Idx - 1) * EltSize);
1359 }
1360
1362 if (AArch64_IMM::expandVectorMOVImm(Imm, Insns, ST))
1363 return false;
1364
1365 auto Check = [&](APInt &Imm, unsigned Size) {
1366 APInt NImm = Imm ^ APInt::getSplat(Imm.getBitWidth(),
1369 MatchInfo.first = NImm;
1370 MatchInfo.second = Size;
1371 return AArch64_IMM::expandVectorMOVImm(NImm, Insns, ST);
1372 };
1373
1374 return Check(Imm, 64) || Check(Imm, 32) ||
1375 (ST.hasFullFP16() && Check(Imm, 16));
1376}
1377
1378void applyConstBuildVectorToFNeg(MachineInstr &MI, MachineRegisterInfo &MRI,
1380 std::pair<APInt, unsigned> &MatchInfo) {
1381 B.setInstrAndDebugLoc(MI);
1382 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1383 // Extract the Immediate into chunks of size EltSize
1384 unsigned EltSize = MatchInfo.second;
1385 unsigned NumLanes = Ty.getSizeInBits() / EltSize;
1386 LLT VTy = NumLanes == 1
1387 ? LLT::floatIEEE(EltSize)
1388 : LLT::fixed_vector(NumLanes, LLT::floatIEEE(EltSize));
1389 SmallVector<APInt> Imms;
1390 for (unsigned I = 0; I < NumLanes; I++)
1391 Imms.push_back(MatchInfo.first.extractBits(EltSize, I * EltSize));
1392 // Build the new BV and FNeg of it.
1393 auto BV = NumLanes == 1 ? B.buildFConstant(VTy, APFloat(APFloat::IEEEdouble(),
1394 MatchInfo.first))
1395 : B.buildBuildVectorConstant(VTy, Imms);
1396 auto FNeg = B.buildFNeg(Ty == VTy ? DstOp(MI.getOperand(0)) : DstOp(VTy), BV);
1397 if (Ty != VTy)
1398 B.buildBitcast(MI.getOperand(0), FNeg);
1399 MI.eraseFromParent();
1400}
1401
1402bool matchFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1403 Register &SrcReg) {
1404 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1405 Register DstReg = MI.getOperand(0).getReg();
1407 return false;
1408 if (MRI.getType(DstReg).isVector())
1409 return false;
1410 // Match a store of a truncate.
1411 if (!mi_match(DstReg, MRI, m_GTrunc(m_Reg(SrcReg))))
1412 return false;
1413 // Only form truncstores for value types of max 64b.
1414 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1415}
1416
1417void applyFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1419 Register &SrcReg) {
1420 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1421 Observer.changingInstr(MI);
1422 MI.getOperand(0).setReg(SrcReg);
1423 Observer.changedInstr(MI);
1424}
1425
1426// Lower vector G_SEXT_INREG back to shifts for selection. We allowed them to
1427// form in the first place for combine opportunities, so any remaining ones
1428// at this stage need be lowered back.
1429bool matchVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI) {
1430 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1431 Register DstReg = MI.getOperand(0).getReg();
1432 LLT DstTy = MRI.getType(DstReg);
1433 return DstTy.isVector();
1434}
1435
1436void applyVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI,
1438 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1439 B.setInstrAndDebugLoc(MI);
1440 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1441 Helper.lower(MI, 0, /* Unused hint type */ LLT());
1442}
1443
1444/// Combine <N x t>, unused = unmerge(G_EXT <2*N x t> v, undef, N)
1445/// => unused, <N x t> = unmerge v
1446bool matchUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1447 Register &MatchInfo) {
1448 auto &Unmerge = cast<GUnmerge>(MI);
1449 if (Unmerge.getNumDefs() != 2)
1450 return false;
1451 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
1452 return false;
1453
1454 LLT DstTy = MRI.getType(Unmerge.getReg(0));
1455 if (!DstTy.isVector())
1456 return false;
1457
1458 MachineInstr *Ext = getOpcodeDef(AArch64::G_EXT, Unmerge.getSourceReg(), MRI);
1459 if (!Ext)
1460 return false;
1461
1462 Register ExtSrc1 = Ext->getOperand(1).getReg();
1463 Register ExtSrc2 = Ext->getOperand(2).getReg();
1464 auto LowestVal =
1466 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.getSizeInBytes())
1467 return false;
1468
1469 if (!getOpcodeDef<GImplicitDef>(ExtSrc2, MRI))
1470 return false;
1471
1472 MatchInfo = ExtSrc1;
1473 return true;
1474}
1475
1476void applyUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1478 GISelChangeObserver &Observer, Register &SrcReg) {
1479 Observer.changingInstr(MI);
1480 // Swap dst registers.
1481 Register Dst1 = MI.getOperand(0).getReg();
1482 MI.getOperand(0).setReg(MI.getOperand(1).getReg());
1483 MI.getOperand(1).setReg(Dst1);
1484 MI.getOperand(2).setReg(SrcReg);
1485 Observer.changedInstr(MI);
1486}
1487
1488// Match mul({z/s}ext , {z/s}ext) => {u/s}mull OR
1489// Match v2s64 mul instructions, which will then be scalarised later on
1490// Doing these two matches in one function to ensure that the order of matching
1491// will always be the same.
1492// Try lowering MUL to MULL before trying to scalarize if needed.
1493bool matchMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI) {
1494 // Get the instructions that defined the source operand
1495 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1496 return DstTy == LLT::fixed_vector(2, 64);
1497}
1498
1499void applyMulv2s64(MachineInstr &MI, MachineRegisterInfo &MRI,
1501 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
1502 "Expected a G_MUL instruction");
1503
1504 // Get the instructions that defined the source operand
1505 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1506 assert(DstTy == LLT::fixed_vector(2, 64) && "Expected v2s64 Mul");
1507 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1508 Helper.fewerElementsVector(
1509 MI, 0,
1511}
1512
1513class AArch64PostLegalizerLoweringImpl : public Combiner {
1514protected:
1515 const CombinerHelper Helper;
1516 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1517 const AArch64Subtarget &STI;
1518
1519public:
1520 AArch64PostLegalizerLoweringImpl(
1521 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1522 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1523 const AArch64Subtarget &STI);
1524
1525 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
1526
1527 bool tryCombineAll(MachineInstr &I) const override;
1528
1529private:
1530#define GET_GICOMBINER_CLASS_MEMBERS
1531#include "AArch64GenPostLegalizeGILowering.inc"
1532#undef GET_GICOMBINER_CLASS_MEMBERS
1533};
1534
1535#define GET_GICOMBINER_IMPL
1536#include "AArch64GenPostLegalizeGILowering.inc"
1537#undef GET_GICOMBINER_IMPL
1538
1539AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1540 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
1541 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1542 const AArch64Subtarget &STI)
1543 : Combiner(MF, CInfo, /*VT*/ nullptr, CSEInfo),
1544 Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
1545 STI(STI),
1547#include "AArch64GenPostLegalizeGILowering.inc"
1549{
1550}
1551
1552bool runPostLegalizerLowering(
1553 MachineFunction &MF,
1554 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig) {
1555 if (MF.getProperties().hasFailedISel())
1556 return false;
1557 const Function &F = MF.getFunction();
1558
1560 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
1561 /*LegalizerInfo=*/nullptr, /*OptEnabled=*/true,
1562 F.hasOptSize(), F.hasMinSize());
1563 // Disable fixed-point iteration to reduce compile-time
1564 CInfo.MaxIterations = 1;
1565 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
1566 // PostLegalizerCombiner performs DCE, so a full DCE pass is unnecessary.
1567 CInfo.EnableFullDCE = false;
1568 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo, /*CSEInfo=*/nullptr,
1569 RuleConfig, ST);
1570 return Impl.combineMachineInstrs();
1571}
1572
1573class AArch64PostLegalizerLoweringLegacy : public MachineFunctionPass {
1574public:
1575 static char ID;
1576
1577 AArch64PostLegalizerLoweringLegacy();
1578
1579 StringRef getPassName() const override {
1580 return "AArch64PostLegalizerLowering";
1581 }
1582
1583 bool runOnMachineFunction(MachineFunction &MF) override;
1584 void getAnalysisUsage(AnalysisUsage &AU) const override;
1585
1586private:
1587 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1588};
1589} // end anonymous namespace
1590
1591void AArch64PostLegalizerLoweringLegacy::getAnalysisUsage(
1592 AnalysisUsage &AU) const {
1593 AU.setPreservesCFG();
1596}
1597
1598AArch64PostLegalizerLoweringLegacy::AArch64PostLegalizerLoweringLegacy()
1599 : MachineFunctionPass(ID) {
1600 if (!RuleConfig.parseCommandLineOption())
1601 report_fatal_error("Invalid rule identifier");
1602}
1603
1604bool AArch64PostLegalizerLoweringLegacy::runOnMachineFunction(
1605 MachineFunction &MF) {
1606 assert(MF.getProperties().hasLegalized() && "Expected a legalized function?");
1607 return runPostLegalizerLowering(MF, RuleConfig);
1608}
1609
1610char AArch64PostLegalizerLoweringLegacy::ID = 0;
1611INITIALIZE_PASS_BEGIN(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1612 "Lower AArch64 MachineInstrs after legalization", false,
1613 false)
1614INITIALIZE_PASS_END(AArch64PostLegalizerLoweringLegacy, DEBUG_TYPE,
1615 "Lower AArch64 MachineInstrs after legalization", false,
1616 false)
1617
1619 : RuleConfig(
1620 std::make_unique<AArch64PostLegalizerLoweringImplRuleConfig>()) {
1621 if (!RuleConfig->parseCommandLineOption())
1622 reportFatalUsageError("invalid rule identifier");
1623}
1624
1627
1629
1633 MFPropsModifier _(*this, MF);
1634 const bool Changed = runPostLegalizerLowering(MF, *RuleConfig);
1635
1636 if (!Changed)
1637 return PreservedAnalyses::all();
1638
1641 return PA;
1642}
1643
1644namespace llvm {
1646 return new AArch64PostLegalizerLoweringLegacy();
1647}
1648} // end namespace llvm
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)
SDValue Pred
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
uint64_t uint64_t
uint64_t Imm
MachineBasicBlock & MBB
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This contains common combine transformations that may be used in a combine pass,or by the target else...
Option class for Targets to specify which operations are combined how and when.
This contains the base class for all Combiners generated by TableGen.
This contains common code to allow clients to notify changes to machine instr.
#define Check(C,...)
#define DEBUG_TYPE
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
#define _
IRTranslator LLVM IR MI
static constexpr Value * getValue(Ty &ValueOrUse)
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
static bool isAtomic(MachineBasicBlock::iterator I)
#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)
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
Value * RHS
Value * LHS
BinaryOperator * Mul
The Input class is used to parse a yaml document into in-memory structs and vectors.
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:280
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:312
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.
static constexpr LLT float64()
Get a 64-bit IEEE double value.
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
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
LLT getScalarType() 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
LLT divide(int Factor) const
Return a type that is Factor times smaller.
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 constexpr LLT float32()
Get a 32-bit IEEE float value.
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 buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildExtractVectorElementConstant(const DstOp &Res, const SrcOp &Val, const int Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
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.
MachineInstrBuilder buildInsertVectorElement(const DstOp &Res, const SrcOp &Val, const SrcOp &Elt, const SrcOp &Idx)
Build and insert Res = G_INSERT_VECTOR_ELT Val, Elt, Idx.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
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,...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
Wrapper class representing virtual and physical registers.
Definition Register.h:20
static LLVM_ABI bool isReverseMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask swaps the order of elements from exactly one source vector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
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:253
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isVShiftRImm(Register Reg, const MachineRegisterInfo &MRI, LLT Ty, int64_t &Cnt)
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:1593
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:679
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...
auto successors(const MachineBasicBlock *BB)
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition Utils.cpp:520
bool generatePerfectShuffle(ArrayRef< int > Mask, unsigned NumElts, SmallVector< ShuffleEntry > &Entries)
generatePerfectShuffle - Given a Mask, attempt to generate the optimal sequence of instructions using...
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64PostLegalizerLowering()
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
Definition Utils.cpp:1657
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:446
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:1599
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1296
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:440
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
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:879
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:881
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.
ShuffleEntry - Represent a shuffle entry in the decomposion of a vector shuffle.