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