LLVM 24.0.0git
AArch64ISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- AArch64ISelDAGToDAG.cpp - A dag to dag inst selector for AArch64 --===//
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// This file defines an instruction selector for the AArch64 target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AArch64.h"
14#include "AArch64ExpandImm.h"
18#include "llvm/ADT/APSInt.h"
22#include "llvm/IR/Function.h" // To access function attributes.
23#include "llvm/IR/GlobalValue.h"
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/IR/IntrinsicsAArch64.h"
26#include "llvm/Support/Debug.h"
31
32using namespace llvm;
33using namespace llvm::SDPatternMatch;
34
35#define DEBUG_TYPE "aarch64-isel"
36#define PASS_NAME "AArch64 Instruction Selection"
37
38// https://github.com/llvm/llvm-project/issues/114425
39#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
40#pragma inline_depth(0)
41#endif
42
43//===--------------------------------------------------------------------===//
44/// AArch64DAGToDAGISel - AArch64 specific code to select AArch64 machine
45/// instructions for SelectionDAG operations.
46///
47namespace {
48
49class AArch64DAGToDAGISel : public SelectionDAGISel {
50
51 /// Subtarget - Keep a pointer to the AArch64Subtarget around so that we can
52 /// make the right decision when generating code for different targets.
53 const AArch64Subtarget *Subtarget;
54
55public:
56 AArch64DAGToDAGISel() = delete;
57
58 explicit AArch64DAGToDAGISel(AArch64TargetMachine &tm,
59 CodeGenOptLevel OptLevel)
60 : SelectionDAGISel(tm, OptLevel), Subtarget(nullptr) {}
61
62 bool runOnMachineFunction(MachineFunction &MF) override {
63 Subtarget = &MF.getSubtarget<AArch64Subtarget>();
65 }
66
67 void Select(SDNode *Node) override;
68 void PreprocessISelDAG() override;
69
70 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
71 /// inline asm expressions.
72 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
73 InlineAsm::ConstraintCode ConstraintID,
74 std::vector<SDValue> &OutOps) override;
75
76 template <signed Low, signed High, signed Scale>
77 bool SelectRDVLImm(SDValue N, SDValue &Imm);
78
79 template <signed Low, signed High>
80 bool SelectRDSVLShiftImm(SDValue N, SDValue &Imm);
81
82 bool SelectArithExtendedRegister(SDValue N, SDValue &Reg, SDValue &Shift);
83 bool SelectArithUXTXRegister(SDValue N, SDValue &Reg, SDValue &Shift);
84 bool SelectArithImmed(SDValue N, SDValue &Val, SDValue &Shift);
85 bool SelectNegArithImmed(SDValue N, SDValue &Val, SDValue &Shift);
86 bool SelectArithShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) {
87 return SelectShiftedRegister(N, false, Reg, Shift);
88 }
89 bool SelectLogicalShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) {
90 return SelectShiftedRegister(N, true, Reg, Shift);
91 }
92 bool SelectAddrModeIndexed7S8(SDValue N, SDValue &Base, SDValue &OffImm) {
93 return SelectAddrModeIndexed7S(N, 1, Base, OffImm);
94 }
95 bool SelectAddrModeIndexed7S16(SDValue N, SDValue &Base, SDValue &OffImm) {
96 return SelectAddrModeIndexed7S(N, 2, Base, OffImm);
97 }
98 bool SelectAddrModeIndexed7S32(SDValue N, SDValue &Base, SDValue &OffImm) {
99 return SelectAddrModeIndexed7S(N, 4, Base, OffImm);
100 }
101 bool SelectAddrModeIndexed7S64(SDValue N, SDValue &Base, SDValue &OffImm) {
102 return SelectAddrModeIndexed7S(N, 8, Base, OffImm);
103 }
104 bool SelectAddrModeIndexed7S128(SDValue N, SDValue &Base, SDValue &OffImm) {
105 return SelectAddrModeIndexed7S(N, 16, Base, OffImm);
106 }
107 bool SelectAddrModeIndexedS9S128(SDValue N, SDValue &Base, SDValue &OffImm) {
108 return SelectAddrModeIndexedBitWidth(N, true, 9, 16, Base, OffImm);
109 }
110 bool SelectAddrModeIndexedU6S128(SDValue N, SDValue &Base, SDValue &OffImm) {
111 return SelectAddrModeIndexedBitWidth(N, false, 6, 16, Base, OffImm);
112 }
113 bool SelectAddrModeIndexed8(SDValue N, SDValue &Base, SDValue &OffImm) {
114 return SelectAddrModeIndexed(N, 1, Base, OffImm);
115 }
116 bool SelectAddrModeIndexed16(SDValue N, SDValue &Base, SDValue &OffImm) {
117 return SelectAddrModeIndexed(N, 2, Base, OffImm);
118 }
119 bool SelectAddrModeIndexed32(SDValue N, SDValue &Base, SDValue &OffImm) {
120 return SelectAddrModeIndexed(N, 4, Base, OffImm);
121 }
122 bool SelectAddrModeIndexed64(SDValue N, SDValue &Base, SDValue &OffImm) {
123 return SelectAddrModeIndexed(N, 8, Base, OffImm);
124 }
125 bool SelectAddrModeIndexed128(SDValue N, SDValue &Base, SDValue &OffImm) {
126 return SelectAddrModeIndexed(N, 16, Base, OffImm);
127 }
128 bool SelectAddrModeUnscaled8(SDValue N, SDValue &Base, SDValue &OffImm) {
129 return SelectAddrModeUnscaled(N, 1, Base, OffImm);
130 }
131 bool SelectAddrModeUnscaled16(SDValue N, SDValue &Base, SDValue &OffImm) {
132 return SelectAddrModeUnscaled(N, 2, Base, OffImm);
133 }
134 bool SelectAddrModeUnscaled32(SDValue N, SDValue &Base, SDValue &OffImm) {
135 return SelectAddrModeUnscaled(N, 4, Base, OffImm);
136 }
137 bool SelectAddrModeUnscaled64(SDValue N, SDValue &Base, SDValue &OffImm) {
138 return SelectAddrModeUnscaled(N, 8, Base, OffImm);
139 }
140 bool SelectAddrModeUnscaled128(SDValue N, SDValue &Base, SDValue &OffImm) {
141 return SelectAddrModeUnscaled(N, 16, Base, OffImm);
142 }
143 template <unsigned Size, unsigned Max>
144 bool SelectAddrModeIndexedUImm(SDValue N, SDValue &Base, SDValue &OffImm) {
145 // Test if there is an appropriate addressing mode and check if the
146 // immediate fits.
147 bool Found = SelectAddrModeIndexed(N, Size, Base, OffImm);
148 if (Found) {
149 if (auto *CI = dyn_cast<ConstantSDNode>(OffImm)) {
150 int64_t C = CI->getSExtValue();
151 if (C <= Max)
152 return true;
153 }
154 }
155
156 // Otherwise, base only, materialize address in register.
157 Base = N;
158 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64);
159 return true;
160 }
161
162 template<int Width>
163 bool SelectAddrModeWRO(SDValue N, SDValue &Base, SDValue &Offset,
164 SDValue &SignExtend, SDValue &DoShift) {
165 return SelectAddrModeWRO(N, Width / 8, Base, Offset, SignExtend, DoShift);
166 }
167
168 template<int Width>
169 bool SelectAddrModeXRO(SDValue N, SDValue &Base, SDValue &Offset,
170 SDValue &SignExtend, SDValue &DoShift) {
171 return SelectAddrModeXRO(N, Width / 8, Base, Offset, SignExtend, DoShift);
172 }
173
174 bool SelectExtractHigh(SDValue N, SDValue &Res) {
175 if (Subtarget->isLittleEndian() && N->getOpcode() == ISD::BITCAST)
176 N = N->getOperand(0);
177 if (N->getOpcode() != ISD::EXTRACT_SUBVECTOR ||
178 !isa<ConstantSDNode>(N->getOperand(1)))
179 return false;
180 EVT VT = N->getValueType(0);
181 EVT LVT = N->getOperand(0).getValueType();
182 unsigned Index = N->getConstantOperandVal(1);
183 if (!VT.is64BitVector() || !LVT.is128BitVector() ||
184 Index != VT.getVectorNumElements())
185 return false;
186 Res = N->getOperand(0);
187 return true;
188 }
189
190 bool SelectRoundingVLShr(SDValue N, SDValue &Res1, SDValue &Res2) {
191 if (N.getOpcode() != AArch64ISD::VLSHR)
192 return false;
193 SDValue Op = N->getOperand(0);
194 EVT VT = Op.getValueType();
195 unsigned ShtAmt = N->getConstantOperandVal(1);
196 if (ShtAmt > VT.getScalarSizeInBits() / 2 || Op.getOpcode() != ISD::ADD)
197 return false;
198
199 APInt Imm;
200 if (Op.getOperand(1).getOpcode() == AArch64ISD::MOVIshift)
201 Imm = APInt(VT.getScalarSizeInBits(),
202 Op.getOperand(1).getConstantOperandVal(0)
203 << Op.getOperand(1).getConstantOperandVal(1));
204 else if (Op.getOperand(1).getOpcode() == AArch64ISD::DUP &&
205 isa<ConstantSDNode>(Op.getOperand(1).getOperand(0)))
206 Imm = APInt(VT.getScalarSizeInBits(),
207 Op.getOperand(1).getConstantOperandVal(0));
208 else
209 return false;
210
211 if (Imm != 1ULL << (ShtAmt - 1))
212 return false;
213
214 Res1 = Op.getOperand(0);
215 Res2 = CurDAG->getTargetConstant(ShtAmt, SDLoc(N), MVT::i32);
216 return true;
217 }
218
219 bool SelectDupZeroOrUndef(SDValue N) {
220 switch(N->getOpcode()) {
221 case ISD::UNDEF:
222 case ISD::POISON:
223 return true;
224 case AArch64ISD::DUP:
225 case ISD::SPLAT_VECTOR: {
226 auto Opnd0 = N->getOperand(0);
227 if (isNullConstant(Opnd0))
228 return true;
229 if (isNullFPConstant(Opnd0))
230 return true;
231 break;
232 }
233 default:
234 break;
235 }
236
237 return false;
238 }
239
240 bool SelectAny(SDValue) { return true; }
241
242 bool SelectDupZero(SDValue N) {
243 switch(N->getOpcode()) {
244 case AArch64ISD::DUP:
245 case ISD::SPLAT_VECTOR: {
246 auto Opnd0 = N->getOperand(0);
247 if (isNullConstant(Opnd0))
248 return true;
249 if (isNullFPConstant(Opnd0))
250 return true;
251 break;
252 }
253 }
254
255 return false;
256 }
257
258 template <MVT::SimpleValueType VT, bool Negate>
259 bool SelectSVEAddSubImm(SDValue N, SDValue &Imm, SDValue &Shift) {
260 return SelectSVEAddSubImm(N, VT, Imm, Shift, Negate);
261 }
262
263 template <MVT::SimpleValueType VT, bool Negate>
264 bool SelectSVEAddSubSSatImm(SDValue N, SDValue &Imm, SDValue &Shift) {
265 return SelectSVEAddSubSSatImm(N, VT, Imm, Shift, Negate);
266 }
267
268 template <MVT::SimpleValueType VT>
269 bool SelectSVECpyDupImm(SDValue N, SDValue &Imm, SDValue &Shift) {
270 return SelectSVECpyDupImm(N, VT, Imm, Shift);
271 }
272
273 template <MVT::SimpleValueType VT, bool Invert = false>
274 bool SelectSVELogicalImm(SDValue N, SDValue &Imm) {
275 return SelectSVELogicalImm(N, VT, Imm, Invert);
276 }
277
278 template <MVT::SimpleValueType VT>
279 bool SelectSVEArithImm(SDValue N, SDValue &Imm) {
280 return SelectSVEArithImm(N, VT, Imm);
281 }
282
283 template <unsigned Low, unsigned High, bool AllowSaturation = false>
284 bool SelectSVEShiftImm(SDValue N, SDValue &Imm) {
285 return SelectSVEShiftImm(N, Low, High, AllowSaturation, Imm);
286 }
287
288 bool SelectSVEShiftSplatImmR(SDValue N, SDValue &Imm) {
289 if (N->getOpcode() != ISD::SPLAT_VECTOR)
290 return false;
291
292 EVT EltVT = N->getValueType(0).getVectorElementType();
293 return SelectSVEShiftImm(N->getOperand(0), /* Low */ 1,
294 /* High */ EltVT.getFixedSizeInBits(),
295 /* AllowSaturation */ true, Imm);
296 }
297
298 // Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N.
299 template<signed Min, signed Max, signed Scale, bool Shift>
300 bool SelectCntImm(SDValue N, SDValue &Imm) {
302 return false;
303
304 int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue();
305 if (Shift)
306 MulImm = 1LL << MulImm;
307
308 if ((MulImm % std::abs(Scale)) != 0)
309 return false;
310
311 MulImm /= Scale;
312 if ((MulImm >= Min) && (MulImm <= Max)) {
313 Imm = CurDAG->getTargetConstant(MulImm, SDLoc(N), MVT::i32);
314 return true;
315 }
316
317 return false;
318 }
319
320 template <signed Max, signed Scale>
321 bool SelectEXTImm(SDValue N, SDValue &Imm) {
323 return false;
324
325 int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue();
326
327 if (MulImm >= 0 && MulImm <= Max) {
328 MulImm *= Scale;
329 Imm = CurDAG->getTargetConstant(MulImm, SDLoc(N), MVT::i32);
330 return true;
331 }
332
333 return false;
334 }
335
336 template <unsigned BaseReg, unsigned Max>
337 bool ImmToReg(SDValue N, SDValue &Imm) {
338 if (auto *CI = dyn_cast<ConstantSDNode>(N)) {
339 uint64_t C = CI->getZExtValue();
340
341 if (C > Max)
342 return false;
343
344 Imm = CurDAG->getRegister(BaseReg + C, MVT::Other);
345 return true;
346 }
347 return false;
348 }
349
350 /// Form sequences of consecutive 64/128-bit registers for use in NEON
351 /// instructions making use of a vector-list (e.g. ldN, tbl). Vecs must have
352 /// between 1 and 4 elements. If it contains a single element that is returned
353 /// unchanged; otherwise a REG_SEQUENCE value is returned.
356 // Form a sequence of SVE registers for instructions using list of vectors,
357 // e.g. structured loads and stores (ldN, stN).
358 SDValue createZTuple(ArrayRef<SDValue> Vecs);
359
360 // Similar to above, except the register must start at a multiple of the
361 // tuple, e.g. z2 for a 2-tuple, or z8 for a 4-tuple.
362 SDValue createZMulTuple(ArrayRef<SDValue> Regs);
363
364 /// Generic helper for the createDTuple/createQTuple
365 /// functions. Those should almost always be called instead.
366 SDValue createTuple(ArrayRef<SDValue> Vecs, const unsigned RegClassIDs[],
367 const unsigned SubRegs[]);
368
369 void SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc, bool isExt);
370
371 bool tryIndexedLoad(SDNode *N);
372
373 void SelectPtrauthAuth(SDNode *N);
374 void SelectPtrauthResign(SDNode *N);
375 void SelectPtrauthResignWithPC(SDNode *N);
376
377 bool trySelectStackSlotTagP(SDNode *N);
378 void SelectTagP(SDNode *N);
379
380 void SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc,
381 unsigned SubRegIdx);
382 void SelectPostLoad(SDNode *N, unsigned NumVecs, unsigned Opc,
383 unsigned SubRegIdx);
384 void SelectLoadLane(SDNode *N, unsigned NumVecs, unsigned Opc);
385 void SelectPostLoadLane(SDNode *N, unsigned NumVecs, unsigned Opc);
386 void SelectPredicatedLoad(SDNode *N, unsigned NumVecs, unsigned Scale,
387 unsigned Opc_rr, unsigned Opc_ri,
388 bool IsIntr = false);
389 void SelectContiguousMultiVectorLoad(SDNode *N, unsigned NumVecs,
390 unsigned Scale, unsigned Opc_ri,
391 unsigned Opc_rr);
392 void SelectDestructiveMultiIntrinsic(SDNode *N, unsigned NumVecs,
393 bool IsZmMulti, unsigned Opcode,
394 bool HasPred = false);
395 void SelectPExtPair(SDNode *N, unsigned Opc);
396 void SelectWhilePair(SDNode *N, unsigned Opc);
397 void SelectCVTIntrinsic(SDNode *N, unsigned NumVecs, unsigned Opcode);
398 void SelectCVTIntrinsicFP8(SDNode *N, unsigned NumVecs, unsigned Opcode);
399 void SelectClamp(SDNode *N, unsigned NumVecs, unsigned Opcode);
400 void SelectUnaryMultiIntrinsic(SDNode *N, unsigned NumOutVecs,
401 bool IsTupleInput, unsigned Opc);
402 void SelectFrintFromVT(SDNode *N, unsigned NumVecs, unsigned Opcode);
403
404 template <unsigned MaxIdx, unsigned Scale>
405 void SelectMultiVectorMove(SDNode *N, unsigned NumVecs, unsigned BaseReg,
406 unsigned Op);
407 void SelectMultiVectorMoveZ(SDNode *N, unsigned NumVecs,
408 unsigned Op, unsigned MaxIdx, unsigned Scale,
409 unsigned BaseReg = 0);
410 /// SVE Reg+Imm addressing mode.
411 template <int64_t Min, int64_t Max>
412 bool SelectAddrModeIndexedSVE(SDNode *Root, SDValue N, SDValue &Base,
413 SDValue &OffImm);
414 /// SVE Reg+Reg address mode.
415 template <unsigned Scale>
416 bool SelectSVERegRegAddrMode(SDValue N, SDValue &Base, SDValue &Offset) {
417 return SelectSVERegRegAddrMode(N, Scale, Base, Offset);
418 }
419
420 void SelectMultiVectorLutiLane(SDNode *Node, unsigned NumOutVecs,
421 unsigned Opc, uint32_t MaxImm);
422 void SelectMultiVectorLuti6LaneX4(SDNode *Node, unsigned NumIndexVecs);
423
424 void SelectMultiVectorLuti(SDNode *Node, unsigned NumOutVecs, unsigned Opc,
425 unsigned NumInVecs);
426
427 template <unsigned MaxIdx, unsigned Scale>
428 bool SelectSMETileSlice(SDValue N, SDValue &Vector, SDValue &Offset) {
429 return SelectSMETileSlice(N, MaxIdx, Vector, Offset, Scale);
430 }
431
432 void SelectStore(SDNode *N, unsigned NumVecs, unsigned Opc);
433 void SelectPostStore(SDNode *N, unsigned NumVecs, unsigned Opc);
434 void SelectStoreLane(SDNode *N, unsigned NumVecs, unsigned Opc);
435 void SelectPostStoreLane(SDNode *N, unsigned NumVecs, unsigned Opc);
436 void SelectPredicatedStore(SDNode *N, unsigned NumVecs, unsigned Scale,
437 unsigned Opc_rr, unsigned Opc_ri);
438 std::tuple<unsigned, SDValue, SDValue>
439 findAddrModeSVELoadStore(SDNode *N, unsigned Opc_rr, unsigned Opc_ri,
440 const SDValue &OldBase, const SDValue &OldOffset,
441 unsigned Scale);
442
443 bool tryBitfieldExtractOp(SDNode *N);
444 bool tryBitfieldExtractOpFromSExt(SDNode *N);
445 bool tryBitfieldInsertOp(SDNode *N);
446 bool tryBitfieldInsertInZeroOp(SDNode *N);
447 bool tryShiftAmountMod(SDNode *N);
448
449 bool tryReadRegister(SDNode *N);
450 bool tryWriteRegister(SDNode *N);
451
452 bool trySelectCastFixedLengthToScalableVector(SDNode *N);
453 bool trySelectCastScalableToFixedLengthVector(SDNode *N);
454
455 bool trySelectXAR(SDNode *N);
456
457 bool tryFoldCselToFMaxMin(SDNode *N);
458
459// Include the pieces autogenerated from the target description.
460#include "AArch64GenDAGISel.inc"
461
462private:
463 bool SelectShiftedRegister(SDValue N, bool AllowROR, SDValue &Reg,
464 SDValue &Shift);
465 bool SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg, SDValue &Shift);
466 bool SelectAddrModeIndexed7S(SDValue N, unsigned Size, SDValue &Base,
467 SDValue &OffImm) {
468 return SelectAddrModeIndexedBitWidth(N, true, 7, Size, Base, OffImm);
469 }
470 bool SelectAddrModeIndexedBitWidth(SDValue N, bool IsSignedImm, unsigned BW,
471 unsigned Size, SDValue &Base,
472 SDValue &OffImm);
473 bool SelectAddrModeIndexed(SDValue N, unsigned Size, SDValue &Base,
474 SDValue &OffImm);
475 bool SelectAddrModeUnscaled(SDValue N, unsigned Size, SDValue &Base,
476 SDValue &OffImm);
477 bool SelectAddrModeWRO(SDValue N, unsigned Size, SDValue &Base,
478 SDValue &Offset, SDValue &SignExtend,
479 SDValue &DoShift);
480 bool SelectAddrModeXRO(SDValue N, unsigned Size, SDValue &Base,
481 SDValue &Offset, SDValue &SignExtend,
482 SDValue &DoShift);
483 bool isWorthNegatingImm(SDValue V) const;
484 bool isWorthFoldingALU(SDValue V, bool LSL = false) const;
485 bool isWorthFoldingAddr(SDValue V, unsigned Size) const;
486 bool SelectExtendedSHL(SDValue N, unsigned Size, bool WantExtend,
487 SDValue &Offset, SDValue &SignExtend);
488
489 template<unsigned RegWidth>
490 bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos) {
491 return SelectCVTFixedPosOperand(N, FixedPos, RegWidth);
492 }
493 bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, unsigned Width);
494
495 template <unsigned RegWidth>
496 bool SelectCVTFixedPointVec(SDValue N, SDValue &FixedPos) {
497 return SelectCVTFixedPointVec(N, FixedPos, RegWidth);
498 }
499 bool SelectCVTFixedPointVec(SDValue N, SDValue &FixedPos, unsigned Width);
500
501 template<unsigned RegWidth>
502 bool SelectCVTFixedPosRecipOperand(SDValue N, SDValue &FixedPos) {
503 return SelectCVTFixedPosRecipOperand(N, FixedPos, RegWidth);
504 }
505
506 bool SelectCVTFixedPosRecipOperand(SDValue N, SDValue &FixedPos,
507 unsigned Width);
508
509 template <unsigned FloatWidth>
510 bool SelectCVTFixedPosRecipOperandVec(SDValue N, SDValue &FixedPos) {
511 return SelectCVTFixedPosRecipOperandVec(N, FixedPos, FloatWidth);
512 }
513
514 bool SelectCVTFixedPosRecipOperandVec(SDValue N, SDValue &FixedPos,
515 unsigned Width);
516
517 bool SelectCMP_SWAP(SDNode *N);
518
519 bool SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift,
520 bool Negate);
521 bool SelectSVEAddSubImm(SDLoc DL, APInt Value, MVT VT, SDValue &Imm,
522 SDValue &Shift, bool Negate);
523 bool SelectSVEAddSubSSatImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift,
524 bool Negate);
525 bool SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift);
526 bool SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm, bool Invert);
527
528 // Match `<NEON Splat> SVEImm` (where <NEON Splat> could be fmov, movi, etc).
529 bool SelectNEONSplatOfSVELogicalImm(SDValue N, SDValue &Imm);
530 bool SelectNEONSplatOfSVEAddSubImm(SDValue N, SDValue &Imm, SDValue &Shift);
531 bool SelectNEONSplatOfSVEArithSImm(SDValue N, SDValue &Imm);
532 bool SelectNEONSplatOfSImm8(SDValue N, SDValue &Imm);
533 bool SelectNEONSplatOfUImm8(SDValue N, SDValue &Imm);
534
535 bool SelectSVESignedArithImm(SDLoc DL, APInt Value, SDValue &Imm);
536 bool SelectSVESignedArithImm(SDValue N, SDValue &Imm);
537 bool SelectSVEShiftImm(SDValue N, uint64_t Low, uint64_t High,
538 bool AllowSaturation, SDValue &Imm);
539
540 bool SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm);
541 bool SelectSVERegRegAddrMode(SDValue N, unsigned Scale, SDValue &Base,
542 SDValue &Offset);
543 bool SelectSMETileSlice(SDValue N, unsigned MaxSize, SDValue &Vector,
544 SDValue &Offset, unsigned Scale = 1);
545
546 bool SelectAllActivePredicate(SDValue N);
547 bool SelectAnyPredicate(SDValue N);
548
549 bool SelectCmpBranchUImm6Operand(SDNode *P, SDValue N, SDValue &Imm);
550
551 template <bool MatchCBB>
552 bool SelectCmpBranchExtOperand(SDValue N, SDValue &Reg, SDValue &ExtType);
553};
554
555class AArch64DAGToDAGISelLegacy : public SelectionDAGISelLegacy {
556public:
557 static char ID;
558 explicit AArch64DAGToDAGISelLegacy(AArch64TargetMachine &tm,
559 CodeGenOptLevel OptLevel)
561 ID, std::make_unique<AArch64DAGToDAGISel>(tm, OptLevel)) {}
562};
563} // end anonymous namespace
564
565char AArch64DAGToDAGISelLegacy::ID = 0;
566
567INITIALIZE_PASS(AArch64DAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
568
571 std::make_unique<AArch64DAGToDAGISel>(TM, TM.getOptLevel())) {}
572
573/// addBitcastHints - This method adds bitcast hints to the operands of a node
574/// to help instruction selector determine which operands are in Neon registers.
576 SDLoc DL(&N);
577 auto getFloatVT = [&](EVT VT) {
578 EVT ScalarVT = VT.getScalarType();
579 assert((ScalarVT == MVT::i32 || ScalarVT == MVT::i64) && "Unexpected VT");
580 return VT.changeElementType(*(DAG.getContext()),
581 ScalarVT == MVT::i32 ? MVT::f32 : MVT::f64);
582 };
584 NewOps.reserve(N.getNumOperands());
585
586 for (unsigned I = 0, E = N.getNumOperands(); I < E; ++I) {
587 auto bitcasted = DAG.getBitcast(getFloatVT(N.getOperand(I).getValueType()),
588 N.getOperand(I));
589 NewOps.push_back(bitcasted);
590 }
591 EVT OrigVT = N.getValueType(0);
592 SDValue OpNode = DAG.getNode(N.getOpcode(), DL, getFloatVT(OrigVT), NewOps);
593 return DAG.getBitcast(OrigVT, OpNode);
594}
595
596/// isIntImmediate - This method tests to see if the node is a constant
597/// operand. If so Imm will receive the 64-bit value.
598static bool isIntImmediate(const SDNode *N, uint64_t &Imm) {
600 Imm = C->getZExtValue();
601 return true;
602 }
603 return false;
604}
605
606// isIntImmediate - This method tests to see if a constant operand.
607// If so Imm will receive the value.
608static bool isIntImmediate(SDValue N, uint64_t &Imm) {
609 return isIntImmediate(N.getNode(), Imm);
610}
611
612// isOpcWithIntImmediate - This method tests to see if the node is a specific
613// opcode and that it has a immediate integer right operand.
614// If so Imm will receive the 32 bit value.
615static bool isOpcWithIntImmediate(const SDNode *N, unsigned Opc,
616 uint64_t &Imm) {
617 return N->getOpcode() == Opc &&
618 isIntImmediate(N->getOperand(1).getNode(), Imm);
619}
620
621// isIntImmediateEq - This method tests to see if N is a constant operand that
622// is equivalent to 'ImmExpected'.
623#ifndef NDEBUG
624static bool isIntImmediateEq(SDValue N, const uint64_t ImmExpected) {
625 uint64_t Imm;
626 if (!isIntImmediate(N.getNode(), Imm))
627 return false;
628 return Imm == ImmExpected;
629}
630#endif
631
632static APInt DecodeFMOVImm(uint64_t Imm, unsigned RegWidth) {
633 assert(RegWidth == 32 || RegWidth == 64);
634 if (RegWidth == 32)
635 return APInt(RegWidth,
637 return APInt(RegWidth, AArch64_AM::decodeAdvSIMDModImmType12(Imm));
638}
639
640// Decodes the raw integer splat value from a NEON splat operation.
641static std::optional<APInt> DecodeNEONSplat(SDValue N) {
642 assert(N.getValueType().isInteger() && "Only integers are supported");
643 if (N->getOpcode() == AArch64ISD::NVCAST)
644 N = N->getOperand(0);
645 unsigned SplatWidth = N.getScalarValueSizeInBits();
646 if (N.getOpcode() == AArch64ISD::FMOV)
647 return DecodeFMOVImm(N.getConstantOperandVal(0), SplatWidth);
648 if (N->getOpcode() == AArch64ISD::MOVI)
649 return APInt(SplatWidth, N.getConstantOperandVal(0));
650 if (N->getOpcode() == AArch64ISD::MOVIshift)
651 return APInt(SplatWidth, N.getConstantOperandVal(0)
652 << N.getConstantOperandVal(1));
653 if (N->getOpcode() == AArch64ISD::MVNIshift)
654 return ~APInt(SplatWidth, N.getConstantOperandVal(0)
655 << N.getConstantOperandVal(1));
656 if (N->getOpcode() == AArch64ISD::MOVIedit)
658 N.getConstantOperandVal(0)));
659 if (N->getOpcode() == AArch64ISD::DUP)
660 if (auto *Const = dyn_cast<ConstantSDNode>(N->getOperand(0)))
661 return Const->getAPIntValue().trunc(SplatWidth);
662 APInt SplatVal;
663 if (ISD::isConstantSplatVector(N.getNode(), SplatVal))
664 return SplatVal.trunc(SplatWidth);
665 // TODO: Recognize more splat-like NEON operations. See ConstantBuildVector
666 // in AArch64ISelLowering.
667 return std::nullopt;
668}
669
670// If \p N is a NEON splat operation (movi, fmov, etc), return the splat value
671// matching the element size of N.
672static std::optional<APInt> GetNEONSplatValue(SDValue N) {
673 unsigned SplatWidth = N.getScalarValueSizeInBits();
674 if (std::optional<APInt> SplatVal = DecodeNEONSplat(N)) {
675 if (SplatVal->getBitWidth() <= SplatWidth)
676 return APInt::getSplat(SplatWidth, *SplatVal);
677 if (SplatVal->isSplat(SplatWidth))
678 return SplatVal->trunc(SplatWidth);
679 }
680 return std::nullopt;
681}
682
683bool AArch64DAGToDAGISel::SelectNEONSplatOfSVELogicalImm(SDValue N,
684 SDValue &Imm) {
685 std::optional<APInt> ImmVal = GetNEONSplatValue(N);
686 if (!ImmVal)
687 return false;
688 uint64_t Encoding;
689 if (!AArch64_AM::isSVELogicalImm(N.getScalarValueSizeInBits(),
690 ImmVal->getZExtValue(), Encoding))
691 return false;
692
693 Imm = CurDAG->getTargetConstant(Encoding, SDLoc(N), MVT::i64);
694 return true;
695}
696
697bool AArch64DAGToDAGISel::SelectNEONSplatOfSVEAddSubImm(SDValue N, SDValue &Imm,
698 SDValue &Shift) {
699 if (std::optional<APInt> ImmVal = GetNEONSplatValue(N))
700 return SelectSVEAddSubImm(SDLoc(N), *ImmVal,
701 N.getValueType().getScalarType().getSimpleVT(),
702 Imm, Shift,
703 /*Negate=*/false);
704 return false;
705}
706
707bool AArch64DAGToDAGISel::SelectNEONSplatOfSVEArithSImm(SDValue N,
708 SDValue &Imm) {
709 if (std::optional<APInt> ImmVal = GetNEONSplatValue(N))
710 return SelectSVESignedArithImm(SDLoc(N), *ImmVal, Imm);
711 return false;
712}
713
714bool AArch64DAGToDAGISel::SelectNEONSplatOfSImm8(SDValue N, SDValue &Imm) {
715 std::optional<APInt> ImmAPIntVal = GetNEONSplatValue(N);
716 if (!ImmAPIntVal)
717 return false;
718
719 int64_t ImmVal = ImmAPIntVal->getSExtValue();
720 if (ImmVal < -128 || ImmVal > 127)
721 return false;
722
723 Imm = CurDAG->getSignedTargetConstant(ImmVal, SDLoc(N), MVT::i32);
724 return true;
725}
726
727bool AArch64DAGToDAGISel::SelectNEONSplatOfUImm8(SDValue N, SDValue &Imm) {
728 std::optional<APInt> ImmAPIntVal = GetNEONSplatValue(N);
729 if (!ImmAPIntVal)
730 return false;
731
732 uint64_t ImmVal = ImmAPIntVal->getZExtValue();
733 if (ImmVal > 255)
734 return false;
735
736 Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32);
737 return true;
738}
739
740bool AArch64DAGToDAGISel::SelectInlineAsmMemoryOperand(
741 const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID,
742 std::vector<SDValue> &OutOps) {
743 switch(ConstraintID) {
744 default:
745 llvm_unreachable("Unexpected asm memory constraint");
746 case InlineAsm::ConstraintCode::m:
747 case InlineAsm::ConstraintCode::o:
748 case InlineAsm::ConstraintCode::Q:
749 // We need to make sure that this one operand does not end up in XZR, thus
750 // require the address to be in a PointerRegClass register.
751 const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
752 const TargetRegisterClass *TRC = TRI->getPointerRegClass();
753 SDLoc dl(Op);
754 SDValue RC = CurDAG->getTargetConstant(TRC->getID(), dl, MVT::i64);
755 SDValue NewOp =
756 SDValue(CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS,
757 dl, Op.getValueType(),
758 Op, RC), 0);
759 OutOps.push_back(NewOp);
760 return false;
761 }
762 return true;
763}
764
765/// SelectArithImmed - Select an immediate value that can be represented as
766/// a 12-bit value shifted left by either 0 or 12. If so, return true with
767/// Val set to the 12-bit value and Shift set to the shifter operand.
768bool AArch64DAGToDAGISel::SelectArithImmed(SDValue N, SDValue &Val,
769 SDValue &Shift) {
770 // This function is called from the addsub_shifted_imm ComplexPattern,
771 // which lists [imm] as the list of opcode it's interested in, however
772 // we still need to check whether the operand is actually an immediate
773 // here because the ComplexPattern opcode list is only used in
774 // root-level opcode matching.
775 if (!isa<ConstantSDNode>(N.getNode()))
776 return false;
777
778 uint64_t Immed = N.getNode()->getAsZExtVal();
779
781 return false;
782
783 unsigned ShiftAmt = AArch64_AM::getArithImmedShift(Immed);
784 Immed >>= ShiftAmt;
785
786 unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt);
787 SDLoc dl(N);
788 Val = CurDAG->getTargetConstant(Immed, dl, MVT::i32);
789 Shift = CurDAG->getTargetConstant(ShVal, dl, MVT::i32);
790 return true;
791}
792
793/// SelectNegArithImmed - As above, but negates the value before trying to
794/// select it.
795bool AArch64DAGToDAGISel::SelectNegArithImmed(SDValue N, SDValue &Val,
796 SDValue &Shift) {
797 // This function is called from the addsub_shifted_imm ComplexPattern,
798 // which lists [imm] as the list of opcode it's interested in, however
799 // we still need to check whether the operand is actually an immediate
800 // here because the ComplexPattern opcode list is only used in
801 // root-level opcode matching.
802 if (!isa<ConstantSDNode>(N.getNode()))
803 return false;
804
805 // The immediate operand must be a 24-bit zero-extended immediate.
806 uint64_t Immed = N.getNode()->getAsZExtVal();
807
808 // This negation is almost always valid, but "cmp wN, #0" and "cmn wN, #0"
809 // have the opposite effect on the C flag, so this pattern mustn't match under
810 // those circumstances.
811 if (Immed == 0)
812 return false;
813
814 if (N.getValueType() == MVT::i32)
815 Immed = ~((uint32_t)Immed) + 1;
816 else
817 Immed = ~Immed + 1ULL;
818 if (Immed & 0xFFFFFFFFFF000000ULL)
819 return false;
820
821 Immed &= 0xFFFFFFULL;
822 return SelectArithImmed(CurDAG->getConstant(Immed, SDLoc(N), MVT::i32), Val,
823 Shift);
824}
825
826/// getShiftTypeForNode - Translate a shift node to the corresponding
827/// ShiftType value.
829 switch (N.getOpcode()) {
830 default:
832 case ISD::SHL:
833 return AArch64_AM::LSL;
834 case ISD::SRL:
835 return AArch64_AM::LSR;
836 case ISD::SRA:
837 return AArch64_AM::ASR;
838 case ISD::ROTR:
839 return AArch64_AM::ROR;
840 }
841}
842
844 return isa<MemSDNode>(*N) || N->getOpcode() == AArch64ISD::PREFETCH;
845}
846
847/// Determine whether it is worth it to fold SHL into the addressing
848/// mode.
850 assert(V.getOpcode() == ISD::SHL && "invalid opcode");
851 // It is worth folding logical shift of up to three places.
852 auto *CSD = dyn_cast<ConstantSDNode>(V.getOperand(1));
853 if (!CSD)
854 return false;
855 unsigned ShiftVal = CSD->getZExtValue();
856 if (ShiftVal > 3)
857 return false;
858
859 // Check if this particular node is reused in any non-memory related
860 // operation. If yes, do not try to fold this node into the address
861 // computation, since the computation will be kept.
862 const SDNode *Node = V.getNode();
863 for (SDNode *UI : Node->users())
864 if (!isMemOpOrPrefetch(UI))
865 for (SDNode *UII : UI->users())
866 if (!isMemOpOrPrefetch(UII))
867 return false;
868 return true;
869}
870
871/// Determine whether it is worth to fold V into an extended register addressing
872/// mode.
873bool AArch64DAGToDAGISel::isWorthFoldingAddr(SDValue V, unsigned Size) const {
874 // Trivial if we are optimizing for code size or if there is only
875 // one use of the value.
876 if (CurDAG->shouldOptForSize() || V.hasOneUse())
877 return true;
878
879 // If a subtarget has a slow shift, folding a shift into multiple loads
880 // costs additional micro-ops.
881 if (Subtarget->hasAddrLSLSlow14() && (Size == 2 || Size == 16))
882 return false;
883
884 // Check whether we're going to emit the address arithmetic anyway because
885 // it's used by a non-address operation.
886 if (V.getOpcode() == ISD::SHL && isWorthFoldingSHL(V))
887 return true;
888 if (V.getOpcode() == ISD::ADD) {
889 const SDValue LHS = V.getOperand(0);
890 const SDValue RHS = V.getOperand(1);
891 if (LHS.getOpcode() == ISD::SHL && isWorthFoldingSHL(LHS))
892 return true;
893 if (RHS.getOpcode() == ISD::SHL && isWorthFoldingSHL(RHS))
894 return true;
895 }
896
897 // It hurts otherwise, since the value will be reused.
898 return false;
899}
900
901/// and (shl/srl/sra, x, c), mask --> shl (srl/sra, x, c1), c2
902/// to select more shifted register
903bool AArch64DAGToDAGISel::SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg,
904 SDValue &Shift) {
905 EVT VT = N.getValueType();
906 if (VT != MVT::i32 && VT != MVT::i64)
907 return false;
908
909 if (N->getOpcode() != ISD::AND || !N->hasOneUse())
910 return false;
911 SDValue LHS = N.getOperand(0);
912 if (!LHS->hasOneUse())
913 return false;
914
915 unsigned LHSOpcode = LHS->getOpcode();
916 if (LHSOpcode != ISD::SHL && LHSOpcode != ISD::SRL && LHSOpcode != ISD::SRA)
917 return false;
918
919 ConstantSDNode *ShiftAmtNode = dyn_cast<ConstantSDNode>(LHS.getOperand(1));
920 if (!ShiftAmtNode)
921 return false;
922
923 uint64_t ShiftAmtC = ShiftAmtNode->getZExtValue();
924 ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(N.getOperand(1));
925 if (!RHSC)
926 return false;
927
928 APInt AndMask = RHSC->getAPIntValue();
929 unsigned LowZBits, MaskLen;
930 if (!AndMask.isShiftedMask(LowZBits, MaskLen))
931 return false;
932
933 unsigned BitWidth = N.getValueSizeInBits();
934 SDLoc DL(LHS);
935 uint64_t NewShiftC;
936 unsigned NewShiftOp;
937 if (LHSOpcode == ISD::SHL) {
938 // LowZBits <= ShiftAmtC will fall into isBitfieldPositioningOp
939 // BitWidth != LowZBits + MaskLen doesn't match the pattern
940 if (LowZBits <= ShiftAmtC || (BitWidth != LowZBits + MaskLen))
941 return false;
942
943 NewShiftC = LowZBits - ShiftAmtC;
944 NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri;
945 } else {
946 if (LowZBits == 0)
947 return false;
948
949 // NewShiftC >= BitWidth will fall into isBitfieldExtractOp
950 NewShiftC = LowZBits + ShiftAmtC;
951 if (NewShiftC >= BitWidth)
952 return false;
953
954 // SRA need all high bits
955 if (LHSOpcode == ISD::SRA && (BitWidth != (LowZBits + MaskLen)))
956 return false;
957
958 // SRL high bits can be 0 or 1
959 if (LHSOpcode == ISD::SRL && (BitWidth > (NewShiftC + MaskLen)))
960 return false;
961
962 if (LHSOpcode == ISD::SRL)
963 NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri;
964 else
965 NewShiftOp = VT == MVT::i64 ? AArch64::SBFMXri : AArch64::SBFMWri;
966 }
967
968 assert(NewShiftC < BitWidth && "Invalid shift amount");
969 SDValue NewShiftAmt = CurDAG->getTargetConstant(NewShiftC, DL, VT);
970 SDValue BitWidthMinus1 = CurDAG->getTargetConstant(BitWidth - 1, DL, VT);
971 Reg = SDValue(CurDAG->getMachineNode(NewShiftOp, DL, VT, LHS->getOperand(0),
972 NewShiftAmt, BitWidthMinus1),
973 0);
974 unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, LowZBits);
975 Shift = CurDAG->getTargetConstant(ShVal, DL, MVT::i32);
976 return true;
977}
978
979/// getExtendTypeForNode - Translate an extend node to the corresponding
980/// ExtendType value.
982getExtendTypeForNode(SDValue N, bool IsLoadStore = false) {
983 if (N.getOpcode() == ISD::SIGN_EXTEND ||
984 N.getOpcode() == ISD::SIGN_EXTEND_INREG) {
985 EVT SrcVT;
986 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG)
987 SrcVT = cast<VTSDNode>(N.getOperand(1))->getVT();
988 else
989 SrcVT = N.getOperand(0).getValueType();
990
991 if (!IsLoadStore && SrcVT == MVT::i8)
992 return AArch64_AM::SXTB;
993 else if (!IsLoadStore && SrcVT == MVT::i16)
994 return AArch64_AM::SXTH;
995 else if (SrcVT == MVT::i32)
996 return AArch64_AM::SXTW;
997 assert(SrcVT != MVT::i64 && "extend from 64-bits?");
998
1000 } else if (N.getOpcode() == ISD::ZERO_EXTEND ||
1001 N.getOpcode() == ISD::ANY_EXTEND) {
1002 EVT SrcVT = N.getOperand(0).getValueType();
1003 if (!IsLoadStore && SrcVT == MVT::i8)
1004 return AArch64_AM::UXTB;
1005 else if (!IsLoadStore && SrcVT == MVT::i16)
1006 return AArch64_AM::UXTH;
1007 else if (SrcVT == MVT::i32)
1008 return AArch64_AM::UXTW;
1009 assert(SrcVT != MVT::i64 && "extend from 64-bits?");
1010
1012 } else if (N.getOpcode() == ISD::AND) {
1013 ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1));
1014 if (!CSD)
1016 uint64_t AndMask = CSD->getZExtValue();
1017
1018 switch (AndMask) {
1019 default:
1021 case 0xFF:
1022 return !IsLoadStore ? AArch64_AM::UXTB : AArch64_AM::InvalidShiftExtend;
1023 case 0xFFFF:
1024 return !IsLoadStore ? AArch64_AM::UXTH : AArch64_AM::InvalidShiftExtend;
1025 case 0xFFFFFFFF:
1026 return AArch64_AM::UXTW;
1027 }
1028 }
1029
1031}
1032
1033/// Determine whether constant -V is cheaper to materialise than V.
1034bool AArch64DAGToDAGISel::isWorthNegatingImm(SDValue V) const {
1035 assert(isa<ConstantSDNode>(V) && "invalid node");
1036
1037 EVT VT = V.getValueType();
1038 assert((VT == MVT::i32 || VT == MVT::i64) && "invalid type");
1039
1040 // It's only worth negating the constant if it doesn't have other uses.
1041 if (!V.hasOneUse())
1042 return false;
1043
1044 uint64_t Imm = cast<ConstantSDNode>(V)->getZExtValue();
1045 unsigned BitSize = VT.getSizeInBits();
1047 AArch64_IMM::expandMOVImm(Imm, BitSize, OrigCost);
1048 AArch64_IMM::expandMOVImm(-Imm, BitSize, NewCost);
1049 return NewCost.size() < OrigCost.size();
1050}
1051
1052/// Determine whether it is worth to fold V into an extended register of an
1053/// Add/Sub. LSL means we are folding into an `add w0, w1, w2, lsl #N`
1054/// instruction, and the shift should be treated as worth folding even if has
1055/// multiple uses.
1056bool AArch64DAGToDAGISel::isWorthFoldingALU(SDValue V, bool LSL) const {
1057 // Trivial if we are optimizing for code size or if there is only
1058 // one use of the value.
1059 if (CurDAG->shouldOptForSize() || V.hasOneUse())
1060 return true;
1061
1062 // If a subtarget has a fastpath LSL we can fold a logical shift into
1063 // the add/sub and save a cycle.
1064 if (LSL && Subtarget->hasALULSLFast() && V.getOpcode() == ISD::SHL &&
1065 V.getConstantOperandVal(1) <= 4 &&
1067 return true;
1068
1069 // It hurts otherwise, since the value will be reused.
1070 return false;
1071}
1072
1073/// SelectShiftedRegister - Select a "shifted register" operand. If the value
1074/// is not shifted, set the Shift operand to default of "LSL 0". The logical
1075/// instructions allow the shifted register to be rotated, but the arithmetic
1076/// instructions do not. The AllowROR parameter specifies whether ROR is
1077/// supported.
1078bool AArch64DAGToDAGISel::SelectShiftedRegister(SDValue N, bool AllowROR,
1079 SDValue &Reg, SDValue &Shift) {
1080 if (SelectShiftedRegisterFromAnd(N, Reg, Shift))
1081 return true;
1082
1084 if (ShType == AArch64_AM::InvalidShiftExtend)
1085 return false;
1086 if (!AllowROR && ShType == AArch64_AM::ROR)
1087 return false;
1088
1089 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1090 unsigned BitSize = N.getValueSizeInBits();
1091 unsigned Val = RHS->getZExtValue() & (BitSize - 1);
1092 unsigned ShVal = AArch64_AM::getShifterImm(ShType, Val);
1093
1094 Reg = N.getOperand(0);
1095 Shift = CurDAG->getTargetConstant(ShVal, SDLoc(N), MVT::i32);
1096 return isWorthFoldingALU(N, true);
1097 }
1098
1099 return false;
1100}
1101
1102/// Instructions that accept extend modifiers like UXTW expect the register
1103/// being extended to be a GPR32, but the incoming DAG might be acting on a
1104/// GPR64 (either via SEXT_INREG or AND). Extract the appropriate low bits if
1105/// this is the case.
1107 if (N.getValueType() == MVT::i32)
1108 return N;
1109
1110 SDLoc dl(N);
1111 return CurDAG->getTargetExtractSubreg(AArch64::sub_32, dl, MVT::i32, N);
1112}
1113
1114// Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N.
1115template<signed Low, signed High, signed Scale>
1116bool AArch64DAGToDAGISel::SelectRDVLImm(SDValue N, SDValue &Imm) {
1117 if (!isa<ConstantSDNode>(N))
1118 return false;
1119
1120 int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue();
1121 if ((MulImm % std::abs(Scale)) == 0) {
1122 int64_t RDVLImm = MulImm / Scale;
1123 if ((RDVLImm >= Low) && (RDVLImm <= High)) {
1124 Imm = CurDAG->getSignedTargetConstant(RDVLImm, SDLoc(N), MVT::i32);
1125 return true;
1126 }
1127 }
1128
1129 return false;
1130}
1131
1132// Returns a suitable RDSVL multiplier from a left shift.
1133template <signed Low, signed High>
1134bool AArch64DAGToDAGISel::SelectRDSVLShiftImm(SDValue N, SDValue &Imm) {
1135 if (!isa<ConstantSDNode>(N))
1136 return false;
1137
1138 int64_t MulImm = 1LL << cast<ConstantSDNode>(N)->getSExtValue();
1139 if (MulImm >= Low && MulImm <= High) {
1140 Imm = CurDAG->getSignedTargetConstant(MulImm, SDLoc(N), MVT::i32);
1141 return true;
1142 }
1143
1144 return false;
1145}
1146
1147/// SelectArithExtendedRegister - Select a "extended register" operand. This
1148/// operand folds in an extend followed by an optional left shift.
1149bool AArch64DAGToDAGISel::SelectArithExtendedRegister(SDValue N, SDValue &Reg,
1150 SDValue &Shift) {
1151 unsigned ShiftVal = 0;
1153
1154 if (N.getOpcode() == ISD::SHL) {
1155 ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1));
1156 if (!CSD)
1157 return false;
1158 ShiftVal = CSD->getZExtValue();
1159 if (ShiftVal > 4)
1160 return false;
1161
1162 Ext = getExtendTypeForNode(N.getOperand(0));
1164 return false;
1165
1166 Reg = N.getOperand(0).getOperand(0);
1167 } else {
1168 Ext = getExtendTypeForNode(N);
1170 return false;
1171
1172 // Don't match sext of vector extracts. These can use SMOV, but if we match
1173 // this as an extended register, we'll always fold the extend into an ALU op
1174 // user of the extend (which results in a UMOV).
1176 SDValue Op = N.getOperand(0);
1177 if (Op->getOpcode() == ISD::ANY_EXTEND)
1178 Op = Op->getOperand(0);
1179 if (Op.getOpcode() == ISD::EXTRACT_VECTOR_ELT &&
1180 Op.getOperand(0).getValueType().isFixedLengthVector())
1181 return false;
1182 }
1183
1184 Reg = N.getOperand(0);
1185
1186 // Don't match if free 32-bit -> 64-bit zext can be used instead. Use the
1187 // isDef32 as a heuristic for when the operand is likely to be a 32bit def.
1188 auto isDef32 = [](SDValue N) {
1189 unsigned Opc = N.getOpcode();
1190 return Opc != ISD::TRUNCATE && Opc != TargetOpcode::EXTRACT_SUBREG &&
1193 Opc != ISD::FREEZE;
1194 };
1195 if (Ext == AArch64_AM::UXTW && Reg->getValueType(0).getSizeInBits() == 32 &&
1196 isDef32(Reg))
1197 return false;
1198 }
1199
1200 // AArch64 mandates that the RHS of the operation must use the smallest
1201 // register class that could contain the size being extended from. Thus,
1202 // if we're folding a (sext i8), we need the RHS to be a GPR32, even though
1203 // there might not be an actual 32-bit value in the program. We can
1204 // (harmlessly) synthesize one by injected an EXTRACT_SUBREG here.
1205 assert(Ext != AArch64_AM::UXTX && Ext != AArch64_AM::SXTX);
1206 Reg = narrowIfNeeded(CurDAG, Reg);
1207 Shift = CurDAG->getTargetConstant(getArithExtendImm(Ext, ShiftVal), SDLoc(N),
1208 MVT::i32);
1209 return isWorthFoldingALU(N);
1210}
1211
1212/// SelectArithUXTXRegister - Select a "UXTX register" operand. This
1213/// operand is referred by the instructions have SP operand
1214bool AArch64DAGToDAGISel::SelectArithUXTXRegister(SDValue N, SDValue &Reg,
1215 SDValue &Shift) {
1216 unsigned ShiftVal = 0;
1218
1219 if (N.getOpcode() != ISD::SHL)
1220 return false;
1221
1222 ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1));
1223 if (!CSD)
1224 return false;
1225 ShiftVal = CSD->getZExtValue();
1226 if (ShiftVal > 4)
1227 return false;
1228
1229 Ext = AArch64_AM::UXTX;
1230 Reg = N.getOperand(0);
1231 Shift = CurDAG->getTargetConstant(getArithExtendImm(Ext, ShiftVal), SDLoc(N),
1232 MVT::i32);
1233 return isWorthFoldingALU(N);
1234}
1235
1236/// If there's a use of this ADDlow that's not itself a load/store then we'll
1237/// need to create a real ADD instruction from it anyway and there's no point in
1238/// folding it into the mem op. Theoretically, it shouldn't matter, but there's
1239/// a single pseudo-instruction for an ADRP/ADD pair so over-aggressive folding
1240/// leads to duplicated ADRP instructions.
1242 for (auto *User : N->users()) {
1243 if (User->getOpcode() != ISD::LOAD && User->getOpcode() != ISD::STORE &&
1244 User->getOpcode() != ISD::ATOMIC_LOAD &&
1245 User->getOpcode() != ISD::ATOMIC_STORE)
1246 return false;
1247
1248 // ldar and stlr have much more restrictive addressing modes (just a
1249 // register).
1250 if (isStrongerThanMonotonic(cast<MemSDNode>(User)->getSuccessOrdering()))
1251 return false;
1252 }
1253
1254 return true;
1255}
1256
1257/// Check if the immediate offset is valid as a scaled immediate.
1258static bool isValidAsScaledImmediate(int64_t Offset, unsigned Range,
1259 unsigned Size) {
1260 if ((Offset & (Size - 1)) == 0 && Offset >= 0 &&
1261 Offset < (Range << Log2_32(Size)))
1262 return true;
1263 return false;
1264}
1265
1266/// SelectAddrModeIndexedBitWidth - Select a "register plus scaled (un)signed BW-bit
1267/// immediate" address. The "Size" argument is the size in bytes of the memory
1268/// reference, which determines the scale.
1269bool AArch64DAGToDAGISel::SelectAddrModeIndexedBitWidth(SDValue N, bool IsSignedImm,
1270 unsigned BW, unsigned Size,
1271 SDValue &Base,
1272 SDValue &OffImm) {
1273 SDLoc dl(N);
1274 const DataLayout &DL = CurDAG->getDataLayout();
1275 const TargetLowering *TLI = getTargetLowering();
1276 if (N.getOpcode() == ISD::FrameIndex) {
1277 int FI = cast<FrameIndexSDNode>(N)->getIndex();
1278 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
1279 OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64);
1280 return true;
1281 }
1282
1283 // As opposed to the (12-bit) Indexed addressing mode below, the 7/9-bit signed
1284 // selected here doesn't support labels/immediates, only base+offset.
1285 if (CurDAG->isBaseWithConstantOffset(N)) {
1286 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1287 if (IsSignedImm) {
1288 int64_t RHSC = RHS->getSExtValue();
1289 unsigned Scale = Log2_32(Size);
1290 int64_t Range = 0x1LL << (BW - 1);
1291
1292 if ((RHSC & (Size - 1)) == 0 && RHSC >= -(Range << Scale) &&
1293 RHSC < (Range << Scale)) {
1294 Base = N.getOperand(0);
1295 if (Base.getOpcode() == ISD::FrameIndex) {
1296 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
1297 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
1298 }
1299 OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64);
1300 return true;
1301 }
1302 } else {
1303 // unsigned Immediate
1304 uint64_t RHSC = RHS->getZExtValue();
1305 unsigned Scale = Log2_32(Size);
1306 uint64_t Range = 0x1ULL << BW;
1307
1308 if ((RHSC & (Size - 1)) == 0 && RHSC < (Range << Scale)) {
1309 Base = N.getOperand(0);
1310 if (Base.getOpcode() == ISD::FrameIndex) {
1311 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
1312 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
1313 }
1314 OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64);
1315 return true;
1316 }
1317 }
1318 }
1319 }
1320 // Base only. The address will be materialized into a register before
1321 // the memory is accessed.
1322 // add x0, Xbase, #offset
1323 // stp x1, x2, [x0]
1324 Base = N;
1325 OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64);
1326 return true;
1327}
1328
1329/// SelectAddrModeIndexed - Select a "register plus scaled unsigned 12-bit
1330/// immediate" address. The "Size" argument is the size in bytes of the memory
1331/// reference, which determines the scale.
1332bool AArch64DAGToDAGISel::SelectAddrModeIndexed(SDValue N, unsigned Size,
1333 SDValue &Base, SDValue &OffImm) {
1334 SDLoc dl(N);
1335 const DataLayout &DL = CurDAG->getDataLayout();
1336 const TargetLowering *TLI = getTargetLowering();
1337 if (N.getOpcode() == ISD::FrameIndex) {
1338 int FI = cast<FrameIndexSDNode>(N)->getIndex();
1339 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
1340 OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64);
1341 return true;
1342 }
1343
1344 if (N.getOpcode() == AArch64ISD::ADDlow && isWorthFoldingADDlow(N)) {
1345 GlobalAddressSDNode *GAN =
1346 dyn_cast<GlobalAddressSDNode>(N.getOperand(1).getNode());
1347 Base = N.getOperand(0);
1348 OffImm = N.getOperand(1);
1349 if (!GAN)
1350 return true;
1351
1352 if (GAN->getOffset() % Size == 0 &&
1354 return true;
1355 }
1356
1357 if (CurDAG->isBaseWithConstantOffset(N)) {
1358 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1359 int64_t RHSC = (int64_t)RHS->getZExtValue();
1360 unsigned Scale = Log2_32(Size);
1361 if (isValidAsScaledImmediate(RHSC, 0x1000, Size)) {
1362 Base = N.getOperand(0);
1363 if (Base.getOpcode() == ISD::FrameIndex) {
1364 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
1365 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
1366 }
1367 OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64);
1368 return true;
1369 }
1370 }
1371 }
1372
1373 // Before falling back to our general case, check if the unscaled
1374 // instructions can handle this. If so, that's preferable.
1375 if (SelectAddrModeUnscaled(N, Size, Base, OffImm))
1376 return false;
1377
1378 // Base only. The address will be materialized into a register before
1379 // the memory is accessed.
1380 // add x0, Xbase, #offset
1381 // ldr x0, [x0]
1382 Base = N;
1383 OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64);
1384 return true;
1385}
1386
1387/// SelectAddrModeUnscaled - Select a "register plus unscaled signed 9-bit
1388/// immediate" address. This should only match when there is an offset that
1389/// is not valid for a scaled immediate addressing mode. The "Size" argument
1390/// is the size in bytes of the memory reference, which is needed here to know
1391/// what is valid for a scaled immediate.
1392bool AArch64DAGToDAGISel::SelectAddrModeUnscaled(SDValue N, unsigned Size,
1393 SDValue &Base,
1394 SDValue &OffImm) {
1395 if (!CurDAG->isBaseWithConstantOffset(N))
1396 return false;
1397 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1398 int64_t RHSC = RHS->getSExtValue();
1399 if (RHSC >= -256 && RHSC < 256) {
1400 Base = N.getOperand(0);
1401 if (Base.getOpcode() == ISD::FrameIndex) {
1402 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
1403 const TargetLowering *TLI = getTargetLowering();
1404 Base = CurDAG->getTargetFrameIndex(
1405 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
1406 }
1407 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i64);
1408 return true;
1409 }
1410 }
1411 return false;
1412}
1413
1415 SDLoc dl(N);
1416 SDValue ImpDef = SDValue(
1417 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::i64), 0);
1418 return CurDAG->getTargetInsertSubreg(AArch64::sub_32, dl, MVT::i64, ImpDef,
1419 N);
1420}
1421
1422/// Check if the given SHL node (\p N), can be used to form an
1423/// extended register for an addressing mode.
1424bool AArch64DAGToDAGISel::SelectExtendedSHL(SDValue N, unsigned Size,
1425 bool WantExtend, SDValue &Offset,
1426 SDValue &SignExtend) {
1427 assert(N.getOpcode() == ISD::SHL && "Invalid opcode.");
1428 ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1));
1429 if (!CSD || (CSD->getZExtValue() & 0x7) != CSD->getZExtValue())
1430 return false;
1431
1432 SDLoc dl(N);
1433 if (WantExtend) {
1435 getExtendTypeForNode(N.getOperand(0), true);
1437 return false;
1438
1439 Offset = narrowIfNeeded(CurDAG, N.getOperand(0).getOperand(0));
1440 SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl,
1441 MVT::i32);
1442 } else {
1443 Offset = N.getOperand(0);
1444 SignExtend = CurDAG->getTargetConstant(0, dl, MVT::i32);
1445 }
1446
1447 unsigned LegalShiftVal = Log2_32(Size);
1448 unsigned ShiftVal = CSD->getZExtValue();
1449
1450 if (ShiftVal != 0 && ShiftVal != LegalShiftVal)
1451 return false;
1452
1453 return isWorthFoldingAddr(N, Size);
1454}
1455
1456bool AArch64DAGToDAGISel::SelectAddrModeWRO(SDValue N, unsigned Size,
1458 SDValue &SignExtend,
1459 SDValue &DoShift) {
1460 if (N.getOpcode() != ISD::ADD)
1461 return false;
1462 SDValue LHS = N.getOperand(0);
1463 SDValue RHS = N.getOperand(1);
1464 SDLoc dl(N);
1465
1466 // We don't want to match immediate adds here, because they are better lowered
1467 // to the register-immediate addressing modes.
1469 return false;
1470
1471 // Check if this particular node is reused in any non-memory related
1472 // operation. If yes, do not try to fold this node into the address
1473 // computation, since the computation will be kept.
1474 const SDNode *Node = N.getNode();
1475 for (SDNode *UI : Node->users()) {
1476 if (!isMemOpOrPrefetch(UI))
1477 return false;
1478 }
1479
1480 // Remember if it is worth folding N when it produces extended register.
1481 bool IsExtendedRegisterWorthFolding = isWorthFoldingAddr(N, Size);
1482
1483 // Try to match a shifted extend on the RHS.
1484 if (IsExtendedRegisterWorthFolding && RHS.getOpcode() == ISD::SHL &&
1485 SelectExtendedSHL(RHS, Size, true, Offset, SignExtend)) {
1486 Base = LHS;
1487 DoShift = CurDAG->getTargetConstant(true, dl, MVT::i32);
1488 return true;
1489 }
1490
1491 // Try to match a shifted extend on the LHS.
1492 if (IsExtendedRegisterWorthFolding && LHS.getOpcode() == ISD::SHL &&
1493 SelectExtendedSHL(LHS, Size, true, Offset, SignExtend)) {
1494 Base = RHS;
1495 DoShift = CurDAG->getTargetConstant(true, dl, MVT::i32);
1496 return true;
1497 }
1498
1499 // There was no shift, whatever else we find.
1500 DoShift = CurDAG->getTargetConstant(false, dl, MVT::i32);
1501
1503 // Try to match an unshifted extend on the LHS.
1504 if (IsExtendedRegisterWorthFolding &&
1505 (Ext = getExtendTypeForNode(LHS, true)) !=
1507 Base = RHS;
1508 Offset = narrowIfNeeded(CurDAG, LHS.getOperand(0));
1509 SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl,
1510 MVT::i32);
1511 if (isWorthFoldingAddr(LHS, Size))
1512 return true;
1513 }
1514
1515 // Try to match an unshifted extend on the RHS.
1516 if (IsExtendedRegisterWorthFolding &&
1517 (Ext = getExtendTypeForNode(RHS, true)) !=
1519 Base = LHS;
1520 Offset = narrowIfNeeded(CurDAG, RHS.getOperand(0));
1521 SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl,
1522 MVT::i32);
1523 if (isWorthFoldingAddr(RHS, Size))
1524 return true;
1525 }
1526
1527 return false;
1528}
1529
1530// Check if the given immediate is preferred by ADD. If an immediate can be
1531// encoded in an ADD, or it can be encoded in an "ADD LSL #12" and can not be
1532// encoded by one MOVZ, return true.
1533static bool isPreferredADD(int64_t ImmOff) {
1534 // Constant in [0x0, 0xfff] can be encoded in ADD.
1535 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
1536 return true;
1537 // Check if it can be encoded in an "ADD LSL #12".
1538 if ((ImmOff & 0xffffffffff000fffLL) == 0x0LL)
1539 // As a single MOVZ is faster than a "ADD of LSL #12", ignore such constant.
1540 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
1541 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
1542 return false;
1543}
1544
1545bool AArch64DAGToDAGISel::SelectAddrModeXRO(SDValue N, unsigned Size,
1547 SDValue &SignExtend,
1548 SDValue &DoShift) {
1549 if (N.getOpcode() != ISD::ADD)
1550 return false;
1551 SDValue LHS = N.getOperand(0);
1552 SDValue RHS = N.getOperand(1);
1553 SDLoc DL(N);
1554
1555 // Check if this particular node is reused in any non-memory related
1556 // operation. If yes, do not try to fold this node into the address
1557 // computation, since the computation will be kept.
1558 const SDNode *Node = N.getNode();
1559 for (SDNode *UI : Node->users()) {
1560 if (!isMemOpOrPrefetch(UI))
1561 return false;
1562 }
1563
1564 // Watch out if RHS is a wide immediate, it can not be selected into
1565 // [BaseReg+Imm] addressing mode. Also it may not be able to be encoded into
1566 // ADD/SUB. Instead it will use [BaseReg + 0] address mode and generate
1567 // instructions like:
1568 // MOV X0, WideImmediate
1569 // ADD X1, BaseReg, X0
1570 // LDR X2, [X1, 0]
1571 // For such situation, using [BaseReg, XReg] addressing mode can save one
1572 // ADD/SUB:
1573 // MOV X0, WideImmediate
1574 // LDR X2, [BaseReg, X0]
1575 if (isa<ConstantSDNode>(RHS)) {
1576 int64_t ImmOff = (int64_t)RHS->getAsZExtVal();
1577 // Skip the immediate can be selected by load/store addressing mode.
1578 // Also skip the immediate can be encoded by a single ADD (SUB is also
1579 // checked by using -ImmOff).
1580 if (isValidAsScaledImmediate(ImmOff, 0x1000, Size) ||
1581 isPreferredADD(ImmOff) || isPreferredADD(-ImmOff))
1582 return false;
1583
1584 SDValue Ops[] = { RHS };
1585 SDNode *MOVI =
1586 CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops);
1587 SDValue MOVIV = SDValue(MOVI, 0);
1588 // This ADD of two X register will be selected into [Reg+Reg] mode.
1589 N = CurDAG->getNode(ISD::ADD, DL, MVT::i64, LHS, MOVIV);
1590 }
1591
1592 // Remember if it is worth folding N when it produces extended register.
1593 bool IsExtendedRegisterWorthFolding = isWorthFoldingAddr(N, Size);
1594
1595 // Try to match a shifted extend on the RHS.
1596 if (IsExtendedRegisterWorthFolding && RHS.getOpcode() == ISD::SHL &&
1597 SelectExtendedSHL(RHS, Size, false, Offset, SignExtend)) {
1598 Base = LHS;
1599 DoShift = CurDAG->getTargetConstant(true, DL, MVT::i32);
1600 return true;
1601 }
1602
1603 // Try to match a shifted extend on the LHS.
1604 if (IsExtendedRegisterWorthFolding && LHS.getOpcode() == ISD::SHL &&
1605 SelectExtendedSHL(LHS, Size, false, Offset, SignExtend)) {
1606 Base = RHS;
1607 DoShift = CurDAG->getTargetConstant(true, DL, MVT::i32);
1608 return true;
1609 }
1610
1611 // Match any non-shifted, non-extend, non-immediate add expression.
1612 Base = LHS;
1613 Offset = RHS;
1614 SignExtend = CurDAG->getTargetConstant(false, DL, MVT::i32);
1615 DoShift = CurDAG->getTargetConstant(false, DL, MVT::i32);
1616 // Reg1 + Reg2 is free: no check needed.
1617 return true;
1618}
1619
1620SDValue AArch64DAGToDAGISel::createDTuple(ArrayRef<SDValue> Regs) {
1621 static const unsigned RegClassIDs[] = {
1622 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
1623 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
1624 AArch64::dsub2, AArch64::dsub3};
1625
1626 return createTuple(Regs, RegClassIDs, SubRegs);
1627}
1628
1629SDValue AArch64DAGToDAGISel::createQTuple(ArrayRef<SDValue> Regs) {
1630 static const unsigned RegClassIDs[] = {
1631 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
1632 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
1633 AArch64::qsub2, AArch64::qsub3};
1634
1635 return createTuple(Regs, RegClassIDs, SubRegs);
1636}
1637
1638SDValue AArch64DAGToDAGISel::createZTuple(ArrayRef<SDValue> Regs) {
1639 static const unsigned RegClassIDs[] = {AArch64::ZPR2RegClassID,
1640 AArch64::ZPR3RegClassID,
1641 AArch64::ZPR4RegClassID};
1642 static const unsigned SubRegs[] = {AArch64::zsub0, AArch64::zsub1,
1643 AArch64::zsub2, AArch64::zsub3};
1644
1645 return createTuple(Regs, RegClassIDs, SubRegs);
1646}
1647
1648SDValue AArch64DAGToDAGISel::createZMulTuple(ArrayRef<SDValue> Regs) {
1649 assert(Regs.size() == 2 || Regs.size() == 4);
1650
1651 // The createTuple interface requires 3 RegClassIDs for each possible
1652 // tuple type even though we only have them for ZPR2 and ZPR4.
1653 static const unsigned RegClassIDs[] = {AArch64::ZPR2Mul2RegClassID, 0,
1654 AArch64::ZPR4Mul4RegClassID};
1655 static const unsigned SubRegs[] = {AArch64::zsub0, AArch64::zsub1,
1656 AArch64::zsub2, AArch64::zsub3};
1657 return createTuple(Regs, RegClassIDs, SubRegs);
1658}
1659
1660SDValue AArch64DAGToDAGISel::createTuple(ArrayRef<SDValue> Regs,
1661 const unsigned RegClassIDs[],
1662 const unsigned SubRegs[]) {
1663 // There's no special register-class for a vector-list of 1 element: it's just
1664 // a vector.
1665 if (Regs.size() == 1)
1666 return Regs[0];
1667
1668 assert(Regs.size() >= 2 && Regs.size() <= 4);
1669
1670 SDLoc DL(Regs[0]);
1671
1673
1674 // First operand of REG_SEQUENCE is the desired RegClass.
1675 Ops.push_back(
1676 CurDAG->getTargetConstant(RegClassIDs[Regs.size() - 2], DL, MVT::i32));
1677
1678 // Then we get pairs of source & subregister-position for the components.
1679 for (unsigned i = 0; i < Regs.size(); ++i) {
1680 Ops.push_back(Regs[i]);
1681 Ops.push_back(CurDAG->getTargetConstant(SubRegs[i], DL, MVT::i32));
1682 }
1683
1684 SDNode *N =
1685 CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops);
1686 return SDValue(N, 0);
1687}
1688
1689void AArch64DAGToDAGISel::SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc,
1690 bool isExt) {
1691 SDLoc dl(N);
1692 EVT VT = N->getValueType(0);
1693
1694 unsigned ExtOff = isExt;
1695
1696 // Form a REG_SEQUENCE to force register allocation.
1697 unsigned Vec0Off = ExtOff + 1;
1698 SmallVector<SDValue, 4> Regs(N->ops().slice(Vec0Off, NumVecs));
1699 SDValue RegSeq = createQTuple(Regs);
1700
1702 if (isExt)
1703 Ops.push_back(N->getOperand(1));
1704 Ops.push_back(RegSeq);
1705 Ops.push_back(N->getOperand(NumVecs + ExtOff + 1));
1706 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops));
1707}
1708
1709static std::tuple<SDValue, SDValue>
1711 SDLoc DL(Disc);
1712 SDValue AddrDisc;
1713 SDValue ConstDisc;
1714
1715 // If this is a blend, remember the constant and address discriminators.
1716 // Otherwise, it's either a constant discriminator, or a non-blended
1717 // address discriminator.
1718 if (Disc->getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
1719 Disc->getConstantOperandVal(0) == Intrinsic::ptrauth_blend) {
1720 AddrDisc = Disc->getOperand(1);
1721 ConstDisc = Disc->getOperand(2);
1722 } else {
1723 ConstDisc = Disc;
1724 }
1725
1726 // If the constant discriminator (either the blend RHS, or the entire
1727 // discriminator value) isn't a 16-bit constant, bail out, and let the
1728 // discriminator be computed separately.
1729 auto *ConstDiscN = dyn_cast<ConstantSDNode>(ConstDisc);
1730 if (!ConstDiscN || !isUInt<16>(ConstDiscN->getZExtValue()))
1731 return std::make_tuple(DAG->getTargetConstant(0, DL, MVT::i64), Disc);
1732
1733 // If there's no address discriminator, use XZR directly.
1734 if (!AddrDisc)
1735 AddrDisc = DAG->getRegister(AArch64::XZR, MVT::i64);
1736
1737 return std::make_tuple(
1738 DAG->getTargetConstant(ConstDiscN->getZExtValue(), DL, MVT::i64),
1739 AddrDisc);
1740}
1741
1742void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
1743 SDLoc DL(N);
1744 // IntrinsicID is operand #0
1745 SDValue Val = N->getOperand(1);
1746 SDValue AUTKey = N->getOperand(2);
1747 SDValue AUTDisc = N->getOperand(3);
1748
1749 unsigned AUTKeyC = cast<ConstantSDNode>(AUTKey)->getZExtValue();
1750 AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64);
1751
1752 SDValue AUTAddrDisc, AUTConstDisc;
1753 std::tie(AUTConstDisc, AUTAddrDisc) =
1754 extractPtrauthBlendDiscriminators(AUTDisc, CurDAG);
1755
1756 if (!Subtarget->isX16X17Safer()) {
1757 std::vector<SDValue> Ops = {Val, AUTKey, AUTConstDisc, AUTAddrDisc};
1758 // Copy deactivation symbol if present.
1759 if (N->getNumOperands() > 4)
1760 Ops.push_back(N->getOperand(4));
1761
1762 SDNode *AUT =
1763 CurDAG->getMachineNode(AArch64::AUTxMxN, DL, MVT::i64, MVT::i64, Ops);
1764 ReplaceNode(N, AUT);
1765 } else {
1766 SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
1767 AArch64::X16, Val, SDValue());
1768 SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, X16Copy.getValue(1)};
1769
1770 SDNode *AUT = CurDAG->getMachineNode(AArch64::AUTx16x17, DL, MVT::i64, Ops);
1771 ReplaceNode(N, AUT);
1772 }
1773}
1774
1775void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) {
1776 SDLoc DL(N);
1777 // IntrinsicID is operand #0, if W_CHAIN it is #1
1778 int OffsetBase = N->getOpcode() == ISD::INTRINSIC_W_CHAIN ? 1 : 0;
1779 SDValue Val = N->getOperand(OffsetBase + 1);
1780 SDValue AUTKey = N->getOperand(OffsetBase + 2);
1781 SDValue AUTDisc = N->getOperand(OffsetBase + 3);
1782 SDValue PACKey = N->getOperand(OffsetBase + 4);
1783 SDValue PACDisc = N->getOperand(OffsetBase + 5);
1784 uint32_t IntNum = N->getConstantOperandVal(OffsetBase + 0);
1785 bool HasLoad = IntNum == Intrinsic::ptrauth_resign_load_relative;
1786
1787 unsigned AUTKeyC = cast<ConstantSDNode>(AUTKey)->getZExtValue();
1788 unsigned PACKeyC = cast<ConstantSDNode>(PACKey)->getZExtValue();
1789
1790 AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64);
1791 PACKey = CurDAG->getTargetConstant(PACKeyC, DL, MVT::i64);
1792
1793 SDValue AUTAddrDisc, AUTConstDisc;
1794 std::tie(AUTConstDisc, AUTAddrDisc) =
1795 extractPtrauthBlendDiscriminators(AUTDisc, CurDAG);
1796
1797 SDValue PACAddrDisc, PACConstDisc;
1798 std::tie(PACConstDisc, PACAddrDisc) =
1799 extractPtrauthBlendDiscriminators(PACDisc, CurDAG);
1800
1801 SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
1802 AArch64::X16, Val, SDValue());
1803
1804 if (HasLoad) {
1805 SDValue Addend = N->getOperand(OffsetBase + 6);
1806 SDValue IncomingChain = N->getOperand(0);
1807 SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc,
1808 PACKey, PACConstDisc, PACAddrDisc,
1809 Addend, IncomingChain, X16Copy.getValue(1)};
1810
1811 SDNode *AUTRELLOADPAC = CurDAG->getMachineNode(AArch64::AUTRELLOADPAC, DL,
1812 MVT::i64, MVT::Other, Ops);
1813 ReplaceNode(N, AUTRELLOADPAC);
1814 } else {
1815 SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, PACKey,
1816 PACConstDisc, PACAddrDisc, X16Copy.getValue(1)};
1817
1818 SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops);
1819 ReplaceNode(N, AUTPAC);
1820 }
1821}
1822
1823void AArch64DAGToDAGISel::SelectPtrauthResignWithPC(SDNode *N) {
1824 SDLoc DL(N);
1825 SDValue Val = N->getOperand(1);
1826 SDValue AUTKey = N->getOperand(2);
1827 SDValue AUTDisc = N->getOperand(3);
1828 SDValue AUTPC = N->getOperand(4);
1829 SDValue PACKey = N->getOperand(5);
1830 SDValue PACDisc = N->getOperand(6);
1831
1832 unsigned AUTKeyC = cast<ConstantSDNode>(AUTKey)->getZExtValue();
1833 unsigned PACKeyC = cast<ConstantSDNode>(PACKey)->getZExtValue();
1834
1835 AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64);
1836 PACKey = CurDAG->getTargetConstant(PACKeyC, DL, MVT::i64);
1837
1838 SDValue PACAddrDisc, PACConstDisc;
1839 std::tie(PACConstDisc, PACAddrDisc) =
1840 extractPtrauthBlendDiscriminators(PACDisc, CurDAG);
1841
1842 SDValue X17Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
1843 AArch64::X17, Val, SDValue());
1844 SDValue X16Copy = CurDAG->getCopyToReg(
1845 CurDAG->getEntryNode(), DL, AArch64::X16, AUTDisc, X17Copy.getValue(1));
1846 SDValue X15Copy = CurDAG->getCopyToReg(
1847 CurDAG->getEntryNode(), DL, AArch64::X15, AUTPC, X16Copy.getValue(1));
1848
1849 SDValue Ops[] = {AUTKey, PACKey, PACConstDisc, PACAddrDisc,
1850 X15Copy.getValue(1)};
1851 SDNode *AUTPCPAC =
1852 CurDAG->getMachineNode(AArch64::AUTPCPAC, DL, MVT::i64, Ops);
1853 ReplaceNode(N, AUTPCPAC);
1854}
1855
1856bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) {
1857 LoadSDNode *LD = cast<LoadSDNode>(N);
1858 if (LD->isUnindexed())
1859 return false;
1860 EVT VT = LD->getMemoryVT();
1861 EVT DstVT = N->getValueType(0);
1862 ISD::MemIndexedMode AM = LD->getAddressingMode();
1863 bool IsPre = AM == ISD::PRE_INC || AM == ISD::PRE_DEC;
1864 ConstantSDNode *OffsetOp = cast<ConstantSDNode>(LD->getOffset());
1865 int OffsetVal = (int)OffsetOp->getZExtValue();
1866
1867 // We're not doing validity checking here. That was done when checking
1868 // if we should mark the load as indexed or not. We're just selecting
1869 // the right instruction.
1870 unsigned Opcode = 0;
1871
1872 ISD::LoadExtType ExtType = LD->getExtensionType();
1873 bool InsertTo64 = false;
1874 if (VT == MVT::i64)
1875 Opcode = IsPre ? AArch64::LDRXpre : AArch64::LDRXpost;
1876 else if (VT == MVT::i32) {
1877 if (ExtType == ISD::NON_EXTLOAD)
1878 Opcode = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
1879 else if (ExtType == ISD::SEXTLOAD)
1880 Opcode = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
1881 else {
1882 Opcode = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
1883 InsertTo64 = true;
1884 // The result of the load is only i32. It's the subreg_to_reg that makes
1885 // it into an i64.
1886 DstVT = MVT::i32;
1887 }
1888 } else if (VT == MVT::i16) {
1889 if (ExtType == ISD::SEXTLOAD) {
1890 if (DstVT == MVT::i64)
1891 Opcode = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
1892 else
1893 Opcode = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
1894 } else {
1895 Opcode = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
1896 InsertTo64 = DstVT == MVT::i64;
1897 // The result of the load is only i32. It's the subreg_to_reg that makes
1898 // it into an i64.
1899 DstVT = MVT::i32;
1900 }
1901 } else if (VT == MVT::i8) {
1902 if (ExtType == ISD::SEXTLOAD) {
1903 if (DstVT == MVT::i64)
1904 Opcode = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
1905 else
1906 Opcode = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
1907 } else {
1908 Opcode = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
1909 InsertTo64 = DstVT == MVT::i64;
1910 // The result of the load is only i32. It's the subreg_to_reg that makes
1911 // it into an i64.
1912 DstVT = MVT::i32;
1913 }
1914 } else if (VT == MVT::f16) {
1915 Opcode = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
1916 } else if (VT == MVT::bf16) {
1917 Opcode = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
1918 } else if (VT == MVT::f32) {
1919 Opcode = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
1920 } else if (VT == MVT::f64 ||
1921 (VT.is64BitVector() && Subtarget->isLittleEndian())) {
1922 Opcode = IsPre ? AArch64::LDRDpre : AArch64::LDRDpost;
1923 } else if (VT.is128BitVector() && Subtarget->isLittleEndian()) {
1924 Opcode = IsPre ? AArch64::LDRQpre : AArch64::LDRQpost;
1925 } else if (VT.is64BitVector()) {
1926 if (IsPre || OffsetVal != 8)
1927 return false;
1928 switch (VT.getScalarSizeInBits()) {
1929 case 8:
1930 Opcode = AArch64::LD1Onev8b_POST;
1931 break;
1932 case 16:
1933 Opcode = AArch64::LD1Onev4h_POST;
1934 break;
1935 case 32:
1936 Opcode = AArch64::LD1Onev2s_POST;
1937 break;
1938 case 64:
1939 Opcode = AArch64::LD1Onev1d_POST;
1940 break;
1941 default:
1942 llvm_unreachable("Expected vector element to be a power of 2");
1943 }
1944 } else if (VT.is128BitVector()) {
1945 if (IsPre || OffsetVal != 16)
1946 return false;
1947 switch (VT.getScalarSizeInBits()) {
1948 case 8:
1949 Opcode = AArch64::LD1Onev16b_POST;
1950 break;
1951 case 16:
1952 Opcode = AArch64::LD1Onev8h_POST;
1953 break;
1954 case 32:
1955 Opcode = AArch64::LD1Onev4s_POST;
1956 break;
1957 case 64:
1958 Opcode = AArch64::LD1Onev2d_POST;
1959 break;
1960 default:
1961 llvm_unreachable("Expected vector element to be a power of 2");
1962 }
1963 } else
1964 return false;
1965 SDValue Chain = LD->getChain();
1966 SDValue Base = LD->getBasePtr();
1967 SDLoc dl(N);
1968 // LD1 encodes an immediate offset by using XZR as the offset register.
1969 SDValue Offset = (VT.isVector() && !Subtarget->isLittleEndian())
1970 ? CurDAG->getRegister(AArch64::XZR, MVT::i64)
1971 : CurDAG->getTargetConstant(OffsetVal, dl, MVT::i64);
1972 SDValue Ops[] = { Base, Offset, Chain };
1973 SDNode *Res = CurDAG->getMachineNode(Opcode, dl, MVT::i64, DstVT,
1974 MVT::Other, Ops);
1975
1976 // Transfer memoperands.
1977 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
1978 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Res), {MemOp});
1979
1980 // Either way, we're replacing the node, so tell the caller that.
1981 SDValue LoadedVal = SDValue(Res, 1);
1982 if (InsertTo64) {
1983 SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, dl, MVT::i32);
1984 LoadedVal = SDValue(CurDAG->getMachineNode(AArch64::SUBREG_TO_REG, dl,
1985 MVT::i64, LoadedVal, SubReg),
1986 0);
1987 }
1988
1989 ReplaceUses(SDValue(N, 0), LoadedVal);
1990 ReplaceUses(SDValue(N, 1), SDValue(Res, 0));
1991 ReplaceUses(SDValue(N, 2), SDValue(Res, 2));
1992 CurDAG->RemoveDeadNode(N);
1993 return true;
1994}
1995
1996void AArch64DAGToDAGISel::SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc,
1997 unsigned SubRegIdx) {
1998 SDLoc dl(N);
1999 EVT VT = N->getValueType(0);
2000 SDValue Chain = N->getOperand(0);
2001
2002 SDValue Ops[] = {N->getOperand(2), // Mem operand;
2003 Chain};
2004
2005 const EVT ResTys[] = {MVT::Untyped, MVT::Other};
2006
2007 SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2008 SDValue SuperReg = SDValue(Ld, 0);
2009 for (unsigned i = 0; i < NumVecs; ++i)
2010 ReplaceUses(SDValue(N, i),
2011 CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg));
2012
2013 ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1));
2014
2015 // Transfer memoperands. In the case of AArch64::LD64B, there won't be one,
2016 // because it's too simple to have needed special treatment during lowering.
2017 if (auto *MemIntr = dyn_cast<MemIntrinsicSDNode>(N)) {
2018 MachineMemOperand *MemOp = MemIntr->getMemOperand();
2019 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp});
2020 }
2021
2022 CurDAG->RemoveDeadNode(N);
2023}
2024
2025void AArch64DAGToDAGISel::SelectPostLoad(SDNode *N, unsigned NumVecs,
2026 unsigned Opc, unsigned SubRegIdx) {
2027 SDLoc dl(N);
2028 EVT VT = N->getValueType(0);
2029 SDValue Chain = N->getOperand(0);
2030
2031 SDValue Ops[] = {N->getOperand(1), // Mem operand
2032 N->getOperand(2), // Incremental
2033 Chain};
2034
2035 const EVT ResTys[] = {MVT::i64, // Type of the write back register
2036 MVT::Untyped, MVT::Other};
2037
2038 SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2039
2040 // Update uses of write back register
2041 ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0));
2042
2043 // Update uses of vector list
2044 SDValue SuperReg = SDValue(Ld, 1);
2045 if (NumVecs == 1)
2046 ReplaceUses(SDValue(N, 0), SuperReg);
2047 else
2048 for (unsigned i = 0; i < NumVecs; ++i)
2049 ReplaceUses(SDValue(N, i),
2050 CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg));
2051
2052 // Transfer memoperands.
2053 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2054 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp});
2055
2056 // Update the chain
2057 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2));
2058 CurDAG->RemoveDeadNode(N);
2059}
2060
2061/// Optimize \param OldBase and \param OldOffset selecting the best addressing
2062/// mode. Returns a tuple consisting of an Opcode, an SDValue representing the
2063/// new Base and an SDValue representing the new offset.
2064std::tuple<unsigned, SDValue, SDValue>
2065AArch64DAGToDAGISel::findAddrModeSVELoadStore(SDNode *N, unsigned Opc_rr,
2066 unsigned Opc_ri,
2067 const SDValue &OldBase,
2068 const SDValue &OldOffset,
2069 unsigned Scale) {
2070 SDValue NewBase = OldBase;
2071 SDValue NewOffset = OldOffset;
2072 // Detect a possible Reg+Imm addressing mode.
2073 const bool IsRegImm = SelectAddrModeIndexedSVE</*Min=*/-8, /*Max=*/7>(
2074 N, OldBase, NewBase, NewOffset);
2075
2076 // Detect a possible reg+reg addressing mode, but only if we haven't already
2077 // detected a Reg+Imm one.
2078 const bool IsRegReg =
2079 !IsRegImm && SelectSVERegRegAddrMode(OldBase, Scale, NewBase, NewOffset);
2080
2081 // Select the instruction.
2082 return std::make_tuple(IsRegReg ? Opc_rr : Opc_ri, NewBase, NewOffset);
2083}
2084
2085enum class SelectTypeKind {
2086 Int1 = 0,
2087 Int = 1,
2088 FP = 2,
2090};
2091
2092/// This function selects an opcode from a list of opcodes, which is
2093/// expected to be the opcode for { 8-bit, 16-bit, 32-bit, 64-bit }
2094/// element types, in this order.
2095template <SelectTypeKind Kind>
2096static unsigned SelectOpcodeFromVT(EVT VT, ArrayRef<unsigned> Opcodes) {
2097 // Only match scalable vector VTs
2098 if (!VT.isScalableVector())
2099 return 0;
2100
2101 EVT EltVT = VT.getVectorElementType();
2102 unsigned Key = VT.getVectorMinNumElements();
2103 switch (Kind) {
2105 break;
2107 if (EltVT != MVT::i8 && EltVT != MVT::i16 && EltVT != MVT::i32 &&
2108 EltVT != MVT::i64)
2109 return 0;
2110 break;
2112 if (EltVT != MVT::i1)
2113 return 0;
2114 break;
2115 case SelectTypeKind::FP:
2116 if (EltVT == MVT::bf16)
2117 Key = 16;
2118 else if (EltVT != MVT::bf16 && EltVT != MVT::f16 && EltVT != MVT::f32 &&
2119 EltVT != MVT::f64)
2120 return 0;
2121 break;
2122 }
2123
2124 unsigned Offset;
2125 switch (Key) {
2126 case 16: // 8-bit or bf16
2127 Offset = 0;
2128 break;
2129 case 8: // 16-bit
2130 Offset = 1;
2131 break;
2132 case 4: // 32-bit
2133 Offset = 2;
2134 break;
2135 case 2: // 64-bit
2136 Offset = 3;
2137 break;
2138 default:
2139 return 0;
2140 }
2141
2142 return (Opcodes.size() <= Offset) ? 0 : Opcodes[Offset];
2143}
2144
2145// This function is almost identical to SelectWhilePair, but has an
2146// extra check on the range of the immediate operand.
2147// TODO: Merge these two functions together at some point?
2148void AArch64DAGToDAGISel::SelectPExtPair(SDNode *N, unsigned Opc) {
2149 // Immediate can be either 0 or 1.
2150 if (ConstantSDNode *Imm = dyn_cast<ConstantSDNode>(N->getOperand(2)))
2151 if (Imm->getZExtValue() > 1)
2152 return;
2153
2154 SDLoc DL(N);
2155 EVT VT = N->getValueType(0);
2156 SDValue Ops[] = {N->getOperand(1), N->getOperand(2)};
2157 SDNode *WhilePair = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops);
2158 SDValue SuperReg = SDValue(WhilePair, 0);
2159
2160 for (unsigned I = 0; I < 2; ++I)
2161 ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg(
2162 AArch64::psub0 + I, DL, VT, SuperReg));
2163
2164 CurDAG->RemoveDeadNode(N);
2165}
2166
2167void AArch64DAGToDAGISel::SelectWhilePair(SDNode *N, unsigned Opc) {
2168 SDLoc DL(N);
2169 EVT VT = N->getValueType(0);
2170
2171 SDValue Ops[] = {N->getOperand(1), N->getOperand(2)};
2172
2173 SDNode *WhilePair = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops);
2174 SDValue SuperReg = SDValue(WhilePair, 0);
2175
2176 for (unsigned I = 0; I < 2; ++I)
2177 ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg(
2178 AArch64::psub0 + I, DL, VT, SuperReg));
2179
2180 CurDAG->RemoveDeadNode(N);
2181}
2182
2183void AArch64DAGToDAGISel::SelectCVTIntrinsic(SDNode *N, unsigned NumVecs,
2184 unsigned Opcode) {
2185 EVT VT = N->getValueType(0);
2186 SmallVector<SDValue, 4> Regs(N->ops().slice(1, NumVecs));
2187 SDValue Ops = createZTuple(Regs);
2188 SDLoc DL(N);
2189 SDNode *Intrinsic = CurDAG->getMachineNode(Opcode, DL, MVT::Untyped, Ops);
2190 SDValue SuperReg = SDValue(Intrinsic, 0);
2191 for (unsigned i = 0; i < NumVecs; ++i)
2192 ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg(
2193 AArch64::zsub0 + i, DL, VT, SuperReg));
2194
2195 CurDAG->RemoveDeadNode(N);
2196}
2197
2198void AArch64DAGToDAGISel::SelectCVTIntrinsicFP8(SDNode *N, unsigned NumVecs,
2199 unsigned Opcode) {
2200 SDLoc DL(N);
2201 EVT VT = N->getValueType(0);
2202 SmallVector<SDValue, 4> Ops(N->op_begin() + 2, N->op_end());
2203 Ops.push_back(/*Chain*/ N->getOperand(0));
2204
2205 SDNode *Instruction =
2206 CurDAG->getMachineNode(Opcode, DL, {MVT::Untyped, MVT::Other}, Ops);
2207 SDValue SuperReg = SDValue(Instruction, 0);
2208
2209 for (unsigned i = 0; i < NumVecs; ++i)
2210 ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg(
2211 AArch64::zsub0 + i, DL, VT, SuperReg));
2212
2213 // Copy chain
2214 unsigned ChainIdx = NumVecs;
2215 ReplaceUses(SDValue(N, ChainIdx), SDValue(Instruction, 1));
2216 CurDAG->RemoveDeadNode(N);
2217}
2218
2219void AArch64DAGToDAGISel::SelectDestructiveMultiIntrinsic(SDNode *N,
2220 unsigned NumVecs,
2221 bool IsZmMulti,
2222 unsigned Opcode,
2223 bool HasPred) {
2224 assert(Opcode != 0 && "Unexpected opcode");
2225
2226 SDLoc DL(N);
2227 EVT VT = N->getValueType(0);
2228 SDUse *OpsIter = N->op_begin() + 1; // Skip intrinsic ID
2230
2231 auto GetMultiVecOperand = [&]() {
2232 SmallVector<SDValue, 4> Regs(OpsIter, OpsIter + NumVecs);
2233 OpsIter += NumVecs;
2234 return createZMulTuple(Regs);
2235 };
2236
2237 if (HasPred)
2238 Ops.push_back(*OpsIter++);
2239
2240 Ops.push_back(GetMultiVecOperand());
2241 if (IsZmMulti)
2242 Ops.push_back(GetMultiVecOperand());
2243 else
2244 Ops.push_back(*OpsIter++);
2245
2246 // Append any remaining operands.
2247 Ops.append(OpsIter, N->op_end());
2248 SDNode *Intrinsic;
2249 Intrinsic = CurDAG->getMachineNode(Opcode, DL, MVT::Untyped, Ops);
2250 SDValue SuperReg = SDValue(Intrinsic, 0);
2251 for (unsigned i = 0; i < NumVecs; ++i)
2252 ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg(
2253 AArch64::zsub0 + i, DL, VT, SuperReg));
2254
2255 CurDAG->RemoveDeadNode(N);
2256}
2257
2258void AArch64DAGToDAGISel::SelectPredicatedLoad(SDNode *N, unsigned NumVecs,
2259 unsigned Scale, unsigned Opc_ri,
2260 unsigned Opc_rr, bool IsIntr) {
2261 assert(Scale < 5 && "Invalid scaling value.");
2262 SDLoc DL(N);
2263 EVT VT = N->getValueType(0);
2264 SDValue Chain = N->getOperand(0);
2265
2266 // Optimize addressing mode.
2268 unsigned Opc;
2269 std::tie(Opc, Base, Offset) = findAddrModeSVELoadStore(
2270 N, Opc_rr, Opc_ri, N->getOperand(IsIntr ? 3 : 2),
2271 CurDAG->getTargetConstant(0, DL, MVT::i64), Scale);
2272
2273 SDValue Ops[] = {N->getOperand(IsIntr ? 2 : 1), // Predicate
2274 Base, // Memory operand
2275 Offset, Chain};
2276
2277 const EVT ResTys[] = {MVT::Untyped, MVT::Other};
2278
2279 SDNode *Load = CurDAG->getMachineNode(Opc, DL, ResTys, Ops);
2280 SDValue SuperReg = SDValue(Load, 0);
2281 for (unsigned i = 0; i < NumVecs; ++i)
2282 ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg(
2283 AArch64::zsub0 + i, DL, VT, SuperReg));
2284
2285 // Copy chain
2286 unsigned ChainIdx = NumVecs;
2287 ReplaceUses(SDValue(N, ChainIdx), SDValue(Load, 1));
2288 CurDAG->RemoveDeadNode(N);
2289}
2290
2291void AArch64DAGToDAGISel::SelectContiguousMultiVectorLoad(SDNode *N,
2292 unsigned NumVecs,
2293 unsigned Scale,
2294 unsigned Opc_ri,
2295 unsigned Opc_rr) {
2296 assert(Scale < 4 && "Invalid scaling value.");
2297 SDLoc DL(N);
2298 EVT VT = N->getValueType(0);
2299 SDValue Chain = N->getOperand(0);
2300
2301 SDValue PNg = N->getOperand(2);
2302 SDValue Base = N->getOperand(3);
2303 SDValue Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
2304 unsigned Opc;
2305 std::tie(Opc, Base, Offset) =
2306 findAddrModeSVELoadStore(N, Opc_rr, Opc_ri, Base, Offset, Scale);
2307
2308 SDValue Ops[] = {PNg, // Predicate-as-counter
2309 Base, // Memory operand
2310 Offset, Chain};
2311
2312 const EVT ResTys[] = {MVT::Untyped, MVT::Other};
2313
2314 SDNode *Load = CurDAG->getMachineNode(Opc, DL, ResTys, Ops);
2315 SDValue SuperReg = SDValue(Load, 0);
2316 for (unsigned i = 0; i < NumVecs; ++i)
2317 ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg(
2318 AArch64::zsub0 + i, DL, VT, SuperReg));
2319
2320 // Copy chain
2321 unsigned ChainIdx = NumVecs;
2322 ReplaceUses(SDValue(N, ChainIdx), SDValue(Load, 1));
2323 CurDAG->RemoveDeadNode(N);
2324}
2325
2326void AArch64DAGToDAGISel::SelectFrintFromVT(SDNode *N, unsigned NumVecs,
2327 unsigned Opcode) {
2328 if (N->getValueType(0) != MVT::nxv4f32)
2329 return;
2330 SelectUnaryMultiIntrinsic(N, NumVecs, true, Opcode);
2331}
2332
2333void AArch64DAGToDAGISel::SelectMultiVectorLutiLane(SDNode *Node,
2334 unsigned NumOutVecs,
2335 unsigned Opc,
2336 uint32_t MaxImm) {
2337 if (ConstantSDNode *Imm = dyn_cast<ConstantSDNode>(Node->getOperand(4)))
2338 if (Imm->getZExtValue() > MaxImm)
2339 return;
2340
2341 SDValue ZtValue;
2342 if (!ImmToReg<AArch64::ZT0, 0>(Node->getOperand(2), ZtValue))
2343 return;
2344
2345 SDValue Chain = Node->getOperand(0);
2346 SDValue Ops[] = {ZtValue, Node->getOperand(3), Node->getOperand(4), Chain};
2347 SDLoc DL(Node);
2348 EVT VT = Node->getValueType(0);
2349
2350 SDNode *Instruction =
2351 CurDAG->getMachineNode(Opc, DL, {MVT::Untyped, MVT::Other}, Ops);
2352 SDValue SuperReg = SDValue(Instruction, 0);
2353
2354 for (unsigned I = 0; I < NumOutVecs; ++I)
2355 ReplaceUses(SDValue(Node, I), CurDAG->getTargetExtractSubreg(
2356 AArch64::zsub0 + I, DL, VT, SuperReg));
2357
2358 // Copy chain
2359 unsigned ChainIdx = NumOutVecs;
2360 ReplaceUses(SDValue(Node, ChainIdx), SDValue(Instruction, 1));
2361 CurDAG->RemoveDeadNode(Node);
2362}
2363
2364void AArch64DAGToDAGISel::SelectMultiVectorLuti6LaneX4(SDNode *Node,
2365 unsigned NumIndexVecs) {
2366 assert((NumIndexVecs == 2 || NumIndexVecs == 3) &&
2367 "unexpected number of index vectors");
2368
2369 constexpr unsigned FirstIndexOp = 3;
2370 unsigned ImmOp = FirstIndexOp + NumIndexVecs;
2371 auto *Imm = dyn_cast<ConstantSDNode>(Node->getOperand(ImmOp));
2372 if (!Imm || Imm->getZExtValue() > 1)
2373 return;
2374
2375 // The luti6 instruction always takes a 2-register Zm index tuple. The x3
2376 // ACLE form provides three index vectors, so the lane selects which adjacent
2377 // pair to use before forming Zm (op 3/4 or op 4/5, with op6 as imm)
2378 unsigned Lane = Imm->getZExtValue();
2379 unsigned IndexOp = FirstIndexOp;
2380 if (NumIndexVecs == 3)
2381 IndexOp += Lane;
2382
2383 SDValue TableTuple = createZTuple({Node->getOperand(1), Node->getOperand(2)});
2384 SDValue IndexTuple =
2385 createZTuple({Node->getOperand(IndexOp), Node->getOperand(IndexOp + 1)});
2386 SDValue Ops[] = {TableTuple, IndexTuple, Node->getOperand(ImmOp)};
2387
2388 SDLoc DL(Node);
2389 EVT VT = Node->getValueType(0);
2390 SDNode *Instruction =
2391 CurDAG->getMachineNode(AArch64::LUTI6_4Z2Z2ZI, DL, MVT::Untyped, Ops);
2392 SDValue SuperReg = SDValue(Instruction, 0);
2393
2394 for (unsigned I = 0; I < 4; ++I)
2395 ReplaceUses(SDValue(Node, I), CurDAG->getTargetExtractSubreg(
2396 AArch64::zsub0 + I, DL, VT, SuperReg));
2397
2398 CurDAG->RemoveDeadNode(Node);
2399}
2400
2401void AArch64DAGToDAGISel::SelectMultiVectorLuti(SDNode *Node,
2402 unsigned NumOutVecs,
2403 unsigned Opc,
2404 unsigned NumInVecs) {
2405 assert((NumInVecs == 2 || NumInVecs == 3) &&
2406 "unexpected number of input vectors");
2407
2408 SDValue ZtValue;
2409 if (!ImmToReg<AArch64::ZT0, 0>(Node->getOperand(2), ZtValue))
2410 return;
2411
2412 SmallVector<SDValue, 4> Regs(Node->ops().slice(3, NumInVecs));
2413 SDValue ZTuple = NumInVecs == 3 ? createZTuple(Regs) : createZMulTuple(Regs);
2414 SDValue Ops[] = {ZtValue, ZTuple, Node->getOperand(0)};
2415
2416 SDLoc DL(Node);
2417 EVT VT = Node->getValueType(0);
2418
2419 SDNode *Instruction =
2420 CurDAG->getMachineNode(Opc, DL, {MVT::Untyped, MVT::Other}, Ops);
2421 SDValue SuperReg = SDValue(Instruction, 0);
2422
2423 for (unsigned I = 0; I < NumOutVecs; ++I)
2424 ReplaceUses(SDValue(Node, I), CurDAG->getTargetExtractSubreg(
2425 AArch64::zsub0 + I, DL, VT, SuperReg));
2426
2427 ReplaceUses(SDValue(Node, NumOutVecs), SDValue(Instruction, 1));
2428 CurDAG->RemoveDeadNode(Node);
2429}
2430
2431void AArch64DAGToDAGISel::SelectClamp(SDNode *N, unsigned NumVecs,
2432 unsigned Op) {
2433 SDLoc DL(N);
2434 EVT VT = N->getValueType(0);
2435
2436 SmallVector<SDValue, 4> Regs(N->ops().slice(1, NumVecs));
2437 SDValue Zd = createZMulTuple(Regs);
2438 SDValue Zn = N->getOperand(1 + NumVecs);
2439 SDValue Zm = N->getOperand(2 + NumVecs);
2440
2441 SDValue Ops[] = {Zd, Zn, Zm};
2442
2443 SDNode *Intrinsic = CurDAG->getMachineNode(Op, DL, MVT::Untyped, Ops);
2444 SDValue SuperReg = SDValue(Intrinsic, 0);
2445 for (unsigned i = 0; i < NumVecs; ++i)
2446 ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg(
2447 AArch64::zsub0 + i, DL, VT, SuperReg));
2448
2449 CurDAG->RemoveDeadNode(N);
2450}
2451
2452bool SelectSMETile(unsigned &BaseReg, unsigned TileNum) {
2453 switch (BaseReg) {
2454 default:
2455 return false;
2456 case AArch64::ZA:
2457 case AArch64::ZAB0:
2458 if (TileNum == 0)
2459 break;
2460 return false;
2461 case AArch64::ZAH0:
2462 if (TileNum <= 1)
2463 break;
2464 return false;
2465 case AArch64::ZAS0:
2466 if (TileNum <= 3)
2467 break;
2468 return false;
2469 case AArch64::ZAD0:
2470 if (TileNum <= 7)
2471 break;
2472 return false;
2473 }
2474
2475 BaseReg += TileNum;
2476 return true;
2477}
2478
2479template <unsigned MaxIdx, unsigned Scale>
2480void AArch64DAGToDAGISel::SelectMultiVectorMove(SDNode *N, unsigned NumVecs,
2481 unsigned BaseReg, unsigned Op) {
2482 unsigned TileNum = 0;
2483 if (BaseReg != AArch64::ZA)
2484 TileNum = N->getConstantOperandVal(2);
2485
2486 if (!SelectSMETile(BaseReg, TileNum))
2487 return;
2488
2489 SDValue SliceBase, Base, Offset;
2490 if (BaseReg == AArch64::ZA)
2491 SliceBase = N->getOperand(2);
2492 else
2493 SliceBase = N->getOperand(3);
2494
2495 if (!SelectSMETileSlice(SliceBase, MaxIdx, Base, Offset, Scale))
2496 return;
2497
2498 SDLoc DL(N);
2499 SDValue SubReg = CurDAG->getRegister(BaseReg, MVT::Other);
2500 SDValue Ops[] = {SubReg, Base, Offset, /*Chain*/ N->getOperand(0)};
2501 SDNode *Mov = CurDAG->getMachineNode(Op, DL, {MVT::Untyped, MVT::Other}, Ops);
2502
2503 EVT VT = N->getValueType(0);
2504 for (unsigned I = 0; I < NumVecs; ++I)
2505 ReplaceUses(SDValue(N, I),
2506 CurDAG->getTargetExtractSubreg(AArch64::zsub0 + I, DL, VT,
2507 SDValue(Mov, 0)));
2508 // Copy chain
2509 unsigned ChainIdx = NumVecs;
2510 ReplaceUses(SDValue(N, ChainIdx), SDValue(Mov, 1));
2511 CurDAG->RemoveDeadNode(N);
2512}
2513
2514void AArch64DAGToDAGISel::SelectMultiVectorMoveZ(SDNode *N, unsigned NumVecs,
2515 unsigned Op, unsigned MaxIdx,
2516 unsigned Scale, unsigned BaseReg) {
2517 // Slice can be in different positions
2518 // The array to vector: llvm.aarch64.sme.readz.<h/v>.<sz>(slice)
2519 // The tile to vector: llvm.aarch64.sme.readz.<h/v>.<sz>(tile, slice)
2520 SDValue SliceBase = N->getOperand(2);
2521 if (BaseReg != AArch64::ZA)
2522 SliceBase = N->getOperand(3);
2523
2525 if (!SelectSMETileSlice(SliceBase, MaxIdx, Base, Offset, Scale))
2526 return;
2527 // The correct Za tile number is computed in Machine Instruction
2528 // See EmitZAInstr
2529 // DAG cannot select Za tile as an output register with ZReg
2530 SDLoc DL(N);
2532 if (BaseReg != AArch64::ZA )
2533 Ops.push_back(N->getOperand(2));
2534 Ops.push_back(Base);
2535 Ops.push_back(Offset);
2536 Ops.push_back(N->getOperand(0)); //Chain
2537 SDNode *Mov = CurDAG->getMachineNode(Op, DL, {MVT::Untyped, MVT::Other}, Ops);
2538
2539 EVT VT = N->getValueType(0);
2540 for (unsigned I = 0; I < NumVecs; ++I)
2541 ReplaceUses(SDValue(N, I),
2542 CurDAG->getTargetExtractSubreg(AArch64::zsub0 + I, DL, VT,
2543 SDValue(Mov, 0)));
2544
2545 // Copy chain
2546 unsigned ChainIdx = NumVecs;
2547 ReplaceUses(SDValue(N, ChainIdx), SDValue(Mov, 1));
2548 CurDAG->RemoveDeadNode(N);
2549}
2550
2551void AArch64DAGToDAGISel::SelectUnaryMultiIntrinsic(SDNode *N,
2552 unsigned NumOutVecs,
2553 bool IsTupleInput,
2554 unsigned Opc) {
2555 SDLoc DL(N);
2556 EVT VT = N->getValueType(0);
2557 unsigned NumInVecs = N->getNumOperands() - 1;
2558
2560 if (IsTupleInput) {
2561 assert((NumInVecs == 2 || NumInVecs == 4) &&
2562 "Don't know how to handle multi-register input!");
2563 SmallVector<SDValue, 4> Regs(N->ops().slice(1, NumInVecs));
2564 Ops.push_back(createZMulTuple(Regs));
2565 } else {
2566 // All intrinsic nodes have the ID as the first operand, hence the "1 + I".
2567 for (unsigned I = 0; I < NumInVecs; I++)
2568 Ops.push_back(N->getOperand(1 + I));
2569 }
2570
2571 SDNode *Res = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops);
2572 SDValue SuperReg = SDValue(Res, 0);
2573
2574 for (unsigned I = 0; I < NumOutVecs; I++)
2575 ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg(
2576 AArch64::zsub0 + I, DL, VT, SuperReg));
2577 CurDAG->RemoveDeadNode(N);
2578}
2579
2580void AArch64DAGToDAGISel::SelectStore(SDNode *N, unsigned NumVecs,
2581 unsigned Opc) {
2582 SDLoc dl(N);
2583 EVT VT = N->getOperand(2)->getValueType(0);
2584
2585 // Form a REG_SEQUENCE to force register allocation.
2586 bool Is128Bit = VT.getSizeInBits() == 128;
2587 SmallVector<SDValue, 4> Regs(N->ops().slice(2, NumVecs));
2588 SDValue RegSeq = Is128Bit ? createQTuple(Regs) : createDTuple(Regs);
2589
2590 SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), N->getOperand(0)};
2591 SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops);
2592
2593 // Transfer memoperands.
2594 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2595 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
2596
2597 ReplaceNode(N, St);
2598}
2599
2600void AArch64DAGToDAGISel::SelectPredicatedStore(SDNode *N, unsigned NumVecs,
2601 unsigned Scale, unsigned Opc_rr,
2602 unsigned Opc_ri) {
2603 SDLoc dl(N);
2604
2605 // Form a REG_SEQUENCE to force register allocation.
2606 SmallVector<SDValue, 4> Regs(N->ops().slice(2, NumVecs));
2607 SDValue RegSeq = createZTuple(Regs);
2608
2609 // Optimize addressing mode.
2610 unsigned Opc;
2612 std::tie(Opc, Base, Offset) = findAddrModeSVELoadStore(
2613 N, Opc_rr, Opc_ri, N->getOperand(NumVecs + 3),
2614 CurDAG->getTargetConstant(0, dl, MVT::i64), Scale);
2615
2616 SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), // predicate
2617 Base, // address
2618 Offset, // offset
2619 N->getOperand(0)}; // chain
2620 SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops);
2621
2622 // Transfer memoperands.
2623 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2624 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
2625
2626 ReplaceNode(N, St);
2627}
2628
2629void AArch64DAGToDAGISel::SelectPostStore(SDNode *N, unsigned NumVecs,
2630 unsigned Opc) {
2631 SDLoc dl(N);
2632 EVT VT = N->getOperand(2)->getValueType(0);
2633 const EVT ResTys[] = {MVT::i64, // Type of the write back register
2634 MVT::Other}; // Type for the Chain
2635
2636 // Form a REG_SEQUENCE to force register allocation.
2637 bool Is128Bit = VT.getSizeInBits() == 128;
2638 SmallVector<SDValue, 4> Regs(N->ops().slice(1, NumVecs));
2639 SDValue RegSeq = Is128Bit ? createQTuple(Regs) : createDTuple(Regs);
2640
2641 SDValue Ops[] = {RegSeq,
2642 N->getOperand(NumVecs + 1), // base register
2643 N->getOperand(NumVecs + 2), // Incremental
2644 N->getOperand(0)}; // Chain
2645 SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2646
2647 // Transfer memoperands.
2648 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2649 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
2650
2651 ReplaceNode(N, St);
2652}
2653
2654namespace {
2655/// WidenVector - Given a value in the V64 register class, produce the
2656/// equivalent value in the V128 register class.
2657class WidenVector {
2658 SelectionDAG &DAG;
2659
2660public:
2661 WidenVector(SelectionDAG &DAG) : DAG(DAG) {}
2662
2663 SDValue operator()(SDValue V64Reg) {
2664 EVT VT = V64Reg.getValueType();
2665 unsigned NarrowSize = VT.getVectorNumElements();
2666 MVT EltTy = VT.getVectorElementType().getSimpleVT();
2667 MVT WideTy = MVT::getVectorVT(EltTy, 2 * NarrowSize);
2668 SDLoc DL(V64Reg);
2669
2670 SDValue Undef =
2671 SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, WideTy), 0);
2672 return DAG.getTargetInsertSubreg(AArch64::dsub, DL, WideTy, Undef, V64Reg);
2673 }
2674};
2675} // namespace
2676
2677/// NarrowVector - Given a value in the V128 register class, produce the
2678/// equivalent value in the V64 register class.
2680 EVT VT = V128Reg.getValueType();
2681 unsigned WideSize = VT.getVectorNumElements();
2682 MVT EltTy = VT.getVectorElementType().getSimpleVT();
2683 MVT NarrowTy = MVT::getVectorVT(EltTy, WideSize / 2);
2684
2685 return DAG.getTargetExtractSubreg(AArch64::dsub, SDLoc(V128Reg), NarrowTy,
2686 V128Reg);
2687}
2688
2689void AArch64DAGToDAGISel::SelectLoadLane(SDNode *N, unsigned NumVecs,
2690 unsigned Opc) {
2691 SDLoc dl(N);
2692 EVT VT = N->getValueType(0);
2693 bool Narrow = VT.getSizeInBits() == 64;
2694
2695 // Form a REG_SEQUENCE to force register allocation.
2696 SmallVector<SDValue, 4> Regs(N->ops().slice(2, NumVecs));
2697
2698 if (Narrow)
2699 transform(Regs, Regs.begin(),
2700 WidenVector(*CurDAG));
2701
2702 SDValue RegSeq = createQTuple(Regs);
2703
2704 const EVT ResTys[] = {MVT::Untyped, MVT::Other};
2705
2706 unsigned LaneNo = N->getConstantOperandVal(NumVecs + 2);
2707
2708 SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64),
2709 N->getOperand(NumVecs + 3), N->getOperand(0)};
2710 SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2711 SDValue SuperReg = SDValue(Ld, 0);
2712
2713 EVT WideVT = RegSeq.getOperand(1)->getValueType(0);
2714 static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1,
2715 AArch64::qsub2, AArch64::qsub3 };
2716 for (unsigned i = 0; i < NumVecs; ++i) {
2717 SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, SuperReg);
2718 if (Narrow)
2719 NV = NarrowVector(NV, *CurDAG);
2720 ReplaceUses(SDValue(N, i), NV);
2721 }
2722
2723 ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1));
2724 CurDAG->RemoveDeadNode(N);
2725}
2726
2727void AArch64DAGToDAGISel::SelectPostLoadLane(SDNode *N, unsigned NumVecs,
2728 unsigned Opc) {
2729 SDLoc dl(N);
2730 EVT VT = N->getValueType(0);
2731 bool Narrow = VT.getSizeInBits() == 64;
2732
2733 // Form a REG_SEQUENCE to force register allocation.
2734 SmallVector<SDValue, 4> Regs(N->ops().slice(1, NumVecs));
2735
2736 if (Narrow)
2737 transform(Regs, Regs.begin(),
2738 WidenVector(*CurDAG));
2739
2740 SDValue RegSeq = createQTuple(Regs);
2741
2742 const EVT ResTys[] = {MVT::i64, // Type of the write back register
2743 RegSeq->getValueType(0), MVT::Other};
2744
2745 unsigned LaneNo = N->getConstantOperandVal(NumVecs + 1);
2746
2747 SDValue Ops[] = {RegSeq,
2748 CurDAG->getTargetConstant(LaneNo, dl,
2749 MVT::i64), // Lane Number
2750 N->getOperand(NumVecs + 2), // Base register
2751 N->getOperand(NumVecs + 3), // Incremental
2752 N->getOperand(0)};
2753 SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2754
2755 // Update uses of the write back register
2756 ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0));
2757
2758 // Update uses of the vector list
2759 SDValue SuperReg = SDValue(Ld, 1);
2760 if (NumVecs == 1) {
2761 ReplaceUses(SDValue(N, 0),
2762 Narrow ? NarrowVector(SuperReg, *CurDAG) : SuperReg);
2763 } else {
2764 EVT WideVT = RegSeq.getOperand(1)->getValueType(0);
2765 static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1,
2766 AArch64::qsub2, AArch64::qsub3 };
2767 for (unsigned i = 0; i < NumVecs; ++i) {
2768 SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT,
2769 SuperReg);
2770 if (Narrow)
2771 NV = NarrowVector(NV, *CurDAG);
2772 ReplaceUses(SDValue(N, i), NV);
2773 }
2774 }
2775
2776 // Update the Chain
2777 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2));
2778 CurDAG->RemoveDeadNode(N);
2779}
2780
2781void AArch64DAGToDAGISel::SelectStoreLane(SDNode *N, unsigned NumVecs,
2782 unsigned Opc) {
2783 SDLoc dl(N);
2784 EVT VT = N->getOperand(2)->getValueType(0);
2785 bool Narrow = VT.getSizeInBits() == 64;
2786
2787 // Form a REG_SEQUENCE to force register allocation.
2788 SmallVector<SDValue, 4> Regs(N->ops().slice(2, NumVecs));
2789
2790 if (Narrow)
2791 transform(Regs, Regs.begin(),
2792 WidenVector(*CurDAG));
2793
2794 SDValue RegSeq = createQTuple(Regs);
2795
2796 unsigned LaneNo = N->getConstantOperandVal(NumVecs + 2);
2797
2798 SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64),
2799 N->getOperand(NumVecs + 3), N->getOperand(0)};
2800 SDNode *St = CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops);
2801
2802 // Transfer memoperands.
2803 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2804 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
2805
2806 ReplaceNode(N, St);
2807}
2808
2809void AArch64DAGToDAGISel::SelectPostStoreLane(SDNode *N, unsigned NumVecs,
2810 unsigned Opc) {
2811 SDLoc dl(N);
2812 EVT VT = N->getOperand(2)->getValueType(0);
2813 bool Narrow = VT.getSizeInBits() == 64;
2814
2815 // Form a REG_SEQUENCE to force register allocation.
2816 SmallVector<SDValue, 4> Regs(N->ops().slice(1, NumVecs));
2817
2818 if (Narrow)
2819 transform(Regs, Regs.begin(),
2820 WidenVector(*CurDAG));
2821
2822 SDValue RegSeq = createQTuple(Regs);
2823
2824 const EVT ResTys[] = {MVT::i64, // Type of the write back register
2825 MVT::Other};
2826
2827 unsigned LaneNo = N->getConstantOperandVal(NumVecs + 1);
2828
2829 SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64),
2830 N->getOperand(NumVecs + 2), // Base Register
2831 N->getOperand(NumVecs + 3), // Incremental
2832 N->getOperand(0)};
2833 SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2834
2835 // Transfer memoperands.
2836 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2837 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
2838
2839 ReplaceNode(N, St);
2840}
2841
2843 unsigned &Opc, SDValue &Opd0,
2844 unsigned &LSB, unsigned &MSB,
2845 unsigned NumberOfIgnoredLowBits,
2846 bool BiggerPattern) {
2847 assert(N->getOpcode() == ISD::AND &&
2848 "N must be a AND operation to call this function");
2849
2850 EVT VT = N->getValueType(0);
2851
2852 // Here we can test the type of VT and return false when the type does not
2853 // match, but since it is done prior to that call in the current context
2854 // we turned that into an assert to avoid redundant code.
2855 assert((VT == MVT::i32 || VT == MVT::i64) &&
2856 "Type checking must have been done before calling this function");
2857
2858 // FIXME: simplify-demanded-bits in DAGCombine will probably have
2859 // changed the AND node to a 32-bit mask operation. We'll have to
2860 // undo that as part of the transform here if we want to catch all
2861 // the opportunities.
2862 // Currently the NumberOfIgnoredLowBits argument helps to recover
2863 // from these situations when matching bigger pattern (bitfield insert).
2864
2865 // For unsigned extracts, check for a shift right and mask
2866 uint64_t AndImm = 0;
2867 if (!isOpcWithIntImmediate(N, ISD::AND, AndImm))
2868 return false;
2869
2870 const SDNode *Op0 = N->getOperand(0).getNode();
2871
2872 // Because of simplify-demanded-bits in DAGCombine, the mask may have been
2873 // simplified. Try to undo that
2874 AndImm |= maskTrailingOnes<uint64_t>(NumberOfIgnoredLowBits);
2875
2876 // The immediate is a mask of the low bits iff imm & (imm+1) == 0
2877 if (AndImm & (AndImm + 1))
2878 return false;
2879
2880 bool ClampMSB = false;
2881 uint64_t SrlImm = 0;
2882 // Handle the SRL + ANY_EXTEND case.
2883 if (VT == MVT::i64 && Op0->getOpcode() == ISD::ANY_EXTEND &&
2884 isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, SrlImm)) {
2885 // Extend the incoming operand of the SRL to 64-bit.
2886 Opd0 = Widen(CurDAG, Op0->getOperand(0).getOperand(0));
2887 // Make sure to clamp the MSB so that we preserve the semantics of the
2888 // original operations.
2889 ClampMSB = true;
2890 } else if (VT == MVT::i32 && Op0->getOpcode() == ISD::TRUNCATE &&
2892 SrlImm)) {
2893 // If the shift result was truncated, we can still combine them.
2894 Opd0 = Op0->getOperand(0).getOperand(0);
2895
2896 // Use the type of SRL node.
2897 VT = Opd0->getValueType(0);
2898 } else if (isOpcWithIntImmediate(Op0, ISD::SRL, SrlImm)) {
2899 Opd0 = Op0->getOperand(0);
2900 ClampMSB = (VT == MVT::i32);
2901 } else if (BiggerPattern) {
2902 // Let's pretend a 0 shift right has been performed.
2903 // The resulting code will be at least as good as the original one
2904 // plus it may expose more opportunities for bitfield insert pattern.
2905 // FIXME: Currently we limit this to the bigger pattern, because
2906 // some optimizations expect AND and not UBFM.
2907 Opd0 = N->getOperand(0);
2908 } else
2909 return false;
2910
2911 // Bail out on large immediates. This happens when no proper
2912 // combining/constant folding was performed.
2913 if (!BiggerPattern && (SrlImm <= 0 || SrlImm >= VT.getSizeInBits())) {
2914 LLVM_DEBUG(
2915 (dbgs() << N
2916 << ": Found large shift immediate, this should not happen\n"));
2917 return false;
2918 }
2919
2920 LSB = SrlImm;
2921 MSB = SrlImm +
2922 (VT == MVT::i32 ? llvm::countr_one<uint32_t>(AndImm)
2923 : llvm::countr_one<uint64_t>(AndImm)) -
2924 1;
2925 if (ClampMSB)
2926 // Since we're moving the extend before the right shift operation, we need
2927 // to clamp the MSB to make sure we don't shift in undefined bits instead of
2928 // the zeros which would get shifted in with the original right shift
2929 // operation.
2930 MSB = MSB > 31 ? 31 : MSB;
2931
2932 Opc = VT == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri;
2933 return true;
2934}
2935
2937 SDValue &Opd0, unsigned &Immr,
2938 unsigned &Imms) {
2939 assert(N->getOpcode() == ISD::SIGN_EXTEND_INREG);
2940
2941 EVT VT = N->getValueType(0);
2942 unsigned BitWidth = VT.getSizeInBits();
2943 assert((VT == MVT::i32 || VT == MVT::i64) &&
2944 "Type checking must have been done before calling this function");
2945
2946 SDValue Op = N->getOperand(0);
2947 if (Op->getOpcode() == ISD::TRUNCATE) {
2948 Op = Op->getOperand(0);
2949 VT = Op->getValueType(0);
2950 BitWidth = VT.getSizeInBits();
2951 }
2952
2953 uint64_t ShiftImm;
2954 if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRL, ShiftImm) &&
2955 !isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm))
2956 return false;
2957
2958 unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits();
2959 if (ShiftImm + Width > BitWidth)
2960 return false;
2961
2962 Opc = (VT == MVT::i32) ? AArch64::SBFMWri : AArch64::SBFMXri;
2963 Opd0 = Op.getOperand(0);
2964 Immr = ShiftImm;
2965 Imms = ShiftImm + Width - 1;
2966 return true;
2967}
2968
2970 SDValue &Opd0, unsigned &LSB,
2971 unsigned &MSB) {
2972 // We are looking for the following pattern which basically extracts several
2973 // continuous bits from the source value and places it from the LSB of the
2974 // destination value, all other bits of the destination value or set to zero:
2975 //
2976 // Value2 = AND Value, MaskImm
2977 // SRL Value2, ShiftImm
2978 //
2979 // with MaskImm >> ShiftImm to search for the bit width.
2980 //
2981 // This gets selected into a single UBFM:
2982 //
2983 // UBFM Value, ShiftImm, Log2_64(MaskImm)
2984 //
2985
2986 if (N->getOpcode() != ISD::SRL)
2987 return false;
2988
2989 uint64_t AndMask = 0;
2990 if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, AndMask))
2991 return false;
2992
2993 Opd0 = N->getOperand(0).getOperand(0);
2994
2995 uint64_t SrlImm = 0;
2996 if (!isIntImmediate(N->getOperand(1), SrlImm))
2997 return false;
2998
2999 // Check whether we really have several bits extract here.
3000 if (!isMask_64(AndMask >> SrlImm))
3001 return false;
3002
3003 Opc = N->getValueType(0) == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri;
3004 LSB = SrlImm;
3005 MSB = llvm::Log2_64(AndMask);
3006 return true;
3007}
3008
3009static bool isBitfieldExtractOpFromShr(SDNode *N, unsigned &Opc, SDValue &Opd0,
3010 unsigned &Immr, unsigned &Imms,
3011 bool BiggerPattern) {
3012 assert((N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL) &&
3013 "N must be a SHR/SRA operation to call this function");
3014
3015 EVT VT = N->getValueType(0);
3016
3017 // Here we can test the type of VT and return false when the type does not
3018 // match, but since it is done prior to that call in the current context
3019 // we turned that into an assert to avoid redundant code.
3020 assert((VT == MVT::i32 || VT == MVT::i64) &&
3021 "Type checking must have been done before calling this function");
3022
3023 // Check for AND + SRL doing several bits extract.
3024 if (isSeveralBitsExtractOpFromShr(N, Opc, Opd0, Immr, Imms))
3025 return true;
3026
3027 // We're looking for a shift of a shift.
3028 uint64_t ShlImm = 0;
3029 uint64_t TruncBits = 0;
3030 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, ShlImm)) {
3031 Opd0 = N->getOperand(0).getOperand(0);
3032 } else if (VT == MVT::i32 && N->getOpcode() == ISD::SRL &&
3033 N->getOperand(0).getNode()->getOpcode() == ISD::TRUNCATE) {
3034 // We are looking for a shift of truncate. Truncate from i64 to i32 could
3035 // be considered as setting high 32 bits as zero. Our strategy here is to
3036 // always generate 64bit UBFM. This consistency will help the CSE pass
3037 // later find more redundancy.
3038 Opd0 = N->getOperand(0).getOperand(0);
3039 TruncBits = Opd0->getValueType(0).getSizeInBits() - VT.getSizeInBits();
3040 VT = Opd0.getValueType();
3041 assert(VT == MVT::i64 && "the promoted type should be i64");
3042 } else if (BiggerPattern) {
3043 // Let's pretend a 0 shift left has been performed.
3044 // FIXME: Currently we limit this to the bigger pattern case,
3045 // because some optimizations expect AND and not UBFM
3046 Opd0 = N->getOperand(0);
3047 } else
3048 return false;
3049
3050 // Missing combines/constant folding may have left us with strange
3051 // constants.
3052 if (ShlImm >= VT.getSizeInBits()) {
3053 LLVM_DEBUG(
3054 (dbgs() << N
3055 << ": Found large shift immediate, this should not happen\n"));
3056 return false;
3057 }
3058
3059 uint64_t SrlImm = 0;
3060 if (!isIntImmediate(N->getOperand(1), SrlImm))
3061 return false;
3062
3063 assert(SrlImm > 0 && SrlImm < VT.getSizeInBits() &&
3064 "bad amount in shift node!");
3065 int immr = SrlImm - ShlImm;
3066 Immr = immr < 0 ? immr + VT.getSizeInBits() : immr;
3067 Imms = VT.getSizeInBits() - ShlImm - TruncBits - 1;
3068 // SRA requires a signed extraction
3069 if (VT == MVT::i32)
3070 Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMWri : AArch64::UBFMWri;
3071 else
3072 Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMXri : AArch64::UBFMXri;
3073 return true;
3074}
3075
3076bool AArch64DAGToDAGISel::tryBitfieldExtractOpFromSExt(SDNode *N) {
3077 assert(N->getOpcode() == ISD::SIGN_EXTEND);
3078
3079 EVT VT = N->getValueType(0);
3080 EVT NarrowVT = N->getOperand(0)->getValueType(0);
3081 if (VT != MVT::i64 || NarrowVT != MVT::i32)
3082 return false;
3083
3084 uint64_t ShiftImm;
3085 SDValue Op = N->getOperand(0);
3086 if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm))
3087 return false;
3088
3089 SDLoc dl(N);
3090 // Extend the incoming operand of the shift to 64-bits.
3091 SDValue Opd0 = Widen(CurDAG, Op.getOperand(0));
3092 unsigned Immr = ShiftImm;
3093 unsigned Imms = NarrowVT.getSizeInBits() - 1;
3094 SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT),
3095 CurDAG->getTargetConstant(Imms, dl, VT)};
3096 CurDAG->SelectNodeTo(N, AArch64::SBFMXri, VT, Ops);
3097 return true;
3098}
3099
3100static bool isBitfieldExtractOp(SelectionDAG *CurDAG, SDNode *N, unsigned &Opc,
3101 SDValue &Opd0, unsigned &Immr, unsigned &Imms,
3102 unsigned NumberOfIgnoredLowBits = 0,
3103 bool BiggerPattern = false) {
3104 if (N->getValueType(0) != MVT::i32 && N->getValueType(0) != MVT::i64)
3105 return false;
3106
3107 switch (N->getOpcode()) {
3108 default:
3109 if (!N->isMachineOpcode())
3110 return false;
3111 break;
3112 case ISD::AND:
3113 return isBitfieldExtractOpFromAnd(CurDAG, N, Opc, Opd0, Immr, Imms,
3114 NumberOfIgnoredLowBits, BiggerPattern);
3115 case ISD::SRL:
3116 case ISD::SRA:
3117 return isBitfieldExtractOpFromShr(N, Opc, Opd0, Immr, Imms, BiggerPattern);
3118
3120 return isBitfieldExtractOpFromSExtInReg(N, Opc, Opd0, Immr, Imms);
3121 }
3122
3123 unsigned NOpc = N->getMachineOpcode();
3124 switch (NOpc) {
3125 default:
3126 return false;
3127 case AArch64::SBFMWri:
3128 case AArch64::UBFMWri:
3129 case AArch64::SBFMXri:
3130 case AArch64::UBFMXri:
3131 Opc = NOpc;
3132 Opd0 = N->getOperand(0);
3133 Immr = N->getConstantOperandVal(1);
3134 Imms = N->getConstantOperandVal(2);
3135 return true;
3136 }
3137 // Unreachable
3138 return false;
3139}
3140
3141bool AArch64DAGToDAGISel::tryBitfieldExtractOp(SDNode *N) {
3142 unsigned Opc, Immr, Imms;
3143 SDValue Opd0;
3144 if (!isBitfieldExtractOp(CurDAG, N, Opc, Opd0, Immr, Imms))
3145 return false;
3146
3147 EVT VT = N->getValueType(0);
3148 SDLoc dl(N);
3149
3150 // If the bit extract operation is 64bit but the original type is 32bit, we
3151 // need to add one EXTRACT_SUBREG.
3152 if ((Opc == AArch64::SBFMXri || Opc == AArch64::UBFMXri) && VT == MVT::i32) {
3153 SDValue Ops64[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, MVT::i64),
3154 CurDAG->getTargetConstant(Imms, dl, MVT::i64)};
3155
3156 SDNode *BFM = CurDAG->getMachineNode(Opc, dl, MVT::i64, Ops64);
3157 SDValue Inner = CurDAG->getTargetExtractSubreg(AArch64::sub_32, dl,
3158 MVT::i32, SDValue(BFM, 0));
3159 ReplaceNode(N, Inner.getNode());
3160 return true;
3161 }
3162
3163 SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT),
3164 CurDAG->getTargetConstant(Imms, dl, VT)};
3165 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
3166 return true;
3167}
3168
3169/// Does DstMask form a complementary pair with the mask provided by
3170/// BitsToBeInserted, suitable for use in a BFI instruction. Roughly speaking,
3171/// this asks whether DstMask zeroes precisely those bits that will be set by
3172/// the other half.
3173static bool isBitfieldDstMask(uint64_t DstMask, const APInt &BitsToBeInserted,
3174 unsigned NumberOfIgnoredHighBits, EVT VT) {
3175 assert((VT == MVT::i32 || VT == MVT::i64) &&
3176 "i32 or i64 mask type expected!");
3177 unsigned BitWidth = VT.getSizeInBits() - NumberOfIgnoredHighBits;
3178
3179 // Enable implicitTrunc as we're intentionally ignoring high bits.
3180 APInt SignificantDstMask =
3181 APInt(BitWidth, DstMask, /*isSigned=*/false, /*implicitTrunc=*/true);
3182 APInt SignificantBitsToBeInserted = BitsToBeInserted.zextOrTrunc(BitWidth);
3183
3184 return (SignificantDstMask & SignificantBitsToBeInserted) == 0 &&
3185 (SignificantDstMask | SignificantBitsToBeInserted).isAllOnes();
3186}
3187
3188// Look for bits that will be useful for later uses.
3189// A bit is consider useless as soon as it is dropped and never used
3190// before it as been dropped.
3191// E.g., looking for useful bit of x
3192// 1. y = x & 0x7
3193// 2. z = y >> 2
3194// After #1, x useful bits are 0x7, then the useful bits of x, live through
3195// y.
3196// After #2, the useful bits of x are 0x4.
3197// However, if x is used on an unpredictable instruction, then all its bits
3198// are useful.
3199// E.g.
3200// 1. y = x & 0x7
3201// 2. z = y >> 2
3202// 3. str x, [@x]
3203static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth = 0);
3204
3206 unsigned Depth) {
3207 uint64_t Imm =
3208 cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue();
3209 Imm = AArch64_AM::decodeLogicalImmediate(Imm, UsefulBits.getBitWidth());
3210 UsefulBits &= APInt(UsefulBits.getBitWidth(), Imm);
3211 getUsefulBits(Op, UsefulBits, Depth + 1);
3212}
3213
3215 uint64_t Imm, uint64_t MSB,
3216 unsigned Depth) {
3217 // inherit the bitwidth value
3218 APInt OpUsefulBits(UsefulBits);
3219 OpUsefulBits = 1;
3220
3221 if (MSB >= Imm) {
3222 OpUsefulBits <<= MSB - Imm + 1;
3223 --OpUsefulBits;
3224 // The interesting part will be in the lower part of the result
3225 getUsefulBits(Op, OpUsefulBits, Depth + 1);
3226 // The interesting part was starting at Imm in the argument
3227 OpUsefulBits <<= Imm;
3228 } else {
3229 OpUsefulBits <<= MSB + 1;
3230 --OpUsefulBits;
3231 // The interesting part will be shifted in the result
3232 OpUsefulBits <<= OpUsefulBits.getBitWidth() - Imm;
3233 getUsefulBits(Op, OpUsefulBits, Depth + 1);
3234 // The interesting part was at zero in the argument
3235 OpUsefulBits.lshrInPlace(OpUsefulBits.getBitWidth() - Imm);
3236 }
3237
3238 UsefulBits &= OpUsefulBits;
3239}
3240
3241static void getUsefulBitsFromUBFM(SDValue Op, APInt &UsefulBits,
3242 unsigned Depth) {
3243 uint64_t Imm =
3244 cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue();
3245 uint64_t MSB =
3246 cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
3247
3248 getUsefulBitsFromBitfieldMoveOpd(Op, UsefulBits, Imm, MSB, Depth);
3249}
3250
3252 unsigned Depth) {
3253 uint64_t ShiftTypeAndValue =
3254 cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
3255 APInt Mask(UsefulBits);
3256 Mask.clearAllBits();
3257 Mask.flipAllBits();
3258
3259 if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSL) {
3260 // Shift Left
3261 uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue);
3262 Mask <<= ShiftAmt;
3263 getUsefulBits(Op, Mask, Depth + 1);
3264 Mask.lshrInPlace(ShiftAmt);
3265 } else if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSR) {
3266 // Shift Right
3267 // We do not handle AArch64_AM::ASR, because the sign will change the
3268 // number of useful bits
3269 uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue);
3270 Mask.lshrInPlace(ShiftAmt);
3271 getUsefulBits(Op, Mask, Depth + 1);
3272 Mask <<= ShiftAmt;
3273 } else
3274 return;
3275
3276 UsefulBits &= Mask;
3277}
3278
3279static void getUsefulBitsFromBFM(SDValue Op, SDValue Orig, APInt &UsefulBits,
3280 unsigned Depth) {
3281 uint64_t Imm =
3282 cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
3283 uint64_t MSB =
3284 cast<const ConstantSDNode>(Op.getOperand(3).getNode())->getZExtValue();
3285
3286 APInt OpUsefulBits(UsefulBits);
3287 OpUsefulBits = 1;
3288
3289 APInt ResultUsefulBits(UsefulBits.getBitWidth(), 0);
3290 ResultUsefulBits.flipAllBits();
3291 APInt Mask(UsefulBits.getBitWidth(), 0);
3292
3293 getUsefulBits(Op, ResultUsefulBits, Depth + 1);
3294
3295 if (MSB >= Imm) {
3296 // The instruction is a BFXIL.
3297 uint64_t Width = MSB - Imm + 1;
3298 uint64_t LSB = Imm;
3299
3300 OpUsefulBits <<= Width;
3301 --OpUsefulBits;
3302
3303 if (Op.getOperand(1) == Orig) {
3304 // Copy the low bits from the result to bits starting from LSB.
3305 Mask = ResultUsefulBits & OpUsefulBits;
3306 Mask <<= LSB;
3307 }
3308
3309 if (Op.getOperand(0) == Orig)
3310 // Bits starting from LSB in the input contribute to the result.
3311 Mask |= (ResultUsefulBits & ~OpUsefulBits);
3312 } else {
3313 // The instruction is a BFI.
3314 uint64_t Width = MSB + 1;
3315 uint64_t LSB = UsefulBits.getBitWidth() - Imm;
3316
3317 OpUsefulBits <<= Width;
3318 --OpUsefulBits;
3319 OpUsefulBits <<= LSB;
3320
3321 if (Op.getOperand(1) == Orig) {
3322 // Copy the bits from the result to the zero bits.
3323 Mask = ResultUsefulBits & OpUsefulBits;
3324 Mask.lshrInPlace(LSB);
3325 }
3326
3327 if (Op.getOperand(0) == Orig)
3328 Mask |= (ResultUsefulBits & ~OpUsefulBits);
3329 }
3330
3331 UsefulBits &= Mask;
3332}
3333
3334static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits,
3335 SDValue Orig, unsigned Depth) {
3336
3337 // Users of this node should have already been instruction selected
3338 // FIXME: Can we turn that into an assert?
3339 if (!UserNode->isMachineOpcode())
3340 return;
3341
3342 switch (UserNode->getMachineOpcode()) {
3343 default:
3344 return;
3345 case AArch64::ANDSWri:
3346 case AArch64::ANDSXri:
3347 case AArch64::ANDWri:
3348 case AArch64::ANDXri:
3349 // We increment Depth only when we call the getUsefulBits
3350 return getUsefulBitsFromAndWithImmediate(SDValue(UserNode, 0), UsefulBits,
3351 Depth);
3352 case AArch64::UBFMWri:
3353 case AArch64::UBFMXri:
3354 return getUsefulBitsFromUBFM(SDValue(UserNode, 0), UsefulBits, Depth);
3355
3356 case AArch64::ORRWrs:
3357 case AArch64::ORRXrs:
3358 if (UserNode->getOperand(0) != Orig && UserNode->getOperand(1) == Orig)
3359 getUsefulBitsFromOrWithShiftedReg(SDValue(UserNode, 0), UsefulBits,
3360 Depth);
3361 return;
3362 case AArch64::BFMWri:
3363 case AArch64::BFMXri:
3364 return getUsefulBitsFromBFM(SDValue(UserNode, 0), Orig, UsefulBits, Depth);
3365
3366 case AArch64::STRBBui:
3367 case AArch64::STURBBi:
3368 if (UserNode->getOperand(0) != Orig)
3369 return;
3370 UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xff);
3371 return;
3372
3373 case AArch64::STRHHui:
3374 case AArch64::STURHHi:
3375 if (UserNode->getOperand(0) != Orig)
3376 return;
3377 UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xffff);
3378 return;
3379 }
3380}
3381
3382static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth) {
3384 return;
3385 // Initialize UsefulBits
3386 if (!Depth) {
3387 unsigned Bitwidth = Op.getScalarValueSizeInBits();
3388 // At the beginning, assume every produced bits is useful
3389 UsefulBits = APInt(Bitwidth, 0);
3390 UsefulBits.flipAllBits();
3391 }
3392 APInt UsersUsefulBits(UsefulBits.getBitWidth(), 0);
3393
3394 for (SDNode *Node : Op.getNode()->users()) {
3395 // A use cannot produce useful bits
3396 APInt UsefulBitsForUse = APInt(UsefulBits);
3397 getUsefulBitsForUse(Node, UsefulBitsForUse, Op, Depth);
3398 UsersUsefulBits |= UsefulBitsForUse;
3399 }
3400 // UsefulBits contains the produced bits that are meaningful for the
3401 // current definition, thus a user cannot make a bit meaningful at
3402 // this point
3403 UsefulBits &= UsersUsefulBits;
3404}
3405
3406/// Create a machine node performing a notional SHL of Op by ShlAmount. If
3407/// ShlAmount is negative, do a (logical) right-shift instead. If ShlAmount is
3408/// 0, return Op unchanged.
3409static SDValue getLeftShift(SelectionDAG *CurDAG, SDValue Op, int ShlAmount) {
3410 if (ShlAmount == 0)
3411 return Op;
3412
3413 EVT VT = Op.getValueType();
3414 SDLoc dl(Op);
3415 unsigned BitWidth = VT.getSizeInBits();
3416 unsigned UBFMOpc = BitWidth == 32 ? AArch64::UBFMWri : AArch64::UBFMXri;
3417
3418 SDNode *ShiftNode;
3419 if (ShlAmount > 0) {
3420 // LSL wD, wN, #Amt == UBFM wD, wN, #32-Amt, #31-Amt
3421 ShiftNode = CurDAG->getMachineNode(
3422 UBFMOpc, dl, VT, Op,
3423 CurDAG->getTargetConstant(BitWidth - ShlAmount, dl, VT),
3424 CurDAG->getTargetConstant(BitWidth - 1 - ShlAmount, dl, VT));
3425 } else {
3426 // LSR wD, wN, #Amt == UBFM wD, wN, #Amt, #32-1
3427 assert(ShlAmount < 0 && "expected right shift");
3428 int ShrAmount = -ShlAmount;
3429 ShiftNode = CurDAG->getMachineNode(
3430 UBFMOpc, dl, VT, Op, CurDAG->getTargetConstant(ShrAmount, dl, VT),
3431 CurDAG->getTargetConstant(BitWidth - 1, dl, VT));
3432 }
3433
3434 return SDValue(ShiftNode, 0);
3435}
3436
3437// For bit-field-positioning pattern "(and (shl VAL, N), ShiftedMask)".
3438static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op,
3439 bool BiggerPattern,
3440 const uint64_t NonZeroBits,
3441 SDValue &Src, int &DstLSB,
3442 int &Width);
3443
3444// For bit-field-positioning pattern "shl VAL, N)".
3445static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op,
3446 bool BiggerPattern,
3447 const uint64_t NonZeroBits,
3448 SDValue &Src, int &DstLSB,
3449 int &Width);
3450
3451/// Does this tree qualify as an attempt to move a bitfield into position,
3452/// essentially "(and (shl VAL, N), Mask)" or (shl VAL, N).
3454 bool BiggerPattern, SDValue &Src,
3455 int &DstLSB, int &Width) {
3456 EVT VT = Op.getValueType();
3457 unsigned BitWidth = VT.getSizeInBits();
3458 (void)BitWidth;
3459 assert(BitWidth == 32 || BitWidth == 64);
3460
3462
3463 // Non-zero in the sense that they're not provably zero, which is the key
3464 // point if we want to use this value
3465 const uint64_t NonZeroBits = (~Known.Zero).getZExtValue();
3466 if (!isShiftedMask_64(NonZeroBits))
3467 return false;
3468
3469 switch (Op.getOpcode()) {
3470 default:
3471 break;
3472 case ISD::AND:
3473 return isBitfieldPositioningOpFromAnd(CurDAG, Op, BiggerPattern,
3474 NonZeroBits, Src, DstLSB, Width);
3475 case ISD::SHL:
3476 return isBitfieldPositioningOpFromShl(CurDAG, Op, BiggerPattern,
3477 NonZeroBits, Src, DstLSB, Width);
3478 }
3479
3480 return false;
3481}
3482
3484 bool BiggerPattern,
3485 const uint64_t NonZeroBits,
3486 SDValue &Src, int &DstLSB,
3487 int &Width) {
3488 assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed");
3489
3490 EVT VT = Op.getValueType();
3491 assert((VT == MVT::i32 || VT == MVT::i64) &&
3492 "Caller guarantees VT is one of i32 or i64");
3493 (void)VT;
3494
3495 uint64_t AndImm;
3496 if (!isOpcWithIntImmediate(Op.getNode(), ISD::AND, AndImm))
3497 return false;
3498
3499 // If (~AndImm & NonZeroBits) is not zero at POS, we know that
3500 // 1) (AndImm & (1 << POS) == 0)
3501 // 2) the result of AND is not zero at POS bit (according to NonZeroBits)
3502 //
3503 // 1) and 2) don't agree so something must be wrong (e.g., in
3504 // 'SelectionDAG::computeKnownBits')
3505 assert((~AndImm & NonZeroBits) == 0 &&
3506 "Something must be wrong (e.g., in SelectionDAG::computeKnownBits)");
3507
3508 SDValue AndOp0 = Op.getOperand(0);
3509
3510 uint64_t ShlImm;
3511 SDValue ShlOp0;
3512 if (isOpcWithIntImmediate(AndOp0.getNode(), ISD::SHL, ShlImm)) {
3513 // For pattern "and(shl(val, N), shifted-mask)", 'ShlOp0' is set to 'val'.
3514 ShlOp0 = AndOp0.getOperand(0);
3515 } else if (VT == MVT::i64 && AndOp0.getOpcode() == ISD::ANY_EXTEND &&
3517 ShlImm)) {
3518 // For pattern "and(any_extend(shl(val, N)), shifted-mask)"
3519
3520 // ShlVal == shl(val, N), which is a left shift on a smaller type.
3521 SDValue ShlVal = AndOp0.getOperand(0);
3522
3523 // Since this is after type legalization and ShlVal is extended to MVT::i64,
3524 // expect VT to be MVT::i32.
3525 assert((ShlVal.getValueType() == MVT::i32) && "Expect VT to be MVT::i32.");
3526
3527 // Widens 'val' to MVT::i64 as the source of bit field positioning.
3528 ShlOp0 = Widen(CurDAG, ShlVal.getOperand(0));
3529 } else
3530 return false;
3531
3532 // For !BiggerPattern, bail out if the AndOp0 has more than one use, since
3533 // then we'll end up generating AndOp0+UBFIZ instead of just keeping
3534 // AndOp0+AND.
3535 if (!BiggerPattern && !AndOp0.hasOneUse())
3536 return false;
3537
3538 DstLSB = llvm::countr_zero(NonZeroBits);
3539 Width = llvm::countr_one(NonZeroBits >> DstLSB);
3540
3541 // Bail out on large Width. This happens when no proper combining / constant
3542 // folding was performed.
3543 if (Width >= (int)VT.getSizeInBits()) {
3544 // If VT is i64, Width > 64 is insensible since NonZeroBits is uint64_t, and
3545 // Width == 64 indicates a missed dag-combine from "(and val, AllOnes)" to
3546 // "val".
3547 // If VT is i32, what Width >= 32 means:
3548 // - For "(and (any_extend(shl val, N)), shifted-mask)", the`and` Op
3549 // demands at least 'Width' bits (after dag-combiner). This together with
3550 // `any_extend` Op (undefined higher bits) indicates missed combination
3551 // when lowering the 'and' IR instruction to an machine IR instruction.
3552 LLVM_DEBUG(
3553 dbgs()
3554 << "Found large Width in bit-field-positioning -- this indicates no "
3555 "proper combining / constant folding was performed\n");
3556 return false;
3557 }
3558
3559 // BFI encompasses sufficiently many nodes that it's worth inserting an extra
3560 // LSL/LSR if the mask in NonZeroBits doesn't quite match up with the ISD::SHL
3561 // amount. BiggerPattern is true when this pattern is being matched for BFI,
3562 // BiggerPattern is false when this pattern is being matched for UBFIZ, in
3563 // which case it is not profitable to insert an extra shift.
3564 if (ShlImm != uint64_t(DstLSB) && !BiggerPattern)
3565 return false;
3566
3567 Src = getLeftShift(CurDAG, ShlOp0, ShlImm - DstLSB);
3568 return true;
3569}
3570
3571// For node (shl (and val, mask), N)), returns true if the node is equivalent to
3572// UBFIZ.
3574 SDValue &Src, int &DstLSB,
3575 int &Width) {
3576 // Caller should have verified that N is a left shift with constant shift
3577 // amount; asserts that.
3578 assert(Op.getOpcode() == ISD::SHL &&
3579 "Op.getNode() should be a SHL node to call this function");
3580 assert(isIntImmediateEq(Op.getOperand(1), ShlImm) &&
3581 "Op.getNode() should shift ShlImm to call this function");
3582
3583 uint64_t AndImm = 0;
3584 SDValue Op0 = Op.getOperand(0);
3585 if (!isOpcWithIntImmediate(Op0.getNode(), ISD::AND, AndImm))
3586 return false;
3587
3588 const uint64_t ShiftedAndImm = ((AndImm << ShlImm) >> ShlImm);
3589 if (isMask_64(ShiftedAndImm)) {
3590 // AndImm is a superset of (AllOnes >> ShlImm); in other words, AndImm
3591 // should end with Mask, and could be prefixed with random bits if those
3592 // bits are shifted out.
3593 //
3594 // For example, xyz11111 (with {x,y,z} being 0 or 1) is fine if ShlImm >= 3;
3595 // the AND result corresponding to those bits are shifted out, so it's fine
3596 // to not extract them.
3597 Width = llvm::countr_one(ShiftedAndImm);
3598 DstLSB = ShlImm;
3599 Src = Op0.getOperand(0);
3600 return true;
3601 }
3602 return false;
3603}
3604
3606 bool BiggerPattern,
3607 const uint64_t NonZeroBits,
3608 SDValue &Src, int &DstLSB,
3609 int &Width) {
3610 assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed");
3611
3612 EVT VT = Op.getValueType();
3613 assert((VT == MVT::i32 || VT == MVT::i64) &&
3614 "Caller guarantees that type is i32 or i64");
3615 (void)VT;
3616
3617 uint64_t ShlImm;
3618 if (!isOpcWithIntImmediate(Op.getNode(), ISD::SHL, ShlImm))
3619 return false;
3620
3621 if (!BiggerPattern && !Op.hasOneUse())
3622 return false;
3623
3624 if (isSeveralBitsPositioningOpFromShl(ShlImm, Op, Src, DstLSB, Width))
3625 return true;
3626
3627 DstLSB = llvm::countr_zero(NonZeroBits);
3628 Width = llvm::countr_one(NonZeroBits >> DstLSB);
3629
3630 if (ShlImm != uint64_t(DstLSB) && !BiggerPattern)
3631 return false;
3632
3633 Src = getLeftShift(CurDAG, Op.getOperand(0), ShlImm - DstLSB);
3634 return true;
3635}
3636
3637static bool isShiftedMask(uint64_t Mask, EVT VT) {
3638 assert(VT == MVT::i32 || VT == MVT::i64);
3639 if (VT == MVT::i32)
3640 return isShiftedMask_32(Mask);
3641 return isShiftedMask_64(Mask);
3642}
3643
3644// Generate a BFI/BFXIL from 'or (and X, MaskImm), OrImm' iff the value being
3645// inserted only sets known zero bits.
3647 assert(N->getOpcode() == ISD::OR && "Expect a OR operation");
3648
3649 EVT VT = N->getValueType(0);
3650 if (VT != MVT::i32 && VT != MVT::i64)
3651 return false;
3652
3653 unsigned BitWidth = VT.getSizeInBits();
3654
3655 uint64_t OrImm;
3656 if (!isOpcWithIntImmediate(N, ISD::OR, OrImm))
3657 return false;
3658
3659 // Skip this transformation if the ORR immediate can be encoded in the ORR.
3660 // Otherwise, we'll trade an AND+ORR for ORR+BFI/BFXIL, which is most likely
3661 // performance neutral.
3663 return false;
3664
3665 uint64_t MaskImm;
3666 SDValue And = N->getOperand(0);
3667 // Must be a single use AND with an immediate operand.
3668 if (!And.hasOneUse() ||
3669 !isOpcWithIntImmediate(And.getNode(), ISD::AND, MaskImm))
3670 return false;
3671
3672 // Compute the Known Zero for the AND as this allows us to catch more general
3673 // cases than just looking for AND with imm.
3675
3676 // Non-zero in the sense that they're not provably zero, which is the key
3677 // point if we want to use this value.
3678 uint64_t NotKnownZero = (~Known.Zero).getZExtValue();
3679
3680 // The KnownZero mask must be a shifted mask (e.g., 1110..011, 11100..00).
3681 if (!isShiftedMask(Known.Zero.getZExtValue(), VT))
3682 return false;
3683
3684 // The bits being inserted must only set those bits that are known to be zero.
3685 if ((OrImm & NotKnownZero) != 0) {
3686 // FIXME: It's okay if the OrImm sets NotKnownZero bits to 1, but we don't
3687 // currently handle this case.
3688 return false;
3689 }
3690
3691 // BFI/BFXIL dst, src, #lsb, #width.
3692 int LSB = llvm::countr_one(NotKnownZero);
3693 int Width = BitWidth - APInt(BitWidth, NotKnownZero).popcount();
3694
3695 // BFI/BFXIL is an alias of BFM, so translate to BFM operands.
3696 unsigned ImmR = (BitWidth - LSB) % BitWidth;
3697 unsigned ImmS = Width - 1;
3698
3699 // If we're creating a BFI instruction avoid cases where we need more
3700 // instructions to materialize the BFI constant as compared to the original
3701 // ORR. A BFXIL will use the same constant as the original ORR, so the code
3702 // should be no worse in this case.
3703 bool IsBFI = LSB != 0;
3704 uint64_t BFIImm = OrImm >> LSB;
3705 if (IsBFI && !AArch64_AM::isLogicalImmediate(BFIImm, BitWidth)) {
3706 // We have a BFI instruction and we know the constant can't be materialized
3707 // with a ORR-immediate with the zero register.
3708 unsigned OrChunks = 0, BFIChunks = 0;
3709 for (unsigned Shift = 0; Shift < BitWidth; Shift += 16) {
3710 if (((OrImm >> Shift) & 0xFFFF) != 0)
3711 ++OrChunks;
3712 if (((BFIImm >> Shift) & 0xFFFF) != 0)
3713 ++BFIChunks;
3714 }
3715 if (BFIChunks > OrChunks)
3716 return false;
3717 }
3718
3719 // Materialize the constant to be inserted.
3720 SDLoc DL(N);
3721 unsigned MOVIOpc = VT == MVT::i32 ? AArch64::MOVi32imm : AArch64::MOVi64imm;
3722 SDNode *MOVI = CurDAG->getMachineNode(
3723 MOVIOpc, DL, VT, CurDAG->getTargetConstant(BFIImm, DL, VT));
3724
3725 // Create the BFI/BFXIL instruction.
3726 SDValue Ops[] = {And.getOperand(0), SDValue(MOVI, 0),
3727 CurDAG->getTargetConstant(ImmR, DL, VT),
3728 CurDAG->getTargetConstant(ImmS, DL, VT)};
3729 unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri;
3730 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
3731 return true;
3732}
3733
3735 SDValue &ShiftedOperand,
3736 uint64_t &EncodedShiftImm) {
3737 // Avoid folding Dst into ORR-with-shift if Dst has other uses than ORR.
3738 if (!Dst.hasOneUse())
3739 return false;
3740
3741 EVT VT = Dst.getValueType();
3742 assert((VT == MVT::i32 || VT == MVT::i64) &&
3743 "Caller should guarantee that VT is one of i32 or i64");
3744 const unsigned SizeInBits = VT.getSizeInBits();
3745
3746 SDLoc DL(Dst.getNode());
3747 uint64_t AndImm, ShlImm;
3748 if (isOpcWithIntImmediate(Dst.getNode(), ISD::AND, AndImm) &&
3749 isShiftedMask_64(AndImm)) {
3750 // Avoid transforming 'DstOp0' if it has other uses than the AND node.
3751 SDValue DstOp0 = Dst.getOperand(0);
3752 if (!DstOp0.hasOneUse())
3753 return false;
3754
3755 // An example to illustrate the transformation
3756 // From:
3757 // lsr x8, x1, #1
3758 // and x8, x8, #0x3f80
3759 // bfxil x8, x1, #0, #7
3760 // To:
3761 // and x8, x23, #0x7f
3762 // ubfx x9, x23, #8, #7
3763 // orr x23, x8, x9, lsl #7
3764 //
3765 // The number of instructions remains the same, but ORR is faster than BFXIL
3766 // on many AArch64 processors (or as good as BFXIL if not faster). Besides,
3767 // the dependency chain is improved after the transformation.
3768 uint64_t SrlImm;
3769 if (isOpcWithIntImmediate(DstOp0.getNode(), ISD::SRL, SrlImm)) {
3770 uint64_t NumTrailingZeroInShiftedMask = llvm::countr_zero(AndImm);
3771 if ((SrlImm + NumTrailingZeroInShiftedMask) < SizeInBits) {
3772 unsigned MaskWidth =
3773 llvm::countr_one(AndImm >> NumTrailingZeroInShiftedMask);
3774 unsigned UBFMOpc =
3775 (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri;
3776 SDNode *UBFMNode = CurDAG->getMachineNode(
3777 UBFMOpc, DL, VT, DstOp0.getOperand(0),
3778 CurDAG->getTargetConstant(SrlImm + NumTrailingZeroInShiftedMask, DL,
3779 VT),
3780 CurDAG->getTargetConstant(
3781 SrlImm + NumTrailingZeroInShiftedMask + MaskWidth - 1, DL, VT));
3782 ShiftedOperand = SDValue(UBFMNode, 0);
3783 EncodedShiftImm = AArch64_AM::getShifterImm(
3784 AArch64_AM::LSL, NumTrailingZeroInShiftedMask);
3785 return true;
3786 }
3787 }
3788 return false;
3789 }
3790
3791 if (isOpcWithIntImmediate(Dst.getNode(), ISD::SHL, ShlImm)) {
3792 ShiftedOperand = Dst.getOperand(0);
3793 EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm);
3794 return true;
3795 }
3796
3797 uint64_t SrlImm;
3798 if (isOpcWithIntImmediate(Dst.getNode(), ISD::SRL, SrlImm)) {
3799 ShiftedOperand = Dst.getOperand(0);
3800 EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm);
3801 return true;
3802 }
3803 return false;
3804}
3805
3806// Given an 'ISD::OR' node that is going to be selected as BFM, analyze
3807// the operands and select it to AArch64::ORR with shifted registers if
3808// that's more efficient. Returns true iff selection to AArch64::ORR happens.
3809static bool tryOrrWithShift(SDNode *N, SDValue OrOpd0, SDValue OrOpd1,
3810 SDValue Src, SDValue Dst, SelectionDAG *CurDAG,
3811 const bool BiggerPattern) {
3812 EVT VT = N->getValueType(0);
3813 assert(N->getOpcode() == ISD::OR && "Expect N to be an OR node");
3814 assert(((N->getOperand(0) == OrOpd0 && N->getOperand(1) == OrOpd1) ||
3815 (N->getOperand(1) == OrOpd0 && N->getOperand(0) == OrOpd1)) &&
3816 "Expect OrOpd0 and OrOpd1 to be operands of ISD::OR");
3817 assert((VT == MVT::i32 || VT == MVT::i64) &&
3818 "Expect result type to be i32 or i64 since N is combinable to BFM");
3819 SDLoc DL(N);
3820
3821 // Bail out if BFM simplifies away one node in BFM Dst.
3822 if (OrOpd1 != Dst)
3823 return false;
3824
3825 const unsigned OrrOpc = (VT == MVT::i32) ? AArch64::ORRWrs : AArch64::ORRXrs;
3826 // For "BFM Rd, Rn, #immr, #imms", it's known that BFM simplifies away fewer
3827 // nodes from Rn (or inserts additional shift node) if BiggerPattern is true.
3828 if (BiggerPattern) {
3829 uint64_t SrcAndImm;
3830 if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::AND, SrcAndImm) &&
3831 isMask_64(SrcAndImm) && OrOpd0.getOperand(0) == Src) {
3832 // OrOpd0 = AND Src, #Mask
3833 // So BFM simplifies away one AND node from Src and doesn't simplify away
3834 // nodes from Dst. If ORR with left-shifted operand also simplifies away
3835 // one node (from Rd), ORR is better since it has higher throughput and
3836 // smaller latency than BFM on many AArch64 processors (and for the rest
3837 // ORR is at least as good as BFM).
3838 SDValue ShiftedOperand;
3839 uint64_t EncodedShiftImm;
3840 if (isWorthFoldingIntoOrrWithShift(Dst, CurDAG, ShiftedOperand,
3841 EncodedShiftImm)) {
3842 SDValue Ops[] = {OrOpd0, ShiftedOperand,
3843 CurDAG->getTargetConstant(EncodedShiftImm, DL, VT)};
3844 CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops);
3845 return true;
3846 }
3847 }
3848 return false;
3849 }
3850
3851 assert((!BiggerPattern) && "BiggerPattern should be handled above");
3852
3853 uint64_t ShlImm;
3854 if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SHL, ShlImm)) {
3855 if (OrOpd0.getOperand(0) == Src && OrOpd0.hasOneUse()) {
3856 SDValue Ops[] = {
3857 Dst, Src,
3858 CurDAG->getTargetConstant(
3860 CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops);
3861 return true;
3862 }
3863
3864 // Select the following pattern to left-shifted operand rather than BFI.
3865 // %val1 = op ..
3866 // %val2 = shl %val1, #imm
3867 // %res = or %val1, %val2
3868 //
3869 // If N is selected to be BFI, we know that
3870 // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into
3871 // BFI) 2) OrOpd1 would be the destination operand (i.e., preserved)
3872 //
3873 // Instead of selecting N to BFI, fold OrOpd0 as a left shift directly.
3874 if (OrOpd0.getOperand(0) == OrOpd1) {
3875 SDValue Ops[] = {
3876 OrOpd1, OrOpd1,
3877 CurDAG->getTargetConstant(
3879 CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops);
3880 return true;
3881 }
3882 }
3883
3884 uint64_t SrlImm;
3885 if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SRL, SrlImm)) {
3886 // Select the following pattern to right-shifted operand rather than BFXIL.
3887 // %val1 = op ..
3888 // %val2 = lshr %val1, #imm
3889 // %res = or %val1, %val2
3890 //
3891 // If N is selected to be BFXIL, we know that
3892 // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into
3893 // BFXIL) 2) OrOpd1 would be the destination operand (i.e., preserved)
3894 //
3895 // Instead of selecting N to BFXIL, fold OrOpd0 as a right shift directly.
3896 if (OrOpd0.getOperand(0) == OrOpd1) {
3897 SDValue Ops[] = {
3898 OrOpd1, OrOpd1,
3899 CurDAG->getTargetConstant(
3901 CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops);
3902 return true;
3903 }
3904 }
3905
3906 return false;
3907}
3908
3909static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits,
3910 SelectionDAG *CurDAG) {
3911 assert(N->getOpcode() == ISD::OR && "Expect a OR operation");
3912
3913 EVT VT = N->getValueType(0);
3914 if (VT != MVT::i32 && VT != MVT::i64)
3915 return false;
3916
3917 unsigned BitWidth = VT.getSizeInBits();
3918
3919 // Because of simplify-demanded-bits in DAGCombine, involved masks may not
3920 // have the expected shape. Try to undo that.
3921
3922 unsigned NumberOfIgnoredLowBits = UsefulBits.countr_zero();
3923 unsigned NumberOfIgnoredHighBits = UsefulBits.countl_zero();
3924
3925 // Given a OR operation, check if we have the following pattern
3926 // ubfm c, b, imm, imm2 (or something that does the same jobs, see
3927 // isBitfieldExtractOp)
3928 // d = e & mask2 ; where mask is a binary sequence of 1..10..0 and
3929 // countTrailingZeros(mask2) == imm2 - imm + 1
3930 // f = d | c
3931 // if yes, replace the OR instruction with:
3932 // f = BFM Opd0, Opd1, LSB, MSB ; where LSB = imm, and MSB = imm2
3933
3934 // OR is commutative, check all combinations of operand order and values of
3935 // BiggerPattern, i.e.
3936 // Opd0, Opd1, BiggerPattern=false
3937 // Opd1, Opd0, BiggerPattern=false
3938 // Opd0, Opd1, BiggerPattern=true
3939 // Opd1, Opd0, BiggerPattern=true
3940 // Several of these combinations may match, so check with BiggerPattern=false
3941 // first since that will produce better results by matching more instructions
3942 // and/or inserting fewer extra instructions.
3943 for (int I = 0; I < 4; ++I) {
3944
3945 SDValue Dst, Src;
3946 unsigned ImmR, ImmS;
3947 bool BiggerPattern = I / 2;
3948 SDValue OrOpd0Val = N->getOperand(I % 2);
3949 SDNode *OrOpd0 = OrOpd0Val.getNode();
3950 SDValue OrOpd1Val = N->getOperand((I + 1) % 2);
3951 SDNode *OrOpd1 = OrOpd1Val.getNode();
3952
3953 unsigned BFXOpc;
3954 int DstLSB, Width;
3955 if (isBitfieldExtractOp(CurDAG, OrOpd0, BFXOpc, Src, ImmR, ImmS,
3956 NumberOfIgnoredLowBits, BiggerPattern)) {
3957 // Check that the returned opcode is compatible with the pattern,
3958 // i.e., same type and zero extended (U and not S)
3959 if ((BFXOpc != AArch64::UBFMXri && VT == MVT::i64) ||
3960 (BFXOpc != AArch64::UBFMWri && VT == MVT::i32))
3961 continue;
3962
3963 // Compute the width of the bitfield insertion
3964 DstLSB = 0;
3965 Width = ImmS - ImmR + 1;
3966 // FIXME: This constraint is to catch bitfield insertion we may
3967 // want to widen the pattern if we want to grab general bitfield
3968 // move case
3969 if (Width <= 0)
3970 continue;
3971
3972 // If the mask on the insertee is correct, we have a BFXIL operation. We
3973 // can share the ImmR and ImmS values from the already-computed UBFM.
3974 } else if (isBitfieldPositioningOp(CurDAG, OrOpd0Val,
3975 BiggerPattern,
3976 Src, DstLSB, Width)) {
3977 ImmR = (BitWidth - DstLSB) % BitWidth;
3978 ImmS = Width - 1;
3979 } else
3980 continue;
3981
3982 // Check the second part of the pattern
3983 EVT VT = OrOpd1Val.getValueType();
3984 assert((VT == MVT::i32 || VT == MVT::i64) && "unexpected OR operand");
3985
3986 // Compute the Known Zero for the candidate of the first operand.
3987 // This allows to catch more general case than just looking for
3988 // AND with imm. Indeed, simplify-demanded-bits may have removed
3989 // the AND instruction because it proves it was useless.
3990 KnownBits Known = CurDAG->computeKnownBits(OrOpd1Val);
3991
3992 // Check if there is enough room for the second operand to appear
3993 // in the first one
3994 APInt BitsToBeInserted =
3995 APInt::getBitsSet(Known.getBitWidth(), DstLSB, DstLSB + Width);
3996
3997 if ((BitsToBeInserted & ~Known.Zero) != 0)
3998 continue;
3999
4000 // Set the first operand
4001 uint64_t Imm;
4002 if (isOpcWithIntImmediate(OrOpd1, ISD::AND, Imm) &&
4003 isBitfieldDstMask(Imm, BitsToBeInserted, NumberOfIgnoredHighBits, VT))
4004 // In that case, we can eliminate the AND
4005 Dst = OrOpd1->getOperand(0);
4006 else
4007 // Maybe the AND has been removed by simplify-demanded-bits
4008 // or is useful because it discards more bits
4009 Dst = OrOpd1Val;
4010
4011 // Before selecting ISD::OR node to AArch64::BFM, see if an AArch64::ORR
4012 // with shifted operand is more efficient.
4013 if (tryOrrWithShift(N, OrOpd0Val, OrOpd1Val, Src, Dst, CurDAG,
4014 BiggerPattern))
4015 return true;
4016
4017 // both parts match
4018 SDLoc DL(N);
4019 SDValue Ops[] = {Dst, Src, CurDAG->getTargetConstant(ImmR, DL, VT),
4020 CurDAG->getTargetConstant(ImmS, DL, VT)};
4021 unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri;
4022 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
4023 return true;
4024 }
4025
4026 // Generate a BFXIL from 'or (and X, Mask0Imm), (and Y, Mask1Imm)' iff
4027 // Mask0Imm and ~Mask1Imm are equivalent and one of the MaskImms is a shifted
4028 // mask (e.g., 0x000ffff0).
4029 uint64_t Mask0Imm, Mask1Imm;
4030 SDValue And0 = N->getOperand(0);
4031 SDValue And1 = N->getOperand(1);
4032 if (And0.hasOneUse() && And1.hasOneUse() &&
4033 isOpcWithIntImmediate(And0.getNode(), ISD::AND, Mask0Imm) &&
4034 isOpcWithIntImmediate(And1.getNode(), ISD::AND, Mask1Imm) &&
4035 APInt(BitWidth, Mask0Imm) == ~APInt(BitWidth, Mask1Imm) &&
4036 (isShiftedMask(Mask0Imm, VT) || isShiftedMask(Mask1Imm, VT))) {
4037
4038 // ORR is commutative, so canonicalize to the form 'or (and X, Mask0Imm),
4039 // (and Y, Mask1Imm)' where Mask1Imm is the shifted mask masking off the
4040 // bits to be inserted.
4041 if (isShiftedMask(Mask0Imm, VT)) {
4042 std::swap(And0, And1);
4043 std::swap(Mask0Imm, Mask1Imm);
4044 }
4045
4046 SDValue Src = And1->getOperand(0);
4047 SDValue Dst = And0->getOperand(0);
4048 unsigned LSB = llvm::countr_zero(Mask1Imm);
4049 int Width = BitWidth - APInt(BitWidth, Mask0Imm).popcount();
4050
4051 // The BFXIL inserts the low-order bits from a source register, so right
4052 // shift the needed bits into place.
4053 SDLoc DL(N);
4054 unsigned ShiftOpc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri;
4055 uint64_t LsrImm = LSB;
4056 if (Src->hasOneUse() &&
4057 isOpcWithIntImmediate(Src.getNode(), ISD::SRL, LsrImm) &&
4058 (LsrImm + LSB) < BitWidth) {
4059 Src = Src->getOperand(0);
4060 LsrImm += LSB;
4061 }
4062
4063 SDNode *LSR = CurDAG->getMachineNode(
4064 ShiftOpc, DL, VT, Src, CurDAG->getTargetConstant(LsrImm, DL, VT),
4065 CurDAG->getTargetConstant(BitWidth - 1, DL, VT));
4066
4067 // BFXIL is an alias of BFM, so translate to BFM operands.
4068 unsigned ImmR = (BitWidth - LSB) % BitWidth;
4069 unsigned ImmS = Width - 1;
4070
4071 // Create the BFXIL instruction.
4072 SDValue Ops[] = {Dst, SDValue(LSR, 0),
4073 CurDAG->getTargetConstant(ImmR, DL, VT),
4074 CurDAG->getTargetConstant(ImmS, DL, VT)};
4075 unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri;
4076 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
4077 return true;
4078 }
4079
4080 return false;
4081}
4082
4083bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) {
4084 if (N->getOpcode() != ISD::OR)
4085 return false;
4086
4087 APInt NUsefulBits;
4088 getUsefulBits(SDValue(N, 0), NUsefulBits);
4089
4090 // If all bits are not useful, just return UNDEF.
4091 if (!NUsefulBits) {
4092 CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0));
4093 return true;
4094 }
4095
4096 if (tryBitfieldInsertOpFromOr(N, NUsefulBits, CurDAG))
4097 return true;
4098
4099 return tryBitfieldInsertOpFromOrAndImm(N, CurDAG);
4100}
4101
4102/// SelectBitfieldInsertInZeroOp - Match a UBFIZ instruction that is the
4103/// equivalent of a left shift by a constant amount followed by an and masking
4104/// out a contiguous set of bits.
4105bool AArch64DAGToDAGISel::tryBitfieldInsertInZeroOp(SDNode *N) {
4106 if (N->getOpcode() != ISD::AND)
4107 return false;
4108
4109 EVT VT = N->getValueType(0);
4110 if (VT != MVT::i32 && VT != MVT::i64)
4111 return false;
4112
4113 SDValue Op0;
4114 int DstLSB, Width;
4115 if (!isBitfieldPositioningOp(CurDAG, SDValue(N, 0), /*BiggerPattern=*/false,
4116 Op0, DstLSB, Width))
4117 return false;
4118
4119 // ImmR is the rotate right amount.
4120 unsigned ImmR = (VT.getSizeInBits() - DstLSB) % VT.getSizeInBits();
4121 // ImmS is the most significant bit of the source to be moved.
4122 unsigned ImmS = Width - 1;
4123
4124 SDLoc DL(N);
4125 SDValue Ops[] = {Op0, CurDAG->getTargetConstant(ImmR, DL, VT),
4126 CurDAG->getTargetConstant(ImmS, DL, VT)};
4127 unsigned Opc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri;
4128 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
4129 return true;
4130}
4131
4132/// tryShiftAmountMod - Take advantage of built-in mod of shift amount in
4133/// variable shift/rotate instructions.
4134bool AArch64DAGToDAGISel::tryShiftAmountMod(SDNode *N) {
4135 EVT VT = N->getValueType(0);
4136
4137 unsigned Opc;
4138 switch (N->getOpcode()) {
4139 case ISD::ROTR:
4140 Opc = (VT == MVT::i32) ? AArch64::RORVWr : AArch64::RORVXr;
4141 break;
4142 case ISD::SHL:
4143 Opc = (VT == MVT::i32) ? AArch64::LSLVWr : AArch64::LSLVXr;
4144 break;
4145 case ISD::SRL:
4146 Opc = (VT == MVT::i32) ? AArch64::LSRVWr : AArch64::LSRVXr;
4147 break;
4148 case ISD::SRA:
4149 Opc = (VT == MVT::i32) ? AArch64::ASRVWr : AArch64::ASRVXr;
4150 break;
4151 default:
4152 return false;
4153 }
4154
4155 uint64_t Size;
4156 uint64_t Bits;
4157 if (VT == MVT::i32) {
4158 Bits = 5;
4159 Size = 32;
4160 } else if (VT == MVT::i64) {
4161 Bits = 6;
4162 Size = 64;
4163 } else
4164 return false;
4165
4166 SDValue ShiftAmt = N->getOperand(1);
4167 SDLoc DL(N);
4168 SDValue NewShiftAmt;
4169
4170 // Skip over an extend of the shift amount.
4171 if (ShiftAmt->getOpcode() == ISD::ZERO_EXTEND ||
4172 ShiftAmt->getOpcode() == ISD::ANY_EXTEND)
4173 ShiftAmt = ShiftAmt->getOperand(0);
4174
4175 if (ShiftAmt->getOpcode() == ISD::ADD || ShiftAmt->getOpcode() == ISD::SUB) {
4176 SDValue Add0 = ShiftAmt->getOperand(0);
4177 SDValue Add1 = ShiftAmt->getOperand(1);
4178 uint64_t Add0Imm;
4179 uint64_t Add1Imm;
4180 if (isIntImmediate(Add1, Add1Imm) && (Add1Imm % Size == 0)) {
4181 // If we are shifting by X+/-N where N == 0 mod Size, then just shift by X
4182 // to avoid the ADD/SUB.
4183 NewShiftAmt = Add0;
4184 } else if (ShiftAmt->getOpcode() == ISD::SUB &&
4185 isIntImmediate(Add0, Add0Imm) && Add0Imm != 0 &&
4186 (Add0Imm % Size == 0)) {
4187 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X
4188 // to generate a NEG instead of a SUB from a constant.
4189 unsigned NegOpc;
4190 unsigned ZeroReg;
4191 EVT SubVT = ShiftAmt->getValueType(0);
4192 if (SubVT == MVT::i32) {
4193 NegOpc = AArch64::SUBWrr;
4194 ZeroReg = AArch64::WZR;
4195 } else {
4196 assert(SubVT == MVT::i64);
4197 NegOpc = AArch64::SUBXrr;
4198 ZeroReg = AArch64::XZR;
4199 }
4200 SDValue Zero =
4201 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT);
4202 MachineSDNode *Neg =
4203 CurDAG->getMachineNode(NegOpc, DL, SubVT, Zero, Add1);
4204 NewShiftAmt = SDValue(Neg, 0);
4205 } else if (ShiftAmt->getOpcode() == ISD::SUB &&
4206 isIntImmediate(Add0, Add0Imm) && (Add0Imm % Size == Size - 1)) {
4207 // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X
4208 // to generate a NOT instead of a SUB from a constant.
4209 unsigned NotOpc;
4210 unsigned ZeroReg;
4211 EVT SubVT = ShiftAmt->getValueType(0);
4212 if (SubVT == MVT::i32) {
4213 NotOpc = AArch64::ORNWrr;
4214 ZeroReg = AArch64::WZR;
4215 } else {
4216 assert(SubVT == MVT::i64);
4217 NotOpc = AArch64::ORNXrr;
4218 ZeroReg = AArch64::XZR;
4219 }
4220 SDValue Zero =
4221 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT);
4222 MachineSDNode *Not =
4223 CurDAG->getMachineNode(NotOpc, DL, SubVT, Zero, Add1);
4224 NewShiftAmt = SDValue(Not, 0);
4225 } else
4226 return false;
4227 } else {
4228 // If the shift amount is masked with an AND, check that the mask covers the
4229 // bits that are implicitly ANDed off by the above opcodes and if so, skip
4230 // the AND.
4231 uint64_t MaskImm;
4232 if (!isOpcWithIntImmediate(ShiftAmt.getNode(), ISD::AND, MaskImm) &&
4233 !isOpcWithIntImmediate(ShiftAmt.getNode(), AArch64ISD::ANDS, MaskImm))
4234 return false;
4235
4236 if ((unsigned)llvm::countr_one(MaskImm) < Bits)
4237 return false;
4238
4239 NewShiftAmt = ShiftAmt->getOperand(0);
4240 }
4241
4242 // Narrow/widen the shift amount to match the size of the shift operation.
4243 if (VT == MVT::i32)
4244 NewShiftAmt = narrowIfNeeded(CurDAG, NewShiftAmt);
4245 else if (VT == MVT::i64 && NewShiftAmt->getValueType(0) == MVT::i32) {
4246 SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, DL, MVT::i32);
4247 MachineSDNode *Ext = CurDAG->getMachineNode(AArch64::SUBREG_TO_REG, DL, VT,
4248 NewShiftAmt, SubReg);
4249 NewShiftAmt = SDValue(Ext, 0);
4250 }
4251
4252 SDValue Ops[] = {N->getOperand(0), NewShiftAmt};
4253 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
4254 return true;
4255}
4256
4258 SDValue &FixedPos,
4259 unsigned RegWidth,
4260 bool isReciprocal) {
4261 APFloat FVal(0.0);
4263 FVal = CN->getValueAPF();
4264 else if (LoadSDNode *LN = dyn_cast<LoadSDNode>(N)) {
4265 // Some otherwise illegal constants are allowed in this case.
4266 if (LN->getOperand(1).getOpcode() != AArch64ISD::ADDlow ||
4267 !isa<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1)))
4268 return false;
4269
4270 ConstantPoolSDNode *CN =
4271 dyn_cast<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1));
4272 FVal = cast<ConstantFP>(CN->getConstVal())->getValueAPF();
4273 } else
4274 return false;
4275
4276 if (unsigned FBits =
4277 CheckFixedPointOperandConstant(FVal, RegWidth, isReciprocal)) {
4278 FixedPos = CurDAG->getTargetConstant(FBits, SDLoc(N), MVT::i32);
4279 return true;
4280 }
4281
4282 return false;
4283}
4284
4286 SDValue N,
4287 SDValue &FixedPos,
4288 unsigned RegWidth,
4289 bool isReciprocal) {
4290 if ((N.getOpcode() == AArch64ISD::NVCAST || N.getOpcode() == ISD::BITCAST) &&
4291 N.getValueType().getScalarSizeInBits() ==
4292 N.getOperand(0).getValueType().getScalarSizeInBits())
4293 N = N.getOperand(0);
4294
4295 auto ImmToFloat = [RegWidth](APInt Imm) {
4296 switch (RegWidth) {
4297 case 16:
4298 return APFloat(APFloat::IEEEhalf(), Imm);
4299 case 32:
4300 return APFloat(APFloat::IEEEsingle(), Imm);
4301 case 64:
4302 return APFloat(APFloat::IEEEdouble(), Imm);
4303 default:
4304 llvm_unreachable("Unexpected RegWidth!");
4305 };
4306 };
4307
4308 APFloat FVal(0.0);
4309 switch (N->getOpcode()) {
4310 case AArch64ISD::MOVIshift:
4311 FVal = ImmToFloat(APInt(RegWidth, N.getConstantOperandVal(0)
4312 << N.getConstantOperandVal(1)));
4313 break;
4314 case AArch64ISD::FMOV:
4315 FVal = ImmToFloat(DecodeFMOVImm(N.getConstantOperandVal(0), RegWidth));
4316 break;
4317 case AArch64ISD::DUP:
4318 if (isa<ConstantSDNode>(N.getOperand(0)))
4319 FVal = ImmToFloat(N.getConstantOperandAPInt(0).trunc(RegWidth));
4320 else
4321 return false;
4322 break;
4323 default:
4324 return false;
4325 }
4326
4327 if (unsigned FBits =
4328 CheckFixedPointOperandConstant(FVal, RegWidth, isReciprocal)) {
4329 FixedPos = CurDAG->getTargetConstant(FBits, SDLoc(N), MVT::i32);
4330 return true;
4331 }
4332
4333 return false;
4334}
4335
4336bool AArch64DAGToDAGISel::SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos,
4337 unsigned RegWidth) {
4338 return checkCVTFixedPointOperandWithFBits(CurDAG, N, FixedPos, RegWidth,
4339 /*isReciprocal*/ false);
4340}
4341
4342bool AArch64DAGToDAGISel::SelectCVTFixedPointVec(SDValue N, SDValue &FixedPos,
4343 unsigned RegWidth) {
4345 CurDAG, N, FixedPos, RegWidth, /*isReciprocal*/ false);
4346}
4347
4348bool AArch64DAGToDAGISel::SelectCVTFixedPosRecipOperandVec(SDValue N,
4349 SDValue &FixedPos,
4350 unsigned RegWidth) {
4352 CurDAG, N, FixedPos, RegWidth, /*isReciprocal*/ true);
4353}
4354
4355bool AArch64DAGToDAGISel::SelectCVTFixedPosRecipOperand(SDValue N,
4356 SDValue &FixedPos,
4357 unsigned RegWidth) {
4358 return checkCVTFixedPointOperandWithFBits(CurDAG, N, FixedPos, RegWidth,
4359 /*isReciprocal*/ true);
4360}
4361
4362// Inspects a register string of the form o0:op1:CRn:CRm:op2 gets the fields
4363// of the string and obtains the integer values from them and combines these
4364// into a single value to be used in the MRS/MSR instruction.
4367 RegString.split(Fields, ':');
4368
4369 if (Fields.size() == 1)
4370 return -1;
4371
4372 assert(Fields.size() == 5
4373 && "Invalid number of fields in read register string");
4374
4376 bool AllIntFields = true;
4377
4378 for (StringRef Field : Fields) {
4379 unsigned IntField;
4380 AllIntFields &= !Field.getAsInteger(10, IntField);
4381 Ops.push_back(IntField);
4382 }
4383
4384 assert(AllIntFields &&
4385 "Unexpected non-integer value in special register string.");
4386 (void)AllIntFields;
4387
4388 // Need to combine the integer fields of the string into a single value
4389 // based on the bit encoding of MRS/MSR instruction.
4390 return (Ops[0] << 14) | (Ops[1] << 11) | (Ops[2] << 7) | (Ops[3] << 3) |
4391 (Ops[4]);
4392}
4393
4394// Lower the read_register intrinsic to an MRS instruction node if the special
4395// register string argument is either of the form detailed in the ALCE (the
4396// form described in getIntOperandsFromRegisterString) or is a named register
4397// known by the MRS SysReg mapper.
4398bool AArch64DAGToDAGISel::tryReadRegister(SDNode *N) {
4399 const auto *MD = cast<MDNodeSDNode>(N->getOperand(1));
4400 const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0));
4401 SDLoc DL(N);
4402
4403 bool ReadIs128Bit = N->getOpcode() == AArch64ISD::MRRS;
4404
4405 unsigned Opcode64Bit = AArch64::MRS;
4406 int Imm = getIntOperandFromRegisterString(RegString->getString());
4407 if (Imm == -1) {
4408 // No match, Use the sysreg mapper to map the remaining possible strings to
4409 // the value for the register to be used for the instruction operand.
4410 const auto *TheReg =
4411 AArch64SysReg::lookupSysRegByName(RegString->getString());
4412 if (TheReg && TheReg->Readable &&
4413 TheReg->haveFeatures(Subtarget->getFeatureBits()))
4414 Imm = TheReg->Encoding;
4415 else
4416 Imm = AArch64SysReg::parseGenericRegister(RegString->getString());
4417
4418 if (Imm == -1) {
4419 // Still no match, see if this is "pc" or give up.
4420 if (!ReadIs128Bit && RegString->getString() == "pc") {
4421 Opcode64Bit = AArch64::ADR;
4422 Imm = 0;
4423 } else {
4424 // Not a system register. It may name an allocatable 64-bit GPR/FPR read
4425 // by the MSVC __getReg/__getRegFp intrinsics. Emit a pseudo that
4426 // carries the source register as an immediate so the read does not
4427 // reference an undefined physical register (which the machine verifier
4428 // rejects); the AsmPrinter materializes the real mov/fmov.
4429 Register PReg = Subtarget->getTargetLowering()->matchRegisterName(
4430 RegString->getString());
4431 unsigned PseudoOp = 0;
4432 if (AArch64::GPR64RegClass.contains(PReg))
4433 PseudoOp = AArch64::READ_REGISTER_GPR64;
4434 else if (AArch64::FPR64RegClass.contains(PReg))
4435 PseudoOp = AArch64::READ_REGISTER_FPR64;
4436 if (!ReadIs128Bit && PseudoOp && N->getValueType(0) == MVT::i64) {
4437 CurDAG->SelectNodeTo(N, PseudoOp, MVT::i64, MVT::Other,
4438 {CurDAG->getTargetConstant(PReg, DL, MVT::i32),
4439 N->getOperand(0)});
4440 return true;
4441 }
4442 return false;
4443 }
4444 }
4445 }
4446
4447 SDValue InChain = N->getOperand(0);
4448 SDValue SysRegImm = CurDAG->getTargetConstant(Imm, DL, MVT::i32);
4449 if (!ReadIs128Bit) {
4450 CurDAG->SelectNodeTo(N, Opcode64Bit, MVT::i64, MVT::Other /* Chain */,
4451 {SysRegImm, InChain});
4452 } else {
4453 SDNode *MRRS = CurDAG->getMachineNode(
4454 AArch64::MRRS, DL,
4455 {MVT::Untyped /* XSeqPair */, MVT::Other /* Chain */},
4456 {SysRegImm, InChain});
4457
4458 // Sysregs are not endian. The even register always contains the low half
4459 // of the register.
4460 SDValue Lo = CurDAG->getTargetExtractSubreg(AArch64::sube64, DL, MVT::i64,
4461 SDValue(MRRS, 0));
4462 SDValue Hi = CurDAG->getTargetExtractSubreg(AArch64::subo64, DL, MVT::i64,
4463 SDValue(MRRS, 0));
4464 SDValue OutChain = SDValue(MRRS, 1);
4465
4466 ReplaceUses(SDValue(N, 0), Lo);
4467 ReplaceUses(SDValue(N, 1), Hi);
4468 ReplaceUses(SDValue(N, 2), OutChain);
4469 };
4470 return true;
4471}
4472
4473// Lower the write_register intrinsic to an MSR instruction node if the special
4474// register string argument is either of the form detailed in the ALCE (the
4475// form described in getIntOperandsFromRegisterString) or is a named register
4476// known by the MSR SysReg mapper.
4477bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) {
4478 const auto *MD = cast<MDNodeSDNode>(N->getOperand(1));
4479 const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0));
4480 SDLoc DL(N);
4481
4482 bool WriteIs128Bit = N->getOpcode() == AArch64ISD::MSRR;
4483
4484 if (!WriteIs128Bit) {
4485 // Check if the register was one of those allowed as the pstatefield value
4486 // in the MSR (immediate) instruction. To accept the values allowed in the
4487 // pstatefield for the MSR (immediate) instruction, we also require that an
4488 // immediate value has been provided as an argument, we know that this is
4489 // the case as it has been ensured by semantic checking.
4490 auto trySelectPState = [&](auto PMapper, unsigned State) {
4491 if (PMapper) {
4492 assert(isa<ConstantSDNode>(N->getOperand(2)) &&
4493 "Expected a constant integer expression.");
4494 unsigned Reg = PMapper->Encoding;
4495 uint64_t Immed = N->getConstantOperandVal(2);
4496 CurDAG->SelectNodeTo(
4497 N, State, MVT::Other, CurDAG->getTargetConstant(Reg, DL, MVT::i32),
4498 CurDAG->getTargetConstant(Immed, DL, MVT::i16), N->getOperand(0));
4499 return true;
4500 }
4501 return false;
4502 };
4503
4504 if (trySelectPState(
4505 AArch64PState::lookupPStateImm0_15ByName(RegString->getString()),
4506 AArch64::MSRpstateImm4))
4507 return true;
4508 if (trySelectPState(
4509 AArch64PState::lookupPStateImm0_1ByName(RegString->getString()),
4510 AArch64::MSRpstateImm1))
4511 return true;
4512 }
4513
4514 int Imm = getIntOperandFromRegisterString(RegString->getString());
4515 if (Imm == -1) {
4516 // Use the sysreg mapper to attempt to map the remaining possible strings
4517 // to the value for the register to be used for the MSR (register)
4518 // instruction operand.
4519 auto TheReg = AArch64SysReg::lookupSysRegByName(RegString->getString());
4520 if (TheReg && TheReg->Writeable &&
4521 TheReg->haveFeatures(Subtarget->getFeatureBits()))
4522 Imm = TheReg->Encoding;
4523 else
4524 Imm = AArch64SysReg::parseGenericRegister(RegString->getString());
4525
4526 if (Imm == -1) {
4527 // Used by the MSVC __setReg/__setRegFp intrinsics. Copy the value into
4528 // the physical register and keep it live with a FAKE_USE so the write is
4529 // not dead-eliminated. (getRegisterByName rejects allocatable registers,
4530 // so the generic write path cannot handle these.)
4531 Register PReg = Subtarget->getTargetLowering()->matchRegisterName(
4532 RegString->getString());
4533 bool IsGPR = AArch64::GPR64RegClass.contains(PReg);
4534 bool IsFPR = AArch64::FPR64RegClass.contains(PReg);
4535 if (!WriteIs128Bit && (IsGPR || IsFPR) &&
4536 N->getOperand(2).getValueType() == MVT::i64) {
4537 SDValue Copy =
4538 CurDAG->getCopyToReg(N->getOperand(0), DL, PReg, N->getOperand(2));
4539 SDValue RegOp = CurDAG->getRegister(PReg, MVT::i64);
4540 SDNode *FakeUse = CurDAG->getMachineNode(TargetOpcode::FAKE_USE, DL,
4541 MVT::Other, {RegOp, Copy});
4542 ReplaceUses(SDValue(N, 0), SDValue(FakeUse, 0));
4543 CurDAG->RemoveDeadNode(N);
4544 return true;
4545 }
4546 return false;
4547 }
4548 }
4549
4550 SDValue InChain = N->getOperand(0);
4551 if (!WriteIs128Bit) {
4552 CurDAG->SelectNodeTo(N, AArch64::MSR, MVT::Other,
4553 CurDAG->getTargetConstant(Imm, DL, MVT::i32),
4554 N->getOperand(2), InChain);
4555 } else {
4556 // No endian swap. The lower half always goes into the even subreg, and the
4557 // higher half always into the odd supreg.
4558 SDNode *Pair = CurDAG->getMachineNode(
4559 TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped /* XSeqPair */,
4560 {CurDAG->getTargetConstant(AArch64::XSeqPairsClassRegClass.getID(), DL,
4561 MVT::i32),
4562 N->getOperand(2),
4563 CurDAG->getTargetConstant(AArch64::sube64, DL, MVT::i32),
4564 N->getOperand(3),
4565 CurDAG->getTargetConstant(AArch64::subo64, DL, MVT::i32)});
4566
4567 CurDAG->SelectNodeTo(N, AArch64::MSRR, MVT::Other,
4568 CurDAG->getTargetConstant(Imm, DL, MVT::i32),
4569 SDValue(Pair, 0), InChain);
4570 }
4571
4572 return true;
4573}
4574
4575/// We've got special pseudo-instructions for these
4576bool AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) {
4577 unsigned Opcode;
4578 EVT MemTy = cast<MemSDNode>(N)->getMemoryVT();
4579
4580 // Leave IR for LSE if subtarget supports it.
4581 if (Subtarget->hasLSE()) return false;
4582
4583 if (MemTy == MVT::i8)
4584 Opcode = AArch64::CMP_SWAP_8;
4585 else if (MemTy == MVT::i16)
4586 Opcode = AArch64::CMP_SWAP_16;
4587 else if (MemTy == MVT::i32)
4588 Opcode = AArch64::CMP_SWAP_32;
4589 else if (MemTy == MVT::i64)
4590 Opcode = AArch64::CMP_SWAP_64;
4591 else
4592 llvm_unreachable("Unknown AtomicCmpSwap type");
4593
4594 MVT RegTy = MemTy == MVT::i64 ? MVT::i64 : MVT::i32;
4595 SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3),
4596 N->getOperand(0)};
4597 SDNode *CmpSwap = CurDAG->getMachineNode(
4598 Opcode, SDLoc(N),
4599 CurDAG->getVTList(RegTy, MVT::i32, MVT::Other), Ops);
4600
4601 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
4602 CurDAG->setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
4603
4604 ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0));
4605 ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2));
4606 CurDAG->RemoveDeadNode(N);
4607
4608 return true;
4609}
4610
4611bool AArch64DAGToDAGISel::SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm,
4612 SDValue &Shift, bool Negate) {
4613 if (!isa<ConstantSDNode>(N))
4614 return false;
4615
4616 APInt Val =
4617 cast<ConstantSDNode>(N)->getAPIntValue().trunc(VT.getFixedSizeInBits());
4618
4619 return SelectSVEAddSubImm(SDLoc(N), Val, VT, Imm, Shift, Negate);
4620}
4621
4622bool AArch64DAGToDAGISel::SelectSVEAddSubImm(SDLoc DL, APInt Val, MVT VT,
4623 SDValue &Imm, SDValue &Shift,
4624 bool Negate) {
4625 if (Negate)
4626 Val = -Val;
4627
4628 switch (VT.SimpleTy) {
4629 case MVT::i8:
4630 // All immediates are supported.
4631 Shift = CurDAG->getTargetConstant(0, DL, MVT::i32);
4632 Imm = CurDAG->getTargetConstant(Val.getZExtValue(), DL, MVT::i32);
4633 return true;
4634 case MVT::i16:
4635 case MVT::i32:
4636 case MVT::i64:
4637 // Support 8bit unsigned immediates.
4638 if ((Val & ~0xff) == 0) {
4639 Shift = CurDAG->getTargetConstant(0, DL, MVT::i32);
4640 Imm = CurDAG->getTargetConstant(Val.getZExtValue(), DL, MVT::i32);
4641 return true;
4642 }
4643 // Support 16bit unsigned immediates that are a multiple of 256.
4644 if ((Val & ~0xff00) == 0) {
4645 Shift = CurDAG->getTargetConstant(8, DL, MVT::i32);
4646 Imm = CurDAG->getTargetConstant(Val.lshr(8).getZExtValue(), DL, MVT::i32);
4647 return true;
4648 }
4649 break;
4650 default:
4651 break;
4652 }
4653
4654 return false;
4655}
4656
4657bool AArch64DAGToDAGISel::SelectSVEAddSubSSatImm(SDValue N, MVT VT,
4658 SDValue &Imm, SDValue &Shift,
4659 bool Negate) {
4660 if (!isa<ConstantSDNode>(N))
4661 return false;
4662
4663 SDLoc DL(N);
4664 int64_t Val = cast<ConstantSDNode>(N)
4665 ->getAPIntValue()
4667 .getSExtValue();
4668
4669 if (Negate)
4670 Val = -Val;
4671
4672 // Signed saturating instructions treat their immediate operand as unsigned,
4673 // whereas the related intrinsics define their operands to be signed. This
4674 // means we can only use the immediate form when the operand is non-negative.
4675 if (Val < 0)
4676 return false;
4677
4678 switch (VT.SimpleTy) {
4679 case MVT::i8:
4680 // All positive immediates are supported.
4681 Shift = CurDAG->getTargetConstant(0, DL, MVT::i32);
4682 Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32);
4683 return true;
4684 case MVT::i16:
4685 case MVT::i32:
4686 case MVT::i64:
4687 // Support 8bit positive immediates.
4688 if (Val <= 255) {
4689 Shift = CurDAG->getTargetConstant(0, DL, MVT::i32);
4690 Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32);
4691 return true;
4692 }
4693 // Support 16bit positive immediates that are a multiple of 256.
4694 if (Val <= 65280 && Val % 256 == 0) {
4695 Shift = CurDAG->getTargetConstant(8, DL, MVT::i32);
4696 Imm = CurDAG->getTargetConstant(Val >> 8, DL, MVT::i32);
4697 return true;
4698 }
4699 break;
4700 default:
4701 break;
4702 }
4703
4704 return false;
4705}
4706
4707bool AArch64DAGToDAGISel::SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm,
4708 SDValue &Shift) {
4709 if (!isa<ConstantSDNode>(N))
4710 return false;
4711
4712 SDLoc DL(N);
4713 int64_t Val = cast<ConstantSDNode>(N)
4714 ->getAPIntValue()
4715 .trunc(VT.getFixedSizeInBits())
4716 .getSExtValue();
4717 int32_t ImmVal, ShiftVal;
4718 if (!AArch64_AM::isSVECpyDupImm(VT.getScalarSizeInBits(), Val, ImmVal,
4719 ShiftVal))
4720 return false;
4721
4722 Shift = CurDAG->getTargetConstant(ShiftVal, DL, MVT::i32);
4723 Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32);
4724 return true;
4725}
4726
4727bool AArch64DAGToDAGISel::SelectSVESignedArithImm(SDValue N, SDValue &Imm) {
4728 if (auto CNode = dyn_cast<ConstantSDNode>(N))
4729 return SelectSVESignedArithImm(SDLoc(N), CNode->getAPIntValue(), Imm);
4730 return false;
4731}
4732
4733bool AArch64DAGToDAGISel::SelectSVESignedArithImm(SDLoc DL, APInt Val,
4734 SDValue &Imm) {
4735 int64_t ImmVal = Val.getSExtValue();
4736 if (ImmVal >= -128 && ImmVal < 128) {
4737 Imm = CurDAG->getSignedTargetConstant(ImmVal, DL, MVT::i32);
4738 return true;
4739 }
4740 return false;
4741}
4742
4743bool AArch64DAGToDAGISel::SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm) {
4744 if (auto CNode = dyn_cast<ConstantSDNode>(N)) {
4745 uint64_t ImmVal = CNode->getZExtValue();
4746
4747 switch (VT.SimpleTy) {
4748 case MVT::i8:
4749 ImmVal &= 0xFF;
4750 break;
4751 case MVT::i16:
4752 ImmVal &= 0xFFFF;
4753 break;
4754 case MVT::i32:
4755 ImmVal &= 0xFFFFFFFF;
4756 break;
4757 case MVT::i64:
4758 break;
4759 default:
4760 llvm_unreachable("Unexpected type");
4761 }
4762
4763 if (ImmVal < 256) {
4764 Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32);
4765 return true;
4766 }
4767 }
4768 return false;
4769}
4770
4771bool AArch64DAGToDAGISel::SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm,
4772 bool Invert) {
4773 uint64_t ImmVal;
4774 if (auto CI = dyn_cast<ConstantSDNode>(N))
4775 ImmVal = CI->getZExtValue();
4776 else if (auto CFP = dyn_cast<ConstantFPSDNode>(N))
4777 ImmVal = CFP->getValueAPF().bitcastToAPInt().getZExtValue();
4778 else
4779 return false;
4780
4781 if (Invert)
4782 ImmVal = ~ImmVal;
4783
4784 uint64_t encoding;
4785 if (!AArch64_AM::isSVELogicalImm(VT.getScalarSizeInBits(), ImmVal, encoding))
4786 return false;
4787
4788 Imm = CurDAG->getTargetConstant(encoding, SDLoc(N), MVT::i64);
4789 return true;
4790}
4791
4792// SVE shift intrinsics allow shift amounts larger than the element's bitwidth.
4793// Rather than attempt to normalise everything we can sometimes saturate the
4794// shift amount during selection. This function also allows for consistent
4795// isel patterns by ensuring the resulting "Imm" node is of the i32 type
4796// required by the instructions.
4797bool AArch64DAGToDAGISel::SelectSVEShiftImm(SDValue N, uint64_t Low,
4798 uint64_t High, bool AllowSaturation,
4799 SDValue &Imm) {
4800 if (auto *CN = dyn_cast<ConstantSDNode>(N)) {
4801 uint64_t ImmVal = CN->getZExtValue();
4802
4803 // Reject shift amounts that are too small.
4804 if (ImmVal < Low)
4805 return false;
4806
4807 // Reject or saturate shift amounts that are too big.
4808 if (ImmVal > High) {
4809 if (!AllowSaturation)
4810 return false;
4811 ImmVal = High;
4812 }
4813
4814 Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32);
4815 return true;
4816 }
4817
4818 return false;
4819}
4820
4821bool AArch64DAGToDAGISel::trySelectStackSlotTagP(SDNode *N) {
4822 // tagp(FrameIndex, IRGstack, tag_offset):
4823 // since the offset between FrameIndex and IRGstack is a compile-time
4824 // constant, this can be lowered to a single ADDG instruction.
4825 if (!(isa<FrameIndexSDNode>(N->getOperand(1)))) {
4826 return false;
4827 }
4828
4829 SDValue IRG_SP = N->getOperand(2);
4830 if (IRG_SP->getOpcode() != ISD::INTRINSIC_W_CHAIN ||
4831 IRG_SP->getConstantOperandVal(1) != Intrinsic::aarch64_irg_sp) {
4832 return false;
4833 }
4834
4835 const TargetLowering *TLI = getTargetLowering();
4836 SDLoc DL(N);
4837 int FI = cast<FrameIndexSDNode>(N->getOperand(1))->getIndex();
4838 SDValue FiOp = CurDAG->getTargetFrameIndex(
4839 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
4840 int TagOffset = N->getConstantOperandVal(3);
4841
4842 SDNode *Out = CurDAG->getMachineNode(
4843 AArch64::TAGPstack, DL, MVT::i64,
4844 {FiOp, CurDAG->getTargetConstant(0, DL, MVT::i64), N->getOperand(2),
4845 CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)});
4846 ReplaceNode(N, Out);
4847 return true;
4848}
4849
4850void AArch64DAGToDAGISel::SelectTagP(SDNode *N) {
4851 assert(isa<ConstantSDNode>(N->getOperand(3)) &&
4852 "llvm.aarch64.tagp third argument must be an immediate");
4853 if (trySelectStackSlotTagP(N))
4854 return;
4855 // FIXME: above applies in any case when offset between Op1 and Op2 is a
4856 // compile-time constant, not just for stack allocations.
4857
4858 // General case for unrelated pointers in Op1 and Op2.
4859 SDLoc DL(N);
4860 int TagOffset = N->getConstantOperandVal(3);
4861 SDNode *N1 = CurDAG->getMachineNode(AArch64::SUBP, DL, MVT::i64,
4862 {N->getOperand(1), N->getOperand(2)});
4863 SDNode *N2 = CurDAG->getMachineNode(AArch64::ADDXrr, DL, MVT::i64,
4864 {SDValue(N1, 0), N->getOperand(2)});
4865 SDNode *N3 = CurDAG->getMachineNode(
4866 AArch64::ADDG, DL, MVT::i64,
4867 {SDValue(N2, 0), CurDAG->getTargetConstant(0, DL, MVT::i64),
4868 CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)});
4869 ReplaceNode(N, N3);
4870}
4871
4872bool AArch64DAGToDAGISel::trySelectCastFixedLengthToScalableVector(SDNode *N) {
4873 assert(N->getOpcode() == ISD::INSERT_SUBVECTOR && "Invalid Node!");
4874
4875 // Bail when not a "cast" like insert_subvector.
4876 if (N->getConstantOperandVal(2) != 0)
4877 return false;
4878 if (!N->getOperand(0).isUndef())
4879 return false;
4880
4881 // Bail when normal isel should do the job.
4882 EVT VT = N->getValueType(0);
4883 EVT InVT = N->getOperand(1).getValueType();
4884 if (VT.isFixedLengthVector() || InVT.isScalableVector())
4885 return false;
4886 if (InVT.getSizeInBits() <= 128)
4887 return false;
4888
4889 // NOTE: We can only get here when doing fixed length SVE code generation.
4890 // We do manual selection because the types involved are not linked to real
4891 // registers (despite being legal) and must be coerced into SVE registers.
4892
4894 "Expected to insert into a packed scalable vector!");
4895
4896 SDLoc DL(N);
4897 auto RC = CurDAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64);
4898 ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT,
4899 N->getOperand(1), RC));
4900 return true;
4901}
4902
4903bool AArch64DAGToDAGISel::trySelectCastScalableToFixedLengthVector(SDNode *N) {
4904 assert(N->getOpcode() == ISD::EXTRACT_SUBVECTOR && "Invalid Node!");
4905
4906 // Bail when not a "cast" like extract_subvector.
4907 if (N->getConstantOperandVal(1) != 0)
4908 return false;
4909
4910 // Bail when normal isel can do the job.
4911 EVT VT = N->getValueType(0);
4912 EVT InVT = N->getOperand(0).getValueType();
4913 if (VT.isScalableVector() || InVT.isFixedLengthVector())
4914 return false;
4915 if (VT.getSizeInBits() <= 128)
4916 return false;
4917
4918 // NOTE: We can only get here when doing fixed length SVE code generation.
4919 // We do manual selection because the types involved are not linked to real
4920 // registers (despite being legal) and must be coerced into SVE registers.
4921
4923 "Expected to extract from a packed scalable vector!");
4924
4925 SDLoc DL(N);
4926 auto RC = CurDAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64);
4927 ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT,
4928 N->getOperand(0), RC));
4929 return true;
4930}
4931
4932bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) {
4933 assert(N->getOpcode() == ISD::OR && "Expected OR instruction");
4934
4935 SDValue N0 = N->getOperand(0);
4936 SDValue N1 = N->getOperand(1);
4937
4938 EVT VT = N->getValueType(0);
4939 SDLoc DL(N);
4940
4941 // Essentially: rotr (xor(x, y), imm) -> xar (x, y, imm)
4942 // Rotate by a constant is a funnel shift in IR which is expanded to
4943 // an OR with shifted operands.
4944 // We do the following transform:
4945 // OR N0, N1 -> xar (x, y, imm)
4946 // Where:
4947 // N1 = SRL_PRED true, V, splat(imm) --> rotr amount
4948 // N0 = SHL_PRED true, V, splat(bits-imm)
4949 // V = (xor x, y)
4950 if (VT.isScalableVector() &&
4951 (Subtarget->hasSVE2() ||
4952 (Subtarget->hasSME() && Subtarget->isStreaming()))) {
4953 if (N0.getOpcode() != AArch64ISD::SHL_PRED ||
4954 N1.getOpcode() != AArch64ISD::SRL_PRED)
4955 std::swap(N0, N1);
4956 if (N0.getOpcode() != AArch64ISD::SHL_PRED ||
4957 N1.getOpcode() != AArch64ISD::SRL_PRED)
4958 return false;
4959
4960 auto *TLI = static_cast<const AArch64TargetLowering *>(getTargetLowering());
4961 if (!TLI->isAllActivePredicate(*CurDAG, N0.getOperand(0)) ||
4962 !TLI->isAllActivePredicate(*CurDAG, N1.getOperand(0)))
4963 return false;
4964
4965 if (N0.getOperand(1) != N1.getOperand(1))
4966 return false;
4967
4968 SDValue R1, R2;
4969 bool IsXOROperand = true;
4970 if (N0.getOperand(1).getOpcode() != ISD::XOR) {
4971 IsXOROperand = false;
4972 } else {
4973 R1 = N0.getOperand(1).getOperand(0);
4974 R2 = N1.getOperand(1).getOperand(1);
4975 }
4976
4977 APInt ShlAmt, ShrAmt;
4978 if (!ISD::isConstantSplatVector(N0.getOperand(2).getNode(), ShlAmt) ||
4980 return false;
4981
4982 if (ShlAmt + ShrAmt != VT.getScalarSizeInBits())
4983 return false;
4984
4985 if (!IsXOROperand) {
4986 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i64);
4987 SDNode *MOV = CurDAG->getMachineNode(AArch64::MOVIv2d_ns, DL, VT, Zero);
4988 SDValue MOVIV = SDValue(MOV, 0);
4989
4990 SDValue ZSub = CurDAG->getTargetConstant(AArch64::zsub, DL, MVT::i32);
4991 SDNode *SubRegToReg =
4992 CurDAG->getMachineNode(AArch64::SUBREG_TO_REG, DL, VT, MOVIV, ZSub);
4993
4994 R1 = N1->getOperand(1);
4995 R2 = SDValue(SubRegToReg, 0);
4996 }
4997
4998 SDValue Imm =
4999 CurDAG->getTargetConstant(ShrAmt.getZExtValue(), DL, MVT::i32);
5000
5001 SDValue Ops[] = {R1, R2, Imm};
5003 VT, {AArch64::XAR_ZZZI_B, AArch64::XAR_ZZZI_H, AArch64::XAR_ZZZI_S,
5004 AArch64::XAR_ZZZI_D})) {
5005 CurDAG->SelectNodeTo(N, Opc, VT, Ops);
5006 return true;
5007 }
5008 return false;
5009 }
5010
5011 // We have Neon SHA3 XAR operation for v2i64 but for types
5012 // v4i32, v8i16, v16i8 we can use SVE operations when SVE2-SHA3
5013 // is available.
5014 EVT SVT;
5015 switch (VT.getSimpleVT().SimpleTy) {
5016 case MVT::v4i32:
5017 case MVT::v2i32:
5018 SVT = MVT::nxv4i32;
5019 break;
5020 case MVT::v8i16:
5021 case MVT::v4i16:
5022 SVT = MVT::nxv8i16;
5023 break;
5024 case MVT::v16i8:
5025 case MVT::v8i8:
5026 SVT = MVT::nxv16i8;
5027 break;
5028 case MVT::v2i64:
5029 case MVT::v1i64:
5030 SVT = Subtarget->hasSHA3() ? MVT::v2i64 : MVT::nxv2i64;
5031 break;
5032 default:
5033 return false;
5034 }
5035
5036 if ((!SVT.isScalableVector() && !Subtarget->hasSHA3()) ||
5037 (SVT.isScalableVector() && !Subtarget->hasSVE2()))
5038 return false;
5039
5040 if (N0->getOpcode() != AArch64ISD::VSHL ||
5041 N1->getOpcode() != AArch64ISD::VLSHR)
5042 return false;
5043
5044 if (N0->getOperand(0) != N1->getOperand(0))
5045 return false;
5046
5047 SDValue R1, R2;
5048 bool IsXOROperand = true;
5049 if (N1->getOperand(0)->getOpcode() != ISD::XOR) {
5050 IsXOROperand = false;
5051 } else {
5052 SDValue XOR = N0.getOperand(0);
5053 R1 = XOR.getOperand(0);
5054 R2 = XOR.getOperand(1);
5055 }
5056
5057 unsigned HsAmt = N0.getConstantOperandVal(1);
5058 unsigned ShAmt = N1.getConstantOperandVal(1);
5059
5060 SDValue Imm = CurDAG->getTargetConstant(
5061 ShAmt, DL, N0.getOperand(1).getValueType(), false);
5062
5063 unsigned VTSizeInBits = VT.getScalarSizeInBits();
5064 if (ShAmt + HsAmt != VTSizeInBits)
5065 return false;
5066
5067 if (!IsXOROperand) {
5068 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i64);
5069 SDNode *MOV =
5070 CurDAG->getMachineNode(AArch64::MOVIv2d_ns, DL, MVT::v2i64, Zero);
5071 SDValue MOVIV = SDValue(MOV, 0);
5072
5073 R1 = N1->getOperand(0);
5074 R2 = MOVIV;
5075 }
5076
5077 if (SVT != VT) {
5078 SDValue Undef =
5079 SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, SVT), 0);
5080
5081 if (SVT.isScalableVector() && VT.is64BitVector()) {
5082 EVT QVT = VT.getDoubleNumVectorElementsVT(*CurDAG->getContext());
5083
5084 SDValue UndefQ = SDValue(
5085 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, QVT), 0);
5086 SDValue DSub = CurDAG->getTargetConstant(AArch64::dsub, DL, MVT::i32);
5087
5088 R1 = SDValue(CurDAG->getMachineNode(AArch64::INSERT_SUBREG, DL, QVT,
5089 UndefQ, R1, DSub),
5090 0);
5091 if (R2.getValueType() == VT)
5092 R2 = SDValue(CurDAG->getMachineNode(AArch64::INSERT_SUBREG, DL, QVT,
5093 UndefQ, R2, DSub),
5094 0);
5095 }
5096
5097 SDValue SubReg = CurDAG->getTargetConstant(
5098 (SVT.isScalableVector() ? AArch64::zsub : AArch64::dsub), DL, MVT::i32);
5099
5100 R1 = SDValue(CurDAG->getMachineNode(AArch64::INSERT_SUBREG, DL, SVT, Undef,
5101 R1, SubReg),
5102 0);
5103
5104 if (SVT.isScalableVector() || R2.getValueType() != SVT)
5105 R2 = SDValue(CurDAG->getMachineNode(AArch64::INSERT_SUBREG, DL, SVT,
5106 Undef, R2, SubReg),
5107 0);
5108 }
5109
5110 SDValue Ops[] = {R1, R2, Imm};
5111 SDNode *XAR = nullptr;
5112
5113 if (SVT.isScalableVector()) {
5115 SVT, {AArch64::XAR_ZZZI_B, AArch64::XAR_ZZZI_H, AArch64::XAR_ZZZI_S,
5116 AArch64::XAR_ZZZI_D}))
5117 XAR = CurDAG->getMachineNode(Opc, DL, SVT, Ops);
5118 } else {
5119 XAR = CurDAG->getMachineNode(AArch64::XAR, DL, SVT, Ops);
5120 }
5121
5122 assert(XAR && "Unexpected NULL value for XAR instruction in DAG");
5123
5124 if (SVT != VT) {
5125 if (VT.is64BitVector() && SVT.isScalableVector()) {
5126 EVT QVT = VT.getDoubleNumVectorElementsVT(*CurDAG->getContext());
5127
5128 SDValue ZSub = CurDAG->getTargetConstant(AArch64::zsub, DL, MVT::i32);
5129 SDNode *Q = CurDAG->getMachineNode(AArch64::EXTRACT_SUBREG, DL, QVT,
5130 SDValue(XAR, 0), ZSub);
5131
5132 SDValue DSub = CurDAG->getTargetConstant(AArch64::dsub, DL, MVT::i32);
5133 XAR = CurDAG->getMachineNode(AArch64::EXTRACT_SUBREG, DL, VT,
5134 SDValue(Q, 0), DSub);
5135 } else {
5136 SDValue SubReg = CurDAG->getTargetConstant(
5137 (SVT.isScalableVector() ? AArch64::zsub : AArch64::dsub), DL,
5138 MVT::i32);
5139 XAR = CurDAG->getMachineNode(AArch64::EXTRACT_SUBREG, DL, VT,
5140 SDValue(XAR, 0), SubReg);
5141 }
5142 }
5143 ReplaceNode(N, XAR);
5144 return true;
5145}
5146
5147/// Returns a copy from WZR or XZR. This can be used during instruction
5148/// selection (it does not require any further selection/legalization).
5150 assert(VT == MVT::i32 || VT == MVT::i64);
5151 return DAG.getCopyFromReg(DAG.getEntryNode(), DL,
5152 VT == MVT::i32 ? AArch64::WZR : AArch64::XZR, VT);
5153}
5154
5155void AArch64DAGToDAGISel::Select(SDNode *Node) {
5156 // If we have a custom node, we already have selected!
5157 if (Node->isMachineOpcode()) {
5158 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
5159 Node->setNodeId(-1);
5160 return;
5161 }
5162
5163 // Few custom selection stuff.
5164 EVT VT = Node->getValueType(0);
5165
5166 switch (Node->getOpcode()) {
5167 default:
5168 break;
5169
5171 if (SelectCMP_SWAP(Node))
5172 return;
5173 break;
5174
5175 case ISD::READ_REGISTER:
5176 case AArch64ISD::MRRS:
5177 if (tryReadRegister(Node))
5178 return;
5179 break;
5180
5182 case AArch64ISD::MSRR:
5183 if (tryWriteRegister(Node))
5184 return;
5185 break;
5186
5187 case ISD::LOAD: {
5188 // Try to select as an indexed load. Fall through to normal processing
5189 // if we can't.
5190 if (tryIndexedLoad(Node))
5191 return;
5192 break;
5193 }
5194
5195 case ISD::SRL:
5196 case ISD::AND:
5197 case ISD::SRA:
5199 if (tryBitfieldExtractOp(Node))
5200 return;
5201 if (tryBitfieldInsertInZeroOp(Node))
5202 return;
5203 [[fallthrough]];
5204 case ISD::ROTR:
5205 case ISD::SHL:
5206 if (tryShiftAmountMod(Node))
5207 return;
5208 break;
5209
5210 case ISD::SIGN_EXTEND:
5211 if (tryBitfieldExtractOpFromSExt(Node))
5212 return;
5213 break;
5214
5215 case ISD::OR:
5216 if (tryBitfieldInsertOp(Node))
5217 return;
5218 if (trySelectXAR(Node))
5219 return;
5220 break;
5221
5223 if (trySelectCastScalableToFixedLengthVector(Node))
5224 return;
5225 break;
5226 }
5227
5228 case ISD::INSERT_SUBVECTOR: {
5229 if (trySelectCastFixedLengthToScalableVector(Node))
5230 return;
5231 break;
5232 }
5233
5234 case AArch64ISD::CSEL:
5235 if (tryFoldCselToFMaxMin(Node))
5236 return;
5237 break;
5238
5239 case ISD::Constant: {
5240 // Materialize zero constants as copies from WZR/XZR. This allows
5241 // the coalescer to propagate these into other instructions.
5242 ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node);
5243 if (ConstNode->isZero() && (VT == MVT::i32 || VT == MVT::i64)) {
5244 ReplaceNode(Node, getZeroRegister(*CurDAG, SDLoc(Node), VT).getNode());
5245 return;
5246 }
5247 break;
5248 }
5249
5250 case ISD::FrameIndex: {
5251 // Selects to ADDXri FI, 0 which in turn will become ADDXri SP, imm.
5252 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
5253 unsigned Shifter = AArch64_AM::getShifterImm(AArch64_AM::LSL, 0);
5254 const TargetLowering *TLI = getTargetLowering();
5255 SDValue TFI = CurDAG->getTargetFrameIndex(
5256 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
5257 SDLoc DL(Node);
5258 SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, DL, MVT::i32),
5259 CurDAG->getTargetConstant(Shifter, DL, MVT::i32) };
5260 CurDAG->SelectNodeTo(Node, AArch64::ADDXri, MVT::i64, Ops);
5261 return;
5262 }
5264 unsigned IntNo = Node->getConstantOperandVal(1);
5265 switch (IntNo) {
5266 default:
5267 break;
5268 case Intrinsic::aarch64_gcsss: {
5269 SDLoc DL(Node);
5270 SDValue Chain = Node->getOperand(0);
5271 SDValue Val = Node->getOperand(2);
5272 SDValue Zero = CurDAG->getCopyFromReg(Chain, DL, AArch64::XZR, MVT::i64);
5273 SDNode *SS1 =
5274 CurDAG->getMachineNode(AArch64::GCSSS1, DL, MVT::Other, Val, Chain);
5275 SDNode *SS2 = CurDAG->getMachineNode(AArch64::GCSSS2, DL, MVT::i64,
5276 MVT::Other, Zero, SDValue(SS1, 0));
5277 ReplaceNode(Node, SS2);
5278 return;
5279 }
5280 case Intrinsic::aarch64_ldaxp:
5281 case Intrinsic::aarch64_ldxp: {
5282 unsigned Op =
5283 IntNo == Intrinsic::aarch64_ldaxp ? AArch64::LDAXPX : AArch64::LDXPX;
5284 SDValue MemAddr = Node->getOperand(2);
5285 SDLoc DL(Node);
5286 SDValue Chain = Node->getOperand(0);
5287
5288 SDNode *Ld = CurDAG->getMachineNode(Op, DL, MVT::i64, MVT::i64,
5289 MVT::Other, MemAddr, Chain);
5290
5291 // Transfer memoperands.
5292 MachineMemOperand *MemOp =
5293 cast<MemIntrinsicSDNode>(Node)->getMemOperand();
5294 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp});
5295 ReplaceNode(Node, Ld);
5296 return;
5297 }
5298 case Intrinsic::aarch64_stlxp:
5299 case Intrinsic::aarch64_stxp: {
5300 unsigned Op =
5301 IntNo == Intrinsic::aarch64_stlxp ? AArch64::STLXPX : AArch64::STXPX;
5302 SDLoc DL(Node);
5303 SDValue Chain = Node->getOperand(0);
5304 SDValue ValLo = Node->getOperand(2);
5305 SDValue ValHi = Node->getOperand(3);
5306 SDValue MemAddr = Node->getOperand(4);
5307
5308 // Place arguments in the right order.
5309 SDValue Ops[] = {ValLo, ValHi, MemAddr, Chain};
5310
5311 SDNode *St = CurDAG->getMachineNode(Op, DL, MVT::i32, MVT::Other, Ops);
5312 // Transfer memoperands.
5313 MachineMemOperand *MemOp =
5314 cast<MemIntrinsicSDNode>(Node)->getMemOperand();
5315 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
5316
5317 ReplaceNode(Node, St);
5318 return;
5319 }
5320 case Intrinsic::aarch64_neon_ld1x2:
5321 if (VT == MVT::v8i8) {
5322 SelectLoad(Node, 2, AArch64::LD1Twov8b, AArch64::dsub0);
5323 return;
5324 } else if (VT == MVT::v16i8) {
5325 SelectLoad(Node, 2, AArch64::LD1Twov16b, AArch64::qsub0);
5326 return;
5327 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5328 SelectLoad(Node, 2, AArch64::LD1Twov4h, AArch64::dsub0);
5329 return;
5330 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5331 SelectLoad(Node, 2, AArch64::LD1Twov8h, AArch64::qsub0);
5332 return;
5333 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5334 SelectLoad(Node, 2, AArch64::LD1Twov2s, AArch64::dsub0);
5335 return;
5336 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5337 SelectLoad(Node, 2, AArch64::LD1Twov4s, AArch64::qsub0);
5338 return;
5339 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5340 SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0);
5341 return;
5342 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5343 SelectLoad(Node, 2, AArch64::LD1Twov2d, AArch64::qsub0);
5344 return;
5345 }
5346 break;
5347 case Intrinsic::aarch64_neon_ld1x3:
5348 if (VT == MVT::v8i8) {
5349 SelectLoad(Node, 3, AArch64::LD1Threev8b, AArch64::dsub0);
5350 return;
5351 } else if (VT == MVT::v16i8) {
5352 SelectLoad(Node, 3, AArch64::LD1Threev16b, AArch64::qsub0);
5353 return;
5354 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5355 SelectLoad(Node, 3, AArch64::LD1Threev4h, AArch64::dsub0);
5356 return;
5357 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5358 SelectLoad(Node, 3, AArch64::LD1Threev8h, AArch64::qsub0);
5359 return;
5360 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5361 SelectLoad(Node, 3, AArch64::LD1Threev2s, AArch64::dsub0);
5362 return;
5363 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5364 SelectLoad(Node, 3, AArch64::LD1Threev4s, AArch64::qsub0);
5365 return;
5366 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5367 SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0);
5368 return;
5369 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5370 SelectLoad(Node, 3, AArch64::LD1Threev2d, AArch64::qsub0);
5371 return;
5372 }
5373 break;
5374 case Intrinsic::aarch64_neon_ld1x4:
5375 if (VT == MVT::v8i8) {
5376 SelectLoad(Node, 4, AArch64::LD1Fourv8b, AArch64::dsub0);
5377 return;
5378 } else if (VT == MVT::v16i8) {
5379 SelectLoad(Node, 4, AArch64::LD1Fourv16b, AArch64::qsub0);
5380 return;
5381 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5382 SelectLoad(Node, 4, AArch64::LD1Fourv4h, AArch64::dsub0);
5383 return;
5384 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5385 SelectLoad(Node, 4, AArch64::LD1Fourv8h, AArch64::qsub0);
5386 return;
5387 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5388 SelectLoad(Node, 4, AArch64::LD1Fourv2s, AArch64::dsub0);
5389 return;
5390 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5391 SelectLoad(Node, 4, AArch64::LD1Fourv4s, AArch64::qsub0);
5392 return;
5393 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5394 SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0);
5395 return;
5396 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5397 SelectLoad(Node, 4, AArch64::LD1Fourv2d, AArch64::qsub0);
5398 return;
5399 }
5400 break;
5401 case Intrinsic::aarch64_neon_ld2:
5402 if (VT == MVT::v8i8) {
5403 SelectLoad(Node, 2, AArch64::LD2Twov8b, AArch64::dsub0);
5404 return;
5405 } else if (VT == MVT::v16i8) {
5406 SelectLoad(Node, 2, AArch64::LD2Twov16b, AArch64::qsub0);
5407 return;
5408 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5409 SelectLoad(Node, 2, AArch64::LD2Twov4h, AArch64::dsub0);
5410 return;
5411 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5412 SelectLoad(Node, 2, AArch64::LD2Twov8h, AArch64::qsub0);
5413 return;
5414 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5415 SelectLoad(Node, 2, AArch64::LD2Twov2s, AArch64::dsub0);
5416 return;
5417 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5418 SelectLoad(Node, 2, AArch64::LD2Twov4s, AArch64::qsub0);
5419 return;
5420 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5421 SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0);
5422 return;
5423 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5424 SelectLoad(Node, 2, AArch64::LD2Twov2d, AArch64::qsub0);
5425 return;
5426 }
5427 break;
5428 case Intrinsic::aarch64_neon_ld3:
5429 if (VT == MVT::v8i8) {
5430 SelectLoad(Node, 3, AArch64::LD3Threev8b, AArch64::dsub0);
5431 return;
5432 } else if (VT == MVT::v16i8) {
5433 SelectLoad(Node, 3, AArch64::LD3Threev16b, AArch64::qsub0);
5434 return;
5435 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5436 SelectLoad(Node, 3, AArch64::LD3Threev4h, AArch64::dsub0);
5437 return;
5438 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5439 SelectLoad(Node, 3, AArch64::LD3Threev8h, AArch64::qsub0);
5440 return;
5441 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5442 SelectLoad(Node, 3, AArch64::LD3Threev2s, AArch64::dsub0);
5443 return;
5444 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5445 SelectLoad(Node, 3, AArch64::LD3Threev4s, AArch64::qsub0);
5446 return;
5447 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5448 SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0);
5449 return;
5450 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5451 SelectLoad(Node, 3, AArch64::LD3Threev2d, AArch64::qsub0);
5452 return;
5453 }
5454 break;
5455 case Intrinsic::aarch64_neon_ld4:
5456 if (VT == MVT::v8i8) {
5457 SelectLoad(Node, 4, AArch64::LD4Fourv8b, AArch64::dsub0);
5458 return;
5459 } else if (VT == MVT::v16i8) {
5460 SelectLoad(Node, 4, AArch64::LD4Fourv16b, AArch64::qsub0);
5461 return;
5462 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5463 SelectLoad(Node, 4, AArch64::LD4Fourv4h, AArch64::dsub0);
5464 return;
5465 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5466 SelectLoad(Node, 4, AArch64::LD4Fourv8h, AArch64::qsub0);
5467 return;
5468 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5469 SelectLoad(Node, 4, AArch64::LD4Fourv2s, AArch64::dsub0);
5470 return;
5471 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5472 SelectLoad(Node, 4, AArch64::LD4Fourv4s, AArch64::qsub0);
5473 return;
5474 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5475 SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0);
5476 return;
5477 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5478 SelectLoad(Node, 4, AArch64::LD4Fourv2d, AArch64::qsub0);
5479 return;
5480 }
5481 break;
5482 case Intrinsic::aarch64_neon_ld2r:
5483 if (VT == MVT::v8i8) {
5484 SelectLoad(Node, 2, AArch64::LD2Rv8b, AArch64::dsub0);
5485 return;
5486 } else if (VT == MVT::v16i8) {
5487 SelectLoad(Node, 2, AArch64::LD2Rv16b, AArch64::qsub0);
5488 return;
5489 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5490 SelectLoad(Node, 2, AArch64::LD2Rv4h, AArch64::dsub0);
5491 return;
5492 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5493 SelectLoad(Node, 2, AArch64::LD2Rv8h, AArch64::qsub0);
5494 return;
5495 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5496 SelectLoad(Node, 2, AArch64::LD2Rv2s, AArch64::dsub0);
5497 return;
5498 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5499 SelectLoad(Node, 2, AArch64::LD2Rv4s, AArch64::qsub0);
5500 return;
5501 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5502 SelectLoad(Node, 2, AArch64::LD2Rv1d, AArch64::dsub0);
5503 return;
5504 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5505 SelectLoad(Node, 2, AArch64::LD2Rv2d, AArch64::qsub0);
5506 return;
5507 }
5508 break;
5509 case Intrinsic::aarch64_neon_ld3r:
5510 if (VT == MVT::v8i8) {
5511 SelectLoad(Node, 3, AArch64::LD3Rv8b, AArch64::dsub0);
5512 return;
5513 } else if (VT == MVT::v16i8) {
5514 SelectLoad(Node, 3, AArch64::LD3Rv16b, AArch64::qsub0);
5515 return;
5516 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5517 SelectLoad(Node, 3, AArch64::LD3Rv4h, AArch64::dsub0);
5518 return;
5519 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5520 SelectLoad(Node, 3, AArch64::LD3Rv8h, AArch64::qsub0);
5521 return;
5522 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5523 SelectLoad(Node, 3, AArch64::LD3Rv2s, AArch64::dsub0);
5524 return;
5525 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5526 SelectLoad(Node, 3, AArch64::LD3Rv4s, AArch64::qsub0);
5527 return;
5528 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5529 SelectLoad(Node, 3, AArch64::LD3Rv1d, AArch64::dsub0);
5530 return;
5531 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5532 SelectLoad(Node, 3, AArch64::LD3Rv2d, AArch64::qsub0);
5533 return;
5534 }
5535 break;
5536 case Intrinsic::aarch64_neon_ld4r:
5537 if (VT == MVT::v8i8) {
5538 SelectLoad(Node, 4, AArch64::LD4Rv8b, AArch64::dsub0);
5539 return;
5540 } else if (VT == MVT::v16i8) {
5541 SelectLoad(Node, 4, AArch64::LD4Rv16b, AArch64::qsub0);
5542 return;
5543 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
5544 SelectLoad(Node, 4, AArch64::LD4Rv4h, AArch64::dsub0);
5545 return;
5546 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
5547 SelectLoad(Node, 4, AArch64::LD4Rv8h, AArch64::qsub0);
5548 return;
5549 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
5550 SelectLoad(Node, 4, AArch64::LD4Rv2s, AArch64::dsub0);
5551 return;
5552 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
5553 SelectLoad(Node, 4, AArch64::LD4Rv4s, AArch64::qsub0);
5554 return;
5555 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
5556 SelectLoad(Node, 4, AArch64::LD4Rv1d, AArch64::dsub0);
5557 return;
5558 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
5559 SelectLoad(Node, 4, AArch64::LD4Rv2d, AArch64::qsub0);
5560 return;
5561 }
5562 break;
5563 case Intrinsic::aarch64_neon_ld2lane:
5564 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
5565 SelectLoadLane(Node, 2, AArch64::LD2i8);
5566 return;
5567 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
5568 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
5569 SelectLoadLane(Node, 2, AArch64::LD2i16);
5570 return;
5571 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
5572 VT == MVT::v2f32) {
5573 SelectLoadLane(Node, 2, AArch64::LD2i32);
5574 return;
5575 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
5576 VT == MVT::v1f64) {
5577 SelectLoadLane(Node, 2, AArch64::LD2i64);
5578 return;
5579 }
5580 break;
5581 case Intrinsic::aarch64_neon_ld3lane:
5582 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
5583 SelectLoadLane(Node, 3, AArch64::LD3i8);
5584 return;
5585 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
5586 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
5587 SelectLoadLane(Node, 3, AArch64::LD3i16);
5588 return;
5589 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
5590 VT == MVT::v2f32) {
5591 SelectLoadLane(Node, 3, AArch64::LD3i32);
5592 return;
5593 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
5594 VT == MVT::v1f64) {
5595 SelectLoadLane(Node, 3, AArch64::LD3i64);
5596 return;
5597 }
5598 break;
5599 case Intrinsic::aarch64_neon_ld4lane:
5600 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
5601 SelectLoadLane(Node, 4, AArch64::LD4i8);
5602 return;
5603 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
5604 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
5605 SelectLoadLane(Node, 4, AArch64::LD4i16);
5606 return;
5607 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
5608 VT == MVT::v2f32) {
5609 SelectLoadLane(Node, 4, AArch64::LD4i32);
5610 return;
5611 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
5612 VT == MVT::v1f64) {
5613 SelectLoadLane(Node, 4, AArch64::LD4i64);
5614 return;
5615 }
5616 break;
5617 case Intrinsic::aarch64_ld64b:
5618 SelectLoad(Node, 8, AArch64::LD64B, AArch64::x8sub_0);
5619 return;
5620 case Intrinsic::aarch64_sve_ld2q_sret: {
5621 SelectPredicatedLoad(Node, 2, 4, AArch64::LD2Q_IMM, AArch64::LD2Q, true);
5622 return;
5623 }
5624 case Intrinsic::aarch64_sve_ld3q_sret: {
5625 SelectPredicatedLoad(Node, 3, 4, AArch64::LD3Q_IMM, AArch64::LD3Q, true);
5626 return;
5627 }
5628 case Intrinsic::aarch64_sve_ld4q_sret: {
5629 SelectPredicatedLoad(Node, 4, 4, AArch64::LD4Q_IMM, AArch64::LD4Q, true);
5630 return;
5631 }
5632 case Intrinsic::aarch64_sve_ld2_sret: {
5633 if (VT == MVT::nxv16i8) {
5634 SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B,
5635 true);
5636 return;
5637 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5638 VT == MVT::nxv8bf16) {
5639 SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H,
5640 true);
5641 return;
5642 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5643 SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W,
5644 true);
5645 return;
5646 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5647 SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D,
5648 true);
5649 return;
5650 }
5651 break;
5652 }
5653 case Intrinsic::aarch64_sve_ld1_pn_x2: {
5654 if (VT == MVT::nxv16i8) {
5655 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5656 SelectContiguousMultiVectorLoad(
5657 Node, 2, 0, AArch64::LD1B_2Z_IMM_PSEUDO, AArch64::LD1B_2Z_PSEUDO);
5658 else if (Subtarget->hasSVE2p1())
5659 SelectContiguousMultiVectorLoad(Node, 2, 0, AArch64::LD1B_2Z_IMM,
5660 AArch64::LD1B_2Z);
5661 else
5662 break;
5663 return;
5664 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5665 VT == MVT::nxv8bf16) {
5666 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5667 SelectContiguousMultiVectorLoad(
5668 Node, 2, 1, AArch64::LD1H_2Z_IMM_PSEUDO, AArch64::LD1H_2Z_PSEUDO);
5669 else if (Subtarget->hasSVE2p1())
5670 SelectContiguousMultiVectorLoad(Node, 2, 1, AArch64::LD1H_2Z_IMM,
5671 AArch64::LD1H_2Z);
5672 else
5673 break;
5674 return;
5675 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5676 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5677 SelectContiguousMultiVectorLoad(
5678 Node, 2, 2, AArch64::LD1W_2Z_IMM_PSEUDO, AArch64::LD1W_2Z_PSEUDO);
5679 else if (Subtarget->hasSVE2p1())
5680 SelectContiguousMultiVectorLoad(Node, 2, 2, AArch64::LD1W_2Z_IMM,
5681 AArch64::LD1W_2Z);
5682 else
5683 break;
5684 return;
5685 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5686 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5687 SelectContiguousMultiVectorLoad(
5688 Node, 2, 3, AArch64::LD1D_2Z_IMM_PSEUDO, AArch64::LD1D_2Z_PSEUDO);
5689 else if (Subtarget->hasSVE2p1())
5690 SelectContiguousMultiVectorLoad(Node, 2, 3, AArch64::LD1D_2Z_IMM,
5691 AArch64::LD1D_2Z);
5692 else
5693 break;
5694 return;
5695 }
5696 break;
5697 }
5698 case Intrinsic::aarch64_sve_ld1_pn_x4: {
5699 if (VT == MVT::nxv16i8) {
5700 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5701 SelectContiguousMultiVectorLoad(
5702 Node, 4, 0, AArch64::LD1B_4Z_IMM_PSEUDO, AArch64::LD1B_4Z_PSEUDO);
5703 else if (Subtarget->hasSVE2p1())
5704 SelectContiguousMultiVectorLoad(Node, 4, 0, AArch64::LD1B_4Z_IMM,
5705 AArch64::LD1B_4Z);
5706 else
5707 break;
5708 return;
5709 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5710 VT == MVT::nxv8bf16) {
5711 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5712 SelectContiguousMultiVectorLoad(
5713 Node, 4, 1, AArch64::LD1H_4Z_IMM_PSEUDO, AArch64::LD1H_4Z_PSEUDO);
5714 else if (Subtarget->hasSVE2p1())
5715 SelectContiguousMultiVectorLoad(Node, 4, 1, AArch64::LD1H_4Z_IMM,
5716 AArch64::LD1H_4Z);
5717 else
5718 break;
5719 return;
5720 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5721 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5722 SelectContiguousMultiVectorLoad(
5723 Node, 4, 2, AArch64::LD1W_4Z_IMM_PSEUDO, AArch64::LD1W_4Z_PSEUDO);
5724 else if (Subtarget->hasSVE2p1())
5725 SelectContiguousMultiVectorLoad(Node, 4, 2, AArch64::LD1W_4Z_IMM,
5726 AArch64::LD1W_4Z);
5727 else
5728 break;
5729 return;
5730 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5731 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5732 SelectContiguousMultiVectorLoad(
5733 Node, 4, 3, AArch64::LD1D_4Z_IMM_PSEUDO, AArch64::LD1D_4Z_PSEUDO);
5734 else if (Subtarget->hasSVE2p1())
5735 SelectContiguousMultiVectorLoad(Node, 4, 3, AArch64::LD1D_4Z_IMM,
5736 AArch64::LD1D_4Z);
5737 else
5738 break;
5739 return;
5740 }
5741 break;
5742 }
5743 case Intrinsic::aarch64_sve_ldnt1_pn_x2: {
5744 if (VT == MVT::nxv16i8) {
5745 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5746 SelectContiguousMultiVectorLoad(Node, 2, 0,
5747 AArch64::LDNT1B_2Z_IMM_PSEUDO,
5748 AArch64::LDNT1B_2Z_PSEUDO);
5749 else if (Subtarget->hasSVE2p1())
5750 SelectContiguousMultiVectorLoad(Node, 2, 0, AArch64::LDNT1B_2Z_IMM,
5751 AArch64::LDNT1B_2Z);
5752 else
5753 break;
5754 return;
5755 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5756 VT == MVT::nxv8bf16) {
5757 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5758 SelectContiguousMultiVectorLoad(Node, 2, 1,
5759 AArch64::LDNT1H_2Z_IMM_PSEUDO,
5760 AArch64::LDNT1H_2Z_PSEUDO);
5761 else if (Subtarget->hasSVE2p1())
5762 SelectContiguousMultiVectorLoad(Node, 2, 1, AArch64::LDNT1H_2Z_IMM,
5763 AArch64::LDNT1H_2Z);
5764 else
5765 break;
5766 return;
5767 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5768 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5769 SelectContiguousMultiVectorLoad(Node, 2, 2,
5770 AArch64::LDNT1W_2Z_IMM_PSEUDO,
5771 AArch64::LDNT1W_2Z_PSEUDO);
5772 else if (Subtarget->hasSVE2p1())
5773 SelectContiguousMultiVectorLoad(Node, 2, 2, AArch64::LDNT1W_2Z_IMM,
5774 AArch64::LDNT1W_2Z);
5775 else
5776 break;
5777 return;
5778 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5779 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5780 SelectContiguousMultiVectorLoad(Node, 2, 3,
5781 AArch64::LDNT1D_2Z_IMM_PSEUDO,
5782 AArch64::LDNT1D_2Z_PSEUDO);
5783 else if (Subtarget->hasSVE2p1())
5784 SelectContiguousMultiVectorLoad(Node, 2, 3, AArch64::LDNT1D_2Z_IMM,
5785 AArch64::LDNT1D_2Z);
5786 else
5787 break;
5788 return;
5789 }
5790 break;
5791 }
5792 case Intrinsic::aarch64_sve_ldnt1_pn_x4: {
5793 if (VT == MVT::nxv16i8) {
5794 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5795 SelectContiguousMultiVectorLoad(Node, 4, 0,
5796 AArch64::LDNT1B_4Z_IMM_PSEUDO,
5797 AArch64::LDNT1B_4Z_PSEUDO);
5798 else if (Subtarget->hasSVE2p1())
5799 SelectContiguousMultiVectorLoad(Node, 4, 0, AArch64::LDNT1B_4Z_IMM,
5800 AArch64::LDNT1B_4Z);
5801 else
5802 break;
5803 return;
5804 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5805 VT == MVT::nxv8bf16) {
5806 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5807 SelectContiguousMultiVectorLoad(Node, 4, 1,
5808 AArch64::LDNT1H_4Z_IMM_PSEUDO,
5809 AArch64::LDNT1H_4Z_PSEUDO);
5810 else if (Subtarget->hasSVE2p1())
5811 SelectContiguousMultiVectorLoad(Node, 4, 1, AArch64::LDNT1H_4Z_IMM,
5812 AArch64::LDNT1H_4Z);
5813 else
5814 break;
5815 return;
5816 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5817 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5818 SelectContiguousMultiVectorLoad(Node, 4, 2,
5819 AArch64::LDNT1W_4Z_IMM_PSEUDO,
5820 AArch64::LDNT1W_4Z_PSEUDO);
5821 else if (Subtarget->hasSVE2p1())
5822 SelectContiguousMultiVectorLoad(Node, 4, 2, AArch64::LDNT1W_4Z_IMM,
5823 AArch64::LDNT1W_4Z);
5824 else
5825 break;
5826 return;
5827 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5828 if (Subtarget->hasSME2() && Subtarget->isStreaming())
5829 SelectContiguousMultiVectorLoad(Node, 4, 3,
5830 AArch64::LDNT1D_4Z_IMM_PSEUDO,
5831 AArch64::LDNT1D_4Z_PSEUDO);
5832 else if (Subtarget->hasSVE2p1())
5833 SelectContiguousMultiVectorLoad(Node, 4, 3, AArch64::LDNT1D_4Z_IMM,
5834 AArch64::LDNT1D_4Z);
5835 else
5836 break;
5837 return;
5838 }
5839 break;
5840 }
5841 case Intrinsic::aarch64_sve_ld3_sret: {
5842 if (VT == MVT::nxv16i8) {
5843 SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B,
5844 true);
5845 return;
5846 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5847 VT == MVT::nxv8bf16) {
5848 SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H,
5849 true);
5850 return;
5851 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5852 SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W,
5853 true);
5854 return;
5855 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5856 SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D,
5857 true);
5858 return;
5859 }
5860 break;
5861 }
5862 case Intrinsic::aarch64_sve_ld4_sret: {
5863 if (VT == MVT::nxv16i8) {
5864 SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B,
5865 true);
5866 return;
5867 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5868 VT == MVT::nxv8bf16) {
5869 SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H,
5870 true);
5871 return;
5872 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5873 SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W,
5874 true);
5875 return;
5876 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5877 SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D,
5878 true);
5879 return;
5880 }
5881 break;
5882 }
5883 case Intrinsic::aarch64_sme_read_hor_vg2: {
5884 if (VT == MVT::nxv16i8) {
5885 SelectMultiVectorMove<14, 2>(Node, 2, AArch64::ZAB0,
5886 AArch64::MOVA_2ZMXI_H_B);
5887 return;
5888 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5889 VT == MVT::nxv8bf16) {
5890 SelectMultiVectorMove<6, 2>(Node, 2, AArch64::ZAH0,
5891 AArch64::MOVA_2ZMXI_H_H);
5892 return;
5893 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5894 SelectMultiVectorMove<2, 2>(Node, 2, AArch64::ZAS0,
5895 AArch64::MOVA_2ZMXI_H_S);
5896 return;
5897 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5898 SelectMultiVectorMove<0, 2>(Node, 2, AArch64::ZAD0,
5899 AArch64::MOVA_2ZMXI_H_D);
5900 return;
5901 }
5902 break;
5903 }
5904 case Intrinsic::aarch64_sme_read_ver_vg2: {
5905 if (VT == MVT::nxv16i8) {
5906 SelectMultiVectorMove<14, 2>(Node, 2, AArch64::ZAB0,
5907 AArch64::MOVA_2ZMXI_V_B);
5908 return;
5909 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5910 VT == MVT::nxv8bf16) {
5911 SelectMultiVectorMove<6, 2>(Node, 2, AArch64::ZAH0,
5912 AArch64::MOVA_2ZMXI_V_H);
5913 return;
5914 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5915 SelectMultiVectorMove<2, 2>(Node, 2, AArch64::ZAS0,
5916 AArch64::MOVA_2ZMXI_V_S);
5917 return;
5918 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5919 SelectMultiVectorMove<0, 2>(Node, 2, AArch64::ZAD0,
5920 AArch64::MOVA_2ZMXI_V_D);
5921 return;
5922 }
5923 break;
5924 }
5925 case Intrinsic::aarch64_sme_read_hor_vg4: {
5926 if (VT == MVT::nxv16i8) {
5927 SelectMultiVectorMove<12, 4>(Node, 4, AArch64::ZAB0,
5928 AArch64::MOVA_4ZMXI_H_B);
5929 return;
5930 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5931 VT == MVT::nxv8bf16) {
5932 SelectMultiVectorMove<4, 4>(Node, 4, AArch64::ZAH0,
5933 AArch64::MOVA_4ZMXI_H_H);
5934 return;
5935 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5936 SelectMultiVectorMove<0, 2>(Node, 4, AArch64::ZAS0,
5937 AArch64::MOVA_4ZMXI_H_S);
5938 return;
5939 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5940 SelectMultiVectorMove<0, 2>(Node, 4, AArch64::ZAD0,
5941 AArch64::MOVA_4ZMXI_H_D);
5942 return;
5943 }
5944 break;
5945 }
5946 case Intrinsic::aarch64_sme_read_ver_vg4: {
5947 if (VT == MVT::nxv16i8) {
5948 SelectMultiVectorMove<12, 4>(Node, 4, AArch64::ZAB0,
5949 AArch64::MOVA_4ZMXI_V_B);
5950 return;
5951 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5952 VT == MVT::nxv8bf16) {
5953 SelectMultiVectorMove<4, 4>(Node, 4, AArch64::ZAH0,
5954 AArch64::MOVA_4ZMXI_V_H);
5955 return;
5956 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5957 SelectMultiVectorMove<0, 4>(Node, 4, AArch64::ZAS0,
5958 AArch64::MOVA_4ZMXI_V_S);
5959 return;
5960 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5961 SelectMultiVectorMove<0, 4>(Node, 4, AArch64::ZAD0,
5962 AArch64::MOVA_4ZMXI_V_D);
5963 return;
5964 }
5965 break;
5966 }
5967 case Intrinsic::aarch64_sme_read_vg1x2: {
5968 SelectMultiVectorMove<7, 1>(Node, 2, AArch64::ZA,
5969 AArch64::MOVA_VG2_2ZMXI);
5970 return;
5971 }
5972 case Intrinsic::aarch64_sme_read_vg1x4: {
5973 SelectMultiVectorMove<7, 1>(Node, 4, AArch64::ZA,
5974 AArch64::MOVA_VG4_4ZMXI);
5975 return;
5976 }
5977 case Intrinsic::aarch64_sme_readz_horiz_x2: {
5978 if (VT == MVT::nxv16i8) {
5979 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_H_B_PSEUDO, 14, 2);
5980 return;
5981 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5982 VT == MVT::nxv8bf16) {
5983 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_H_H_PSEUDO, 6, 2);
5984 return;
5985 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
5986 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_H_S_PSEUDO, 2, 2);
5987 return;
5988 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
5989 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_H_D_PSEUDO, 0, 2);
5990 return;
5991 }
5992 break;
5993 }
5994 case Intrinsic::aarch64_sme_readz_vert_x2: {
5995 if (VT == MVT::nxv16i8) {
5996 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_V_B_PSEUDO, 14, 2);
5997 return;
5998 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
5999 VT == MVT::nxv8bf16) {
6000 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_V_H_PSEUDO, 6, 2);
6001 return;
6002 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
6003 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_V_S_PSEUDO, 2, 2);
6004 return;
6005 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
6006 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_2ZMI_V_D_PSEUDO, 0, 2);
6007 return;
6008 }
6009 break;
6010 }
6011 case Intrinsic::aarch64_sme_readz_horiz_x4: {
6012 if (VT == MVT::nxv16i8) {
6013 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_H_B_PSEUDO, 12, 4);
6014 return;
6015 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
6016 VT == MVT::nxv8bf16) {
6017 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_H_H_PSEUDO, 4, 4);
6018 return;
6019 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
6020 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_H_S_PSEUDO, 0, 4);
6021 return;
6022 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
6023 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_H_D_PSEUDO, 0, 4);
6024 return;
6025 }
6026 break;
6027 }
6028 case Intrinsic::aarch64_sme_readz_vert_x4: {
6029 if (VT == MVT::nxv16i8) {
6030 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_V_B_PSEUDO, 12, 4);
6031 return;
6032 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
6033 VT == MVT::nxv8bf16) {
6034 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_V_H_PSEUDO, 4, 4);
6035 return;
6036 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
6037 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_V_S_PSEUDO, 0, 4);
6038 return;
6039 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
6040 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_4ZMI_V_D_PSEUDO, 0, 4);
6041 return;
6042 }
6043 break;
6044 }
6045 case Intrinsic::aarch64_sme_readz_x2: {
6046 SelectMultiVectorMoveZ(Node, 2, AArch64::MOVAZ_VG2_2ZMXI_PSEUDO, 7, 1,
6047 AArch64::ZA);
6048 return;
6049 }
6050 case Intrinsic::aarch64_sme_readz_x4: {
6051 SelectMultiVectorMoveZ(Node, 4, AArch64::MOVAZ_VG4_4ZMXI_PSEUDO, 7, 1,
6052 AArch64::ZA);
6053 return;
6054 }
6055 case Intrinsic::swift_async_context_addr: {
6056 SDLoc DL(Node);
6057 SDValue Chain = Node->getOperand(0);
6058 SDValue CopyFP = CurDAG->getCopyFromReg(Chain, DL, AArch64::FP, MVT::i64);
6059 SDValue Res = SDValue(
6060 CurDAG->getMachineNode(AArch64::SUBXri, DL, MVT::i64, CopyFP,
6061 CurDAG->getTargetConstant(8, DL, MVT::i32),
6062 CurDAG->getTargetConstant(0, DL, MVT::i32)),
6063 0);
6064 ReplaceUses(SDValue(Node, 0), Res);
6065 ReplaceUses(SDValue(Node, 1), CopyFP.getValue(1));
6066 CurDAG->RemoveDeadNode(Node);
6067
6068 auto &MF = CurDAG->getMachineFunction();
6069 MF.getFrameInfo().setFrameAddressIsTaken(true);
6070 MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true);
6071 return;
6072 }
6073 case Intrinsic::aarch64_sme_luti2_lane_zt_x4: {
6075 Node->getValueType(0),
6076 {AArch64::LUTI2_4ZTZI_B, AArch64::LUTI2_4ZTZI_H,
6077 AArch64::LUTI2_4ZTZI_S}))
6078 // Second Immediate must be <= 3:
6079 SelectMultiVectorLutiLane(Node, 4, Opc, 3);
6080 return;
6081 }
6082 case Intrinsic::aarch64_sme_luti4_lane_zt_x4: {
6084 Node->getValueType(0),
6085 {0, AArch64::LUTI4_4ZTZI_H, AArch64::LUTI4_4ZTZI_S}))
6086 // Second Immediate must be <= 1:
6087 SelectMultiVectorLutiLane(Node, 4, Opc, 1);
6088 return;
6089 }
6090 case Intrinsic::aarch64_sme_luti2_lane_zt_x2: {
6092 Node->getValueType(0),
6093 {AArch64::LUTI2_2ZTZI_B, AArch64::LUTI2_2ZTZI_H,
6094 AArch64::LUTI2_2ZTZI_S}))
6095 // Second Immediate must be <= 7:
6096 SelectMultiVectorLutiLane(Node, 2, Opc, 7);
6097 return;
6098 }
6099 case Intrinsic::aarch64_sme_luti4_lane_zt_x2: {
6101 Node->getValueType(0),
6102 {AArch64::LUTI4_2ZTZI_B, AArch64::LUTI4_2ZTZI_H,
6103 AArch64::LUTI4_2ZTZI_S}))
6104 // Second Immediate must be <= 3:
6105 SelectMultiVectorLutiLane(Node, 2, Opc, 3);
6106 return;
6107 }
6108 case Intrinsic::aarch64_sme_luti4_zt_x4: {
6109 SelectMultiVectorLuti(Node, 4, AArch64::LUTI4_4ZZT2Z, 2);
6110 return;
6111 }
6112 case Intrinsic::aarch64_sme_luti6_zt_x4: {
6113 SelectMultiVectorLuti(Node, 4, AArch64::LUTI6_4ZT3Z, 3);
6114 return;
6115 }
6116 case Intrinsic::aarch64_sve_fp8_cvtl1_x2:
6118 Node->getValueType(0),
6119 {AArch64::BF1CVTL_2ZZ_BtoH, AArch64::F1CVTL_2ZZ_BtoH}))
6120 SelectCVTIntrinsicFP8(Node, 2, Opc);
6121 return;
6122 case Intrinsic::aarch64_sve_fp8_cvtl2_x2:
6124 Node->getValueType(0),
6125 {AArch64::BF2CVTL_2ZZ_BtoH, AArch64::F2CVTL_2ZZ_BtoH}))
6126 SelectCVTIntrinsicFP8(Node, 2, Opc);
6127 return;
6128 case Intrinsic::aarch64_sve_fp8_cvt1_x2:
6130 Node->getValueType(0),
6131 {AArch64::BF1CVT_2ZZ_BtoH, AArch64::F1CVT_2ZZ_BtoH}))
6132 SelectCVTIntrinsicFP8(Node, 2, Opc);
6133 return;
6134 case Intrinsic::aarch64_sve_fp8_cvt2_x2:
6136 Node->getValueType(0),
6137 {AArch64::BF2CVT_2ZZ_BtoH, AArch64::F2CVT_2ZZ_BtoH}))
6138 SelectCVTIntrinsicFP8(Node, 2, Opc);
6139 return;
6140 case Intrinsic::ptrauth_resign_load_relative:
6141 SelectPtrauthResign(Node);
6142 return;
6143 }
6144 } break;
6146 unsigned IntNo = Node->getConstantOperandVal(0);
6147 switch (IntNo) {
6148 default:
6149 break;
6150 case Intrinsic::aarch64_tagp:
6151 SelectTagP(Node);
6152 return;
6153
6154 case Intrinsic::ptrauth_auth:
6155 SelectPtrauthAuth(Node);
6156 return;
6157
6158 case Intrinsic::ptrauth_resign:
6159 SelectPtrauthResign(Node);
6160 return;
6161
6162 case Intrinsic::ptrauth_auth_with_pc_and_resign:
6163 SelectPtrauthResignWithPC(Node);
6164 return;
6165
6166 case Intrinsic::aarch64_neon_tbl2:
6167 SelectTable(Node, 2,
6168 VT == MVT::v8i8 ? AArch64::TBLv8i8Two : AArch64::TBLv16i8Two,
6169 false);
6170 return;
6171 case Intrinsic::aarch64_neon_tbl3:
6172 SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBLv8i8Three
6173 : AArch64::TBLv16i8Three,
6174 false);
6175 return;
6176 case Intrinsic::aarch64_neon_tbl4:
6177 SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBLv8i8Four
6178 : AArch64::TBLv16i8Four,
6179 false);
6180 return;
6181 case Intrinsic::aarch64_neon_tbx2:
6182 SelectTable(Node, 2,
6183 VT == MVT::v8i8 ? AArch64::TBXv8i8Two : AArch64::TBXv16i8Two,
6184 true);
6185 return;
6186 case Intrinsic::aarch64_neon_tbx3:
6187 SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBXv8i8Three
6188 : AArch64::TBXv16i8Three,
6189 true);
6190 return;
6191 case Intrinsic::aarch64_neon_tbx4:
6192 SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBXv8i8Four
6193 : AArch64::TBXv16i8Four,
6194 true);
6195 return;
6196 case Intrinsic::aarch64_sve_srshl_single_x2:
6198 Node->getValueType(0),
6199 {AArch64::SRSHL_VG2_2ZZ_B, AArch64::SRSHL_VG2_2ZZ_H,
6200 AArch64::SRSHL_VG2_2ZZ_S, AArch64::SRSHL_VG2_2ZZ_D}))
6201 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6202 return;
6203 case Intrinsic::aarch64_sve_srshl_single_x4:
6205 Node->getValueType(0),
6206 {AArch64::SRSHL_VG4_4ZZ_B, AArch64::SRSHL_VG4_4ZZ_H,
6207 AArch64::SRSHL_VG4_4ZZ_S, AArch64::SRSHL_VG4_4ZZ_D}))
6208 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6209 return;
6210 case Intrinsic::aarch64_sme_luti6_lane_x4_x2:
6211 SelectMultiVectorLuti6LaneX4(Node, 2);
6212 return;
6213 case Intrinsic::aarch64_sme_luti6_lane_x4_x3:
6214 SelectMultiVectorLuti6LaneX4(Node, 3);
6215 return;
6216 case Intrinsic::aarch64_sve_urshl_single_x2:
6218 Node->getValueType(0),
6219 {AArch64::URSHL_VG2_2ZZ_B, AArch64::URSHL_VG2_2ZZ_H,
6220 AArch64::URSHL_VG2_2ZZ_S, AArch64::URSHL_VG2_2ZZ_D}))
6221 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6222 return;
6223 case Intrinsic::aarch64_sve_urshl_single_x4:
6225 Node->getValueType(0),
6226 {AArch64::URSHL_VG4_4ZZ_B, AArch64::URSHL_VG4_4ZZ_H,
6227 AArch64::URSHL_VG4_4ZZ_S, AArch64::URSHL_VG4_4ZZ_D}))
6228 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6229 return;
6230 case Intrinsic::aarch64_sve_srshl_x2:
6232 Node->getValueType(0),
6233 {AArch64::SRSHL_VG2_2Z2Z_B, AArch64::SRSHL_VG2_2Z2Z_H,
6234 AArch64::SRSHL_VG2_2Z2Z_S, AArch64::SRSHL_VG2_2Z2Z_D}))
6235 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6236 return;
6237 case Intrinsic::aarch64_sve_srshl_x4:
6239 Node->getValueType(0),
6240 {AArch64::SRSHL_VG4_4Z4Z_B, AArch64::SRSHL_VG4_4Z4Z_H,
6241 AArch64::SRSHL_VG4_4Z4Z_S, AArch64::SRSHL_VG4_4Z4Z_D}))
6242 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6243 return;
6244 case Intrinsic::aarch64_sve_urshl_x2:
6246 Node->getValueType(0),
6247 {AArch64::URSHL_VG2_2Z2Z_B, AArch64::URSHL_VG2_2Z2Z_H,
6248 AArch64::URSHL_VG2_2Z2Z_S, AArch64::URSHL_VG2_2Z2Z_D}))
6249 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6250 return;
6251 case Intrinsic::aarch64_sve_urshl_x4:
6253 Node->getValueType(0),
6254 {AArch64::URSHL_VG4_4Z4Z_B, AArch64::URSHL_VG4_4Z4Z_H,
6255 AArch64::URSHL_VG4_4Z4Z_S, AArch64::URSHL_VG4_4Z4Z_D}))
6256 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6257 return;
6258 case Intrinsic::aarch64_sve_sqdmulh_single_vgx2:
6260 Node->getValueType(0),
6261 {AArch64::SQDMULH_VG2_2ZZ_B, AArch64::SQDMULH_VG2_2ZZ_H,
6262 AArch64::SQDMULH_VG2_2ZZ_S, AArch64::SQDMULH_VG2_2ZZ_D}))
6263 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6264 return;
6265 case Intrinsic::aarch64_sve_sqdmulh_single_vgx4:
6267 Node->getValueType(0),
6268 {AArch64::SQDMULH_VG4_4ZZ_B, AArch64::SQDMULH_VG4_4ZZ_H,
6269 AArch64::SQDMULH_VG4_4ZZ_S, AArch64::SQDMULH_VG4_4ZZ_D}))
6270 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6271 return;
6272 case Intrinsic::aarch64_sve_sqdmulh_vgx2:
6274 Node->getValueType(0),
6275 {AArch64::SQDMULH_VG2_2Z2Z_B, AArch64::SQDMULH_VG2_2Z2Z_H,
6276 AArch64::SQDMULH_VG2_2Z2Z_S, AArch64::SQDMULH_VG2_2Z2Z_D}))
6277 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6278 return;
6279 case Intrinsic::aarch64_sve_sqdmulh_vgx4:
6281 Node->getValueType(0),
6282 {AArch64::SQDMULH_VG4_4Z4Z_B, AArch64::SQDMULH_VG4_4Z4Z_H,
6283 AArch64::SQDMULH_VG4_4Z4Z_S, AArch64::SQDMULH_VG4_4Z4Z_D}))
6284 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6285 return;
6286 case Intrinsic::aarch64_sme_fp8_scale_single_x2:
6288 Node->getValueType(0),
6289 {0, AArch64::FSCALE_2ZZ_H, AArch64::FSCALE_2ZZ_S,
6290 AArch64::FSCALE_2ZZ_D}))
6291 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6292 return;
6293 case Intrinsic::aarch64_sme_fp8_scale_single_x4:
6295 Node->getValueType(0),
6296 {0, AArch64::FSCALE_4ZZ_H, AArch64::FSCALE_4ZZ_S,
6297 AArch64::FSCALE_4ZZ_D}))
6298 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6299 return;
6300 case Intrinsic::aarch64_sme_fp8_scale_x2:
6302 Node->getValueType(0),
6303 {0, AArch64::FSCALE_2Z2Z_H, AArch64::FSCALE_2Z2Z_S,
6304 AArch64::FSCALE_2Z2Z_D}))
6305 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6306 return;
6307 case Intrinsic::aarch64_sme_fp8_scale_x4:
6309 Node->getValueType(0),
6310 {0, AArch64::FSCALE_4Z4Z_H, AArch64::FSCALE_4Z4Z_S,
6311 AArch64::FSCALE_4Z4Z_D}))
6312 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6313 return;
6314 case Intrinsic::aarch64_sve_whilege_x2:
6316 Node->getValueType(0),
6317 {AArch64::WHILEGE_2PXX_B, AArch64::WHILEGE_2PXX_H,
6318 AArch64::WHILEGE_2PXX_S, AArch64::WHILEGE_2PXX_D}))
6319 SelectWhilePair(Node, Op);
6320 return;
6321 case Intrinsic::aarch64_sve_whilegt_x2:
6323 Node->getValueType(0),
6324 {AArch64::WHILEGT_2PXX_B, AArch64::WHILEGT_2PXX_H,
6325 AArch64::WHILEGT_2PXX_S, AArch64::WHILEGT_2PXX_D}))
6326 SelectWhilePair(Node, Op);
6327 return;
6328 case Intrinsic::aarch64_sve_whilehi_x2:
6330 Node->getValueType(0),
6331 {AArch64::WHILEHI_2PXX_B, AArch64::WHILEHI_2PXX_H,
6332 AArch64::WHILEHI_2PXX_S, AArch64::WHILEHI_2PXX_D}))
6333 SelectWhilePair(Node, Op);
6334 return;
6335 case Intrinsic::aarch64_sve_whilehs_x2:
6337 Node->getValueType(0),
6338 {AArch64::WHILEHS_2PXX_B, AArch64::WHILEHS_2PXX_H,
6339 AArch64::WHILEHS_2PXX_S, AArch64::WHILEHS_2PXX_D}))
6340 SelectWhilePair(Node, Op);
6341 return;
6342 case Intrinsic::aarch64_sve_whilele_x2:
6344 Node->getValueType(0),
6345 {AArch64::WHILELE_2PXX_B, AArch64::WHILELE_2PXX_H,
6346 AArch64::WHILELE_2PXX_S, AArch64::WHILELE_2PXX_D}))
6347 SelectWhilePair(Node, Op);
6348 return;
6349 case Intrinsic::aarch64_sve_whilelo_x2:
6351 Node->getValueType(0),
6352 {AArch64::WHILELO_2PXX_B, AArch64::WHILELO_2PXX_H,
6353 AArch64::WHILELO_2PXX_S, AArch64::WHILELO_2PXX_D}))
6354 SelectWhilePair(Node, Op);
6355 return;
6356 case Intrinsic::aarch64_sve_whilels_x2:
6358 Node->getValueType(0),
6359 {AArch64::WHILELS_2PXX_B, AArch64::WHILELS_2PXX_H,
6360 AArch64::WHILELS_2PXX_S, AArch64::WHILELS_2PXX_D}))
6361 SelectWhilePair(Node, Op);
6362 return;
6363 case Intrinsic::aarch64_sve_whilelt_x2:
6365 Node->getValueType(0),
6366 {AArch64::WHILELT_2PXX_B, AArch64::WHILELT_2PXX_H,
6367 AArch64::WHILELT_2PXX_S, AArch64::WHILELT_2PXX_D}))
6368 SelectWhilePair(Node, Op);
6369 return;
6370 case Intrinsic::aarch64_sve_smax_single_x2:
6372 Node->getValueType(0),
6373 {AArch64::SMAX_VG2_2ZZ_B, AArch64::SMAX_VG2_2ZZ_H,
6374 AArch64::SMAX_VG2_2ZZ_S, AArch64::SMAX_VG2_2ZZ_D}))
6375 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6376 return;
6377 case Intrinsic::aarch64_sve_umax_single_x2:
6379 Node->getValueType(0),
6380 {AArch64::UMAX_VG2_2ZZ_B, AArch64::UMAX_VG2_2ZZ_H,
6381 AArch64::UMAX_VG2_2ZZ_S, AArch64::UMAX_VG2_2ZZ_D}))
6382 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6383 return;
6384 case Intrinsic::aarch64_sve_fmax_single_x2:
6386 Node->getValueType(0),
6387 {AArch64::BFMAX_VG2_2ZZ_H, AArch64::FMAX_VG2_2ZZ_H,
6388 AArch64::FMAX_VG2_2ZZ_S, AArch64::FMAX_VG2_2ZZ_D}))
6389 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6390 return;
6391 case Intrinsic::aarch64_sve_smax_single_x4:
6393 Node->getValueType(0),
6394 {AArch64::SMAX_VG4_4ZZ_B, AArch64::SMAX_VG4_4ZZ_H,
6395 AArch64::SMAX_VG4_4ZZ_S, AArch64::SMAX_VG4_4ZZ_D}))
6396 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6397 return;
6398 case Intrinsic::aarch64_sve_umax_single_x4:
6400 Node->getValueType(0),
6401 {AArch64::UMAX_VG4_4ZZ_B, AArch64::UMAX_VG4_4ZZ_H,
6402 AArch64::UMAX_VG4_4ZZ_S, AArch64::UMAX_VG4_4ZZ_D}))
6403 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6404 return;
6405 case Intrinsic::aarch64_sve_fmax_single_x4:
6407 Node->getValueType(0),
6408 {AArch64::BFMAX_VG4_4ZZ_H, AArch64::FMAX_VG4_4ZZ_H,
6409 AArch64::FMAX_VG4_4ZZ_S, AArch64::FMAX_VG4_4ZZ_D}))
6410 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6411 return;
6412 case Intrinsic::aarch64_sve_smin_single_x2:
6414 Node->getValueType(0),
6415 {AArch64::SMIN_VG2_2ZZ_B, AArch64::SMIN_VG2_2ZZ_H,
6416 AArch64::SMIN_VG2_2ZZ_S, AArch64::SMIN_VG2_2ZZ_D}))
6417 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6418 return;
6419 case Intrinsic::aarch64_sve_umin_single_x2:
6421 Node->getValueType(0),
6422 {AArch64::UMIN_VG2_2ZZ_B, AArch64::UMIN_VG2_2ZZ_H,
6423 AArch64::UMIN_VG2_2ZZ_S, AArch64::UMIN_VG2_2ZZ_D}))
6424 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6425 return;
6426 case Intrinsic::aarch64_sve_fmin_single_x2:
6428 Node->getValueType(0),
6429 {AArch64::BFMIN_VG2_2ZZ_H, AArch64::FMIN_VG2_2ZZ_H,
6430 AArch64::FMIN_VG2_2ZZ_S, AArch64::FMIN_VG2_2ZZ_D}))
6431 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6432 return;
6433 case Intrinsic::aarch64_sve_smin_single_x4:
6435 Node->getValueType(0),
6436 {AArch64::SMIN_VG4_4ZZ_B, AArch64::SMIN_VG4_4ZZ_H,
6437 AArch64::SMIN_VG4_4ZZ_S, AArch64::SMIN_VG4_4ZZ_D}))
6438 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6439 return;
6440 case Intrinsic::aarch64_sve_umin_single_x4:
6442 Node->getValueType(0),
6443 {AArch64::UMIN_VG4_4ZZ_B, AArch64::UMIN_VG4_4ZZ_H,
6444 AArch64::UMIN_VG4_4ZZ_S, AArch64::UMIN_VG4_4ZZ_D}))
6445 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6446 return;
6447 case Intrinsic::aarch64_sve_fmin_single_x4:
6449 Node->getValueType(0),
6450 {AArch64::BFMIN_VG4_4ZZ_H, AArch64::FMIN_VG4_4ZZ_H,
6451 AArch64::FMIN_VG4_4ZZ_S, AArch64::FMIN_VG4_4ZZ_D}))
6452 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6453 return;
6454 case Intrinsic::aarch64_sve_smax_x2:
6456 Node->getValueType(0),
6457 {AArch64::SMAX_VG2_2Z2Z_B, AArch64::SMAX_VG2_2Z2Z_H,
6458 AArch64::SMAX_VG2_2Z2Z_S, AArch64::SMAX_VG2_2Z2Z_D}))
6459 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6460 return;
6461 case Intrinsic::aarch64_sve_umax_x2:
6463 Node->getValueType(0),
6464 {AArch64::UMAX_VG2_2Z2Z_B, AArch64::UMAX_VG2_2Z2Z_H,
6465 AArch64::UMAX_VG2_2Z2Z_S, AArch64::UMAX_VG2_2Z2Z_D}))
6466 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6467 return;
6468 case Intrinsic::aarch64_sve_fmax_x2:
6470 Node->getValueType(0),
6471 {AArch64::BFMAX_VG2_2Z2Z_H, AArch64::FMAX_VG2_2Z2Z_H,
6472 AArch64::FMAX_VG2_2Z2Z_S, AArch64::FMAX_VG2_2Z2Z_D}))
6473 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6474 return;
6475 case Intrinsic::aarch64_sve_smax_x4:
6477 Node->getValueType(0),
6478 {AArch64::SMAX_VG4_4Z4Z_B, AArch64::SMAX_VG4_4Z4Z_H,
6479 AArch64::SMAX_VG4_4Z4Z_S, AArch64::SMAX_VG4_4Z4Z_D}))
6480 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6481 return;
6482 case Intrinsic::aarch64_sve_umax_x4:
6484 Node->getValueType(0),
6485 {AArch64::UMAX_VG4_4Z4Z_B, AArch64::UMAX_VG4_4Z4Z_H,
6486 AArch64::UMAX_VG4_4Z4Z_S, AArch64::UMAX_VG4_4Z4Z_D}))
6487 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6488 return;
6489 case Intrinsic::aarch64_sve_fmax_x4:
6491 Node->getValueType(0),
6492 {AArch64::BFMAX_VG4_4Z2Z_H, AArch64::FMAX_VG4_4Z4Z_H,
6493 AArch64::FMAX_VG4_4Z4Z_S, AArch64::FMAX_VG4_4Z4Z_D}))
6494 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6495 return;
6496 case Intrinsic::aarch64_sme_famax_x2:
6498 Node->getValueType(0),
6499 {0, AArch64::FAMAX_2Z2Z_H, AArch64::FAMAX_2Z2Z_S,
6500 AArch64::FAMAX_2Z2Z_D}))
6501 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6502 return;
6503 case Intrinsic::aarch64_sme_famax_x4:
6505 Node->getValueType(0),
6506 {0, AArch64::FAMAX_4Z4Z_H, AArch64::FAMAX_4Z4Z_S,
6507 AArch64::FAMAX_4Z4Z_D}))
6508 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6509 return;
6510 case Intrinsic::aarch64_sme_famin_x2:
6512 Node->getValueType(0),
6513 {0, AArch64::FAMIN_2Z2Z_H, AArch64::FAMIN_2Z2Z_S,
6514 AArch64::FAMIN_2Z2Z_D}))
6515 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6516 return;
6517 case Intrinsic::aarch64_sme_famin_x4:
6519 Node->getValueType(0),
6520 {0, AArch64::FAMIN_4Z4Z_H, AArch64::FAMIN_4Z4Z_S,
6521 AArch64::FAMIN_4Z4Z_D}))
6522 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6523 return;
6524 case Intrinsic::aarch64_sve_smin_x2:
6526 Node->getValueType(0),
6527 {AArch64::SMIN_VG2_2Z2Z_B, AArch64::SMIN_VG2_2Z2Z_H,
6528 AArch64::SMIN_VG2_2Z2Z_S, AArch64::SMIN_VG2_2Z2Z_D}))
6529 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6530 return;
6531 case Intrinsic::aarch64_sve_umin_x2:
6533 Node->getValueType(0),
6534 {AArch64::UMIN_VG2_2Z2Z_B, AArch64::UMIN_VG2_2Z2Z_H,
6535 AArch64::UMIN_VG2_2Z2Z_S, AArch64::UMIN_VG2_2Z2Z_D}))
6536 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6537 return;
6538 case Intrinsic::aarch64_sve_fmin_x2:
6540 Node->getValueType(0),
6541 {AArch64::BFMIN_VG2_2Z2Z_H, AArch64::FMIN_VG2_2Z2Z_H,
6542 AArch64::FMIN_VG2_2Z2Z_S, AArch64::FMIN_VG2_2Z2Z_D}))
6543 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6544 return;
6545 case Intrinsic::aarch64_sve_smin_x4:
6547 Node->getValueType(0),
6548 {AArch64::SMIN_VG4_4Z4Z_B, AArch64::SMIN_VG4_4Z4Z_H,
6549 AArch64::SMIN_VG4_4Z4Z_S, AArch64::SMIN_VG4_4Z4Z_D}))
6550 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6551 return;
6552 case Intrinsic::aarch64_sve_umin_x4:
6554 Node->getValueType(0),
6555 {AArch64::UMIN_VG4_4Z4Z_B, AArch64::UMIN_VG4_4Z4Z_H,
6556 AArch64::UMIN_VG4_4Z4Z_S, AArch64::UMIN_VG4_4Z4Z_D}))
6557 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6558 return;
6559 case Intrinsic::aarch64_sve_fmin_x4:
6561 Node->getValueType(0),
6562 {AArch64::BFMIN_VG4_4Z2Z_H, AArch64::FMIN_VG4_4Z4Z_H,
6563 AArch64::FMIN_VG4_4Z4Z_S, AArch64::FMIN_VG4_4Z4Z_D}))
6564 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6565 return;
6566 case Intrinsic::aarch64_sve_fmaxnm_single_x2 :
6568 Node->getValueType(0),
6569 {AArch64::BFMAXNM_VG2_2ZZ_H, AArch64::FMAXNM_VG2_2ZZ_H,
6570 AArch64::FMAXNM_VG2_2ZZ_S, AArch64::FMAXNM_VG2_2ZZ_D}))
6571 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6572 return;
6573 case Intrinsic::aarch64_sve_fmaxnm_single_x4 :
6575 Node->getValueType(0),
6576 {AArch64::BFMAXNM_VG4_4ZZ_H, AArch64::FMAXNM_VG4_4ZZ_H,
6577 AArch64::FMAXNM_VG4_4ZZ_S, AArch64::FMAXNM_VG4_4ZZ_D}))
6578 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6579 return;
6580 case Intrinsic::aarch64_sve_fminnm_single_x2:
6582 Node->getValueType(0),
6583 {AArch64::BFMINNM_VG2_2ZZ_H, AArch64::FMINNM_VG2_2ZZ_H,
6584 AArch64::FMINNM_VG2_2ZZ_S, AArch64::FMINNM_VG2_2ZZ_D}))
6585 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6586 return;
6587 case Intrinsic::aarch64_sve_fminnm_single_x4:
6589 Node->getValueType(0),
6590 {AArch64::BFMINNM_VG4_4ZZ_H, AArch64::FMINNM_VG4_4ZZ_H,
6591 AArch64::FMINNM_VG4_4ZZ_S, AArch64::FMINNM_VG4_4ZZ_D}))
6592 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6593 return;
6594 case Intrinsic::aarch64_sve_fscale_single_x4:
6595 SelectDestructiveMultiIntrinsic(Node, 4, false, AArch64::BFSCALE_4ZZ);
6596 return;
6597 case Intrinsic::aarch64_sve_fscale_single_x2:
6598 SelectDestructiveMultiIntrinsic(Node, 2, false, AArch64::BFSCALE_2ZZ);
6599 return;
6600 case Intrinsic::aarch64_sve_fmul_single_x4:
6602 Node->getValueType(0),
6603 {AArch64::BFMUL_4ZZ, AArch64::FMUL_4ZZ_H, AArch64::FMUL_4ZZ_S,
6604 AArch64::FMUL_4ZZ_D}))
6605 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6606 return;
6607 case Intrinsic::aarch64_sve_fmul_single_x2:
6609 Node->getValueType(0),
6610 {AArch64::BFMUL_2ZZ, AArch64::FMUL_2ZZ_H, AArch64::FMUL_2ZZ_S,
6611 AArch64::FMUL_2ZZ_D}))
6612 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6613 return;
6614 case Intrinsic::aarch64_sve_fmaxnm_x2:
6616 Node->getValueType(0),
6617 {AArch64::BFMAXNM_VG2_2Z2Z_H, AArch64::FMAXNM_VG2_2Z2Z_H,
6618 AArch64::FMAXNM_VG2_2Z2Z_S, AArch64::FMAXNM_VG2_2Z2Z_D}))
6619 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6620 return;
6621 case Intrinsic::aarch64_sve_fmaxnm_x4:
6623 Node->getValueType(0),
6624 {AArch64::BFMAXNM_VG4_4Z2Z_H, AArch64::FMAXNM_VG4_4Z4Z_H,
6625 AArch64::FMAXNM_VG4_4Z4Z_S, AArch64::FMAXNM_VG4_4Z4Z_D}))
6626 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6627 return;
6628 case Intrinsic::aarch64_sve_fminnm_x2:
6630 Node->getValueType(0),
6631 {AArch64::BFMINNM_VG2_2Z2Z_H, AArch64::FMINNM_VG2_2Z2Z_H,
6632 AArch64::FMINNM_VG2_2Z2Z_S, AArch64::FMINNM_VG2_2Z2Z_D}))
6633 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6634 return;
6635 case Intrinsic::aarch64_sve_fminnm_x4:
6637 Node->getValueType(0),
6638 {AArch64::BFMINNM_VG4_4Z2Z_H, AArch64::FMINNM_VG4_4Z4Z_H,
6639 AArch64::FMINNM_VG4_4Z4Z_S, AArch64::FMINNM_VG4_4Z4Z_D}))
6640 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6641 return;
6642 case Intrinsic::aarch64_sve_aese_lane_x2:
6643 SelectDestructiveMultiIntrinsic(Node, 2, false, AArch64::AESE_2ZZI_B);
6644 return;
6645 case Intrinsic::aarch64_sve_aesd_lane_x2:
6646 SelectDestructiveMultiIntrinsic(Node, 2, false, AArch64::AESD_2ZZI_B);
6647 return;
6648 case Intrinsic::aarch64_sve_aesemc_lane_x2:
6649 SelectDestructiveMultiIntrinsic(Node, 2, false, AArch64::AESEMC_2ZZI_B);
6650 return;
6651 case Intrinsic::aarch64_sve_aesdimc_lane_x2:
6652 SelectDestructiveMultiIntrinsic(Node, 2, false, AArch64::AESDIMC_2ZZI_B);
6653 return;
6654 case Intrinsic::aarch64_sve_aese_lane_x4:
6655 SelectDestructiveMultiIntrinsic(Node, 4, false, AArch64::AESE_4ZZI_B);
6656 return;
6657 case Intrinsic::aarch64_sve_aesd_lane_x4:
6658 SelectDestructiveMultiIntrinsic(Node, 4, false, AArch64::AESD_4ZZI_B);
6659 return;
6660 case Intrinsic::aarch64_sve_aesemc_lane_x4:
6661 SelectDestructiveMultiIntrinsic(Node, 4, false, AArch64::AESEMC_4ZZI_B);
6662 return;
6663 case Intrinsic::aarch64_sve_aesdimc_lane_x4:
6664 SelectDestructiveMultiIntrinsic(Node, 4, false, AArch64::AESDIMC_4ZZI_B);
6665 return;
6666 case Intrinsic::aarch64_sve_pmlal_pair_x2:
6667 SelectDestructiveMultiIntrinsic(Node, 2, false, AArch64::PMLAL_2ZZZ_Q);
6668 return;
6669 case Intrinsic::aarch64_sve_pmull_pair_x2: {
6670 SDLoc DL(Node);
6671 SmallVector<SDValue, 4> Regs(Node->ops().slice(1, 2));
6672 SDNode *Res =
6673 CurDAG->getMachineNode(AArch64::PMULL_2ZZZ_Q, DL, MVT::Untyped, Regs);
6674 SDValue SuperReg = SDValue(Res, 0);
6675 for (unsigned I = 0; I < 2; I++)
6676 ReplaceUses(SDValue(Node, I),
6677 CurDAG->getTargetExtractSubreg(AArch64::zsub0 + I, DL, VT,
6678 SuperReg));
6679 CurDAG->RemoveDeadNode(Node);
6680 return;
6681 }
6682 case Intrinsic::aarch64_sve_fscale_x4:
6683 SelectDestructiveMultiIntrinsic(Node, 4, true, AArch64::BFSCALE_4Z4Z);
6684 return;
6685 case Intrinsic::aarch64_sve_fscale_x2:
6686 SelectDestructiveMultiIntrinsic(Node, 2, true, AArch64::BFSCALE_2Z2Z);
6687 return;
6688 case Intrinsic::aarch64_sve_fmul_x4:
6690 Node->getValueType(0),
6691 {AArch64::BFMUL_4Z4Z, AArch64::FMUL_4Z4Z_H, AArch64::FMUL_4Z4Z_S,
6692 AArch64::FMUL_4Z4Z_D}))
6693 SelectDestructiveMultiIntrinsic(Node, 4, true, Op);
6694 return;
6695 case Intrinsic::aarch64_sve_fmul_x2:
6697 Node->getValueType(0),
6698 {AArch64::BFMUL_2Z2Z, AArch64::FMUL_2Z2Z_H, AArch64::FMUL_2Z2Z_S,
6699 AArch64::FMUL_2Z2Z_D}))
6700 SelectDestructiveMultiIntrinsic(Node, 2, true, Op);
6701 return;
6702 case Intrinsic::aarch64_sve_fcvtzs_x2:
6703 SelectCVTIntrinsic(Node, 2, AArch64::FCVTZS_2Z2Z_StoS);
6704 return;
6705 case Intrinsic::aarch64_sve_scvtf_x2:
6706 SelectCVTIntrinsic(Node, 2, AArch64::SCVTF_2Z2Z_StoS);
6707 return;
6708 case Intrinsic::aarch64_sve_fcvtzu_x2:
6709 SelectCVTIntrinsic(Node, 2, AArch64::FCVTZU_2Z2Z_StoS);
6710 return;
6711 case Intrinsic::aarch64_sve_ucvtf_x2:
6712 SelectCVTIntrinsic(Node, 2, AArch64::UCVTF_2Z2Z_StoS);
6713 return;
6714 case Intrinsic::aarch64_sve_fcvtzs_x4:
6715 SelectCVTIntrinsic(Node, 4, AArch64::FCVTZS_4Z4Z_StoS);
6716 return;
6717 case Intrinsic::aarch64_sve_scvtf_x4:
6718 SelectCVTIntrinsic(Node, 4, AArch64::SCVTF_4Z4Z_StoS);
6719 return;
6720 case Intrinsic::aarch64_sve_fcvtzu_x4:
6721 SelectCVTIntrinsic(Node, 4, AArch64::FCVTZU_4Z4Z_StoS);
6722 return;
6723 case Intrinsic::aarch64_sve_ucvtf_x4:
6724 SelectCVTIntrinsic(Node, 4, AArch64::UCVTF_4Z4Z_StoS);
6725 return;
6726 case Intrinsic::aarch64_sve_fcvt_widen_x2:
6727 SelectUnaryMultiIntrinsic(Node, 2, false, AArch64::FCVT_2ZZ_H_S);
6728 return;
6729 case Intrinsic::aarch64_sve_fcvtl_widen_x2:
6730 SelectUnaryMultiIntrinsic(Node, 2, false, AArch64::FCVTL_2ZZ_H_S);
6731 return;
6732 case Intrinsic::aarch64_sve_sclamp_single_x2:
6734 Node->getValueType(0),
6735 {AArch64::SCLAMP_VG2_2Z2Z_B, AArch64::SCLAMP_VG2_2Z2Z_H,
6736 AArch64::SCLAMP_VG2_2Z2Z_S, AArch64::SCLAMP_VG2_2Z2Z_D}))
6737 SelectClamp(Node, 2, Op);
6738 return;
6739 case Intrinsic::aarch64_sve_uclamp_single_x2:
6741 Node->getValueType(0),
6742 {AArch64::UCLAMP_VG2_2Z2Z_B, AArch64::UCLAMP_VG2_2Z2Z_H,
6743 AArch64::UCLAMP_VG2_2Z2Z_S, AArch64::UCLAMP_VG2_2Z2Z_D}))
6744 SelectClamp(Node, 2, Op);
6745 return;
6746 case Intrinsic::aarch64_sve_fclamp_single_x2:
6748 Node->getValueType(0),
6749 {0, AArch64::FCLAMP_VG2_2Z2Z_H, AArch64::FCLAMP_VG2_2Z2Z_S,
6750 AArch64::FCLAMP_VG2_2Z2Z_D}))
6751 SelectClamp(Node, 2, Op);
6752 return;
6753 case Intrinsic::aarch64_sve_bfclamp_single_x2:
6754 SelectClamp(Node, 2, AArch64::BFCLAMP_VG2_2ZZZ_H);
6755 return;
6756 case Intrinsic::aarch64_sve_sclamp_single_x4:
6758 Node->getValueType(0),
6759 {AArch64::SCLAMP_VG4_4Z4Z_B, AArch64::SCLAMP_VG4_4Z4Z_H,
6760 AArch64::SCLAMP_VG4_4Z4Z_S, AArch64::SCLAMP_VG4_4Z4Z_D}))
6761 SelectClamp(Node, 4, Op);
6762 return;
6763 case Intrinsic::aarch64_sve_uclamp_single_x4:
6765 Node->getValueType(0),
6766 {AArch64::UCLAMP_VG4_4Z4Z_B, AArch64::UCLAMP_VG4_4Z4Z_H,
6767 AArch64::UCLAMP_VG4_4Z4Z_S, AArch64::UCLAMP_VG4_4Z4Z_D}))
6768 SelectClamp(Node, 4, Op);
6769 return;
6770 case Intrinsic::aarch64_sve_fclamp_single_x4:
6772 Node->getValueType(0),
6773 {0, AArch64::FCLAMP_VG4_4Z4Z_H, AArch64::FCLAMP_VG4_4Z4Z_S,
6774 AArch64::FCLAMP_VG4_4Z4Z_D}))
6775 SelectClamp(Node, 4, Op);
6776 return;
6777 case Intrinsic::aarch64_sve_bfclamp_single_x4:
6778 SelectClamp(Node, 4, AArch64::BFCLAMP_VG4_4ZZZ_H);
6779 return;
6780 case Intrinsic::aarch64_sve_add_single_x2:
6782 Node->getValueType(0),
6783 {AArch64::ADD_VG2_2ZZ_B, AArch64::ADD_VG2_2ZZ_H,
6784 AArch64::ADD_VG2_2ZZ_S, AArch64::ADD_VG2_2ZZ_D}))
6785 SelectDestructiveMultiIntrinsic(Node, 2, false, Op);
6786 return;
6787 case Intrinsic::aarch64_sve_add_single_x4:
6789 Node->getValueType(0),
6790 {AArch64::ADD_VG4_4ZZ_B, AArch64::ADD_VG4_4ZZ_H,
6791 AArch64::ADD_VG4_4ZZ_S, AArch64::ADD_VG4_4ZZ_D}))
6792 SelectDestructiveMultiIntrinsic(Node, 4, false, Op);
6793 return;
6794 case Intrinsic::aarch64_sve_zip_x2:
6796 Node->getValueType(0),
6797 {AArch64::ZIP_VG2_2ZZZ_B, AArch64::ZIP_VG2_2ZZZ_H,
6798 AArch64::ZIP_VG2_2ZZZ_S, AArch64::ZIP_VG2_2ZZZ_D}))
6799 SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op);
6800 return;
6801 case Intrinsic::aarch64_sve_zipq_x2:
6802 SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false,
6803 AArch64::ZIP_VG2_2ZZZ_Q);
6804 return;
6805 case Intrinsic::aarch64_sve_zip_x4:
6807 Node->getValueType(0),
6808 {AArch64::ZIP_VG4_4Z4Z_B, AArch64::ZIP_VG4_4Z4Z_H,
6809 AArch64::ZIP_VG4_4Z4Z_S, AArch64::ZIP_VG4_4Z4Z_D}))
6810 SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op);
6811 return;
6812 case Intrinsic::aarch64_sve_zipq_x4:
6813 SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true,
6814 AArch64::ZIP_VG4_4Z4Z_Q);
6815 return;
6816 case Intrinsic::aarch64_sve_uzp_x2:
6818 Node->getValueType(0),
6819 {AArch64::UZP_VG2_2ZZZ_B, AArch64::UZP_VG2_2ZZZ_H,
6820 AArch64::UZP_VG2_2ZZZ_S, AArch64::UZP_VG2_2ZZZ_D}))
6821 SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op);
6822 return;
6823 case Intrinsic::aarch64_sve_uzpq_x2:
6824 SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false,
6825 AArch64::UZP_VG2_2ZZZ_Q);
6826 return;
6827 case Intrinsic::aarch64_sve_uzp_x4:
6829 Node->getValueType(0),
6830 {AArch64::UZP_VG4_4Z4Z_B, AArch64::UZP_VG4_4Z4Z_H,
6831 AArch64::UZP_VG4_4Z4Z_S, AArch64::UZP_VG4_4Z4Z_D}))
6832 SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op);
6833 return;
6834 case Intrinsic::aarch64_sve_uzpq_x4:
6835 SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true,
6836 AArch64::UZP_VG4_4Z4Z_Q);
6837 return;
6838 case Intrinsic::aarch64_sve_sel_x2:
6840 Node->getValueType(0),
6841 {AArch64::SEL_VG2_2ZC2Z2Z_B, AArch64::SEL_VG2_2ZC2Z2Z_H,
6842 AArch64::SEL_VG2_2ZC2Z2Z_S, AArch64::SEL_VG2_2ZC2Z2Z_D}))
6843 SelectDestructiveMultiIntrinsic(Node, 2, true, Op, /*HasPred=*/true);
6844 return;
6845 case Intrinsic::aarch64_sve_sel_x4:
6847 Node->getValueType(0),
6848 {AArch64::SEL_VG4_4ZC4Z4Z_B, AArch64::SEL_VG4_4ZC4Z4Z_H,
6849 AArch64::SEL_VG4_4ZC4Z4Z_S, AArch64::SEL_VG4_4ZC4Z4Z_D}))
6850 SelectDestructiveMultiIntrinsic(Node, 4, true, Op, /*HasPred=*/true);
6851 return;
6852 case Intrinsic::aarch64_sve_frinta_x2:
6853 SelectFrintFromVT(Node, 2, AArch64::FRINTA_2Z2Z_S);
6854 return;
6855 case Intrinsic::aarch64_sve_frinta_x4:
6856 SelectFrintFromVT(Node, 4, AArch64::FRINTA_4Z4Z_S);
6857 return;
6858 case Intrinsic::aarch64_sve_frintm_x2:
6859 SelectFrintFromVT(Node, 2, AArch64::FRINTM_2Z2Z_S);
6860 return;
6861 case Intrinsic::aarch64_sve_frintm_x4:
6862 SelectFrintFromVT(Node, 4, AArch64::FRINTM_4Z4Z_S);
6863 return;
6864 case Intrinsic::aarch64_sve_frintn_x2:
6865 SelectFrintFromVT(Node, 2, AArch64::FRINTN_2Z2Z_S);
6866 return;
6867 case Intrinsic::aarch64_sve_frintn_x4:
6868 SelectFrintFromVT(Node, 4, AArch64::FRINTN_4Z4Z_S);
6869 return;
6870 case Intrinsic::aarch64_sve_frintp_x2:
6871 SelectFrintFromVT(Node, 2, AArch64::FRINTP_2Z2Z_S);
6872 return;
6873 case Intrinsic::aarch64_sve_frintp_x4:
6874 SelectFrintFromVT(Node, 4, AArch64::FRINTP_4Z4Z_S);
6875 return;
6876 case Intrinsic::aarch64_sve_sunpk_x2:
6878 Node->getValueType(0),
6879 {0, AArch64::SUNPK_VG2_2ZZ_H, AArch64::SUNPK_VG2_2ZZ_S,
6880 AArch64::SUNPK_VG2_2ZZ_D}))
6881 SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op);
6882 return;
6883 case Intrinsic::aarch64_sve_uunpk_x2:
6885 Node->getValueType(0),
6886 {0, AArch64::UUNPK_VG2_2ZZ_H, AArch64::UUNPK_VG2_2ZZ_S,
6887 AArch64::UUNPK_VG2_2ZZ_D}))
6888 SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op);
6889 return;
6890 case Intrinsic::aarch64_sve_sunpk_x4:
6892 Node->getValueType(0),
6893 {0, AArch64::SUNPK_VG4_4Z2Z_H, AArch64::SUNPK_VG4_4Z2Z_S,
6894 AArch64::SUNPK_VG4_4Z2Z_D}))
6895 SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op);
6896 return;
6897 case Intrinsic::aarch64_sve_uunpk_x4:
6899 Node->getValueType(0),
6900 {0, AArch64::UUNPK_VG4_4Z2Z_H, AArch64::UUNPK_VG4_4Z2Z_S,
6901 AArch64::UUNPK_VG4_4Z2Z_D}))
6902 SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op);
6903 return;
6904 case Intrinsic::aarch64_sve_pext_x2: {
6906 Node->getValueType(0),
6907 {AArch64::PEXT_2PCI_B, AArch64::PEXT_2PCI_H, AArch64::PEXT_2PCI_S,
6908 AArch64::PEXT_2PCI_D}))
6909 SelectPExtPair(Node, Op);
6910 return;
6911 }
6912 }
6913 break;
6914 }
6915 case ISD::INTRINSIC_VOID: {
6916 unsigned IntNo = Node->getConstantOperandVal(1);
6917 if (Node->getNumOperands() >= 3)
6918 VT = Node->getOperand(2)->getValueType(0);
6919 switch (IntNo) {
6920 default:
6921 break;
6922 case Intrinsic::aarch64_neon_st1x2: {
6923 if (VT == MVT::v8i8) {
6924 SelectStore(Node, 2, AArch64::ST1Twov8b);
6925 return;
6926 } else if (VT == MVT::v16i8) {
6927 SelectStore(Node, 2, AArch64::ST1Twov16b);
6928 return;
6929 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 ||
6930 VT == MVT::v4bf16) {
6931 SelectStore(Node, 2, AArch64::ST1Twov4h);
6932 return;
6933 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 ||
6934 VT == MVT::v8bf16) {
6935 SelectStore(Node, 2, AArch64::ST1Twov8h);
6936 return;
6937 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
6938 SelectStore(Node, 2, AArch64::ST1Twov2s);
6939 return;
6940 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
6941 SelectStore(Node, 2, AArch64::ST1Twov4s);
6942 return;
6943 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
6944 SelectStore(Node, 2, AArch64::ST1Twov2d);
6945 return;
6946 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
6947 SelectStore(Node, 2, AArch64::ST1Twov1d);
6948 return;
6949 }
6950 break;
6951 }
6952 case Intrinsic::aarch64_neon_st1x3: {
6953 if (VT == MVT::v8i8) {
6954 SelectStore(Node, 3, AArch64::ST1Threev8b);
6955 return;
6956 } else if (VT == MVT::v16i8) {
6957 SelectStore(Node, 3, AArch64::ST1Threev16b);
6958 return;
6959 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 ||
6960 VT == MVT::v4bf16) {
6961 SelectStore(Node, 3, AArch64::ST1Threev4h);
6962 return;
6963 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 ||
6964 VT == MVT::v8bf16) {
6965 SelectStore(Node, 3, AArch64::ST1Threev8h);
6966 return;
6967 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
6968 SelectStore(Node, 3, AArch64::ST1Threev2s);
6969 return;
6970 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
6971 SelectStore(Node, 3, AArch64::ST1Threev4s);
6972 return;
6973 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
6974 SelectStore(Node, 3, AArch64::ST1Threev2d);
6975 return;
6976 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
6977 SelectStore(Node, 3, AArch64::ST1Threev1d);
6978 return;
6979 }
6980 break;
6981 }
6982 case Intrinsic::aarch64_neon_st1x4: {
6983 if (VT == MVT::v8i8) {
6984 SelectStore(Node, 4, AArch64::ST1Fourv8b);
6985 return;
6986 } else if (VT == MVT::v16i8) {
6987 SelectStore(Node, 4, AArch64::ST1Fourv16b);
6988 return;
6989 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 ||
6990 VT == MVT::v4bf16) {
6991 SelectStore(Node, 4, AArch64::ST1Fourv4h);
6992 return;
6993 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 ||
6994 VT == MVT::v8bf16) {
6995 SelectStore(Node, 4, AArch64::ST1Fourv8h);
6996 return;
6997 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
6998 SelectStore(Node, 4, AArch64::ST1Fourv2s);
6999 return;
7000 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7001 SelectStore(Node, 4, AArch64::ST1Fourv4s);
7002 return;
7003 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7004 SelectStore(Node, 4, AArch64::ST1Fourv2d);
7005 return;
7006 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7007 SelectStore(Node, 4, AArch64::ST1Fourv1d);
7008 return;
7009 }
7010 break;
7011 }
7012 case Intrinsic::aarch64_neon_st2: {
7013 if (VT == MVT::v8i8) {
7014 SelectStore(Node, 2, AArch64::ST2Twov8b);
7015 return;
7016 } else if (VT == MVT::v16i8) {
7017 SelectStore(Node, 2, AArch64::ST2Twov16b);
7018 return;
7019 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 ||
7020 VT == MVT::v4bf16) {
7021 SelectStore(Node, 2, AArch64::ST2Twov4h);
7022 return;
7023 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 ||
7024 VT == MVT::v8bf16) {
7025 SelectStore(Node, 2, AArch64::ST2Twov8h);
7026 return;
7027 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7028 SelectStore(Node, 2, AArch64::ST2Twov2s);
7029 return;
7030 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7031 SelectStore(Node, 2, AArch64::ST2Twov4s);
7032 return;
7033 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7034 SelectStore(Node, 2, AArch64::ST2Twov2d);
7035 return;
7036 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7037 SelectStore(Node, 2, AArch64::ST1Twov1d);
7038 return;
7039 }
7040 break;
7041 }
7042 case Intrinsic::aarch64_neon_st3: {
7043 if (VT == MVT::v8i8) {
7044 SelectStore(Node, 3, AArch64::ST3Threev8b);
7045 return;
7046 } else if (VT == MVT::v16i8) {
7047 SelectStore(Node, 3, AArch64::ST3Threev16b);
7048 return;
7049 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 ||
7050 VT == MVT::v4bf16) {
7051 SelectStore(Node, 3, AArch64::ST3Threev4h);
7052 return;
7053 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 ||
7054 VT == MVT::v8bf16) {
7055 SelectStore(Node, 3, AArch64::ST3Threev8h);
7056 return;
7057 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7058 SelectStore(Node, 3, AArch64::ST3Threev2s);
7059 return;
7060 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7061 SelectStore(Node, 3, AArch64::ST3Threev4s);
7062 return;
7063 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7064 SelectStore(Node, 3, AArch64::ST3Threev2d);
7065 return;
7066 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7067 SelectStore(Node, 3, AArch64::ST1Threev1d);
7068 return;
7069 }
7070 break;
7071 }
7072 case Intrinsic::aarch64_neon_st4: {
7073 if (VT == MVT::v8i8) {
7074 SelectStore(Node, 4, AArch64::ST4Fourv8b);
7075 return;
7076 } else if (VT == MVT::v16i8) {
7077 SelectStore(Node, 4, AArch64::ST4Fourv16b);
7078 return;
7079 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 ||
7080 VT == MVT::v4bf16) {
7081 SelectStore(Node, 4, AArch64::ST4Fourv4h);
7082 return;
7083 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 ||
7084 VT == MVT::v8bf16) {
7085 SelectStore(Node, 4, AArch64::ST4Fourv8h);
7086 return;
7087 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7088 SelectStore(Node, 4, AArch64::ST4Fourv2s);
7089 return;
7090 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7091 SelectStore(Node, 4, AArch64::ST4Fourv4s);
7092 return;
7093 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7094 SelectStore(Node, 4, AArch64::ST4Fourv2d);
7095 return;
7096 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7097 SelectStore(Node, 4, AArch64::ST1Fourv1d);
7098 return;
7099 }
7100 break;
7101 }
7102 case Intrinsic::aarch64_neon_st2lane: {
7103 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7104 SelectStoreLane(Node, 2, AArch64::ST2i8);
7105 return;
7106 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7107 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7108 SelectStoreLane(Node, 2, AArch64::ST2i16);
7109 return;
7110 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7111 VT == MVT::v2f32) {
7112 SelectStoreLane(Node, 2, AArch64::ST2i32);
7113 return;
7114 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7115 VT == MVT::v1f64) {
7116 SelectStoreLane(Node, 2, AArch64::ST2i64);
7117 return;
7118 }
7119 break;
7120 }
7121 case Intrinsic::aarch64_neon_st3lane: {
7122 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7123 SelectStoreLane(Node, 3, AArch64::ST3i8);
7124 return;
7125 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7126 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7127 SelectStoreLane(Node, 3, AArch64::ST3i16);
7128 return;
7129 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7130 VT == MVT::v2f32) {
7131 SelectStoreLane(Node, 3, AArch64::ST3i32);
7132 return;
7133 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7134 VT == MVT::v1f64) {
7135 SelectStoreLane(Node, 3, AArch64::ST3i64);
7136 return;
7137 }
7138 break;
7139 }
7140 case Intrinsic::aarch64_neon_st4lane: {
7141 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7142 SelectStoreLane(Node, 4, AArch64::ST4i8);
7143 return;
7144 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7145 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7146 SelectStoreLane(Node, 4, AArch64::ST4i16);
7147 return;
7148 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7149 VT == MVT::v2f32) {
7150 SelectStoreLane(Node, 4, AArch64::ST4i32);
7151 return;
7152 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7153 VT == MVT::v1f64) {
7154 SelectStoreLane(Node, 4, AArch64::ST4i64);
7155 return;
7156 }
7157 break;
7158 }
7159 case Intrinsic::aarch64_sve_st2q: {
7160 SelectPredicatedStore(Node, 2, 4, AArch64::ST2Q, AArch64::ST2Q_IMM);
7161 return;
7162 }
7163 case Intrinsic::aarch64_sve_st3q: {
7164 SelectPredicatedStore(Node, 3, 4, AArch64::ST3Q, AArch64::ST3Q_IMM);
7165 return;
7166 }
7167 case Intrinsic::aarch64_sve_st4q: {
7168 SelectPredicatedStore(Node, 4, 4, AArch64::ST4Q, AArch64::ST4Q_IMM);
7169 return;
7170 }
7171 case Intrinsic::aarch64_sve_st2: {
7172 if (VT == MVT::nxv16i8) {
7173 SelectPredicatedStore(Node, 2, 0, AArch64::ST2B, AArch64::ST2B_IMM);
7174 return;
7175 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
7176 VT == MVT::nxv8bf16) {
7177 SelectPredicatedStore(Node, 2, 1, AArch64::ST2H, AArch64::ST2H_IMM);
7178 return;
7179 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
7180 SelectPredicatedStore(Node, 2, 2, AArch64::ST2W, AArch64::ST2W_IMM);
7181 return;
7182 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
7183 SelectPredicatedStore(Node, 2, 3, AArch64::ST2D, AArch64::ST2D_IMM);
7184 return;
7185 }
7186 break;
7187 }
7188 case Intrinsic::aarch64_sve_st3: {
7189 if (VT == MVT::nxv16i8) {
7190 SelectPredicatedStore(Node, 3, 0, AArch64::ST3B, AArch64::ST3B_IMM);
7191 return;
7192 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
7193 VT == MVT::nxv8bf16) {
7194 SelectPredicatedStore(Node, 3, 1, AArch64::ST3H, AArch64::ST3H_IMM);
7195 return;
7196 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
7197 SelectPredicatedStore(Node, 3, 2, AArch64::ST3W, AArch64::ST3W_IMM);
7198 return;
7199 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
7200 SelectPredicatedStore(Node, 3, 3, AArch64::ST3D, AArch64::ST3D_IMM);
7201 return;
7202 }
7203 break;
7204 }
7205 case Intrinsic::aarch64_sve_st4: {
7206 if (VT == MVT::nxv16i8) {
7207 SelectPredicatedStore(Node, 4, 0, AArch64::ST4B, AArch64::ST4B_IMM);
7208 return;
7209 } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 ||
7210 VT == MVT::nxv8bf16) {
7211 SelectPredicatedStore(Node, 4, 1, AArch64::ST4H, AArch64::ST4H_IMM);
7212 return;
7213 } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) {
7214 SelectPredicatedStore(Node, 4, 2, AArch64::ST4W, AArch64::ST4W_IMM);
7215 return;
7216 } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) {
7217 SelectPredicatedStore(Node, 4, 3, AArch64::ST4D, AArch64::ST4D_IMM);
7218 return;
7219 }
7220 break;
7221 }
7222 }
7223 break;
7224 }
7225 case AArch64ISD::LD2post: {
7226 if (VT == MVT::v8i8) {
7227 SelectPostLoad(Node, 2, AArch64::LD2Twov8b_POST, AArch64::dsub0);
7228 return;
7229 } else if (VT == MVT::v16i8) {
7230 SelectPostLoad(Node, 2, AArch64::LD2Twov16b_POST, AArch64::qsub0);
7231 return;
7232 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7233 SelectPostLoad(Node, 2, AArch64::LD2Twov4h_POST, AArch64::dsub0);
7234 return;
7235 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7236 SelectPostLoad(Node, 2, AArch64::LD2Twov8h_POST, AArch64::qsub0);
7237 return;
7238 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7239 SelectPostLoad(Node, 2, AArch64::LD2Twov2s_POST, AArch64::dsub0);
7240 return;
7241 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7242 SelectPostLoad(Node, 2, AArch64::LD2Twov4s_POST, AArch64::qsub0);
7243 return;
7244 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7245 SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0);
7246 return;
7247 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7248 SelectPostLoad(Node, 2, AArch64::LD2Twov2d_POST, AArch64::qsub0);
7249 return;
7250 }
7251 break;
7252 }
7253 case AArch64ISD::LD3post: {
7254 if (VT == MVT::v8i8) {
7255 SelectPostLoad(Node, 3, AArch64::LD3Threev8b_POST, AArch64::dsub0);
7256 return;
7257 } else if (VT == MVT::v16i8) {
7258 SelectPostLoad(Node, 3, AArch64::LD3Threev16b_POST, AArch64::qsub0);
7259 return;
7260 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7261 SelectPostLoad(Node, 3, AArch64::LD3Threev4h_POST, AArch64::dsub0);
7262 return;
7263 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7264 SelectPostLoad(Node, 3, AArch64::LD3Threev8h_POST, AArch64::qsub0);
7265 return;
7266 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7267 SelectPostLoad(Node, 3, AArch64::LD3Threev2s_POST, AArch64::dsub0);
7268 return;
7269 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7270 SelectPostLoad(Node, 3, AArch64::LD3Threev4s_POST, AArch64::qsub0);
7271 return;
7272 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7273 SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0);
7274 return;
7275 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7276 SelectPostLoad(Node, 3, AArch64::LD3Threev2d_POST, AArch64::qsub0);
7277 return;
7278 }
7279 break;
7280 }
7281 case AArch64ISD::LD4post: {
7282 if (VT == MVT::v8i8) {
7283 SelectPostLoad(Node, 4, AArch64::LD4Fourv8b_POST, AArch64::dsub0);
7284 return;
7285 } else if (VT == MVT::v16i8) {
7286 SelectPostLoad(Node, 4, AArch64::LD4Fourv16b_POST, AArch64::qsub0);
7287 return;
7288 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7289 SelectPostLoad(Node, 4, AArch64::LD4Fourv4h_POST, AArch64::dsub0);
7290 return;
7291 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7292 SelectPostLoad(Node, 4, AArch64::LD4Fourv8h_POST, AArch64::qsub0);
7293 return;
7294 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7295 SelectPostLoad(Node, 4, AArch64::LD4Fourv2s_POST, AArch64::dsub0);
7296 return;
7297 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7298 SelectPostLoad(Node, 4, AArch64::LD4Fourv4s_POST, AArch64::qsub0);
7299 return;
7300 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7301 SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0);
7302 return;
7303 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7304 SelectPostLoad(Node, 4, AArch64::LD4Fourv2d_POST, AArch64::qsub0);
7305 return;
7306 }
7307 break;
7308 }
7309 case AArch64ISD::LD1x2post: {
7310 if (VT == MVT::v8i8) {
7311 SelectPostLoad(Node, 2, AArch64::LD1Twov8b_POST, AArch64::dsub0);
7312 return;
7313 } else if (VT == MVT::v16i8) {
7314 SelectPostLoad(Node, 2, AArch64::LD1Twov16b_POST, AArch64::qsub0);
7315 return;
7316 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7317 SelectPostLoad(Node, 2, AArch64::LD1Twov4h_POST, AArch64::dsub0);
7318 return;
7319 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7320 SelectPostLoad(Node, 2, AArch64::LD1Twov8h_POST, AArch64::qsub0);
7321 return;
7322 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7323 SelectPostLoad(Node, 2, AArch64::LD1Twov2s_POST, AArch64::dsub0);
7324 return;
7325 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7326 SelectPostLoad(Node, 2, AArch64::LD1Twov4s_POST, AArch64::qsub0);
7327 return;
7328 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7329 SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0);
7330 return;
7331 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7332 SelectPostLoad(Node, 2, AArch64::LD1Twov2d_POST, AArch64::qsub0);
7333 return;
7334 }
7335 break;
7336 }
7337 case AArch64ISD::LD1x3post: {
7338 if (VT == MVT::v8i8) {
7339 SelectPostLoad(Node, 3, AArch64::LD1Threev8b_POST, AArch64::dsub0);
7340 return;
7341 } else if (VT == MVT::v16i8) {
7342 SelectPostLoad(Node, 3, AArch64::LD1Threev16b_POST, AArch64::qsub0);
7343 return;
7344 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7345 SelectPostLoad(Node, 3, AArch64::LD1Threev4h_POST, AArch64::dsub0);
7346 return;
7347 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7348 SelectPostLoad(Node, 3, AArch64::LD1Threev8h_POST, AArch64::qsub0);
7349 return;
7350 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7351 SelectPostLoad(Node, 3, AArch64::LD1Threev2s_POST, AArch64::dsub0);
7352 return;
7353 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7354 SelectPostLoad(Node, 3, AArch64::LD1Threev4s_POST, AArch64::qsub0);
7355 return;
7356 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7357 SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0);
7358 return;
7359 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7360 SelectPostLoad(Node, 3, AArch64::LD1Threev2d_POST, AArch64::qsub0);
7361 return;
7362 }
7363 break;
7364 }
7365 case AArch64ISD::LD1x4post: {
7366 if (VT == MVT::v8i8) {
7367 SelectPostLoad(Node, 4, AArch64::LD1Fourv8b_POST, AArch64::dsub0);
7368 return;
7369 } else if (VT == MVT::v16i8) {
7370 SelectPostLoad(Node, 4, AArch64::LD1Fourv16b_POST, AArch64::qsub0);
7371 return;
7372 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7373 SelectPostLoad(Node, 4, AArch64::LD1Fourv4h_POST, AArch64::dsub0);
7374 return;
7375 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7376 SelectPostLoad(Node, 4, AArch64::LD1Fourv8h_POST, AArch64::qsub0);
7377 return;
7378 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7379 SelectPostLoad(Node, 4, AArch64::LD1Fourv2s_POST, AArch64::dsub0);
7380 return;
7381 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7382 SelectPostLoad(Node, 4, AArch64::LD1Fourv4s_POST, AArch64::qsub0);
7383 return;
7384 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7385 SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0);
7386 return;
7387 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7388 SelectPostLoad(Node, 4, AArch64::LD1Fourv2d_POST, AArch64::qsub0);
7389 return;
7390 }
7391 break;
7392 }
7393 case AArch64ISD::LD1DUPpost: {
7394 if (VT == MVT::v8i8) {
7395 SelectPostLoad(Node, 1, AArch64::LD1Rv8b_POST, AArch64::dsub0);
7396 return;
7397 } else if (VT == MVT::v16i8) {
7398 SelectPostLoad(Node, 1, AArch64::LD1Rv16b_POST, AArch64::qsub0);
7399 return;
7400 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7401 SelectPostLoad(Node, 1, AArch64::LD1Rv4h_POST, AArch64::dsub0);
7402 return;
7403 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7404 SelectPostLoad(Node, 1, AArch64::LD1Rv8h_POST, AArch64::qsub0);
7405 return;
7406 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7407 SelectPostLoad(Node, 1, AArch64::LD1Rv2s_POST, AArch64::dsub0);
7408 return;
7409 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7410 SelectPostLoad(Node, 1, AArch64::LD1Rv4s_POST, AArch64::qsub0);
7411 return;
7412 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7413 SelectPostLoad(Node, 1, AArch64::LD1Rv1d_POST, AArch64::dsub0);
7414 return;
7415 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7416 SelectPostLoad(Node, 1, AArch64::LD1Rv2d_POST, AArch64::qsub0);
7417 return;
7418 }
7419 break;
7420 }
7421 case AArch64ISD::LD2DUPpost: {
7422 if (VT == MVT::v8i8) {
7423 SelectPostLoad(Node, 2, AArch64::LD2Rv8b_POST, AArch64::dsub0);
7424 return;
7425 } else if (VT == MVT::v16i8) {
7426 SelectPostLoad(Node, 2, AArch64::LD2Rv16b_POST, AArch64::qsub0);
7427 return;
7428 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7429 SelectPostLoad(Node, 2, AArch64::LD2Rv4h_POST, AArch64::dsub0);
7430 return;
7431 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7432 SelectPostLoad(Node, 2, AArch64::LD2Rv8h_POST, AArch64::qsub0);
7433 return;
7434 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7435 SelectPostLoad(Node, 2, AArch64::LD2Rv2s_POST, AArch64::dsub0);
7436 return;
7437 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7438 SelectPostLoad(Node, 2, AArch64::LD2Rv4s_POST, AArch64::qsub0);
7439 return;
7440 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7441 SelectPostLoad(Node, 2, AArch64::LD2Rv1d_POST, AArch64::dsub0);
7442 return;
7443 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7444 SelectPostLoad(Node, 2, AArch64::LD2Rv2d_POST, AArch64::qsub0);
7445 return;
7446 }
7447 break;
7448 }
7449 case AArch64ISD::LD3DUPpost: {
7450 if (VT == MVT::v8i8) {
7451 SelectPostLoad(Node, 3, AArch64::LD3Rv8b_POST, AArch64::dsub0);
7452 return;
7453 } else if (VT == MVT::v16i8) {
7454 SelectPostLoad(Node, 3, AArch64::LD3Rv16b_POST, AArch64::qsub0);
7455 return;
7456 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7457 SelectPostLoad(Node, 3, AArch64::LD3Rv4h_POST, AArch64::dsub0);
7458 return;
7459 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7460 SelectPostLoad(Node, 3, AArch64::LD3Rv8h_POST, AArch64::qsub0);
7461 return;
7462 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7463 SelectPostLoad(Node, 3, AArch64::LD3Rv2s_POST, AArch64::dsub0);
7464 return;
7465 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7466 SelectPostLoad(Node, 3, AArch64::LD3Rv4s_POST, AArch64::qsub0);
7467 return;
7468 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7469 SelectPostLoad(Node, 3, AArch64::LD3Rv1d_POST, AArch64::dsub0);
7470 return;
7471 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7472 SelectPostLoad(Node, 3, AArch64::LD3Rv2d_POST, AArch64::qsub0);
7473 return;
7474 }
7475 break;
7476 }
7477 case AArch64ISD::LD4DUPpost: {
7478 if (VT == MVT::v8i8) {
7479 SelectPostLoad(Node, 4, AArch64::LD4Rv8b_POST, AArch64::dsub0);
7480 return;
7481 } else if (VT == MVT::v16i8) {
7482 SelectPostLoad(Node, 4, AArch64::LD4Rv16b_POST, AArch64::qsub0);
7483 return;
7484 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7485 SelectPostLoad(Node, 4, AArch64::LD4Rv4h_POST, AArch64::dsub0);
7486 return;
7487 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7488 SelectPostLoad(Node, 4, AArch64::LD4Rv8h_POST, AArch64::qsub0);
7489 return;
7490 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7491 SelectPostLoad(Node, 4, AArch64::LD4Rv2s_POST, AArch64::dsub0);
7492 return;
7493 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7494 SelectPostLoad(Node, 4, AArch64::LD4Rv4s_POST, AArch64::qsub0);
7495 return;
7496 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7497 SelectPostLoad(Node, 4, AArch64::LD4Rv1d_POST, AArch64::dsub0);
7498 return;
7499 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7500 SelectPostLoad(Node, 4, AArch64::LD4Rv2d_POST, AArch64::qsub0);
7501 return;
7502 }
7503 break;
7504 }
7505 case AArch64ISD::LD1LANEpost: {
7506 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7507 SelectPostLoadLane(Node, 1, AArch64::LD1i8_POST);
7508 return;
7509 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7510 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7511 SelectPostLoadLane(Node, 1, AArch64::LD1i16_POST);
7512 return;
7513 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7514 VT == MVT::v2f32) {
7515 SelectPostLoadLane(Node, 1, AArch64::LD1i32_POST);
7516 return;
7517 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7518 VT == MVT::v1f64) {
7519 SelectPostLoadLane(Node, 1, AArch64::LD1i64_POST);
7520 return;
7521 }
7522 break;
7523 }
7524 case AArch64ISD::LD2LANEpost: {
7525 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7526 SelectPostLoadLane(Node, 2, AArch64::LD2i8_POST);
7527 return;
7528 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7529 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7530 SelectPostLoadLane(Node, 2, AArch64::LD2i16_POST);
7531 return;
7532 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7533 VT == MVT::v2f32) {
7534 SelectPostLoadLane(Node, 2, AArch64::LD2i32_POST);
7535 return;
7536 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7537 VT == MVT::v1f64) {
7538 SelectPostLoadLane(Node, 2, AArch64::LD2i64_POST);
7539 return;
7540 }
7541 break;
7542 }
7543 case AArch64ISD::LD3LANEpost: {
7544 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7545 SelectPostLoadLane(Node, 3, AArch64::LD3i8_POST);
7546 return;
7547 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7548 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7549 SelectPostLoadLane(Node, 3, AArch64::LD3i16_POST);
7550 return;
7551 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7552 VT == MVT::v2f32) {
7553 SelectPostLoadLane(Node, 3, AArch64::LD3i32_POST);
7554 return;
7555 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7556 VT == MVT::v1f64) {
7557 SelectPostLoadLane(Node, 3, AArch64::LD3i64_POST);
7558 return;
7559 }
7560 break;
7561 }
7562 case AArch64ISD::LD4LANEpost: {
7563 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7564 SelectPostLoadLane(Node, 4, AArch64::LD4i8_POST);
7565 return;
7566 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7567 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7568 SelectPostLoadLane(Node, 4, AArch64::LD4i16_POST);
7569 return;
7570 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7571 VT == MVT::v2f32) {
7572 SelectPostLoadLane(Node, 4, AArch64::LD4i32_POST);
7573 return;
7574 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7575 VT == MVT::v1f64) {
7576 SelectPostLoadLane(Node, 4, AArch64::LD4i64_POST);
7577 return;
7578 }
7579 break;
7580 }
7581 case AArch64ISD::ST2post: {
7582 VT = Node->getOperand(1).getValueType();
7583 if (VT == MVT::v8i8) {
7584 SelectPostStore(Node, 2, AArch64::ST2Twov8b_POST);
7585 return;
7586 } else if (VT == MVT::v16i8) {
7587 SelectPostStore(Node, 2, AArch64::ST2Twov16b_POST);
7588 return;
7589 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7590 SelectPostStore(Node, 2, AArch64::ST2Twov4h_POST);
7591 return;
7592 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7593 SelectPostStore(Node, 2, AArch64::ST2Twov8h_POST);
7594 return;
7595 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7596 SelectPostStore(Node, 2, AArch64::ST2Twov2s_POST);
7597 return;
7598 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7599 SelectPostStore(Node, 2, AArch64::ST2Twov4s_POST);
7600 return;
7601 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7602 SelectPostStore(Node, 2, AArch64::ST2Twov2d_POST);
7603 return;
7604 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7605 SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST);
7606 return;
7607 }
7608 break;
7609 }
7610 case AArch64ISD::ST3post: {
7611 VT = Node->getOperand(1).getValueType();
7612 if (VT == MVT::v8i8) {
7613 SelectPostStore(Node, 3, AArch64::ST3Threev8b_POST);
7614 return;
7615 } else if (VT == MVT::v16i8) {
7616 SelectPostStore(Node, 3, AArch64::ST3Threev16b_POST);
7617 return;
7618 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7619 SelectPostStore(Node, 3, AArch64::ST3Threev4h_POST);
7620 return;
7621 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7622 SelectPostStore(Node, 3, AArch64::ST3Threev8h_POST);
7623 return;
7624 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7625 SelectPostStore(Node, 3, AArch64::ST3Threev2s_POST);
7626 return;
7627 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7628 SelectPostStore(Node, 3, AArch64::ST3Threev4s_POST);
7629 return;
7630 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7631 SelectPostStore(Node, 3, AArch64::ST3Threev2d_POST);
7632 return;
7633 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7634 SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST);
7635 return;
7636 }
7637 break;
7638 }
7639 case AArch64ISD::ST4post: {
7640 VT = Node->getOperand(1).getValueType();
7641 if (VT == MVT::v8i8) {
7642 SelectPostStore(Node, 4, AArch64::ST4Fourv8b_POST);
7643 return;
7644 } else if (VT == MVT::v16i8) {
7645 SelectPostStore(Node, 4, AArch64::ST4Fourv16b_POST);
7646 return;
7647 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7648 SelectPostStore(Node, 4, AArch64::ST4Fourv4h_POST);
7649 return;
7650 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7651 SelectPostStore(Node, 4, AArch64::ST4Fourv8h_POST);
7652 return;
7653 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7654 SelectPostStore(Node, 4, AArch64::ST4Fourv2s_POST);
7655 return;
7656 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7657 SelectPostStore(Node, 4, AArch64::ST4Fourv4s_POST);
7658 return;
7659 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7660 SelectPostStore(Node, 4, AArch64::ST4Fourv2d_POST);
7661 return;
7662 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7663 SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST);
7664 return;
7665 }
7666 break;
7667 }
7668 case AArch64ISD::ST1x2post: {
7669 VT = Node->getOperand(1).getValueType();
7670 if (VT == MVT::v8i8) {
7671 SelectPostStore(Node, 2, AArch64::ST1Twov8b_POST);
7672 return;
7673 } else if (VT == MVT::v16i8) {
7674 SelectPostStore(Node, 2, AArch64::ST1Twov16b_POST);
7675 return;
7676 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7677 SelectPostStore(Node, 2, AArch64::ST1Twov4h_POST);
7678 return;
7679 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7680 SelectPostStore(Node, 2, AArch64::ST1Twov8h_POST);
7681 return;
7682 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7683 SelectPostStore(Node, 2, AArch64::ST1Twov2s_POST);
7684 return;
7685 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7686 SelectPostStore(Node, 2, AArch64::ST1Twov4s_POST);
7687 return;
7688 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7689 SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST);
7690 return;
7691 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7692 SelectPostStore(Node, 2, AArch64::ST1Twov2d_POST);
7693 return;
7694 }
7695 break;
7696 }
7697 case AArch64ISD::ST1x3post: {
7698 VT = Node->getOperand(1).getValueType();
7699 if (VT == MVT::v8i8) {
7700 SelectPostStore(Node, 3, AArch64::ST1Threev8b_POST);
7701 return;
7702 } else if (VT == MVT::v16i8) {
7703 SelectPostStore(Node, 3, AArch64::ST1Threev16b_POST);
7704 return;
7705 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7706 SelectPostStore(Node, 3, AArch64::ST1Threev4h_POST);
7707 return;
7708 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16 ) {
7709 SelectPostStore(Node, 3, AArch64::ST1Threev8h_POST);
7710 return;
7711 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7712 SelectPostStore(Node, 3, AArch64::ST1Threev2s_POST);
7713 return;
7714 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7715 SelectPostStore(Node, 3, AArch64::ST1Threev4s_POST);
7716 return;
7717 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7718 SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST);
7719 return;
7720 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7721 SelectPostStore(Node, 3, AArch64::ST1Threev2d_POST);
7722 return;
7723 }
7724 break;
7725 }
7726 case AArch64ISD::ST1x4post: {
7727 VT = Node->getOperand(1).getValueType();
7728 if (VT == MVT::v8i8) {
7729 SelectPostStore(Node, 4, AArch64::ST1Fourv8b_POST);
7730 return;
7731 } else if (VT == MVT::v16i8) {
7732 SelectPostStore(Node, 4, AArch64::ST1Fourv16b_POST);
7733 return;
7734 } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) {
7735 SelectPostStore(Node, 4, AArch64::ST1Fourv4h_POST);
7736 return;
7737 } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) {
7738 SelectPostStore(Node, 4, AArch64::ST1Fourv8h_POST);
7739 return;
7740 } else if (VT == MVT::v2i32 || VT == MVT::v2f32) {
7741 SelectPostStore(Node, 4, AArch64::ST1Fourv2s_POST);
7742 return;
7743 } else if (VT == MVT::v4i32 || VT == MVT::v4f32) {
7744 SelectPostStore(Node, 4, AArch64::ST1Fourv4s_POST);
7745 return;
7746 } else if (VT == MVT::v1i64 || VT == MVT::v1f64) {
7747 SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST);
7748 return;
7749 } else if (VT == MVT::v2i64 || VT == MVT::v2f64) {
7750 SelectPostStore(Node, 4, AArch64::ST1Fourv2d_POST);
7751 return;
7752 }
7753 break;
7754 }
7755 case AArch64ISD::ST2LANEpost: {
7756 VT = Node->getOperand(1).getValueType();
7757 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7758 SelectPostStoreLane(Node, 2, AArch64::ST2i8_POST);
7759 return;
7760 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7761 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7762 SelectPostStoreLane(Node, 2, AArch64::ST2i16_POST);
7763 return;
7764 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7765 VT == MVT::v2f32) {
7766 SelectPostStoreLane(Node, 2, AArch64::ST2i32_POST);
7767 return;
7768 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7769 VT == MVT::v1f64) {
7770 SelectPostStoreLane(Node, 2, AArch64::ST2i64_POST);
7771 return;
7772 }
7773 break;
7774 }
7775 case AArch64ISD::ST3LANEpost: {
7776 VT = Node->getOperand(1).getValueType();
7777 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7778 SelectPostStoreLane(Node, 3, AArch64::ST3i8_POST);
7779 return;
7780 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7781 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7782 SelectPostStoreLane(Node, 3, AArch64::ST3i16_POST);
7783 return;
7784 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7785 VT == MVT::v2f32) {
7786 SelectPostStoreLane(Node, 3, AArch64::ST3i32_POST);
7787 return;
7788 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7789 VT == MVT::v1f64) {
7790 SelectPostStoreLane(Node, 3, AArch64::ST3i64_POST);
7791 return;
7792 }
7793 break;
7794 }
7795 case AArch64ISD::ST4LANEpost: {
7796 VT = Node->getOperand(1).getValueType();
7797 if (VT == MVT::v16i8 || VT == MVT::v8i8) {
7798 SelectPostStoreLane(Node, 4, AArch64::ST4i8_POST);
7799 return;
7800 } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 ||
7801 VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) {
7802 SelectPostStoreLane(Node, 4, AArch64::ST4i16_POST);
7803 return;
7804 } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 ||
7805 VT == MVT::v2f32) {
7806 SelectPostStoreLane(Node, 4, AArch64::ST4i32_POST);
7807 return;
7808 } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 ||
7809 VT == MVT::v1f64) {
7810 SelectPostStoreLane(Node, 4, AArch64::ST4i64_POST);
7811 return;
7812 }
7813 break;
7814 }
7815 }
7816
7817 // Select the default instruction
7818 SelectCode(Node);
7819}
7820
7821/// createAArch64ISelDag - This pass converts a legalized DAG into a
7822/// AArch64-specific DAG, ready for instruction scheduling.
7824 CodeGenOptLevel OptLevel) {
7825 return new AArch64DAGToDAGISelLegacy(TM, OptLevel);
7826}
7827
7828/// When \p PredVT is a scalable vector predicate in the form
7829/// MVT::nx<M>xi1, it builds the correspondent scalable vector of
7830/// integers MVT::nx<M>xi<bits> s.t. M x bits = 128. When targeting
7831/// structured vectors (NumVec >1), the output data type is
7832/// MVT::nx<M*NumVec>xi<bits> s.t. M x bits = 128. If the input
7833/// PredVT is not in the form MVT::nx<M>xi1, it returns an invalid
7834/// EVT.
7836 unsigned NumVec) {
7837 assert(NumVec > 0 && NumVec < 5 && "Invalid number of vectors.");
7838 if (!PredVT.isScalableVectorOf(MVT::i1))
7839 return EVT();
7840
7841 if (PredVT != MVT::nxv16i1 && PredVT != MVT::nxv8i1 &&
7842 PredVT != MVT::nxv4i1 && PredVT != MVT::nxv2i1)
7843 return EVT();
7844
7845 ElementCount EC = PredVT.getVectorElementCount();
7846 EVT ScalarVT =
7847 EVT::getIntegerVT(Ctx, AArch64::SVEBitsPerBlock / EC.getKnownMinValue());
7848 EVT MemVT = EVT::getVectorVT(Ctx, ScalarVT, EC * NumVec);
7849
7850 return MemVT;
7851}
7852
7853/// Builds an integer vector type large enough to hold \p NumVec instances
7854/// of \p VecVT.
7855static EVT getMultipleVectorType(LLVMContext &Ctx, EVT VecVT, unsigned NumVec) {
7857 VecVT.getVectorElementCount() * NumVec);
7858}
7859
7860/// Return the EVT of the data associated to a memory operation in \p
7861/// Root. If such EVT cannot be retrieved, it returns an invalid EVT.
7863 if (auto *MemIntr = dyn_cast<MemIntrinsicSDNode>(Root))
7864 return MemIntr->getMemoryVT();
7865
7866 if (isa<MemSDNode>(Root)) {
7867 EVT MemVT = cast<MemSDNode>(Root)->getMemoryVT();
7868
7869 EVT DataVT;
7870 if (auto *Load = dyn_cast<LoadSDNode>(Root))
7871 DataVT = Load->getValueType(0);
7872 else if (auto *Load = dyn_cast<MaskedLoadSDNode>(Root))
7873 DataVT = Load->getValueType(0);
7874 else if (auto *Store = dyn_cast<StoreSDNode>(Root))
7875 DataVT = Store->getValue().getValueType();
7876 else if (auto *Store = dyn_cast<MaskedStoreSDNode>(Root))
7877 DataVT = Store->getValue().getValueType();
7878 else
7879 llvm_unreachable("Unexpected MemSDNode!");
7880
7881 return DataVT.changeVectorElementType(Ctx, MemVT.getVectorElementType());
7882 }
7883
7884 const unsigned Opcode = Root->getOpcode();
7885 // For custom ISD nodes, we have to look at them individually to extract the
7886 // type of the data moved to/from memory.
7887 switch (Opcode) {
7888 case AArch64ISD::LD1_MERGE_ZERO:
7889 case AArch64ISD::LD1S_MERGE_ZERO:
7890 case AArch64ISD::LDNF1_MERGE_ZERO:
7891 case AArch64ISD::LDNF1S_MERGE_ZERO:
7892 return cast<VTSDNode>(Root->getOperand(3))->getVT();
7893 case AArch64ISD::ST1_PRED:
7894 return cast<VTSDNode>(Root->getOperand(4))->getVT();
7895 default:
7896 break;
7897 }
7898
7899 if (Opcode != ISD::INTRINSIC_VOID && Opcode != ISD::INTRINSIC_W_CHAIN)
7900 return EVT();
7901
7902 switch (Root->getConstantOperandVal(1)) {
7903 default:
7904 return EVT();
7905 case Intrinsic::aarch64_sme_ldr:
7906 case Intrinsic::aarch64_sme_str:
7907 return MVT::nxv16i8;
7908 case Intrinsic::aarch64_sve_prf:
7909 // We are using an SVE prefetch intrinsic. Type must be inferred from the
7910 // width of the predicate.
7912 Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/1);
7913 case Intrinsic::aarch64_sve_ld2_sret:
7914 case Intrinsic::aarch64_sve_ld2q_sret:
7916 Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/2);
7917 case Intrinsic::aarch64_sve_st2q:
7919 Ctx, Root->getOperand(4)->getValueType(0), /*NumVec=*/2);
7920 case Intrinsic::aarch64_sve_ld3_sret:
7921 case Intrinsic::aarch64_sve_ld3q_sret:
7923 Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/3);
7924 case Intrinsic::aarch64_sve_st3q:
7926 Ctx, Root->getOperand(5)->getValueType(0), /*NumVec=*/3);
7927 case Intrinsic::aarch64_sve_ld4_sret:
7928 case Intrinsic::aarch64_sve_ld4q_sret:
7930 Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/4);
7931 case Intrinsic::aarch64_sve_st4q:
7933 Ctx, Root->getOperand(6)->getValueType(0), /*NumVec=*/4);
7934 case Intrinsic::aarch64_sve_ld1_pn_x2:
7935 case Intrinsic::aarch64_sve_ldnt1_pn_x2:
7936 return getMultipleVectorType(Ctx, Root->getValueType(0),
7937 /*NumVec=*/2);
7938 case Intrinsic::aarch64_sve_ld1_pn_x4:
7939 case Intrinsic::aarch64_sve_ldnt1_pn_x4:
7940 return getMultipleVectorType(Ctx, Root->getValueType(0),
7941 /*NumVec=*/4);
7942 case Intrinsic::aarch64_sve_st1_pn_x2:
7943 case Intrinsic::aarch64_sve_stnt1_pn_x2:
7944 return getMultipleVectorType(Ctx, Root->getOperand(2).getValueType(),
7945 /*NumVec=*/2);
7946 case Intrinsic::aarch64_sve_st1_pn_x4:
7947 case Intrinsic::aarch64_sve_stnt1_pn_x4:
7948 return getMultipleVectorType(Ctx, Root->getOperand(2).getValueType(),
7949 /*NumVec=*/4);
7950 case Intrinsic::aarch64_sve_ld1udq:
7951 case Intrinsic::aarch64_sve_st1dq:
7952 return EVT(MVT::nxv1i64);
7953 case Intrinsic::aarch64_sve_ld1uwq:
7954 case Intrinsic::aarch64_sve_st1wq:
7955 return EVT(MVT::nxv1i32);
7956 }
7957}
7958
7959/// SelectAddrModeIndexedSVE - Attempt selection of the addressing mode:
7960/// Base + OffImm * sizeof(MemVT) for Min >= OffImm <= Max
7961/// where Root is the memory access using N for its address.
7962template <int64_t Min, int64_t Max>
7963bool AArch64DAGToDAGISel::SelectAddrModeIndexedSVE(SDNode *Root, SDValue N,
7964 SDValue &Base,
7965 SDValue &OffImm) {
7966 const EVT MemVT = getMemVTFromNode(*(CurDAG->getContext()), Root);
7967 const DataLayout &DL = CurDAG->getDataLayout();
7968 const MachineFrameInfo &MFI = MF->getFrameInfo();
7969
7970 if (N.getOpcode() == ISD::FrameIndex) {
7971 int FI = cast<FrameIndexSDNode>(N)->getIndex();
7972 // We can only encode VL scaled offsets, so only fold in frame indexes
7973 // referencing SVE objects.
7974 if (MFI.hasScalableStackID(FI)) {
7975 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
7976 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64);
7977 return true;
7978 }
7979
7980 return false;
7981 }
7982
7983 if (MemVT == EVT())
7984 return false;
7985
7986 if (N.getOpcode() != ISD::ADD)
7987 return false;
7988
7989 SDValue VScale = N.getOperand(1);
7990 int64_t MulImm = std::numeric_limits<int64_t>::max();
7991 if (VScale.getOpcode() == ISD::VSCALE) {
7992 MulImm = cast<ConstantSDNode>(VScale.getOperand(0))->getSExtValue();
7993 } else if (auto C = dyn_cast<ConstantSDNode>(VScale)) {
7994 int64_t ByteOffset = C->getSExtValue();
7995 const auto KnownVScale =
7997
7998 if (!KnownVScale || ByteOffset % KnownVScale != 0)
7999 return false;
8000
8001 MulImm = ByteOffset / KnownVScale;
8002 } else
8003 return false;
8004
8005 TypeSize TS = MemVT.getSizeInBits();
8006 int64_t MemWidthBytes = static_cast<int64_t>(TS.getKnownMinValue()) / 8;
8007
8008 if ((MulImm % MemWidthBytes) != 0)
8009 return false;
8010
8011 int64_t Offset = MulImm / MemWidthBytes;
8013 return false;
8014
8015 Base = N.getOperand(0);
8016 if (Base.getOpcode() == ISD::FrameIndex) {
8017 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
8018 // We can only encode VL scaled offsets, so only fold in frame indexes
8019 // referencing SVE objects.
8020 if (MFI.hasScalableStackID(FI))
8021 Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL));
8022 }
8023
8024 OffImm = CurDAG->getTargetConstant(Offset, SDLoc(N), MVT::i64);
8025 return true;
8026}
8027
8028/// Select register plus register addressing mode for SVE, with scaled
8029/// offset.
8030bool AArch64DAGToDAGISel::SelectSVERegRegAddrMode(SDValue N, unsigned Scale,
8031 SDValue &Base,
8032 SDValue &Offset) {
8033 if (N.getOpcode() != ISD::ADD)
8034 return false;
8035
8036 // Process an ADD node.
8037 const SDValue LHS = N.getOperand(0);
8038 const SDValue RHS = N.getOperand(1);
8039
8040 // 8 bit data does not come with the SHL node, so it is treated
8041 // separately.
8042 if (Scale == 0) {
8043 Base = LHS;
8044 Offset = RHS;
8045 return true;
8046 }
8047
8048 if (auto C = dyn_cast<ConstantSDNode>(RHS)) {
8049 int64_t ImmOff = C->getSExtValue();
8050 unsigned Size = 1 << Scale;
8051
8052 // To use the reg+reg addressing mode, the immediate must be a multiple of
8053 // the vector element's byte size.
8054 if (ImmOff % Size)
8055 return false;
8056
8057 SDLoc DL(N);
8058 Base = LHS;
8059 Offset = CurDAG->getTargetConstant(ImmOff >> Scale, DL, MVT::i64);
8060 SDValue Ops[] = {Offset};
8061 SDNode *MI = CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops);
8062 Offset = SDValue(MI, 0);
8063 return true;
8064 }
8065
8066 // Check if the RHS is a shift node with a constant.
8067 if (RHS.getOpcode() != ISD::SHL)
8068 return false;
8069
8070 const SDValue ShiftRHS = RHS.getOperand(1);
8071 if (auto *C = dyn_cast<ConstantSDNode>(ShiftRHS))
8072 if (C->getZExtValue() == Scale) {
8073 Base = LHS;
8074 Offset = RHS.getOperand(0);
8075 return true;
8076 }
8077
8078 return false;
8079}
8080
8081bool AArch64DAGToDAGISel::SelectAllActivePredicate(SDValue N) {
8082 const AArch64TargetLowering *TLI =
8083 static_cast<const AArch64TargetLowering *>(getTargetLowering());
8084
8085 return TLI->isAllActivePredicate(*CurDAG, N);
8086}
8087
8088bool AArch64DAGToDAGISel::SelectAnyPredicate(SDValue N) {
8089 return N.getValueType().isScalableVectorOf(MVT::i1);
8090}
8091
8092bool AArch64DAGToDAGISel::SelectSMETileSlice(SDValue N, unsigned MaxSize,
8094 unsigned Scale) {
8095 auto MatchConstantOffset = [&](SDValue CN) -> SDValue {
8096 if (auto *C = dyn_cast<ConstantSDNode>(CN)) {
8097 int64_t ImmOff = C->getSExtValue();
8098 if ((ImmOff > 0 && ImmOff <= MaxSize && (ImmOff % Scale == 0)))
8099 return CurDAG->getTargetConstant(ImmOff / Scale, SDLoc(N), MVT::i64);
8100 }
8101 return SDValue();
8102 };
8103
8104 if (SDValue C = MatchConstantOffset(N)) {
8105 Base = getZeroRegister(*CurDAG, SDLoc(N), MVT::i32);
8106 Offset = C;
8107 return true;
8108 }
8109
8110 // Try to untangle an ADD node into a 'reg + offset'
8111 if (CurDAG->isBaseWithConstantOffset(N)) {
8112 if (SDValue C = MatchConstantOffset(N.getOperand(1))) {
8113 Base = N.getOperand(0);
8114 Offset = C;
8115 return true;
8116 }
8117 }
8118
8119 // By default, just match reg + 0.
8120 Base = N;
8121 Offset = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64);
8122 return true;
8123}
8124
8125bool AArch64DAGToDAGISel::SelectCmpBranchUImm6Operand(SDNode *P, SDValue N,
8126 SDValue &Imm) {
8128 static_cast<AArch64CC::CondCode>(P->getConstantOperandVal(1));
8129 if (auto *CN = dyn_cast<ConstantSDNode>(N)) {
8130 // Check conservatively if the immediate fits the valid range [0, 64).
8131 // Immediate variants for GE and HS definitely need to be decremented
8132 // when lowering the pseudos later, so an immediate of 1 would become 0.
8133 // For the inverse conditions LT and LO we don't know for sure if they
8134 // will need a decrement but should the decision be made to reverse the
8135 // branch condition, we again end up with the need to decrement.
8136 // The same argument holds for LE, LS, GT and HI and possibly
8137 // incremented immediates. This can lead to slightly less optimal
8138 // codegen, e.g. we never codegen the legal case
8139 // cblt w0, #63, A
8140 // because we could end up with the illegal case
8141 // cbge w0, #64, B
8142 // should the decision to reverse the branch direction be made. For the
8143 // lower bound cases this is no problem since we can express comparisons
8144 // against 0 with either tbz/tnbz or using wzr/xzr.
8145 uint64_t LowerBound = 0, UpperBound = 64;
8146 switch (CC) {
8147 case AArch64CC::GE:
8148 case AArch64CC::HS:
8149 case AArch64CC::LT:
8150 case AArch64CC::LO:
8151 LowerBound = 1;
8152 break;
8153 case AArch64CC::LE:
8154 case AArch64CC::LS:
8155 case AArch64CC::GT:
8156 case AArch64CC::HI:
8157 UpperBound = 63;
8158 break;
8159 default:
8160 break;
8161 }
8162
8163 if (CN->getAPIntValue().uge(LowerBound) &&
8164 CN->getAPIntValue().ult(UpperBound)) {
8165 SDLoc DL(N);
8166 Imm = CurDAG->getTargetConstant(CN->getZExtValue(), DL, N.getValueType());
8167 return true;
8168 }
8169 }
8170
8171 return false;
8172}
8173
8174template <bool MatchCBB>
8175bool AArch64DAGToDAGISel::SelectCmpBranchExtOperand(SDValue N, SDValue &Reg,
8176 SDValue &ExtType) {
8177
8178 // Use an invalid shift-extend value to indicate we don't need to extend later
8179 if (N.getOpcode() == ISD::AssertZext || N.getOpcode() == ISD::AssertSext) {
8180 EVT Ty = cast<VTSDNode>(N.getOperand(1))->getVT();
8181 if (Ty != (MatchCBB ? MVT::i8 : MVT::i16))
8182 return false;
8183 Reg = N.getOperand(0);
8184 ExtType = CurDAG->getSignedTargetConstant(AArch64_AM::InvalidShiftExtend,
8185 SDLoc(N), MVT::i32);
8186 return true;
8187 }
8188
8190
8191 if ((MatchCBB && (ET == AArch64_AM::UXTB || ET == AArch64_AM::SXTB)) ||
8192 (!MatchCBB && (ET == AArch64_AM::UXTH || ET == AArch64_AM::SXTH))) {
8193 Reg = N.getOperand(0);
8194 ExtType =
8195 CurDAG->getTargetConstant(getExtendEncoding(ET), SDLoc(N), MVT::i32);
8196 return true;
8197 }
8198
8199 return false;
8200}
8201
8202/// Try to fold AArch64 CSEL/FCMP patterns to FMAXNM/FMINNM.
8203///
8204/// This is intentionally done in PreprocessISelDAG rather than DAGCombine:
8205/// doing this earlier based on the defining operation of X can be invalidated
8206/// by later DAG combines. At this point the DAG is being prepared for
8207/// instruction selection, so the use of isKnownNeverSNaN(X) applies to the
8208/// final SDValue being selected.
8209/// Only handles FCMP(X, C) with scalar FP types, where C is a non-NaN constant.
8210/// The nsz requirement is needed only when C is zero, to avoid signed-zero
8211/// mismatches. The never-sNaN check is required because AArch64 FMAXNM/FMINNM
8212/// differ from fcmp+fcsel for signaling NaN inputs.
8213bool AArch64DAGToDAGISel::tryFoldCselToFMaxMin(SDNode *N) {
8214 EVT VT = N->getValueType(0);
8215
8216 // Scalar FP only.
8217 if (!VT.isFloatingPoint() || VT.isVector())
8218 return false;
8219
8220 SDValue TVal = N->getOperand(0);
8221 SDValue FVal = N->getOperand(1);
8222 SDValue CCVal = N->getOperand(2);
8223 SDValue Cmp = N->getOperand(3);
8224
8225 if (Cmp.getOpcode() != AArch64ISD::FCMP)
8226 return false;
8227
8228 auto *CC = dyn_cast<ConstantSDNode>(CCVal);
8229 if (!CC)
8230 return false;
8231
8232 SDValue CmpLHS = Cmp.getOperand(0);
8233 SDValue CmpRHS = Cmp.getOperand(1);
8234 unsigned CondCode = CC->getZExtValue();
8235
8236 // Map VT and operation (max/min) to machine opcode.
8237 auto getOpc = [](EVT VT, bool isMax) -> unsigned {
8238 if (VT == MVT::f16)
8239 return isMax ? AArch64::FMAXNMHrr : AArch64::FMINNMHrr;
8240 else if (VT == MVT::f32)
8241 return isMax ? AArch64::FMAXNMSrr : AArch64::FMINNMSrr;
8242 else if (VT == MVT::f64)
8243 return isMax ? AArch64::FMAXNMDrr : AArch64::FMINNMDrr;
8244 else
8245 return 0; // unsupported
8246 };
8247
8248 // Determine whether to use max or min based on condition code and operands.
8249 bool isMax;
8250 if (CondCode == AArch64CC::GT || CondCode == AArch64CC::GE) {
8251 if (TVal == CmpLHS && FVal == CmpRHS)
8252 isMax = true;
8253 else
8254 return false;
8255 } else if (CondCode == AArch64CC::MI || CondCode == AArch64CC::LS) {
8256 if (TVal == CmpLHS && FVal == CmpRHS)
8257 isMax = false;
8258 else
8259 return false;
8260 } else {
8261 return false;
8262 }
8263
8264 // Get the machine opcode for this VT and operation.
8265 unsigned Opc = getOpc(VT, isMax);
8266 if (!Opc)
8267 return false;
8268
8269 // Constant must be non-NaN.
8270 auto *CFP = dyn_cast<ConstantFPSDNode>(CmpRHS);
8271 if (!CFP || CFP->getValueAPF().isNaN())
8272 return false;
8273
8274 // nsz flag required only when constant is zero: fmaxnm(+0,-0)=+0 differs from
8275 // fcmp+select's -0. For non-zero constants, semantics are identical.
8276 if (CFP->isZero() && !N->getFlags().hasNoSignedZeros())
8277 return false;
8278
8279 // Only fold if variable operand is never sNaN.
8280 // This runs after DAG combines, so later combines cannot remove a defining
8281 // operation used by isKnownNeverSNaN().
8282 if (!CurDAG->isKnownNeverSNaN(CmpLHS))
8283 return false;
8284
8285 CurDAG->SelectNodeTo(N, Opc, VT, CmpLHS, CmpRHS);
8286 return true;
8287}
8288
8289void AArch64DAGToDAGISel::PreprocessISelDAG() {
8290 bool MadeChange = false;
8291 for (SDNode &N : llvm::make_early_inc_range(CurDAG->allnodes())) {
8292 if (N.use_empty())
8293 continue;
8294
8296 switch (N.getOpcode()) {
8297 case ISD::SCALAR_TO_VECTOR: {
8298 EVT ScalarTy = N.getValueType(0).getVectorElementType();
8299 if ((ScalarTy == MVT::i32 || ScalarTy == MVT::i64) &&
8300 ScalarTy == N.getOperand(0).getValueType())
8301 Result = addBitcastHints(*CurDAG, N);
8302
8303 break;
8304 }
8305 case AArch64ISD::VSHL: {
8306 // Undo mul(shl(A,C),B) -> shl(mul(A,B),C) canonicalisation when A is an
8307 // extend that can be folded into the shift.
8308 EVT VT = N.getValueType(0);
8309 SDValue A, B, C = N.getOperand(1);
8310 if (sd_match(N.getOperand(0),
8312 m_SExt(m_Value()))),
8313 m_Value(B))))) {
8314 // If both mul operands are extended, preserve the smull/umull idiom.
8315 if (B.getOpcode() == A.getOpcode())
8316 break;
8317 SDLoc DL(&N);
8318 SDValue SHL = CurDAG->getNode(AArch64ISD::VSHL, DL, VT, A, C);
8319 Result = CurDAG->getNode(ISD::MUL, DL, VT, SHL, B);
8320 }
8321 break;
8322 }
8323 default:
8324 break;
8325 }
8326
8327 if (Result) {
8328 LLVM_DEBUG(dbgs() << "AArch64 DAG preprocessing replacing:\nOld: ");
8329 LLVM_DEBUG(N.dump(CurDAG));
8330 LLVM_DEBUG(dbgs() << "\nNew: ");
8331 LLVM_DEBUG(Result.dump(CurDAG));
8332 LLVM_DEBUG(dbgs() << "\n");
8333
8334 CurDAG->ReplaceAllUsesOfValueWith(SDValue(&N, 0), Result);
8335 MadeChange = true;
8336 }
8337 }
8338
8339 if (MadeChange)
8340 CurDAG->RemoveDeadNodes();
8341
8343}
static SDValue Widen(SelectionDAG *CurDAG, SDValue N)
static bool isBitfieldExtractOpFromSExtInReg(SDNode *N, unsigned &Opc, SDValue &Opd0, unsigned &Immr, unsigned &Imms)
static int getIntOperandFromRegisterString(StringRef RegString)
static SDValue NarrowVector(SDValue V128Reg, SelectionDAG &DAG)
NarrowVector - Given a value in the V128 register class, produce the equivalent value in the V64 regi...
static std::optional< APInt > GetNEONSplatValue(SDValue N)
static bool isBitfieldDstMask(uint64_t DstMask, const APInt &BitsToBeInserted, unsigned NumberOfIgnoredHighBits, EVT VT)
Does DstMask form a complementary pair with the mask provided by BitsToBeInserted,...
static SDValue narrowIfNeeded(SelectionDAG *CurDAG, SDValue N)
Instructions that accept extend modifiers like UXTW expect the register being extended to be a GPR32,...
static bool isSeveralBitsPositioningOpFromShl(const uint64_t ShlImm, SDValue Op, SDValue &Src, int &DstLSB, int &Width)
static bool isBitfieldPositioningOp(SelectionDAG *CurDAG, SDValue Op, bool BiggerPattern, SDValue &Src, int &DstLSB, int &Width)
Does this tree qualify as an attempt to move a bitfield into position, essentially "(and (shl VAL,...
static bool isOpcWithIntImmediate(const SDNode *N, unsigned Opc, uint64_t &Imm)
static bool tryBitfieldInsertOpFromOrAndImm(SDNode *N, SelectionDAG *CurDAG)
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static SDValue addBitcastHints(SelectionDAG &DAG, SDNode &N)
addBitcastHints - This method adds bitcast hints to the operands of a node to help instruction select...
static void getUsefulBitsFromOrWithShiftedReg(SDValue Op, APInt &UsefulBits, unsigned Depth)
static bool isBitfieldExtractOpFromAnd(SelectionDAG *CurDAG, SDNode *N, unsigned &Opc, SDValue &Opd0, unsigned &LSB, unsigned &MSB, unsigned NumberOfIgnoredLowBits, bool BiggerPattern)
static bool isBitfieldExtractOp(SelectionDAG *CurDAG, SDNode *N, unsigned &Opc, SDValue &Opd0, unsigned &Immr, unsigned &Imms, unsigned NumberOfIgnoredLowBits=0, bool BiggerPattern=false)
static bool isShiftedMask(uint64_t Mask, EVT VT)
bool SelectSMETile(unsigned &BaseReg, unsigned TileNum)
static EVT getMemVTFromNode(LLVMContext &Ctx, SDNode *Root)
Return the EVT of the data associated to a memory operation in Root.
static bool checkCVTFixedPointOperandWithFBits(SelectionDAG *CurDAG, SDValue N, SDValue &FixedPos, unsigned RegWidth, bool isReciprocal)
static bool isWorthFoldingADDlow(SDValue N)
If there's a use of this ADDlow that's not itself a load/store then we'll need to create a real ADD i...
static AArch64_AM::ShiftExtendType getShiftTypeForNode(SDValue N)
getShiftTypeForNode - Translate a shift node to the corresponding ShiftType value.
static bool isSeveralBitsExtractOpFromShr(SDNode *N, unsigned &Opc, SDValue &Opd0, unsigned &LSB, unsigned &MSB)
static unsigned SelectOpcodeFromVT(EVT VT, ArrayRef< unsigned > Opcodes)
This function selects an opcode from a list of opcodes, which is expected to be the opcode for { 8-bi...
static EVT getPackedVectorTypeFromPredicateType(LLVMContext &Ctx, EVT PredVT, unsigned NumVec)
When PredVT is a scalable vector predicate in the form MVT::nx<M>xi1, it builds the correspondent sca...
static std::optional< APInt > DecodeNEONSplat(SDValue N)
static bool checkCVTFixedPointOperandWithFBitsForVectors(SelectionDAG *CurDAG, SDValue N, SDValue &FixedPos, unsigned RegWidth, bool isReciprocal)
static SDValue getZeroRegister(SelectionDAG &DAG, SDLoc DL, EVT VT)
Returns a copy from WZR or XZR.
static bool isPreferredADD(int64_t ImmOff)
static void getUsefulBitsFromBitfieldMoveOpd(SDValue Op, APInt &UsefulBits, uint64_t Imm, uint64_t MSB, unsigned Depth)
static SDValue getLeftShift(SelectionDAG *CurDAG, SDValue Op, int ShlAmount)
Create a machine node performing a notional SHL of Op by ShlAmount.
static bool isWorthFoldingSHL(SDValue V)
Determine whether it is worth it to fold SHL into the addressing mode.
static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, bool BiggerPattern, const uint64_t NonZeroBits, SDValue &Src, int &DstLSB, int &Width)
static void getUsefulBitsFromBFM(SDValue Op, SDValue Orig, APInt &UsefulBits, unsigned Depth)
static bool isBitfieldExtractOpFromShr(SDNode *N, unsigned &Opc, SDValue &Opd0, unsigned &Immr, unsigned &Imms, bool BiggerPattern)
static bool tryOrrWithShift(SDNode *N, SDValue OrOpd0, SDValue OrOpd1, SDValue Src, SDValue Dst, SelectionDAG *CurDAG, const bool BiggerPattern)
static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits, SDValue Orig, unsigned Depth)
static bool isMemOpOrPrefetch(SDNode *N)
static void getUsefulBitsFromUBFM(SDValue Op, APInt &UsefulBits, unsigned Depth)
static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits, SelectionDAG *CurDAG)
static APInt DecodeFMOVImm(uint64_t Imm, unsigned RegWidth)
static void getUsefulBitsFromAndWithImmediate(SDValue Op, APInt &UsefulBits, unsigned Depth)
static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth=0)
static bool isIntImmediateEq(SDValue N, const uint64_t ImmExpected)
static EVT getMultipleVectorType(LLVMContext &Ctx, EVT VecVT, unsigned NumVec)
Builds an integer vector type large enough to hold NumVec instances of VecVT.
static AArch64_AM::ShiftExtendType getExtendTypeForNode(SDValue N, bool IsLoadStore=false)
getExtendTypeForNode - Translate an extend node to the corresponding ExtendType value.
static bool isIntImmediate(const SDNode *N, uint64_t &Imm)
isIntImmediate - This method tests to see if the node is a constant operand.
static bool isWorthFoldingIntoOrrWithShift(SDValue Dst, SelectionDAG *CurDAG, SDValue &ShiftedOperand, uint64_t &EncodedShiftImm)
static bool isValidAsScaledImmediate(int64_t Offset, unsigned Range, unsigned Size)
Check if the immediate offset is valid as a scaled immediate.
static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, bool BiggerPattern, const uint64_t NonZeroBits, SDValue &Src, int &DstLSB, int &Width)
return SDValue()
static SDValue WidenVector(SDValue V64Reg, SelectionDAG &DAG)
WidenVector - Given a value in the V64 register class, produce the equivalent value in the V128 regis...
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
AMDGPU Register Bank Select
This file implements the APSInt class, which is a simple class that represents an arbitrary sized int...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define DEBUG_TYPE
IRTranslator LLVM IR MI
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
#define R2(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t High
OptimizedStructLayoutField Field
#define P(N)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
Contains matchers for matching SelectionDAG nodes and values.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:484
#define LLVM_DEBUG(...)
Definition Debug.h:119
#define PASS_NAME
Value * RHS
Value * LHS
AArch64DAGToDAGISelPass(AArch64TargetMachine &TM)
const AArch64RegisterInfo * getRegisterInfo() const override
const AArch64TargetLowering * getTargetLowering() const override
bool isStreaming() const
Returns true if the function has a streaming body.
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
unsigned getSVEVectorSizeInBits() const
bool isAllActivePredicate(const SelectionDAG &DAG, SDValue N) const
Register matchRegisterName(StringRef RegName) const
static const fltSemantics & IEEEsingle()
Definition APFloat.h:304
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static const fltSemantics & IEEEhalf()
Definition APFloat.h:302
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1565
unsigned popcount() const
Count the number of bits set.
Definition APInt.h:1695
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1076
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:968
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit)
Get a value with a block of bits set.
Definition APInt.h:259
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1664
unsigned countl_zero() const
The APInt version of std::countl_zero.
Definition APInt.h:1623
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
Definition APInt.cpp:652
void flipAllBits()
Toggle every bit to its opposite value.
Definition APInt.h:1477
bool isShiftedMask() const
Return true if this APInt value contains a non-empty sequence of ones with the remainder zero.
Definition APInt.h:511
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1587
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
Definition APInt.h:865
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:858
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator begin() const
Definition ArrayRef.h:129
const Constant * getConstVal() const
uint64_t getZExtValue() const
const APInt & getAPIntValue() const
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const GlobalValue * getGlobal() const
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
This class is used to represent ISD::LOAD nodes.
unsigned getID() const
getID() - Return the register class ID number.
Machine Value Type.
SimpleValueType SimpleTy
uint64_t getScalarSizeInBits() const
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
static MVT getVectorVT(MVT VT, unsigned NumElements)
bool hasScalableStackID(int ObjectIdx) const
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
bool isMachineOpcode() const
Test if this node has a post-isel opcode, directly corresponding to a MachineInstr opcode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
unsigned getMachineOpcode() const
This may only be called if isMachineOpcode returns true.
const SDValue & getOperand(unsigned Num) const
uint64_t getConstantOperandVal(unsigned Num) const
Helper method returns the integer value of a ConstantSDNode operand.
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
iterator_range< user_iterator > users()
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
const SDValue & getOperand(unsigned i) const
uint64_t getConstantOperandVal(unsigned i) const
unsigned getOpcode() const
SelectionDAGISelPass(std::unique_ptr< SelectionDAGISel > Selector)
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual void PreprocessISelDAG()
PreprocessISelDAG - This hook allows targets to hack on the graph before instruction selection starts...
virtual bool runOnMachineFunction(MachineFunction &mf)
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDNode * SelectNodeTo(SDNode *N, unsigned MachineOpc, EVT VT)
These are used for target selectors to mutate the specified node to have the specified return type,...
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
static constexpr unsigned MaxRecursionDepth
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
LLVM_ABI SDValue getTargetExtractSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand)
A convenience function for creating TargetInstrInfo::EXTRACT_SUBREG nodes.
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
LLVMContext * getContext() const
LLVM_ABI SDValue getTargetInsertSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand, SDValue Subreg)
A convenience function for creating TargetInstrInfo::INSERT_SUBREG nodes.
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
LLVM Value Representation.
Definition Value.h:75
bool hasOneUse() const
Return true if there is exactly one use of this value.
Definition Value.h:439
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
Definition Value.cpp:993
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
uint32_t parseGenericRegister(StringRef Name)
static uint64_t decodeLogicalImmediate(uint64_t val, unsigned regSize)
decodeLogicalImmediate - Decode a logical immediate value in the form "N:immr:imms" (where the immr a...
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint64_t decodeAdvSIMDModImmType12(uint8_t Imm)
constexpr bool isLegalArithImmed(const uint64_t C)
isLegalArithImmed -
static uint64_t decodeAdvSIMDModImmType11(uint8_t Imm)
unsigned getExtendEncoding(AArch64_AM::ShiftExtendType ET)
Mapping from extend bits to required operation: shifter: 000 ==> uxtb 001 ==> uxth 010 ==> uxtw 011 =...
static uint64_t decodeAdvSIMDModImmType10(uint8_t Imm)
static bool isSVELogicalImm(unsigned SizeInBits, uint64_t ImmVal, uint64_t &Encoding)
constexpr unsigned getArithImmedShift(const uint64_t C)
getArithImmedShift - assumes C is a legal immediate for arithmetic instructions and
static bool isSVECpyDupImm(int SizeInBits, int64_t Val, int32_t &Imm, int32_t &Shift)
static AArch64_AM::ShiftExtendType getShiftType(unsigned Imm)
getShiftType - Extract the shift type.
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
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...
static constexpr unsigned SVEBitsPerBlock
@ POISON
POISON - A poison node.
Definition ISDOpcodes.h:236
@ INSERT_SUBVECTOR
INSERT_SUBVECTOR(VECTOR1, VECTOR2, IDX) - Returns a vector with VECTOR2 inserted into VECTOR1.
Definition ISDOpcodes.h:602
@ ATOMIC_STORE
OUTCHAIN = ATOMIC_STORE(INCHAIN, val, ptr) This corresponds to "store atomic" instruction.
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:264
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:863
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:220
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:854
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:667
@ ATOMIC_LOAD
Val, OUTCHAIN = ATOMIC_LOAD(INCHAIN, ptr) This corresponds to "load atomic" instruction.
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:233
@ SPLAT_VECTOR
SPLAT_VECTOR(VAL) - Returns a vector with the scalar value VAL duplicated in all lanes.
Definition ISDOpcodes.h:674
@ AssertAlign
AssertAlign - These nodes record if a register contains a value that has a known alignment and the tr...
Definition ISDOpcodes.h:69
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
Definition ISDOpcodes.h:230
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:771
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:616
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition ISDOpcodes.h:139
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:578
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:860
@ VSCALE
VSCALE(IMM) - Returns the runtime scaling factor used to calculate the number of elements within a sc...
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:898
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:741
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:205
@ FREEZE
FREEZE - FREEZE(VAL) returns an arbitrary value if VAL is UNDEF (or is evaluated to UNDEF),...
Definition ISDOpcodes.h:241
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:866
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition ISDOpcodes.h:62
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:213
LLVM_ABI bool isConstantSplatVector(const SDNode *N, APInt &SplatValue)
Node predicates.
MemIndexedMode
MemIndexedMode enum - This enum defines the load / store indexed addressing modes.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
BinaryOpc_match< LHS, RHS, true > m_Mul(const LHS &L, const RHS &R)
Or< Preds... > m_AnyOf(const Preds &...preds)
bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P)
auto m_SExt(const Opnd &Op)
UnaryOpc_match< Opnd > m_ZExt(const Opnd &Op)
Value_match m_Value()
Match any valid SDValue.
NUses_match< 1, Value_match > m_OneUse()
Not(const Pred &P) -> Not< Pred >
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
Definition Threading.h:280
@ Offset
Definition DWP.cpp:578
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
bool isStrongerThanMonotonic(AtomicOrdering AO)
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
Definition bit.h:315
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
constexpr bool isShiftedMask_32(uint32_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (32 bit ver...
Definition MathExtras.h:268
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:338
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition MathExtras.h:274
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
Definition STLExtras.h:2026
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:262
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:149
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
FunctionPass * createAArch64ISelDag(AArch64TargetMachine &TM, CodeGenOptLevel OptLevel)
createAArch64ISelDag - This pass converts a legalized DAG into a AArch64-specific DAG,...
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool isNullFPConstant(SDValue V)
Returns true if V is an FP constant with a value of positive zero.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:78
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
Extended Value Type.
Definition ValueTypes.h:35
bool isScalableVectorOf(EVT EltVT) const
Return true if this is a scalable vector with matching element type.
Definition ValueTypes.h:192
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
EVT changeTypeToInteger() const
Return the type converted to an equivalently sized integer or vector with integer element type.
Definition ValueTypes.h:129
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:155
ElementCount getVectorElementCount() const
Definition ValueTypes.h:373
EVT getDoubleNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:494
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
unsigned getVectorMinNumElements() const
Given a vector type, return the minimum number of elements it contains.
Definition ValueTypes.h:382
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
EVT changeVectorElementType(LLVMContext &Context, EVT EltVT) const
Return a VT for a vector type whose attributes match ourselves with the exception of the element type...
Definition ValueTypes.h:98
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:230
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:404
bool isFixedLengthVector() const
Definition ValueTypes.h:199
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
bool isScalableVector() const
Return true if this is a vector type where the runtime length is machine dependent.
Definition ValueTypes.h:187
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
bool is64BitVector() const
Return true if this is a 64-bit vector type.
Definition ValueTypes.h:225
Matching combinators.