LLVM 19.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
24#include "AArch64Subtarget.h"
46#include "llvm/IR/InstrTypes.h"
48#include "llvm/Support/Debug.h"
50#include <optional>
51
52#define GET_GICOMBINER_DEPS
53#include "AArch64GenPostLegalizeGILowering.inc"
54#undef GET_GICOMBINER_DEPS
55
56#define DEBUG_TYPE "aarch64-postlegalizer-lowering"
57
58using namespace llvm;
59using namespace MIPatternMatch;
60using namespace AArch64GISelUtils;
61
62namespace {
63
64#define GET_GICOMBINER_TYPES
65#include "AArch64GenPostLegalizeGILowering.inc"
66#undef GET_GICOMBINER_TYPES
67
68/// Represents a pseudo instruction which replaces a G_SHUFFLE_VECTOR.
69///
70/// Used for matching target-supported shuffles before codegen.
71struct ShuffleVectorPseudo {
72 unsigned Opc; ///< Opcode for the instruction. (E.g. G_ZIP1)
73 Register Dst; ///< Destination register.
74 SmallVector<SrcOp, 2> SrcOps; ///< Source registers.
75 ShuffleVectorPseudo(unsigned Opc, Register Dst,
76 std::initializer_list<SrcOp> SrcOps)
77 : Opc(Opc), Dst(Dst), SrcOps(SrcOps){};
78 ShuffleVectorPseudo() = default;
79};
80
81/// Check if a G_EXT instruction can handle a shuffle mask \p M when the vector
82/// sources of the shuffle are different.
83std::optional<std::pair<bool, uint64_t>> getExtMask(ArrayRef<int> M,
84 unsigned NumElts) {
85 // Look for the first non-undef element.
86 auto FirstRealElt = find_if(M, [](int Elt) { return Elt >= 0; });
87 if (FirstRealElt == M.end())
88 return std::nullopt;
89
90 // Use APInt to handle overflow when calculating expected element.
91 unsigned MaskBits = APInt(32, NumElts * 2).logBase2();
92 APInt ExpectedElt = APInt(MaskBits, *FirstRealElt + 1);
93
94 // The following shuffle indices must be the successive elements after the
95 // first real element.
96 if (any_of(
97 make_range(std::next(FirstRealElt), M.end()),
98 [&ExpectedElt](int Elt) { return Elt != ExpectedElt++ && Elt >= 0; }))
99 return std::nullopt;
100
101 // The index of an EXT is the first element if it is not UNDEF.
102 // Watch out for the beginning UNDEFs. The EXT index should be the expected
103 // value of the first element. E.g.
104 // <-1, -1, 3, ...> is treated as <1, 2, 3, ...>.
105 // <-1, -1, 0, 1, ...> is treated as <2*NumElts-2, 2*NumElts-1, 0, 1, ...>.
106 // ExpectedElt is the last mask index plus 1.
107 uint64_t Imm = ExpectedElt.getZExtValue();
108 bool ReverseExt = false;
109
110 // There are two difference cases requiring to reverse input vectors.
111 // For example, for vector <4 x i32> we have the following cases,
112 // Case 1: shufflevector(<4 x i32>,<4 x i32>,<-1, -1, -1, 0>)
113 // Case 2: shufflevector(<4 x i32>,<4 x i32>,<-1, -1, 7, 0>)
114 // For both cases, we finally use mask <5, 6, 7, 0>, which requires
115 // to reverse two input vectors.
116 if (Imm < NumElts)
117 ReverseExt = true;
118 else
119 Imm -= NumElts;
120 return std::make_pair(ReverseExt, Imm);
121}
122
123/// Helper function for matchINS.
124///
125/// \returns a value when \p M is an ins mask for \p NumInputElements.
126///
127/// First element of the returned pair is true when the produced
128/// G_INSERT_VECTOR_ELT destination should be the LHS of the G_SHUFFLE_VECTOR.
129///
130/// Second element is the destination lane for the G_INSERT_VECTOR_ELT.
131std::optional<std::pair<bool, int>> isINSMask(ArrayRef<int> M,
132 int NumInputElements) {
133 if (M.size() != static_cast<size_t>(NumInputElements))
134 return std::nullopt;
135 int NumLHSMatch = 0, NumRHSMatch = 0;
136 int LastLHSMismatch = -1, LastRHSMismatch = -1;
137 for (int Idx = 0; Idx < NumInputElements; ++Idx) {
138 if (M[Idx] == -1) {
139 ++NumLHSMatch;
140 ++NumRHSMatch;
141 continue;
142 }
143 M[Idx] == Idx ? ++NumLHSMatch : LastLHSMismatch = Idx;
144 M[Idx] == Idx + NumInputElements ? ++NumRHSMatch : LastRHSMismatch = Idx;
145 }
146 const int NumNeededToMatch = NumInputElements - 1;
147 if (NumLHSMatch == NumNeededToMatch)
148 return std::make_pair(true, LastLHSMismatch);
149 if (NumRHSMatch == NumNeededToMatch)
150 return std::make_pair(false, LastRHSMismatch);
151 return std::nullopt;
152}
153
154/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with a
155/// G_REV instruction. Returns the appropriate G_REV opcode in \p Opc.
156bool matchREV(MachineInstr &MI, MachineRegisterInfo &MRI,
157 ShuffleVectorPseudo &MatchInfo) {
158 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
159 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
160 Register Dst = MI.getOperand(0).getReg();
161 Register Src = MI.getOperand(1).getReg();
162 LLT Ty = MRI.getType(Dst);
163 unsigned EltSize = Ty.getScalarSizeInBits();
164
165 // Element size for a rev cannot be 64.
166 if (EltSize == 64)
167 return false;
168
169 unsigned NumElts = Ty.getNumElements();
170
171 // Try to produce a G_REV instruction
172 for (unsigned LaneSize : {64U, 32U, 16U}) {
173 if (isREVMask(ShuffleMask, EltSize, NumElts, LaneSize)) {
174 unsigned Opcode;
175 if (LaneSize == 64U)
176 Opcode = AArch64::G_REV64;
177 else if (LaneSize == 32U)
178 Opcode = AArch64::G_REV32;
179 else
180 Opcode = AArch64::G_REV16;
181
182 MatchInfo = ShuffleVectorPseudo(Opcode, Dst, {Src});
183 return true;
184 }
185 }
186
187 return false;
188}
189
190/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
191/// a G_TRN1 or G_TRN2 instruction.
192bool matchTRN(MachineInstr &MI, MachineRegisterInfo &MRI,
193 ShuffleVectorPseudo &MatchInfo) {
194 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
195 unsigned WhichResult;
196 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
197 Register Dst = MI.getOperand(0).getReg();
198 unsigned NumElts = MRI.getType(Dst).getNumElements();
199 if (!isTRNMask(ShuffleMask, NumElts, WhichResult))
200 return false;
201 unsigned Opc = (WhichResult == 0) ? AArch64::G_TRN1 : AArch64::G_TRN2;
202 Register V1 = MI.getOperand(1).getReg();
203 Register V2 = MI.getOperand(2).getReg();
204 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
205 return true;
206}
207
208/// \return true if a G_SHUFFLE_VECTOR instruction \p MI can be replaced with
209/// a G_UZP1 or G_UZP2 instruction.
210///
211/// \param [in] MI - The shuffle vector instruction.
212/// \param [out] MatchInfo - Either G_UZP1 or G_UZP2 on success.
213bool matchUZP(MachineInstr &MI, MachineRegisterInfo &MRI,
214 ShuffleVectorPseudo &MatchInfo) {
215 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
216 unsigned WhichResult;
217 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
218 Register Dst = MI.getOperand(0).getReg();
219 unsigned NumElts = MRI.getType(Dst).getNumElements();
220 if (!isUZPMask(ShuffleMask, NumElts, WhichResult))
221 return false;
222 unsigned Opc = (WhichResult == 0) ? AArch64::G_UZP1 : AArch64::G_UZP2;
223 Register V1 = MI.getOperand(1).getReg();
224 Register V2 = MI.getOperand(2).getReg();
225 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
226 return true;
227}
228
229bool matchZip(MachineInstr &MI, MachineRegisterInfo &MRI,
230 ShuffleVectorPseudo &MatchInfo) {
231 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
232 unsigned WhichResult;
233 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
234 Register Dst = MI.getOperand(0).getReg();
235 unsigned NumElts = MRI.getType(Dst).getNumElements();
236 if (!isZIPMask(ShuffleMask, NumElts, WhichResult))
237 return false;
238 unsigned Opc = (WhichResult == 0) ? AArch64::G_ZIP1 : AArch64::G_ZIP2;
239 Register V1 = MI.getOperand(1).getReg();
240 Register V2 = MI.getOperand(2).getReg();
241 MatchInfo = ShuffleVectorPseudo(Opc, Dst, {V1, V2});
242 return true;
243}
244
245/// Helper function for matchDup.
246bool matchDupFromInsertVectorElt(int Lane, MachineInstr &MI,
248 ShuffleVectorPseudo &MatchInfo) {
249 if (Lane != 0)
250 return false;
251
252 // Try to match a vector splat operation into a dup instruction.
253 // We're looking for this pattern:
254 //
255 // %scalar:gpr(s64) = COPY $x0
256 // %undef:fpr(<2 x s64>) = G_IMPLICIT_DEF
257 // %cst0:gpr(s32) = G_CONSTANT i32 0
258 // %zerovec:fpr(<2 x s32>) = G_BUILD_VECTOR %cst0(s32), %cst0(s32)
259 // %ins:fpr(<2 x s64>) = G_INSERT_VECTOR_ELT %undef, %scalar(s64), %cst0(s32)
260 // %splat:fpr(<2 x s64>) = G_SHUFFLE_VECTOR %ins(<2 x s64>), %undef,
261 // %zerovec(<2 x s32>)
262 //
263 // ...into:
264 // %splat = G_DUP %scalar
265
266 // Begin matching the insert.
267 auto *InsMI = getOpcodeDef(TargetOpcode::G_INSERT_VECTOR_ELT,
268 MI.getOperand(1).getReg(), MRI);
269 if (!InsMI)
270 return false;
271 // Match the undef vector operand.
272 if (!getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, InsMI->getOperand(1).getReg(),
273 MRI))
274 return false;
275
276 // Match the index constant 0.
277 if (!mi_match(InsMI->getOperand(3).getReg(), MRI, m_ZeroInt()))
278 return false;
279
280 MatchInfo = ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(),
281 {InsMI->getOperand(2).getReg()});
282 return true;
283}
284
285/// Helper function for matchDup.
286bool matchDupFromBuildVector(int Lane, MachineInstr &MI,
288 ShuffleVectorPseudo &MatchInfo) {
289 assert(Lane >= 0 && "Expected positive lane?");
290 // Test if the LHS is a BUILD_VECTOR. If it is, then we can just reference the
291 // lane's definition directly.
292 auto *BuildVecMI = getOpcodeDef(TargetOpcode::G_BUILD_VECTOR,
293 MI.getOperand(1).getReg(), MRI);
294 if (!BuildVecMI)
295 return false;
296 Register Reg = BuildVecMI->getOperand(Lane + 1).getReg();
297 MatchInfo =
298 ShuffleVectorPseudo(AArch64::G_DUP, MI.getOperand(0).getReg(), {Reg});
299 return true;
300}
301
302bool matchDup(MachineInstr &MI, MachineRegisterInfo &MRI,
303 ShuffleVectorPseudo &MatchInfo) {
304 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
305 auto MaybeLane = getSplatIndex(MI);
306 if (!MaybeLane)
307 return false;
308 int Lane = *MaybeLane;
309 // If this is undef splat, generate it via "just" vdup, if possible.
310 if (Lane < 0)
311 Lane = 0;
312 if (matchDupFromInsertVectorElt(Lane, MI, MRI, MatchInfo))
313 return true;
314 if (matchDupFromBuildVector(Lane, MI, MRI, MatchInfo))
315 return true;
316 return false;
317}
318
319// Check if an EXT instruction can handle the shuffle mask when the vector
320// sources of the shuffle are the same.
321bool isSingletonExtMask(ArrayRef<int> M, LLT Ty) {
322 unsigned NumElts = Ty.getNumElements();
323
324 // Assume that the first shuffle index is not UNDEF. Fail if it is.
325 if (M[0] < 0)
326 return false;
327
328 // If this is a VEXT shuffle, the immediate value is the index of the first
329 // element. The other shuffle indices must be the successive elements after
330 // the first one.
331 unsigned ExpectedElt = M[0];
332 for (unsigned I = 1; I < NumElts; ++I) {
333 // Increment the expected index. If it wraps around, just follow it
334 // back to index zero and keep going.
335 ++ExpectedElt;
336 if (ExpectedElt == NumElts)
337 ExpectedElt = 0;
338
339 if (M[I] < 0)
340 continue; // Ignore UNDEF indices.
341 if (ExpectedElt != static_cast<unsigned>(M[I]))
342 return false;
343 }
344
345 return true;
346}
347
348bool matchEXT(MachineInstr &MI, MachineRegisterInfo &MRI,
349 ShuffleVectorPseudo &MatchInfo) {
350 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
351 Register Dst = MI.getOperand(0).getReg();
352 LLT DstTy = MRI.getType(Dst);
353 Register V1 = MI.getOperand(1).getReg();
354 Register V2 = MI.getOperand(2).getReg();
355 auto Mask = MI.getOperand(3).getShuffleMask();
357 auto ExtInfo = getExtMask(Mask, DstTy.getNumElements());
358 uint64_t ExtFactor = MRI.getType(V1).getScalarSizeInBits() / 8;
359
360 if (!ExtInfo) {
361 if (!getOpcodeDef<GImplicitDef>(V2, MRI) ||
362 !isSingletonExtMask(Mask, DstTy))
363 return false;
364
365 Imm = Mask[0] * ExtFactor;
366 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst, {V1, V1, Imm});
367 return true;
368 }
369 bool ReverseExt;
370 std::tie(ReverseExt, Imm) = *ExtInfo;
371 if (ReverseExt)
372 std::swap(V1, V2);
373 Imm *= ExtFactor;
374 MatchInfo = ShuffleVectorPseudo(AArch64::G_EXT, Dst, {V1, V2, Imm});
375 return true;
376}
377
378/// Replace a G_SHUFFLE_VECTOR instruction with a pseudo.
379/// \p Opc is the opcode to use. \p MI is the G_SHUFFLE_VECTOR.
380void applyShuffleVectorPseudo(MachineInstr &MI,
381 ShuffleVectorPseudo &MatchInfo) {
382 MachineIRBuilder MIRBuilder(MI);
383 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst}, MatchInfo.SrcOps);
384 MI.eraseFromParent();
385}
386
387/// Replace a G_SHUFFLE_VECTOR instruction with G_EXT.
388/// Special-cased because the constant operand must be emitted as a G_CONSTANT
389/// for the imported tablegen patterns to work.
390void applyEXT(MachineInstr &MI, ShuffleVectorPseudo &MatchInfo) {
391 MachineIRBuilder MIRBuilder(MI);
392 if (MatchInfo.SrcOps[2].getImm() == 0)
393 MIRBuilder.buildCopy(MatchInfo.Dst, MatchInfo.SrcOps[0]);
394 else {
395 // Tablegen patterns expect an i32 G_CONSTANT as the final op.
396 auto Cst =
397 MIRBuilder.buildConstant(LLT::scalar(32), MatchInfo.SrcOps[2].getImm());
398 MIRBuilder.buildInstr(MatchInfo.Opc, {MatchInfo.Dst},
399 {MatchInfo.SrcOps[0], MatchInfo.SrcOps[1], Cst});
400 }
401 MI.eraseFromParent();
402}
403
404bool matchNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI) {
405 assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT);
406
407 auto ValAndVReg =
408 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
409 return !ValAndVReg;
410}
411
412void applyNonConstInsert(MachineInstr &MI, MachineRegisterInfo &MRI,
413 MachineIRBuilder &Builder) {
414 auto &Insert = cast<GInsertVectorElement>(MI);
415 Builder.setInstrAndDebugLoc(Insert);
416
417 Register Offset = Insert.getIndexReg();
418 LLT VecTy = MRI.getType(Insert.getReg(0));
419 LLT EltTy = MRI.getType(Insert.getElementReg());
420 LLT IdxTy = MRI.getType(Insert.getIndexReg());
421
422 // Create a stack slot and store the vector into it
423 MachineFunction &MF = Builder.getMF();
424 Align Alignment(
425 std::min<uint64_t>(VecTy.getSizeInBytes().getKnownMinValue(), 16));
426 int FrameIdx = MF.getFrameInfo().CreateStackObject(VecTy.getSizeInBytes(),
427 Alignment, false);
428 LLT FramePtrTy = LLT::pointer(0, 64);
430 auto StackTemp = Builder.buildFrameIndex(FramePtrTy, FrameIdx);
431
432 Builder.buildStore(Insert.getOperand(1), StackTemp, PtrInfo, Align(8));
433
434 // Get the pointer to the element, and be sure not to hit undefined behavior
435 // if the index is out of bounds.
437 "Expected a power-2 vector size");
438 auto Mask = Builder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
439 Register And = Builder.buildAnd(IdxTy, Offset, Mask).getReg(0);
440 auto EltSize = Builder.buildConstant(IdxTy, EltTy.getSizeInBytes());
441 Register Mul = Builder.buildMul(IdxTy, And, EltSize).getReg(0);
442 Register EltPtr =
443 Builder.buildPtrAdd(MRI.getType(StackTemp.getReg(0)), StackTemp, Mul)
444 .getReg(0);
445
446 // Write the inserted element
447 Builder.buildStore(Insert.getElementReg(), EltPtr, PtrInfo, Align(1));
448 // Reload the whole vector.
449 Builder.buildLoad(Insert.getReg(0), StackTemp, PtrInfo, Align(8));
450 Insert.eraseFromParent();
451}
452
453/// Match a G_SHUFFLE_VECTOR with a mask which corresponds to a
454/// G_INSERT_VECTOR_ELT and G_EXTRACT_VECTOR_ELT pair.
455///
456/// e.g.
457/// %shuf = G_SHUFFLE_VECTOR %left, %right, shufflemask(0, 0)
458///
459/// Can be represented as
460///
461/// %extract = G_EXTRACT_VECTOR_ELT %left, 0
462/// %ins = G_INSERT_VECTOR_ELT %left, %extract, 1
463///
464bool matchINS(MachineInstr &MI, MachineRegisterInfo &MRI,
465 std::tuple<Register, int, Register, int> &MatchInfo) {
466 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
467 ArrayRef<int> ShuffleMask = MI.getOperand(3).getShuffleMask();
468 Register Dst = MI.getOperand(0).getReg();
469 int NumElts = MRI.getType(Dst).getNumElements();
470 auto DstIsLeftAndDstLane = isINSMask(ShuffleMask, NumElts);
471 if (!DstIsLeftAndDstLane)
472 return false;
473 bool DstIsLeft;
474 int DstLane;
475 std::tie(DstIsLeft, DstLane) = *DstIsLeftAndDstLane;
476 Register Left = MI.getOperand(1).getReg();
477 Register Right = MI.getOperand(2).getReg();
478 Register DstVec = DstIsLeft ? Left : Right;
479 Register SrcVec = Left;
480
481 int SrcLane = ShuffleMask[DstLane];
482 if (SrcLane >= NumElts) {
483 SrcVec = Right;
484 SrcLane -= NumElts;
485 }
486
487 MatchInfo = std::make_tuple(DstVec, DstLane, SrcVec, SrcLane);
488 return true;
489}
490
491void applyINS(MachineInstr &MI, MachineRegisterInfo &MRI,
492 MachineIRBuilder &Builder,
493 std::tuple<Register, int, Register, int> &MatchInfo) {
494 Builder.setInstrAndDebugLoc(MI);
495 Register Dst = MI.getOperand(0).getReg();
496 auto ScalarTy = MRI.getType(Dst).getElementType();
497 Register DstVec, SrcVec;
498 int DstLane, SrcLane;
499 std::tie(DstVec, DstLane, SrcVec, SrcLane) = MatchInfo;
500 auto SrcCst = Builder.buildConstant(LLT::scalar(64), SrcLane);
501 auto Extract = Builder.buildExtractVectorElement(ScalarTy, SrcVec, SrcCst);
502 auto DstCst = Builder.buildConstant(LLT::scalar(64), DstLane);
503 Builder.buildInsertVectorElement(Dst, DstVec, Extract, DstCst);
504 MI.eraseFromParent();
505}
506
507/// isVShiftRImm - Check if this is a valid vector for the immediate
508/// operand of a vector shift right operation. The value must be in the range:
509/// 1 <= Value <= ElementBits for a right shift.
511 int64_t &Cnt) {
512 assert(Ty.isVector() && "vector shift count is not a vector type");
513 MachineInstr *MI = MRI.getVRegDef(Reg);
514 auto Cst = getAArch64VectorSplatScalar(*MI, MRI);
515 if (!Cst)
516 return false;
517 Cnt = *Cst;
518 int64_t ElementBits = Ty.getScalarSizeInBits();
519 return Cnt >= 1 && Cnt <= ElementBits;
520}
521
522/// Match a vector G_ASHR or G_LSHR with a valid immediate shift.
523bool matchVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
524 int64_t &Imm) {
525 assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
526 MI.getOpcode() == TargetOpcode::G_LSHR);
527 LLT Ty = MRI.getType(MI.getOperand(1).getReg());
528 if (!Ty.isVector())
529 return false;
530 return isVShiftRImm(MI.getOperand(2).getReg(), MRI, Ty, Imm);
531}
532
533void applyVAshrLshrImm(MachineInstr &MI, MachineRegisterInfo &MRI,
534 int64_t &Imm) {
535 unsigned Opc = MI.getOpcode();
536 assert(Opc == TargetOpcode::G_ASHR || Opc == TargetOpcode::G_LSHR);
537 unsigned NewOpc =
538 Opc == TargetOpcode::G_ASHR ? AArch64::G_VASHR : AArch64::G_VLSHR;
539 MachineIRBuilder MIB(MI);
540 auto ImmDef = MIB.buildConstant(LLT::scalar(32), Imm);
541 MIB.buildInstr(NewOpc, {MI.getOperand(0)}, {MI.getOperand(1), ImmDef});
542 MI.eraseFromParent();
543}
544
545/// Determine if it is possible to modify the \p RHS and predicate \p P of a
546/// G_ICMP instruction such that the right-hand side is an arithmetic immediate.
547///
548/// \returns A pair containing the updated immediate and predicate which may
549/// be used to optimize the instruction.
550///
551/// \note This assumes that the comparison has been legalized.
552std::optional<std::pair<uint64_t, CmpInst::Predicate>>
553tryAdjustICmpImmAndPred(Register RHS, CmpInst::Predicate P,
554 const MachineRegisterInfo &MRI) {
555 const auto &Ty = MRI.getType(RHS);
556 if (Ty.isVector())
557 return std::nullopt;
558 unsigned Size = Ty.getSizeInBits();
559 assert((Size == 32 || Size == 64) && "Expected 32 or 64 bit compare only?");
560
561 // If the RHS is not a constant, or the RHS is already a valid arithmetic
562 // immediate, then there is nothing to change.
563 auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS, MRI);
564 if (!ValAndVReg)
565 return std::nullopt;
566 uint64_t C = ValAndVReg->Value.getZExtValue();
567 if (isLegalArithImmed(C))
568 return std::nullopt;
569
570 // We have a non-arithmetic immediate. Check if adjusting the immediate and
571 // adjusting the predicate will result in a legal arithmetic immediate.
572 switch (P) {
573 default:
574 return std::nullopt;
577 // Check for
578 //
579 // x slt c => x sle c - 1
580 // x sge c => x sgt c - 1
581 //
582 // When c is not the smallest possible negative number.
583 if ((Size == 64 && static_cast<int64_t>(C) == INT64_MIN) ||
584 (Size == 32 && static_cast<int32_t>(C) == INT32_MIN))
585 return std::nullopt;
587 C -= 1;
588 break;
591 // Check for
592 //
593 // x ult c => x ule c - 1
594 // x uge c => x ugt c - 1
595 //
596 // When c is not zero.
597 if (C == 0)
598 return std::nullopt;
600 C -= 1;
601 break;
604 // Check for
605 //
606 // x sle c => x slt c + 1
607 // x sgt c => s sge c + 1
608 //
609 // When c is not the largest possible signed integer.
610 if ((Size == 32 && static_cast<int32_t>(C) == INT32_MAX) ||
611 (Size == 64 && static_cast<int64_t>(C) == INT64_MAX))
612 return std::nullopt;
614 C += 1;
615 break;
618 // Check for
619 //
620 // x ule c => x ult c + 1
621 // x ugt c => s uge c + 1
622 //
623 // When c is not the largest possible unsigned integer.
624 if ((Size == 32 && static_cast<uint32_t>(C) == UINT32_MAX) ||
625 (Size == 64 && C == UINT64_MAX))
626 return std::nullopt;
628 C += 1;
629 break;
630 }
631
632 // Check if the new constant is valid, and return the updated constant and
633 // predicate if it is.
634 if (Size == 32)
635 C = static_cast<uint32_t>(C);
636 if (!isLegalArithImmed(C))
637 return std::nullopt;
638 return {{C, P}};
639}
640
641/// Determine whether or not it is possible to update the RHS and predicate of
642/// a G_ICMP instruction such that the RHS will be selected as an arithmetic
643/// immediate.
644///
645/// \p MI - The G_ICMP instruction
646/// \p MatchInfo - The new RHS immediate and predicate on success
647///
648/// See tryAdjustICmpImmAndPred for valid transformations.
649bool matchAdjustICmpImmAndPred(
651 std::pair<uint64_t, CmpInst::Predicate> &MatchInfo) {
652 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
653 Register RHS = MI.getOperand(3).getReg();
654 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
655 if (auto MaybeNewImmAndPred = tryAdjustICmpImmAndPred(RHS, Pred, MRI)) {
656 MatchInfo = *MaybeNewImmAndPred;
657 return true;
658 }
659 return false;
660}
661
662void applyAdjustICmpImmAndPred(
663 MachineInstr &MI, std::pair<uint64_t, CmpInst::Predicate> &MatchInfo,
664 MachineIRBuilder &MIB, GISelChangeObserver &Observer) {
666 MachineOperand &RHS = MI.getOperand(3);
668 auto Cst = MIB.buildConstant(MRI.cloneVirtualRegister(RHS.getReg()),
669 MatchInfo.first);
670 Observer.changingInstr(MI);
671 RHS.setReg(Cst->getOperand(0).getReg());
672 MI.getOperand(1).setPredicate(MatchInfo.second);
673 Observer.changedInstr(MI);
674}
675
676bool matchDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
677 std::pair<unsigned, int> &MatchInfo) {
678 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
679 Register Src1Reg = MI.getOperand(1).getReg();
680 const LLT SrcTy = MRI.getType(Src1Reg);
681 const LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
682
683 auto LaneIdx = getSplatIndex(MI);
684 if (!LaneIdx)
685 return false;
686
687 // The lane idx should be within the first source vector.
688 if (*LaneIdx >= SrcTy.getNumElements())
689 return false;
690
691 if (DstTy != SrcTy)
692 return false;
693
694 LLT ScalarTy = SrcTy.getElementType();
695 unsigned ScalarSize = ScalarTy.getSizeInBits();
696
697 unsigned Opc = 0;
698 switch (SrcTy.getNumElements()) {
699 case 2:
700 if (ScalarSize == 64)
701 Opc = AArch64::G_DUPLANE64;
702 else if (ScalarSize == 32)
703 Opc = AArch64::G_DUPLANE32;
704 break;
705 case 4:
706 if (ScalarSize == 32)
707 Opc = AArch64::G_DUPLANE32;
708 else if (ScalarSize == 16)
709 Opc = AArch64::G_DUPLANE16;
710 break;
711 case 8:
712 if (ScalarSize == 8)
713 Opc = AArch64::G_DUPLANE8;
714 else if (ScalarSize == 16)
715 Opc = AArch64::G_DUPLANE16;
716 break;
717 case 16:
718 if (ScalarSize == 8)
719 Opc = AArch64::G_DUPLANE8;
720 break;
721 default:
722 break;
723 }
724 if (!Opc)
725 return false;
726
727 MatchInfo.first = Opc;
728 MatchInfo.second = *LaneIdx;
729 return true;
730}
731
732void applyDupLane(MachineInstr &MI, MachineRegisterInfo &MRI,
733 MachineIRBuilder &B, std::pair<unsigned, int> &MatchInfo) {
734 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
735 Register Src1Reg = MI.getOperand(1).getReg();
736 const LLT SrcTy = MRI.getType(Src1Reg);
737
738 B.setInstrAndDebugLoc(MI);
739 auto Lane = B.buildConstant(LLT::scalar(64), MatchInfo.second);
740
741 Register DupSrc = MI.getOperand(1).getReg();
742 // For types like <2 x s32>, we can use G_DUPLANE32, with a <4 x s32> source.
743 // To do this, we can use a G_CONCAT_VECTORS to do the widening.
744 if (SrcTy.getSizeInBits() == 64) {
745 auto Undef = B.buildUndef(SrcTy);
746 DupSrc = B.buildConcatVectors(SrcTy.multiplyElements(2),
747 {Src1Reg, Undef.getReg(0)})
748 .getReg(0);
749 }
750 B.buildInstr(MatchInfo.first, {MI.getOperand(0).getReg()}, {DupSrc, Lane});
751 MI.eraseFromParent();
752}
753
754bool matchScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI) {
755 auto &Unmerge = cast<GUnmerge>(MI);
756 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
757 const LLT SrcTy = MRI.getType(Src1Reg);
758 if (SrcTy.getSizeInBits() != 128 && SrcTy.getSizeInBits() != 64)
759 return false;
760 return SrcTy.isVector() && !SrcTy.isScalable() &&
761 Unmerge.getNumOperands() == (unsigned)SrcTy.getNumElements() + 1;
762}
763
764void applyScalarizeVectorUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
766 auto &Unmerge = cast<GUnmerge>(MI);
767 Register Src1Reg = Unmerge.getReg(Unmerge.getNumOperands() - 1);
768 const LLT SrcTy = MRI.getType(Src1Reg);
769 assert((SrcTy.isVector() && !SrcTy.isScalable()) &&
770 "Expected a fixed length vector");
771
772 for (int I = 0; I < SrcTy.getNumElements(); ++I)
773 B.buildExtractVectorElementConstant(Unmerge.getReg(I), Src1Reg, I);
774 MI.eraseFromParent();
775}
776
777bool matchBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI) {
778 assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
780 if (!Splat)
781 return false;
782 if (Splat->isReg())
783 return true;
784 // Later, during selection, we'll try to match imported patterns using
785 // immAllOnesV and immAllZerosV. These require G_BUILD_VECTOR. Don't lower
786 // G_BUILD_VECTORs which could match those patterns.
787 int64_t Cst = Splat->getCst();
788 return (Cst != 0 && Cst != -1);
789}
790
791void applyBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI,
793 B.setInstrAndDebugLoc(MI);
794 B.buildInstr(AArch64::G_DUP, {MI.getOperand(0).getReg()},
795 {MI.getOperand(1).getReg()});
796 MI.eraseFromParent();
797}
798
799/// \returns how many instructions would be saved by folding a G_ICMP's shift
800/// and/or extension operations.
802 // No instructions to save if there's more than one use or no uses.
803 if (!MRI.hasOneNonDBGUse(CmpOp))
804 return 0;
805
806 // FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
807 auto IsSupportedExtend = [&](const MachineInstr &MI) {
808 if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
809 return true;
810 if (MI.getOpcode() != TargetOpcode::G_AND)
811 return false;
812 auto ValAndVReg =
813 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
814 if (!ValAndVReg)
815 return false;
816 uint64_t Mask = ValAndVReg->Value.getZExtValue();
817 return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
818 };
819
821 if (IsSupportedExtend(*Def))
822 return 1;
823
824 unsigned Opc = Def->getOpcode();
825 if (Opc != TargetOpcode::G_SHL && Opc != TargetOpcode::G_ASHR &&
826 Opc != TargetOpcode::G_LSHR)
827 return 0;
828
829 auto MaybeShiftAmt =
830 getIConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
831 if (!MaybeShiftAmt)
832 return 0;
833 uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
834 MachineInstr *ShiftLHS =
835 getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
836
837 // Check if we can fold an extend and a shift.
838 // FIXME: This is duplicated with the selector. (See:
839 // selectArithExtendedRegister)
840 if (IsSupportedExtend(*ShiftLHS))
841 return (ShiftAmt <= 4) ? 2 : 1;
842
843 LLT Ty = MRI.getType(Def->getOperand(0).getReg());
844 if (Ty.isVector())
845 return 0;
846 unsigned ShiftSize = Ty.getSizeInBits();
847 if ((ShiftSize == 32 && ShiftAmt <= 31) ||
848 (ShiftSize == 64 && ShiftAmt <= 63))
849 return 1;
850 return 0;
851}
852
853/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
854/// instruction \p MI.
855bool trySwapICmpOperands(MachineInstr &MI, MachineRegisterInfo &MRI) {
856 assert(MI.getOpcode() == TargetOpcode::G_ICMP);
857 // Swap the operands if it would introduce a profitable folding opportunity.
858 // (e.g. a shift + extend).
859 //
860 // For example:
861 // lsl w13, w11, #1
862 // cmp w13, w12
863 // can be turned into:
864 // cmp w12, w11, lsl #1
865
866 // Don't swap if there's a constant on the RHS, because we know we can fold
867 // that.
868 Register RHS = MI.getOperand(3).getReg();
869 auto RHSCst = getIConstantVRegValWithLookThrough(RHS, MRI);
870 if (RHSCst && isLegalArithImmed(RHSCst->Value.getSExtValue()))
871 return false;
872
873 Register LHS = MI.getOperand(2).getReg();
874 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
875 auto GetRegForProfit = [&](Register Reg) {
877 return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
878 };
879
880 // Don't have a constant on the RHS. If we swap the LHS and RHS of the
881 // compare, would we be able to fold more instructions?
882 Register TheLHS = GetRegForProfit(LHS);
883 Register TheRHS = GetRegForProfit(RHS);
884
885 // If the LHS is more likely to give us a folding opportunity, then swap the
886 // LHS and RHS.
887 return (getCmpOperandFoldingProfit(TheLHS, MRI) >
889}
890
891void applySwapICmpOperands(MachineInstr &MI, GISelChangeObserver &Observer) {
892 auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
893 Register LHS = MI.getOperand(2).getReg();
894 Register RHS = MI.getOperand(3).getReg();
895 Observer.changedInstr(MI);
896 MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
897 MI.getOperand(2).setReg(RHS);
898 MI.getOperand(3).setReg(LHS);
899 Observer.changedInstr(MI);
900}
901
902/// \returns a function which builds a vector floating point compare instruction
903/// for a condition code \p CC.
904/// \param [in] IsZero - True if the comparison is against 0.
905/// \param [in] NoNans - True if the target has NoNansFPMath.
906std::function<Register(MachineIRBuilder &)>
907getVectorFCMP(AArch64CC::CondCode CC, Register LHS, Register RHS, bool IsZero,
908 bool NoNans, MachineRegisterInfo &MRI) {
909 LLT DstTy = MRI.getType(LHS);
910 assert(DstTy.isVector() && "Expected vector types only?");
911 assert(DstTy == MRI.getType(RHS) && "Src and Dst types must match!");
912 switch (CC) {
913 default:
914 llvm_unreachable("Unexpected condition code!");
915 case AArch64CC::NE:
916 return [LHS, RHS, IsZero, DstTy](MachineIRBuilder &MIB) {
917 auto FCmp = IsZero
918 ? MIB.buildInstr(AArch64::G_FCMEQZ, {DstTy}, {LHS})
919 : MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS});
920 return MIB.buildNot(DstTy, FCmp).getReg(0);
921 };
922 case AArch64CC::EQ:
923 return [LHS, RHS, IsZero, DstTy](MachineIRBuilder &MIB) {
924 return IsZero
925 ? MIB.buildInstr(AArch64::G_FCMEQZ, {DstTy}, {LHS}).getReg(0)
926 : MIB.buildInstr(AArch64::G_FCMEQ, {DstTy}, {LHS, RHS})
927 .getReg(0);
928 };
929 case AArch64CC::GE:
930 return [LHS, RHS, IsZero, DstTy](MachineIRBuilder &MIB) {
931 return IsZero
932 ? MIB.buildInstr(AArch64::G_FCMGEZ, {DstTy}, {LHS}).getReg(0)
933 : MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {LHS, RHS})
934 .getReg(0);
935 };
936 case AArch64CC::GT:
937 return [LHS, RHS, IsZero, DstTy](MachineIRBuilder &MIB) {
938 return IsZero
939 ? MIB.buildInstr(AArch64::G_FCMGTZ, {DstTy}, {LHS}).getReg(0)
940 : MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {LHS, RHS})
941 .getReg(0);
942 };
943 case AArch64CC::LS:
944 return [LHS, RHS, IsZero, DstTy](MachineIRBuilder &MIB) {
945 return IsZero
946 ? MIB.buildInstr(AArch64::G_FCMLEZ, {DstTy}, {LHS}).getReg(0)
947 : MIB.buildInstr(AArch64::G_FCMGE, {DstTy}, {RHS, LHS})
948 .getReg(0);
949 };
950 case AArch64CC::MI:
951 return [LHS, RHS, IsZero, DstTy](MachineIRBuilder &MIB) {
952 return IsZero
953 ? MIB.buildInstr(AArch64::G_FCMLTZ, {DstTy}, {LHS}).getReg(0)
954 : MIB.buildInstr(AArch64::G_FCMGT, {DstTy}, {RHS, LHS})
955 .getReg(0);
956 };
957 }
958}
959
960/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
961bool matchLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
962 MachineIRBuilder &MIB) {
963 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
964 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
965
966 Register Dst = MI.getOperand(0).getReg();
967 LLT DstTy = MRI.getType(Dst);
968 if (!DstTy.isVector() || !ST.hasNEON())
969 return false;
970 Register LHS = MI.getOperand(2).getReg();
971 unsigned EltSize = MRI.getType(LHS).getScalarSizeInBits();
972 if (EltSize == 16 && !ST.hasFullFP16())
973 return false;
974 if (EltSize != 16 && EltSize != 32 && EltSize != 64)
975 return false;
976
977 return true;
978}
979
980/// Try to lower a vector G_FCMP \p MI into an AArch64-specific pseudo.
981void applyLowerVectorFCMP(MachineInstr &MI, MachineRegisterInfo &MRI,
982 MachineIRBuilder &MIB) {
983 assert(MI.getOpcode() == TargetOpcode::G_FCMP);
984 const auto &ST = MI.getMF()->getSubtarget<AArch64Subtarget>();
985
986 const auto &CmpMI = cast<GFCmp>(MI);
987
988 Register Dst = CmpMI.getReg(0);
989 CmpInst::Predicate Pred = CmpMI.getCond();
990 Register LHS = CmpMI.getLHSReg();
991 Register RHS = CmpMI.getRHSReg();
992
993 LLT DstTy = MRI.getType(Dst);
994
995 auto Splat = getAArch64VectorSplat(*MRI.getVRegDef(RHS), MRI);
996
997 // Compares against 0 have special target-specific pseudos.
998 bool IsZero = Splat && Splat->isCst() && Splat->getCst() == 0;
999
1000 bool Invert = false;
1002 if ((Pred == CmpInst::Predicate::FCMP_ORD ||
1003 Pred == CmpInst::Predicate::FCMP_UNO) &&
1004 IsZero) {
1005 // The special case "fcmp ord %a, 0" is the canonical check that LHS isn't
1006 // NaN, so equivalent to a == a and doesn't need the two comparisons an
1007 // "ord" normally would.
1008 // Similarly, "fcmp uno %a, 0" is the canonical check that LHS is NaN and is
1009 // thus equivalent to a != a.
1010 RHS = LHS;
1011 IsZero = false;
1012 CC = Pred == CmpInst::Predicate::FCMP_ORD ? AArch64CC::EQ : AArch64CC::NE;
1013 } else
1014 changeVectorFCMPPredToAArch64CC(Pred, CC, CC2, Invert);
1015
1016 // Instead of having an apply function, just build here to simplify things.
1018
1019 const bool NoNans =
1020 ST.getTargetLowering()->getTargetMachine().Options.NoNaNsFPMath;
1021
1022 auto Cmp = getVectorFCMP(CC, LHS, RHS, IsZero, NoNans, MRI);
1023 Register CmpRes;
1024 if (CC2 == AArch64CC::AL)
1025 CmpRes = Cmp(MIB);
1026 else {
1027 auto Cmp2 = getVectorFCMP(CC2, LHS, RHS, IsZero, NoNans, MRI);
1028 auto Cmp2Dst = Cmp2(MIB);
1029 auto Cmp1Dst = Cmp(MIB);
1030 CmpRes = MIB.buildOr(DstTy, Cmp1Dst, Cmp2Dst).getReg(0);
1031 }
1032 if (Invert)
1033 CmpRes = MIB.buildNot(DstTy, CmpRes).getReg(0);
1034 MRI.replaceRegWith(Dst, CmpRes);
1035 MI.eraseFromParent();
1036}
1037
1038bool matchFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1039 Register &SrcReg) {
1040 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1041 Register DstReg = MI.getOperand(0).getReg();
1042 if (MRI.getType(DstReg).isVector())
1043 return false;
1044 // Match a store of a truncate.
1045 if (!mi_match(DstReg, MRI, m_GTrunc(m_Reg(SrcReg))))
1046 return false;
1047 // Only form truncstores for value types of max 64b.
1048 return MRI.getType(SrcReg).getSizeInBits() <= 64;
1049}
1050
1051void applyFormTruncstore(MachineInstr &MI, MachineRegisterInfo &MRI,
1053 Register &SrcReg) {
1054 assert(MI.getOpcode() == TargetOpcode::G_STORE);
1055 Observer.changingInstr(MI);
1056 MI.getOperand(0).setReg(SrcReg);
1057 Observer.changedInstr(MI);
1058}
1059
1060// Lower vector G_SEXT_INREG back to shifts for selection. We allowed them to
1061// form in the first place for combine opportunities, so any remaining ones
1062// at this stage need be lowered back.
1063bool matchVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI) {
1064 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1065 Register DstReg = MI.getOperand(0).getReg();
1066 LLT DstTy = MRI.getType(DstReg);
1067 return DstTy.isVector();
1068}
1069
1070void applyVectorSextInReg(MachineInstr &MI, MachineRegisterInfo &MRI,
1072 assert(MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1073 B.setInstrAndDebugLoc(MI);
1074 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1075 Helper.lower(MI, 0, /* Unused hint type */ LLT());
1076}
1077
1078/// Combine <N x t>, unused = unmerge(G_EXT <2*N x t> v, undef, N)
1079/// => unused, <N x t> = unmerge v
1080bool matchUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1081 Register &MatchInfo) {
1082 auto &Unmerge = cast<GUnmerge>(MI);
1083 if (Unmerge.getNumDefs() != 2)
1084 return false;
1085 if (!MRI.use_nodbg_empty(Unmerge.getReg(1)))
1086 return false;
1087
1088 LLT DstTy = MRI.getType(Unmerge.getReg(0));
1089 if (!DstTy.isVector())
1090 return false;
1091
1092 MachineInstr *Ext = getOpcodeDef(AArch64::G_EXT, Unmerge.getSourceReg(), MRI);
1093 if (!Ext)
1094 return false;
1095
1096 Register ExtSrc1 = Ext->getOperand(1).getReg();
1097 Register ExtSrc2 = Ext->getOperand(2).getReg();
1098 auto LowestVal =
1099 getIConstantVRegValWithLookThrough(Ext->getOperand(3).getReg(), MRI);
1100 if (!LowestVal || LowestVal->Value.getZExtValue() != DstTy.getSizeInBytes())
1101 return false;
1102
1103 if (!getOpcodeDef<GImplicitDef>(ExtSrc2, MRI))
1104 return false;
1105
1106 MatchInfo = ExtSrc1;
1107 return true;
1108}
1109
1110void applyUnmergeExtToUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI,
1112 GISelChangeObserver &Observer, Register &SrcReg) {
1113 Observer.changingInstr(MI);
1114 // Swap dst registers.
1115 Register Dst1 = MI.getOperand(0).getReg();
1116 MI.getOperand(0).setReg(MI.getOperand(1).getReg());
1117 MI.getOperand(1).setReg(Dst1);
1118 MI.getOperand(2).setReg(SrcReg);
1119 Observer.changedInstr(MI);
1120}
1121
1122// Match mul({z/s}ext , {z/s}ext) => {u/s}mull OR
1123// Match v2s64 mul instructions, which will then be scalarised later on
1124// Doing these two matches in one function to ensure that the order of matching
1125// will always be the same.
1126// Try lowering MUL to MULL before trying to scalarize if needed.
1127bool matchExtMulToMULL(MachineInstr &MI, MachineRegisterInfo &MRI) {
1128 // Get the instructions that defined the source operand
1129 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1130 MachineInstr *I1 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
1131 MachineInstr *I2 = getDefIgnoringCopies(MI.getOperand(2).getReg(), MRI);
1132
1133 if (DstTy.isVector()) {
1134 // If the source operands were EXTENDED before, then {U/S}MULL can be used
1135 unsigned I1Opc = I1->getOpcode();
1136 unsigned I2Opc = I2->getOpcode();
1137 if (((I1Opc == TargetOpcode::G_ZEXT && I2Opc == TargetOpcode::G_ZEXT) ||
1138 (I1Opc == TargetOpcode::G_SEXT && I2Opc == TargetOpcode::G_SEXT)) &&
1139 (MRI.getType(I1->getOperand(0).getReg()).getScalarSizeInBits() ==
1140 MRI.getType(I1->getOperand(1).getReg()).getScalarSizeInBits() * 2) &&
1141 (MRI.getType(I2->getOperand(0).getReg()).getScalarSizeInBits() ==
1142 MRI.getType(I2->getOperand(1).getReg()).getScalarSizeInBits() * 2)) {
1143 return true;
1144 }
1145 // If result type is v2s64, scalarise the instruction
1146 else if (DstTy == LLT::fixed_vector(2, 64)) {
1147 return true;
1148 }
1149 }
1150 return false;
1151}
1152
1153void applyExtMulToMULL(MachineInstr &MI, MachineRegisterInfo &MRI,
1155 assert(MI.getOpcode() == TargetOpcode::G_MUL &&
1156 "Expected a G_MUL instruction");
1157
1158 // Get the instructions that defined the source operand
1159 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
1160 MachineInstr *I1 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
1161 MachineInstr *I2 = getDefIgnoringCopies(MI.getOperand(2).getReg(), MRI);
1162
1163 // If the source operands were EXTENDED before, then {U/S}MULL can be used
1164 unsigned I1Opc = I1->getOpcode();
1165 unsigned I2Opc = I2->getOpcode();
1166 if (((I1Opc == TargetOpcode::G_ZEXT && I2Opc == TargetOpcode::G_ZEXT) ||
1167 (I1Opc == TargetOpcode::G_SEXT && I2Opc == TargetOpcode::G_SEXT)) &&
1168 (MRI.getType(I1->getOperand(0).getReg()).getScalarSizeInBits() ==
1169 MRI.getType(I1->getOperand(1).getReg()).getScalarSizeInBits() * 2) &&
1170 (MRI.getType(I2->getOperand(0).getReg()).getScalarSizeInBits() ==
1171 MRI.getType(I2->getOperand(1).getReg()).getScalarSizeInBits() * 2)) {
1172
1173 B.setInstrAndDebugLoc(MI);
1174 B.buildInstr(I1->getOpcode() == TargetOpcode::G_ZEXT ? AArch64::G_UMULL
1175 : AArch64::G_SMULL,
1176 {MI.getOperand(0).getReg()},
1177 {I1->getOperand(1).getReg(), I2->getOperand(1).getReg()});
1178 MI.eraseFromParent();
1179 }
1180 // If result type is v2s64, scalarise the instruction
1181 else if (DstTy == LLT::fixed_vector(2, 64)) {
1182 LegalizerHelper Helper(*MI.getMF(), Observer, B);
1183 B.setInstrAndDebugLoc(MI);
1184 Helper.fewerElementsVector(
1185 MI, 0,
1186 DstTy.changeElementCount(
1188 }
1189}
1190
1191class AArch64PostLegalizerLoweringImpl : public Combiner {
1192protected:
1193 // TODO: Make CombinerHelper methods const.
1194 mutable CombinerHelper Helper;
1195 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig;
1196 const AArch64Subtarget &STI;
1197
1198public:
1199 AArch64PostLegalizerLoweringImpl(
1200 MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
1201 GISelCSEInfo *CSEInfo,
1202 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1203 const AArch64Subtarget &STI);
1204
1205 static const char *getName() { return "AArch6400PreLegalizerCombiner"; }
1206
1207 bool tryCombineAll(MachineInstr &I) const override;
1208
1209private:
1210#define GET_GICOMBINER_CLASS_MEMBERS
1211#include "AArch64GenPostLegalizeGILowering.inc"
1212#undef GET_GICOMBINER_CLASS_MEMBERS
1213};
1214
1215#define GET_GICOMBINER_IMPL
1216#include "AArch64GenPostLegalizeGILowering.inc"
1217#undef GET_GICOMBINER_IMPL
1218
1219AArch64PostLegalizerLoweringImpl::AArch64PostLegalizerLoweringImpl(
1220 MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
1221 GISelCSEInfo *CSEInfo,
1222 const AArch64PostLegalizerLoweringImplRuleConfig &RuleConfig,
1223 const AArch64Subtarget &STI)
1224 : Combiner(MF, CInfo, TPC, /*KB*/ nullptr, CSEInfo),
1225 Helper(Observer, B, /*IsPreLegalize*/ true), RuleConfig(RuleConfig),
1226 STI(STI),
1228#include "AArch64GenPostLegalizeGILowering.inc"
1230{
1231}
1232
1233class AArch64PostLegalizerLowering : public MachineFunctionPass {
1234public:
1235 static char ID;
1236
1237 AArch64PostLegalizerLowering();
1238
1239 StringRef getPassName() const override {
1240 return "AArch64PostLegalizerLowering";
1241 }
1242
1243 bool runOnMachineFunction(MachineFunction &MF) override;
1244 void getAnalysisUsage(AnalysisUsage &AU) const override;
1245
1246private:
1247 AArch64PostLegalizerLoweringImplRuleConfig RuleConfig;
1248};
1249} // end anonymous namespace
1250
1251void AArch64PostLegalizerLowering::getAnalysisUsage(AnalysisUsage &AU) const {
1253 AU.setPreservesCFG();
1256}
1257
1258AArch64PostLegalizerLowering::AArch64PostLegalizerLowering()
1261
1262 if (!RuleConfig.parseCommandLineOption())
1263 report_fatal_error("Invalid rule identifier");
1264}
1265
1266bool AArch64PostLegalizerLowering::runOnMachineFunction(MachineFunction &MF) {
1267 if (MF.getProperties().hasProperty(
1268 MachineFunctionProperties::Property::FailedISel))
1269 return false;
1271 MachineFunctionProperties::Property::Legalized) &&
1272 "Expected a legalized function?");
1273 auto *TPC = &getAnalysis<TargetPassConfig>();
1274 const Function &F = MF.getFunction();
1275
1277 CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
1278 /*LegalizerInfo*/ nullptr, /*OptEnabled=*/true,
1279 F.hasOptSize(), F.hasMinSize());
1280 AArch64PostLegalizerLoweringImpl Impl(MF, CInfo, TPC, /*CSEInfo*/ nullptr,
1281 RuleConfig, ST);
1282 return Impl.combineMachineInstrs();
1283}
1284
1285char AArch64PostLegalizerLowering::ID = 0;
1286INITIALIZE_PASS_BEGIN(AArch64PostLegalizerLowering, DEBUG_TYPE,
1287 "Lower AArch64 MachineInstrs after legalization", false,
1288 false)
1290INITIALIZE_PASS_END(AArch64PostLegalizerLowering, DEBUG_TYPE,
1291 "Lower AArch64 MachineInstrs after legalization", false,
1292 false)
1293
1294namespace llvm {
1296 return new AArch64PostLegalizerLowering();
1297}
1298} // end namespace llvm
unsigned const MachineRegisterInfo * MRI
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 isLegalArithImmed(uint64_t C)
static bool isINSMask(ArrayRef< int > M, int NumInputElements, bool &DstIsLeft, int &Anomaly)
static unsigned getCmpOperandFoldingProfit(SDValue Op)
Returns how profitable it is to fold a comparison's operand's shift and/or extension operations.
static bool isCMN(SDValue Op, ISD::CondCode CC)
This file declares the targeting of the Machinelegalizer class for AArch64.
#define GET_GICOMBINER_CONSTRUCTOR_INITS
Lower AArch64 MachineInstrs after legalization
#define DEBUG_TYPE
basic Basic Alias true
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.
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Size
This contains common code to allow clients to notify changes to machine instr.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define P(N)
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:55
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:59
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Target-Independent Code Generator Pass Configuration Options pass.
Value * RHS
Value * LHS
BinaryOperator * Mul
Class for arbitrary precision integers.
Definition: APInt.h:76
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1491
unsigned logBase2() const
Definition: APInt.h:1703
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:269
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:993
@ ICMP_SLT
signed less than
Definition: InstrTypes.h:1022
@ ICMP_SLE
signed less or equal
Definition: InstrTypes.h:1023
@ ICMP_UGE
unsigned greater or equal
Definition: InstrTypes.h:1017
@ ICMP_UGT
unsigned greater than
Definition: InstrTypes.h:1016
@ ICMP_SGT
signed greater than
Definition: InstrTypes.h:1020
@ ICMP_ULT
unsigned less than
Definition: InstrTypes.h:1018
@ ICMP_SGE
signed greater or equal
Definition: InstrTypes.h:1021
@ ICMP_ULE
unsigned less or equal
Definition: InstrTypes.h:1019
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Definition: InstrTypes.h:1167
Combiner implementation.
Definition: Combiner.h:34
virtual bool tryCombineAll(MachineInstr &I) const =0
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
The CSE Analysis object.
Definition: CSEInfo.h:69
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.
constexpr unsigned getScalarSizeInBits() const
Definition: LowLevelType.h:267
constexpr LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
Definition: LowLevelType.h:254
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
Definition: LowLevelType.h:159
constexpr bool isVector() const
Definition: LowLevelType.h:148
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
Definition: LowLevelType.h:57
constexpr bool isScalable() const
Returns true if the LLT is a scalable vector.
Definition: LowLevelType.h:170
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:193
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
Definition: LowLevelType.h:290
constexpr ElementCount getElementCount() const
Definition: LowLevelType.h:184
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
Definition: LowLevelType.h:100
constexpr LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
Definition: LowLevelType.h:230
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
Definition: LowLevelType.h:203
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
bool hasProperty(Property P) const
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 buildMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_MUL Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildExtractVectorElement(const DstOp &Res, const SrcOp &Val, const SrcOp &Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildFrameIndex(const DstOp &Res, int Idx)
Build and insert Res = G_FRAME_INDEX Idx.
MachineFunction & getMF()
Getter for the function we currently build.
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.
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.
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.
Definition: MachineInstr.h:69
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:558
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:568
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,...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Target-Independent Code Generator Pass Configuration Options.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition: TypeSize.h:168
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:251
#define UINT64_MAX
Definition: DataTypes.h:77
#define INT64_MIN
Definition: DataTypes.h:74
#define INT64_MAX
Definition: DataTypes.h:71
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::optional< RegOrConstant > getAArch64VectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
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.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
Definition: BitmaskEnum.h:121
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
operand_type_match m_Reg()
SpecificConstantMatch m_ZeroInt()
{ Convenience matchers for specific integer values.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
@ Undef
Value of the register doesn't matter.
Reg
All possible values of the reg field in the ModR/M byte.
NodeAddr< DefNode * > Def
Definition: RDFGraph.h:384
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456
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:627
void initializeAArch64PostLegalizerLoweringPass(PassRegistry &)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
bool isTRNMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResult)
Return true for trn1 or trn2 masks of the form: <0, 8, 2, 10, 4, 12, 6, 14> or <1,...
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition: MathExtras.h:280
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition: Utils.cpp:467
FunctionPass * createAArch64PostLegalizerLowering()
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1729
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:156
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.
void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition: Utils.cpp:1142
bool isZIPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut)
Return true for zip1 or zip2 masks of the form: <0, 8, 1, 9, 2, 10, 3, 11> or <4, 12,...
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:415
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1749
int getSplatIndex(ArrayRef< int > Mask)
If all non-negative Mask elements are the same value, return that value.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.