10b57cec5SDimitry Andric //===-- AArch64ISelDAGToDAG.cpp - A dag to dag inst selector for AArch64 --===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines an instruction selector for the AArch64 target. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 13e8d8bef9SDimitry Andric #include "AArch64MachineFunctionInfo.h" 140b57cec5SDimitry Andric #include "AArch64TargetMachine.h" 150b57cec5SDimitry Andric #include "MCTargetDesc/AArch64AddressingModes.h" 160b57cec5SDimitry Andric #include "llvm/ADT/APSInt.h" 17bdd1243dSDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h" 190b57cec5SDimitry Andric #include "llvm/IR/Function.h" // To access function attributes. 200b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h" 210b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 22480093f4SDimitry Andric #include "llvm/IR/IntrinsicsAArch64.h" 230b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 240b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 250b57cec5SDimitry Andric #include "llvm/Support/KnownBits.h" 260b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 270b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric #define DEBUG_TYPE "aarch64-isel" 32bdd1243dSDimitry Andric #define PASS_NAME "AArch64 Instruction Selection" 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 350b57cec5SDimitry Andric /// AArch64DAGToDAGISel - AArch64 specific code to select AArch64 machine 360b57cec5SDimitry Andric /// instructions for SelectionDAG operations. 370b57cec5SDimitry Andric /// 380b57cec5SDimitry Andric namespace { 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric class AArch64DAGToDAGISel : public SelectionDAGISel { 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric /// Subtarget - Keep a pointer to the AArch64Subtarget around so that we can 430b57cec5SDimitry Andric /// make the right decision when generating code for different targets. 440b57cec5SDimitry Andric const AArch64Subtarget *Subtarget; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric public: 47bdd1243dSDimitry Andric static char ID; 48bdd1243dSDimitry Andric 49bdd1243dSDimitry Andric AArch64DAGToDAGISel() = delete; 50bdd1243dSDimitry Andric 510b57cec5SDimitry Andric explicit AArch64DAGToDAGISel(AArch64TargetMachine &tm, 52*5f757f3fSDimitry Andric CodeGenOptLevel OptLevel) 53bdd1243dSDimitry Andric : SelectionDAGISel(ID, tm, OptLevel), Subtarget(nullptr) {} 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 560b57cec5SDimitry Andric Subtarget = &MF.getSubtarget<AArch64Subtarget>(); 570b57cec5SDimitry Andric return SelectionDAGISel::runOnMachineFunction(MF); 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric void Select(SDNode *Node) override; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 630b57cec5SDimitry Andric /// inline asm expressions. 640b57cec5SDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, 65*5f757f3fSDimitry Andric InlineAsm::ConstraintCode ConstraintID, 660b57cec5SDimitry Andric std::vector<SDValue> &OutOps) override; 670b57cec5SDimitry Andric 685ffd83dbSDimitry Andric template <signed Low, signed High, signed Scale> 695ffd83dbSDimitry Andric bool SelectRDVLImm(SDValue N, SDValue &Imm); 705ffd83dbSDimitry Andric 710b57cec5SDimitry Andric bool SelectArithExtendedRegister(SDValue N, SDValue &Reg, SDValue &Shift); 72fcaf7f86SDimitry Andric bool SelectArithUXTXRegister(SDValue N, SDValue &Reg, SDValue &Shift); 730b57cec5SDimitry Andric bool SelectArithImmed(SDValue N, SDValue &Val, SDValue &Shift); 740b57cec5SDimitry Andric bool SelectNegArithImmed(SDValue N, SDValue &Val, SDValue &Shift); 750b57cec5SDimitry Andric bool SelectArithShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) { 760b57cec5SDimitry Andric return SelectShiftedRegister(N, false, Reg, Shift); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric bool SelectLogicalShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) { 790b57cec5SDimitry Andric return SelectShiftedRegister(N, true, Reg, Shift); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric bool SelectAddrModeIndexed7S8(SDValue N, SDValue &Base, SDValue &OffImm) { 820b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 1, Base, OffImm); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric bool SelectAddrModeIndexed7S16(SDValue N, SDValue &Base, SDValue &OffImm) { 850b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 2, Base, OffImm); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric bool SelectAddrModeIndexed7S32(SDValue N, SDValue &Base, SDValue &OffImm) { 880b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 4, Base, OffImm); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric bool SelectAddrModeIndexed7S64(SDValue N, SDValue &Base, SDValue &OffImm) { 910b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 8, Base, OffImm); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric bool SelectAddrModeIndexed7S128(SDValue N, SDValue &Base, SDValue &OffImm) { 940b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 16, Base, OffImm); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric bool SelectAddrModeIndexedS9S128(SDValue N, SDValue &Base, SDValue &OffImm) { 970b57cec5SDimitry Andric return SelectAddrModeIndexedBitWidth(N, true, 9, 16, Base, OffImm); 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric bool SelectAddrModeIndexedU6S128(SDValue N, SDValue &Base, SDValue &OffImm) { 1000b57cec5SDimitry Andric return SelectAddrModeIndexedBitWidth(N, false, 6, 16, Base, OffImm); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric bool SelectAddrModeIndexed8(SDValue N, SDValue &Base, SDValue &OffImm) { 1030b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 1, Base, OffImm); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric bool SelectAddrModeIndexed16(SDValue N, SDValue &Base, SDValue &OffImm) { 1060b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 2, Base, OffImm); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric bool SelectAddrModeIndexed32(SDValue N, SDValue &Base, SDValue &OffImm) { 1090b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 4, Base, OffImm); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric bool SelectAddrModeIndexed64(SDValue N, SDValue &Base, SDValue &OffImm) { 1120b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 8, Base, OffImm); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric bool SelectAddrModeIndexed128(SDValue N, SDValue &Base, SDValue &OffImm) { 1150b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 16, Base, OffImm); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric bool SelectAddrModeUnscaled8(SDValue N, SDValue &Base, SDValue &OffImm) { 1180b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 1, Base, OffImm); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric bool SelectAddrModeUnscaled16(SDValue N, SDValue &Base, SDValue &OffImm) { 1210b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 2, Base, OffImm); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric bool SelectAddrModeUnscaled32(SDValue N, SDValue &Base, SDValue &OffImm) { 1240b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 4, Base, OffImm); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric bool SelectAddrModeUnscaled64(SDValue N, SDValue &Base, SDValue &OffImm) { 1270b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 8, Base, OffImm); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric bool SelectAddrModeUnscaled128(SDValue N, SDValue &Base, SDValue &OffImm) { 1300b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 16, Base, OffImm); 1310b57cec5SDimitry Andric } 132fe6060f1SDimitry Andric template <unsigned Size, unsigned Max> 133fe6060f1SDimitry Andric bool SelectAddrModeIndexedUImm(SDValue N, SDValue &Base, SDValue &OffImm) { 134fe6060f1SDimitry Andric // Test if there is an appropriate addressing mode and check if the 135fe6060f1SDimitry Andric // immediate fits. 136fe6060f1SDimitry Andric bool Found = SelectAddrModeIndexed(N, Size, Base, OffImm); 137fe6060f1SDimitry Andric if (Found) { 138fe6060f1SDimitry Andric if (auto *CI = dyn_cast<ConstantSDNode>(OffImm)) { 139fe6060f1SDimitry Andric int64_t C = CI->getSExtValue(); 140fe6060f1SDimitry Andric if (C <= Max) 141fe6060f1SDimitry Andric return true; 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric // Otherwise, base only, materialize address in register. 146fe6060f1SDimitry Andric Base = N; 147fe6060f1SDimitry Andric OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 148fe6060f1SDimitry Andric return true; 149fe6060f1SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric template<int Width> 1520b57cec5SDimitry Andric bool SelectAddrModeWRO(SDValue N, SDValue &Base, SDValue &Offset, 1530b57cec5SDimitry Andric SDValue &SignExtend, SDValue &DoShift) { 1540b57cec5SDimitry Andric return SelectAddrModeWRO(N, Width / 8, Base, Offset, SignExtend, DoShift); 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric template<int Width> 1580b57cec5SDimitry Andric bool SelectAddrModeXRO(SDValue N, SDValue &Base, SDValue &Offset, 1590b57cec5SDimitry Andric SDValue &SignExtend, SDValue &DoShift) { 1600b57cec5SDimitry Andric return SelectAddrModeXRO(N, Width / 8, Base, Offset, SignExtend, DoShift); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 16381ad6265SDimitry Andric bool SelectExtractHigh(SDValue N, SDValue &Res) { 16481ad6265SDimitry Andric if (Subtarget->isLittleEndian() && N->getOpcode() == ISD::BITCAST) 16581ad6265SDimitry Andric N = N->getOperand(0); 16681ad6265SDimitry Andric if (N->getOpcode() != ISD::EXTRACT_SUBVECTOR || 16781ad6265SDimitry Andric !isa<ConstantSDNode>(N->getOperand(1))) 16881ad6265SDimitry Andric return false; 16981ad6265SDimitry Andric EVT VT = N->getValueType(0); 17081ad6265SDimitry Andric EVT LVT = N->getOperand(0).getValueType(); 17181ad6265SDimitry Andric unsigned Index = N->getConstantOperandVal(1); 17281ad6265SDimitry Andric if (!VT.is64BitVector() || !LVT.is128BitVector() || 17381ad6265SDimitry Andric Index != VT.getVectorNumElements()) 17481ad6265SDimitry Andric return false; 17581ad6265SDimitry Andric Res = N->getOperand(0); 17681ad6265SDimitry Andric return true; 17781ad6265SDimitry Andric } 17881ad6265SDimitry Andric 179bdd1243dSDimitry Andric bool SelectRoundingVLShr(SDValue N, SDValue &Res1, SDValue &Res2) { 180bdd1243dSDimitry Andric if (N.getOpcode() != AArch64ISD::VLSHR) 181bdd1243dSDimitry Andric return false; 182bdd1243dSDimitry Andric SDValue Op = N->getOperand(0); 183bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 184bdd1243dSDimitry Andric unsigned ShtAmt = N->getConstantOperandVal(1); 185bdd1243dSDimitry Andric if (ShtAmt > VT.getScalarSizeInBits() / 2 || Op.getOpcode() != ISD::ADD) 186bdd1243dSDimitry Andric return false; 187bdd1243dSDimitry Andric 188bdd1243dSDimitry Andric APInt Imm; 189bdd1243dSDimitry Andric if (Op.getOperand(1).getOpcode() == AArch64ISD::MOVIshift) 190bdd1243dSDimitry Andric Imm = APInt(VT.getScalarSizeInBits(), 191bdd1243dSDimitry Andric Op.getOperand(1).getConstantOperandVal(0) 192bdd1243dSDimitry Andric << Op.getOperand(1).getConstantOperandVal(1)); 193bdd1243dSDimitry Andric else if (Op.getOperand(1).getOpcode() == AArch64ISD::DUP && 194bdd1243dSDimitry Andric isa<ConstantSDNode>(Op.getOperand(1).getOperand(0))) 195bdd1243dSDimitry Andric Imm = APInt(VT.getScalarSizeInBits(), 196bdd1243dSDimitry Andric Op.getOperand(1).getConstantOperandVal(0)); 197bdd1243dSDimitry Andric else 198bdd1243dSDimitry Andric return false; 199bdd1243dSDimitry Andric 200bdd1243dSDimitry Andric if (Imm != 1ULL << (ShtAmt - 1)) 201bdd1243dSDimitry Andric return false; 202bdd1243dSDimitry Andric 203bdd1243dSDimitry Andric Res1 = Op.getOperand(0); 204bdd1243dSDimitry Andric Res2 = CurDAG->getTargetConstant(ShtAmt, SDLoc(N), MVT::i32); 205bdd1243dSDimitry Andric return true; 206bdd1243dSDimitry Andric } 207bdd1243dSDimitry Andric 208480093f4SDimitry Andric bool SelectDupZeroOrUndef(SDValue N) { 209480093f4SDimitry Andric switch(N->getOpcode()) { 210480093f4SDimitry Andric case ISD::UNDEF: 211480093f4SDimitry Andric return true; 212480093f4SDimitry Andric case AArch64ISD::DUP: 213480093f4SDimitry Andric case ISD::SPLAT_VECTOR: { 214480093f4SDimitry Andric auto Opnd0 = N->getOperand(0); 215bdd1243dSDimitry Andric if (isNullConstant(Opnd0)) 216480093f4SDimitry Andric return true; 217bdd1243dSDimitry Andric if (isNullFPConstant(Opnd0)) 218480093f4SDimitry Andric return true; 219480093f4SDimitry Andric break; 220480093f4SDimitry Andric } 221480093f4SDimitry Andric default: 222480093f4SDimitry Andric break; 223480093f4SDimitry Andric } 224480093f4SDimitry Andric 225480093f4SDimitry Andric return false; 226480093f4SDimitry Andric } 227480093f4SDimitry Andric 2285ffd83dbSDimitry Andric bool SelectDupZero(SDValue N) { 2295ffd83dbSDimitry Andric switch(N->getOpcode()) { 2305ffd83dbSDimitry Andric case AArch64ISD::DUP: 2315ffd83dbSDimitry Andric case ISD::SPLAT_VECTOR: { 2325ffd83dbSDimitry Andric auto Opnd0 = N->getOperand(0); 233bdd1243dSDimitry Andric if (isNullConstant(Opnd0)) 2345ffd83dbSDimitry Andric return true; 235bdd1243dSDimitry Andric if (isNullFPConstant(Opnd0)) 2365ffd83dbSDimitry Andric return true; 2375ffd83dbSDimitry Andric break; 2385ffd83dbSDimitry Andric } 2395ffd83dbSDimitry Andric } 2405ffd83dbSDimitry Andric 2415ffd83dbSDimitry Andric return false; 2425ffd83dbSDimitry Andric } 2435ffd83dbSDimitry Andric 24406c3fb27SDimitry Andric bool SelectDupNegativeZero(SDValue N) { 24506c3fb27SDimitry Andric switch(N->getOpcode()) { 24606c3fb27SDimitry Andric case AArch64ISD::DUP: 24706c3fb27SDimitry Andric case ISD::SPLAT_VECTOR: { 24806c3fb27SDimitry Andric ConstantFPSDNode *Const = dyn_cast<ConstantFPSDNode>(N->getOperand(0)); 24906c3fb27SDimitry Andric return Const && Const->isZero() && Const->isNegative(); 25006c3fb27SDimitry Andric } 25106c3fb27SDimitry Andric } 25206c3fb27SDimitry Andric 25306c3fb27SDimitry Andric return false; 25406c3fb27SDimitry Andric } 25506c3fb27SDimitry Andric 256480093f4SDimitry Andric template<MVT::SimpleValueType VT> 257480093f4SDimitry Andric bool SelectSVEAddSubImm(SDValue N, SDValue &Imm, SDValue &Shift) { 258480093f4SDimitry Andric return SelectSVEAddSubImm(N, VT, Imm, Shift); 259480093f4SDimitry Andric } 260480093f4SDimitry Andric 26181ad6265SDimitry Andric template <MVT::SimpleValueType VT> 26281ad6265SDimitry Andric bool SelectSVECpyDupImm(SDValue N, SDValue &Imm, SDValue &Shift) { 26381ad6265SDimitry Andric return SelectSVECpyDupImm(N, VT, Imm, Shift); 26481ad6265SDimitry Andric } 26581ad6265SDimitry Andric 266fe6060f1SDimitry Andric template <MVT::SimpleValueType VT, bool Invert = false> 267480093f4SDimitry Andric bool SelectSVELogicalImm(SDValue N, SDValue &Imm) { 268fe6060f1SDimitry Andric return SelectSVELogicalImm(N, VT, Imm, Invert); 269480093f4SDimitry Andric } 270480093f4SDimitry Andric 271e8d8bef9SDimitry Andric template <MVT::SimpleValueType VT> 272e8d8bef9SDimitry Andric bool SelectSVEArithImm(SDValue N, SDValue &Imm) { 273e8d8bef9SDimitry Andric return SelectSVEArithImm(N, VT, Imm); 274e8d8bef9SDimitry Andric } 275e8d8bef9SDimitry Andric 276e8d8bef9SDimitry Andric template <unsigned Low, unsigned High, bool AllowSaturation = false> 277e8d8bef9SDimitry Andric bool SelectSVEShiftImm(SDValue N, SDValue &Imm) { 278e8d8bef9SDimitry Andric return SelectSVEShiftImm(N, Low, High, AllowSaturation, Imm); 2795ffd83dbSDimitry Andric } 2805ffd83dbSDimitry Andric 28181ad6265SDimitry Andric bool SelectSVEShiftSplatImmR(SDValue N, SDValue &Imm) { 28281ad6265SDimitry Andric if (N->getOpcode() != ISD::SPLAT_VECTOR) 28381ad6265SDimitry Andric return false; 28481ad6265SDimitry Andric 28581ad6265SDimitry Andric EVT EltVT = N->getValueType(0).getVectorElementType(); 28681ad6265SDimitry Andric return SelectSVEShiftImm(N->getOperand(0), /* Low */ 1, 28781ad6265SDimitry Andric /* High */ EltVT.getFixedSizeInBits(), 28881ad6265SDimitry Andric /* AllowSaturation */ true, Imm); 28981ad6265SDimitry Andric } 29081ad6265SDimitry Andric 291480093f4SDimitry Andric // Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N. 292480093f4SDimitry Andric template<signed Min, signed Max, signed Scale, bool Shift> 293480093f4SDimitry Andric bool SelectCntImm(SDValue N, SDValue &Imm) { 294480093f4SDimitry Andric if (!isa<ConstantSDNode>(N)) 295480093f4SDimitry Andric return false; 296480093f4SDimitry Andric 297480093f4SDimitry Andric int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue(); 298480093f4SDimitry Andric if (Shift) 299480093f4SDimitry Andric MulImm = 1LL << MulImm; 300480093f4SDimitry Andric 301480093f4SDimitry Andric if ((MulImm % std::abs(Scale)) != 0) 302480093f4SDimitry Andric return false; 303480093f4SDimitry Andric 304480093f4SDimitry Andric MulImm /= Scale; 305480093f4SDimitry Andric if ((MulImm >= Min) && (MulImm <= Max)) { 306480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(MulImm, SDLoc(N), MVT::i32); 307480093f4SDimitry Andric return true; 308480093f4SDimitry Andric } 309480093f4SDimitry Andric 310480093f4SDimitry Andric return false; 311480093f4SDimitry Andric } 3120b57cec5SDimitry Andric 313fe6060f1SDimitry Andric template <signed Max, signed Scale> 314fe6060f1SDimitry Andric bool SelectEXTImm(SDValue N, SDValue &Imm) { 315fe6060f1SDimitry Andric if (!isa<ConstantSDNode>(N)) 316fe6060f1SDimitry Andric return false; 317fe6060f1SDimitry Andric 318fe6060f1SDimitry Andric int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue(); 319fe6060f1SDimitry Andric 320fe6060f1SDimitry Andric if (MulImm >= 0 && MulImm <= Max) { 321fe6060f1SDimitry Andric MulImm *= Scale; 322fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(MulImm, SDLoc(N), MVT::i32); 323fe6060f1SDimitry Andric return true; 324fe6060f1SDimitry Andric } 325fe6060f1SDimitry Andric 326fe6060f1SDimitry Andric return false; 327fe6060f1SDimitry Andric } 328fe6060f1SDimitry Andric 329*5f757f3fSDimitry Andric template <unsigned BaseReg, unsigned Max> 330*5f757f3fSDimitry Andric bool ImmToReg(SDValue N, SDValue &Imm) { 33181ad6265SDimitry Andric if (auto *CI = dyn_cast<ConstantSDNode>(N)) { 33281ad6265SDimitry Andric uint64_t C = CI->getZExtValue(); 333*5f757f3fSDimitry Andric 334*5f757f3fSDimitry Andric if (C > Max) 335*5f757f3fSDimitry Andric return false; 336*5f757f3fSDimitry Andric 33781ad6265SDimitry Andric Imm = CurDAG->getRegister(BaseReg + C, MVT::Other); 33881ad6265SDimitry Andric return true; 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric return false; 34181ad6265SDimitry Andric } 34281ad6265SDimitry Andric 3430b57cec5SDimitry Andric /// Form sequences of consecutive 64/128-bit registers for use in NEON 3440b57cec5SDimitry Andric /// instructions making use of a vector-list (e.g. ldN, tbl). Vecs must have 3450b57cec5SDimitry Andric /// between 1 and 4 elements. If it contains a single element that is returned 3460b57cec5SDimitry Andric /// unchanged; otherwise a REG_SEQUENCE value is returned. 3470b57cec5SDimitry Andric SDValue createDTuple(ArrayRef<SDValue> Vecs); 3480b57cec5SDimitry Andric SDValue createQTuple(ArrayRef<SDValue> Vecs); 3495ffd83dbSDimitry Andric // Form a sequence of SVE registers for instructions using list of vectors, 3505ffd83dbSDimitry Andric // e.g. structured loads and stores (ldN, stN). 3515ffd83dbSDimitry Andric SDValue createZTuple(ArrayRef<SDValue> Vecs); 3520b57cec5SDimitry Andric 35306c3fb27SDimitry Andric // Similar to above, except the register must start at a multiple of the 35406c3fb27SDimitry Andric // tuple, e.g. z2 for a 2-tuple, or z8 for a 4-tuple. 35506c3fb27SDimitry Andric SDValue createZMulTuple(ArrayRef<SDValue> Regs); 35606c3fb27SDimitry Andric 3570b57cec5SDimitry Andric /// Generic helper for the createDTuple/createQTuple 3580b57cec5SDimitry Andric /// functions. Those should almost always be called instead. 3590b57cec5SDimitry Andric SDValue createTuple(ArrayRef<SDValue> Vecs, const unsigned RegClassIDs[], 3600b57cec5SDimitry Andric const unsigned SubRegs[]); 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric void SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc, bool isExt); 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric bool tryIndexedLoad(SDNode *N); 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric bool trySelectStackSlotTagP(SDNode *N); 3670b57cec5SDimitry Andric void SelectTagP(SDNode *N); 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric void SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc, 3700b57cec5SDimitry Andric unsigned SubRegIdx); 3710b57cec5SDimitry Andric void SelectPostLoad(SDNode *N, unsigned NumVecs, unsigned Opc, 3720b57cec5SDimitry Andric unsigned SubRegIdx); 3730b57cec5SDimitry Andric void SelectLoadLane(SDNode *N, unsigned NumVecs, unsigned Opc); 3740b57cec5SDimitry Andric void SelectPostLoadLane(SDNode *N, unsigned NumVecs, unsigned Opc); 375979e22ffSDimitry Andric void SelectPredicatedLoad(SDNode *N, unsigned NumVecs, unsigned Scale, 376349cc55cSDimitry Andric unsigned Opc_rr, unsigned Opc_ri, 377349cc55cSDimitry Andric bool IsIntr = false); 37806c3fb27SDimitry Andric void SelectContiguousMultiVectorLoad(SDNode *N, unsigned NumVecs, 37906c3fb27SDimitry Andric unsigned Scale, unsigned Opc_ri, 38006c3fb27SDimitry Andric unsigned Opc_rr); 38106c3fb27SDimitry Andric void SelectDestructiveMultiIntrinsic(SDNode *N, unsigned NumVecs, 38206c3fb27SDimitry Andric bool IsZmMulti, unsigned Opcode, 38306c3fb27SDimitry Andric bool HasPred = false); 38406c3fb27SDimitry Andric void SelectPExtPair(SDNode *N, unsigned Opc); 385bdd1243dSDimitry Andric void SelectWhilePair(SDNode *N, unsigned Opc); 386bdd1243dSDimitry Andric void SelectCVTIntrinsic(SDNode *N, unsigned NumVecs, unsigned Opcode); 38706c3fb27SDimitry Andric void SelectClamp(SDNode *N, unsigned NumVecs, unsigned Opcode); 38806c3fb27SDimitry Andric void SelectUnaryMultiIntrinsic(SDNode *N, unsigned NumOutVecs, 38906c3fb27SDimitry Andric bool IsTupleInput, unsigned Opc); 39006c3fb27SDimitry Andric void SelectFrintFromVT(SDNode *N, unsigned NumVecs, unsigned Opcode); 39106c3fb27SDimitry Andric 39206c3fb27SDimitry Andric template <unsigned MaxIdx, unsigned Scale> 39306c3fb27SDimitry Andric void SelectMultiVectorMove(SDNode *N, unsigned NumVecs, unsigned BaseReg, 39406c3fb27SDimitry Andric unsigned Op); 3955ffd83dbSDimitry Andric 3965ffd83dbSDimitry Andric bool SelectAddrModeFrameIndexSVE(SDValue N, SDValue &Base, SDValue &OffImm); 3975ffd83dbSDimitry Andric /// SVE Reg+Imm addressing mode. 3985ffd83dbSDimitry Andric template <int64_t Min, int64_t Max> 3995ffd83dbSDimitry Andric bool SelectAddrModeIndexedSVE(SDNode *Root, SDValue N, SDValue &Base, 4005ffd83dbSDimitry Andric SDValue &OffImm); 4015ffd83dbSDimitry Andric /// SVE Reg+Reg address mode. 4025ffd83dbSDimitry Andric template <unsigned Scale> 4035ffd83dbSDimitry Andric bool SelectSVERegRegAddrMode(SDValue N, SDValue &Base, SDValue &Offset) { 4045ffd83dbSDimitry Andric return SelectSVERegRegAddrMode(N, Scale, Base, Offset); 4055ffd83dbSDimitry Andric } 4060b57cec5SDimitry Andric 407*5f757f3fSDimitry Andric void SelectMultiVectorLuti(SDNode *Node, unsigned NumOutVecs, unsigned Opc, 408*5f757f3fSDimitry Andric uint32_t MaxImm); 409*5f757f3fSDimitry Andric 410bdd1243dSDimitry Andric template <unsigned MaxIdx, unsigned Scale> 41181ad6265SDimitry Andric bool SelectSMETileSlice(SDValue N, SDValue &Vector, SDValue &Offset) { 412bdd1243dSDimitry Andric return SelectSMETileSlice(N, MaxIdx, Vector, Offset, Scale); 41381ad6265SDimitry Andric } 41481ad6265SDimitry Andric 4150b57cec5SDimitry Andric void SelectStore(SDNode *N, unsigned NumVecs, unsigned Opc); 4160b57cec5SDimitry Andric void SelectPostStore(SDNode *N, unsigned NumVecs, unsigned Opc); 4170b57cec5SDimitry Andric void SelectStoreLane(SDNode *N, unsigned NumVecs, unsigned Opc); 4180b57cec5SDimitry Andric void SelectPostStoreLane(SDNode *N, unsigned NumVecs, unsigned Opc); 419979e22ffSDimitry Andric void SelectPredicatedStore(SDNode *N, unsigned NumVecs, unsigned Scale, 420979e22ffSDimitry Andric unsigned Opc_rr, unsigned Opc_ri); 4215ffd83dbSDimitry Andric std::tuple<unsigned, SDValue, SDValue> 422979e22ffSDimitry Andric findAddrModeSVELoadStore(SDNode *N, unsigned Opc_rr, unsigned Opc_ri, 423979e22ffSDimitry Andric const SDValue &OldBase, const SDValue &OldOffset, 424979e22ffSDimitry Andric unsigned Scale); 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric bool tryBitfieldExtractOp(SDNode *N); 4270b57cec5SDimitry Andric bool tryBitfieldExtractOpFromSExt(SDNode *N); 4280b57cec5SDimitry Andric bool tryBitfieldInsertOp(SDNode *N); 4290b57cec5SDimitry Andric bool tryBitfieldInsertInZeroOp(SDNode *N); 4300b57cec5SDimitry Andric bool tryShiftAmountMod(SDNode *N); 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric bool tryReadRegister(SDNode *N); 4330b57cec5SDimitry Andric bool tryWriteRegister(SDNode *N); 4340b57cec5SDimitry Andric 43506c3fb27SDimitry Andric bool trySelectCastFixedLengthToScalableVector(SDNode *N); 43606c3fb27SDimitry Andric bool trySelectCastScalableToFixedLengthVector(SDNode *N); 43706c3fb27SDimitry Andric 438*5f757f3fSDimitry Andric bool trySelectXAR(SDNode *N); 439*5f757f3fSDimitry Andric 4400b57cec5SDimitry Andric // Include the pieces autogenerated from the target description. 4410b57cec5SDimitry Andric #include "AArch64GenDAGISel.inc" 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric private: 4440b57cec5SDimitry Andric bool SelectShiftedRegister(SDValue N, bool AllowROR, SDValue &Reg, 4450b57cec5SDimitry Andric SDValue &Shift); 446bdd1243dSDimitry Andric bool SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg, SDValue &Shift); 4470b57cec5SDimitry Andric bool SelectAddrModeIndexed7S(SDValue N, unsigned Size, SDValue &Base, 4480b57cec5SDimitry Andric SDValue &OffImm) { 4490b57cec5SDimitry Andric return SelectAddrModeIndexedBitWidth(N, true, 7, Size, Base, OffImm); 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric bool SelectAddrModeIndexedBitWidth(SDValue N, bool IsSignedImm, unsigned BW, 4520b57cec5SDimitry Andric unsigned Size, SDValue &Base, 4530b57cec5SDimitry Andric SDValue &OffImm); 4540b57cec5SDimitry Andric bool SelectAddrModeIndexed(SDValue N, unsigned Size, SDValue &Base, 4550b57cec5SDimitry Andric SDValue &OffImm); 4560b57cec5SDimitry Andric bool SelectAddrModeUnscaled(SDValue N, unsigned Size, SDValue &Base, 4570b57cec5SDimitry Andric SDValue &OffImm); 4580b57cec5SDimitry Andric bool SelectAddrModeWRO(SDValue N, unsigned Size, SDValue &Base, 4590b57cec5SDimitry Andric SDValue &Offset, SDValue &SignExtend, 4600b57cec5SDimitry Andric SDValue &DoShift); 4610b57cec5SDimitry Andric bool SelectAddrModeXRO(SDValue N, unsigned Size, SDValue &Base, 4620b57cec5SDimitry Andric SDValue &Offset, SDValue &SignExtend, 4630b57cec5SDimitry Andric SDValue &DoShift); 464*5f757f3fSDimitry Andric bool isWorthFoldingALU(SDValue V, bool LSL = false) const; 465*5f757f3fSDimitry Andric bool isWorthFoldingAddr(SDValue V) const; 4660b57cec5SDimitry Andric bool SelectExtendedSHL(SDValue N, unsigned Size, bool WantExtend, 4670b57cec5SDimitry Andric SDValue &Offset, SDValue &SignExtend); 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric template<unsigned RegWidth> 4700b57cec5SDimitry Andric bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos) { 4710b57cec5SDimitry Andric return SelectCVTFixedPosOperand(N, FixedPos, RegWidth); 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, unsigned Width); 4750b57cec5SDimitry Andric 476*5f757f3fSDimitry Andric template<unsigned RegWidth> 477*5f757f3fSDimitry Andric bool SelectCVTFixedPosRecipOperand(SDValue N, SDValue &FixedPos) { 478*5f757f3fSDimitry Andric return SelectCVTFixedPosRecipOperand(N, FixedPos, RegWidth); 479*5f757f3fSDimitry Andric } 480*5f757f3fSDimitry Andric 481*5f757f3fSDimitry Andric bool SelectCVTFixedPosRecipOperand(SDValue N, SDValue &FixedPos, 482*5f757f3fSDimitry Andric unsigned Width); 483*5f757f3fSDimitry Andric 4840b57cec5SDimitry Andric bool SelectCMP_SWAP(SDNode *N); 4850b57cec5SDimitry Andric 486480093f4SDimitry Andric bool SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift); 48781ad6265SDimitry Andric bool SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift); 488fe6060f1SDimitry Andric bool SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm, bool Invert); 489480093f4SDimitry Andric 490480093f4SDimitry Andric bool SelectSVESignedArithImm(SDValue N, SDValue &Imm); 491e8d8bef9SDimitry Andric bool SelectSVEShiftImm(SDValue N, uint64_t Low, uint64_t High, 492e8d8bef9SDimitry Andric bool AllowSaturation, SDValue &Imm); 493480093f4SDimitry Andric 494e8d8bef9SDimitry Andric bool SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm); 4955ffd83dbSDimitry Andric bool SelectSVERegRegAddrMode(SDValue N, unsigned Scale, SDValue &Base, 4965ffd83dbSDimitry Andric SDValue &Offset); 497bdd1243dSDimitry Andric bool SelectSMETileSlice(SDValue N, unsigned MaxSize, SDValue &Vector, 498bdd1243dSDimitry Andric SDValue &Offset, unsigned Scale = 1); 499fe6060f1SDimitry Andric 500fe6060f1SDimitry Andric bool SelectAllActivePredicate(SDValue N); 50106c3fb27SDimitry Andric bool SelectAnyPredicate(SDValue N); 5020b57cec5SDimitry Andric }; 5030b57cec5SDimitry Andric } // end anonymous namespace 5040b57cec5SDimitry Andric 505bdd1243dSDimitry Andric char AArch64DAGToDAGISel::ID = 0; 506bdd1243dSDimitry Andric 507bdd1243dSDimitry Andric INITIALIZE_PASS(AArch64DAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 508bdd1243dSDimitry Andric 5090b57cec5SDimitry Andric /// isIntImmediate - This method tests to see if the node is a constant 5100b57cec5SDimitry Andric /// operand. If so Imm will receive the 32-bit value. 5110b57cec5SDimitry Andric static bool isIntImmediate(const SDNode *N, uint64_t &Imm) { 5120b57cec5SDimitry Andric if (const ConstantSDNode *C = dyn_cast<const ConstantSDNode>(N)) { 5130b57cec5SDimitry Andric Imm = C->getZExtValue(); 5140b57cec5SDimitry Andric return true; 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric return false; 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric // isIntImmediate - This method tests to see if a constant operand. 5200b57cec5SDimitry Andric // If so Imm will receive the value. 5210b57cec5SDimitry Andric static bool isIntImmediate(SDValue N, uint64_t &Imm) { 5220b57cec5SDimitry Andric return isIntImmediate(N.getNode(), Imm); 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric // isOpcWithIntImmediate - This method tests to see if the node is a specific 5260b57cec5SDimitry Andric // opcode and that it has a immediate integer right operand. 5270b57cec5SDimitry Andric // If so Imm will receive the 32 bit value. 5280b57cec5SDimitry Andric static bool isOpcWithIntImmediate(const SDNode *N, unsigned Opc, 5290b57cec5SDimitry Andric uint64_t &Imm) { 5300b57cec5SDimitry Andric return N->getOpcode() == Opc && 5310b57cec5SDimitry Andric isIntImmediate(N->getOperand(1).getNode(), Imm); 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric 534bdd1243dSDimitry Andric // isIntImmediateEq - This method tests to see if N is a constant operand that 535bdd1243dSDimitry Andric // is equivalent to 'ImmExpected'. 536bdd1243dSDimitry Andric #ifndef NDEBUG 537bdd1243dSDimitry Andric static bool isIntImmediateEq(SDValue N, const uint64_t ImmExpected) { 538bdd1243dSDimitry Andric uint64_t Imm; 539bdd1243dSDimitry Andric if (!isIntImmediate(N.getNode(), Imm)) 540bdd1243dSDimitry Andric return false; 541bdd1243dSDimitry Andric return Imm == ImmExpected; 542bdd1243dSDimitry Andric } 543bdd1243dSDimitry Andric #endif 544bdd1243dSDimitry Andric 5450b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectInlineAsmMemoryOperand( 546*5f757f3fSDimitry Andric const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID, 547*5f757f3fSDimitry Andric std::vector<SDValue> &OutOps) { 5480b57cec5SDimitry Andric switch(ConstraintID) { 5490b57cec5SDimitry Andric default: 5500b57cec5SDimitry Andric llvm_unreachable("Unexpected asm memory constraint"); 551*5f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: 552*5f757f3fSDimitry Andric case InlineAsm::ConstraintCode::o: 553*5f757f3fSDimitry Andric case InlineAsm::ConstraintCode::Q: 5540b57cec5SDimitry Andric // We need to make sure that this one operand does not end up in XZR, thus 5550b57cec5SDimitry Andric // require the address to be in a PointerRegClass register. 5560b57cec5SDimitry Andric const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); 5570b57cec5SDimitry Andric const TargetRegisterClass *TRC = TRI->getPointerRegClass(*MF); 5580b57cec5SDimitry Andric SDLoc dl(Op); 5590b57cec5SDimitry Andric SDValue RC = CurDAG->getTargetConstant(TRC->getID(), dl, MVT::i64); 5600b57cec5SDimitry Andric SDValue NewOp = 5610b57cec5SDimitry Andric SDValue(CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 5620b57cec5SDimitry Andric dl, Op.getValueType(), 5630b57cec5SDimitry Andric Op, RC), 0); 5640b57cec5SDimitry Andric OutOps.push_back(NewOp); 5650b57cec5SDimitry Andric return false; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric return true; 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric /// SelectArithImmed - Select an immediate value that can be represented as 5710b57cec5SDimitry Andric /// a 12-bit value shifted left by either 0 or 12. If so, return true with 5720b57cec5SDimitry Andric /// Val set to the 12-bit value and Shift set to the shifter operand. 5730b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectArithImmed(SDValue N, SDValue &Val, 5740b57cec5SDimitry Andric SDValue &Shift) { 5750b57cec5SDimitry Andric // This function is called from the addsub_shifted_imm ComplexPattern, 5760b57cec5SDimitry Andric // which lists [imm] as the list of opcode it's interested in, however 5770b57cec5SDimitry Andric // we still need to check whether the operand is actually an immediate 5780b57cec5SDimitry Andric // here because the ComplexPattern opcode list is only used in 5790b57cec5SDimitry Andric // root-level opcode matching. 5800b57cec5SDimitry Andric if (!isa<ConstantSDNode>(N.getNode())) 5810b57cec5SDimitry Andric return false; 5820b57cec5SDimitry Andric 5830b57cec5SDimitry Andric uint64_t Immed = cast<ConstantSDNode>(N.getNode())->getZExtValue(); 5840b57cec5SDimitry Andric unsigned ShiftAmt; 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric if (Immed >> 12 == 0) { 5870b57cec5SDimitry Andric ShiftAmt = 0; 5880b57cec5SDimitry Andric } else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) { 5890b57cec5SDimitry Andric ShiftAmt = 12; 5900b57cec5SDimitry Andric Immed = Immed >> 12; 5910b57cec5SDimitry Andric } else 5920b57cec5SDimitry Andric return false; 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt); 5950b57cec5SDimitry Andric SDLoc dl(N); 5960b57cec5SDimitry Andric Val = CurDAG->getTargetConstant(Immed, dl, MVT::i32); 5970b57cec5SDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, dl, MVT::i32); 5980b57cec5SDimitry Andric return true; 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric /// SelectNegArithImmed - As above, but negates the value before trying to 6020b57cec5SDimitry Andric /// select it. 6030b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectNegArithImmed(SDValue N, SDValue &Val, 6040b57cec5SDimitry Andric SDValue &Shift) { 6050b57cec5SDimitry Andric // This function is called from the addsub_shifted_imm ComplexPattern, 6060b57cec5SDimitry Andric // which lists [imm] as the list of opcode it's interested in, however 6070b57cec5SDimitry Andric // we still need to check whether the operand is actually an immediate 6080b57cec5SDimitry Andric // here because the ComplexPattern opcode list is only used in 6090b57cec5SDimitry Andric // root-level opcode matching. 6100b57cec5SDimitry Andric if (!isa<ConstantSDNode>(N.getNode())) 6110b57cec5SDimitry Andric return false; 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric // The immediate operand must be a 24-bit zero-extended immediate. 6140b57cec5SDimitry Andric uint64_t Immed = cast<ConstantSDNode>(N.getNode())->getZExtValue(); 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // This negation is almost always valid, but "cmp wN, #0" and "cmn wN, #0" 6170b57cec5SDimitry Andric // have the opposite effect on the C flag, so this pattern mustn't match under 6180b57cec5SDimitry Andric // those circumstances. 6190b57cec5SDimitry Andric if (Immed == 0) 6200b57cec5SDimitry Andric return false; 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric if (N.getValueType() == MVT::i32) 6230b57cec5SDimitry Andric Immed = ~((uint32_t)Immed) + 1; 6240b57cec5SDimitry Andric else 6250b57cec5SDimitry Andric Immed = ~Immed + 1ULL; 6260b57cec5SDimitry Andric if (Immed & 0xFFFFFFFFFF000000ULL) 6270b57cec5SDimitry Andric return false; 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric Immed &= 0xFFFFFFULL; 6300b57cec5SDimitry Andric return SelectArithImmed(CurDAG->getConstant(Immed, SDLoc(N), MVT::i32), Val, 6310b57cec5SDimitry Andric Shift); 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric /// getShiftTypeForNode - Translate a shift node to the corresponding 6350b57cec5SDimitry Andric /// ShiftType value. 6360b57cec5SDimitry Andric static AArch64_AM::ShiftExtendType getShiftTypeForNode(SDValue N) { 6370b57cec5SDimitry Andric switch (N.getOpcode()) { 6380b57cec5SDimitry Andric default: 6390b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 6400b57cec5SDimitry Andric case ISD::SHL: 6410b57cec5SDimitry Andric return AArch64_AM::LSL; 6420b57cec5SDimitry Andric case ISD::SRL: 6430b57cec5SDimitry Andric return AArch64_AM::LSR; 6440b57cec5SDimitry Andric case ISD::SRA: 6450b57cec5SDimitry Andric return AArch64_AM::ASR; 6460b57cec5SDimitry Andric case ISD::ROTR: 6470b57cec5SDimitry Andric return AArch64_AM::ROR; 6480b57cec5SDimitry Andric } 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric /// Determine whether it is worth it to fold SHL into the addressing 6520b57cec5SDimitry Andric /// mode. 6530b57cec5SDimitry Andric static bool isWorthFoldingSHL(SDValue V) { 6540b57cec5SDimitry Andric assert(V.getOpcode() == ISD::SHL && "invalid opcode"); 6550b57cec5SDimitry Andric // It is worth folding logical shift of up to three places. 6560b57cec5SDimitry Andric auto *CSD = dyn_cast<ConstantSDNode>(V.getOperand(1)); 6570b57cec5SDimitry Andric if (!CSD) 6580b57cec5SDimitry Andric return false; 6590b57cec5SDimitry Andric unsigned ShiftVal = CSD->getZExtValue(); 6600b57cec5SDimitry Andric if (ShiftVal > 3) 6610b57cec5SDimitry Andric return false; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric // Check if this particular node is reused in any non-memory related 6640b57cec5SDimitry Andric // operation. If yes, do not try to fold this node into the address 6650b57cec5SDimitry Andric // computation, since the computation will be kept. 6660b57cec5SDimitry Andric const SDNode *Node = V.getNode(); 6670b57cec5SDimitry Andric for (SDNode *UI : Node->uses()) 6680b57cec5SDimitry Andric if (!isa<MemSDNode>(*UI)) 6690b57cec5SDimitry Andric for (SDNode *UII : UI->uses()) 6700b57cec5SDimitry Andric if (!isa<MemSDNode>(*UII)) 6710b57cec5SDimitry Andric return false; 6720b57cec5SDimitry Andric return true; 6730b57cec5SDimitry Andric } 6740b57cec5SDimitry Andric 675*5f757f3fSDimitry Andric /// Determine whether it is worth to fold V into an extended register addressing 676*5f757f3fSDimitry Andric /// mode. 677*5f757f3fSDimitry Andric bool AArch64DAGToDAGISel::isWorthFoldingAddr(SDValue V) const { 6780b57cec5SDimitry Andric // Trivial if we are optimizing for code size or if there is only 6790b57cec5SDimitry Andric // one use of the value. 680480093f4SDimitry Andric if (CurDAG->shouldOptForSize() || V.hasOneUse()) 6810b57cec5SDimitry Andric return true; 6820b57cec5SDimitry Andric // If a subtarget has a fastpath LSL we can fold a logical shift into 6830b57cec5SDimitry Andric // the addressing mode and save a cycle. 684*5f757f3fSDimitry Andric if (Subtarget->hasAddrLSLFast() && V.getOpcode() == ISD::SHL && 6850b57cec5SDimitry Andric isWorthFoldingSHL(V)) 6860b57cec5SDimitry Andric return true; 687*5f757f3fSDimitry Andric if (Subtarget->hasAddrLSLFast() && V.getOpcode() == ISD::ADD) { 6880b57cec5SDimitry Andric const SDValue LHS = V.getOperand(0); 6890b57cec5SDimitry Andric const SDValue RHS = V.getOperand(1); 6900b57cec5SDimitry Andric if (LHS.getOpcode() == ISD::SHL && isWorthFoldingSHL(LHS)) 6910b57cec5SDimitry Andric return true; 6920b57cec5SDimitry Andric if (RHS.getOpcode() == ISD::SHL && isWorthFoldingSHL(RHS)) 6930b57cec5SDimitry Andric return true; 6940b57cec5SDimitry Andric } 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric // It hurts otherwise, since the value will be reused. 6970b57cec5SDimitry Andric return false; 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 700bdd1243dSDimitry Andric /// and (shl/srl/sra, x, c), mask --> shl (srl/sra, x, c1), c2 701bdd1243dSDimitry Andric /// to select more shifted register 702bdd1243dSDimitry Andric bool AArch64DAGToDAGISel::SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg, 703bdd1243dSDimitry Andric SDValue &Shift) { 704bdd1243dSDimitry Andric EVT VT = N.getValueType(); 705bdd1243dSDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 706bdd1243dSDimitry Andric return false; 707bdd1243dSDimitry Andric 708bdd1243dSDimitry Andric if (N->getOpcode() != ISD::AND || !N->hasOneUse()) 709bdd1243dSDimitry Andric return false; 710bdd1243dSDimitry Andric SDValue LHS = N.getOperand(0); 711bdd1243dSDimitry Andric if (!LHS->hasOneUse()) 712bdd1243dSDimitry Andric return false; 713bdd1243dSDimitry Andric 714bdd1243dSDimitry Andric unsigned LHSOpcode = LHS->getOpcode(); 715bdd1243dSDimitry Andric if (LHSOpcode != ISD::SHL && LHSOpcode != ISD::SRL && LHSOpcode != ISD::SRA) 716bdd1243dSDimitry Andric return false; 717bdd1243dSDimitry Andric 718bdd1243dSDimitry Andric ConstantSDNode *ShiftAmtNode = dyn_cast<ConstantSDNode>(LHS.getOperand(1)); 719bdd1243dSDimitry Andric if (!ShiftAmtNode) 720bdd1243dSDimitry Andric return false; 721bdd1243dSDimitry Andric 722bdd1243dSDimitry Andric uint64_t ShiftAmtC = ShiftAmtNode->getZExtValue(); 723bdd1243dSDimitry Andric ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(N.getOperand(1)); 724bdd1243dSDimitry Andric if (!RHSC) 725bdd1243dSDimitry Andric return false; 726bdd1243dSDimitry Andric 727bdd1243dSDimitry Andric APInt AndMask = RHSC->getAPIntValue(); 728bdd1243dSDimitry Andric unsigned LowZBits, MaskLen; 729bdd1243dSDimitry Andric if (!AndMask.isShiftedMask(LowZBits, MaskLen)) 730bdd1243dSDimitry Andric return false; 731bdd1243dSDimitry Andric 732bdd1243dSDimitry Andric unsigned BitWidth = N.getValueSizeInBits(); 733bdd1243dSDimitry Andric SDLoc DL(LHS); 734bdd1243dSDimitry Andric uint64_t NewShiftC; 735bdd1243dSDimitry Andric unsigned NewShiftOp; 736bdd1243dSDimitry Andric if (LHSOpcode == ISD::SHL) { 737bdd1243dSDimitry Andric // LowZBits <= ShiftAmtC will fall into isBitfieldPositioningOp 738bdd1243dSDimitry Andric // BitWidth != LowZBits + MaskLen doesn't match the pattern 739bdd1243dSDimitry Andric if (LowZBits <= ShiftAmtC || (BitWidth != LowZBits + MaskLen)) 740bdd1243dSDimitry Andric return false; 741bdd1243dSDimitry Andric 742bdd1243dSDimitry Andric NewShiftC = LowZBits - ShiftAmtC; 743bdd1243dSDimitry Andric NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri; 744bdd1243dSDimitry Andric } else { 745bdd1243dSDimitry Andric if (LowZBits == 0) 746bdd1243dSDimitry Andric return false; 747bdd1243dSDimitry Andric 748bdd1243dSDimitry Andric // NewShiftC >= BitWidth will fall into isBitfieldExtractOp 749bdd1243dSDimitry Andric NewShiftC = LowZBits + ShiftAmtC; 750bdd1243dSDimitry Andric if (NewShiftC >= BitWidth) 751bdd1243dSDimitry Andric return false; 752bdd1243dSDimitry Andric 753bdd1243dSDimitry Andric // SRA need all high bits 754bdd1243dSDimitry Andric if (LHSOpcode == ISD::SRA && (BitWidth != (LowZBits + MaskLen))) 755bdd1243dSDimitry Andric return false; 756bdd1243dSDimitry Andric 757bdd1243dSDimitry Andric // SRL high bits can be 0 or 1 758bdd1243dSDimitry Andric if (LHSOpcode == ISD::SRL && (BitWidth > (NewShiftC + MaskLen))) 759bdd1243dSDimitry Andric return false; 760bdd1243dSDimitry Andric 761bdd1243dSDimitry Andric if (LHSOpcode == ISD::SRL) 762bdd1243dSDimitry Andric NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri; 763bdd1243dSDimitry Andric else 764bdd1243dSDimitry Andric NewShiftOp = VT == MVT::i64 ? AArch64::SBFMXri : AArch64::SBFMWri; 765bdd1243dSDimitry Andric } 766bdd1243dSDimitry Andric 767bdd1243dSDimitry Andric assert(NewShiftC < BitWidth && "Invalid shift amount"); 768bdd1243dSDimitry Andric SDValue NewShiftAmt = CurDAG->getTargetConstant(NewShiftC, DL, VT); 769bdd1243dSDimitry Andric SDValue BitWidthMinus1 = CurDAG->getTargetConstant(BitWidth - 1, DL, VT); 770bdd1243dSDimitry Andric Reg = SDValue(CurDAG->getMachineNode(NewShiftOp, DL, VT, LHS->getOperand(0), 771bdd1243dSDimitry Andric NewShiftAmt, BitWidthMinus1), 772bdd1243dSDimitry Andric 0); 773bdd1243dSDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, LowZBits); 774bdd1243dSDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, DL, MVT::i32); 775bdd1243dSDimitry Andric return true; 776bdd1243dSDimitry Andric } 777bdd1243dSDimitry Andric 7780b57cec5SDimitry Andric /// getExtendTypeForNode - Translate an extend node to the corresponding 7790b57cec5SDimitry Andric /// ExtendType value. 7800b57cec5SDimitry Andric static AArch64_AM::ShiftExtendType 7810b57cec5SDimitry Andric getExtendTypeForNode(SDValue N, bool IsLoadStore = false) { 7820b57cec5SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND || 7830b57cec5SDimitry Andric N.getOpcode() == ISD::SIGN_EXTEND_INREG) { 7840b57cec5SDimitry Andric EVT SrcVT; 7850b57cec5SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG) 7860b57cec5SDimitry Andric SrcVT = cast<VTSDNode>(N.getOperand(1))->getVT(); 7870b57cec5SDimitry Andric else 7880b57cec5SDimitry Andric SrcVT = N.getOperand(0).getValueType(); 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric if (!IsLoadStore && SrcVT == MVT::i8) 7910b57cec5SDimitry Andric return AArch64_AM::SXTB; 7920b57cec5SDimitry Andric else if (!IsLoadStore && SrcVT == MVT::i16) 7930b57cec5SDimitry Andric return AArch64_AM::SXTH; 7940b57cec5SDimitry Andric else if (SrcVT == MVT::i32) 7950b57cec5SDimitry Andric return AArch64_AM::SXTW; 7960b57cec5SDimitry Andric assert(SrcVT != MVT::i64 && "extend from 64-bits?"); 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 7990b57cec5SDimitry Andric } else if (N.getOpcode() == ISD::ZERO_EXTEND || 8000b57cec5SDimitry Andric N.getOpcode() == ISD::ANY_EXTEND) { 8010b57cec5SDimitry Andric EVT SrcVT = N.getOperand(0).getValueType(); 8020b57cec5SDimitry Andric if (!IsLoadStore && SrcVT == MVT::i8) 8030b57cec5SDimitry Andric return AArch64_AM::UXTB; 8040b57cec5SDimitry Andric else if (!IsLoadStore && SrcVT == MVT::i16) 8050b57cec5SDimitry Andric return AArch64_AM::UXTH; 8060b57cec5SDimitry Andric else if (SrcVT == MVT::i32) 8070b57cec5SDimitry Andric return AArch64_AM::UXTW; 8080b57cec5SDimitry Andric assert(SrcVT != MVT::i64 && "extend from 64-bits?"); 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 8110b57cec5SDimitry Andric } else if (N.getOpcode() == ISD::AND) { 8120b57cec5SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 8130b57cec5SDimitry Andric if (!CSD) 8140b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 8150b57cec5SDimitry Andric uint64_t AndMask = CSD->getZExtValue(); 8160b57cec5SDimitry Andric 8170b57cec5SDimitry Andric switch (AndMask) { 8180b57cec5SDimitry Andric default: 8190b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 8200b57cec5SDimitry Andric case 0xFF: 8210b57cec5SDimitry Andric return !IsLoadStore ? AArch64_AM::UXTB : AArch64_AM::InvalidShiftExtend; 8220b57cec5SDimitry Andric case 0xFFFF: 8230b57cec5SDimitry Andric return !IsLoadStore ? AArch64_AM::UXTH : AArch64_AM::InvalidShiftExtend; 8240b57cec5SDimitry Andric case 0xFFFFFFFF: 8250b57cec5SDimitry Andric return AArch64_AM::UXTW; 8260b57cec5SDimitry Andric } 8270b57cec5SDimitry Andric } 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 8300b57cec5SDimitry Andric } 8310b57cec5SDimitry Andric 832*5f757f3fSDimitry Andric /// Determine whether it is worth to fold V into an extended register of an 833*5f757f3fSDimitry Andric /// Add/Sub. LSL means we are folding into an `add w0, w1, w2, lsl #N` 834*5f757f3fSDimitry Andric /// instruction, and the shift should be treated as worth folding even if has 835*5f757f3fSDimitry Andric /// multiple uses. 836*5f757f3fSDimitry Andric bool AArch64DAGToDAGISel::isWorthFoldingALU(SDValue V, bool LSL) const { 837*5f757f3fSDimitry Andric // Trivial if we are optimizing for code size or if there is only 838*5f757f3fSDimitry Andric // one use of the value. 839*5f757f3fSDimitry Andric if (CurDAG->shouldOptForSize() || V.hasOneUse()) 840*5f757f3fSDimitry Andric return true; 841*5f757f3fSDimitry Andric 842*5f757f3fSDimitry Andric // If a subtarget has a fastpath LSL we can fold a logical shift into 843*5f757f3fSDimitry Andric // the add/sub and save a cycle. 844*5f757f3fSDimitry Andric if (LSL && Subtarget->hasALULSLFast() && V.getOpcode() == ISD::SHL && 845*5f757f3fSDimitry Andric V.getConstantOperandVal(1) <= 4 && 846*5f757f3fSDimitry Andric getExtendTypeForNode(V.getOperand(0)) == AArch64_AM::InvalidShiftExtend) 847*5f757f3fSDimitry Andric return true; 848*5f757f3fSDimitry Andric 849*5f757f3fSDimitry Andric // It hurts otherwise, since the value will be reused. 850*5f757f3fSDimitry Andric return false; 851*5f757f3fSDimitry Andric } 852*5f757f3fSDimitry Andric 853*5f757f3fSDimitry Andric /// SelectShiftedRegister - Select a "shifted register" operand. If the value 854*5f757f3fSDimitry Andric /// is not shifted, set the Shift operand to default of "LSL 0". The logical 855*5f757f3fSDimitry Andric /// instructions allow the shifted register to be rotated, but the arithmetic 856*5f757f3fSDimitry Andric /// instructions do not. The AllowROR parameter specifies whether ROR is 857*5f757f3fSDimitry Andric /// supported. 858*5f757f3fSDimitry Andric bool AArch64DAGToDAGISel::SelectShiftedRegister(SDValue N, bool AllowROR, 859*5f757f3fSDimitry Andric SDValue &Reg, SDValue &Shift) { 860*5f757f3fSDimitry Andric if (SelectShiftedRegisterFromAnd(N, Reg, Shift)) 861*5f757f3fSDimitry Andric return true; 862*5f757f3fSDimitry Andric 863*5f757f3fSDimitry Andric AArch64_AM::ShiftExtendType ShType = getShiftTypeForNode(N); 864*5f757f3fSDimitry Andric if (ShType == AArch64_AM::InvalidShiftExtend) 865*5f757f3fSDimitry Andric return false; 866*5f757f3fSDimitry Andric if (!AllowROR && ShType == AArch64_AM::ROR) 867*5f757f3fSDimitry Andric return false; 868*5f757f3fSDimitry Andric 869*5f757f3fSDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 870*5f757f3fSDimitry Andric unsigned BitSize = N.getValueSizeInBits(); 871*5f757f3fSDimitry Andric unsigned Val = RHS->getZExtValue() & (BitSize - 1); 872*5f757f3fSDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(ShType, Val); 873*5f757f3fSDimitry Andric 874*5f757f3fSDimitry Andric Reg = N.getOperand(0); 875*5f757f3fSDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, SDLoc(N), MVT::i32); 876*5f757f3fSDimitry Andric return isWorthFoldingALU(N, true); 877*5f757f3fSDimitry Andric } 878*5f757f3fSDimitry Andric 879*5f757f3fSDimitry Andric return false; 880*5f757f3fSDimitry Andric } 881*5f757f3fSDimitry Andric 8820b57cec5SDimitry Andric /// Instructions that accept extend modifiers like UXTW expect the register 8830b57cec5SDimitry Andric /// being extended to be a GPR32, but the incoming DAG might be acting on a 8840b57cec5SDimitry Andric /// GPR64 (either via SEXT_INREG or AND). Extract the appropriate low bits if 8850b57cec5SDimitry Andric /// this is the case. 8860b57cec5SDimitry Andric static SDValue narrowIfNeeded(SelectionDAG *CurDAG, SDValue N) { 8870b57cec5SDimitry Andric if (N.getValueType() == MVT::i32) 8880b57cec5SDimitry Andric return N; 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric SDLoc dl(N); 89106c3fb27SDimitry Andric return CurDAG->getTargetExtractSubreg(AArch64::sub_32, dl, MVT::i32, N); 8920b57cec5SDimitry Andric } 8930b57cec5SDimitry Andric 8945ffd83dbSDimitry Andric // Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N. 8955ffd83dbSDimitry Andric template<signed Low, signed High, signed Scale> 8965ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectRDVLImm(SDValue N, SDValue &Imm) { 8975ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(N)) 8985ffd83dbSDimitry Andric return false; 8995ffd83dbSDimitry Andric 9005ffd83dbSDimitry Andric int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue(); 9015ffd83dbSDimitry Andric if ((MulImm % std::abs(Scale)) == 0) { 9025ffd83dbSDimitry Andric int64_t RDVLImm = MulImm / Scale; 9035ffd83dbSDimitry Andric if ((RDVLImm >= Low) && (RDVLImm <= High)) { 9045ffd83dbSDimitry Andric Imm = CurDAG->getTargetConstant(RDVLImm, SDLoc(N), MVT::i32); 9055ffd83dbSDimitry Andric return true; 9065ffd83dbSDimitry Andric } 9075ffd83dbSDimitry Andric } 9085ffd83dbSDimitry Andric 9095ffd83dbSDimitry Andric return false; 9105ffd83dbSDimitry Andric } 9110b57cec5SDimitry Andric 9120b57cec5SDimitry Andric /// SelectArithExtendedRegister - Select a "extended register" operand. This 9130b57cec5SDimitry Andric /// operand folds in an extend followed by an optional left shift. 9140b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectArithExtendedRegister(SDValue N, SDValue &Reg, 9150b57cec5SDimitry Andric SDValue &Shift) { 9160b57cec5SDimitry Andric unsigned ShiftVal = 0; 9170b57cec5SDimitry Andric AArch64_AM::ShiftExtendType Ext; 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric if (N.getOpcode() == ISD::SHL) { 9200b57cec5SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 9210b57cec5SDimitry Andric if (!CSD) 9220b57cec5SDimitry Andric return false; 9230b57cec5SDimitry Andric ShiftVal = CSD->getZExtValue(); 9240b57cec5SDimitry Andric if (ShiftVal > 4) 9250b57cec5SDimitry Andric return false; 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric Ext = getExtendTypeForNode(N.getOperand(0)); 9280b57cec5SDimitry Andric if (Ext == AArch64_AM::InvalidShiftExtend) 9290b57cec5SDimitry Andric return false; 9300b57cec5SDimitry Andric 9310b57cec5SDimitry Andric Reg = N.getOperand(0).getOperand(0); 9320b57cec5SDimitry Andric } else { 9330b57cec5SDimitry Andric Ext = getExtendTypeForNode(N); 9340b57cec5SDimitry Andric if (Ext == AArch64_AM::InvalidShiftExtend) 9350b57cec5SDimitry Andric return false; 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric Reg = N.getOperand(0); 9380b57cec5SDimitry Andric 93981ad6265SDimitry Andric // Don't match if free 32-bit -> 64-bit zext can be used instead. Use the 94081ad6265SDimitry Andric // isDef32 as a heuristic for when the operand is likely to be a 32bit def. 94181ad6265SDimitry Andric auto isDef32 = [](SDValue N) { 94281ad6265SDimitry Andric unsigned Opc = N.getOpcode(); 94381ad6265SDimitry Andric return Opc != ISD::TRUNCATE && Opc != TargetOpcode::EXTRACT_SUBREG && 94481ad6265SDimitry Andric Opc != ISD::CopyFromReg && Opc != ISD::AssertSext && 94581ad6265SDimitry Andric Opc != ISD::AssertZext && Opc != ISD::AssertAlign && 94681ad6265SDimitry Andric Opc != ISD::FREEZE; 94781ad6265SDimitry Andric }; 94881ad6265SDimitry Andric if (Ext == AArch64_AM::UXTW && Reg->getValueType(0).getSizeInBits() == 32 && 94981ad6265SDimitry Andric isDef32(Reg)) 9500b57cec5SDimitry Andric return false; 9510b57cec5SDimitry Andric } 9520b57cec5SDimitry Andric 9530b57cec5SDimitry Andric // AArch64 mandates that the RHS of the operation must use the smallest 9540b57cec5SDimitry Andric // register class that could contain the size being extended from. Thus, 9550b57cec5SDimitry Andric // if we're folding a (sext i8), we need the RHS to be a GPR32, even though 9560b57cec5SDimitry Andric // there might not be an actual 32-bit value in the program. We can 9570b57cec5SDimitry Andric // (harmlessly) synthesize one by injected an EXTRACT_SUBREG here. 9580b57cec5SDimitry Andric assert(Ext != AArch64_AM::UXTX && Ext != AArch64_AM::SXTX); 9590b57cec5SDimitry Andric Reg = narrowIfNeeded(CurDAG, Reg); 9600b57cec5SDimitry Andric Shift = CurDAG->getTargetConstant(getArithExtendImm(Ext, ShiftVal), SDLoc(N), 9610b57cec5SDimitry Andric MVT::i32); 962*5f757f3fSDimitry Andric return isWorthFoldingALU(N); 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric 965fcaf7f86SDimitry Andric /// SelectArithUXTXRegister - Select a "UXTX register" operand. This 966fcaf7f86SDimitry Andric /// operand is refered by the instructions have SP operand 967fcaf7f86SDimitry Andric bool AArch64DAGToDAGISel::SelectArithUXTXRegister(SDValue N, SDValue &Reg, 968fcaf7f86SDimitry Andric SDValue &Shift) { 969fcaf7f86SDimitry Andric unsigned ShiftVal = 0; 970fcaf7f86SDimitry Andric AArch64_AM::ShiftExtendType Ext; 971fcaf7f86SDimitry Andric 972fcaf7f86SDimitry Andric if (N.getOpcode() != ISD::SHL) 973fcaf7f86SDimitry Andric return false; 974fcaf7f86SDimitry Andric 975fcaf7f86SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 976fcaf7f86SDimitry Andric if (!CSD) 977fcaf7f86SDimitry Andric return false; 978fcaf7f86SDimitry Andric ShiftVal = CSD->getZExtValue(); 979fcaf7f86SDimitry Andric if (ShiftVal > 4) 980fcaf7f86SDimitry Andric return false; 981fcaf7f86SDimitry Andric 982fcaf7f86SDimitry Andric Ext = AArch64_AM::UXTX; 983fcaf7f86SDimitry Andric Reg = N.getOperand(0); 984fcaf7f86SDimitry Andric Shift = CurDAG->getTargetConstant(getArithExtendImm(Ext, ShiftVal), SDLoc(N), 985fcaf7f86SDimitry Andric MVT::i32); 986*5f757f3fSDimitry Andric return isWorthFoldingALU(N); 987fcaf7f86SDimitry Andric } 988fcaf7f86SDimitry Andric 9890b57cec5SDimitry Andric /// If there's a use of this ADDlow that's not itself a load/store then we'll 9900b57cec5SDimitry Andric /// need to create a real ADD instruction from it anyway and there's no point in 9910b57cec5SDimitry Andric /// folding it into the mem op. Theoretically, it shouldn't matter, but there's 9920b57cec5SDimitry Andric /// a single pseudo-instruction for an ADRP/ADD pair so over-aggressive folding 9930b57cec5SDimitry Andric /// leads to duplicated ADRP instructions. 9940b57cec5SDimitry Andric static bool isWorthFoldingADDlow(SDValue N) { 995bdd1243dSDimitry Andric for (auto *Use : N->uses()) { 9960b57cec5SDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 9970b57cec5SDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 9980b57cec5SDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 9990b57cec5SDimitry Andric return false; 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric // ldar and stlr have much more restrictive addressing modes (just a 10020b57cec5SDimitry Andric // register). 1003fe6060f1SDimitry Andric if (isStrongerThanMonotonic(cast<MemSDNode>(Use)->getSuccessOrdering())) 10040b57cec5SDimitry Andric return false; 10050b57cec5SDimitry Andric } 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric return true; 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric 1010*5f757f3fSDimitry Andric /// Check if the immediate offset is valid as a scaled immediate. 1011*5f757f3fSDimitry Andric static bool isValidAsScaledImmediate(int64_t Offset, unsigned Range, 1012*5f757f3fSDimitry Andric unsigned Size) { 1013*5f757f3fSDimitry Andric if ((Offset & (Size - 1)) == 0 && Offset >= 0 && 1014*5f757f3fSDimitry Andric Offset < (Range << Log2_32(Size))) 1015*5f757f3fSDimitry Andric return true; 1016*5f757f3fSDimitry Andric return false; 1017*5f757f3fSDimitry Andric } 1018*5f757f3fSDimitry Andric 10190b57cec5SDimitry Andric /// SelectAddrModeIndexedBitWidth - Select a "register plus scaled (un)signed BW-bit 10200b57cec5SDimitry Andric /// immediate" address. The "Size" argument is the size in bytes of the memory 10210b57cec5SDimitry Andric /// reference, which determines the scale. 10220b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexedBitWidth(SDValue N, bool IsSignedImm, 10230b57cec5SDimitry Andric unsigned BW, unsigned Size, 10240b57cec5SDimitry Andric SDValue &Base, 10250b57cec5SDimitry Andric SDValue &OffImm) { 10260b57cec5SDimitry Andric SDLoc dl(N); 10270b57cec5SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 10280b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 10290b57cec5SDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 10300b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 10310b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 10320b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 10330b57cec5SDimitry Andric return true; 10340b57cec5SDimitry Andric } 10350b57cec5SDimitry Andric 10360b57cec5SDimitry Andric // As opposed to the (12-bit) Indexed addressing mode below, the 7/9-bit signed 10370b57cec5SDimitry Andric // selected here doesn't support labels/immediates, only base+offset. 10380b57cec5SDimitry Andric if (CurDAG->isBaseWithConstantOffset(N)) { 10390b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 10400b57cec5SDimitry Andric if (IsSignedImm) { 10410b57cec5SDimitry Andric int64_t RHSC = RHS->getSExtValue(); 10420b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 10430b57cec5SDimitry Andric int64_t Range = 0x1LL << (BW - 1); 10440b57cec5SDimitry Andric 10450b57cec5SDimitry Andric if ((RHSC & (Size - 1)) == 0 && RHSC >= -(Range << Scale) && 10460b57cec5SDimitry Andric RHSC < (Range << Scale)) { 10470b57cec5SDimitry Andric Base = N.getOperand(0); 10480b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 10490b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 10500b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 10510b57cec5SDimitry Andric } 10520b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64); 10530b57cec5SDimitry Andric return true; 10540b57cec5SDimitry Andric } 10550b57cec5SDimitry Andric } else { 10560b57cec5SDimitry Andric // unsigned Immediate 10570b57cec5SDimitry Andric uint64_t RHSC = RHS->getZExtValue(); 10580b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 10590b57cec5SDimitry Andric uint64_t Range = 0x1ULL << BW; 10600b57cec5SDimitry Andric 10610b57cec5SDimitry Andric if ((RHSC & (Size - 1)) == 0 && RHSC < (Range << Scale)) { 10620b57cec5SDimitry Andric Base = N.getOperand(0); 10630b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 10640b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 10650b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 10660b57cec5SDimitry Andric } 10670b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64); 10680b57cec5SDimitry Andric return true; 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric } 10720b57cec5SDimitry Andric } 10730b57cec5SDimitry Andric // Base only. The address will be materialized into a register before 10740b57cec5SDimitry Andric // the memory is accessed. 10750b57cec5SDimitry Andric // add x0, Xbase, #offset 10760b57cec5SDimitry Andric // stp x1, x2, [x0] 10770b57cec5SDimitry Andric Base = N; 10780b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 10790b57cec5SDimitry Andric return true; 10800b57cec5SDimitry Andric } 10810b57cec5SDimitry Andric 10820b57cec5SDimitry Andric /// SelectAddrModeIndexed - Select a "register plus scaled unsigned 12-bit 10830b57cec5SDimitry Andric /// immediate" address. The "Size" argument is the size in bytes of the memory 10840b57cec5SDimitry Andric /// reference, which determines the scale. 10850b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexed(SDValue N, unsigned Size, 10860b57cec5SDimitry Andric SDValue &Base, SDValue &OffImm) { 10870b57cec5SDimitry Andric SDLoc dl(N); 10880b57cec5SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 10890b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 10900b57cec5SDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 10910b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 10920b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 10930b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 10940b57cec5SDimitry Andric return true; 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric if (N.getOpcode() == AArch64ISD::ADDlow && isWorthFoldingADDlow(N)) { 10980b57cec5SDimitry Andric GlobalAddressSDNode *GAN = 10990b57cec5SDimitry Andric dyn_cast<GlobalAddressSDNode>(N.getOperand(1).getNode()); 11000b57cec5SDimitry Andric Base = N.getOperand(0); 11010b57cec5SDimitry Andric OffImm = N.getOperand(1); 11020b57cec5SDimitry Andric if (!GAN) 11030b57cec5SDimitry Andric return true; 11040b57cec5SDimitry Andric 11055ffd83dbSDimitry Andric if (GAN->getOffset() % Size == 0 && 11065ffd83dbSDimitry Andric GAN->getGlobal()->getPointerAlignment(DL) >= Size) 11070b57cec5SDimitry Andric return true; 11080b57cec5SDimitry Andric } 11090b57cec5SDimitry Andric 11100b57cec5SDimitry Andric if (CurDAG->isBaseWithConstantOffset(N)) { 11110b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 11120b57cec5SDimitry Andric int64_t RHSC = (int64_t)RHS->getZExtValue(); 11130b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 1114*5f757f3fSDimitry Andric if (isValidAsScaledImmediate(RHSC, 0x1000, Size)) { 11150b57cec5SDimitry Andric Base = N.getOperand(0); 11160b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 11170b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 11180b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 11190b57cec5SDimitry Andric } 11200b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64); 11210b57cec5SDimitry Andric return true; 11220b57cec5SDimitry Andric } 11230b57cec5SDimitry Andric } 11240b57cec5SDimitry Andric } 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric // Before falling back to our general case, check if the unscaled 11270b57cec5SDimitry Andric // instructions can handle this. If so, that's preferable. 11280b57cec5SDimitry Andric if (SelectAddrModeUnscaled(N, Size, Base, OffImm)) 11290b57cec5SDimitry Andric return false; 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric // Base only. The address will be materialized into a register before 11320b57cec5SDimitry Andric // the memory is accessed. 11330b57cec5SDimitry Andric // add x0, Xbase, #offset 11340b57cec5SDimitry Andric // ldr x0, [x0] 11350b57cec5SDimitry Andric Base = N; 11360b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 11370b57cec5SDimitry Andric return true; 11380b57cec5SDimitry Andric } 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric /// SelectAddrModeUnscaled - Select a "register plus unscaled signed 9-bit 11410b57cec5SDimitry Andric /// immediate" address. This should only match when there is an offset that 11420b57cec5SDimitry Andric /// is not valid for a scaled immediate addressing mode. The "Size" argument 11430b57cec5SDimitry Andric /// is the size in bytes of the memory reference, which is needed here to know 11440b57cec5SDimitry Andric /// what is valid for a scaled immediate. 11450b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeUnscaled(SDValue N, unsigned Size, 11460b57cec5SDimitry Andric SDValue &Base, 11470b57cec5SDimitry Andric SDValue &OffImm) { 11480b57cec5SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(N)) 11490b57cec5SDimitry Andric return false; 11500b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 11510b57cec5SDimitry Andric int64_t RHSC = RHS->getSExtValue(); 11520b57cec5SDimitry Andric if (RHSC >= -256 && RHSC < 256) { 11530b57cec5SDimitry Andric Base = N.getOperand(0); 11540b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 11550b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 11560b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 11570b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex( 11580b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 11590b57cec5SDimitry Andric } 11600b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i64); 11610b57cec5SDimitry Andric return true; 11620b57cec5SDimitry Andric } 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric return false; 11650b57cec5SDimitry Andric } 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric static SDValue Widen(SelectionDAG *CurDAG, SDValue N) { 11680b57cec5SDimitry Andric SDLoc dl(N); 11690b57cec5SDimitry Andric SDValue ImpDef = SDValue( 11700b57cec5SDimitry Andric CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::i64), 0); 117106c3fb27SDimitry Andric return CurDAG->getTargetInsertSubreg(AArch64::sub_32, dl, MVT::i64, ImpDef, 117206c3fb27SDimitry Andric N); 11730b57cec5SDimitry Andric } 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric /// Check if the given SHL node (\p N), can be used to form an 11760b57cec5SDimitry Andric /// extended register for an addressing mode. 11770b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectExtendedSHL(SDValue N, unsigned Size, 11780b57cec5SDimitry Andric bool WantExtend, SDValue &Offset, 11790b57cec5SDimitry Andric SDValue &SignExtend) { 11800b57cec5SDimitry Andric assert(N.getOpcode() == ISD::SHL && "Invalid opcode."); 11810b57cec5SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 11820b57cec5SDimitry Andric if (!CSD || (CSD->getZExtValue() & 0x7) != CSD->getZExtValue()) 11830b57cec5SDimitry Andric return false; 11840b57cec5SDimitry Andric 11850b57cec5SDimitry Andric SDLoc dl(N); 11860b57cec5SDimitry Andric if (WantExtend) { 11870b57cec5SDimitry Andric AArch64_AM::ShiftExtendType Ext = 11880b57cec5SDimitry Andric getExtendTypeForNode(N.getOperand(0), true); 11890b57cec5SDimitry Andric if (Ext == AArch64_AM::InvalidShiftExtend) 11900b57cec5SDimitry Andric return false; 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric Offset = narrowIfNeeded(CurDAG, N.getOperand(0).getOperand(0)); 11930b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl, 11940b57cec5SDimitry Andric MVT::i32); 11950b57cec5SDimitry Andric } else { 11960b57cec5SDimitry Andric Offset = N.getOperand(0); 11970b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(0, dl, MVT::i32); 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric 12000b57cec5SDimitry Andric unsigned LegalShiftVal = Log2_32(Size); 12010b57cec5SDimitry Andric unsigned ShiftVal = CSD->getZExtValue(); 12020b57cec5SDimitry Andric 12030b57cec5SDimitry Andric if (ShiftVal != 0 && ShiftVal != LegalShiftVal) 12040b57cec5SDimitry Andric return false; 12050b57cec5SDimitry Andric 1206*5f757f3fSDimitry Andric return isWorthFoldingAddr(N); 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeWRO(SDValue N, unsigned Size, 12100b57cec5SDimitry Andric SDValue &Base, SDValue &Offset, 12110b57cec5SDimitry Andric SDValue &SignExtend, 12120b57cec5SDimitry Andric SDValue &DoShift) { 12130b57cec5SDimitry Andric if (N.getOpcode() != ISD::ADD) 12140b57cec5SDimitry Andric return false; 12150b57cec5SDimitry Andric SDValue LHS = N.getOperand(0); 12160b57cec5SDimitry Andric SDValue RHS = N.getOperand(1); 12170b57cec5SDimitry Andric SDLoc dl(N); 12180b57cec5SDimitry Andric 12190b57cec5SDimitry Andric // We don't want to match immediate adds here, because they are better lowered 12200b57cec5SDimitry Andric // to the register-immediate addressing modes. 12210b57cec5SDimitry Andric if (isa<ConstantSDNode>(LHS) || isa<ConstantSDNode>(RHS)) 12220b57cec5SDimitry Andric return false; 12230b57cec5SDimitry Andric 12240b57cec5SDimitry Andric // Check if this particular node is reused in any non-memory related 12250b57cec5SDimitry Andric // operation. If yes, do not try to fold this node into the address 12260b57cec5SDimitry Andric // computation, since the computation will be kept. 12270b57cec5SDimitry Andric const SDNode *Node = N.getNode(); 12280b57cec5SDimitry Andric for (SDNode *UI : Node->uses()) { 12290b57cec5SDimitry Andric if (!isa<MemSDNode>(*UI)) 12300b57cec5SDimitry Andric return false; 12310b57cec5SDimitry Andric } 12320b57cec5SDimitry Andric 12330b57cec5SDimitry Andric // Remember if it is worth folding N when it produces extended register. 1234*5f757f3fSDimitry Andric bool IsExtendedRegisterWorthFolding = isWorthFoldingAddr(N); 12350b57cec5SDimitry Andric 12360b57cec5SDimitry Andric // Try to match a shifted extend on the RHS. 12370b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && RHS.getOpcode() == ISD::SHL && 12380b57cec5SDimitry Andric SelectExtendedSHL(RHS, Size, true, Offset, SignExtend)) { 12390b57cec5SDimitry Andric Base = LHS; 12400b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, dl, MVT::i32); 12410b57cec5SDimitry Andric return true; 12420b57cec5SDimitry Andric } 12430b57cec5SDimitry Andric 12440b57cec5SDimitry Andric // Try to match a shifted extend on the LHS. 12450b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && LHS.getOpcode() == ISD::SHL && 12460b57cec5SDimitry Andric SelectExtendedSHL(LHS, Size, true, Offset, SignExtend)) { 12470b57cec5SDimitry Andric Base = RHS; 12480b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, dl, MVT::i32); 12490b57cec5SDimitry Andric return true; 12500b57cec5SDimitry Andric } 12510b57cec5SDimitry Andric 12520b57cec5SDimitry Andric // There was no shift, whatever else we find. 12530b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(false, dl, MVT::i32); 12540b57cec5SDimitry Andric 12550b57cec5SDimitry Andric AArch64_AM::ShiftExtendType Ext = AArch64_AM::InvalidShiftExtend; 12560b57cec5SDimitry Andric // Try to match an unshifted extend on the LHS. 12570b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && 12580b57cec5SDimitry Andric (Ext = getExtendTypeForNode(LHS, true)) != 12590b57cec5SDimitry Andric AArch64_AM::InvalidShiftExtend) { 12600b57cec5SDimitry Andric Base = RHS; 12610b57cec5SDimitry Andric Offset = narrowIfNeeded(CurDAG, LHS.getOperand(0)); 12620b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl, 12630b57cec5SDimitry Andric MVT::i32); 1264*5f757f3fSDimitry Andric if (isWorthFoldingAddr(LHS)) 12650b57cec5SDimitry Andric return true; 12660b57cec5SDimitry Andric } 12670b57cec5SDimitry Andric 12680b57cec5SDimitry Andric // Try to match an unshifted extend on the RHS. 12690b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && 12700b57cec5SDimitry Andric (Ext = getExtendTypeForNode(RHS, true)) != 12710b57cec5SDimitry Andric AArch64_AM::InvalidShiftExtend) { 12720b57cec5SDimitry Andric Base = LHS; 12730b57cec5SDimitry Andric Offset = narrowIfNeeded(CurDAG, RHS.getOperand(0)); 12740b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl, 12750b57cec5SDimitry Andric MVT::i32); 1276*5f757f3fSDimitry Andric if (isWorthFoldingAddr(RHS)) 12770b57cec5SDimitry Andric return true; 12780b57cec5SDimitry Andric } 12790b57cec5SDimitry Andric 12800b57cec5SDimitry Andric return false; 12810b57cec5SDimitry Andric } 12820b57cec5SDimitry Andric 12830b57cec5SDimitry Andric // Check if the given immediate is preferred by ADD. If an immediate can be 12840b57cec5SDimitry Andric // encoded in an ADD, or it can be encoded in an "ADD LSL #12" and can not be 12850b57cec5SDimitry Andric // encoded by one MOVZ, return true. 12860b57cec5SDimitry Andric static bool isPreferredADD(int64_t ImmOff) { 12870b57cec5SDimitry Andric // Constant in [0x0, 0xfff] can be encoded in ADD. 12880b57cec5SDimitry Andric if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL) 12890b57cec5SDimitry Andric return true; 12900b57cec5SDimitry Andric // Check if it can be encoded in an "ADD LSL #12". 12910b57cec5SDimitry Andric if ((ImmOff & 0xffffffffff000fffLL) == 0x0LL) 12920b57cec5SDimitry Andric // As a single MOVZ is faster than a "ADD of LSL #12", ignore such constant. 12930b57cec5SDimitry Andric return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL && 12940b57cec5SDimitry Andric (ImmOff & 0xffffffffffff0fffLL) != 0x0LL; 12950b57cec5SDimitry Andric return false; 12960b57cec5SDimitry Andric } 12970b57cec5SDimitry Andric 12980b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeXRO(SDValue N, unsigned Size, 12990b57cec5SDimitry Andric SDValue &Base, SDValue &Offset, 13000b57cec5SDimitry Andric SDValue &SignExtend, 13010b57cec5SDimitry Andric SDValue &DoShift) { 13020b57cec5SDimitry Andric if (N.getOpcode() != ISD::ADD) 13030b57cec5SDimitry Andric return false; 13040b57cec5SDimitry Andric SDValue LHS = N.getOperand(0); 13050b57cec5SDimitry Andric SDValue RHS = N.getOperand(1); 13060b57cec5SDimitry Andric SDLoc DL(N); 13070b57cec5SDimitry Andric 13080b57cec5SDimitry Andric // Check if this particular node is reused in any non-memory related 13090b57cec5SDimitry Andric // operation. If yes, do not try to fold this node into the address 13100b57cec5SDimitry Andric // computation, since the computation will be kept. 13110b57cec5SDimitry Andric const SDNode *Node = N.getNode(); 13120b57cec5SDimitry Andric for (SDNode *UI : Node->uses()) { 13130b57cec5SDimitry Andric if (!isa<MemSDNode>(*UI)) 13140b57cec5SDimitry Andric return false; 13150b57cec5SDimitry Andric } 13160b57cec5SDimitry Andric 13170b57cec5SDimitry Andric // Watch out if RHS is a wide immediate, it can not be selected into 13180b57cec5SDimitry Andric // [BaseReg+Imm] addressing mode. Also it may not be able to be encoded into 13190b57cec5SDimitry Andric // ADD/SUB. Instead it will use [BaseReg + 0] address mode and generate 13200b57cec5SDimitry Andric // instructions like: 13210b57cec5SDimitry Andric // MOV X0, WideImmediate 13220b57cec5SDimitry Andric // ADD X1, BaseReg, X0 13230b57cec5SDimitry Andric // LDR X2, [X1, 0] 13240b57cec5SDimitry Andric // For such situation, using [BaseReg, XReg] addressing mode can save one 13250b57cec5SDimitry Andric // ADD/SUB: 13260b57cec5SDimitry Andric // MOV X0, WideImmediate 13270b57cec5SDimitry Andric // LDR X2, [BaseReg, X0] 13280b57cec5SDimitry Andric if (isa<ConstantSDNode>(RHS)) { 13290b57cec5SDimitry Andric int64_t ImmOff = (int64_t)cast<ConstantSDNode>(RHS)->getZExtValue(); 13300b57cec5SDimitry Andric // Skip the immediate can be selected by load/store addressing mode. 13310b57cec5SDimitry Andric // Also skip the immediate can be encoded by a single ADD (SUB is also 13320b57cec5SDimitry Andric // checked by using -ImmOff). 1333*5f757f3fSDimitry Andric if (isValidAsScaledImmediate(ImmOff, 0x1000, Size) || 13340b57cec5SDimitry Andric isPreferredADD(ImmOff) || isPreferredADD(-ImmOff)) 13350b57cec5SDimitry Andric return false; 13360b57cec5SDimitry Andric 13370b57cec5SDimitry Andric SDValue Ops[] = { RHS }; 13380b57cec5SDimitry Andric SDNode *MOVI = 13390b57cec5SDimitry Andric CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops); 13400b57cec5SDimitry Andric SDValue MOVIV = SDValue(MOVI, 0); 13410b57cec5SDimitry Andric // This ADD of two X register will be selected into [Reg+Reg] mode. 13420b57cec5SDimitry Andric N = CurDAG->getNode(ISD::ADD, DL, MVT::i64, LHS, MOVIV); 13430b57cec5SDimitry Andric } 13440b57cec5SDimitry Andric 13450b57cec5SDimitry Andric // Remember if it is worth folding N when it produces extended register. 1346*5f757f3fSDimitry Andric bool IsExtendedRegisterWorthFolding = isWorthFoldingAddr(N); 13470b57cec5SDimitry Andric 13480b57cec5SDimitry Andric // Try to match a shifted extend on the RHS. 13490b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && RHS.getOpcode() == ISD::SHL && 13500b57cec5SDimitry Andric SelectExtendedSHL(RHS, Size, false, Offset, SignExtend)) { 13510b57cec5SDimitry Andric Base = LHS; 13520b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, DL, MVT::i32); 13530b57cec5SDimitry Andric return true; 13540b57cec5SDimitry Andric } 13550b57cec5SDimitry Andric 13560b57cec5SDimitry Andric // Try to match a shifted extend on the LHS. 13570b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && LHS.getOpcode() == ISD::SHL && 13580b57cec5SDimitry Andric SelectExtendedSHL(LHS, Size, false, Offset, SignExtend)) { 13590b57cec5SDimitry Andric Base = RHS; 13600b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, DL, MVT::i32); 13610b57cec5SDimitry Andric return true; 13620b57cec5SDimitry Andric } 13630b57cec5SDimitry Andric 13640b57cec5SDimitry Andric // Match any non-shifted, non-extend, non-immediate add expression. 13650b57cec5SDimitry Andric Base = LHS; 13660b57cec5SDimitry Andric Offset = RHS; 13670b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(false, DL, MVT::i32); 13680b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(false, DL, MVT::i32); 13690b57cec5SDimitry Andric // Reg1 + Reg2 is free: no check needed. 13700b57cec5SDimitry Andric return true; 13710b57cec5SDimitry Andric } 13720b57cec5SDimitry Andric 13730b57cec5SDimitry Andric SDValue AArch64DAGToDAGISel::createDTuple(ArrayRef<SDValue> Regs) { 13740b57cec5SDimitry Andric static const unsigned RegClassIDs[] = { 13750b57cec5SDimitry Andric AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID}; 13760b57cec5SDimitry Andric static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1, 13770b57cec5SDimitry Andric AArch64::dsub2, AArch64::dsub3}; 13780b57cec5SDimitry Andric 13790b57cec5SDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 13800b57cec5SDimitry Andric } 13810b57cec5SDimitry Andric 13820b57cec5SDimitry Andric SDValue AArch64DAGToDAGISel::createQTuple(ArrayRef<SDValue> Regs) { 13830b57cec5SDimitry Andric static const unsigned RegClassIDs[] = { 13840b57cec5SDimitry Andric AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID}; 13850b57cec5SDimitry Andric static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1, 13860b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3}; 13870b57cec5SDimitry Andric 13880b57cec5SDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 13890b57cec5SDimitry Andric } 13900b57cec5SDimitry Andric 13915ffd83dbSDimitry Andric SDValue AArch64DAGToDAGISel::createZTuple(ArrayRef<SDValue> Regs) { 13925ffd83dbSDimitry Andric static const unsigned RegClassIDs[] = {AArch64::ZPR2RegClassID, 13935ffd83dbSDimitry Andric AArch64::ZPR3RegClassID, 13945ffd83dbSDimitry Andric AArch64::ZPR4RegClassID}; 13955ffd83dbSDimitry Andric static const unsigned SubRegs[] = {AArch64::zsub0, AArch64::zsub1, 13965ffd83dbSDimitry Andric AArch64::zsub2, AArch64::zsub3}; 13975ffd83dbSDimitry Andric 13985ffd83dbSDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 13995ffd83dbSDimitry Andric } 14005ffd83dbSDimitry Andric 140106c3fb27SDimitry Andric SDValue AArch64DAGToDAGISel::createZMulTuple(ArrayRef<SDValue> Regs) { 140206c3fb27SDimitry Andric assert(Regs.size() == 2 || Regs.size() == 4); 140306c3fb27SDimitry Andric 140406c3fb27SDimitry Andric // The createTuple interface requires 3 RegClassIDs for each possible 140506c3fb27SDimitry Andric // tuple type even though we only have them for ZPR2 and ZPR4. 140606c3fb27SDimitry Andric static const unsigned RegClassIDs[] = {AArch64::ZPR2Mul2RegClassID, 0, 140706c3fb27SDimitry Andric AArch64::ZPR4Mul4RegClassID}; 140806c3fb27SDimitry Andric static const unsigned SubRegs[] = {AArch64::zsub0, AArch64::zsub1, 140906c3fb27SDimitry Andric AArch64::zsub2, AArch64::zsub3}; 141006c3fb27SDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 141106c3fb27SDimitry Andric } 141206c3fb27SDimitry Andric 14130b57cec5SDimitry Andric SDValue AArch64DAGToDAGISel::createTuple(ArrayRef<SDValue> Regs, 14140b57cec5SDimitry Andric const unsigned RegClassIDs[], 14150b57cec5SDimitry Andric const unsigned SubRegs[]) { 14160b57cec5SDimitry Andric // There's no special register-class for a vector-list of 1 element: it's just 14170b57cec5SDimitry Andric // a vector. 14180b57cec5SDimitry Andric if (Regs.size() == 1) 14190b57cec5SDimitry Andric return Regs[0]; 14200b57cec5SDimitry Andric 14210b57cec5SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 4); 14220b57cec5SDimitry Andric 14230b57cec5SDimitry Andric SDLoc DL(Regs[0]); 14240b57cec5SDimitry Andric 14250b57cec5SDimitry Andric SmallVector<SDValue, 4> Ops; 14260b57cec5SDimitry Andric 14270b57cec5SDimitry Andric // First operand of REG_SEQUENCE is the desired RegClass. 14280b57cec5SDimitry Andric Ops.push_back( 14290b57cec5SDimitry Andric CurDAG->getTargetConstant(RegClassIDs[Regs.size() - 2], DL, MVT::i32)); 14300b57cec5SDimitry Andric 14310b57cec5SDimitry Andric // Then we get pairs of source & subregister-position for the components. 14320b57cec5SDimitry Andric for (unsigned i = 0; i < Regs.size(); ++i) { 14330b57cec5SDimitry Andric Ops.push_back(Regs[i]); 14340b57cec5SDimitry Andric Ops.push_back(CurDAG->getTargetConstant(SubRegs[i], DL, MVT::i32)); 14350b57cec5SDimitry Andric } 14360b57cec5SDimitry Andric 14370b57cec5SDimitry Andric SDNode *N = 14380b57cec5SDimitry Andric CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 14390b57cec5SDimitry Andric return SDValue(N, 0); 14400b57cec5SDimitry Andric } 14410b57cec5SDimitry Andric 14420b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc, 14430b57cec5SDimitry Andric bool isExt) { 14440b57cec5SDimitry Andric SDLoc dl(N); 14450b57cec5SDimitry Andric EVT VT = N->getValueType(0); 14460b57cec5SDimitry Andric 14470b57cec5SDimitry Andric unsigned ExtOff = isExt; 14480b57cec5SDimitry Andric 14490b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 14500b57cec5SDimitry Andric unsigned Vec0Off = ExtOff + 1; 14510b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + Vec0Off, 14520b57cec5SDimitry Andric N->op_begin() + Vec0Off + NumVecs); 14530b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 14540b57cec5SDimitry Andric 14550b57cec5SDimitry Andric SmallVector<SDValue, 6> Ops; 14560b57cec5SDimitry Andric if (isExt) 14570b57cec5SDimitry Andric Ops.push_back(N->getOperand(1)); 14580b57cec5SDimitry Andric Ops.push_back(RegSeq); 14590b57cec5SDimitry Andric Ops.push_back(N->getOperand(NumVecs + ExtOff + 1)); 14600b57cec5SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops)); 14610b57cec5SDimitry Andric } 14620b57cec5SDimitry Andric 14630b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { 14640b57cec5SDimitry Andric LoadSDNode *LD = cast<LoadSDNode>(N); 14650b57cec5SDimitry Andric if (LD->isUnindexed()) 14660b57cec5SDimitry Andric return false; 14670b57cec5SDimitry Andric EVT VT = LD->getMemoryVT(); 14680b57cec5SDimitry Andric EVT DstVT = N->getValueType(0); 14690b57cec5SDimitry Andric ISD::MemIndexedMode AM = LD->getAddressingMode(); 14700b57cec5SDimitry Andric bool IsPre = AM == ISD::PRE_INC || AM == ISD::PRE_DEC; 14710b57cec5SDimitry Andric 14720b57cec5SDimitry Andric // We're not doing validity checking here. That was done when checking 14730b57cec5SDimitry Andric // if we should mark the load as indexed or not. We're just selecting 14740b57cec5SDimitry Andric // the right instruction. 14750b57cec5SDimitry Andric unsigned Opcode = 0; 14760b57cec5SDimitry Andric 14770b57cec5SDimitry Andric ISD::LoadExtType ExtType = LD->getExtensionType(); 14780b57cec5SDimitry Andric bool InsertTo64 = false; 14790b57cec5SDimitry Andric if (VT == MVT::i64) 14800b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRXpre : AArch64::LDRXpost; 14810b57cec5SDimitry Andric else if (VT == MVT::i32) { 14820b57cec5SDimitry Andric if (ExtType == ISD::NON_EXTLOAD) 14830b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost; 14840b57cec5SDimitry Andric else if (ExtType == ISD::SEXTLOAD) 14850b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost; 14860b57cec5SDimitry Andric else { 14870b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost; 14880b57cec5SDimitry Andric InsertTo64 = true; 14890b57cec5SDimitry Andric // The result of the load is only i32. It's the subreg_to_reg that makes 14900b57cec5SDimitry Andric // it into an i64. 14910b57cec5SDimitry Andric DstVT = MVT::i32; 14920b57cec5SDimitry Andric } 14930b57cec5SDimitry Andric } else if (VT == MVT::i16) { 14940b57cec5SDimitry Andric if (ExtType == ISD::SEXTLOAD) { 14950b57cec5SDimitry Andric if (DstVT == MVT::i64) 14960b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost; 14970b57cec5SDimitry Andric else 14980b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost; 14990b57cec5SDimitry Andric } else { 15000b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost; 15010b57cec5SDimitry Andric InsertTo64 = DstVT == MVT::i64; 15020b57cec5SDimitry Andric // The result of the load is only i32. It's the subreg_to_reg that makes 15030b57cec5SDimitry Andric // it into an i64. 15040b57cec5SDimitry Andric DstVT = MVT::i32; 15050b57cec5SDimitry Andric } 15060b57cec5SDimitry Andric } else if (VT == MVT::i8) { 15070b57cec5SDimitry Andric if (ExtType == ISD::SEXTLOAD) { 15080b57cec5SDimitry Andric if (DstVT == MVT::i64) 15090b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost; 15100b57cec5SDimitry Andric else 15110b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost; 15120b57cec5SDimitry Andric } else { 15130b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost; 15140b57cec5SDimitry Andric InsertTo64 = DstVT == MVT::i64; 15150b57cec5SDimitry Andric // The result of the load is only i32. It's the subreg_to_reg that makes 15160b57cec5SDimitry Andric // it into an i64. 15170b57cec5SDimitry Andric DstVT = MVT::i32; 15180b57cec5SDimitry Andric } 15190b57cec5SDimitry Andric } else if (VT == MVT::f16) { 15200b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost; 15215ffd83dbSDimitry Andric } else if (VT == MVT::bf16) { 15225ffd83dbSDimitry Andric Opcode = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost; 15230b57cec5SDimitry Andric } else if (VT == MVT::f32) { 15240b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost; 15250b57cec5SDimitry Andric } else if (VT == MVT::f64 || VT.is64BitVector()) { 15260b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRDpre : AArch64::LDRDpost; 15270b57cec5SDimitry Andric } else if (VT.is128BitVector()) { 15280b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRQpre : AArch64::LDRQpost; 15290b57cec5SDimitry Andric } else 15300b57cec5SDimitry Andric return false; 15310b57cec5SDimitry Andric SDValue Chain = LD->getChain(); 15320b57cec5SDimitry Andric SDValue Base = LD->getBasePtr(); 15330b57cec5SDimitry Andric ConstantSDNode *OffsetOp = cast<ConstantSDNode>(LD->getOffset()); 15340b57cec5SDimitry Andric int OffsetVal = (int)OffsetOp->getZExtValue(); 15350b57cec5SDimitry Andric SDLoc dl(N); 15360b57cec5SDimitry Andric SDValue Offset = CurDAG->getTargetConstant(OffsetVal, dl, MVT::i64); 15370b57cec5SDimitry Andric SDValue Ops[] = { Base, Offset, Chain }; 15380b57cec5SDimitry Andric SDNode *Res = CurDAG->getMachineNode(Opcode, dl, MVT::i64, DstVT, 15390b57cec5SDimitry Andric MVT::Other, Ops); 1540fe6060f1SDimitry Andric 1541fe6060f1SDimitry Andric // Transfer memoperands. 1542fe6060f1SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand(); 1543fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Res), {MemOp}); 1544fe6060f1SDimitry Andric 15450b57cec5SDimitry Andric // Either way, we're replacing the node, so tell the caller that. 15460b57cec5SDimitry Andric SDValue LoadedVal = SDValue(Res, 1); 15470b57cec5SDimitry Andric if (InsertTo64) { 15480b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, dl, MVT::i32); 15490b57cec5SDimitry Andric LoadedVal = 15500b57cec5SDimitry Andric SDValue(CurDAG->getMachineNode( 15510b57cec5SDimitry Andric AArch64::SUBREG_TO_REG, dl, MVT::i64, 15520b57cec5SDimitry Andric CurDAG->getTargetConstant(0, dl, MVT::i64), LoadedVal, 15530b57cec5SDimitry Andric SubReg), 15540b57cec5SDimitry Andric 0); 15550b57cec5SDimitry Andric } 15560b57cec5SDimitry Andric 15570b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), LoadedVal); 15580b57cec5SDimitry Andric ReplaceUses(SDValue(N, 1), SDValue(Res, 0)); 15590b57cec5SDimitry Andric ReplaceUses(SDValue(N, 2), SDValue(Res, 2)); 15600b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 15610b57cec5SDimitry Andric return true; 15620b57cec5SDimitry Andric } 15630b57cec5SDimitry Andric 15640b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc, 15650b57cec5SDimitry Andric unsigned SubRegIdx) { 15660b57cec5SDimitry Andric SDLoc dl(N); 15670b57cec5SDimitry Andric EVT VT = N->getValueType(0); 15680b57cec5SDimitry Andric SDValue Chain = N->getOperand(0); 15690b57cec5SDimitry Andric 15700b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(2), // Mem operand; 15710b57cec5SDimitry Andric Chain}; 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 15740b57cec5SDimitry Andric 15750b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 15760b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 0); 15770b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 15780b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), 15790b57cec5SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg)); 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1)); 15820b57cec5SDimitry Andric 1583e8d8bef9SDimitry Andric // Transfer memoperands. In the case of AArch64::LD64B, there won't be one, 1584e8d8bef9SDimitry Andric // because it's too simple to have needed special treatment during lowering. 1585e8d8bef9SDimitry Andric if (auto *MemIntr = dyn_cast<MemIntrinsicSDNode>(N)) { 1586e8d8bef9SDimitry Andric MachineMemOperand *MemOp = MemIntr->getMemOperand(); 15870b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp}); 1588e8d8bef9SDimitry Andric } 15890b57cec5SDimitry Andric 15900b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 15910b57cec5SDimitry Andric } 15920b57cec5SDimitry Andric 15930b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostLoad(SDNode *N, unsigned NumVecs, 15940b57cec5SDimitry Andric unsigned Opc, unsigned SubRegIdx) { 15950b57cec5SDimitry Andric SDLoc dl(N); 15960b57cec5SDimitry Andric EVT VT = N->getValueType(0); 15970b57cec5SDimitry Andric SDValue Chain = N->getOperand(0); 15980b57cec5SDimitry Andric 15990b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(1), // Mem operand 16000b57cec5SDimitry Andric N->getOperand(2), // Incremental 16010b57cec5SDimitry Andric Chain}; 16020b57cec5SDimitry Andric 16030b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 16040b57cec5SDimitry Andric MVT::Untyped, MVT::Other}; 16050b57cec5SDimitry Andric 16060b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 16070b57cec5SDimitry Andric 16080b57cec5SDimitry Andric // Update uses of write back register 16090b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0)); 16100b57cec5SDimitry Andric 16110b57cec5SDimitry Andric // Update uses of vector list 16120b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 1); 16130b57cec5SDimitry Andric if (NumVecs == 1) 16140b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), SuperReg); 16150b57cec5SDimitry Andric else 16160b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 16170b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), 16180b57cec5SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg)); 16190b57cec5SDimitry Andric 16200b57cec5SDimitry Andric // Update the chain 16210b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2)); 16220b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 16230b57cec5SDimitry Andric } 16240b57cec5SDimitry Andric 16255ffd83dbSDimitry Andric /// Optimize \param OldBase and \param OldOffset selecting the best addressing 16265ffd83dbSDimitry Andric /// mode. Returns a tuple consisting of an Opcode, an SDValue representing the 16275ffd83dbSDimitry Andric /// new Base and an SDValue representing the new offset. 16285ffd83dbSDimitry Andric std::tuple<unsigned, SDValue, SDValue> 1629979e22ffSDimitry Andric AArch64DAGToDAGISel::findAddrModeSVELoadStore(SDNode *N, unsigned Opc_rr, 1630979e22ffSDimitry Andric unsigned Opc_ri, 16315ffd83dbSDimitry Andric const SDValue &OldBase, 1632979e22ffSDimitry Andric const SDValue &OldOffset, 1633979e22ffSDimitry Andric unsigned Scale) { 16345ffd83dbSDimitry Andric SDValue NewBase = OldBase; 16355ffd83dbSDimitry Andric SDValue NewOffset = OldOffset; 16365ffd83dbSDimitry Andric // Detect a possible Reg+Imm addressing mode. 16375ffd83dbSDimitry Andric const bool IsRegImm = SelectAddrModeIndexedSVE</*Min=*/-8, /*Max=*/7>( 16385ffd83dbSDimitry Andric N, OldBase, NewBase, NewOffset); 16395ffd83dbSDimitry Andric 16405ffd83dbSDimitry Andric // Detect a possible reg+reg addressing mode, but only if we haven't already 16415ffd83dbSDimitry Andric // detected a Reg+Imm one. 16425ffd83dbSDimitry Andric const bool IsRegReg = 1643979e22ffSDimitry Andric !IsRegImm && SelectSVERegRegAddrMode(OldBase, Scale, NewBase, NewOffset); 16445ffd83dbSDimitry Andric 16455ffd83dbSDimitry Andric // Select the instruction. 16465ffd83dbSDimitry Andric return std::make_tuple(IsRegReg ? Opc_rr : Opc_ri, NewBase, NewOffset); 16475ffd83dbSDimitry Andric } 16485ffd83dbSDimitry Andric 1649bdd1243dSDimitry Andric enum class SelectTypeKind { 1650bdd1243dSDimitry Andric Int1 = 0, 165106c3fb27SDimitry Andric Int = 1, 165206c3fb27SDimitry Andric FP = 2, 165306c3fb27SDimitry Andric AnyType = 3, 1654bdd1243dSDimitry Andric }; 1655bdd1243dSDimitry Andric 1656bdd1243dSDimitry Andric /// This function selects an opcode from a list of opcodes, which is 1657bdd1243dSDimitry Andric /// expected to be the opcode for { 8-bit, 16-bit, 32-bit, 64-bit } 1658bdd1243dSDimitry Andric /// element types, in this order. 1659bdd1243dSDimitry Andric template <SelectTypeKind Kind> 1660bdd1243dSDimitry Andric static unsigned SelectOpcodeFromVT(EVT VT, ArrayRef<unsigned> Opcodes) { 1661bdd1243dSDimitry Andric // Only match scalable vector VTs 1662bdd1243dSDimitry Andric if (!VT.isScalableVector()) 1663bdd1243dSDimitry Andric return 0; 1664bdd1243dSDimitry Andric 1665bdd1243dSDimitry Andric EVT EltVT = VT.getVectorElementType(); 1666bdd1243dSDimitry Andric switch (Kind) { 166706c3fb27SDimitry Andric case SelectTypeKind::AnyType: 166806c3fb27SDimitry Andric break; 166906c3fb27SDimitry Andric case SelectTypeKind::Int: 167006c3fb27SDimitry Andric if (EltVT != MVT::i8 && EltVT != MVT::i16 && EltVT != MVT::i32 && 167106c3fb27SDimitry Andric EltVT != MVT::i64) 167206c3fb27SDimitry Andric return 0; 167306c3fb27SDimitry Andric break; 1674bdd1243dSDimitry Andric case SelectTypeKind::Int1: 1675bdd1243dSDimitry Andric if (EltVT != MVT::i1) 1676bdd1243dSDimitry Andric return 0; 1677bdd1243dSDimitry Andric break; 167806c3fb27SDimitry Andric case SelectTypeKind::FP: 167906c3fb27SDimitry Andric if (EltVT != MVT::f16 && EltVT != MVT::f32 && EltVT != MVT::f64) 168006c3fb27SDimitry Andric return 0; 168106c3fb27SDimitry Andric break; 1682bdd1243dSDimitry Andric } 1683bdd1243dSDimitry Andric 1684bdd1243dSDimitry Andric unsigned Offset; 1685bdd1243dSDimitry Andric switch (VT.getVectorMinNumElements()) { 1686bdd1243dSDimitry Andric case 16: // 8-bit 1687bdd1243dSDimitry Andric Offset = 0; 1688bdd1243dSDimitry Andric break; 1689bdd1243dSDimitry Andric case 8: // 16-bit 1690bdd1243dSDimitry Andric Offset = 1; 1691bdd1243dSDimitry Andric break; 1692bdd1243dSDimitry Andric case 4: // 32-bit 1693bdd1243dSDimitry Andric Offset = 2; 1694bdd1243dSDimitry Andric break; 1695bdd1243dSDimitry Andric case 2: // 64-bit 1696bdd1243dSDimitry Andric Offset = 3; 1697bdd1243dSDimitry Andric break; 1698bdd1243dSDimitry Andric default: 1699bdd1243dSDimitry Andric return 0; 1700bdd1243dSDimitry Andric } 1701bdd1243dSDimitry Andric 1702bdd1243dSDimitry Andric return (Opcodes.size() <= Offset) ? 0 : Opcodes[Offset]; 1703bdd1243dSDimitry Andric } 1704bdd1243dSDimitry Andric 170506c3fb27SDimitry Andric // This function is almost identical to SelectWhilePair, but has an 170606c3fb27SDimitry Andric // extra check on the range of the immediate operand. 170706c3fb27SDimitry Andric // TODO: Merge these two functions together at some point? 170806c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectPExtPair(SDNode *N, unsigned Opc) { 170906c3fb27SDimitry Andric // Immediate can be either 0 or 1. 171006c3fb27SDimitry Andric if (ConstantSDNode *Imm = dyn_cast<ConstantSDNode>(N->getOperand(2))) 171106c3fb27SDimitry Andric if (Imm->getZExtValue() > 1) 171206c3fb27SDimitry Andric return; 171306c3fb27SDimitry Andric 171406c3fb27SDimitry Andric SDLoc DL(N); 171506c3fb27SDimitry Andric EVT VT = N->getValueType(0); 171606c3fb27SDimitry Andric SDValue Ops[] = {N->getOperand(1), N->getOperand(2)}; 171706c3fb27SDimitry Andric SDNode *WhilePair = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops); 171806c3fb27SDimitry Andric SDValue SuperReg = SDValue(WhilePair, 0); 171906c3fb27SDimitry Andric 172006c3fb27SDimitry Andric for (unsigned I = 0; I < 2; ++I) 172106c3fb27SDimitry Andric ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg( 172206c3fb27SDimitry Andric AArch64::psub0 + I, DL, VT, SuperReg)); 172306c3fb27SDimitry Andric 172406c3fb27SDimitry Andric CurDAG->RemoveDeadNode(N); 172506c3fb27SDimitry Andric } 172606c3fb27SDimitry Andric 1727bdd1243dSDimitry Andric void AArch64DAGToDAGISel::SelectWhilePair(SDNode *N, unsigned Opc) { 1728bdd1243dSDimitry Andric SDLoc DL(N); 1729bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 1730bdd1243dSDimitry Andric 1731bdd1243dSDimitry Andric SDValue Ops[] = {N->getOperand(1), N->getOperand(2)}; 1732bdd1243dSDimitry Andric 1733bdd1243dSDimitry Andric SDNode *WhilePair = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops); 1734bdd1243dSDimitry Andric SDValue SuperReg = SDValue(WhilePair, 0); 1735bdd1243dSDimitry Andric 1736bdd1243dSDimitry Andric for (unsigned I = 0; I < 2; ++I) 1737bdd1243dSDimitry Andric ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg( 1738bdd1243dSDimitry Andric AArch64::psub0 + I, DL, VT, SuperReg)); 1739bdd1243dSDimitry Andric 1740bdd1243dSDimitry Andric CurDAG->RemoveDeadNode(N); 1741bdd1243dSDimitry Andric } 1742bdd1243dSDimitry Andric 1743bdd1243dSDimitry Andric void AArch64DAGToDAGISel::SelectCVTIntrinsic(SDNode *N, unsigned NumVecs, 1744bdd1243dSDimitry Andric unsigned Opcode) { 1745bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 1746bdd1243dSDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 1747bdd1243dSDimitry Andric SDValue Ops = createZTuple(Regs); 1748bdd1243dSDimitry Andric SDLoc DL(N); 1749bdd1243dSDimitry Andric SDNode *Intrinsic = CurDAG->getMachineNode(Opcode, DL, MVT::Untyped, Ops); 1750bdd1243dSDimitry Andric SDValue SuperReg = SDValue(Intrinsic, 0); 1751bdd1243dSDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 1752bdd1243dSDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 1753bdd1243dSDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 1754bdd1243dSDimitry Andric 1755bdd1243dSDimitry Andric CurDAG->RemoveDeadNode(N); 175606c3fb27SDimitry Andric } 175706c3fb27SDimitry Andric 175806c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectDestructiveMultiIntrinsic(SDNode *N, 175906c3fb27SDimitry Andric unsigned NumVecs, 176006c3fb27SDimitry Andric bool IsZmMulti, 176106c3fb27SDimitry Andric unsigned Opcode, 176206c3fb27SDimitry Andric bool HasPred) { 176306c3fb27SDimitry Andric assert(Opcode != 0 && "Unexpected opcode"); 176406c3fb27SDimitry Andric 176506c3fb27SDimitry Andric SDLoc DL(N); 176606c3fb27SDimitry Andric EVT VT = N->getValueType(0); 176706c3fb27SDimitry Andric unsigned FirstVecIdx = HasPred ? 2 : 1; 176806c3fb27SDimitry Andric 176906c3fb27SDimitry Andric auto GetMultiVecOperand = [=](unsigned StartIdx) { 177006c3fb27SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + StartIdx, 177106c3fb27SDimitry Andric N->op_begin() + StartIdx + NumVecs); 177206c3fb27SDimitry Andric return createZMulTuple(Regs); 177306c3fb27SDimitry Andric }; 177406c3fb27SDimitry Andric 177506c3fb27SDimitry Andric SDValue Zdn = GetMultiVecOperand(FirstVecIdx); 177606c3fb27SDimitry Andric 177706c3fb27SDimitry Andric SDValue Zm; 177806c3fb27SDimitry Andric if (IsZmMulti) 177906c3fb27SDimitry Andric Zm = GetMultiVecOperand(NumVecs + FirstVecIdx); 178006c3fb27SDimitry Andric else 178106c3fb27SDimitry Andric Zm = N->getOperand(NumVecs + FirstVecIdx); 178206c3fb27SDimitry Andric 178306c3fb27SDimitry Andric SDNode *Intrinsic; 178406c3fb27SDimitry Andric if (HasPred) 178506c3fb27SDimitry Andric Intrinsic = CurDAG->getMachineNode(Opcode, DL, MVT::Untyped, 178606c3fb27SDimitry Andric N->getOperand(1), Zdn, Zm); 178706c3fb27SDimitry Andric else 178806c3fb27SDimitry Andric Intrinsic = CurDAG->getMachineNode(Opcode, DL, MVT::Untyped, Zdn, Zm); 178906c3fb27SDimitry Andric SDValue SuperReg = SDValue(Intrinsic, 0); 179006c3fb27SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 179106c3fb27SDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 179206c3fb27SDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 179306c3fb27SDimitry Andric 179406c3fb27SDimitry Andric CurDAG->RemoveDeadNode(N); 1795bdd1243dSDimitry Andric } 1796bdd1243dSDimitry Andric 17975ffd83dbSDimitry Andric void AArch64DAGToDAGISel::SelectPredicatedLoad(SDNode *N, unsigned NumVecs, 1798979e22ffSDimitry Andric unsigned Scale, unsigned Opc_ri, 1799349cc55cSDimitry Andric unsigned Opc_rr, bool IsIntr) { 1800*5f757f3fSDimitry Andric assert(Scale < 5 && "Invalid scaling value."); 18015ffd83dbSDimitry Andric SDLoc DL(N); 18025ffd83dbSDimitry Andric EVT VT = N->getValueType(0); 18035ffd83dbSDimitry Andric SDValue Chain = N->getOperand(0); 18045ffd83dbSDimitry Andric 1805979e22ffSDimitry Andric // Optimize addressing mode. 1806979e22ffSDimitry Andric SDValue Base, Offset; 1807979e22ffSDimitry Andric unsigned Opc; 1808979e22ffSDimitry Andric std::tie(Opc, Base, Offset) = findAddrModeSVELoadStore( 1809349cc55cSDimitry Andric N, Opc_rr, Opc_ri, N->getOperand(IsIntr ? 3 : 2), 1810979e22ffSDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i64), Scale); 1811979e22ffSDimitry Andric 1812349cc55cSDimitry Andric SDValue Ops[] = {N->getOperand(IsIntr ? 2 : 1), // Predicate 1813979e22ffSDimitry Andric Base, // Memory operand 1814979e22ffSDimitry Andric Offset, Chain}; 18155ffd83dbSDimitry Andric 18165ffd83dbSDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 18175ffd83dbSDimitry Andric 18185ffd83dbSDimitry Andric SDNode *Load = CurDAG->getMachineNode(Opc, DL, ResTys, Ops); 18195ffd83dbSDimitry Andric SDValue SuperReg = SDValue(Load, 0); 18205ffd83dbSDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 18215ffd83dbSDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 18225ffd83dbSDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 18235ffd83dbSDimitry Andric 18245ffd83dbSDimitry Andric // Copy chain 18255ffd83dbSDimitry Andric unsigned ChainIdx = NumVecs; 18265ffd83dbSDimitry Andric ReplaceUses(SDValue(N, ChainIdx), SDValue(Load, 1)); 18275ffd83dbSDimitry Andric CurDAG->RemoveDeadNode(N); 18285ffd83dbSDimitry Andric } 18295ffd83dbSDimitry Andric 183006c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectContiguousMultiVectorLoad(SDNode *N, 183106c3fb27SDimitry Andric unsigned NumVecs, 183206c3fb27SDimitry Andric unsigned Scale, 183306c3fb27SDimitry Andric unsigned Opc_ri, 183406c3fb27SDimitry Andric unsigned Opc_rr) { 183506c3fb27SDimitry Andric assert(Scale < 4 && "Invalid scaling value."); 183606c3fb27SDimitry Andric SDLoc DL(N); 183706c3fb27SDimitry Andric EVT VT = N->getValueType(0); 183806c3fb27SDimitry Andric SDValue Chain = N->getOperand(0); 183906c3fb27SDimitry Andric 184006c3fb27SDimitry Andric SDValue PNg = N->getOperand(2); 184106c3fb27SDimitry Andric SDValue Base = N->getOperand(3); 184206c3fb27SDimitry Andric SDValue Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); 184306c3fb27SDimitry Andric unsigned Opc; 184406c3fb27SDimitry Andric std::tie(Opc, Base, Offset) = 184506c3fb27SDimitry Andric findAddrModeSVELoadStore(N, Opc_rr, Opc_ri, Base, Offset, Scale); 184606c3fb27SDimitry Andric 184706c3fb27SDimitry Andric SDValue Ops[] = {PNg, // Predicate-as-counter 184806c3fb27SDimitry Andric Base, // Memory operand 184906c3fb27SDimitry Andric Offset, Chain}; 185006c3fb27SDimitry Andric 185106c3fb27SDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 185206c3fb27SDimitry Andric 185306c3fb27SDimitry Andric SDNode *Load = CurDAG->getMachineNode(Opc, DL, ResTys, Ops); 185406c3fb27SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 185506c3fb27SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 185606c3fb27SDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 185706c3fb27SDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 185806c3fb27SDimitry Andric 185906c3fb27SDimitry Andric // Copy chain 186006c3fb27SDimitry Andric unsigned ChainIdx = NumVecs; 186106c3fb27SDimitry Andric ReplaceUses(SDValue(N, ChainIdx), SDValue(Load, 1)); 186206c3fb27SDimitry Andric CurDAG->RemoveDeadNode(N); 186306c3fb27SDimitry Andric } 186406c3fb27SDimitry Andric 186506c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectFrintFromVT(SDNode *N, unsigned NumVecs, 186606c3fb27SDimitry Andric unsigned Opcode) { 186706c3fb27SDimitry Andric if (N->getValueType(0) != MVT::nxv4f32) 186806c3fb27SDimitry Andric return; 186906c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(N, NumVecs, true, Opcode); 187006c3fb27SDimitry Andric } 187106c3fb27SDimitry Andric 1872*5f757f3fSDimitry Andric void AArch64DAGToDAGISel::SelectMultiVectorLuti(SDNode *Node, 1873*5f757f3fSDimitry Andric unsigned NumOutVecs, 1874*5f757f3fSDimitry Andric unsigned Opc, uint32_t MaxImm) { 1875*5f757f3fSDimitry Andric if (ConstantSDNode *Imm = dyn_cast<ConstantSDNode>(Node->getOperand(4))) 1876*5f757f3fSDimitry Andric if (Imm->getZExtValue() > MaxImm) 1877*5f757f3fSDimitry Andric return; 1878*5f757f3fSDimitry Andric 1879*5f757f3fSDimitry Andric SDValue ZtValue; 1880*5f757f3fSDimitry Andric if (!ImmToReg<AArch64::ZT0, 0>(Node->getOperand(2), ZtValue)) 1881*5f757f3fSDimitry Andric return; 1882*5f757f3fSDimitry Andric SDValue Ops[] = {ZtValue, Node->getOperand(3), Node->getOperand(4)}; 1883*5f757f3fSDimitry Andric SDLoc DL(Node); 1884*5f757f3fSDimitry Andric EVT VT = Node->getValueType(0); 1885*5f757f3fSDimitry Andric 1886*5f757f3fSDimitry Andric SDNode *Instruction = 1887*5f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, DL, {MVT::Untyped, MVT::Other}, Ops); 1888*5f757f3fSDimitry Andric SDValue SuperReg = SDValue(Instruction, 0); 1889*5f757f3fSDimitry Andric 1890*5f757f3fSDimitry Andric for (unsigned I = 0; I < NumOutVecs; ++I) 1891*5f757f3fSDimitry Andric ReplaceUses(SDValue(Node, I), CurDAG->getTargetExtractSubreg( 1892*5f757f3fSDimitry Andric AArch64::zsub0 + I, DL, VT, SuperReg)); 1893*5f757f3fSDimitry Andric 1894*5f757f3fSDimitry Andric // Copy chain 1895*5f757f3fSDimitry Andric unsigned ChainIdx = NumOutVecs; 1896*5f757f3fSDimitry Andric ReplaceUses(SDValue(Node, ChainIdx), SDValue(Instruction, 1)); 1897*5f757f3fSDimitry Andric CurDAG->RemoveDeadNode(Node); 1898*5f757f3fSDimitry Andric } 1899*5f757f3fSDimitry Andric 190006c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectClamp(SDNode *N, unsigned NumVecs, 190106c3fb27SDimitry Andric unsigned Op) { 190206c3fb27SDimitry Andric SDLoc DL(N); 190306c3fb27SDimitry Andric EVT VT = N->getValueType(0); 190406c3fb27SDimitry Andric 190506c3fb27SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 190606c3fb27SDimitry Andric SDValue Zd = createZMulTuple(Regs); 190706c3fb27SDimitry Andric SDValue Zn = N->getOperand(1 + NumVecs); 190806c3fb27SDimitry Andric SDValue Zm = N->getOperand(2 + NumVecs); 190906c3fb27SDimitry Andric 191006c3fb27SDimitry Andric SDValue Ops[] = {Zd, Zn, Zm}; 191106c3fb27SDimitry Andric 191206c3fb27SDimitry Andric SDNode *Intrinsic = CurDAG->getMachineNode(Op, DL, MVT::Untyped, Ops); 191306c3fb27SDimitry Andric SDValue SuperReg = SDValue(Intrinsic, 0); 191406c3fb27SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 191506c3fb27SDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 191606c3fb27SDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 191706c3fb27SDimitry Andric 191806c3fb27SDimitry Andric CurDAG->RemoveDeadNode(N); 191906c3fb27SDimitry Andric } 192006c3fb27SDimitry Andric 192106c3fb27SDimitry Andric bool SelectSMETile(unsigned &BaseReg, unsigned TileNum) { 192206c3fb27SDimitry Andric switch (BaseReg) { 192306c3fb27SDimitry Andric default: 192406c3fb27SDimitry Andric return false; 192506c3fb27SDimitry Andric case AArch64::ZA: 192606c3fb27SDimitry Andric case AArch64::ZAB0: 192706c3fb27SDimitry Andric if (TileNum == 0) 192806c3fb27SDimitry Andric break; 192906c3fb27SDimitry Andric return false; 193006c3fb27SDimitry Andric case AArch64::ZAH0: 193106c3fb27SDimitry Andric if (TileNum <= 1) 193206c3fb27SDimitry Andric break; 193306c3fb27SDimitry Andric return false; 193406c3fb27SDimitry Andric case AArch64::ZAS0: 193506c3fb27SDimitry Andric if (TileNum <= 3) 193606c3fb27SDimitry Andric break; 193706c3fb27SDimitry Andric return false; 193806c3fb27SDimitry Andric case AArch64::ZAD0: 193906c3fb27SDimitry Andric if (TileNum <= 7) 194006c3fb27SDimitry Andric break; 194106c3fb27SDimitry Andric return false; 194206c3fb27SDimitry Andric } 194306c3fb27SDimitry Andric 194406c3fb27SDimitry Andric BaseReg += TileNum; 194506c3fb27SDimitry Andric return true; 194606c3fb27SDimitry Andric } 194706c3fb27SDimitry Andric 194806c3fb27SDimitry Andric template <unsigned MaxIdx, unsigned Scale> 194906c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectMultiVectorMove(SDNode *N, unsigned NumVecs, 195006c3fb27SDimitry Andric unsigned BaseReg, unsigned Op) { 195106c3fb27SDimitry Andric unsigned TileNum = 0; 195206c3fb27SDimitry Andric if (BaseReg != AArch64::ZA) 195306c3fb27SDimitry Andric TileNum = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); 195406c3fb27SDimitry Andric 195506c3fb27SDimitry Andric if (!SelectSMETile(BaseReg, TileNum)) 195606c3fb27SDimitry Andric return; 195706c3fb27SDimitry Andric 195806c3fb27SDimitry Andric SDValue SliceBase, Base, Offset; 195906c3fb27SDimitry Andric if (BaseReg == AArch64::ZA) 196006c3fb27SDimitry Andric SliceBase = N->getOperand(2); 196106c3fb27SDimitry Andric else 196206c3fb27SDimitry Andric SliceBase = N->getOperand(3); 196306c3fb27SDimitry Andric 196406c3fb27SDimitry Andric if (!SelectSMETileSlice(SliceBase, MaxIdx, Base, Offset, Scale)) 196506c3fb27SDimitry Andric return; 196606c3fb27SDimitry Andric 196706c3fb27SDimitry Andric SDLoc DL(N); 196806c3fb27SDimitry Andric SDValue SubReg = CurDAG->getRegister(BaseReg, MVT::Other); 196906c3fb27SDimitry Andric SDValue Ops[] = {SubReg, Base, Offset, /*Chain*/ N->getOperand(0)}; 197006c3fb27SDimitry Andric SDNode *Mov = CurDAG->getMachineNode(Op, DL, {MVT::Untyped, MVT::Other}, Ops); 197106c3fb27SDimitry Andric 197206c3fb27SDimitry Andric EVT VT = N->getValueType(0); 197306c3fb27SDimitry Andric for (unsigned I = 0; I < NumVecs; ++I) 197406c3fb27SDimitry Andric ReplaceUses(SDValue(N, I), 197506c3fb27SDimitry Andric CurDAG->getTargetExtractSubreg(AArch64::zsub0 + I, DL, VT, 197606c3fb27SDimitry Andric SDValue(Mov, 0))); 197706c3fb27SDimitry Andric // Copy chain 197806c3fb27SDimitry Andric unsigned ChainIdx = NumVecs; 197906c3fb27SDimitry Andric ReplaceUses(SDValue(N, ChainIdx), SDValue(Mov, 1)); 198006c3fb27SDimitry Andric CurDAG->RemoveDeadNode(N); 198106c3fb27SDimitry Andric } 198206c3fb27SDimitry Andric 198306c3fb27SDimitry Andric void AArch64DAGToDAGISel::SelectUnaryMultiIntrinsic(SDNode *N, 198406c3fb27SDimitry Andric unsigned NumOutVecs, 198506c3fb27SDimitry Andric bool IsTupleInput, 198606c3fb27SDimitry Andric unsigned Opc) { 198706c3fb27SDimitry Andric SDLoc DL(N); 198806c3fb27SDimitry Andric EVT VT = N->getValueType(0); 198906c3fb27SDimitry Andric unsigned NumInVecs = N->getNumOperands() - 1; 199006c3fb27SDimitry Andric 199106c3fb27SDimitry Andric SmallVector<SDValue, 6> Ops; 199206c3fb27SDimitry Andric if (IsTupleInput) { 199306c3fb27SDimitry Andric assert((NumInVecs == 2 || NumInVecs == 4) && 199406c3fb27SDimitry Andric "Don't know how to handle multi-register input!"); 199506c3fb27SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, 199606c3fb27SDimitry Andric N->op_begin() + 1 + NumInVecs); 199706c3fb27SDimitry Andric Ops.push_back(createZMulTuple(Regs)); 199806c3fb27SDimitry Andric } else { 199906c3fb27SDimitry Andric // All intrinsic nodes have the ID as the first operand, hence the "1 + I". 200006c3fb27SDimitry Andric for (unsigned I = 0; I < NumInVecs; I++) 200106c3fb27SDimitry Andric Ops.push_back(N->getOperand(1 + I)); 200206c3fb27SDimitry Andric } 200306c3fb27SDimitry Andric 200406c3fb27SDimitry Andric SDNode *Res = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops); 200506c3fb27SDimitry Andric SDValue SuperReg = SDValue(Res, 0); 200606c3fb27SDimitry Andric 200706c3fb27SDimitry Andric for (unsigned I = 0; I < NumOutVecs; I++) 200806c3fb27SDimitry Andric ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg( 200906c3fb27SDimitry Andric AArch64::zsub0 + I, DL, VT, SuperReg)); 201006c3fb27SDimitry Andric CurDAG->RemoveDeadNode(N); 201106c3fb27SDimitry Andric } 201206c3fb27SDimitry Andric 20130b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectStore(SDNode *N, unsigned NumVecs, 20140b57cec5SDimitry Andric unsigned Opc) { 20150b57cec5SDimitry Andric SDLoc dl(N); 20160b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 20170b57cec5SDimitry Andric 20180b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 20190b57cec5SDimitry Andric bool Is128Bit = VT.getSizeInBits() == 128; 20200b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 20210b57cec5SDimitry Andric SDValue RegSeq = Is128Bit ? createQTuple(Regs) : createDTuple(Regs); 20220b57cec5SDimitry Andric 20230b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), N->getOperand(0)}; 20240b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops); 20250b57cec5SDimitry Andric 20260b57cec5SDimitry Andric // Transfer memoperands. 20270b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 20280b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 20290b57cec5SDimitry Andric 20300b57cec5SDimitry Andric ReplaceNode(N, St); 20310b57cec5SDimitry Andric } 20320b57cec5SDimitry Andric 20335ffd83dbSDimitry Andric void AArch64DAGToDAGISel::SelectPredicatedStore(SDNode *N, unsigned NumVecs, 2034979e22ffSDimitry Andric unsigned Scale, unsigned Opc_rr, 2035979e22ffSDimitry Andric unsigned Opc_ri) { 20365ffd83dbSDimitry Andric SDLoc dl(N); 20375ffd83dbSDimitry Andric 20385ffd83dbSDimitry Andric // Form a REG_SEQUENCE to force register allocation. 20395ffd83dbSDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 20405ffd83dbSDimitry Andric SDValue RegSeq = createZTuple(Regs); 20415ffd83dbSDimitry Andric 20425ffd83dbSDimitry Andric // Optimize addressing mode. 20435ffd83dbSDimitry Andric unsigned Opc; 20445ffd83dbSDimitry Andric SDValue Offset, Base; 2045979e22ffSDimitry Andric std::tie(Opc, Base, Offset) = findAddrModeSVELoadStore( 20465ffd83dbSDimitry Andric N, Opc_rr, Opc_ri, N->getOperand(NumVecs + 3), 2047979e22ffSDimitry Andric CurDAG->getTargetConstant(0, dl, MVT::i64), Scale); 20485ffd83dbSDimitry Andric 20495ffd83dbSDimitry Andric SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), // predicate 20505ffd83dbSDimitry Andric Base, // address 20515ffd83dbSDimitry Andric Offset, // offset 20525ffd83dbSDimitry Andric N->getOperand(0)}; // chain 20535ffd83dbSDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops); 20545ffd83dbSDimitry Andric 20555ffd83dbSDimitry Andric ReplaceNode(N, St); 20565ffd83dbSDimitry Andric } 20575ffd83dbSDimitry Andric 20585ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeFrameIndexSVE(SDValue N, SDValue &Base, 20595ffd83dbSDimitry Andric SDValue &OffImm) { 20605ffd83dbSDimitry Andric SDLoc dl(N); 20615ffd83dbSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 20625ffd83dbSDimitry Andric const TargetLowering *TLI = getTargetLowering(); 20635ffd83dbSDimitry Andric 20645ffd83dbSDimitry Andric // Try to match it for the frame address 20655ffd83dbSDimitry Andric if (auto FINode = dyn_cast<FrameIndexSDNode>(N)) { 20665ffd83dbSDimitry Andric int FI = FINode->getIndex(); 20675ffd83dbSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 20685ffd83dbSDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 20695ffd83dbSDimitry Andric return true; 20705ffd83dbSDimitry Andric } 20715ffd83dbSDimitry Andric 20725ffd83dbSDimitry Andric return false; 20735ffd83dbSDimitry Andric } 20745ffd83dbSDimitry Andric 20750b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostStore(SDNode *N, unsigned NumVecs, 20760b57cec5SDimitry Andric unsigned Opc) { 20770b57cec5SDimitry Andric SDLoc dl(N); 20780b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 20790b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 20800b57cec5SDimitry Andric MVT::Other}; // Type for the Chain 20810b57cec5SDimitry Andric 20820b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 20830b57cec5SDimitry Andric bool Is128Bit = VT.getSizeInBits() == 128; 20840b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 20850b57cec5SDimitry Andric SDValue RegSeq = Is128Bit ? createQTuple(Regs) : createDTuple(Regs); 20860b57cec5SDimitry Andric 20870b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, 20880b57cec5SDimitry Andric N->getOperand(NumVecs + 1), // base register 20890b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Incremental 20900b57cec5SDimitry Andric N->getOperand(0)}; // Chain 20910b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 20920b57cec5SDimitry Andric 20930b57cec5SDimitry Andric ReplaceNode(N, St); 20940b57cec5SDimitry Andric } 20950b57cec5SDimitry Andric 20960b57cec5SDimitry Andric namespace { 20970b57cec5SDimitry Andric /// WidenVector - Given a value in the V64 register class, produce the 20980b57cec5SDimitry Andric /// equivalent value in the V128 register class. 20990b57cec5SDimitry Andric class WidenVector { 21000b57cec5SDimitry Andric SelectionDAG &DAG; 21010b57cec5SDimitry Andric 21020b57cec5SDimitry Andric public: 21030b57cec5SDimitry Andric WidenVector(SelectionDAG &DAG) : DAG(DAG) {} 21040b57cec5SDimitry Andric 21050b57cec5SDimitry Andric SDValue operator()(SDValue V64Reg) { 21060b57cec5SDimitry Andric EVT VT = V64Reg.getValueType(); 21070b57cec5SDimitry Andric unsigned NarrowSize = VT.getVectorNumElements(); 21080b57cec5SDimitry Andric MVT EltTy = VT.getVectorElementType().getSimpleVT(); 21090b57cec5SDimitry Andric MVT WideTy = MVT::getVectorVT(EltTy, 2 * NarrowSize); 21100b57cec5SDimitry Andric SDLoc DL(V64Reg); 21110b57cec5SDimitry Andric 21120b57cec5SDimitry Andric SDValue Undef = 21130b57cec5SDimitry Andric SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, WideTy), 0); 21140b57cec5SDimitry Andric return DAG.getTargetInsertSubreg(AArch64::dsub, DL, WideTy, Undef, V64Reg); 21150b57cec5SDimitry Andric } 21160b57cec5SDimitry Andric }; 21170b57cec5SDimitry Andric } // namespace 21180b57cec5SDimitry Andric 21190b57cec5SDimitry Andric /// NarrowVector - Given a value in the V128 register class, produce the 21200b57cec5SDimitry Andric /// equivalent value in the V64 register class. 21210b57cec5SDimitry Andric static SDValue NarrowVector(SDValue V128Reg, SelectionDAG &DAG) { 21220b57cec5SDimitry Andric EVT VT = V128Reg.getValueType(); 21230b57cec5SDimitry Andric unsigned WideSize = VT.getVectorNumElements(); 21240b57cec5SDimitry Andric MVT EltTy = VT.getVectorElementType().getSimpleVT(); 21250b57cec5SDimitry Andric MVT NarrowTy = MVT::getVectorVT(EltTy, WideSize / 2); 21260b57cec5SDimitry Andric 21270b57cec5SDimitry Andric return DAG.getTargetExtractSubreg(AArch64::dsub, SDLoc(V128Reg), NarrowTy, 21280b57cec5SDimitry Andric V128Reg); 21290b57cec5SDimitry Andric } 21300b57cec5SDimitry Andric 21310b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectLoadLane(SDNode *N, unsigned NumVecs, 21320b57cec5SDimitry Andric unsigned Opc) { 21330b57cec5SDimitry Andric SDLoc dl(N); 21340b57cec5SDimitry Andric EVT VT = N->getValueType(0); 21350b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 21360b57cec5SDimitry Andric 21370b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 21380b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 21390b57cec5SDimitry Andric 21400b57cec5SDimitry Andric if (Narrow) 21410b57cec5SDimitry Andric transform(Regs, Regs.begin(), 21420b57cec5SDimitry Andric WidenVector(*CurDAG)); 21430b57cec5SDimitry Andric 21440b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 21450b57cec5SDimitry Andric 21460b57cec5SDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 21470b57cec5SDimitry Andric 21480b57cec5SDimitry Andric unsigned LaneNo = 21490b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 2))->getZExtValue(); 21500b57cec5SDimitry Andric 21510b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 21520b57cec5SDimitry Andric N->getOperand(NumVecs + 3), N->getOperand(0)}; 21530b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 21540b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 0); 21550b57cec5SDimitry Andric 21560b57cec5SDimitry Andric EVT WideVT = RegSeq.getOperand(1)->getValueType(0); 21570b57cec5SDimitry Andric static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1, 21580b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3 }; 21590b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) { 21600b57cec5SDimitry Andric SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, SuperReg); 21610b57cec5SDimitry Andric if (Narrow) 21620b57cec5SDimitry Andric NV = NarrowVector(NV, *CurDAG); 21630b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), NV); 21640b57cec5SDimitry Andric } 21650b57cec5SDimitry Andric 21660b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1)); 21670b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 21680b57cec5SDimitry Andric } 21690b57cec5SDimitry Andric 21700b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostLoadLane(SDNode *N, unsigned NumVecs, 21710b57cec5SDimitry Andric unsigned Opc) { 21720b57cec5SDimitry Andric SDLoc dl(N); 21730b57cec5SDimitry Andric EVT VT = N->getValueType(0); 21740b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 21750b57cec5SDimitry Andric 21760b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 21770b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 21780b57cec5SDimitry Andric 21790b57cec5SDimitry Andric if (Narrow) 21800b57cec5SDimitry Andric transform(Regs, Regs.begin(), 21810b57cec5SDimitry Andric WidenVector(*CurDAG)); 21820b57cec5SDimitry Andric 21830b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 21860b57cec5SDimitry Andric RegSeq->getValueType(0), MVT::Other}; 21870b57cec5SDimitry Andric 21880b57cec5SDimitry Andric unsigned LaneNo = 21890b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 1))->getZExtValue(); 21900b57cec5SDimitry Andric 21910b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, 21920b57cec5SDimitry Andric CurDAG->getTargetConstant(LaneNo, dl, 21930b57cec5SDimitry Andric MVT::i64), // Lane Number 21940b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Base register 21950b57cec5SDimitry Andric N->getOperand(NumVecs + 3), // Incremental 21960b57cec5SDimitry Andric N->getOperand(0)}; 21970b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 21980b57cec5SDimitry Andric 21990b57cec5SDimitry Andric // Update uses of the write back register 22000b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0)); 22010b57cec5SDimitry Andric 22020b57cec5SDimitry Andric // Update uses of the vector list 22030b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 1); 22040b57cec5SDimitry Andric if (NumVecs == 1) { 22050b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), 22060b57cec5SDimitry Andric Narrow ? NarrowVector(SuperReg, *CurDAG) : SuperReg); 22070b57cec5SDimitry Andric } else { 22080b57cec5SDimitry Andric EVT WideVT = RegSeq.getOperand(1)->getValueType(0); 22090b57cec5SDimitry Andric static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1, 22100b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3 }; 22110b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) { 22120b57cec5SDimitry Andric SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, 22130b57cec5SDimitry Andric SuperReg); 22140b57cec5SDimitry Andric if (Narrow) 22150b57cec5SDimitry Andric NV = NarrowVector(NV, *CurDAG); 22160b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), NV); 22170b57cec5SDimitry Andric } 22180b57cec5SDimitry Andric } 22190b57cec5SDimitry Andric 22200b57cec5SDimitry Andric // Update the Chain 22210b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2)); 22220b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 22230b57cec5SDimitry Andric } 22240b57cec5SDimitry Andric 22250b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectStoreLane(SDNode *N, unsigned NumVecs, 22260b57cec5SDimitry Andric unsigned Opc) { 22270b57cec5SDimitry Andric SDLoc dl(N); 22280b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 22290b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 22300b57cec5SDimitry Andric 22310b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 22320b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 22330b57cec5SDimitry Andric 22340b57cec5SDimitry Andric if (Narrow) 22350b57cec5SDimitry Andric transform(Regs, Regs.begin(), 22360b57cec5SDimitry Andric WidenVector(*CurDAG)); 22370b57cec5SDimitry Andric 22380b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 22390b57cec5SDimitry Andric 22400b57cec5SDimitry Andric unsigned LaneNo = 22410b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 2))->getZExtValue(); 22420b57cec5SDimitry Andric 22430b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 22440b57cec5SDimitry Andric N->getOperand(NumVecs + 3), N->getOperand(0)}; 22450b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops); 22460b57cec5SDimitry Andric 22470b57cec5SDimitry Andric // Transfer memoperands. 22480b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 22490b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 22500b57cec5SDimitry Andric 22510b57cec5SDimitry Andric ReplaceNode(N, St); 22520b57cec5SDimitry Andric } 22530b57cec5SDimitry Andric 22540b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostStoreLane(SDNode *N, unsigned NumVecs, 22550b57cec5SDimitry Andric unsigned Opc) { 22560b57cec5SDimitry Andric SDLoc dl(N); 22570b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 22580b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 22590b57cec5SDimitry Andric 22600b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 22610b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 22620b57cec5SDimitry Andric 22630b57cec5SDimitry Andric if (Narrow) 22640b57cec5SDimitry Andric transform(Regs, Regs.begin(), 22650b57cec5SDimitry Andric WidenVector(*CurDAG)); 22660b57cec5SDimitry Andric 22670b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 22680b57cec5SDimitry Andric 22690b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 22700b57cec5SDimitry Andric MVT::Other}; 22710b57cec5SDimitry Andric 22720b57cec5SDimitry Andric unsigned LaneNo = 22730b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 1))->getZExtValue(); 22740b57cec5SDimitry Andric 22750b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 22760b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Base Register 22770b57cec5SDimitry Andric N->getOperand(NumVecs + 3), // Incremental 22780b57cec5SDimitry Andric N->getOperand(0)}; 22790b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 22800b57cec5SDimitry Andric 22810b57cec5SDimitry Andric // Transfer memoperands. 22820b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 22830b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 22840b57cec5SDimitry Andric 22850b57cec5SDimitry Andric ReplaceNode(N, St); 22860b57cec5SDimitry Andric } 22870b57cec5SDimitry Andric 22880b57cec5SDimitry Andric static bool isBitfieldExtractOpFromAnd(SelectionDAG *CurDAG, SDNode *N, 22890b57cec5SDimitry Andric unsigned &Opc, SDValue &Opd0, 22900b57cec5SDimitry Andric unsigned &LSB, unsigned &MSB, 22910b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits, 22920b57cec5SDimitry Andric bool BiggerPattern) { 22930b57cec5SDimitry Andric assert(N->getOpcode() == ISD::AND && 22940b57cec5SDimitry Andric "N must be a AND operation to call this function"); 22950b57cec5SDimitry Andric 22960b57cec5SDimitry Andric EVT VT = N->getValueType(0); 22970b57cec5SDimitry Andric 22980b57cec5SDimitry Andric // Here we can test the type of VT and return false when the type does not 22990b57cec5SDimitry Andric // match, but since it is done prior to that call in the current context 23000b57cec5SDimitry Andric // we turned that into an assert to avoid redundant code. 23010b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 23020b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 23030b57cec5SDimitry Andric 23040b57cec5SDimitry Andric // FIXME: simplify-demanded-bits in DAGCombine will probably have 23050b57cec5SDimitry Andric // changed the AND node to a 32-bit mask operation. We'll have to 23060b57cec5SDimitry Andric // undo that as part of the transform here if we want to catch all 23070b57cec5SDimitry Andric // the opportunities. 23080b57cec5SDimitry Andric // Currently the NumberOfIgnoredLowBits argument helps to recover 2309bdd1243dSDimitry Andric // from these situations when matching bigger pattern (bitfield insert). 23100b57cec5SDimitry Andric 23110b57cec5SDimitry Andric // For unsigned extracts, check for a shift right and mask 23120b57cec5SDimitry Andric uint64_t AndImm = 0; 23130b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N, ISD::AND, AndImm)) 23140b57cec5SDimitry Andric return false; 23150b57cec5SDimitry Andric 23160b57cec5SDimitry Andric const SDNode *Op0 = N->getOperand(0).getNode(); 23170b57cec5SDimitry Andric 23180b57cec5SDimitry Andric // Because of simplify-demanded-bits in DAGCombine, the mask may have been 23190b57cec5SDimitry Andric // simplified. Try to undo that 23200b57cec5SDimitry Andric AndImm |= maskTrailingOnes<uint64_t>(NumberOfIgnoredLowBits); 23210b57cec5SDimitry Andric 23220b57cec5SDimitry Andric // The immediate is a mask of the low bits iff imm & (imm+1) == 0 23230b57cec5SDimitry Andric if (AndImm & (AndImm + 1)) 23240b57cec5SDimitry Andric return false; 23250b57cec5SDimitry Andric 23260b57cec5SDimitry Andric bool ClampMSB = false; 23270b57cec5SDimitry Andric uint64_t SrlImm = 0; 23280b57cec5SDimitry Andric // Handle the SRL + ANY_EXTEND case. 23290b57cec5SDimitry Andric if (VT == MVT::i64 && Op0->getOpcode() == ISD::ANY_EXTEND && 23300b57cec5SDimitry Andric isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, SrlImm)) { 23310b57cec5SDimitry Andric // Extend the incoming operand of the SRL to 64-bit. 23320b57cec5SDimitry Andric Opd0 = Widen(CurDAG, Op0->getOperand(0).getOperand(0)); 23330b57cec5SDimitry Andric // Make sure to clamp the MSB so that we preserve the semantics of the 23340b57cec5SDimitry Andric // original operations. 23350b57cec5SDimitry Andric ClampMSB = true; 23360b57cec5SDimitry Andric } else if (VT == MVT::i32 && Op0->getOpcode() == ISD::TRUNCATE && 23370b57cec5SDimitry Andric isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, 23380b57cec5SDimitry Andric SrlImm)) { 23390b57cec5SDimitry Andric // If the shift result was truncated, we can still combine them. 23400b57cec5SDimitry Andric Opd0 = Op0->getOperand(0).getOperand(0); 23410b57cec5SDimitry Andric 23420b57cec5SDimitry Andric // Use the type of SRL node. 23430b57cec5SDimitry Andric VT = Opd0->getValueType(0); 23440b57cec5SDimitry Andric } else if (isOpcWithIntImmediate(Op0, ISD::SRL, SrlImm)) { 23450b57cec5SDimitry Andric Opd0 = Op0->getOperand(0); 234681ad6265SDimitry Andric ClampMSB = (VT == MVT::i32); 23470b57cec5SDimitry Andric } else if (BiggerPattern) { 23480b57cec5SDimitry Andric // Let's pretend a 0 shift right has been performed. 23490b57cec5SDimitry Andric // The resulting code will be at least as good as the original one 23500b57cec5SDimitry Andric // plus it may expose more opportunities for bitfield insert pattern. 23510b57cec5SDimitry Andric // FIXME: Currently we limit this to the bigger pattern, because 23520b57cec5SDimitry Andric // some optimizations expect AND and not UBFM. 23530b57cec5SDimitry Andric Opd0 = N->getOperand(0); 23540b57cec5SDimitry Andric } else 23550b57cec5SDimitry Andric return false; 23560b57cec5SDimitry Andric 23570b57cec5SDimitry Andric // Bail out on large immediates. This happens when no proper 23580b57cec5SDimitry Andric // combining/constant folding was performed. 23590b57cec5SDimitry Andric if (!BiggerPattern && (SrlImm <= 0 || SrlImm >= VT.getSizeInBits())) { 23600b57cec5SDimitry Andric LLVM_DEBUG( 23610b57cec5SDimitry Andric (dbgs() << N 23620b57cec5SDimitry Andric << ": Found large shift immediate, this should not happen\n")); 23630b57cec5SDimitry Andric return false; 23640b57cec5SDimitry Andric } 23650b57cec5SDimitry Andric 23660b57cec5SDimitry Andric LSB = SrlImm; 236706c3fb27SDimitry Andric MSB = SrlImm + 236806c3fb27SDimitry Andric (VT == MVT::i32 ? llvm::countr_one<uint32_t>(AndImm) 236906c3fb27SDimitry Andric : llvm::countr_one<uint64_t>(AndImm)) - 23700b57cec5SDimitry Andric 1; 23710b57cec5SDimitry Andric if (ClampMSB) 23720b57cec5SDimitry Andric // Since we're moving the extend before the right shift operation, we need 23730b57cec5SDimitry Andric // to clamp the MSB to make sure we don't shift in undefined bits instead of 23740b57cec5SDimitry Andric // the zeros which would get shifted in with the original right shift 23750b57cec5SDimitry Andric // operation. 23760b57cec5SDimitry Andric MSB = MSB > 31 ? 31 : MSB; 23770b57cec5SDimitry Andric 23780b57cec5SDimitry Andric Opc = VT == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri; 23790b57cec5SDimitry Andric return true; 23800b57cec5SDimitry Andric } 23810b57cec5SDimitry Andric 23820b57cec5SDimitry Andric static bool isBitfieldExtractOpFromSExtInReg(SDNode *N, unsigned &Opc, 23830b57cec5SDimitry Andric SDValue &Opd0, unsigned &Immr, 23840b57cec5SDimitry Andric unsigned &Imms) { 23850b57cec5SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND_INREG); 23860b57cec5SDimitry Andric 23870b57cec5SDimitry Andric EVT VT = N->getValueType(0); 23880b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 23890b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 23900b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 23910b57cec5SDimitry Andric 23920b57cec5SDimitry Andric SDValue Op = N->getOperand(0); 23930b57cec5SDimitry Andric if (Op->getOpcode() == ISD::TRUNCATE) { 23940b57cec5SDimitry Andric Op = Op->getOperand(0); 23950b57cec5SDimitry Andric VT = Op->getValueType(0); 23960b57cec5SDimitry Andric BitWidth = VT.getSizeInBits(); 23970b57cec5SDimitry Andric } 23980b57cec5SDimitry Andric 23990b57cec5SDimitry Andric uint64_t ShiftImm; 24000b57cec5SDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRL, ShiftImm) && 24010b57cec5SDimitry Andric !isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm)) 24020b57cec5SDimitry Andric return false; 24030b57cec5SDimitry Andric 24040b57cec5SDimitry Andric unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits(); 24050b57cec5SDimitry Andric if (ShiftImm + Width > BitWidth) 24060b57cec5SDimitry Andric return false; 24070b57cec5SDimitry Andric 24080b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::SBFMWri : AArch64::SBFMXri; 24090b57cec5SDimitry Andric Opd0 = Op.getOperand(0); 24100b57cec5SDimitry Andric Immr = ShiftImm; 24110b57cec5SDimitry Andric Imms = ShiftImm + Width - 1; 24120b57cec5SDimitry Andric return true; 24130b57cec5SDimitry Andric } 24140b57cec5SDimitry Andric 24150b57cec5SDimitry Andric static bool isSeveralBitsExtractOpFromShr(SDNode *N, unsigned &Opc, 24160b57cec5SDimitry Andric SDValue &Opd0, unsigned &LSB, 24170b57cec5SDimitry Andric unsigned &MSB) { 24180b57cec5SDimitry Andric // We are looking for the following pattern which basically extracts several 24190b57cec5SDimitry Andric // continuous bits from the source value and places it from the LSB of the 24200b57cec5SDimitry Andric // destination value, all other bits of the destination value or set to zero: 24210b57cec5SDimitry Andric // 24220b57cec5SDimitry Andric // Value2 = AND Value, MaskImm 24230b57cec5SDimitry Andric // SRL Value2, ShiftImm 24240b57cec5SDimitry Andric // 24250b57cec5SDimitry Andric // with MaskImm >> ShiftImm to search for the bit width. 24260b57cec5SDimitry Andric // 24270b57cec5SDimitry Andric // This gets selected into a single UBFM: 24280b57cec5SDimitry Andric // 242906c3fb27SDimitry Andric // UBFM Value, ShiftImm, Log2_64(MaskImm) 24300b57cec5SDimitry Andric // 24310b57cec5SDimitry Andric 24320b57cec5SDimitry Andric if (N->getOpcode() != ISD::SRL) 24330b57cec5SDimitry Andric return false; 24340b57cec5SDimitry Andric 24350b57cec5SDimitry Andric uint64_t AndMask = 0; 24360b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, AndMask)) 24370b57cec5SDimitry Andric return false; 24380b57cec5SDimitry Andric 24390b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 24400b57cec5SDimitry Andric 24410b57cec5SDimitry Andric uint64_t SrlImm = 0; 24420b57cec5SDimitry Andric if (!isIntImmediate(N->getOperand(1), SrlImm)) 24430b57cec5SDimitry Andric return false; 24440b57cec5SDimitry Andric 24450b57cec5SDimitry Andric // Check whether we really have several bits extract here. 2446bdd1243dSDimitry Andric if (!isMask_64(AndMask >> SrlImm)) 24470b57cec5SDimitry Andric return false; 2448bdd1243dSDimitry Andric 2449bdd1243dSDimitry Andric Opc = N->getValueType(0) == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri; 2450bdd1243dSDimitry Andric LSB = SrlImm; 245106c3fb27SDimitry Andric MSB = llvm::Log2_64(AndMask); 2452bdd1243dSDimitry Andric return true; 24530b57cec5SDimitry Andric } 24540b57cec5SDimitry Andric 24550b57cec5SDimitry Andric static bool isBitfieldExtractOpFromShr(SDNode *N, unsigned &Opc, SDValue &Opd0, 24560b57cec5SDimitry Andric unsigned &Immr, unsigned &Imms, 24570b57cec5SDimitry Andric bool BiggerPattern) { 24580b57cec5SDimitry Andric assert((N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL) && 24590b57cec5SDimitry Andric "N must be a SHR/SRA operation to call this function"); 24600b57cec5SDimitry Andric 24610b57cec5SDimitry Andric EVT VT = N->getValueType(0); 24620b57cec5SDimitry Andric 24630b57cec5SDimitry Andric // Here we can test the type of VT and return false when the type does not 24640b57cec5SDimitry Andric // match, but since it is done prior to that call in the current context 24650b57cec5SDimitry Andric // we turned that into an assert to avoid redundant code. 24660b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 24670b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 24680b57cec5SDimitry Andric 24690b57cec5SDimitry Andric // Check for AND + SRL doing several bits extract. 24700b57cec5SDimitry Andric if (isSeveralBitsExtractOpFromShr(N, Opc, Opd0, Immr, Imms)) 24710b57cec5SDimitry Andric return true; 24720b57cec5SDimitry Andric 24730b57cec5SDimitry Andric // We're looking for a shift of a shift. 24740b57cec5SDimitry Andric uint64_t ShlImm = 0; 24750b57cec5SDimitry Andric uint64_t TruncBits = 0; 24760b57cec5SDimitry Andric if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, ShlImm)) { 24770b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 24780b57cec5SDimitry Andric } else if (VT == MVT::i32 && N->getOpcode() == ISD::SRL && 24790b57cec5SDimitry Andric N->getOperand(0).getNode()->getOpcode() == ISD::TRUNCATE) { 24800b57cec5SDimitry Andric // We are looking for a shift of truncate. Truncate from i64 to i32 could 24810b57cec5SDimitry Andric // be considered as setting high 32 bits as zero. Our strategy here is to 24820b57cec5SDimitry Andric // always generate 64bit UBFM. This consistency will help the CSE pass 24830b57cec5SDimitry Andric // later find more redundancy. 24840b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 24850b57cec5SDimitry Andric TruncBits = Opd0->getValueType(0).getSizeInBits() - VT.getSizeInBits(); 24860b57cec5SDimitry Andric VT = Opd0.getValueType(); 24870b57cec5SDimitry Andric assert(VT == MVT::i64 && "the promoted type should be i64"); 24880b57cec5SDimitry Andric } else if (BiggerPattern) { 24890b57cec5SDimitry Andric // Let's pretend a 0 shift left has been performed. 24900b57cec5SDimitry Andric // FIXME: Currently we limit this to the bigger pattern case, 24910b57cec5SDimitry Andric // because some optimizations expect AND and not UBFM 24920b57cec5SDimitry Andric Opd0 = N->getOperand(0); 24930b57cec5SDimitry Andric } else 24940b57cec5SDimitry Andric return false; 24950b57cec5SDimitry Andric 24960b57cec5SDimitry Andric // Missing combines/constant folding may have left us with strange 24970b57cec5SDimitry Andric // constants. 24980b57cec5SDimitry Andric if (ShlImm >= VT.getSizeInBits()) { 24990b57cec5SDimitry Andric LLVM_DEBUG( 25000b57cec5SDimitry Andric (dbgs() << N 25010b57cec5SDimitry Andric << ": Found large shift immediate, this should not happen\n")); 25020b57cec5SDimitry Andric return false; 25030b57cec5SDimitry Andric } 25040b57cec5SDimitry Andric 25050b57cec5SDimitry Andric uint64_t SrlImm = 0; 25060b57cec5SDimitry Andric if (!isIntImmediate(N->getOperand(1), SrlImm)) 25070b57cec5SDimitry Andric return false; 25080b57cec5SDimitry Andric 25090b57cec5SDimitry Andric assert(SrlImm > 0 && SrlImm < VT.getSizeInBits() && 25100b57cec5SDimitry Andric "bad amount in shift node!"); 25110b57cec5SDimitry Andric int immr = SrlImm - ShlImm; 25120b57cec5SDimitry Andric Immr = immr < 0 ? immr + VT.getSizeInBits() : immr; 25130b57cec5SDimitry Andric Imms = VT.getSizeInBits() - ShlImm - TruncBits - 1; 25140b57cec5SDimitry Andric // SRA requires a signed extraction 25150b57cec5SDimitry Andric if (VT == MVT::i32) 25160b57cec5SDimitry Andric Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMWri : AArch64::UBFMWri; 25170b57cec5SDimitry Andric else 25180b57cec5SDimitry Andric Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMXri : AArch64::UBFMXri; 25190b57cec5SDimitry Andric return true; 25200b57cec5SDimitry Andric } 25210b57cec5SDimitry Andric 25220b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldExtractOpFromSExt(SDNode *N) { 25230b57cec5SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND); 25240b57cec5SDimitry Andric 25250b57cec5SDimitry Andric EVT VT = N->getValueType(0); 25260b57cec5SDimitry Andric EVT NarrowVT = N->getOperand(0)->getValueType(0); 25270b57cec5SDimitry Andric if (VT != MVT::i64 || NarrowVT != MVT::i32) 25280b57cec5SDimitry Andric return false; 25290b57cec5SDimitry Andric 25300b57cec5SDimitry Andric uint64_t ShiftImm; 25310b57cec5SDimitry Andric SDValue Op = N->getOperand(0); 25320b57cec5SDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm)) 25330b57cec5SDimitry Andric return false; 25340b57cec5SDimitry Andric 25350b57cec5SDimitry Andric SDLoc dl(N); 25360b57cec5SDimitry Andric // Extend the incoming operand of the shift to 64-bits. 25370b57cec5SDimitry Andric SDValue Opd0 = Widen(CurDAG, Op.getOperand(0)); 25380b57cec5SDimitry Andric unsigned Immr = ShiftImm; 25390b57cec5SDimitry Andric unsigned Imms = NarrowVT.getSizeInBits() - 1; 25400b57cec5SDimitry Andric SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT), 25410b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, VT)}; 25420b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, AArch64::SBFMXri, VT, Ops); 25430b57cec5SDimitry Andric return true; 25440b57cec5SDimitry Andric } 25450b57cec5SDimitry Andric 25460b57cec5SDimitry Andric static bool isBitfieldExtractOp(SelectionDAG *CurDAG, SDNode *N, unsigned &Opc, 25470b57cec5SDimitry Andric SDValue &Opd0, unsigned &Immr, unsigned &Imms, 25480b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits = 0, 25490b57cec5SDimitry Andric bool BiggerPattern = false) { 25500b57cec5SDimitry Andric if (N->getValueType(0) != MVT::i32 && N->getValueType(0) != MVT::i64) 25510b57cec5SDimitry Andric return false; 25520b57cec5SDimitry Andric 25530b57cec5SDimitry Andric switch (N->getOpcode()) { 25540b57cec5SDimitry Andric default: 25550b57cec5SDimitry Andric if (!N->isMachineOpcode()) 25560b57cec5SDimitry Andric return false; 25570b57cec5SDimitry Andric break; 25580b57cec5SDimitry Andric case ISD::AND: 25590b57cec5SDimitry Andric return isBitfieldExtractOpFromAnd(CurDAG, N, Opc, Opd0, Immr, Imms, 25600b57cec5SDimitry Andric NumberOfIgnoredLowBits, BiggerPattern); 25610b57cec5SDimitry Andric case ISD::SRL: 25620b57cec5SDimitry Andric case ISD::SRA: 25630b57cec5SDimitry Andric return isBitfieldExtractOpFromShr(N, Opc, Opd0, Immr, Imms, BiggerPattern); 25640b57cec5SDimitry Andric 25650b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 25660b57cec5SDimitry Andric return isBitfieldExtractOpFromSExtInReg(N, Opc, Opd0, Immr, Imms); 25670b57cec5SDimitry Andric } 25680b57cec5SDimitry Andric 25690b57cec5SDimitry Andric unsigned NOpc = N->getMachineOpcode(); 25700b57cec5SDimitry Andric switch (NOpc) { 25710b57cec5SDimitry Andric default: 25720b57cec5SDimitry Andric return false; 25730b57cec5SDimitry Andric case AArch64::SBFMWri: 25740b57cec5SDimitry Andric case AArch64::UBFMWri: 25750b57cec5SDimitry Andric case AArch64::SBFMXri: 25760b57cec5SDimitry Andric case AArch64::UBFMXri: 25770b57cec5SDimitry Andric Opc = NOpc; 25780b57cec5SDimitry Andric Opd0 = N->getOperand(0); 25790b57cec5SDimitry Andric Immr = cast<ConstantSDNode>(N->getOperand(1).getNode())->getZExtValue(); 25800b57cec5SDimitry Andric Imms = cast<ConstantSDNode>(N->getOperand(2).getNode())->getZExtValue(); 25810b57cec5SDimitry Andric return true; 25820b57cec5SDimitry Andric } 25830b57cec5SDimitry Andric // Unreachable 25840b57cec5SDimitry Andric return false; 25850b57cec5SDimitry Andric } 25860b57cec5SDimitry Andric 25870b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldExtractOp(SDNode *N) { 25880b57cec5SDimitry Andric unsigned Opc, Immr, Imms; 25890b57cec5SDimitry Andric SDValue Opd0; 25900b57cec5SDimitry Andric if (!isBitfieldExtractOp(CurDAG, N, Opc, Opd0, Immr, Imms)) 25910b57cec5SDimitry Andric return false; 25920b57cec5SDimitry Andric 25930b57cec5SDimitry Andric EVT VT = N->getValueType(0); 25940b57cec5SDimitry Andric SDLoc dl(N); 25950b57cec5SDimitry Andric 25960b57cec5SDimitry Andric // If the bit extract operation is 64bit but the original type is 32bit, we 25970b57cec5SDimitry Andric // need to add one EXTRACT_SUBREG. 25980b57cec5SDimitry Andric if ((Opc == AArch64::SBFMXri || Opc == AArch64::UBFMXri) && VT == MVT::i32) { 25990b57cec5SDimitry Andric SDValue Ops64[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, MVT::i64), 26000b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, MVT::i64)}; 26010b57cec5SDimitry Andric 26020b57cec5SDimitry Andric SDNode *BFM = CurDAG->getMachineNode(Opc, dl, MVT::i64, Ops64); 260306c3fb27SDimitry Andric SDValue Inner = CurDAG->getTargetExtractSubreg(AArch64::sub_32, dl, 260406c3fb27SDimitry Andric MVT::i32, SDValue(BFM, 0)); 260506c3fb27SDimitry Andric ReplaceNode(N, Inner.getNode()); 26060b57cec5SDimitry Andric return true; 26070b57cec5SDimitry Andric } 26080b57cec5SDimitry Andric 26090b57cec5SDimitry Andric SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT), 26100b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, VT)}; 26110b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 26120b57cec5SDimitry Andric return true; 26130b57cec5SDimitry Andric } 26140b57cec5SDimitry Andric 26150b57cec5SDimitry Andric /// Does DstMask form a complementary pair with the mask provided by 26160b57cec5SDimitry Andric /// BitsToBeInserted, suitable for use in a BFI instruction. Roughly speaking, 26170b57cec5SDimitry Andric /// this asks whether DstMask zeroes precisely those bits that will be set by 26180b57cec5SDimitry Andric /// the other half. 26190b57cec5SDimitry Andric static bool isBitfieldDstMask(uint64_t DstMask, const APInt &BitsToBeInserted, 26200b57cec5SDimitry Andric unsigned NumberOfIgnoredHighBits, EVT VT) { 26210b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 26220b57cec5SDimitry Andric "i32 or i64 mask type expected!"); 26230b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits() - NumberOfIgnoredHighBits; 26240b57cec5SDimitry Andric 26250b57cec5SDimitry Andric APInt SignificantDstMask = APInt(BitWidth, DstMask); 26260b57cec5SDimitry Andric APInt SignificantBitsToBeInserted = BitsToBeInserted.zextOrTrunc(BitWidth); 26270b57cec5SDimitry Andric 26280b57cec5SDimitry Andric return (SignificantDstMask & SignificantBitsToBeInserted) == 0 && 2629349cc55cSDimitry Andric (SignificantDstMask | SignificantBitsToBeInserted).isAllOnes(); 26300b57cec5SDimitry Andric } 26310b57cec5SDimitry Andric 26320b57cec5SDimitry Andric // Look for bits that will be useful for later uses. 26330b57cec5SDimitry Andric // A bit is consider useless as soon as it is dropped and never used 26340b57cec5SDimitry Andric // before it as been dropped. 26350b57cec5SDimitry Andric // E.g., looking for useful bit of x 26360b57cec5SDimitry Andric // 1. y = x & 0x7 26370b57cec5SDimitry Andric // 2. z = y >> 2 26380b57cec5SDimitry Andric // After #1, x useful bits are 0x7, then the useful bits of x, live through 26390b57cec5SDimitry Andric // y. 26400b57cec5SDimitry Andric // After #2, the useful bits of x are 0x4. 26410b57cec5SDimitry Andric // However, if x is used on an unpredicatable instruction, then all its bits 26420b57cec5SDimitry Andric // are useful. 26430b57cec5SDimitry Andric // E.g. 26440b57cec5SDimitry Andric // 1. y = x & 0x7 26450b57cec5SDimitry Andric // 2. z = y >> 2 26460b57cec5SDimitry Andric // 3. str x, [@x] 26470b57cec5SDimitry Andric static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth = 0); 26480b57cec5SDimitry Andric 26490b57cec5SDimitry Andric static void getUsefulBitsFromAndWithImmediate(SDValue Op, APInt &UsefulBits, 26500b57cec5SDimitry Andric unsigned Depth) { 26510b57cec5SDimitry Andric uint64_t Imm = 26520b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue(); 26530b57cec5SDimitry Andric Imm = AArch64_AM::decodeLogicalImmediate(Imm, UsefulBits.getBitWidth()); 26540b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), Imm); 26550b57cec5SDimitry Andric getUsefulBits(Op, UsefulBits, Depth + 1); 26560b57cec5SDimitry Andric } 26570b57cec5SDimitry Andric 26580b57cec5SDimitry Andric static void getUsefulBitsFromBitfieldMoveOpd(SDValue Op, APInt &UsefulBits, 26590b57cec5SDimitry Andric uint64_t Imm, uint64_t MSB, 26600b57cec5SDimitry Andric unsigned Depth) { 26610b57cec5SDimitry Andric // inherit the bitwidth value 26620b57cec5SDimitry Andric APInt OpUsefulBits(UsefulBits); 26630b57cec5SDimitry Andric OpUsefulBits = 1; 26640b57cec5SDimitry Andric 26650b57cec5SDimitry Andric if (MSB >= Imm) { 26660b57cec5SDimitry Andric OpUsefulBits <<= MSB - Imm + 1; 26670b57cec5SDimitry Andric --OpUsefulBits; 26680b57cec5SDimitry Andric // The interesting part will be in the lower part of the result 26690b57cec5SDimitry Andric getUsefulBits(Op, OpUsefulBits, Depth + 1); 26700b57cec5SDimitry Andric // The interesting part was starting at Imm in the argument 26710b57cec5SDimitry Andric OpUsefulBits <<= Imm; 26720b57cec5SDimitry Andric } else { 26730b57cec5SDimitry Andric OpUsefulBits <<= MSB + 1; 26740b57cec5SDimitry Andric --OpUsefulBits; 26750b57cec5SDimitry Andric // The interesting part will be shifted in the result 26760b57cec5SDimitry Andric OpUsefulBits <<= OpUsefulBits.getBitWidth() - Imm; 26770b57cec5SDimitry Andric getUsefulBits(Op, OpUsefulBits, Depth + 1); 26780b57cec5SDimitry Andric // The interesting part was at zero in the argument 26790b57cec5SDimitry Andric OpUsefulBits.lshrInPlace(OpUsefulBits.getBitWidth() - Imm); 26800b57cec5SDimitry Andric } 26810b57cec5SDimitry Andric 26820b57cec5SDimitry Andric UsefulBits &= OpUsefulBits; 26830b57cec5SDimitry Andric } 26840b57cec5SDimitry Andric 26850b57cec5SDimitry Andric static void getUsefulBitsFromUBFM(SDValue Op, APInt &UsefulBits, 26860b57cec5SDimitry Andric unsigned Depth) { 26870b57cec5SDimitry Andric uint64_t Imm = 26880b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue(); 26890b57cec5SDimitry Andric uint64_t MSB = 26900b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 26910b57cec5SDimitry Andric 26920b57cec5SDimitry Andric getUsefulBitsFromBitfieldMoveOpd(Op, UsefulBits, Imm, MSB, Depth); 26930b57cec5SDimitry Andric } 26940b57cec5SDimitry Andric 26950b57cec5SDimitry Andric static void getUsefulBitsFromOrWithShiftedReg(SDValue Op, APInt &UsefulBits, 26960b57cec5SDimitry Andric unsigned Depth) { 26970b57cec5SDimitry Andric uint64_t ShiftTypeAndValue = 26980b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 26990b57cec5SDimitry Andric APInt Mask(UsefulBits); 27000b57cec5SDimitry Andric Mask.clearAllBits(); 27010b57cec5SDimitry Andric Mask.flipAllBits(); 27020b57cec5SDimitry Andric 27030b57cec5SDimitry Andric if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSL) { 27040b57cec5SDimitry Andric // Shift Left 27050b57cec5SDimitry Andric uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue); 27060b57cec5SDimitry Andric Mask <<= ShiftAmt; 27070b57cec5SDimitry Andric getUsefulBits(Op, Mask, Depth + 1); 27080b57cec5SDimitry Andric Mask.lshrInPlace(ShiftAmt); 27090b57cec5SDimitry Andric } else if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSR) { 27100b57cec5SDimitry Andric // Shift Right 27110b57cec5SDimitry Andric // We do not handle AArch64_AM::ASR, because the sign will change the 27120b57cec5SDimitry Andric // number of useful bits 27130b57cec5SDimitry Andric uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue); 27140b57cec5SDimitry Andric Mask.lshrInPlace(ShiftAmt); 27150b57cec5SDimitry Andric getUsefulBits(Op, Mask, Depth + 1); 27160b57cec5SDimitry Andric Mask <<= ShiftAmt; 27170b57cec5SDimitry Andric } else 27180b57cec5SDimitry Andric return; 27190b57cec5SDimitry Andric 27200b57cec5SDimitry Andric UsefulBits &= Mask; 27210b57cec5SDimitry Andric } 27220b57cec5SDimitry Andric 27230b57cec5SDimitry Andric static void getUsefulBitsFromBFM(SDValue Op, SDValue Orig, APInt &UsefulBits, 27240b57cec5SDimitry Andric unsigned Depth) { 27250b57cec5SDimitry Andric uint64_t Imm = 27260b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 27270b57cec5SDimitry Andric uint64_t MSB = 27280b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(3).getNode())->getZExtValue(); 27290b57cec5SDimitry Andric 27300b57cec5SDimitry Andric APInt OpUsefulBits(UsefulBits); 27310b57cec5SDimitry Andric OpUsefulBits = 1; 27320b57cec5SDimitry Andric 27330b57cec5SDimitry Andric APInt ResultUsefulBits(UsefulBits.getBitWidth(), 0); 27340b57cec5SDimitry Andric ResultUsefulBits.flipAllBits(); 27350b57cec5SDimitry Andric APInt Mask(UsefulBits.getBitWidth(), 0); 27360b57cec5SDimitry Andric 27370b57cec5SDimitry Andric getUsefulBits(Op, ResultUsefulBits, Depth + 1); 27380b57cec5SDimitry Andric 27390b57cec5SDimitry Andric if (MSB >= Imm) { 27400b57cec5SDimitry Andric // The instruction is a BFXIL. 27410b57cec5SDimitry Andric uint64_t Width = MSB - Imm + 1; 27420b57cec5SDimitry Andric uint64_t LSB = Imm; 27430b57cec5SDimitry Andric 27440b57cec5SDimitry Andric OpUsefulBits <<= Width; 27450b57cec5SDimitry Andric --OpUsefulBits; 27460b57cec5SDimitry Andric 27470b57cec5SDimitry Andric if (Op.getOperand(1) == Orig) { 27480b57cec5SDimitry Andric // Copy the low bits from the result to bits starting from LSB. 27490b57cec5SDimitry Andric Mask = ResultUsefulBits & OpUsefulBits; 27500b57cec5SDimitry Andric Mask <<= LSB; 27510b57cec5SDimitry Andric } 27520b57cec5SDimitry Andric 27530b57cec5SDimitry Andric if (Op.getOperand(0) == Orig) 27540b57cec5SDimitry Andric // Bits starting from LSB in the input contribute to the result. 27550b57cec5SDimitry Andric Mask |= (ResultUsefulBits & ~OpUsefulBits); 27560b57cec5SDimitry Andric } else { 27570b57cec5SDimitry Andric // The instruction is a BFI. 27580b57cec5SDimitry Andric uint64_t Width = MSB + 1; 27590b57cec5SDimitry Andric uint64_t LSB = UsefulBits.getBitWidth() - Imm; 27600b57cec5SDimitry Andric 27610b57cec5SDimitry Andric OpUsefulBits <<= Width; 27620b57cec5SDimitry Andric --OpUsefulBits; 27630b57cec5SDimitry Andric OpUsefulBits <<= LSB; 27640b57cec5SDimitry Andric 27650b57cec5SDimitry Andric if (Op.getOperand(1) == Orig) { 27660b57cec5SDimitry Andric // Copy the bits from the result to the zero bits. 27670b57cec5SDimitry Andric Mask = ResultUsefulBits & OpUsefulBits; 27680b57cec5SDimitry Andric Mask.lshrInPlace(LSB); 27690b57cec5SDimitry Andric } 27700b57cec5SDimitry Andric 27710b57cec5SDimitry Andric if (Op.getOperand(0) == Orig) 27720b57cec5SDimitry Andric Mask |= (ResultUsefulBits & ~OpUsefulBits); 27730b57cec5SDimitry Andric } 27740b57cec5SDimitry Andric 27750b57cec5SDimitry Andric UsefulBits &= Mask; 27760b57cec5SDimitry Andric } 27770b57cec5SDimitry Andric 27780b57cec5SDimitry Andric static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits, 27790b57cec5SDimitry Andric SDValue Orig, unsigned Depth) { 27800b57cec5SDimitry Andric 27810b57cec5SDimitry Andric // Users of this node should have already been instruction selected 27820b57cec5SDimitry Andric // FIXME: Can we turn that into an assert? 27830b57cec5SDimitry Andric if (!UserNode->isMachineOpcode()) 27840b57cec5SDimitry Andric return; 27850b57cec5SDimitry Andric 27860b57cec5SDimitry Andric switch (UserNode->getMachineOpcode()) { 27870b57cec5SDimitry Andric default: 27880b57cec5SDimitry Andric return; 27890b57cec5SDimitry Andric case AArch64::ANDSWri: 27900b57cec5SDimitry Andric case AArch64::ANDSXri: 27910b57cec5SDimitry Andric case AArch64::ANDWri: 27920b57cec5SDimitry Andric case AArch64::ANDXri: 27930b57cec5SDimitry Andric // We increment Depth only when we call the getUsefulBits 27940b57cec5SDimitry Andric return getUsefulBitsFromAndWithImmediate(SDValue(UserNode, 0), UsefulBits, 27950b57cec5SDimitry Andric Depth); 27960b57cec5SDimitry Andric case AArch64::UBFMWri: 27970b57cec5SDimitry Andric case AArch64::UBFMXri: 27980b57cec5SDimitry Andric return getUsefulBitsFromUBFM(SDValue(UserNode, 0), UsefulBits, Depth); 27990b57cec5SDimitry Andric 28000b57cec5SDimitry Andric case AArch64::ORRWrs: 28010b57cec5SDimitry Andric case AArch64::ORRXrs: 2802fe6060f1SDimitry Andric if (UserNode->getOperand(0) != Orig && UserNode->getOperand(1) == Orig) 2803fe6060f1SDimitry Andric getUsefulBitsFromOrWithShiftedReg(SDValue(UserNode, 0), UsefulBits, 28040b57cec5SDimitry Andric Depth); 2805fe6060f1SDimitry Andric return; 28060b57cec5SDimitry Andric case AArch64::BFMWri: 28070b57cec5SDimitry Andric case AArch64::BFMXri: 28080b57cec5SDimitry Andric return getUsefulBitsFromBFM(SDValue(UserNode, 0), Orig, UsefulBits, Depth); 28090b57cec5SDimitry Andric 28100b57cec5SDimitry Andric case AArch64::STRBBui: 28110b57cec5SDimitry Andric case AArch64::STURBBi: 28120b57cec5SDimitry Andric if (UserNode->getOperand(0) != Orig) 28130b57cec5SDimitry Andric return; 28140b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xff); 28150b57cec5SDimitry Andric return; 28160b57cec5SDimitry Andric 28170b57cec5SDimitry Andric case AArch64::STRHHui: 28180b57cec5SDimitry Andric case AArch64::STURHHi: 28190b57cec5SDimitry Andric if (UserNode->getOperand(0) != Orig) 28200b57cec5SDimitry Andric return; 28210b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xffff); 28220b57cec5SDimitry Andric return; 28230b57cec5SDimitry Andric } 28240b57cec5SDimitry Andric } 28250b57cec5SDimitry Andric 28260b57cec5SDimitry Andric static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth) { 28278bcb0991SDimitry Andric if (Depth >= SelectionDAG::MaxRecursionDepth) 28280b57cec5SDimitry Andric return; 28290b57cec5SDimitry Andric // Initialize UsefulBits 28300b57cec5SDimitry Andric if (!Depth) { 28310b57cec5SDimitry Andric unsigned Bitwidth = Op.getScalarValueSizeInBits(); 28320b57cec5SDimitry Andric // At the beginning, assume every produced bits is useful 28330b57cec5SDimitry Andric UsefulBits = APInt(Bitwidth, 0); 28340b57cec5SDimitry Andric UsefulBits.flipAllBits(); 28350b57cec5SDimitry Andric } 28360b57cec5SDimitry Andric APInt UsersUsefulBits(UsefulBits.getBitWidth(), 0); 28370b57cec5SDimitry Andric 28380b57cec5SDimitry Andric for (SDNode *Node : Op.getNode()->uses()) { 28390b57cec5SDimitry Andric // A use cannot produce useful bits 28400b57cec5SDimitry Andric APInt UsefulBitsForUse = APInt(UsefulBits); 28410b57cec5SDimitry Andric getUsefulBitsForUse(Node, UsefulBitsForUse, Op, Depth); 28420b57cec5SDimitry Andric UsersUsefulBits |= UsefulBitsForUse; 28430b57cec5SDimitry Andric } 28440b57cec5SDimitry Andric // UsefulBits contains the produced bits that are meaningful for the 28450b57cec5SDimitry Andric // current definition, thus a user cannot make a bit meaningful at 28460b57cec5SDimitry Andric // this point 28470b57cec5SDimitry Andric UsefulBits &= UsersUsefulBits; 28480b57cec5SDimitry Andric } 28490b57cec5SDimitry Andric 28500b57cec5SDimitry Andric /// Create a machine node performing a notional SHL of Op by ShlAmount. If 28510b57cec5SDimitry Andric /// ShlAmount is negative, do a (logical) right-shift instead. If ShlAmount is 28520b57cec5SDimitry Andric /// 0, return Op unchanged. 28530b57cec5SDimitry Andric static SDValue getLeftShift(SelectionDAG *CurDAG, SDValue Op, int ShlAmount) { 28540b57cec5SDimitry Andric if (ShlAmount == 0) 28550b57cec5SDimitry Andric return Op; 28560b57cec5SDimitry Andric 28570b57cec5SDimitry Andric EVT VT = Op.getValueType(); 28580b57cec5SDimitry Andric SDLoc dl(Op); 28590b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 28600b57cec5SDimitry Andric unsigned UBFMOpc = BitWidth == 32 ? AArch64::UBFMWri : AArch64::UBFMXri; 28610b57cec5SDimitry Andric 28620b57cec5SDimitry Andric SDNode *ShiftNode; 28630b57cec5SDimitry Andric if (ShlAmount > 0) { 28640b57cec5SDimitry Andric // LSL wD, wN, #Amt == UBFM wD, wN, #32-Amt, #31-Amt 28650b57cec5SDimitry Andric ShiftNode = CurDAG->getMachineNode( 28660b57cec5SDimitry Andric UBFMOpc, dl, VT, Op, 28670b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - ShlAmount, dl, VT), 28680b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1 - ShlAmount, dl, VT)); 28690b57cec5SDimitry Andric } else { 28700b57cec5SDimitry Andric // LSR wD, wN, #Amt == UBFM wD, wN, #Amt, #32-1 28710b57cec5SDimitry Andric assert(ShlAmount < 0 && "expected right shift"); 28720b57cec5SDimitry Andric int ShrAmount = -ShlAmount; 28730b57cec5SDimitry Andric ShiftNode = CurDAG->getMachineNode( 28740b57cec5SDimitry Andric UBFMOpc, dl, VT, Op, CurDAG->getTargetConstant(ShrAmount, dl, VT), 28750b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1, dl, VT)); 28760b57cec5SDimitry Andric } 28770b57cec5SDimitry Andric 28780b57cec5SDimitry Andric return SDValue(ShiftNode, 0); 28790b57cec5SDimitry Andric } 28800b57cec5SDimitry Andric 2881bdd1243dSDimitry Andric // For bit-field-positioning pattern "(and (shl VAL, N), ShiftedMask)". 2882bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, 28830b57cec5SDimitry Andric bool BiggerPattern, 2884bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2885bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2886bdd1243dSDimitry Andric int &Width); 2887bdd1243dSDimitry Andric 2888bdd1243dSDimitry Andric // For bit-field-positioning pattern "shl VAL, N)". 2889bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, 2890bdd1243dSDimitry Andric bool BiggerPattern, 2891bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2892bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2893bdd1243dSDimitry Andric int &Width); 2894bdd1243dSDimitry Andric 2895bdd1243dSDimitry Andric /// Does this tree qualify as an attempt to move a bitfield into position, 2896bdd1243dSDimitry Andric /// essentially "(and (shl VAL, N), Mask)" or (shl VAL, N). 2897bdd1243dSDimitry Andric static bool isBitfieldPositioningOp(SelectionDAG *CurDAG, SDValue Op, 2898bdd1243dSDimitry Andric bool BiggerPattern, SDValue &Src, 2899bdd1243dSDimitry Andric int &DstLSB, int &Width) { 29000b57cec5SDimitry Andric EVT VT = Op.getValueType(); 29010b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 29020b57cec5SDimitry Andric (void)BitWidth; 29030b57cec5SDimitry Andric assert(BitWidth == 32 || BitWidth == 64); 29040b57cec5SDimitry Andric 29050b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(Op); 29060b57cec5SDimitry Andric 29070b57cec5SDimitry Andric // Non-zero in the sense that they're not provably zero, which is the key 29080b57cec5SDimitry Andric // point if we want to use this value 2909bdd1243dSDimitry Andric const uint64_t NonZeroBits = (~Known.Zero).getZExtValue(); 29100b57cec5SDimitry Andric if (!isShiftedMask_64(NonZeroBits)) 29110b57cec5SDimitry Andric return false; 29120b57cec5SDimitry Andric 2913bdd1243dSDimitry Andric switch (Op.getOpcode()) { 2914bdd1243dSDimitry Andric default: 2915bdd1243dSDimitry Andric break; 2916bdd1243dSDimitry Andric case ISD::AND: 2917bdd1243dSDimitry Andric return isBitfieldPositioningOpFromAnd(CurDAG, Op, BiggerPattern, 2918bdd1243dSDimitry Andric NonZeroBits, Src, DstLSB, Width); 2919bdd1243dSDimitry Andric case ISD::SHL: 2920bdd1243dSDimitry Andric return isBitfieldPositioningOpFromShl(CurDAG, Op, BiggerPattern, 2921bdd1243dSDimitry Andric NonZeroBits, Src, DstLSB, Width); 2922bdd1243dSDimitry Andric } 2923bdd1243dSDimitry Andric 2924bdd1243dSDimitry Andric return false; 2925bdd1243dSDimitry Andric } 2926bdd1243dSDimitry Andric 2927bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, 2928bdd1243dSDimitry Andric bool BiggerPattern, 2929bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2930bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2931bdd1243dSDimitry Andric int &Width) { 2932bdd1243dSDimitry Andric assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed"); 2933bdd1243dSDimitry Andric 2934bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 2935bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 2936bdd1243dSDimitry Andric "Caller guarantees VT is one of i32 or i64"); 2937bdd1243dSDimitry Andric (void)VT; 2938bdd1243dSDimitry Andric 2939bdd1243dSDimitry Andric uint64_t AndImm; 2940bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::AND, AndImm)) 2941bdd1243dSDimitry Andric return false; 2942bdd1243dSDimitry Andric 2943bdd1243dSDimitry Andric // If (~AndImm & NonZeroBits) is not zero at POS, we know that 2944bdd1243dSDimitry Andric // 1) (AndImm & (1 << POS) == 0) 2945bdd1243dSDimitry Andric // 2) the result of AND is not zero at POS bit (according to NonZeroBits) 2946bdd1243dSDimitry Andric // 2947bdd1243dSDimitry Andric // 1) and 2) don't agree so something must be wrong (e.g., in 2948bdd1243dSDimitry Andric // 'SelectionDAG::computeKnownBits') 2949bdd1243dSDimitry Andric assert((~AndImm & NonZeroBits) == 0 && 2950bdd1243dSDimitry Andric "Something must be wrong (e.g., in SelectionDAG::computeKnownBits)"); 2951bdd1243dSDimitry Andric 2952bdd1243dSDimitry Andric SDValue AndOp0 = Op.getOperand(0); 2953bdd1243dSDimitry Andric 2954bdd1243dSDimitry Andric uint64_t ShlImm; 2955bdd1243dSDimitry Andric SDValue ShlOp0; 2956bdd1243dSDimitry Andric if (isOpcWithIntImmediate(AndOp0.getNode(), ISD::SHL, ShlImm)) { 2957bdd1243dSDimitry Andric // For pattern "and(shl(val, N), shifted-mask)", 'ShlOp0' is set to 'val'. 2958bdd1243dSDimitry Andric ShlOp0 = AndOp0.getOperand(0); 2959bdd1243dSDimitry Andric } else if (VT == MVT::i64 && AndOp0.getOpcode() == ISD::ANY_EXTEND && 2960bdd1243dSDimitry Andric isOpcWithIntImmediate(AndOp0.getOperand(0).getNode(), ISD::SHL, 2961bdd1243dSDimitry Andric ShlImm)) { 2962bdd1243dSDimitry Andric // For pattern "and(any_extend(shl(val, N)), shifted-mask)" 2963bdd1243dSDimitry Andric 2964bdd1243dSDimitry Andric // ShlVal == shl(val, N), which is a left shift on a smaller type. 2965bdd1243dSDimitry Andric SDValue ShlVal = AndOp0.getOperand(0); 2966bdd1243dSDimitry Andric 2967bdd1243dSDimitry Andric // Since this is after type legalization and ShlVal is extended to MVT::i64, 2968bdd1243dSDimitry Andric // expect VT to be MVT::i32. 2969bdd1243dSDimitry Andric assert((ShlVal.getValueType() == MVT::i32) && "Expect VT to be MVT::i32."); 2970bdd1243dSDimitry Andric 2971bdd1243dSDimitry Andric // Widens 'val' to MVT::i64 as the source of bit field positioning. 2972bdd1243dSDimitry Andric ShlOp0 = Widen(CurDAG, ShlVal.getOperand(0)); 2973bdd1243dSDimitry Andric } else 2974bdd1243dSDimitry Andric return false; 2975bdd1243dSDimitry Andric 2976bdd1243dSDimitry Andric // For !BiggerPattern, bail out if the AndOp0 has more than one use, since 2977bdd1243dSDimitry Andric // then we'll end up generating AndOp0+UBFIZ instead of just keeping 2978bdd1243dSDimitry Andric // AndOp0+AND. 2979bdd1243dSDimitry Andric if (!BiggerPattern && !AndOp0.hasOneUse()) 2980bdd1243dSDimitry Andric return false; 2981bdd1243dSDimitry Andric 298206c3fb27SDimitry Andric DstLSB = llvm::countr_zero(NonZeroBits); 298306c3fb27SDimitry Andric Width = llvm::countr_one(NonZeroBits >> DstLSB); 2984bdd1243dSDimitry Andric 2985bdd1243dSDimitry Andric // Bail out on large Width. This happens when no proper combining / constant 2986bdd1243dSDimitry Andric // folding was performed. 2987bdd1243dSDimitry Andric if (Width >= (int)VT.getSizeInBits()) { 2988bdd1243dSDimitry Andric // If VT is i64, Width > 64 is insensible since NonZeroBits is uint64_t, and 2989bdd1243dSDimitry Andric // Width == 64 indicates a missed dag-combine from "(and val, AllOnes)" to 2990bdd1243dSDimitry Andric // "val". 2991bdd1243dSDimitry Andric // If VT is i32, what Width >= 32 means: 2992bdd1243dSDimitry Andric // - For "(and (any_extend(shl val, N)), shifted-mask)", the`and` Op 2993bdd1243dSDimitry Andric // demands at least 'Width' bits (after dag-combiner). This together with 2994bdd1243dSDimitry Andric // `any_extend` Op (undefined higher bits) indicates missed combination 2995bdd1243dSDimitry Andric // when lowering the 'and' IR instruction to an machine IR instruction. 2996bdd1243dSDimitry Andric LLVM_DEBUG( 2997bdd1243dSDimitry Andric dbgs() 2998bdd1243dSDimitry Andric << "Found large Width in bit-field-positioning -- this indicates no " 2999bdd1243dSDimitry Andric "proper combining / constant folding was performed\n"); 3000bdd1243dSDimitry Andric return false; 3001bdd1243dSDimitry Andric } 30020b57cec5SDimitry Andric 30030b57cec5SDimitry Andric // BFI encompasses sufficiently many nodes that it's worth inserting an extra 30040b57cec5SDimitry Andric // LSL/LSR if the mask in NonZeroBits doesn't quite match up with the ISD::SHL 30050b57cec5SDimitry Andric // amount. BiggerPattern is true when this pattern is being matched for BFI, 30060b57cec5SDimitry Andric // BiggerPattern is false when this pattern is being matched for UBFIZ, in 30070b57cec5SDimitry Andric // which case it is not profitable to insert an extra shift. 3008bdd1243dSDimitry Andric if (ShlImm != uint64_t(DstLSB) && !BiggerPattern) 30090b57cec5SDimitry Andric return false; 30100b57cec5SDimitry Andric 3011bdd1243dSDimitry Andric Src = getLeftShift(CurDAG, ShlOp0, ShlImm - DstLSB); 3012bdd1243dSDimitry Andric return true; 3013bdd1243dSDimitry Andric } 3014bdd1243dSDimitry Andric 3015bdd1243dSDimitry Andric // For node (shl (and val, mask), N)), returns true if the node is equivalent to 3016bdd1243dSDimitry Andric // UBFIZ. 3017bdd1243dSDimitry Andric static bool isSeveralBitsPositioningOpFromShl(const uint64_t ShlImm, SDValue Op, 3018bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 3019bdd1243dSDimitry Andric int &Width) { 3020bdd1243dSDimitry Andric // Caller should have verified that N is a left shift with constant shift 3021bdd1243dSDimitry Andric // amount; asserts that. 3022bdd1243dSDimitry Andric assert(Op.getOpcode() == ISD::SHL && 3023bdd1243dSDimitry Andric "Op.getNode() should be a SHL node to call this function"); 3024bdd1243dSDimitry Andric assert(isIntImmediateEq(Op.getOperand(1), ShlImm) && 3025bdd1243dSDimitry Andric "Op.getNode() should shift ShlImm to call this function"); 3026bdd1243dSDimitry Andric 3027bdd1243dSDimitry Andric uint64_t AndImm = 0; 3028bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 3029bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op0.getNode(), ISD::AND, AndImm)) 3030bdd1243dSDimitry Andric return false; 3031bdd1243dSDimitry Andric 3032bdd1243dSDimitry Andric const uint64_t ShiftedAndImm = ((AndImm << ShlImm) >> ShlImm); 3033bdd1243dSDimitry Andric if (isMask_64(ShiftedAndImm)) { 3034bdd1243dSDimitry Andric // AndImm is a superset of (AllOnes >> ShlImm); in other words, AndImm 3035bdd1243dSDimitry Andric // should end with Mask, and could be prefixed with random bits if those 3036bdd1243dSDimitry Andric // bits are shifted out. 3037bdd1243dSDimitry Andric // 3038bdd1243dSDimitry Andric // For example, xyz11111 (with {x,y,z} being 0 or 1) is fine if ShlImm >= 3; 3039bdd1243dSDimitry Andric // the AND result corresponding to those bits are shifted out, so it's fine 3040bdd1243dSDimitry Andric // to not extract them. 304106c3fb27SDimitry Andric Width = llvm::countr_one(ShiftedAndImm); 3042bdd1243dSDimitry Andric DstLSB = ShlImm; 3043bdd1243dSDimitry Andric Src = Op0.getOperand(0); 3044bdd1243dSDimitry Andric return true; 3045bdd1243dSDimitry Andric } 3046bdd1243dSDimitry Andric return false; 3047bdd1243dSDimitry Andric } 3048bdd1243dSDimitry Andric 3049bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, 3050bdd1243dSDimitry Andric bool BiggerPattern, 3051bdd1243dSDimitry Andric const uint64_t NonZeroBits, 3052bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 3053bdd1243dSDimitry Andric int &Width) { 3054bdd1243dSDimitry Andric assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed"); 3055bdd1243dSDimitry Andric 3056bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 3057bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3058bdd1243dSDimitry Andric "Caller guarantees that type is i32 or i64"); 3059bdd1243dSDimitry Andric (void)VT; 3060bdd1243dSDimitry Andric 3061bdd1243dSDimitry Andric uint64_t ShlImm; 3062bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SHL, ShlImm)) 3063bdd1243dSDimitry Andric return false; 3064bdd1243dSDimitry Andric 3065bdd1243dSDimitry Andric if (!BiggerPattern && !Op.hasOneUse()) 3066bdd1243dSDimitry Andric return false; 3067bdd1243dSDimitry Andric 3068bdd1243dSDimitry Andric if (isSeveralBitsPositioningOpFromShl(ShlImm, Op, Src, DstLSB, Width)) 3069bdd1243dSDimitry Andric return true; 3070bdd1243dSDimitry Andric 307106c3fb27SDimitry Andric DstLSB = llvm::countr_zero(NonZeroBits); 307206c3fb27SDimitry Andric Width = llvm::countr_one(NonZeroBits >> DstLSB); 3073bdd1243dSDimitry Andric 3074bdd1243dSDimitry Andric if (ShlImm != uint64_t(DstLSB) && !BiggerPattern) 3075bdd1243dSDimitry Andric return false; 3076bdd1243dSDimitry Andric 3077bdd1243dSDimitry Andric Src = getLeftShift(CurDAG, Op.getOperand(0), ShlImm - DstLSB); 30780b57cec5SDimitry Andric return true; 30790b57cec5SDimitry Andric } 30800b57cec5SDimitry Andric 30810b57cec5SDimitry Andric static bool isShiftedMask(uint64_t Mask, EVT VT) { 30820b57cec5SDimitry Andric assert(VT == MVT::i32 || VT == MVT::i64); 30830b57cec5SDimitry Andric if (VT == MVT::i32) 30840b57cec5SDimitry Andric return isShiftedMask_32(Mask); 30850b57cec5SDimitry Andric return isShiftedMask_64(Mask); 30860b57cec5SDimitry Andric } 30870b57cec5SDimitry Andric 30880b57cec5SDimitry Andric // Generate a BFI/BFXIL from 'or (and X, MaskImm), OrImm' iff the value being 30890b57cec5SDimitry Andric // inserted only sets known zero bits. 30900b57cec5SDimitry Andric static bool tryBitfieldInsertOpFromOrAndImm(SDNode *N, SelectionDAG *CurDAG) { 30910b57cec5SDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); 30920b57cec5SDimitry Andric 30930b57cec5SDimitry Andric EVT VT = N->getValueType(0); 30940b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 30950b57cec5SDimitry Andric return false; 30960b57cec5SDimitry Andric 30970b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 30980b57cec5SDimitry Andric 30990b57cec5SDimitry Andric uint64_t OrImm; 31000b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N, ISD::OR, OrImm)) 31010b57cec5SDimitry Andric return false; 31020b57cec5SDimitry Andric 31030b57cec5SDimitry Andric // Skip this transformation if the ORR immediate can be encoded in the ORR. 31040b57cec5SDimitry Andric // Otherwise, we'll trade an AND+ORR for ORR+BFI/BFXIL, which is most likely 31050b57cec5SDimitry Andric // performance neutral. 31060b57cec5SDimitry Andric if (AArch64_AM::isLogicalImmediate(OrImm, BitWidth)) 31070b57cec5SDimitry Andric return false; 31080b57cec5SDimitry Andric 31090b57cec5SDimitry Andric uint64_t MaskImm; 31100b57cec5SDimitry Andric SDValue And = N->getOperand(0); 31110b57cec5SDimitry Andric // Must be a single use AND with an immediate operand. 31120b57cec5SDimitry Andric if (!And.hasOneUse() || 31130b57cec5SDimitry Andric !isOpcWithIntImmediate(And.getNode(), ISD::AND, MaskImm)) 31140b57cec5SDimitry Andric return false; 31150b57cec5SDimitry Andric 31160b57cec5SDimitry Andric // Compute the Known Zero for the AND as this allows us to catch more general 31170b57cec5SDimitry Andric // cases than just looking for AND with imm. 31180b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(And); 31190b57cec5SDimitry Andric 31200b57cec5SDimitry Andric // Non-zero in the sense that they're not provably zero, which is the key 31210b57cec5SDimitry Andric // point if we want to use this value. 31220b57cec5SDimitry Andric uint64_t NotKnownZero = (~Known.Zero).getZExtValue(); 31230b57cec5SDimitry Andric 31240b57cec5SDimitry Andric // The KnownZero mask must be a shifted mask (e.g., 1110..011, 11100..00). 31250b57cec5SDimitry Andric if (!isShiftedMask(Known.Zero.getZExtValue(), VT)) 31260b57cec5SDimitry Andric return false; 31270b57cec5SDimitry Andric 31280b57cec5SDimitry Andric // The bits being inserted must only set those bits that are known to be zero. 31290b57cec5SDimitry Andric if ((OrImm & NotKnownZero) != 0) { 31300b57cec5SDimitry Andric // FIXME: It's okay if the OrImm sets NotKnownZero bits to 1, but we don't 31310b57cec5SDimitry Andric // currently handle this case. 31320b57cec5SDimitry Andric return false; 31330b57cec5SDimitry Andric } 31340b57cec5SDimitry Andric 31350b57cec5SDimitry Andric // BFI/BFXIL dst, src, #lsb, #width. 313606c3fb27SDimitry Andric int LSB = llvm::countr_one(NotKnownZero); 313706c3fb27SDimitry Andric int Width = BitWidth - APInt(BitWidth, NotKnownZero).popcount(); 31380b57cec5SDimitry Andric 31390b57cec5SDimitry Andric // BFI/BFXIL is an alias of BFM, so translate to BFM operands. 31400b57cec5SDimitry Andric unsigned ImmR = (BitWidth - LSB) % BitWidth; 31410b57cec5SDimitry Andric unsigned ImmS = Width - 1; 31420b57cec5SDimitry Andric 31430b57cec5SDimitry Andric // If we're creating a BFI instruction avoid cases where we need more 31440b57cec5SDimitry Andric // instructions to materialize the BFI constant as compared to the original 31450b57cec5SDimitry Andric // ORR. A BFXIL will use the same constant as the original ORR, so the code 31460b57cec5SDimitry Andric // should be no worse in this case. 31470b57cec5SDimitry Andric bool IsBFI = LSB != 0; 31480b57cec5SDimitry Andric uint64_t BFIImm = OrImm >> LSB; 31490b57cec5SDimitry Andric if (IsBFI && !AArch64_AM::isLogicalImmediate(BFIImm, BitWidth)) { 31500b57cec5SDimitry Andric // We have a BFI instruction and we know the constant can't be materialized 31510b57cec5SDimitry Andric // with a ORR-immediate with the zero register. 31520b57cec5SDimitry Andric unsigned OrChunks = 0, BFIChunks = 0; 31530b57cec5SDimitry Andric for (unsigned Shift = 0; Shift < BitWidth; Shift += 16) { 31540b57cec5SDimitry Andric if (((OrImm >> Shift) & 0xFFFF) != 0) 31550b57cec5SDimitry Andric ++OrChunks; 31560b57cec5SDimitry Andric if (((BFIImm >> Shift) & 0xFFFF) != 0) 31570b57cec5SDimitry Andric ++BFIChunks; 31580b57cec5SDimitry Andric } 31590b57cec5SDimitry Andric if (BFIChunks > OrChunks) 31600b57cec5SDimitry Andric return false; 31610b57cec5SDimitry Andric } 31620b57cec5SDimitry Andric 31630b57cec5SDimitry Andric // Materialize the constant to be inserted. 31640b57cec5SDimitry Andric SDLoc DL(N); 31650b57cec5SDimitry Andric unsigned MOVIOpc = VT == MVT::i32 ? AArch64::MOVi32imm : AArch64::MOVi64imm; 31660b57cec5SDimitry Andric SDNode *MOVI = CurDAG->getMachineNode( 31670b57cec5SDimitry Andric MOVIOpc, DL, VT, CurDAG->getTargetConstant(BFIImm, DL, VT)); 31680b57cec5SDimitry Andric 31690b57cec5SDimitry Andric // Create the BFI/BFXIL instruction. 31700b57cec5SDimitry Andric SDValue Ops[] = {And.getOperand(0), SDValue(MOVI, 0), 31710b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmR, DL, VT), 31720b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 31730b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 31740b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 31750b57cec5SDimitry Andric return true; 31760b57cec5SDimitry Andric } 31770b57cec5SDimitry Andric 3178bdd1243dSDimitry Andric static bool isWorthFoldingIntoOrrWithShift(SDValue Dst, SelectionDAG *CurDAG, 3179bdd1243dSDimitry Andric SDValue &ShiftedOperand, 3180bdd1243dSDimitry Andric uint64_t &EncodedShiftImm) { 3181bdd1243dSDimitry Andric // Avoid folding Dst into ORR-with-shift if Dst has other uses than ORR. 3182bdd1243dSDimitry Andric if (!Dst.hasOneUse()) 3183bdd1243dSDimitry Andric return false; 3184bdd1243dSDimitry Andric 3185bdd1243dSDimitry Andric EVT VT = Dst.getValueType(); 3186bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3187bdd1243dSDimitry Andric "Caller should guarantee that VT is one of i32 or i64"); 3188bdd1243dSDimitry Andric const unsigned SizeInBits = VT.getSizeInBits(); 3189bdd1243dSDimitry Andric 3190bdd1243dSDimitry Andric SDLoc DL(Dst.getNode()); 3191bdd1243dSDimitry Andric uint64_t AndImm, ShlImm; 3192bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::AND, AndImm) && 3193bdd1243dSDimitry Andric isShiftedMask_64(AndImm)) { 3194bdd1243dSDimitry Andric // Avoid transforming 'DstOp0' if it has other uses than the AND node. 3195bdd1243dSDimitry Andric SDValue DstOp0 = Dst.getOperand(0); 3196bdd1243dSDimitry Andric if (!DstOp0.hasOneUse()) 3197bdd1243dSDimitry Andric return false; 3198bdd1243dSDimitry Andric 3199bdd1243dSDimitry Andric // An example to illustrate the transformation 3200bdd1243dSDimitry Andric // From: 3201bdd1243dSDimitry Andric // lsr x8, x1, #1 3202bdd1243dSDimitry Andric // and x8, x8, #0x3f80 3203bdd1243dSDimitry Andric // bfxil x8, x1, #0, #7 3204bdd1243dSDimitry Andric // To: 3205bdd1243dSDimitry Andric // and x8, x23, #0x7f 3206bdd1243dSDimitry Andric // ubfx x9, x23, #8, #7 3207bdd1243dSDimitry Andric // orr x23, x8, x9, lsl #7 3208bdd1243dSDimitry Andric // 3209bdd1243dSDimitry Andric // The number of instructions remains the same, but ORR is faster than BFXIL 3210bdd1243dSDimitry Andric // on many AArch64 processors (or as good as BFXIL if not faster). Besides, 3211bdd1243dSDimitry Andric // the dependency chain is improved after the transformation. 3212bdd1243dSDimitry Andric uint64_t SrlImm; 3213bdd1243dSDimitry Andric if (isOpcWithIntImmediate(DstOp0.getNode(), ISD::SRL, SrlImm)) { 321406c3fb27SDimitry Andric uint64_t NumTrailingZeroInShiftedMask = llvm::countr_zero(AndImm); 3215bdd1243dSDimitry Andric if ((SrlImm + NumTrailingZeroInShiftedMask) < SizeInBits) { 3216bdd1243dSDimitry Andric unsigned MaskWidth = 321706c3fb27SDimitry Andric llvm::countr_one(AndImm >> NumTrailingZeroInShiftedMask); 3218bdd1243dSDimitry Andric unsigned UBFMOpc = 3219bdd1243dSDimitry Andric (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 3220bdd1243dSDimitry Andric SDNode *UBFMNode = CurDAG->getMachineNode( 3221bdd1243dSDimitry Andric UBFMOpc, DL, VT, DstOp0.getOperand(0), 3222bdd1243dSDimitry Andric CurDAG->getTargetConstant(SrlImm + NumTrailingZeroInShiftedMask, DL, 3223bdd1243dSDimitry Andric VT), 3224bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3225bdd1243dSDimitry Andric SrlImm + NumTrailingZeroInShiftedMask + MaskWidth - 1, DL, VT)); 3226bdd1243dSDimitry Andric ShiftedOperand = SDValue(UBFMNode, 0); 3227bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm( 3228bdd1243dSDimitry Andric AArch64_AM::LSL, NumTrailingZeroInShiftedMask); 3229bdd1243dSDimitry Andric return true; 3230bdd1243dSDimitry Andric } 3231bdd1243dSDimitry Andric } 3232bdd1243dSDimitry Andric return false; 3233bdd1243dSDimitry Andric } 3234bdd1243dSDimitry Andric 3235bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::SHL, ShlImm)) { 3236bdd1243dSDimitry Andric ShiftedOperand = Dst.getOperand(0); 3237bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm); 3238bdd1243dSDimitry Andric return true; 3239bdd1243dSDimitry Andric } 3240bdd1243dSDimitry Andric 3241bdd1243dSDimitry Andric uint64_t SrlImm; 3242bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::SRL, SrlImm)) { 3243bdd1243dSDimitry Andric ShiftedOperand = Dst.getOperand(0); 3244bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm); 3245bdd1243dSDimitry Andric return true; 3246bdd1243dSDimitry Andric } 3247bdd1243dSDimitry Andric return false; 3248bdd1243dSDimitry Andric } 3249bdd1243dSDimitry Andric 3250bdd1243dSDimitry Andric // Given an 'ISD::OR' node that is going to be selected as BFM, analyze 3251bdd1243dSDimitry Andric // the operands and select it to AArch64::ORR with shifted registers if 3252bdd1243dSDimitry Andric // that's more efficient. Returns true iff selection to AArch64::ORR happens. 3253bdd1243dSDimitry Andric static bool tryOrrWithShift(SDNode *N, SDValue OrOpd0, SDValue OrOpd1, 3254bdd1243dSDimitry Andric SDValue Src, SDValue Dst, SelectionDAG *CurDAG, 3255bdd1243dSDimitry Andric const bool BiggerPattern) { 3256bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 3257bdd1243dSDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect N to be an OR node"); 3258bdd1243dSDimitry Andric assert(((N->getOperand(0) == OrOpd0 && N->getOperand(1) == OrOpd1) || 3259bdd1243dSDimitry Andric (N->getOperand(1) == OrOpd0 && N->getOperand(0) == OrOpd1)) && 3260bdd1243dSDimitry Andric "Expect OrOpd0 and OrOpd1 to be operands of ISD::OR"); 3261bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3262bdd1243dSDimitry Andric "Expect result type to be i32 or i64 since N is combinable to BFM"); 3263bdd1243dSDimitry Andric SDLoc DL(N); 3264bdd1243dSDimitry Andric 3265bdd1243dSDimitry Andric // Bail out if BFM simplifies away one node in BFM Dst. 3266bdd1243dSDimitry Andric if (OrOpd1 != Dst) 3267bdd1243dSDimitry Andric return false; 3268bdd1243dSDimitry Andric 3269bdd1243dSDimitry Andric const unsigned OrrOpc = (VT == MVT::i32) ? AArch64::ORRWrs : AArch64::ORRXrs; 3270bdd1243dSDimitry Andric // For "BFM Rd, Rn, #immr, #imms", it's known that BFM simplifies away fewer 3271bdd1243dSDimitry Andric // nodes from Rn (or inserts additional shift node) if BiggerPattern is true. 3272bdd1243dSDimitry Andric if (BiggerPattern) { 3273bdd1243dSDimitry Andric uint64_t SrcAndImm; 3274bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::AND, SrcAndImm) && 3275bdd1243dSDimitry Andric isMask_64(SrcAndImm) && OrOpd0.getOperand(0) == Src) { 3276bdd1243dSDimitry Andric // OrOpd0 = AND Src, #Mask 3277bdd1243dSDimitry Andric // So BFM simplifies away one AND node from Src and doesn't simplify away 3278bdd1243dSDimitry Andric // nodes from Dst. If ORR with left-shifted operand also simplifies away 3279bdd1243dSDimitry Andric // one node (from Rd), ORR is better since it has higher throughput and 3280bdd1243dSDimitry Andric // smaller latency than BFM on many AArch64 processors (and for the rest 3281bdd1243dSDimitry Andric // ORR is at least as good as BFM). 3282bdd1243dSDimitry Andric SDValue ShiftedOperand; 3283bdd1243dSDimitry Andric uint64_t EncodedShiftImm; 3284bdd1243dSDimitry Andric if (isWorthFoldingIntoOrrWithShift(Dst, CurDAG, ShiftedOperand, 3285bdd1243dSDimitry Andric EncodedShiftImm)) { 3286bdd1243dSDimitry Andric SDValue Ops[] = {OrOpd0, ShiftedOperand, 3287bdd1243dSDimitry Andric CurDAG->getTargetConstant(EncodedShiftImm, DL, VT)}; 3288bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3289bdd1243dSDimitry Andric return true; 3290bdd1243dSDimitry Andric } 3291bdd1243dSDimitry Andric } 3292bdd1243dSDimitry Andric return false; 3293bdd1243dSDimitry Andric } 3294bdd1243dSDimitry Andric 3295bdd1243dSDimitry Andric assert((!BiggerPattern) && "BiggerPattern should be handled above"); 3296bdd1243dSDimitry Andric 3297bdd1243dSDimitry Andric uint64_t ShlImm; 3298bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SHL, ShlImm)) { 3299bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == Src && OrOpd0.hasOneUse()) { 3300bdd1243dSDimitry Andric SDValue Ops[] = { 3301bdd1243dSDimitry Andric Dst, Src, 3302bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3303bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm), DL, VT)}; 3304bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3305bdd1243dSDimitry Andric return true; 3306bdd1243dSDimitry Andric } 3307bdd1243dSDimitry Andric 3308bdd1243dSDimitry Andric // Select the following pattern to left-shifted operand rather than BFI. 3309bdd1243dSDimitry Andric // %val1 = op .. 3310bdd1243dSDimitry Andric // %val2 = shl %val1, #imm 3311bdd1243dSDimitry Andric // %res = or %val1, %val2 3312bdd1243dSDimitry Andric // 3313bdd1243dSDimitry Andric // If N is selected to be BFI, we know that 3314bdd1243dSDimitry Andric // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into 3315bdd1243dSDimitry Andric // BFI) 2) OrOpd1 would be the destination operand (i.e., preserved) 3316bdd1243dSDimitry Andric // 3317bdd1243dSDimitry Andric // Instead of selecting N to BFI, fold OrOpd0 as a left shift directly. 3318bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == OrOpd1) { 3319bdd1243dSDimitry Andric SDValue Ops[] = { 3320bdd1243dSDimitry Andric OrOpd1, OrOpd1, 3321bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3322bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm), DL, VT)}; 3323bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3324bdd1243dSDimitry Andric return true; 3325bdd1243dSDimitry Andric } 3326bdd1243dSDimitry Andric } 3327bdd1243dSDimitry Andric 3328bdd1243dSDimitry Andric uint64_t SrlImm; 3329bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SRL, SrlImm)) { 3330bdd1243dSDimitry Andric // Select the following pattern to right-shifted operand rather than BFXIL. 3331bdd1243dSDimitry Andric // %val1 = op .. 3332bdd1243dSDimitry Andric // %val2 = lshr %val1, #imm 3333bdd1243dSDimitry Andric // %res = or %val1, %val2 3334bdd1243dSDimitry Andric // 3335bdd1243dSDimitry Andric // If N is selected to be BFXIL, we know that 3336bdd1243dSDimitry Andric // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into 3337bdd1243dSDimitry Andric // BFXIL) 2) OrOpd1 would be the destination operand (i.e., preserved) 3338bdd1243dSDimitry Andric // 3339bdd1243dSDimitry Andric // Instead of selecting N to BFXIL, fold OrOpd0 as a right shift directly. 3340bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == OrOpd1) { 3341bdd1243dSDimitry Andric SDValue Ops[] = { 3342bdd1243dSDimitry Andric OrOpd1, OrOpd1, 3343bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3344bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm), DL, VT)}; 3345bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3346bdd1243dSDimitry Andric return true; 3347bdd1243dSDimitry Andric } 3348bdd1243dSDimitry Andric } 3349bdd1243dSDimitry Andric 3350bdd1243dSDimitry Andric return false; 3351bdd1243dSDimitry Andric } 3352bdd1243dSDimitry Andric 33530b57cec5SDimitry Andric static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits, 33540b57cec5SDimitry Andric SelectionDAG *CurDAG) { 33550b57cec5SDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); 33560b57cec5SDimitry Andric 33570b57cec5SDimitry Andric EVT VT = N->getValueType(0); 33580b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 33590b57cec5SDimitry Andric return false; 33600b57cec5SDimitry Andric 33610b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 33620b57cec5SDimitry Andric 33630b57cec5SDimitry Andric // Because of simplify-demanded-bits in DAGCombine, involved masks may not 33640b57cec5SDimitry Andric // have the expected shape. Try to undo that. 33650b57cec5SDimitry Andric 336606c3fb27SDimitry Andric unsigned NumberOfIgnoredLowBits = UsefulBits.countr_zero(); 336706c3fb27SDimitry Andric unsigned NumberOfIgnoredHighBits = UsefulBits.countl_zero(); 33680b57cec5SDimitry Andric 33690b57cec5SDimitry Andric // Given a OR operation, check if we have the following pattern 33700b57cec5SDimitry Andric // ubfm c, b, imm, imm2 (or something that does the same jobs, see 33710b57cec5SDimitry Andric // isBitfieldExtractOp) 33720b57cec5SDimitry Andric // d = e & mask2 ; where mask is a binary sequence of 1..10..0 and 33730b57cec5SDimitry Andric // countTrailingZeros(mask2) == imm2 - imm + 1 33740b57cec5SDimitry Andric // f = d | c 33750b57cec5SDimitry Andric // if yes, replace the OR instruction with: 33760b57cec5SDimitry Andric // f = BFM Opd0, Opd1, LSB, MSB ; where LSB = imm, and MSB = imm2 33770b57cec5SDimitry Andric 33780b57cec5SDimitry Andric // OR is commutative, check all combinations of operand order and values of 33790b57cec5SDimitry Andric // BiggerPattern, i.e. 33800b57cec5SDimitry Andric // Opd0, Opd1, BiggerPattern=false 33810b57cec5SDimitry Andric // Opd1, Opd0, BiggerPattern=false 33820b57cec5SDimitry Andric // Opd0, Opd1, BiggerPattern=true 33830b57cec5SDimitry Andric // Opd1, Opd0, BiggerPattern=true 33840b57cec5SDimitry Andric // Several of these combinations may match, so check with BiggerPattern=false 33850b57cec5SDimitry Andric // first since that will produce better results by matching more instructions 33860b57cec5SDimitry Andric // and/or inserting fewer extra instructions. 33870b57cec5SDimitry Andric for (int I = 0; I < 4; ++I) { 33880b57cec5SDimitry Andric 33890b57cec5SDimitry Andric SDValue Dst, Src; 33900b57cec5SDimitry Andric unsigned ImmR, ImmS; 33910b57cec5SDimitry Andric bool BiggerPattern = I / 2; 33920b57cec5SDimitry Andric SDValue OrOpd0Val = N->getOperand(I % 2); 33930b57cec5SDimitry Andric SDNode *OrOpd0 = OrOpd0Val.getNode(); 33940b57cec5SDimitry Andric SDValue OrOpd1Val = N->getOperand((I + 1) % 2); 33950b57cec5SDimitry Andric SDNode *OrOpd1 = OrOpd1Val.getNode(); 33960b57cec5SDimitry Andric 33970b57cec5SDimitry Andric unsigned BFXOpc; 33980b57cec5SDimitry Andric int DstLSB, Width; 33990b57cec5SDimitry Andric if (isBitfieldExtractOp(CurDAG, OrOpd0, BFXOpc, Src, ImmR, ImmS, 34000b57cec5SDimitry Andric NumberOfIgnoredLowBits, BiggerPattern)) { 34010b57cec5SDimitry Andric // Check that the returned opcode is compatible with the pattern, 34020b57cec5SDimitry Andric // i.e., same type and zero extended (U and not S) 34030b57cec5SDimitry Andric if ((BFXOpc != AArch64::UBFMXri && VT == MVT::i64) || 34040b57cec5SDimitry Andric (BFXOpc != AArch64::UBFMWri && VT == MVT::i32)) 34050b57cec5SDimitry Andric continue; 34060b57cec5SDimitry Andric 34070b57cec5SDimitry Andric // Compute the width of the bitfield insertion 34080b57cec5SDimitry Andric DstLSB = 0; 34090b57cec5SDimitry Andric Width = ImmS - ImmR + 1; 34100b57cec5SDimitry Andric // FIXME: This constraint is to catch bitfield insertion we may 34110b57cec5SDimitry Andric // want to widen the pattern if we want to grab general bitfied 34120b57cec5SDimitry Andric // move case 34130b57cec5SDimitry Andric if (Width <= 0) 34140b57cec5SDimitry Andric continue; 34150b57cec5SDimitry Andric 34160b57cec5SDimitry Andric // If the mask on the insertee is correct, we have a BFXIL operation. We 34170b57cec5SDimitry Andric // can share the ImmR and ImmS values from the already-computed UBFM. 34180b57cec5SDimitry Andric } else if (isBitfieldPositioningOp(CurDAG, OrOpd0Val, 34190b57cec5SDimitry Andric BiggerPattern, 34200b57cec5SDimitry Andric Src, DstLSB, Width)) { 34210b57cec5SDimitry Andric ImmR = (BitWidth - DstLSB) % BitWidth; 34220b57cec5SDimitry Andric ImmS = Width - 1; 34230b57cec5SDimitry Andric } else 34240b57cec5SDimitry Andric continue; 34250b57cec5SDimitry Andric 34260b57cec5SDimitry Andric // Check the second part of the pattern 34270b57cec5SDimitry Andric EVT VT = OrOpd1Val.getValueType(); 34280b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && "unexpected OR operand"); 34290b57cec5SDimitry Andric 34300b57cec5SDimitry Andric // Compute the Known Zero for the candidate of the first operand. 34310b57cec5SDimitry Andric // This allows to catch more general case than just looking for 34320b57cec5SDimitry Andric // AND with imm. Indeed, simplify-demanded-bits may have removed 34330b57cec5SDimitry Andric // the AND instruction because it proves it was useless. 34340b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(OrOpd1Val); 34350b57cec5SDimitry Andric 34360b57cec5SDimitry Andric // Check if there is enough room for the second operand to appear 34370b57cec5SDimitry Andric // in the first one 34380b57cec5SDimitry Andric APInt BitsToBeInserted = 34390b57cec5SDimitry Andric APInt::getBitsSet(Known.getBitWidth(), DstLSB, DstLSB + Width); 34400b57cec5SDimitry Andric 34410b57cec5SDimitry Andric if ((BitsToBeInserted & ~Known.Zero) != 0) 34420b57cec5SDimitry Andric continue; 34430b57cec5SDimitry Andric 34440b57cec5SDimitry Andric // Set the first operand 34450b57cec5SDimitry Andric uint64_t Imm; 34460b57cec5SDimitry Andric if (isOpcWithIntImmediate(OrOpd1, ISD::AND, Imm) && 34470b57cec5SDimitry Andric isBitfieldDstMask(Imm, BitsToBeInserted, NumberOfIgnoredHighBits, VT)) 34480b57cec5SDimitry Andric // In that case, we can eliminate the AND 34490b57cec5SDimitry Andric Dst = OrOpd1->getOperand(0); 34500b57cec5SDimitry Andric else 34510b57cec5SDimitry Andric // Maybe the AND has been removed by simplify-demanded-bits 34520b57cec5SDimitry Andric // or is useful because it discards more bits 34530b57cec5SDimitry Andric Dst = OrOpd1Val; 34540b57cec5SDimitry Andric 3455bdd1243dSDimitry Andric // Before selecting ISD::OR node to AArch64::BFM, see if an AArch64::ORR 3456bdd1243dSDimitry Andric // with shifted operand is more efficient. 3457bdd1243dSDimitry Andric if (tryOrrWithShift(N, OrOpd0Val, OrOpd1Val, Src, Dst, CurDAG, 3458bdd1243dSDimitry Andric BiggerPattern)) 3459bdd1243dSDimitry Andric return true; 3460bdd1243dSDimitry Andric 34610b57cec5SDimitry Andric // both parts match 34620b57cec5SDimitry Andric SDLoc DL(N); 34630b57cec5SDimitry Andric SDValue Ops[] = {Dst, Src, CurDAG->getTargetConstant(ImmR, DL, VT), 34640b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 34650b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 34660b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 34670b57cec5SDimitry Andric return true; 34680b57cec5SDimitry Andric } 34690b57cec5SDimitry Andric 34700b57cec5SDimitry Andric // Generate a BFXIL from 'or (and X, Mask0Imm), (and Y, Mask1Imm)' iff 34710b57cec5SDimitry Andric // Mask0Imm and ~Mask1Imm are equivalent and one of the MaskImms is a shifted 34720b57cec5SDimitry Andric // mask (e.g., 0x000ffff0). 34730b57cec5SDimitry Andric uint64_t Mask0Imm, Mask1Imm; 34740b57cec5SDimitry Andric SDValue And0 = N->getOperand(0); 34750b57cec5SDimitry Andric SDValue And1 = N->getOperand(1); 34760b57cec5SDimitry Andric if (And0.hasOneUse() && And1.hasOneUse() && 34770b57cec5SDimitry Andric isOpcWithIntImmediate(And0.getNode(), ISD::AND, Mask0Imm) && 34780b57cec5SDimitry Andric isOpcWithIntImmediate(And1.getNode(), ISD::AND, Mask1Imm) && 34790b57cec5SDimitry Andric APInt(BitWidth, Mask0Imm) == ~APInt(BitWidth, Mask1Imm) && 34800b57cec5SDimitry Andric (isShiftedMask(Mask0Imm, VT) || isShiftedMask(Mask1Imm, VT))) { 34810b57cec5SDimitry Andric 34820b57cec5SDimitry Andric // ORR is commutative, so canonicalize to the form 'or (and X, Mask0Imm), 34830b57cec5SDimitry Andric // (and Y, Mask1Imm)' where Mask1Imm is the shifted mask masking off the 34840b57cec5SDimitry Andric // bits to be inserted. 34850b57cec5SDimitry Andric if (isShiftedMask(Mask0Imm, VT)) { 34860b57cec5SDimitry Andric std::swap(And0, And1); 34870b57cec5SDimitry Andric std::swap(Mask0Imm, Mask1Imm); 34880b57cec5SDimitry Andric } 34890b57cec5SDimitry Andric 34900b57cec5SDimitry Andric SDValue Src = And1->getOperand(0); 34910b57cec5SDimitry Andric SDValue Dst = And0->getOperand(0); 349206c3fb27SDimitry Andric unsigned LSB = llvm::countr_zero(Mask1Imm); 349306c3fb27SDimitry Andric int Width = BitWidth - APInt(BitWidth, Mask0Imm).popcount(); 34940b57cec5SDimitry Andric 34950b57cec5SDimitry Andric // The BFXIL inserts the low-order bits from a source register, so right 34960b57cec5SDimitry Andric // shift the needed bits into place. 34970b57cec5SDimitry Andric SDLoc DL(N); 34980b57cec5SDimitry Andric unsigned ShiftOpc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 349981ad6265SDimitry Andric uint64_t LsrImm = LSB; 350081ad6265SDimitry Andric if (Src->hasOneUse() && 350181ad6265SDimitry Andric isOpcWithIntImmediate(Src.getNode(), ISD::SRL, LsrImm) && 350281ad6265SDimitry Andric (LsrImm + LSB) < BitWidth) { 350381ad6265SDimitry Andric Src = Src->getOperand(0); 350481ad6265SDimitry Andric LsrImm += LSB; 350581ad6265SDimitry Andric } 350681ad6265SDimitry Andric 35070b57cec5SDimitry Andric SDNode *LSR = CurDAG->getMachineNode( 350881ad6265SDimitry Andric ShiftOpc, DL, VT, Src, CurDAG->getTargetConstant(LsrImm, DL, VT), 35090b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1, DL, VT)); 35100b57cec5SDimitry Andric 35110b57cec5SDimitry Andric // BFXIL is an alias of BFM, so translate to BFM operands. 35120b57cec5SDimitry Andric unsigned ImmR = (BitWidth - LSB) % BitWidth; 35130b57cec5SDimitry Andric unsigned ImmS = Width - 1; 35140b57cec5SDimitry Andric 35150b57cec5SDimitry Andric // Create the BFXIL instruction. 35160b57cec5SDimitry Andric SDValue Ops[] = {Dst, SDValue(LSR, 0), 35170b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmR, DL, VT), 35180b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 35190b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 35200b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 35210b57cec5SDimitry Andric return true; 35220b57cec5SDimitry Andric } 35230b57cec5SDimitry Andric 35240b57cec5SDimitry Andric return false; 35250b57cec5SDimitry Andric } 35260b57cec5SDimitry Andric 35270b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) { 35280b57cec5SDimitry Andric if (N->getOpcode() != ISD::OR) 35290b57cec5SDimitry Andric return false; 35300b57cec5SDimitry Andric 35310b57cec5SDimitry Andric APInt NUsefulBits; 35320b57cec5SDimitry Andric getUsefulBits(SDValue(N, 0), NUsefulBits); 35330b57cec5SDimitry Andric 35340b57cec5SDimitry Andric // If all bits are not useful, just return UNDEF. 35350b57cec5SDimitry Andric if (!NUsefulBits) { 35360b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); 35370b57cec5SDimitry Andric return true; 35380b57cec5SDimitry Andric } 35390b57cec5SDimitry Andric 35400b57cec5SDimitry Andric if (tryBitfieldInsertOpFromOr(N, NUsefulBits, CurDAG)) 35410b57cec5SDimitry Andric return true; 35420b57cec5SDimitry Andric 35430b57cec5SDimitry Andric return tryBitfieldInsertOpFromOrAndImm(N, CurDAG); 35440b57cec5SDimitry Andric } 35450b57cec5SDimitry Andric 35460b57cec5SDimitry Andric /// SelectBitfieldInsertInZeroOp - Match a UBFIZ instruction that is the 35470b57cec5SDimitry Andric /// equivalent of a left shift by a constant amount followed by an and masking 35480b57cec5SDimitry Andric /// out a contiguous set of bits. 35490b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldInsertInZeroOp(SDNode *N) { 35500b57cec5SDimitry Andric if (N->getOpcode() != ISD::AND) 35510b57cec5SDimitry Andric return false; 35520b57cec5SDimitry Andric 35530b57cec5SDimitry Andric EVT VT = N->getValueType(0); 35540b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 35550b57cec5SDimitry Andric return false; 35560b57cec5SDimitry Andric 35570b57cec5SDimitry Andric SDValue Op0; 35580b57cec5SDimitry Andric int DstLSB, Width; 35590b57cec5SDimitry Andric if (!isBitfieldPositioningOp(CurDAG, SDValue(N, 0), /*BiggerPattern=*/false, 35600b57cec5SDimitry Andric Op0, DstLSB, Width)) 35610b57cec5SDimitry Andric return false; 35620b57cec5SDimitry Andric 35630b57cec5SDimitry Andric // ImmR is the rotate right amount. 35640b57cec5SDimitry Andric unsigned ImmR = (VT.getSizeInBits() - DstLSB) % VT.getSizeInBits(); 35650b57cec5SDimitry Andric // ImmS is the most significant bit of the source to be moved. 35660b57cec5SDimitry Andric unsigned ImmS = Width - 1; 35670b57cec5SDimitry Andric 35680b57cec5SDimitry Andric SDLoc DL(N); 35690b57cec5SDimitry Andric SDValue Ops[] = {Op0, CurDAG->getTargetConstant(ImmR, DL, VT), 35700b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 35710b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 35720b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 35730b57cec5SDimitry Andric return true; 35740b57cec5SDimitry Andric } 35750b57cec5SDimitry Andric 35760b57cec5SDimitry Andric /// tryShiftAmountMod - Take advantage of built-in mod of shift amount in 35770b57cec5SDimitry Andric /// variable shift/rotate instructions. 35780b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryShiftAmountMod(SDNode *N) { 35790b57cec5SDimitry Andric EVT VT = N->getValueType(0); 35800b57cec5SDimitry Andric 35810b57cec5SDimitry Andric unsigned Opc; 35820b57cec5SDimitry Andric switch (N->getOpcode()) { 35830b57cec5SDimitry Andric case ISD::ROTR: 35840b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::RORVWr : AArch64::RORVXr; 35850b57cec5SDimitry Andric break; 35860b57cec5SDimitry Andric case ISD::SHL: 35870b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::LSLVWr : AArch64::LSLVXr; 35880b57cec5SDimitry Andric break; 35890b57cec5SDimitry Andric case ISD::SRL: 35900b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::LSRVWr : AArch64::LSRVXr; 35910b57cec5SDimitry Andric break; 35920b57cec5SDimitry Andric case ISD::SRA: 35930b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::ASRVWr : AArch64::ASRVXr; 35940b57cec5SDimitry Andric break; 35950b57cec5SDimitry Andric default: 35960b57cec5SDimitry Andric return false; 35970b57cec5SDimitry Andric } 35980b57cec5SDimitry Andric 35990b57cec5SDimitry Andric uint64_t Size; 36000b57cec5SDimitry Andric uint64_t Bits; 36010b57cec5SDimitry Andric if (VT == MVT::i32) { 36020b57cec5SDimitry Andric Bits = 5; 36030b57cec5SDimitry Andric Size = 32; 36040b57cec5SDimitry Andric } else if (VT == MVT::i64) { 36050b57cec5SDimitry Andric Bits = 6; 36060b57cec5SDimitry Andric Size = 64; 36070b57cec5SDimitry Andric } else 36080b57cec5SDimitry Andric return false; 36090b57cec5SDimitry Andric 36100b57cec5SDimitry Andric SDValue ShiftAmt = N->getOperand(1); 36110b57cec5SDimitry Andric SDLoc DL(N); 36120b57cec5SDimitry Andric SDValue NewShiftAmt; 36130b57cec5SDimitry Andric 36140b57cec5SDimitry Andric // Skip over an extend of the shift amount. 36150b57cec5SDimitry Andric if (ShiftAmt->getOpcode() == ISD::ZERO_EXTEND || 36160b57cec5SDimitry Andric ShiftAmt->getOpcode() == ISD::ANY_EXTEND) 36170b57cec5SDimitry Andric ShiftAmt = ShiftAmt->getOperand(0); 36180b57cec5SDimitry Andric 36190b57cec5SDimitry Andric if (ShiftAmt->getOpcode() == ISD::ADD || ShiftAmt->getOpcode() == ISD::SUB) { 36200b57cec5SDimitry Andric SDValue Add0 = ShiftAmt->getOperand(0); 36210b57cec5SDimitry Andric SDValue Add1 = ShiftAmt->getOperand(1); 36220b57cec5SDimitry Andric uint64_t Add0Imm; 36230b57cec5SDimitry Andric uint64_t Add1Imm; 362481ad6265SDimitry Andric if (isIntImmediate(Add1, Add1Imm) && (Add1Imm % Size == 0)) { 36250b57cec5SDimitry Andric // If we are shifting by X+/-N where N == 0 mod Size, then just shift by X 36260b57cec5SDimitry Andric // to avoid the ADD/SUB. 36270b57cec5SDimitry Andric NewShiftAmt = Add0; 362881ad6265SDimitry Andric } else if (ShiftAmt->getOpcode() == ISD::SUB && 36290b57cec5SDimitry Andric isIntImmediate(Add0, Add0Imm) && Add0Imm != 0 && 36300b57cec5SDimitry Andric (Add0Imm % Size == 0)) { 363181ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X 363281ad6265SDimitry Andric // to generate a NEG instead of a SUB from a constant. 36330b57cec5SDimitry Andric unsigned NegOpc; 36340b57cec5SDimitry Andric unsigned ZeroReg; 36350b57cec5SDimitry Andric EVT SubVT = ShiftAmt->getValueType(0); 36360b57cec5SDimitry Andric if (SubVT == MVT::i32) { 36370b57cec5SDimitry Andric NegOpc = AArch64::SUBWrr; 36380b57cec5SDimitry Andric ZeroReg = AArch64::WZR; 36390b57cec5SDimitry Andric } else { 36400b57cec5SDimitry Andric assert(SubVT == MVT::i64); 36410b57cec5SDimitry Andric NegOpc = AArch64::SUBXrr; 36420b57cec5SDimitry Andric ZeroReg = AArch64::XZR; 36430b57cec5SDimitry Andric } 36440b57cec5SDimitry Andric SDValue Zero = 36450b57cec5SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT); 36460b57cec5SDimitry Andric MachineSDNode *Neg = 36470b57cec5SDimitry Andric CurDAG->getMachineNode(NegOpc, DL, SubVT, Zero, Add1); 36480b57cec5SDimitry Andric NewShiftAmt = SDValue(Neg, 0); 364981ad6265SDimitry Andric } else if (ShiftAmt->getOpcode() == ISD::SUB && 365081ad6265SDimitry Andric isIntImmediate(Add0, Add0Imm) && (Add0Imm % Size == Size - 1)) { 365181ad6265SDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 365281ad6265SDimitry Andric // to generate a NOT instead of a SUB from a constant. 365381ad6265SDimitry Andric unsigned NotOpc; 365481ad6265SDimitry Andric unsigned ZeroReg; 365581ad6265SDimitry Andric EVT SubVT = ShiftAmt->getValueType(0); 365681ad6265SDimitry Andric if (SubVT == MVT::i32) { 365781ad6265SDimitry Andric NotOpc = AArch64::ORNWrr; 365881ad6265SDimitry Andric ZeroReg = AArch64::WZR; 365981ad6265SDimitry Andric } else { 366081ad6265SDimitry Andric assert(SubVT == MVT::i64); 366181ad6265SDimitry Andric NotOpc = AArch64::ORNXrr; 366281ad6265SDimitry Andric ZeroReg = AArch64::XZR; 366381ad6265SDimitry Andric } 366481ad6265SDimitry Andric SDValue Zero = 366581ad6265SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT); 366681ad6265SDimitry Andric MachineSDNode *Not = 366781ad6265SDimitry Andric CurDAG->getMachineNode(NotOpc, DL, SubVT, Zero, Add1); 366881ad6265SDimitry Andric NewShiftAmt = SDValue(Not, 0); 36690b57cec5SDimitry Andric } else 36700b57cec5SDimitry Andric return false; 36710b57cec5SDimitry Andric } else { 36720b57cec5SDimitry Andric // If the shift amount is masked with an AND, check that the mask covers the 36730b57cec5SDimitry Andric // bits that are implicitly ANDed off by the above opcodes and if so, skip 36740b57cec5SDimitry Andric // the AND. 36750b57cec5SDimitry Andric uint64_t MaskImm; 36765ffd83dbSDimitry Andric if (!isOpcWithIntImmediate(ShiftAmt.getNode(), ISD::AND, MaskImm) && 36775ffd83dbSDimitry Andric !isOpcWithIntImmediate(ShiftAmt.getNode(), AArch64ISD::ANDS, MaskImm)) 36780b57cec5SDimitry Andric return false; 36790b57cec5SDimitry Andric 368006c3fb27SDimitry Andric if ((unsigned)llvm::countr_one(MaskImm) < Bits) 36810b57cec5SDimitry Andric return false; 36820b57cec5SDimitry Andric 36830b57cec5SDimitry Andric NewShiftAmt = ShiftAmt->getOperand(0); 36840b57cec5SDimitry Andric } 36850b57cec5SDimitry Andric 36860b57cec5SDimitry Andric // Narrow/widen the shift amount to match the size of the shift operation. 36870b57cec5SDimitry Andric if (VT == MVT::i32) 36880b57cec5SDimitry Andric NewShiftAmt = narrowIfNeeded(CurDAG, NewShiftAmt); 36890b57cec5SDimitry Andric else if (VT == MVT::i64 && NewShiftAmt->getValueType(0) == MVT::i32) { 36900b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, DL, MVT::i32); 36910b57cec5SDimitry Andric MachineSDNode *Ext = CurDAG->getMachineNode( 36920b57cec5SDimitry Andric AArch64::SUBREG_TO_REG, DL, VT, 36930b57cec5SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i64), NewShiftAmt, SubReg); 36940b57cec5SDimitry Andric NewShiftAmt = SDValue(Ext, 0); 36950b57cec5SDimitry Andric } 36960b57cec5SDimitry Andric 36970b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(0), NewShiftAmt}; 36980b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 36990b57cec5SDimitry Andric return true; 37000b57cec5SDimitry Andric } 37010b57cec5SDimitry Andric 3702*5f757f3fSDimitry Andric static bool checkCVTFixedPointOperandWithFBits(SelectionDAG *CurDAG, SDValue N, 3703*5f757f3fSDimitry Andric SDValue &FixedPos, 3704*5f757f3fSDimitry Andric unsigned RegWidth, 3705*5f757f3fSDimitry Andric bool isReciprocal) { 37060b57cec5SDimitry Andric APFloat FVal(0.0); 37070b57cec5SDimitry Andric if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N)) 37080b57cec5SDimitry Andric FVal = CN->getValueAPF(); 37090b57cec5SDimitry Andric else if (LoadSDNode *LN = dyn_cast<LoadSDNode>(N)) { 37100b57cec5SDimitry Andric // Some otherwise illegal constants are allowed in this case. 37110b57cec5SDimitry Andric if (LN->getOperand(1).getOpcode() != AArch64ISD::ADDlow || 37120b57cec5SDimitry Andric !isa<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1))) 37130b57cec5SDimitry Andric return false; 37140b57cec5SDimitry Andric 37150b57cec5SDimitry Andric ConstantPoolSDNode *CN = 37160b57cec5SDimitry Andric dyn_cast<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1)); 37170b57cec5SDimitry Andric FVal = cast<ConstantFP>(CN->getConstVal())->getValueAPF(); 37180b57cec5SDimitry Andric } else 37190b57cec5SDimitry Andric return false; 37200b57cec5SDimitry Andric 37210b57cec5SDimitry Andric // An FCVT[SU] instruction performs: convertToInt(Val * 2^fbits) where fbits 37220b57cec5SDimitry Andric // is between 1 and 32 for a destination w-register, or 1 and 64 for an 37230b57cec5SDimitry Andric // x-register. 37240b57cec5SDimitry Andric // 37250b57cec5SDimitry Andric // By this stage, we've detected (fp_to_[su]int (fmul Val, THIS_NODE)) so we 37260b57cec5SDimitry Andric // want THIS_NODE to be 2^fbits. This is much easier to deal with using 37270b57cec5SDimitry Andric // integers. 37280b57cec5SDimitry Andric bool IsExact; 37290b57cec5SDimitry Andric 3730*5f757f3fSDimitry Andric if (isReciprocal) 3731*5f757f3fSDimitry Andric if (!FVal.getExactInverse(&FVal)) 3732*5f757f3fSDimitry Andric return false; 3733*5f757f3fSDimitry Andric 37340b57cec5SDimitry Andric // fbits is between 1 and 64 in the worst-case, which means the fmul 37350b57cec5SDimitry Andric // could have 2^64 as an actual operand. Need 65 bits of precision. 37360b57cec5SDimitry Andric APSInt IntVal(65, true); 37370b57cec5SDimitry Andric FVal.convertToInteger(IntVal, APFloat::rmTowardZero, &IsExact); 37380b57cec5SDimitry Andric 37390b57cec5SDimitry Andric // N.b. isPowerOf2 also checks for > 0. 3740*5f757f3fSDimitry Andric if (!IsExact || !IntVal.isPowerOf2()) 3741*5f757f3fSDimitry Andric return false; 37420b57cec5SDimitry Andric unsigned FBits = IntVal.logBase2(); 37430b57cec5SDimitry Andric 37440b57cec5SDimitry Andric // Checks above should have guaranteed that we haven't lost information in 37450b57cec5SDimitry Andric // finding FBits, but it must still be in range. 37460b57cec5SDimitry Andric if (FBits == 0 || FBits > RegWidth) return false; 37470b57cec5SDimitry Andric 37480b57cec5SDimitry Andric FixedPos = CurDAG->getTargetConstant(FBits, SDLoc(N), MVT::i32); 37490b57cec5SDimitry Andric return true; 37500b57cec5SDimitry Andric } 37510b57cec5SDimitry Andric 3752*5f757f3fSDimitry Andric bool AArch64DAGToDAGISel::SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, 3753*5f757f3fSDimitry Andric unsigned RegWidth) { 3754*5f757f3fSDimitry Andric return checkCVTFixedPointOperandWithFBits(CurDAG, N, FixedPos, RegWidth, 3755*5f757f3fSDimitry Andric false); 3756*5f757f3fSDimitry Andric } 3757*5f757f3fSDimitry Andric 3758*5f757f3fSDimitry Andric bool AArch64DAGToDAGISel::SelectCVTFixedPosRecipOperand(SDValue N, 3759*5f757f3fSDimitry Andric SDValue &FixedPos, 3760*5f757f3fSDimitry Andric unsigned RegWidth) { 3761*5f757f3fSDimitry Andric return checkCVTFixedPointOperandWithFBits(CurDAG, N, FixedPos, RegWidth, 3762*5f757f3fSDimitry Andric true); 3763*5f757f3fSDimitry Andric } 3764*5f757f3fSDimitry Andric 37650b57cec5SDimitry Andric // Inspects a register string of the form o0:op1:CRn:CRm:op2 gets the fields 37660b57cec5SDimitry Andric // of the string and obtains the integer values from them and combines these 37670b57cec5SDimitry Andric // into a single value to be used in the MRS/MSR instruction. 37680b57cec5SDimitry Andric static int getIntOperandFromRegisterString(StringRef RegString) { 37690b57cec5SDimitry Andric SmallVector<StringRef, 5> Fields; 37700b57cec5SDimitry Andric RegString.split(Fields, ':'); 37710b57cec5SDimitry Andric 37720b57cec5SDimitry Andric if (Fields.size() == 1) 37730b57cec5SDimitry Andric return -1; 37740b57cec5SDimitry Andric 37750b57cec5SDimitry Andric assert(Fields.size() == 5 37760b57cec5SDimitry Andric && "Invalid number of fields in read register string"); 37770b57cec5SDimitry Andric 37780b57cec5SDimitry Andric SmallVector<int, 5> Ops; 37790b57cec5SDimitry Andric bool AllIntFields = true; 37800b57cec5SDimitry Andric 37810b57cec5SDimitry Andric for (StringRef Field : Fields) { 37820b57cec5SDimitry Andric unsigned IntField; 37830b57cec5SDimitry Andric AllIntFields &= !Field.getAsInteger(10, IntField); 37840b57cec5SDimitry Andric Ops.push_back(IntField); 37850b57cec5SDimitry Andric } 37860b57cec5SDimitry Andric 37870b57cec5SDimitry Andric assert(AllIntFields && 37880b57cec5SDimitry Andric "Unexpected non-integer value in special register string."); 3789fe6060f1SDimitry Andric (void)AllIntFields; 37900b57cec5SDimitry Andric 37910b57cec5SDimitry Andric // Need to combine the integer fields of the string into a single value 37920b57cec5SDimitry Andric // based on the bit encoding of MRS/MSR instruction. 37930b57cec5SDimitry Andric return (Ops[0] << 14) | (Ops[1] << 11) | (Ops[2] << 7) | 37940b57cec5SDimitry Andric (Ops[3] << 3) | (Ops[4]); 37950b57cec5SDimitry Andric } 37960b57cec5SDimitry Andric 37970b57cec5SDimitry Andric // Lower the read_register intrinsic to an MRS instruction node if the special 37980b57cec5SDimitry Andric // register string argument is either of the form detailed in the ALCE (the 37990b57cec5SDimitry Andric // form described in getIntOperandsFromRegsterString) or is a named register 38000b57cec5SDimitry Andric // known by the MRS SysReg mapper. 38010b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryReadRegister(SDNode *N) { 3802349cc55cSDimitry Andric const auto *MD = cast<MDNodeSDNode>(N->getOperand(1)); 3803349cc55cSDimitry Andric const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0)); 38040b57cec5SDimitry Andric SDLoc DL(N); 38050b57cec5SDimitry Andric 3806bdd1243dSDimitry Andric bool ReadIs128Bit = N->getOpcode() == AArch64ISD::MRRS; 38070b57cec5SDimitry Andric 3808bdd1243dSDimitry Andric unsigned Opcode64Bit = AArch64::MRS; 3809bdd1243dSDimitry Andric int Imm = getIntOperandFromRegisterString(RegString->getString()); 3810bdd1243dSDimitry Andric if (Imm == -1) { 3811bdd1243dSDimitry Andric // No match, Use the sysreg mapper to map the remaining possible strings to 3812bdd1243dSDimitry Andric // the value for the register to be used for the instruction operand. 3813bdd1243dSDimitry Andric const auto *TheReg = 3814bdd1243dSDimitry Andric AArch64SysReg::lookupSysRegByName(RegString->getString()); 38150b57cec5SDimitry Andric if (TheReg && TheReg->Readable && 38160b57cec5SDimitry Andric TheReg->haveFeatures(Subtarget->getFeatureBits())) 3817bdd1243dSDimitry Andric Imm = TheReg->Encoding; 38180b57cec5SDimitry Andric else 3819bdd1243dSDimitry Andric Imm = AArch64SysReg::parseGenericRegister(RegString->getString()); 38200b57cec5SDimitry Andric 3821bdd1243dSDimitry Andric if (Imm == -1) { 3822bdd1243dSDimitry Andric // Still no match, see if this is "pc" or give up. 3823bdd1243dSDimitry Andric if (!ReadIs128Bit && RegString->getString() == "pc") { 3824bdd1243dSDimitry Andric Opcode64Bit = AArch64::ADR; 3825bdd1243dSDimitry Andric Imm = 0; 3826bdd1243dSDimitry Andric } else { 38270b57cec5SDimitry Andric return false; 38280b57cec5SDimitry Andric } 3829bdd1243dSDimitry Andric } 3830bdd1243dSDimitry Andric } 3831bdd1243dSDimitry Andric 3832bdd1243dSDimitry Andric SDValue InChain = N->getOperand(0); 3833bdd1243dSDimitry Andric SDValue SysRegImm = CurDAG->getTargetConstant(Imm, DL, MVT::i32); 3834bdd1243dSDimitry Andric if (!ReadIs128Bit) { 3835bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, Opcode64Bit, MVT::i64, MVT::Other /* Chain */, 3836bdd1243dSDimitry Andric {SysRegImm, InChain}); 3837bdd1243dSDimitry Andric } else { 3838bdd1243dSDimitry Andric SDNode *MRRS = CurDAG->getMachineNode( 3839bdd1243dSDimitry Andric AArch64::MRRS, DL, 3840bdd1243dSDimitry Andric {MVT::Untyped /* XSeqPair */, MVT::Other /* Chain */}, 3841bdd1243dSDimitry Andric {SysRegImm, InChain}); 3842bdd1243dSDimitry Andric 3843bdd1243dSDimitry Andric // Sysregs are not endian. The even register always contains the low half 3844bdd1243dSDimitry Andric // of the register. 3845bdd1243dSDimitry Andric SDValue Lo = CurDAG->getTargetExtractSubreg(AArch64::sube64, DL, MVT::i64, 3846bdd1243dSDimitry Andric SDValue(MRRS, 0)); 3847bdd1243dSDimitry Andric SDValue Hi = CurDAG->getTargetExtractSubreg(AArch64::subo64, DL, MVT::i64, 3848bdd1243dSDimitry Andric SDValue(MRRS, 0)); 3849bdd1243dSDimitry Andric SDValue OutChain = SDValue(MRRS, 1); 3850bdd1243dSDimitry Andric 3851bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 0), Lo); 3852bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 1), Hi); 3853bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 2), OutChain); 3854bdd1243dSDimitry Andric }; 3855bdd1243dSDimitry Andric return true; 3856bdd1243dSDimitry Andric } 38570b57cec5SDimitry Andric 38580b57cec5SDimitry Andric // Lower the write_register intrinsic to an MSR instruction node if the special 38590b57cec5SDimitry Andric // register string argument is either of the form detailed in the ALCE (the 38600b57cec5SDimitry Andric // form described in getIntOperandsFromRegsterString) or is a named register 38610b57cec5SDimitry Andric // known by the MSR SysReg mapper. 38620b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) { 3863349cc55cSDimitry Andric const auto *MD = cast<MDNodeSDNode>(N->getOperand(1)); 3864349cc55cSDimitry Andric const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0)); 38650b57cec5SDimitry Andric SDLoc DL(N); 38660b57cec5SDimitry Andric 3867bdd1243dSDimitry Andric bool WriteIs128Bit = N->getOpcode() == AArch64ISD::MSRR; 38680b57cec5SDimitry Andric 3869bdd1243dSDimitry Andric if (!WriteIs128Bit) { 3870bdd1243dSDimitry Andric // Check if the register was one of those allowed as the pstatefield value 3871bdd1243dSDimitry Andric // in the MSR (immediate) instruction. To accept the values allowed in the 38720b57cec5SDimitry Andric // pstatefield for the MSR (immediate) instruction, we also require that an 38730b57cec5SDimitry Andric // immediate value has been provided as an argument, we know that this is 38740b57cec5SDimitry Andric // the case as it has been ensured by semantic checking. 3875bdd1243dSDimitry Andric auto trySelectPState = [&](auto PMapper, unsigned State) { 38760b57cec5SDimitry Andric if (PMapper) { 3877bdd1243dSDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(2)) && 3878bdd1243dSDimitry Andric "Expected a constant integer expression."); 38790b57cec5SDimitry Andric unsigned Reg = PMapper->Encoding; 38800b57cec5SDimitry Andric uint64_t Immed = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); 3881bdd1243dSDimitry Andric CurDAG->SelectNodeTo( 3882bdd1243dSDimitry Andric N, State, MVT::Other, CurDAG->getTargetConstant(Reg, DL, MVT::i32), 3883bdd1243dSDimitry Andric CurDAG->getTargetConstant(Immed, DL, MVT::i16), N->getOperand(0)); 3884bdd1243dSDimitry Andric return true; 38850b57cec5SDimitry Andric } 3886bdd1243dSDimitry Andric return false; 3887bdd1243dSDimitry Andric }; 3888bdd1243dSDimitry Andric 3889bdd1243dSDimitry Andric if (trySelectPState( 3890bdd1243dSDimitry Andric AArch64PState::lookupPStateImm0_15ByName(RegString->getString()), 3891bdd1243dSDimitry Andric AArch64::MSRpstateImm4)) 3892bdd1243dSDimitry Andric return true; 3893bdd1243dSDimitry Andric if (trySelectPState( 3894bdd1243dSDimitry Andric AArch64PState::lookupPStateImm0_1ByName(RegString->getString()), 3895bdd1243dSDimitry Andric AArch64::MSRpstateImm1)) 38960b57cec5SDimitry Andric return true; 38970b57cec5SDimitry Andric } 38980b57cec5SDimitry Andric 3899bdd1243dSDimitry Andric int Imm = getIntOperandFromRegisterString(RegString->getString()); 3900bdd1243dSDimitry Andric if (Imm == -1) { 39010b57cec5SDimitry Andric // Use the sysreg mapper to attempt to map the remaining possible strings 39020b57cec5SDimitry Andric // to the value for the register to be used for the MSR (register) 39030b57cec5SDimitry Andric // instruction operand. 39040b57cec5SDimitry Andric auto TheReg = AArch64SysReg::lookupSysRegByName(RegString->getString()); 39050b57cec5SDimitry Andric if (TheReg && TheReg->Writeable && 39060b57cec5SDimitry Andric TheReg->haveFeatures(Subtarget->getFeatureBits())) 3907bdd1243dSDimitry Andric Imm = TheReg->Encoding; 39080b57cec5SDimitry Andric else 3909bdd1243dSDimitry Andric Imm = AArch64SysReg::parseGenericRegister(RegString->getString()); 3910bdd1243dSDimitry Andric 3911bdd1243dSDimitry Andric if (Imm == -1) 3912bdd1243dSDimitry Andric return false; 39130b57cec5SDimitry Andric } 39140b57cec5SDimitry Andric 3915bdd1243dSDimitry Andric SDValue InChain = N->getOperand(0); 3916bdd1243dSDimitry Andric if (!WriteIs128Bit) { 3917bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::MSR, MVT::Other, 3918bdd1243dSDimitry Andric CurDAG->getTargetConstant(Imm, DL, MVT::i32), 3919bdd1243dSDimitry Andric N->getOperand(2), InChain); 3920bdd1243dSDimitry Andric } else { 3921bdd1243dSDimitry Andric // No endian swap. The lower half always goes into the even subreg, and the 3922bdd1243dSDimitry Andric // higher half always into the odd supreg. 3923bdd1243dSDimitry Andric SDNode *Pair = CurDAG->getMachineNode( 3924bdd1243dSDimitry Andric TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped /* XSeqPair */, 3925bdd1243dSDimitry Andric {CurDAG->getTargetConstant(AArch64::XSeqPairsClassRegClass.getID(), DL, 3926bdd1243dSDimitry Andric MVT::i32), 3927bdd1243dSDimitry Andric N->getOperand(2), 3928bdd1243dSDimitry Andric CurDAG->getTargetConstant(AArch64::sube64, DL, MVT::i32), 3929bdd1243dSDimitry Andric N->getOperand(3), 3930bdd1243dSDimitry Andric CurDAG->getTargetConstant(AArch64::subo64, DL, MVT::i32)}); 3931bdd1243dSDimitry Andric 3932bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::MSRR, MVT::Other, 3933bdd1243dSDimitry Andric CurDAG->getTargetConstant(Imm, DL, MVT::i32), 3934bdd1243dSDimitry Andric SDValue(Pair, 0), InChain); 3935bdd1243dSDimitry Andric } 3936bdd1243dSDimitry Andric 3937bdd1243dSDimitry Andric return true; 39380b57cec5SDimitry Andric } 39390b57cec5SDimitry Andric 39400b57cec5SDimitry Andric /// We've got special pseudo-instructions for these 39410b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) { 39420b57cec5SDimitry Andric unsigned Opcode; 39430b57cec5SDimitry Andric EVT MemTy = cast<MemSDNode>(N)->getMemoryVT(); 39440b57cec5SDimitry Andric 39450b57cec5SDimitry Andric // Leave IR for LSE if subtarget supports it. 39460b57cec5SDimitry Andric if (Subtarget->hasLSE()) return false; 39470b57cec5SDimitry Andric 39480b57cec5SDimitry Andric if (MemTy == MVT::i8) 39490b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_8; 39500b57cec5SDimitry Andric else if (MemTy == MVT::i16) 39510b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_16; 39520b57cec5SDimitry Andric else if (MemTy == MVT::i32) 39530b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_32; 39540b57cec5SDimitry Andric else if (MemTy == MVT::i64) 39550b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_64; 39560b57cec5SDimitry Andric else 39570b57cec5SDimitry Andric llvm_unreachable("Unknown AtomicCmpSwap type"); 39580b57cec5SDimitry Andric 39590b57cec5SDimitry Andric MVT RegTy = MemTy == MVT::i64 ? MVT::i64 : MVT::i32; 39600b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3), 39610b57cec5SDimitry Andric N->getOperand(0)}; 39620b57cec5SDimitry Andric SDNode *CmpSwap = CurDAG->getMachineNode( 39630b57cec5SDimitry Andric Opcode, SDLoc(N), 39640b57cec5SDimitry Andric CurDAG->getVTList(RegTy, MVT::i32, MVT::Other), Ops); 39650b57cec5SDimitry Andric 39660b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand(); 39670b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp}); 39680b57cec5SDimitry Andric 39690b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0)); 39700b57cec5SDimitry Andric ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2)); 39710b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 39720b57cec5SDimitry Andric 39730b57cec5SDimitry Andric return true; 39740b57cec5SDimitry Andric } 39750b57cec5SDimitry Andric 397681ad6265SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm, 397781ad6265SDimitry Andric SDValue &Shift) { 397881ad6265SDimitry Andric if (!isa<ConstantSDNode>(N)) 39795ffd83dbSDimitry Andric return false; 39805ffd83dbSDimitry Andric 39815ffd83dbSDimitry Andric SDLoc DL(N); 398281ad6265SDimitry Andric uint64_t Val = cast<ConstantSDNode>(N) 398381ad6265SDimitry Andric ->getAPIntValue() 398481ad6265SDimitry Andric .trunc(VT.getFixedSizeInBits()) 398581ad6265SDimitry Andric .getZExtValue(); 3986480093f4SDimitry Andric 3987480093f4SDimitry Andric switch (VT.SimpleTy) { 3988480093f4SDimitry Andric case MVT::i8: 398981ad6265SDimitry Andric // All immediates are supported. 3990fe6060f1SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 399181ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32); 3992fe6060f1SDimitry Andric return true; 3993fe6060f1SDimitry Andric case MVT::i16: 3994480093f4SDimitry Andric case MVT::i32: 3995480093f4SDimitry Andric case MVT::i64: 399681ad6265SDimitry Andric // Support 8bit unsigned immediates. 399781ad6265SDimitry Andric if (Val <= 255) { 3998480093f4SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 399981ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32); 4000480093f4SDimitry Andric return true; 400181ad6265SDimitry Andric } 400281ad6265SDimitry Andric // Support 16bit unsigned immediates that are a multiple of 256. 400381ad6265SDimitry Andric if (Val <= 65280 && Val % 256 == 0) { 4004480093f4SDimitry Andric Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); 400581ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val >> 8, DL, MVT::i32); 4006480093f4SDimitry Andric return true; 4007480093f4SDimitry Andric } 4008480093f4SDimitry Andric break; 4009480093f4SDimitry Andric default: 4010480093f4SDimitry Andric break; 4011480093f4SDimitry Andric } 401281ad6265SDimitry Andric 401381ad6265SDimitry Andric return false; 401481ad6265SDimitry Andric } 401581ad6265SDimitry Andric 401681ad6265SDimitry Andric bool AArch64DAGToDAGISel::SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm, 401781ad6265SDimitry Andric SDValue &Shift) { 401881ad6265SDimitry Andric if (!isa<ConstantSDNode>(N)) 401981ad6265SDimitry Andric return false; 402081ad6265SDimitry Andric 402181ad6265SDimitry Andric SDLoc DL(N); 402281ad6265SDimitry Andric int64_t Val = cast<ConstantSDNode>(N) 402381ad6265SDimitry Andric ->getAPIntValue() 402481ad6265SDimitry Andric .trunc(VT.getFixedSizeInBits()) 402581ad6265SDimitry Andric .getSExtValue(); 402681ad6265SDimitry Andric 402781ad6265SDimitry Andric switch (VT.SimpleTy) { 402881ad6265SDimitry Andric case MVT::i8: 402981ad6265SDimitry Andric // All immediates are supported. 403081ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 403181ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val & 0xFF, DL, MVT::i32); 403281ad6265SDimitry Andric return true; 403381ad6265SDimitry Andric case MVT::i16: 403481ad6265SDimitry Andric case MVT::i32: 403581ad6265SDimitry Andric case MVT::i64: 403681ad6265SDimitry Andric // Support 8bit signed immediates. 403781ad6265SDimitry Andric if (Val >= -128 && Val <= 127) { 403881ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 403981ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val & 0xFF, DL, MVT::i32); 404081ad6265SDimitry Andric return true; 404181ad6265SDimitry Andric } 404281ad6265SDimitry Andric // Support 16bit signed immediates that are a multiple of 256. 404381ad6265SDimitry Andric if (Val >= -32768 && Val <= 32512 && Val % 256 == 0) { 404481ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); 404581ad6265SDimitry Andric Imm = CurDAG->getTargetConstant((Val >> 8) & 0xFF, DL, MVT::i32); 404681ad6265SDimitry Andric return true; 404781ad6265SDimitry Andric } 404881ad6265SDimitry Andric break; 404981ad6265SDimitry Andric default: 405081ad6265SDimitry Andric break; 4051480093f4SDimitry Andric } 4052480093f4SDimitry Andric 4053480093f4SDimitry Andric return false; 4054480093f4SDimitry Andric } 4055480093f4SDimitry Andric 4056480093f4SDimitry Andric bool AArch64DAGToDAGISel::SelectSVESignedArithImm(SDValue N, SDValue &Imm) { 4057480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 4058480093f4SDimitry Andric int64_t ImmVal = CNode->getSExtValue(); 4059480093f4SDimitry Andric SDLoc DL(N); 40605ffd83dbSDimitry Andric if (ImmVal >= -128 && ImmVal < 128) { 4061480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32); 4062480093f4SDimitry Andric return true; 4063480093f4SDimitry Andric } 4064480093f4SDimitry Andric } 4065480093f4SDimitry Andric return false; 4066480093f4SDimitry Andric } 4067480093f4SDimitry Andric 4068e8d8bef9SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm) { 4069480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 4070e8d8bef9SDimitry Andric uint64_t ImmVal = CNode->getZExtValue(); 4071e8d8bef9SDimitry Andric 4072e8d8bef9SDimitry Andric switch (VT.SimpleTy) { 4073e8d8bef9SDimitry Andric case MVT::i8: 4074e8d8bef9SDimitry Andric ImmVal &= 0xFF; 4075e8d8bef9SDimitry Andric break; 4076e8d8bef9SDimitry Andric case MVT::i16: 4077e8d8bef9SDimitry Andric ImmVal &= 0xFFFF; 4078e8d8bef9SDimitry Andric break; 4079e8d8bef9SDimitry Andric case MVT::i32: 4080e8d8bef9SDimitry Andric ImmVal &= 0xFFFFFFFF; 4081e8d8bef9SDimitry Andric break; 4082e8d8bef9SDimitry Andric case MVT::i64: 4083e8d8bef9SDimitry Andric break; 4084e8d8bef9SDimitry Andric default: 4085e8d8bef9SDimitry Andric llvm_unreachable("Unexpected type"); 4086e8d8bef9SDimitry Andric } 4087e8d8bef9SDimitry Andric 4088480093f4SDimitry Andric if (ImmVal < 256) { 4089e8d8bef9SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32); 4090480093f4SDimitry Andric return true; 4091480093f4SDimitry Andric } 4092480093f4SDimitry Andric } 4093480093f4SDimitry Andric return false; 4094480093f4SDimitry Andric } 4095480093f4SDimitry Andric 4096fe6060f1SDimitry Andric bool AArch64DAGToDAGISel::SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm, 4097fe6060f1SDimitry Andric bool Invert) { 4098480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 4099480093f4SDimitry Andric uint64_t ImmVal = CNode->getZExtValue(); 4100480093f4SDimitry Andric SDLoc DL(N); 4101480093f4SDimitry Andric 4102fe6060f1SDimitry Andric if (Invert) 4103fe6060f1SDimitry Andric ImmVal = ~ImmVal; 4104fe6060f1SDimitry Andric 4105480093f4SDimitry Andric // Shift mask depending on type size. 4106480093f4SDimitry Andric switch (VT.SimpleTy) { 4107480093f4SDimitry Andric case MVT::i8: 4108480093f4SDimitry Andric ImmVal &= 0xFF; 4109480093f4SDimitry Andric ImmVal |= ImmVal << 8; 4110480093f4SDimitry Andric ImmVal |= ImmVal << 16; 4111480093f4SDimitry Andric ImmVal |= ImmVal << 32; 4112480093f4SDimitry Andric break; 4113480093f4SDimitry Andric case MVT::i16: 4114480093f4SDimitry Andric ImmVal &= 0xFFFF; 4115480093f4SDimitry Andric ImmVal |= ImmVal << 16; 4116480093f4SDimitry Andric ImmVal |= ImmVal << 32; 4117480093f4SDimitry Andric break; 4118480093f4SDimitry Andric case MVT::i32: 4119480093f4SDimitry Andric ImmVal &= 0xFFFFFFFF; 4120480093f4SDimitry Andric ImmVal |= ImmVal << 32; 4121480093f4SDimitry Andric break; 4122480093f4SDimitry Andric case MVT::i64: 4123480093f4SDimitry Andric break; 4124480093f4SDimitry Andric default: 4125480093f4SDimitry Andric llvm_unreachable("Unexpected type"); 4126480093f4SDimitry Andric } 4127480093f4SDimitry Andric 4128480093f4SDimitry Andric uint64_t encoding; 4129480093f4SDimitry Andric if (AArch64_AM::processLogicalImmediate(ImmVal, 64, encoding)) { 4130480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(encoding, DL, MVT::i64); 4131480093f4SDimitry Andric return true; 4132480093f4SDimitry Andric } 4133480093f4SDimitry Andric } 4134480093f4SDimitry Andric return false; 4135480093f4SDimitry Andric } 4136480093f4SDimitry Andric 4137e8d8bef9SDimitry Andric // SVE shift intrinsics allow shift amounts larger than the element's bitwidth. 4138e8d8bef9SDimitry Andric // Rather than attempt to normalise everything we can sometimes saturate the 4139e8d8bef9SDimitry Andric // shift amount during selection. This function also allows for consistent 4140e8d8bef9SDimitry Andric // isel patterns by ensuring the resulting "Imm" node is of the i32 type 4141e8d8bef9SDimitry Andric // required by the instructions. 4142e8d8bef9SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEShiftImm(SDValue N, uint64_t Low, 4143e8d8bef9SDimitry Andric uint64_t High, bool AllowSaturation, 4144e8d8bef9SDimitry Andric SDValue &Imm) { 41455ffd83dbSDimitry Andric if (auto *CN = dyn_cast<ConstantSDNode>(N)) { 41465ffd83dbSDimitry Andric uint64_t ImmVal = CN->getZExtValue(); 41475ffd83dbSDimitry Andric 4148e8d8bef9SDimitry Andric // Reject shift amounts that are too small. 4149e8d8bef9SDimitry Andric if (ImmVal < Low) 4150e8d8bef9SDimitry Andric return false; 4151e8d8bef9SDimitry Andric 4152e8d8bef9SDimitry Andric // Reject or saturate shift amounts that are too big. 4153e8d8bef9SDimitry Andric if (ImmVal > High) { 4154e8d8bef9SDimitry Andric if (!AllowSaturation) 4155e8d8bef9SDimitry Andric return false; 4156e8d8bef9SDimitry Andric ImmVal = High; 41575ffd83dbSDimitry Andric } 4158e8d8bef9SDimitry Andric 4159e8d8bef9SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32); 4160e8d8bef9SDimitry Andric return true; 41615ffd83dbSDimitry Andric } 41625ffd83dbSDimitry Andric 41635ffd83dbSDimitry Andric return false; 41645ffd83dbSDimitry Andric } 41655ffd83dbSDimitry Andric 41660b57cec5SDimitry Andric bool AArch64DAGToDAGISel::trySelectStackSlotTagP(SDNode *N) { 41670b57cec5SDimitry Andric // tagp(FrameIndex, IRGstack, tag_offset): 41680b57cec5SDimitry Andric // since the offset between FrameIndex and IRGstack is a compile-time 41690b57cec5SDimitry Andric // constant, this can be lowered to a single ADDG instruction. 41700b57cec5SDimitry Andric if (!(isa<FrameIndexSDNode>(N->getOperand(1)))) { 41710b57cec5SDimitry Andric return false; 41720b57cec5SDimitry Andric } 41730b57cec5SDimitry Andric 41740b57cec5SDimitry Andric SDValue IRG_SP = N->getOperand(2); 41750b57cec5SDimitry Andric if (IRG_SP->getOpcode() != ISD::INTRINSIC_W_CHAIN || 41760b57cec5SDimitry Andric cast<ConstantSDNode>(IRG_SP->getOperand(1))->getZExtValue() != 41770b57cec5SDimitry Andric Intrinsic::aarch64_irg_sp) { 41780b57cec5SDimitry Andric return false; 41790b57cec5SDimitry Andric } 41800b57cec5SDimitry Andric 41810b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 41820b57cec5SDimitry Andric SDLoc DL(N); 41830b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N->getOperand(1))->getIndex(); 41840b57cec5SDimitry Andric SDValue FiOp = CurDAG->getTargetFrameIndex( 41850b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 41860b57cec5SDimitry Andric int TagOffset = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(); 41870b57cec5SDimitry Andric 41880b57cec5SDimitry Andric SDNode *Out = CurDAG->getMachineNode( 41890b57cec5SDimitry Andric AArch64::TAGPstack, DL, MVT::i64, 41900b57cec5SDimitry Andric {FiOp, CurDAG->getTargetConstant(0, DL, MVT::i64), N->getOperand(2), 41910b57cec5SDimitry Andric CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)}); 41920b57cec5SDimitry Andric ReplaceNode(N, Out); 41930b57cec5SDimitry Andric return true; 41940b57cec5SDimitry Andric } 41950b57cec5SDimitry Andric 41960b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectTagP(SDNode *N) { 41970b57cec5SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(3)) && 41980b57cec5SDimitry Andric "llvm.aarch64.tagp third argument must be an immediate"); 41990b57cec5SDimitry Andric if (trySelectStackSlotTagP(N)) 42000b57cec5SDimitry Andric return; 42010b57cec5SDimitry Andric // FIXME: above applies in any case when offset between Op1 and Op2 is a 42020b57cec5SDimitry Andric // compile-time constant, not just for stack allocations. 42030b57cec5SDimitry Andric 42040b57cec5SDimitry Andric // General case for unrelated pointers in Op1 and Op2. 42050b57cec5SDimitry Andric SDLoc DL(N); 42060b57cec5SDimitry Andric int TagOffset = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(); 42070b57cec5SDimitry Andric SDNode *N1 = CurDAG->getMachineNode(AArch64::SUBP, DL, MVT::i64, 42080b57cec5SDimitry Andric {N->getOperand(1), N->getOperand(2)}); 42090b57cec5SDimitry Andric SDNode *N2 = CurDAG->getMachineNode(AArch64::ADDXrr, DL, MVT::i64, 42100b57cec5SDimitry Andric {SDValue(N1, 0), N->getOperand(2)}); 42110b57cec5SDimitry Andric SDNode *N3 = CurDAG->getMachineNode( 42120b57cec5SDimitry Andric AArch64::ADDG, DL, MVT::i64, 42130b57cec5SDimitry Andric {SDValue(N2, 0), CurDAG->getTargetConstant(0, DL, MVT::i64), 42140b57cec5SDimitry Andric CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)}); 42150b57cec5SDimitry Andric ReplaceNode(N, N3); 42160b57cec5SDimitry Andric } 42170b57cec5SDimitry Andric 421806c3fb27SDimitry Andric bool AArch64DAGToDAGISel::trySelectCastFixedLengthToScalableVector(SDNode *N) { 421906c3fb27SDimitry Andric assert(N->getOpcode() == ISD::INSERT_SUBVECTOR && "Invalid Node!"); 42205ffd83dbSDimitry Andric 422106c3fb27SDimitry Andric // Bail when not a "cast" like insert_subvector. 422206c3fb27SDimitry Andric if (cast<ConstantSDNode>(N->getOperand(2))->getZExtValue() != 0) 422306c3fb27SDimitry Andric return false; 422406c3fb27SDimitry Andric if (!N->getOperand(0).isUndef()) 422506c3fb27SDimitry Andric return false; 42265ffd83dbSDimitry Andric 422706c3fb27SDimitry Andric // Bail when normal isel should do the job. 422806c3fb27SDimitry Andric EVT VT = N->getValueType(0); 422906c3fb27SDimitry Andric EVT InVT = N->getOperand(1).getValueType(); 423006c3fb27SDimitry Andric if (VT.isFixedLengthVector() || InVT.isScalableVector()) 423106c3fb27SDimitry Andric return false; 423206c3fb27SDimitry Andric if (InVT.getSizeInBits() <= 128) 423306c3fb27SDimitry Andric return false; 423406c3fb27SDimitry Andric 423506c3fb27SDimitry Andric // NOTE: We can only get here when doing fixed length SVE code generation. 423606c3fb27SDimitry Andric // We do manual selection because the types involved are not linked to real 423706c3fb27SDimitry Andric // registers (despite being legal) and must be coerced into SVE registers. 423806c3fb27SDimitry Andric 423906c3fb27SDimitry Andric assert(VT.getSizeInBits().getKnownMinValue() == AArch64::SVEBitsPerBlock && 42405ffd83dbSDimitry Andric "Expected to insert into a packed scalable vector!"); 42415ffd83dbSDimitry Andric 424206c3fb27SDimitry Andric SDLoc DL(N); 424306c3fb27SDimitry Andric auto RC = CurDAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64); 424406c3fb27SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, 424506c3fb27SDimitry Andric N->getOperand(1), RC)); 424606c3fb27SDimitry Andric return true; 42475ffd83dbSDimitry Andric } 424806c3fb27SDimitry Andric 424906c3fb27SDimitry Andric bool AArch64DAGToDAGISel::trySelectCastScalableToFixedLengthVector(SDNode *N) { 425006c3fb27SDimitry Andric assert(N->getOpcode() == ISD::EXTRACT_SUBVECTOR && "Invalid Node!"); 425106c3fb27SDimitry Andric 425206c3fb27SDimitry Andric // Bail when not a "cast" like extract_subvector. 425306c3fb27SDimitry Andric if (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue() != 0) 425406c3fb27SDimitry Andric return false; 425506c3fb27SDimitry Andric 425606c3fb27SDimitry Andric // Bail when normal isel can do the job. 425706c3fb27SDimitry Andric EVT VT = N->getValueType(0); 425806c3fb27SDimitry Andric EVT InVT = N->getOperand(0).getValueType(); 425906c3fb27SDimitry Andric if (VT.isScalableVector() || InVT.isFixedLengthVector()) 426006c3fb27SDimitry Andric return false; 426106c3fb27SDimitry Andric if (VT.getSizeInBits() <= 128) 426206c3fb27SDimitry Andric return false; 426306c3fb27SDimitry Andric 426406c3fb27SDimitry Andric // NOTE: We can only get here when doing fixed length SVE code generation. 426506c3fb27SDimitry Andric // We do manual selection because the types involved are not linked to real 426606c3fb27SDimitry Andric // registers (despite being legal) and must be coerced into SVE registers. 426706c3fb27SDimitry Andric 426806c3fb27SDimitry Andric assert(InVT.getSizeInBits().getKnownMinValue() == AArch64::SVEBitsPerBlock && 426906c3fb27SDimitry Andric "Expected to extract from a packed scalable vector!"); 427006c3fb27SDimitry Andric 427106c3fb27SDimitry Andric SDLoc DL(N); 427206c3fb27SDimitry Andric auto RC = CurDAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64); 427306c3fb27SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, 427406c3fb27SDimitry Andric N->getOperand(0), RC)); 427506c3fb27SDimitry Andric return true; 42765ffd83dbSDimitry Andric } 42775ffd83dbSDimitry Andric 4278*5f757f3fSDimitry Andric bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) { 4279*5f757f3fSDimitry Andric assert(N->getOpcode() == ISD::OR && "Expected OR instruction"); 4280*5f757f3fSDimitry Andric 4281*5f757f3fSDimitry Andric SDValue N0 = N->getOperand(0); 4282*5f757f3fSDimitry Andric SDValue N1 = N->getOperand(1); 4283*5f757f3fSDimitry Andric 4284*5f757f3fSDimitry Andric if (N0->getOpcode() != AArch64ISD::VSHL || 4285*5f757f3fSDimitry Andric N1->getOpcode() != AArch64ISD::VLSHR) 4286*5f757f3fSDimitry Andric return false; 4287*5f757f3fSDimitry Andric 4288*5f757f3fSDimitry Andric if (N0->getOperand(0) != N1->getOperand(0) || 4289*5f757f3fSDimitry Andric N1->getOperand(0)->getOpcode() != ISD::XOR) 4290*5f757f3fSDimitry Andric return false; 4291*5f757f3fSDimitry Andric 4292*5f757f3fSDimitry Andric SDValue XOR = N0.getOperand(0); 4293*5f757f3fSDimitry Andric SDValue R1 = XOR.getOperand(0); 4294*5f757f3fSDimitry Andric SDValue R2 = XOR.getOperand(1); 4295*5f757f3fSDimitry Andric 4296*5f757f3fSDimitry Andric unsigned HsAmt = N0.getConstantOperandVal(1); 4297*5f757f3fSDimitry Andric unsigned ShAmt = N1.getConstantOperandVal(1); 4298*5f757f3fSDimitry Andric 4299*5f757f3fSDimitry Andric SDLoc DL = SDLoc(N0.getOperand(1)); 4300*5f757f3fSDimitry Andric SDValue Imm = CurDAG->getTargetConstant( 4301*5f757f3fSDimitry Andric ShAmt, DL, N0.getOperand(1).getValueType(), false); 4302*5f757f3fSDimitry Andric 4303*5f757f3fSDimitry Andric if (ShAmt + HsAmt != 64) 4304*5f757f3fSDimitry Andric return false; 4305*5f757f3fSDimitry Andric 4306*5f757f3fSDimitry Andric SDValue Ops[] = {R1, R2, Imm}; 4307*5f757f3fSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::XAR, N0.getValueType(), Ops); 4308*5f757f3fSDimitry Andric 4309*5f757f3fSDimitry Andric return true; 4310*5f757f3fSDimitry Andric } 4311*5f757f3fSDimitry Andric 43120b57cec5SDimitry Andric void AArch64DAGToDAGISel::Select(SDNode *Node) { 43130b57cec5SDimitry Andric // If we have a custom node, we already have selected! 43140b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 43150b57cec5SDimitry Andric LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 43160b57cec5SDimitry Andric Node->setNodeId(-1); 43170b57cec5SDimitry Andric return; 43180b57cec5SDimitry Andric } 43190b57cec5SDimitry Andric 43200b57cec5SDimitry Andric // Few custom selection stuff. 43210b57cec5SDimitry Andric EVT VT = Node->getValueType(0); 43220b57cec5SDimitry Andric 43230b57cec5SDimitry Andric switch (Node->getOpcode()) { 43240b57cec5SDimitry Andric default: 43250b57cec5SDimitry Andric break; 43260b57cec5SDimitry Andric 43270b57cec5SDimitry Andric case ISD::ATOMIC_CMP_SWAP: 43280b57cec5SDimitry Andric if (SelectCMP_SWAP(Node)) 43290b57cec5SDimitry Andric return; 43300b57cec5SDimitry Andric break; 43310b57cec5SDimitry Andric 43320b57cec5SDimitry Andric case ISD::READ_REGISTER: 4333bdd1243dSDimitry Andric case AArch64ISD::MRRS: 43340b57cec5SDimitry Andric if (tryReadRegister(Node)) 43350b57cec5SDimitry Andric return; 43360b57cec5SDimitry Andric break; 43370b57cec5SDimitry Andric 43380b57cec5SDimitry Andric case ISD::WRITE_REGISTER: 4339bdd1243dSDimitry Andric case AArch64ISD::MSRR: 43400b57cec5SDimitry Andric if (tryWriteRegister(Node)) 43410b57cec5SDimitry Andric return; 43420b57cec5SDimitry Andric break; 43430b57cec5SDimitry Andric 43440b57cec5SDimitry Andric case ISD::LOAD: { 43450b57cec5SDimitry Andric // Try to select as an indexed load. Fall through to normal processing 43460b57cec5SDimitry Andric // if we can't. 43470b57cec5SDimitry Andric if (tryIndexedLoad(Node)) 43480b57cec5SDimitry Andric return; 43490b57cec5SDimitry Andric break; 43500b57cec5SDimitry Andric } 43510b57cec5SDimitry Andric 43520b57cec5SDimitry Andric case ISD::SRL: 43530b57cec5SDimitry Andric case ISD::AND: 43540b57cec5SDimitry Andric case ISD::SRA: 43550b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 43560b57cec5SDimitry Andric if (tryBitfieldExtractOp(Node)) 43570b57cec5SDimitry Andric return; 43580b57cec5SDimitry Andric if (tryBitfieldInsertInZeroOp(Node)) 43590b57cec5SDimitry Andric return; 4360bdd1243dSDimitry Andric [[fallthrough]]; 43610b57cec5SDimitry Andric case ISD::ROTR: 43620b57cec5SDimitry Andric case ISD::SHL: 43630b57cec5SDimitry Andric if (tryShiftAmountMod(Node)) 43640b57cec5SDimitry Andric return; 43650b57cec5SDimitry Andric break; 43660b57cec5SDimitry Andric 43670b57cec5SDimitry Andric case ISD::SIGN_EXTEND: 43680b57cec5SDimitry Andric if (tryBitfieldExtractOpFromSExt(Node)) 43690b57cec5SDimitry Andric return; 43700b57cec5SDimitry Andric break; 43710b57cec5SDimitry Andric 43720b57cec5SDimitry Andric case ISD::OR: 43730b57cec5SDimitry Andric if (tryBitfieldInsertOp(Node)) 43740b57cec5SDimitry Andric return; 4375*5f757f3fSDimitry Andric if (Subtarget->hasSHA3() && trySelectXAR(Node)) 4376*5f757f3fSDimitry Andric return; 43770b57cec5SDimitry Andric break; 43780b57cec5SDimitry Andric 43795ffd83dbSDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 438006c3fb27SDimitry Andric if (trySelectCastScalableToFixedLengthVector(Node)) 43815ffd83dbSDimitry Andric return; 438206c3fb27SDimitry Andric break; 43835ffd83dbSDimitry Andric } 43845ffd83dbSDimitry Andric 43855ffd83dbSDimitry Andric case ISD::INSERT_SUBVECTOR: { 438606c3fb27SDimitry Andric if (trySelectCastFixedLengthToScalableVector(Node)) 43875ffd83dbSDimitry Andric return; 438806c3fb27SDimitry Andric break; 43895ffd83dbSDimitry Andric } 43905ffd83dbSDimitry Andric 43910b57cec5SDimitry Andric case ISD::Constant: { 43920b57cec5SDimitry Andric // Materialize zero constants as copies from WZR/XZR. This allows 43930b57cec5SDimitry Andric // the coalescer to propagate these into other instructions. 43940b57cec5SDimitry Andric ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node); 4395349cc55cSDimitry Andric if (ConstNode->isZero()) { 43960b57cec5SDimitry Andric if (VT == MVT::i32) { 43970b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg( 43980b57cec5SDimitry Andric CurDAG->getEntryNode(), SDLoc(Node), AArch64::WZR, MVT::i32); 43990b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 44000b57cec5SDimitry Andric return; 44010b57cec5SDimitry Andric } else if (VT == MVT::i64) { 44020b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg( 44030b57cec5SDimitry Andric CurDAG->getEntryNode(), SDLoc(Node), AArch64::XZR, MVT::i64); 44040b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 44050b57cec5SDimitry Andric return; 44060b57cec5SDimitry Andric } 44070b57cec5SDimitry Andric } 44080b57cec5SDimitry Andric break; 44090b57cec5SDimitry Andric } 44100b57cec5SDimitry Andric 44110b57cec5SDimitry Andric case ISD::FrameIndex: { 44120b57cec5SDimitry Andric // Selects to ADDXri FI, 0 which in turn will become ADDXri SP, imm. 44130b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 44140b57cec5SDimitry Andric unsigned Shifter = AArch64_AM::getShifterImm(AArch64_AM::LSL, 0); 44150b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 44160b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex( 44170b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 44180b57cec5SDimitry Andric SDLoc DL(Node); 44190b57cec5SDimitry Andric SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, DL, MVT::i32), 44200b57cec5SDimitry Andric CurDAG->getTargetConstant(Shifter, DL, MVT::i32) }; 44210b57cec5SDimitry Andric CurDAG->SelectNodeTo(Node, AArch64::ADDXri, MVT::i64, Ops); 44220b57cec5SDimitry Andric return; 44230b57cec5SDimitry Andric } 44240b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 44250b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 44260b57cec5SDimitry Andric switch (IntNo) { 44270b57cec5SDimitry Andric default: 44280b57cec5SDimitry Andric break; 44290b57cec5SDimitry Andric case Intrinsic::aarch64_ldaxp: 44300b57cec5SDimitry Andric case Intrinsic::aarch64_ldxp: { 44310b57cec5SDimitry Andric unsigned Op = 44320b57cec5SDimitry Andric IntNo == Intrinsic::aarch64_ldaxp ? AArch64::LDAXPX : AArch64::LDXPX; 44330b57cec5SDimitry Andric SDValue MemAddr = Node->getOperand(2); 44340b57cec5SDimitry Andric SDLoc DL(Node); 44350b57cec5SDimitry Andric SDValue Chain = Node->getOperand(0); 44360b57cec5SDimitry Andric 44370b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Op, DL, MVT::i64, MVT::i64, 44380b57cec5SDimitry Andric MVT::Other, MemAddr, Chain); 44390b57cec5SDimitry Andric 44400b57cec5SDimitry Andric // Transfer memoperands. 44410b57cec5SDimitry Andric MachineMemOperand *MemOp = 44420b57cec5SDimitry Andric cast<MemIntrinsicSDNode>(Node)->getMemOperand(); 44430b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp}); 44440b57cec5SDimitry Andric ReplaceNode(Node, Ld); 44450b57cec5SDimitry Andric return; 44460b57cec5SDimitry Andric } 44470b57cec5SDimitry Andric case Intrinsic::aarch64_stlxp: 44480b57cec5SDimitry Andric case Intrinsic::aarch64_stxp: { 44490b57cec5SDimitry Andric unsigned Op = 44500b57cec5SDimitry Andric IntNo == Intrinsic::aarch64_stlxp ? AArch64::STLXPX : AArch64::STXPX; 44510b57cec5SDimitry Andric SDLoc DL(Node); 44520b57cec5SDimitry Andric SDValue Chain = Node->getOperand(0); 44530b57cec5SDimitry Andric SDValue ValLo = Node->getOperand(2); 44540b57cec5SDimitry Andric SDValue ValHi = Node->getOperand(3); 44550b57cec5SDimitry Andric SDValue MemAddr = Node->getOperand(4); 44560b57cec5SDimitry Andric 44570b57cec5SDimitry Andric // Place arguments in the right order. 44580b57cec5SDimitry Andric SDValue Ops[] = {ValLo, ValHi, MemAddr, Chain}; 44590b57cec5SDimitry Andric 44600b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Op, DL, MVT::i32, MVT::Other, Ops); 44610b57cec5SDimitry Andric // Transfer memoperands. 44620b57cec5SDimitry Andric MachineMemOperand *MemOp = 44630b57cec5SDimitry Andric cast<MemIntrinsicSDNode>(Node)->getMemOperand(); 44640b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 44650b57cec5SDimitry Andric 44660b57cec5SDimitry Andric ReplaceNode(Node, St); 44670b57cec5SDimitry Andric return; 44680b57cec5SDimitry Andric } 44690b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x2: 44700b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44710b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov8b, AArch64::dsub0); 44720b57cec5SDimitry Andric return; 44730b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44740b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov16b, AArch64::qsub0); 44750b57cec5SDimitry Andric return; 44765ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44770b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov4h, AArch64::dsub0); 44780b57cec5SDimitry Andric return; 44795ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 44800b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov8h, AArch64::qsub0); 44810b57cec5SDimitry Andric return; 44820b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 44830b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov2s, AArch64::dsub0); 44840b57cec5SDimitry Andric return; 44850b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 44860b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov4s, AArch64::qsub0); 44870b57cec5SDimitry Andric return; 44880b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 44890b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0); 44900b57cec5SDimitry Andric return; 44910b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 44920b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov2d, AArch64::qsub0); 44930b57cec5SDimitry Andric return; 44940b57cec5SDimitry Andric } 44950b57cec5SDimitry Andric break; 44960b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x3: 44970b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44980b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev8b, AArch64::dsub0); 44990b57cec5SDimitry Andric return; 45000b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45010b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev16b, AArch64::qsub0); 45020b57cec5SDimitry Andric return; 45035ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45040b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev4h, AArch64::dsub0); 45050b57cec5SDimitry Andric return; 45065ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45070b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev8h, AArch64::qsub0); 45080b57cec5SDimitry Andric return; 45090b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45100b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev2s, AArch64::dsub0); 45110b57cec5SDimitry Andric return; 45120b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45130b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev4s, AArch64::qsub0); 45140b57cec5SDimitry Andric return; 45150b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45160b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0); 45170b57cec5SDimitry Andric return; 45180b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45190b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev2d, AArch64::qsub0); 45200b57cec5SDimitry Andric return; 45210b57cec5SDimitry Andric } 45220b57cec5SDimitry Andric break; 45230b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x4: 45240b57cec5SDimitry Andric if (VT == MVT::v8i8) { 45250b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv8b, AArch64::dsub0); 45260b57cec5SDimitry Andric return; 45270b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45280b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv16b, AArch64::qsub0); 45290b57cec5SDimitry Andric return; 45305ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45310b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv4h, AArch64::dsub0); 45320b57cec5SDimitry Andric return; 45335ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45340b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv8h, AArch64::qsub0); 45350b57cec5SDimitry Andric return; 45360b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45370b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv2s, AArch64::dsub0); 45380b57cec5SDimitry Andric return; 45390b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45400b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv4s, AArch64::qsub0); 45410b57cec5SDimitry Andric return; 45420b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45430b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0); 45440b57cec5SDimitry Andric return; 45450b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45460b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv2d, AArch64::qsub0); 45470b57cec5SDimitry Andric return; 45480b57cec5SDimitry Andric } 45490b57cec5SDimitry Andric break; 45500b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2: 45510b57cec5SDimitry Andric if (VT == MVT::v8i8) { 45520b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov8b, AArch64::dsub0); 45530b57cec5SDimitry Andric return; 45540b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45550b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov16b, AArch64::qsub0); 45560b57cec5SDimitry Andric return; 45575ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45580b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov4h, AArch64::dsub0); 45590b57cec5SDimitry Andric return; 45605ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45610b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov8h, AArch64::qsub0); 45620b57cec5SDimitry Andric return; 45630b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45640b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov2s, AArch64::dsub0); 45650b57cec5SDimitry Andric return; 45660b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45670b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov4s, AArch64::qsub0); 45680b57cec5SDimitry Andric return; 45690b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45700b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0); 45710b57cec5SDimitry Andric return; 45720b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45730b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov2d, AArch64::qsub0); 45740b57cec5SDimitry Andric return; 45750b57cec5SDimitry Andric } 45760b57cec5SDimitry Andric break; 45770b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3: 45780b57cec5SDimitry Andric if (VT == MVT::v8i8) { 45790b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev8b, AArch64::dsub0); 45800b57cec5SDimitry Andric return; 45810b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45820b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev16b, AArch64::qsub0); 45830b57cec5SDimitry Andric return; 45845ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45850b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev4h, AArch64::dsub0); 45860b57cec5SDimitry Andric return; 45875ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45880b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev8h, AArch64::qsub0); 45890b57cec5SDimitry Andric return; 45900b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45910b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev2s, AArch64::dsub0); 45920b57cec5SDimitry Andric return; 45930b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45940b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev4s, AArch64::qsub0); 45950b57cec5SDimitry Andric return; 45960b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45970b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0); 45980b57cec5SDimitry Andric return; 45990b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46000b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev2d, AArch64::qsub0); 46010b57cec5SDimitry Andric return; 46020b57cec5SDimitry Andric } 46030b57cec5SDimitry Andric break; 46040b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4: 46050b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46060b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv8b, AArch64::dsub0); 46070b57cec5SDimitry Andric return; 46080b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46090b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv16b, AArch64::qsub0); 46100b57cec5SDimitry Andric return; 46115ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46120b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv4h, AArch64::dsub0); 46130b57cec5SDimitry Andric return; 46145ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46150b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv8h, AArch64::qsub0); 46160b57cec5SDimitry Andric return; 46170b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46180b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv2s, AArch64::dsub0); 46190b57cec5SDimitry Andric return; 46200b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46210b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv4s, AArch64::qsub0); 46220b57cec5SDimitry Andric return; 46230b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 46240b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0); 46250b57cec5SDimitry Andric return; 46260b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46270b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv2d, AArch64::qsub0); 46280b57cec5SDimitry Andric return; 46290b57cec5SDimitry Andric } 46300b57cec5SDimitry Andric break; 46310b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2r: 46320b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46330b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv8b, AArch64::dsub0); 46340b57cec5SDimitry Andric return; 46350b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46360b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv16b, AArch64::qsub0); 46370b57cec5SDimitry Andric return; 46385ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46390b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv4h, AArch64::dsub0); 46400b57cec5SDimitry Andric return; 46415ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46420b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv8h, AArch64::qsub0); 46430b57cec5SDimitry Andric return; 46440b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46450b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv2s, AArch64::dsub0); 46460b57cec5SDimitry Andric return; 46470b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46480b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv4s, AArch64::qsub0); 46490b57cec5SDimitry Andric return; 46500b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 46510b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv1d, AArch64::dsub0); 46520b57cec5SDimitry Andric return; 46530b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46540b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv2d, AArch64::qsub0); 46550b57cec5SDimitry Andric return; 46560b57cec5SDimitry Andric } 46570b57cec5SDimitry Andric break; 46580b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3r: 46590b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46600b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv8b, AArch64::dsub0); 46610b57cec5SDimitry Andric return; 46620b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46630b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv16b, AArch64::qsub0); 46640b57cec5SDimitry Andric return; 46655ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46660b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv4h, AArch64::dsub0); 46670b57cec5SDimitry Andric return; 46685ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46690b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv8h, AArch64::qsub0); 46700b57cec5SDimitry Andric return; 46710b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46720b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv2s, AArch64::dsub0); 46730b57cec5SDimitry Andric return; 46740b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46750b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv4s, AArch64::qsub0); 46760b57cec5SDimitry Andric return; 46770b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 46780b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv1d, AArch64::dsub0); 46790b57cec5SDimitry Andric return; 46800b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46810b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv2d, AArch64::qsub0); 46820b57cec5SDimitry Andric return; 46830b57cec5SDimitry Andric } 46840b57cec5SDimitry Andric break; 46850b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4r: 46860b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46870b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv8b, AArch64::dsub0); 46880b57cec5SDimitry Andric return; 46890b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46900b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv16b, AArch64::qsub0); 46910b57cec5SDimitry Andric return; 46925ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46930b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv4h, AArch64::dsub0); 46940b57cec5SDimitry Andric return; 46955ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46960b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv8h, AArch64::qsub0); 46970b57cec5SDimitry Andric return; 46980b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46990b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv2s, AArch64::dsub0); 47000b57cec5SDimitry Andric return; 47010b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 47020b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv4s, AArch64::qsub0); 47030b57cec5SDimitry Andric return; 47040b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 47050b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv1d, AArch64::dsub0); 47060b57cec5SDimitry Andric return; 47070b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 47080b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv2d, AArch64::qsub0); 47090b57cec5SDimitry Andric return; 47100b57cec5SDimitry Andric } 47110b57cec5SDimitry Andric break; 47120b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2lane: 47130b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 47140b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i8); 47150b57cec5SDimitry Andric return; 47160b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 47175ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 47180b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i16); 47190b57cec5SDimitry Andric return; 47200b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 47210b57cec5SDimitry Andric VT == MVT::v2f32) { 47220b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i32); 47230b57cec5SDimitry Andric return; 47240b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 47250b57cec5SDimitry Andric VT == MVT::v1f64) { 47260b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i64); 47270b57cec5SDimitry Andric return; 47280b57cec5SDimitry Andric } 47290b57cec5SDimitry Andric break; 47300b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3lane: 47310b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 47320b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i8); 47330b57cec5SDimitry Andric return; 47340b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 47355ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 47360b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i16); 47370b57cec5SDimitry Andric return; 47380b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 47390b57cec5SDimitry Andric VT == MVT::v2f32) { 47400b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i32); 47410b57cec5SDimitry Andric return; 47420b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 47430b57cec5SDimitry Andric VT == MVT::v1f64) { 47440b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i64); 47450b57cec5SDimitry Andric return; 47460b57cec5SDimitry Andric } 47470b57cec5SDimitry Andric break; 47480b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4lane: 47490b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 47500b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i8); 47510b57cec5SDimitry Andric return; 47520b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 47535ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 47540b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i16); 47550b57cec5SDimitry Andric return; 47560b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 47570b57cec5SDimitry Andric VT == MVT::v2f32) { 47580b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i32); 47590b57cec5SDimitry Andric return; 47600b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 47610b57cec5SDimitry Andric VT == MVT::v1f64) { 47620b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i64); 47630b57cec5SDimitry Andric return; 47640b57cec5SDimitry Andric } 47650b57cec5SDimitry Andric break; 4766e8d8bef9SDimitry Andric case Intrinsic::aarch64_ld64b: 4767e8d8bef9SDimitry Andric SelectLoad(Node, 8, AArch64::LD64B, AArch64::x8sub_0); 4768e8d8bef9SDimitry Andric return; 4769*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld2q_sret: { 4770*5f757f3fSDimitry Andric SelectPredicatedLoad(Node, 2, 4, AArch64::LD2Q_IMM, AArch64::LD2Q, true); 4771*5f757f3fSDimitry Andric return; 4772*5f757f3fSDimitry Andric } 4773*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld3q_sret: { 4774*5f757f3fSDimitry Andric SelectPredicatedLoad(Node, 3, 4, AArch64::LD3Q_IMM, AArch64::LD3Q, true); 4775*5f757f3fSDimitry Andric return; 4776*5f757f3fSDimitry Andric } 4777*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld4q_sret: { 4778*5f757f3fSDimitry Andric SelectPredicatedLoad(Node, 4, 4, AArch64::LD4Q_IMM, AArch64::LD4Q, true); 4779*5f757f3fSDimitry Andric return; 4780*5f757f3fSDimitry Andric } 4781349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: { 4782349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4783349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B, 4784349cc55cSDimitry Andric true); 4785349cc55cSDimitry Andric return; 4786349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 478781ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4788349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H, 4789349cc55cSDimitry Andric true); 4790349cc55cSDimitry Andric return; 4791349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4792349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W, 4793349cc55cSDimitry Andric true); 4794349cc55cSDimitry Andric return; 4795349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4796349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D, 4797349cc55cSDimitry Andric true); 4798349cc55cSDimitry Andric return; 4799349cc55cSDimitry Andric } 4800349cc55cSDimitry Andric break; 4801349cc55cSDimitry Andric } 480206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ld1_pn_x2: { 480306c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 4804*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4805*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4806*5f757f3fSDimitry Andric Node, 2, 0, AArch64::LD1B_2Z_IMM_PSEUDO, AArch64::LD1B_2Z_PSEUDO); 4807*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4808*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 0, AArch64::LD1B_2Z_IMM, 4809*5f757f3fSDimitry Andric AArch64::LD1B_2Z); 4810*5f757f3fSDimitry Andric else 4811*5f757f3fSDimitry Andric break; 481206c3fb27SDimitry Andric return; 481306c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 481406c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 4815*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4816*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4817*5f757f3fSDimitry Andric Node, 2, 1, AArch64::LD1H_2Z_IMM_PSEUDO, AArch64::LD1H_2Z_PSEUDO); 4818*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4819*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 1, AArch64::LD1H_2Z_IMM, 4820*5f757f3fSDimitry Andric AArch64::LD1H_2Z); 4821*5f757f3fSDimitry Andric else 4822*5f757f3fSDimitry Andric break; 482306c3fb27SDimitry Andric return; 482406c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4825*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4826*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4827*5f757f3fSDimitry Andric Node, 2, 2, AArch64::LD1W_2Z_IMM_PSEUDO, AArch64::LD1W_2Z_PSEUDO); 4828*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4829*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 2, AArch64::LD1W_2Z_IMM, 4830*5f757f3fSDimitry Andric AArch64::LD1W_2Z); 4831*5f757f3fSDimitry Andric else 4832*5f757f3fSDimitry Andric break; 483306c3fb27SDimitry Andric return; 483406c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4835*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4836*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4837*5f757f3fSDimitry Andric Node, 2, 3, AArch64::LD1D_2Z_IMM_PSEUDO, AArch64::LD1D_2Z_PSEUDO); 4838*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4839*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 3, AArch64::LD1D_2Z_IMM, 4840*5f757f3fSDimitry Andric AArch64::LD1D_2Z); 4841*5f757f3fSDimitry Andric else 4842*5f757f3fSDimitry Andric break; 484306c3fb27SDimitry Andric return; 484406c3fb27SDimitry Andric } 484506c3fb27SDimitry Andric break; 484606c3fb27SDimitry Andric } 484706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ld1_pn_x4: { 484806c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 4849*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4850*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4851*5f757f3fSDimitry Andric Node, 4, 0, AArch64::LD1B_4Z_IMM_PSEUDO, AArch64::LD1B_4Z_PSEUDO); 4852*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4853*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 0, AArch64::LD1B_4Z_IMM, 4854*5f757f3fSDimitry Andric AArch64::LD1B_4Z); 4855*5f757f3fSDimitry Andric else 4856*5f757f3fSDimitry Andric break; 485706c3fb27SDimitry Andric return; 485806c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 485906c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 4860*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4861*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4862*5f757f3fSDimitry Andric Node, 4, 1, AArch64::LD1H_4Z_IMM_PSEUDO, AArch64::LD1H_4Z_PSEUDO); 4863*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4864*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 1, AArch64::LD1H_4Z_IMM, 4865*5f757f3fSDimitry Andric AArch64::LD1H_4Z); 4866*5f757f3fSDimitry Andric else 4867*5f757f3fSDimitry Andric break; 486806c3fb27SDimitry Andric return; 486906c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4870*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4871*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4872*5f757f3fSDimitry Andric Node, 4, 2, AArch64::LD1W_4Z_IMM_PSEUDO, AArch64::LD1W_4Z_PSEUDO); 4873*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4874*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 2, AArch64::LD1W_4Z_IMM, 4875*5f757f3fSDimitry Andric AArch64::LD1W_4Z); 4876*5f757f3fSDimitry Andric else 4877*5f757f3fSDimitry Andric break; 487806c3fb27SDimitry Andric return; 487906c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4880*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4881*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 4882*5f757f3fSDimitry Andric Node, 4, 3, AArch64::LD1D_4Z_IMM_PSEUDO, AArch64::LD1D_4Z_PSEUDO); 4883*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4884*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 3, AArch64::LD1D_4Z_IMM, 4885*5f757f3fSDimitry Andric AArch64::LD1D_4Z); 4886*5f757f3fSDimitry Andric else 4887*5f757f3fSDimitry Andric break; 488806c3fb27SDimitry Andric return; 488906c3fb27SDimitry Andric } 489006c3fb27SDimitry Andric break; 489106c3fb27SDimitry Andric } 489206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ldnt1_pn_x2: { 489306c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 4894*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4895*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 0, 4896*5f757f3fSDimitry Andric AArch64::LDNT1B_2Z_IMM_PSEUDO, 4897*5f757f3fSDimitry Andric AArch64::LDNT1B_2Z_PSEUDO); 4898*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4899*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 0, AArch64::LDNT1B_2Z_IMM, 4900*5f757f3fSDimitry Andric AArch64::LDNT1B_2Z); 4901*5f757f3fSDimitry Andric else 4902*5f757f3fSDimitry Andric break; 490306c3fb27SDimitry Andric return; 490406c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 490506c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 4906*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4907*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 1, 4908*5f757f3fSDimitry Andric AArch64::LDNT1H_2Z_IMM_PSEUDO, 4909*5f757f3fSDimitry Andric AArch64::LDNT1H_2Z_PSEUDO); 4910*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4911*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 1, AArch64::LDNT1H_2Z_IMM, 4912*5f757f3fSDimitry Andric AArch64::LDNT1H_2Z); 4913*5f757f3fSDimitry Andric else 4914*5f757f3fSDimitry Andric break; 491506c3fb27SDimitry Andric return; 491606c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4917*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4918*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 2, 4919*5f757f3fSDimitry Andric AArch64::LDNT1W_2Z_IMM_PSEUDO, 4920*5f757f3fSDimitry Andric AArch64::LDNT1W_2Z_PSEUDO); 4921*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4922*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 2, AArch64::LDNT1W_2Z_IMM, 4923*5f757f3fSDimitry Andric AArch64::LDNT1W_2Z); 4924*5f757f3fSDimitry Andric else 4925*5f757f3fSDimitry Andric break; 492606c3fb27SDimitry Andric return; 492706c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4928*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4929*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 3, 4930*5f757f3fSDimitry Andric AArch64::LDNT1D_2Z_IMM_PSEUDO, 4931*5f757f3fSDimitry Andric AArch64::LDNT1D_2Z_PSEUDO); 4932*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4933*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 3, AArch64::LDNT1D_2Z_IMM, 4934*5f757f3fSDimitry Andric AArch64::LDNT1D_2Z); 4935*5f757f3fSDimitry Andric else 4936*5f757f3fSDimitry Andric break; 493706c3fb27SDimitry Andric return; 493806c3fb27SDimitry Andric } 493906c3fb27SDimitry Andric break; 494006c3fb27SDimitry Andric } 494106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ldnt1_pn_x4: { 494206c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 4943*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4944*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 0, 4945*5f757f3fSDimitry Andric AArch64::LDNT1B_4Z_IMM_PSEUDO, 4946*5f757f3fSDimitry Andric AArch64::LDNT1B_4Z_PSEUDO); 4947*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4948*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 0, AArch64::LDNT1B_4Z_IMM, 4949*5f757f3fSDimitry Andric AArch64::LDNT1B_4Z); 4950*5f757f3fSDimitry Andric else 4951*5f757f3fSDimitry Andric break; 495206c3fb27SDimitry Andric return; 495306c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 495406c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 4955*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4956*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 1, 4957*5f757f3fSDimitry Andric AArch64::LDNT1H_4Z_IMM_PSEUDO, 4958*5f757f3fSDimitry Andric AArch64::LDNT1H_4Z_PSEUDO); 4959*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4960*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 1, AArch64::LDNT1H_4Z_IMM, 4961*5f757f3fSDimitry Andric AArch64::LDNT1H_4Z); 4962*5f757f3fSDimitry Andric else 4963*5f757f3fSDimitry Andric break; 496406c3fb27SDimitry Andric return; 496506c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4966*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4967*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 2, 4968*5f757f3fSDimitry Andric AArch64::LDNT1W_4Z_IMM_PSEUDO, 4969*5f757f3fSDimitry Andric AArch64::LDNT1W_4Z_PSEUDO); 4970*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4971*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 2, AArch64::LDNT1W_4Z_IMM, 4972*5f757f3fSDimitry Andric AArch64::LDNT1W_4Z); 4973*5f757f3fSDimitry Andric else 4974*5f757f3fSDimitry Andric break; 497506c3fb27SDimitry Andric return; 497606c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4977*5f757f3fSDimitry Andric if (Subtarget->hasSME2()) 4978*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 3, 4979*5f757f3fSDimitry Andric AArch64::LDNT1D_4Z_IMM_PSEUDO, 4980*5f757f3fSDimitry Andric AArch64::LDNT1D_4Z_PSEUDO); 4981*5f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 4982*5f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 3, AArch64::LDNT1D_4Z_IMM, 4983*5f757f3fSDimitry Andric AArch64::LDNT1D_4Z); 4984*5f757f3fSDimitry Andric else 4985*5f757f3fSDimitry Andric break; 498606c3fb27SDimitry Andric return; 498706c3fb27SDimitry Andric } 498806c3fb27SDimitry Andric break; 498906c3fb27SDimitry Andric } 4990349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: { 4991349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4992349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B, 4993349cc55cSDimitry Andric true); 4994349cc55cSDimitry Andric return; 4995349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 499681ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4997349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H, 4998349cc55cSDimitry Andric true); 4999349cc55cSDimitry Andric return; 5000349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5001349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W, 5002349cc55cSDimitry Andric true); 5003349cc55cSDimitry Andric return; 5004349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5005349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D, 5006349cc55cSDimitry Andric true); 5007349cc55cSDimitry Andric return; 5008349cc55cSDimitry Andric } 5009349cc55cSDimitry Andric break; 5010349cc55cSDimitry Andric } 5011349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: { 5012349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 5013349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B, 5014349cc55cSDimitry Andric true); 5015349cc55cSDimitry Andric return; 5016349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 501781ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5018349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H, 5019349cc55cSDimitry Andric true); 5020349cc55cSDimitry Andric return; 5021349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5022349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W, 5023349cc55cSDimitry Andric true); 5024349cc55cSDimitry Andric return; 5025349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5026349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D, 5027349cc55cSDimitry Andric true); 5028349cc55cSDimitry Andric return; 5029349cc55cSDimitry Andric } 5030349cc55cSDimitry Andric break; 5031349cc55cSDimitry Andric } 503206c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_hor_vg2: { 503306c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 503406c3fb27SDimitry Andric SelectMultiVectorMove<14, 2>(Node, 2, AArch64::ZAB0, 503506c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_B); 503606c3fb27SDimitry Andric return; 503706c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 503806c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 503906c3fb27SDimitry Andric SelectMultiVectorMove<6, 2>(Node, 2, AArch64::ZAH0, 504006c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_H); 504106c3fb27SDimitry Andric return; 504206c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 504306c3fb27SDimitry Andric SelectMultiVectorMove<2, 2>(Node, 2, AArch64::ZAS0, 504406c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_S); 504506c3fb27SDimitry Andric return; 504606c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 504706c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 2, AArch64::ZAD0, 504806c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_D); 504906c3fb27SDimitry Andric return; 505006c3fb27SDimitry Andric } 505106c3fb27SDimitry Andric break; 505206c3fb27SDimitry Andric } 505306c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_ver_vg2: { 505406c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 505506c3fb27SDimitry Andric SelectMultiVectorMove<14, 2>(Node, 2, AArch64::ZAB0, 505606c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_B); 505706c3fb27SDimitry Andric return; 505806c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 505906c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 506006c3fb27SDimitry Andric SelectMultiVectorMove<6, 2>(Node, 2, AArch64::ZAH0, 506106c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_H); 506206c3fb27SDimitry Andric return; 506306c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 506406c3fb27SDimitry Andric SelectMultiVectorMove<2, 2>(Node, 2, AArch64::ZAS0, 506506c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_S); 506606c3fb27SDimitry Andric return; 506706c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 506806c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 2, AArch64::ZAD0, 506906c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_D); 507006c3fb27SDimitry Andric return; 507106c3fb27SDimitry Andric } 507206c3fb27SDimitry Andric break; 507306c3fb27SDimitry Andric } 507406c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_hor_vg4: { 507506c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 507606c3fb27SDimitry Andric SelectMultiVectorMove<12, 4>(Node, 4, AArch64::ZAB0, 507706c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_B); 507806c3fb27SDimitry Andric return; 507906c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 508006c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 508106c3fb27SDimitry Andric SelectMultiVectorMove<4, 4>(Node, 4, AArch64::ZAH0, 508206c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_H); 508306c3fb27SDimitry Andric return; 508406c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 508506c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 4, AArch64::ZAS0, 508606c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_S); 508706c3fb27SDimitry Andric return; 508806c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 508906c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 4, AArch64::ZAD0, 509006c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_D); 509106c3fb27SDimitry Andric return; 509206c3fb27SDimitry Andric } 509306c3fb27SDimitry Andric break; 509406c3fb27SDimitry Andric } 509506c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_ver_vg4: { 509606c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 509706c3fb27SDimitry Andric SelectMultiVectorMove<12, 4>(Node, 4, AArch64::ZAB0, 509806c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_B); 509906c3fb27SDimitry Andric return; 510006c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 510106c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 510206c3fb27SDimitry Andric SelectMultiVectorMove<4, 4>(Node, 4, AArch64::ZAH0, 510306c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_H); 510406c3fb27SDimitry Andric return; 510506c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 510606c3fb27SDimitry Andric SelectMultiVectorMove<0, 4>(Node, 4, AArch64::ZAS0, 510706c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_S); 510806c3fb27SDimitry Andric return; 510906c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 511006c3fb27SDimitry Andric SelectMultiVectorMove<0, 4>(Node, 4, AArch64::ZAD0, 511106c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_D); 511206c3fb27SDimitry Andric return; 511306c3fb27SDimitry Andric } 511406c3fb27SDimitry Andric break; 511506c3fb27SDimitry Andric } 511606c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_vg1x2: { 511706c3fb27SDimitry Andric SelectMultiVectorMove<7, 1>(Node, 2, AArch64::ZA, 511806c3fb27SDimitry Andric AArch64::MOVA_VG2_2ZMXI); 511906c3fb27SDimitry Andric return; 512006c3fb27SDimitry Andric } 512106c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_vg1x4: { 512206c3fb27SDimitry Andric SelectMultiVectorMove<7, 1>(Node, 4, AArch64::ZA, 512306c3fb27SDimitry Andric AArch64::MOVA_VG4_4ZMXI); 512406c3fb27SDimitry Andric return; 512506c3fb27SDimitry Andric } 5126fcaf7f86SDimitry Andric case Intrinsic::swift_async_context_addr: { 5127fcaf7f86SDimitry Andric SDLoc DL(Node); 5128fcaf7f86SDimitry Andric SDValue Chain = Node->getOperand(0); 5129fcaf7f86SDimitry Andric SDValue CopyFP = CurDAG->getCopyFromReg(Chain, DL, AArch64::FP, MVT::i64); 5130fcaf7f86SDimitry Andric SDValue Res = SDValue( 5131fcaf7f86SDimitry Andric CurDAG->getMachineNode(AArch64::SUBXri, DL, MVT::i64, CopyFP, 5132fcaf7f86SDimitry Andric CurDAG->getTargetConstant(8, DL, MVT::i32), 5133fcaf7f86SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i32)), 5134fcaf7f86SDimitry Andric 0); 5135fcaf7f86SDimitry Andric ReplaceUses(SDValue(Node, 0), Res); 5136fcaf7f86SDimitry Andric ReplaceUses(SDValue(Node, 1), CopyFP.getValue(1)); 5137fcaf7f86SDimitry Andric CurDAG->RemoveDeadNode(Node); 5138fcaf7f86SDimitry Andric 5139fcaf7f86SDimitry Andric auto &MF = CurDAG->getMachineFunction(); 5140fcaf7f86SDimitry Andric MF.getFrameInfo().setFrameAddressIsTaken(true); 5141fcaf7f86SDimitry Andric MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); 5142fcaf7f86SDimitry Andric return; 5143fcaf7f86SDimitry Andric } 5144*5f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti2_lane_zt_x4: { 5145*5f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 5146*5f757f3fSDimitry Andric Node->getValueType(0), 5147*5f757f3fSDimitry Andric {AArch64::LUTI2_4ZTZI_B, AArch64::LUTI2_4ZTZI_H, 5148*5f757f3fSDimitry Andric AArch64::LUTI2_4ZTZI_S})) 5149*5f757f3fSDimitry Andric // Second Immediate must be <= 3: 5150*5f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 4, Opc, 3); 5151*5f757f3fSDimitry Andric return; 5152*5f757f3fSDimitry Andric } 5153*5f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti4_lane_zt_x4: { 5154*5f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 5155*5f757f3fSDimitry Andric Node->getValueType(0), 5156*5f757f3fSDimitry Andric {0, AArch64::LUTI4_4ZTZI_H, AArch64::LUTI4_4ZTZI_S})) 5157*5f757f3fSDimitry Andric // Second Immediate must be <= 1: 5158*5f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 4, Opc, 1); 5159*5f757f3fSDimitry Andric return; 5160*5f757f3fSDimitry Andric } 5161*5f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti2_lane_zt_x2: { 5162*5f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 5163*5f757f3fSDimitry Andric Node->getValueType(0), 5164*5f757f3fSDimitry Andric {AArch64::LUTI2_2ZTZI_B, AArch64::LUTI2_2ZTZI_H, 5165*5f757f3fSDimitry Andric AArch64::LUTI2_2ZTZI_S})) 5166*5f757f3fSDimitry Andric // Second Immediate must be <= 7: 5167*5f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 2, Opc, 7); 5168*5f757f3fSDimitry Andric return; 5169*5f757f3fSDimitry Andric } 5170*5f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti4_lane_zt_x2: { 5171*5f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 5172*5f757f3fSDimitry Andric Node->getValueType(0), 5173*5f757f3fSDimitry Andric {AArch64::LUTI4_2ZTZI_B, AArch64::LUTI4_2ZTZI_H, 5174*5f757f3fSDimitry Andric AArch64::LUTI4_2ZTZI_S})) 5175*5f757f3fSDimitry Andric // Second Immediate must be <= 3: 5176*5f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 2, Opc, 3); 5177*5f757f3fSDimitry Andric return; 5178*5f757f3fSDimitry Andric } 51790b57cec5SDimitry Andric } 51800b57cec5SDimitry Andric } break; 51810b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 51820b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue(); 51830b57cec5SDimitry Andric switch (IntNo) { 51840b57cec5SDimitry Andric default: 51850b57cec5SDimitry Andric break; 51860b57cec5SDimitry Andric case Intrinsic::aarch64_tagp: 51870b57cec5SDimitry Andric SelectTagP(Node); 51880b57cec5SDimitry Andric return; 51890b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl2: 51900b57cec5SDimitry Andric SelectTable(Node, 2, 51910b57cec5SDimitry Andric VT == MVT::v8i8 ? AArch64::TBLv8i8Two : AArch64::TBLv16i8Two, 51920b57cec5SDimitry Andric false); 51930b57cec5SDimitry Andric return; 51940b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl3: 51950b57cec5SDimitry Andric SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBLv8i8Three 51960b57cec5SDimitry Andric : AArch64::TBLv16i8Three, 51970b57cec5SDimitry Andric false); 51980b57cec5SDimitry Andric return; 51990b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl4: 52000b57cec5SDimitry Andric SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBLv8i8Four 52010b57cec5SDimitry Andric : AArch64::TBLv16i8Four, 52020b57cec5SDimitry Andric false); 52030b57cec5SDimitry Andric return; 52040b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx2: 52050b57cec5SDimitry Andric SelectTable(Node, 2, 52060b57cec5SDimitry Andric VT == MVT::v8i8 ? AArch64::TBXv8i8Two : AArch64::TBXv16i8Two, 52070b57cec5SDimitry Andric true); 52080b57cec5SDimitry Andric return; 52090b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx3: 52100b57cec5SDimitry Andric SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBXv8i8Three 52110b57cec5SDimitry Andric : AArch64::TBXv16i8Three, 52120b57cec5SDimitry Andric true); 52130b57cec5SDimitry Andric return; 52140b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx4: 52150b57cec5SDimitry Andric SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBXv8i8Four 52160b57cec5SDimitry Andric : AArch64::TBXv16i8Four, 52170b57cec5SDimitry Andric true); 52180b57cec5SDimitry Andric return; 521906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_single_x2: 522006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 522106c3fb27SDimitry Andric Node->getValueType(0), 522206c3fb27SDimitry Andric {AArch64::SRSHL_VG2_2ZZ_B, AArch64::SRSHL_VG2_2ZZ_H, 522306c3fb27SDimitry Andric AArch64::SRSHL_VG2_2ZZ_S, AArch64::SRSHL_VG2_2ZZ_D})) 522406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 52250b57cec5SDimitry Andric return; 522606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_single_x4: 522706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 522806c3fb27SDimitry Andric Node->getValueType(0), 522906c3fb27SDimitry Andric {AArch64::SRSHL_VG4_4ZZ_B, AArch64::SRSHL_VG4_4ZZ_H, 523006c3fb27SDimitry Andric AArch64::SRSHL_VG4_4ZZ_S, AArch64::SRSHL_VG4_4ZZ_D})) 523106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 523206c3fb27SDimitry Andric return; 523306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_single_x2: 523406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 523506c3fb27SDimitry Andric Node->getValueType(0), 523606c3fb27SDimitry Andric {AArch64::URSHL_VG2_2ZZ_B, AArch64::URSHL_VG2_2ZZ_H, 523706c3fb27SDimitry Andric AArch64::URSHL_VG2_2ZZ_S, AArch64::URSHL_VG2_2ZZ_D})) 523806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 523906c3fb27SDimitry Andric return; 524006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_single_x4: 524106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 524206c3fb27SDimitry Andric Node->getValueType(0), 524306c3fb27SDimitry Andric {AArch64::URSHL_VG4_4ZZ_B, AArch64::URSHL_VG4_4ZZ_H, 524406c3fb27SDimitry Andric AArch64::URSHL_VG4_4ZZ_S, AArch64::URSHL_VG4_4ZZ_D})) 524506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 524606c3fb27SDimitry Andric return; 524706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_x2: 524806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 524906c3fb27SDimitry Andric Node->getValueType(0), 525006c3fb27SDimitry Andric {AArch64::SRSHL_VG2_2Z2Z_B, AArch64::SRSHL_VG2_2Z2Z_H, 525106c3fb27SDimitry Andric AArch64::SRSHL_VG2_2Z2Z_S, AArch64::SRSHL_VG2_2Z2Z_D})) 525206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 525306c3fb27SDimitry Andric return; 525406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_x4: 525506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 525606c3fb27SDimitry Andric Node->getValueType(0), 525706c3fb27SDimitry Andric {AArch64::SRSHL_VG4_4Z4Z_B, AArch64::SRSHL_VG4_4Z4Z_H, 525806c3fb27SDimitry Andric AArch64::SRSHL_VG4_4Z4Z_S, AArch64::SRSHL_VG4_4Z4Z_D})) 525906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 526006c3fb27SDimitry Andric return; 526106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_x2: 526206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 526306c3fb27SDimitry Andric Node->getValueType(0), 526406c3fb27SDimitry Andric {AArch64::URSHL_VG2_2Z2Z_B, AArch64::URSHL_VG2_2Z2Z_H, 526506c3fb27SDimitry Andric AArch64::URSHL_VG2_2Z2Z_S, AArch64::URSHL_VG2_2Z2Z_D})) 526606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 526706c3fb27SDimitry Andric return; 526806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_x4: 526906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 527006c3fb27SDimitry Andric Node->getValueType(0), 527106c3fb27SDimitry Andric {AArch64::URSHL_VG4_4Z4Z_B, AArch64::URSHL_VG4_4Z4Z_H, 527206c3fb27SDimitry Andric AArch64::URSHL_VG4_4Z4Z_S, AArch64::URSHL_VG4_4Z4Z_D})) 527306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 527406c3fb27SDimitry Andric return; 527506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_single_vgx2: 527606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 527706c3fb27SDimitry Andric Node->getValueType(0), 527806c3fb27SDimitry Andric {AArch64::SQDMULH_VG2_2ZZ_B, AArch64::SQDMULH_VG2_2ZZ_H, 527906c3fb27SDimitry Andric AArch64::SQDMULH_VG2_2ZZ_S, AArch64::SQDMULH_VG2_2ZZ_D})) 528006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 528106c3fb27SDimitry Andric return; 528206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_single_vgx4: 528306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 528406c3fb27SDimitry Andric Node->getValueType(0), 528506c3fb27SDimitry Andric {AArch64::SQDMULH_VG4_4ZZ_B, AArch64::SQDMULH_VG4_4ZZ_H, 528606c3fb27SDimitry Andric AArch64::SQDMULH_VG4_4ZZ_S, AArch64::SQDMULH_VG4_4ZZ_D})) 528706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 528806c3fb27SDimitry Andric return; 528906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_vgx2: 529006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 529106c3fb27SDimitry Andric Node->getValueType(0), 529206c3fb27SDimitry Andric {AArch64::SQDMULH_VG2_2Z2Z_B, AArch64::SQDMULH_VG2_2Z2Z_H, 529306c3fb27SDimitry Andric AArch64::SQDMULH_VG2_2Z2Z_S, AArch64::SQDMULH_VG2_2Z2Z_D})) 529406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 529506c3fb27SDimitry Andric return; 529606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_vgx4: 529706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 529806c3fb27SDimitry Andric Node->getValueType(0), 529906c3fb27SDimitry Andric {AArch64::SQDMULH_VG4_4Z4Z_B, AArch64::SQDMULH_VG4_4Z4Z_H, 530006c3fb27SDimitry Andric AArch64::SQDMULH_VG4_4Z4Z_S, AArch64::SQDMULH_VG4_4Z4Z_D})) 530106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 530206c3fb27SDimitry Andric return; 5303bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilege_x2: 5304bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5305bdd1243dSDimitry Andric Node->getValueType(0), 5306bdd1243dSDimitry Andric {AArch64::WHILEGE_2PXX_B, AArch64::WHILEGE_2PXX_H, 5307bdd1243dSDimitry Andric AArch64::WHILEGE_2PXX_S, AArch64::WHILEGE_2PXX_D})) 5308bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5309bdd1243dSDimitry Andric return; 5310bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilegt_x2: 5311bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5312bdd1243dSDimitry Andric Node->getValueType(0), 5313bdd1243dSDimitry Andric {AArch64::WHILEGT_2PXX_B, AArch64::WHILEGT_2PXX_H, 5314bdd1243dSDimitry Andric AArch64::WHILEGT_2PXX_S, AArch64::WHILEGT_2PXX_D})) 5315bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5316bdd1243dSDimitry Andric return; 5317bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilehi_x2: 5318bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5319bdd1243dSDimitry Andric Node->getValueType(0), 5320bdd1243dSDimitry Andric {AArch64::WHILEHI_2PXX_B, AArch64::WHILEHI_2PXX_H, 5321bdd1243dSDimitry Andric AArch64::WHILEHI_2PXX_S, AArch64::WHILEHI_2PXX_D})) 5322bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5323bdd1243dSDimitry Andric return; 5324bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilehs_x2: 5325bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5326bdd1243dSDimitry Andric Node->getValueType(0), 5327bdd1243dSDimitry Andric {AArch64::WHILEHS_2PXX_B, AArch64::WHILEHS_2PXX_H, 5328bdd1243dSDimitry Andric AArch64::WHILEHS_2PXX_S, AArch64::WHILEHS_2PXX_D})) 5329bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5330bdd1243dSDimitry Andric return; 5331bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilele_x2: 5332bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5333bdd1243dSDimitry Andric Node->getValueType(0), 5334bdd1243dSDimitry Andric {AArch64::WHILELE_2PXX_B, AArch64::WHILELE_2PXX_H, 5335bdd1243dSDimitry Andric AArch64::WHILELE_2PXX_S, AArch64::WHILELE_2PXX_D})) 5336bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5337bdd1243dSDimitry Andric return; 5338bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilelo_x2: 5339bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5340bdd1243dSDimitry Andric Node->getValueType(0), 5341bdd1243dSDimitry Andric {AArch64::WHILELO_2PXX_B, AArch64::WHILELO_2PXX_H, 5342bdd1243dSDimitry Andric AArch64::WHILELO_2PXX_S, AArch64::WHILELO_2PXX_D})) 5343bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5344bdd1243dSDimitry Andric return; 5345bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilels_x2: 5346bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5347bdd1243dSDimitry Andric Node->getValueType(0), 5348bdd1243dSDimitry Andric {AArch64::WHILELS_2PXX_B, AArch64::WHILELS_2PXX_H, 5349bdd1243dSDimitry Andric AArch64::WHILELS_2PXX_S, AArch64::WHILELS_2PXX_D})) 5350bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5351bdd1243dSDimitry Andric return; 5352bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilelt_x2: 5353bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5354bdd1243dSDimitry Andric Node->getValueType(0), 5355bdd1243dSDimitry Andric {AArch64::WHILELT_2PXX_B, AArch64::WHILELT_2PXX_H, 5356bdd1243dSDimitry Andric AArch64::WHILELT_2PXX_S, AArch64::WHILELT_2PXX_D})) 5357bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5358bdd1243dSDimitry Andric return; 535906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_single_x2: 536006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 536106c3fb27SDimitry Andric Node->getValueType(0), 536206c3fb27SDimitry Andric {AArch64::SMAX_VG2_2ZZ_B, AArch64::SMAX_VG2_2ZZ_H, 536306c3fb27SDimitry Andric AArch64::SMAX_VG2_2ZZ_S, AArch64::SMAX_VG2_2ZZ_D})) 536406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 536506c3fb27SDimitry Andric return; 536606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_single_x2: 536706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 536806c3fb27SDimitry Andric Node->getValueType(0), 536906c3fb27SDimitry Andric {AArch64::UMAX_VG2_2ZZ_B, AArch64::UMAX_VG2_2ZZ_H, 537006c3fb27SDimitry Andric AArch64::UMAX_VG2_2ZZ_S, AArch64::UMAX_VG2_2ZZ_D})) 537106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 537206c3fb27SDimitry Andric return; 537306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_single_x2: 537406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 537506c3fb27SDimitry Andric Node->getValueType(0), 537606c3fb27SDimitry Andric {0, AArch64::FMAX_VG2_2ZZ_H, AArch64::FMAX_VG2_2ZZ_S, 537706c3fb27SDimitry Andric AArch64::FMAX_VG2_2ZZ_D})) 537806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 537906c3fb27SDimitry Andric return; 538006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_single_x4: 538106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 538206c3fb27SDimitry Andric Node->getValueType(0), 538306c3fb27SDimitry Andric {AArch64::SMAX_VG4_4ZZ_B, AArch64::SMAX_VG4_4ZZ_H, 538406c3fb27SDimitry Andric AArch64::SMAX_VG4_4ZZ_S, AArch64::SMAX_VG4_4ZZ_D})) 538506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 538606c3fb27SDimitry Andric return; 538706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_single_x4: 538806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 538906c3fb27SDimitry Andric Node->getValueType(0), 539006c3fb27SDimitry Andric {AArch64::UMAX_VG4_4ZZ_B, AArch64::UMAX_VG4_4ZZ_H, 539106c3fb27SDimitry Andric AArch64::UMAX_VG4_4ZZ_S, AArch64::UMAX_VG4_4ZZ_D})) 539206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 539306c3fb27SDimitry Andric return; 539406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_single_x4: 539506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 539606c3fb27SDimitry Andric Node->getValueType(0), 539706c3fb27SDimitry Andric {0, AArch64::FMAX_VG4_4ZZ_H, AArch64::FMAX_VG4_4ZZ_S, 539806c3fb27SDimitry Andric AArch64::FMAX_VG4_4ZZ_D})) 539906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 540006c3fb27SDimitry Andric return; 540106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_single_x2: 540206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 540306c3fb27SDimitry Andric Node->getValueType(0), 540406c3fb27SDimitry Andric {AArch64::SMIN_VG2_2ZZ_B, AArch64::SMIN_VG2_2ZZ_H, 540506c3fb27SDimitry Andric AArch64::SMIN_VG2_2ZZ_S, AArch64::SMIN_VG2_2ZZ_D})) 540606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 540706c3fb27SDimitry Andric return; 540806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_single_x2: 540906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 541006c3fb27SDimitry Andric Node->getValueType(0), 541106c3fb27SDimitry Andric {AArch64::UMIN_VG2_2ZZ_B, AArch64::UMIN_VG2_2ZZ_H, 541206c3fb27SDimitry Andric AArch64::UMIN_VG2_2ZZ_S, AArch64::UMIN_VG2_2ZZ_D})) 541306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 541406c3fb27SDimitry Andric return; 541506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_single_x2: 541606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 541706c3fb27SDimitry Andric Node->getValueType(0), 541806c3fb27SDimitry Andric {0, AArch64::FMIN_VG2_2ZZ_H, AArch64::FMIN_VG2_2ZZ_S, 541906c3fb27SDimitry Andric AArch64::FMIN_VG2_2ZZ_D})) 542006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 542106c3fb27SDimitry Andric return; 542206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_single_x4: 542306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 542406c3fb27SDimitry Andric Node->getValueType(0), 542506c3fb27SDimitry Andric {AArch64::SMIN_VG4_4ZZ_B, AArch64::SMIN_VG4_4ZZ_H, 542606c3fb27SDimitry Andric AArch64::SMIN_VG4_4ZZ_S, AArch64::SMIN_VG4_4ZZ_D})) 542706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 542806c3fb27SDimitry Andric return; 542906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_single_x4: 543006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 543106c3fb27SDimitry Andric Node->getValueType(0), 543206c3fb27SDimitry Andric {AArch64::UMIN_VG4_4ZZ_B, AArch64::UMIN_VG4_4ZZ_H, 543306c3fb27SDimitry Andric AArch64::UMIN_VG4_4ZZ_S, AArch64::UMIN_VG4_4ZZ_D})) 543406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 543506c3fb27SDimitry Andric return; 543606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_single_x4: 543706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 543806c3fb27SDimitry Andric Node->getValueType(0), 543906c3fb27SDimitry Andric {0, AArch64::FMIN_VG4_4ZZ_H, AArch64::FMIN_VG4_4ZZ_S, 544006c3fb27SDimitry Andric AArch64::FMIN_VG4_4ZZ_D})) 544106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 544206c3fb27SDimitry Andric return; 544306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_x2: 544406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 544506c3fb27SDimitry Andric Node->getValueType(0), 544606c3fb27SDimitry Andric {AArch64::SMAX_VG2_2Z2Z_B, AArch64::SMAX_VG2_2Z2Z_H, 544706c3fb27SDimitry Andric AArch64::SMAX_VG2_2Z2Z_S, AArch64::SMAX_VG2_2Z2Z_D})) 544806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 544906c3fb27SDimitry Andric return; 545006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_x2: 545106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 545206c3fb27SDimitry Andric Node->getValueType(0), 545306c3fb27SDimitry Andric {AArch64::UMAX_VG2_2Z2Z_B, AArch64::UMAX_VG2_2Z2Z_H, 545406c3fb27SDimitry Andric AArch64::UMAX_VG2_2Z2Z_S, AArch64::UMAX_VG2_2Z2Z_D})) 545506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 545606c3fb27SDimitry Andric return; 545706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_x2: 545806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 545906c3fb27SDimitry Andric Node->getValueType(0), 546006c3fb27SDimitry Andric {0, AArch64::FMAX_VG2_2Z2Z_H, AArch64::FMAX_VG2_2Z2Z_S, 546106c3fb27SDimitry Andric AArch64::FMAX_VG2_2Z2Z_D})) 546206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 546306c3fb27SDimitry Andric return; 546406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_x4: 546506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 546606c3fb27SDimitry Andric Node->getValueType(0), 546706c3fb27SDimitry Andric {AArch64::SMAX_VG4_4Z4Z_B, AArch64::SMAX_VG4_4Z4Z_H, 546806c3fb27SDimitry Andric AArch64::SMAX_VG4_4Z4Z_S, AArch64::SMAX_VG4_4Z4Z_D})) 546906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 547006c3fb27SDimitry Andric return; 547106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_x4: 547206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 547306c3fb27SDimitry Andric Node->getValueType(0), 547406c3fb27SDimitry Andric {AArch64::UMAX_VG4_4Z4Z_B, AArch64::UMAX_VG4_4Z4Z_H, 547506c3fb27SDimitry Andric AArch64::UMAX_VG4_4Z4Z_S, AArch64::UMAX_VG4_4Z4Z_D})) 547606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 547706c3fb27SDimitry Andric return; 547806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_x4: 547906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 548006c3fb27SDimitry Andric Node->getValueType(0), 548106c3fb27SDimitry Andric {0, AArch64::FMAX_VG4_4Z4Z_H, AArch64::FMAX_VG4_4Z4Z_S, 548206c3fb27SDimitry Andric AArch64::FMAX_VG4_4Z4Z_D})) 548306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 548406c3fb27SDimitry Andric return; 548506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_x2: 548606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 548706c3fb27SDimitry Andric Node->getValueType(0), 548806c3fb27SDimitry Andric {AArch64::SMIN_VG2_2Z2Z_B, AArch64::SMIN_VG2_2Z2Z_H, 548906c3fb27SDimitry Andric AArch64::SMIN_VG2_2Z2Z_S, AArch64::SMIN_VG2_2Z2Z_D})) 549006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 549106c3fb27SDimitry Andric return; 549206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_x2: 549306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 549406c3fb27SDimitry Andric Node->getValueType(0), 549506c3fb27SDimitry Andric {AArch64::UMIN_VG2_2Z2Z_B, AArch64::UMIN_VG2_2Z2Z_H, 549606c3fb27SDimitry Andric AArch64::UMIN_VG2_2Z2Z_S, AArch64::UMIN_VG2_2Z2Z_D})) 549706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 549806c3fb27SDimitry Andric return; 549906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_x2: 550006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 550106c3fb27SDimitry Andric Node->getValueType(0), 550206c3fb27SDimitry Andric {0, AArch64::FMIN_VG2_2Z2Z_H, AArch64::FMIN_VG2_2Z2Z_S, 550306c3fb27SDimitry Andric AArch64::FMIN_VG2_2Z2Z_D})) 550406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 550506c3fb27SDimitry Andric return; 550606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_x4: 550706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 550806c3fb27SDimitry Andric Node->getValueType(0), 550906c3fb27SDimitry Andric {AArch64::SMIN_VG4_4Z4Z_B, AArch64::SMIN_VG4_4Z4Z_H, 551006c3fb27SDimitry Andric AArch64::SMIN_VG4_4Z4Z_S, AArch64::SMIN_VG4_4Z4Z_D})) 551106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 551206c3fb27SDimitry Andric return; 551306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_x4: 551406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 551506c3fb27SDimitry Andric Node->getValueType(0), 551606c3fb27SDimitry Andric {AArch64::UMIN_VG4_4Z4Z_B, AArch64::UMIN_VG4_4Z4Z_H, 551706c3fb27SDimitry Andric AArch64::UMIN_VG4_4Z4Z_S, AArch64::UMIN_VG4_4Z4Z_D})) 551806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 551906c3fb27SDimitry Andric return; 552006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_x4: 552106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 552206c3fb27SDimitry Andric Node->getValueType(0), 552306c3fb27SDimitry Andric {0, AArch64::FMIN_VG4_4Z4Z_H, AArch64::FMIN_VG4_4Z4Z_S, 552406c3fb27SDimitry Andric AArch64::FMIN_VG4_4Z4Z_D})) 552506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 552606c3fb27SDimitry Andric return; 552706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_single_x2 : 552806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 552906c3fb27SDimitry Andric Node->getValueType(0), 553006c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG2_2ZZ_H, AArch64::FMAXNM_VG2_2ZZ_S, 553106c3fb27SDimitry Andric AArch64::FMAXNM_VG2_2ZZ_D})) 553206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 553306c3fb27SDimitry Andric return; 553406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_single_x4 : 553506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 553606c3fb27SDimitry Andric Node->getValueType(0), 553706c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG4_4ZZ_H, AArch64::FMAXNM_VG4_4ZZ_S, 553806c3fb27SDimitry Andric AArch64::FMAXNM_VG4_4ZZ_D})) 553906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 554006c3fb27SDimitry Andric return; 554106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_single_x2: 554206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 554306c3fb27SDimitry Andric Node->getValueType(0), 554406c3fb27SDimitry Andric {0, AArch64::FMINNM_VG2_2ZZ_H, AArch64::FMINNM_VG2_2ZZ_S, 554506c3fb27SDimitry Andric AArch64::FMINNM_VG2_2ZZ_D})) 554606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 554706c3fb27SDimitry Andric return; 554806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_single_x4: 554906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 555006c3fb27SDimitry Andric Node->getValueType(0), 555106c3fb27SDimitry Andric {0, AArch64::FMINNM_VG4_4ZZ_H, AArch64::FMINNM_VG4_4ZZ_S, 555206c3fb27SDimitry Andric AArch64::FMINNM_VG4_4ZZ_D})) 555306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 555406c3fb27SDimitry Andric return; 555506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_x2: 555606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 555706c3fb27SDimitry Andric Node->getValueType(0), 555806c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG2_2Z2Z_H, AArch64::FMAXNM_VG2_2Z2Z_S, 555906c3fb27SDimitry Andric AArch64::FMAXNM_VG2_2Z2Z_D})) 556006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 556106c3fb27SDimitry Andric return; 556206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_x4: 556306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 556406c3fb27SDimitry Andric Node->getValueType(0), 556506c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG4_4Z4Z_H, AArch64::FMAXNM_VG4_4Z4Z_S, 556606c3fb27SDimitry Andric AArch64::FMAXNM_VG4_4Z4Z_D})) 556706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 556806c3fb27SDimitry Andric return; 556906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_x2: 557006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 557106c3fb27SDimitry Andric Node->getValueType(0), 557206c3fb27SDimitry Andric {0, AArch64::FMINNM_VG2_2Z2Z_H, AArch64::FMINNM_VG2_2Z2Z_S, 557306c3fb27SDimitry Andric AArch64::FMINNM_VG2_2Z2Z_D})) 557406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 557506c3fb27SDimitry Andric return; 557606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_x4: 557706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 557806c3fb27SDimitry Andric Node->getValueType(0), 557906c3fb27SDimitry Andric {0, AArch64::FMINNM_VG4_4Z4Z_H, AArch64::FMINNM_VG4_4Z4Z_S, 558006c3fb27SDimitry Andric AArch64::FMINNM_VG4_4Z4Z_D})) 558106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 558206c3fb27SDimitry Andric return; 5583bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvts_x2: 5584bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::FCVTZS_2Z2Z_StoS); 5585bdd1243dSDimitry Andric return; 5586bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_scvtf_x2: 5587bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::SCVTF_2Z2Z_StoS); 5588bdd1243dSDimitry Andric return; 5589bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvtu_x2: 5590bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::FCVTZU_2Z2Z_StoS); 5591bdd1243dSDimitry Andric return; 5592bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ucvtf_x2: 5593bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::UCVTF_2Z2Z_StoS); 5594bdd1243dSDimitry Andric return; 5595bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvts_x4: 5596bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::FCVTZS_4Z4Z_StoS); 5597bdd1243dSDimitry Andric return; 5598bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_scvtf_x4: 5599bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::SCVTF_4Z4Z_StoS); 5600bdd1243dSDimitry Andric return; 5601bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvtu_x4: 5602bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::FCVTZU_4Z4Z_StoS); 5603bdd1243dSDimitry Andric return; 5604bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ucvtf_x4: 5605bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::UCVTF_4Z4Z_StoS); 5606bdd1243dSDimitry Andric return; 560706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sclamp_single_x2: 560806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 560906c3fb27SDimitry Andric Node->getValueType(0), 561006c3fb27SDimitry Andric {AArch64::SCLAMP_VG2_2Z2Z_B, AArch64::SCLAMP_VG2_2Z2Z_H, 561106c3fb27SDimitry Andric AArch64::SCLAMP_VG2_2Z2Z_S, AArch64::SCLAMP_VG2_2Z2Z_D})) 561206c3fb27SDimitry Andric SelectClamp(Node, 2, Op); 561306c3fb27SDimitry Andric return; 561406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uclamp_single_x2: 561506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 561606c3fb27SDimitry Andric Node->getValueType(0), 561706c3fb27SDimitry Andric {AArch64::UCLAMP_VG2_2Z2Z_B, AArch64::UCLAMP_VG2_2Z2Z_H, 561806c3fb27SDimitry Andric AArch64::UCLAMP_VG2_2Z2Z_S, AArch64::UCLAMP_VG2_2Z2Z_D})) 561906c3fb27SDimitry Andric SelectClamp(Node, 2, Op); 562006c3fb27SDimitry Andric return; 562106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fclamp_single_x2: 562206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 562306c3fb27SDimitry Andric Node->getValueType(0), 562406c3fb27SDimitry Andric {0, AArch64::FCLAMP_VG2_2Z2Z_H, AArch64::FCLAMP_VG2_2Z2Z_S, 562506c3fb27SDimitry Andric AArch64::FCLAMP_VG2_2Z2Z_D})) 562606c3fb27SDimitry Andric SelectClamp(Node, 2, Op); 562706c3fb27SDimitry Andric return; 562806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sclamp_single_x4: 562906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 563006c3fb27SDimitry Andric Node->getValueType(0), 563106c3fb27SDimitry Andric {AArch64::SCLAMP_VG4_4Z4Z_B, AArch64::SCLAMP_VG4_4Z4Z_H, 563206c3fb27SDimitry Andric AArch64::SCLAMP_VG4_4Z4Z_S, AArch64::SCLAMP_VG4_4Z4Z_D})) 563306c3fb27SDimitry Andric SelectClamp(Node, 4, Op); 563406c3fb27SDimitry Andric return; 563506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uclamp_single_x4: 563606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 563706c3fb27SDimitry Andric Node->getValueType(0), 563806c3fb27SDimitry Andric {AArch64::UCLAMP_VG4_4Z4Z_B, AArch64::UCLAMP_VG4_4Z4Z_H, 563906c3fb27SDimitry Andric AArch64::UCLAMP_VG4_4Z4Z_S, AArch64::UCLAMP_VG4_4Z4Z_D})) 564006c3fb27SDimitry Andric SelectClamp(Node, 4, Op); 564106c3fb27SDimitry Andric return; 564206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fclamp_single_x4: 564306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 564406c3fb27SDimitry Andric Node->getValueType(0), 564506c3fb27SDimitry Andric {0, AArch64::FCLAMP_VG4_4Z4Z_H, AArch64::FCLAMP_VG4_4Z4Z_S, 564606c3fb27SDimitry Andric AArch64::FCLAMP_VG4_4Z4Z_D})) 564706c3fb27SDimitry Andric SelectClamp(Node, 4, Op); 564806c3fb27SDimitry Andric return; 564906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_add_single_x2: 565006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 565106c3fb27SDimitry Andric Node->getValueType(0), 565206c3fb27SDimitry Andric {AArch64::ADD_VG2_2ZZ_B, AArch64::ADD_VG2_2ZZ_H, 565306c3fb27SDimitry Andric AArch64::ADD_VG2_2ZZ_S, AArch64::ADD_VG2_2ZZ_D})) 565406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 565506c3fb27SDimitry Andric return; 565606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_add_single_x4: 565706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 565806c3fb27SDimitry Andric Node->getValueType(0), 565906c3fb27SDimitry Andric {AArch64::ADD_VG4_4ZZ_B, AArch64::ADD_VG4_4ZZ_H, 566006c3fb27SDimitry Andric AArch64::ADD_VG4_4ZZ_S, AArch64::ADD_VG4_4ZZ_D})) 566106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 566206c3fb27SDimitry Andric return; 566306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zip_x2: 566406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 566506c3fb27SDimitry Andric Node->getValueType(0), 566606c3fb27SDimitry Andric {AArch64::ZIP_VG2_2ZZZ_B, AArch64::ZIP_VG2_2ZZZ_H, 566706c3fb27SDimitry Andric AArch64::ZIP_VG2_2ZZZ_S, AArch64::ZIP_VG2_2ZZZ_D})) 566806c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 566906c3fb27SDimitry Andric return; 567006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zipq_x2: 567106c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, 567206c3fb27SDimitry Andric AArch64::ZIP_VG2_2ZZZ_Q); 567306c3fb27SDimitry Andric return; 567406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zip_x4: 567506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 567606c3fb27SDimitry Andric Node->getValueType(0), 567706c3fb27SDimitry Andric {AArch64::ZIP_VG4_4Z4Z_B, AArch64::ZIP_VG4_4Z4Z_H, 567806c3fb27SDimitry Andric AArch64::ZIP_VG4_4Z4Z_S, AArch64::ZIP_VG4_4Z4Z_D})) 567906c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 568006c3fb27SDimitry Andric return; 568106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zipq_x4: 568206c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, 568306c3fb27SDimitry Andric AArch64::ZIP_VG4_4Z4Z_Q); 568406c3fb27SDimitry Andric return; 568506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzp_x2: 568606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 568706c3fb27SDimitry Andric Node->getValueType(0), 568806c3fb27SDimitry Andric {AArch64::UZP_VG2_2ZZZ_B, AArch64::UZP_VG2_2ZZZ_H, 568906c3fb27SDimitry Andric AArch64::UZP_VG2_2ZZZ_S, AArch64::UZP_VG2_2ZZZ_D})) 569006c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 569106c3fb27SDimitry Andric return; 569206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzpq_x2: 569306c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, 569406c3fb27SDimitry Andric AArch64::UZP_VG2_2ZZZ_Q); 569506c3fb27SDimitry Andric return; 569606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzp_x4: 569706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 569806c3fb27SDimitry Andric Node->getValueType(0), 569906c3fb27SDimitry Andric {AArch64::UZP_VG4_4Z4Z_B, AArch64::UZP_VG4_4Z4Z_H, 570006c3fb27SDimitry Andric AArch64::UZP_VG4_4Z4Z_S, AArch64::UZP_VG4_4Z4Z_D})) 570106c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 570206c3fb27SDimitry Andric return; 570306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzpq_x4: 570406c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, 570506c3fb27SDimitry Andric AArch64::UZP_VG4_4Z4Z_Q); 570606c3fb27SDimitry Andric return; 570706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sel_x2: 570806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 570906c3fb27SDimitry Andric Node->getValueType(0), 571006c3fb27SDimitry Andric {AArch64::SEL_VG2_2ZC2Z2Z_B, AArch64::SEL_VG2_2ZC2Z2Z_H, 571106c3fb27SDimitry Andric AArch64::SEL_VG2_2ZC2Z2Z_S, AArch64::SEL_VG2_2ZC2Z2Z_D})) 571206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op, /*HasPred=*/true); 571306c3fb27SDimitry Andric return; 571406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sel_x4: 571506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 571606c3fb27SDimitry Andric Node->getValueType(0), 571706c3fb27SDimitry Andric {AArch64::SEL_VG4_4ZC4Z4Z_B, AArch64::SEL_VG4_4ZC4Z4Z_H, 571806c3fb27SDimitry Andric AArch64::SEL_VG4_4ZC4Z4Z_S, AArch64::SEL_VG4_4ZC4Z4Z_D})) 571906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op, /*HasPred=*/true); 572006c3fb27SDimitry Andric return; 572106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frinta_x2: 572206c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTA_2Z2Z_S); 572306c3fb27SDimitry Andric return; 572406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frinta_x4: 572506c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTA_4Z4Z_S); 572606c3fb27SDimitry Andric return; 572706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintm_x2: 572806c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTM_2Z2Z_S); 572906c3fb27SDimitry Andric return; 573006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintm_x4: 573106c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTM_4Z4Z_S); 573206c3fb27SDimitry Andric return; 573306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintn_x2: 573406c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTN_2Z2Z_S); 573506c3fb27SDimitry Andric return; 573606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintn_x4: 573706c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTN_4Z4Z_S); 573806c3fb27SDimitry Andric return; 573906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintp_x2: 574006c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTP_2Z2Z_S); 574106c3fb27SDimitry Andric return; 574206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintp_x4: 574306c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTP_4Z4Z_S); 574406c3fb27SDimitry Andric return; 574506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sunpk_x2: 574606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 574706c3fb27SDimitry Andric Node->getValueType(0), 574806c3fb27SDimitry Andric {0, AArch64::SUNPK_VG2_2ZZ_H, AArch64::SUNPK_VG2_2ZZ_S, 574906c3fb27SDimitry Andric AArch64::SUNPK_VG2_2ZZ_D})) 575006c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 575106c3fb27SDimitry Andric return; 575206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uunpk_x2: 575306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 575406c3fb27SDimitry Andric Node->getValueType(0), 575506c3fb27SDimitry Andric {0, AArch64::UUNPK_VG2_2ZZ_H, AArch64::UUNPK_VG2_2ZZ_S, 575606c3fb27SDimitry Andric AArch64::UUNPK_VG2_2ZZ_D})) 575706c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 575806c3fb27SDimitry Andric return; 575906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sunpk_x4: 576006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 576106c3fb27SDimitry Andric Node->getValueType(0), 576206c3fb27SDimitry Andric {0, AArch64::SUNPK_VG4_4Z2Z_H, AArch64::SUNPK_VG4_4Z2Z_S, 576306c3fb27SDimitry Andric AArch64::SUNPK_VG4_4Z2Z_D})) 576406c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 576506c3fb27SDimitry Andric return; 576606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uunpk_x4: 576706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 576806c3fb27SDimitry Andric Node->getValueType(0), 576906c3fb27SDimitry Andric {0, AArch64::UUNPK_VG4_4Z2Z_H, AArch64::UUNPK_VG4_4Z2Z_S, 577006c3fb27SDimitry Andric AArch64::UUNPK_VG4_4Z2Z_D})) 577106c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 577206c3fb27SDimitry Andric return; 577306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_pext_x2: { 577406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 577506c3fb27SDimitry Andric Node->getValueType(0), 577606c3fb27SDimitry Andric {AArch64::PEXT_2PCI_B, AArch64::PEXT_2PCI_H, AArch64::PEXT_2PCI_S, 577706c3fb27SDimitry Andric AArch64::PEXT_2PCI_D})) 577806c3fb27SDimitry Andric SelectPExtPair(Node, Op); 577906c3fb27SDimitry Andric return; 578006c3fb27SDimitry Andric } 57810b57cec5SDimitry Andric } 57820b57cec5SDimitry Andric break; 57830b57cec5SDimitry Andric } 57840b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: { 57850b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 57860b57cec5SDimitry Andric if (Node->getNumOperands() >= 3) 57870b57cec5SDimitry Andric VT = Node->getOperand(2)->getValueType(0); 57880b57cec5SDimitry Andric switch (IntNo) { 57890b57cec5SDimitry Andric default: 57900b57cec5SDimitry Andric break; 57910b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x2: { 57920b57cec5SDimitry Andric if (VT == MVT::v8i8) { 57930b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov8b); 57940b57cec5SDimitry Andric return; 57950b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 57960b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov16b); 57970b57cec5SDimitry Andric return; 57985ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 57995ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58000b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov4h); 58010b57cec5SDimitry Andric return; 58025ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58035ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58040b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov8h); 58050b57cec5SDimitry Andric return; 58060b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58070b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov2s); 58080b57cec5SDimitry Andric return; 58090b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58100b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov4s); 58110b57cec5SDimitry Andric return; 58120b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58130b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov2d); 58140b57cec5SDimitry Andric return; 58150b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 58160b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov1d); 58170b57cec5SDimitry Andric return; 58180b57cec5SDimitry Andric } 58190b57cec5SDimitry Andric break; 58200b57cec5SDimitry Andric } 58210b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x3: { 58220b57cec5SDimitry Andric if (VT == MVT::v8i8) { 58230b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev8b); 58240b57cec5SDimitry Andric return; 58250b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 58260b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev16b); 58270b57cec5SDimitry Andric return; 58285ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 58295ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58300b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev4h); 58310b57cec5SDimitry Andric return; 58325ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58335ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58340b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev8h); 58350b57cec5SDimitry Andric return; 58360b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58370b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev2s); 58380b57cec5SDimitry Andric return; 58390b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58400b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev4s); 58410b57cec5SDimitry Andric return; 58420b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58430b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev2d); 58440b57cec5SDimitry Andric return; 58450b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 58460b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev1d); 58470b57cec5SDimitry Andric return; 58480b57cec5SDimitry Andric } 58490b57cec5SDimitry Andric break; 58500b57cec5SDimitry Andric } 58510b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x4: { 58520b57cec5SDimitry Andric if (VT == MVT::v8i8) { 58530b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv8b); 58540b57cec5SDimitry Andric return; 58550b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 58560b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv16b); 58570b57cec5SDimitry Andric return; 58585ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 58595ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58600b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv4h); 58610b57cec5SDimitry Andric return; 58625ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58635ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58640b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv8h); 58650b57cec5SDimitry Andric return; 58660b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58670b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv2s); 58680b57cec5SDimitry Andric return; 58690b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58700b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv4s); 58710b57cec5SDimitry Andric return; 58720b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58730b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv2d); 58740b57cec5SDimitry Andric return; 58750b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 58760b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv1d); 58770b57cec5SDimitry Andric return; 58780b57cec5SDimitry Andric } 58790b57cec5SDimitry Andric break; 58800b57cec5SDimitry Andric } 58810b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st2: { 58820b57cec5SDimitry Andric if (VT == MVT::v8i8) { 58830b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov8b); 58840b57cec5SDimitry Andric return; 58850b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 58860b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov16b); 58870b57cec5SDimitry Andric return; 58885ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 58895ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58900b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov4h); 58910b57cec5SDimitry Andric return; 58925ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58935ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58940b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov8h); 58950b57cec5SDimitry Andric return; 58960b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58970b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov2s); 58980b57cec5SDimitry Andric return; 58990b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 59000b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov4s); 59010b57cec5SDimitry Andric return; 59020b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 59030b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov2d); 59040b57cec5SDimitry Andric return; 59050b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 59060b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov1d); 59070b57cec5SDimitry Andric return; 59080b57cec5SDimitry Andric } 59090b57cec5SDimitry Andric break; 59100b57cec5SDimitry Andric } 59110b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st3: { 59120b57cec5SDimitry Andric if (VT == MVT::v8i8) { 59130b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev8b); 59140b57cec5SDimitry Andric return; 59150b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 59160b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev16b); 59170b57cec5SDimitry Andric return; 59185ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 59195ffd83dbSDimitry Andric VT == MVT::v4bf16) { 59200b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev4h); 59210b57cec5SDimitry Andric return; 59225ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 59235ffd83dbSDimitry Andric VT == MVT::v8bf16) { 59240b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev8h); 59250b57cec5SDimitry Andric return; 59260b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 59270b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev2s); 59280b57cec5SDimitry Andric return; 59290b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 59300b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev4s); 59310b57cec5SDimitry Andric return; 59320b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 59330b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev2d); 59340b57cec5SDimitry Andric return; 59350b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 59360b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev1d); 59370b57cec5SDimitry Andric return; 59380b57cec5SDimitry Andric } 59390b57cec5SDimitry Andric break; 59400b57cec5SDimitry Andric } 59410b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st4: { 59420b57cec5SDimitry Andric if (VT == MVT::v8i8) { 59430b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv8b); 59440b57cec5SDimitry Andric return; 59450b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 59460b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv16b); 59470b57cec5SDimitry Andric return; 59485ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 59495ffd83dbSDimitry Andric VT == MVT::v4bf16) { 59500b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv4h); 59510b57cec5SDimitry Andric return; 59525ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 59535ffd83dbSDimitry Andric VT == MVT::v8bf16) { 59540b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv8h); 59550b57cec5SDimitry Andric return; 59560b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 59570b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv2s); 59580b57cec5SDimitry Andric return; 59590b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 59600b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv4s); 59610b57cec5SDimitry Andric return; 59620b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 59630b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv2d); 59640b57cec5SDimitry Andric return; 59650b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 59660b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv1d); 59670b57cec5SDimitry Andric return; 59680b57cec5SDimitry Andric } 59690b57cec5SDimitry Andric break; 59700b57cec5SDimitry Andric } 59710b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st2lane: { 59720b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 59730b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i8); 59740b57cec5SDimitry Andric return; 59750b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 59765ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 59770b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i16); 59780b57cec5SDimitry Andric return; 59790b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 59800b57cec5SDimitry Andric VT == MVT::v2f32) { 59810b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i32); 59820b57cec5SDimitry Andric return; 59830b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 59840b57cec5SDimitry Andric VT == MVT::v1f64) { 59850b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i64); 59860b57cec5SDimitry Andric return; 59870b57cec5SDimitry Andric } 59880b57cec5SDimitry Andric break; 59890b57cec5SDimitry Andric } 59900b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st3lane: { 59910b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 59920b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i8); 59930b57cec5SDimitry Andric return; 59940b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 59955ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 59960b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i16); 59970b57cec5SDimitry Andric return; 59980b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 59990b57cec5SDimitry Andric VT == MVT::v2f32) { 60000b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i32); 60010b57cec5SDimitry Andric return; 60020b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 60030b57cec5SDimitry Andric VT == MVT::v1f64) { 60040b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i64); 60050b57cec5SDimitry Andric return; 60060b57cec5SDimitry Andric } 60070b57cec5SDimitry Andric break; 60080b57cec5SDimitry Andric } 60090b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st4lane: { 60100b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 60110b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i8); 60120b57cec5SDimitry Andric return; 60130b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 60145ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 60150b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i16); 60160b57cec5SDimitry Andric return; 60170b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 60180b57cec5SDimitry Andric VT == MVT::v2f32) { 60190b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i32); 60200b57cec5SDimitry Andric return; 60210b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 60220b57cec5SDimitry Andric VT == MVT::v1f64) { 60230b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i64); 60240b57cec5SDimitry Andric return; 60250b57cec5SDimitry Andric } 60260b57cec5SDimitry Andric break; 60270b57cec5SDimitry Andric } 6028*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st2q: { 6029*5f757f3fSDimitry Andric SelectPredicatedStore(Node, 2, 4, AArch64::ST2Q, AArch64::ST2Q_IMM); 6030*5f757f3fSDimitry Andric return; 6031*5f757f3fSDimitry Andric } 6032*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st3q: { 6033*5f757f3fSDimitry Andric SelectPredicatedStore(Node, 3, 4, AArch64::ST3Q, AArch64::ST3Q_IMM); 6034*5f757f3fSDimitry Andric return; 6035*5f757f3fSDimitry Andric } 6036*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st4q: { 6037*5f757f3fSDimitry Andric SelectPredicatedStore(Node, 4, 4, AArch64::ST4Q, AArch64::ST4Q_IMM); 6038*5f757f3fSDimitry Andric return; 6039*5f757f3fSDimitry Andric } 60405ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st2: { 60415ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6042979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 0, AArch64::ST2B, AArch64::ST2B_IMM); 60435ffd83dbSDimitry Andric return; 60445ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 604581ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6046979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 1, AArch64::ST2H, AArch64::ST2H_IMM); 60475ffd83dbSDimitry Andric return; 60485ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6049979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 2, AArch64::ST2W, AArch64::ST2W_IMM); 60505ffd83dbSDimitry Andric return; 60515ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6052979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 3, AArch64::ST2D, AArch64::ST2D_IMM); 60535ffd83dbSDimitry Andric return; 60545ffd83dbSDimitry Andric } 60555ffd83dbSDimitry Andric break; 60565ffd83dbSDimitry Andric } 60575ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st3: { 60585ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6059979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 0, AArch64::ST3B, AArch64::ST3B_IMM); 60605ffd83dbSDimitry Andric return; 60615ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 606281ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6063979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 1, AArch64::ST3H, AArch64::ST3H_IMM); 60645ffd83dbSDimitry Andric return; 60655ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6066979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 2, AArch64::ST3W, AArch64::ST3W_IMM); 60675ffd83dbSDimitry Andric return; 60685ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6069979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 3, AArch64::ST3D, AArch64::ST3D_IMM); 60705ffd83dbSDimitry Andric return; 60715ffd83dbSDimitry Andric } 60725ffd83dbSDimitry Andric break; 60735ffd83dbSDimitry Andric } 60745ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st4: { 60755ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6076979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 0, AArch64::ST4B, AArch64::ST4B_IMM); 60775ffd83dbSDimitry Andric return; 60785ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 607981ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6080979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 1, AArch64::ST4H, AArch64::ST4H_IMM); 60815ffd83dbSDimitry Andric return; 60825ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6083979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 2, AArch64::ST4W, AArch64::ST4W_IMM); 60845ffd83dbSDimitry Andric return; 60855ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6086979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 3, AArch64::ST4D, AArch64::ST4D_IMM); 60875ffd83dbSDimitry Andric return; 60885ffd83dbSDimitry Andric } 60895ffd83dbSDimitry Andric break; 60905ffd83dbSDimitry Andric } 60910b57cec5SDimitry Andric } 60920b57cec5SDimitry Andric break; 60930b57cec5SDimitry Andric } 60940b57cec5SDimitry Andric case AArch64ISD::LD2post: { 60950b57cec5SDimitry Andric if (VT == MVT::v8i8) { 60960b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov8b_POST, AArch64::dsub0); 60970b57cec5SDimitry Andric return; 60980b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 60990b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov16b_POST, AArch64::qsub0); 61000b57cec5SDimitry Andric return; 61015ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61020b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov4h_POST, AArch64::dsub0); 61030b57cec5SDimitry Andric return; 61045ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61050b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov8h_POST, AArch64::qsub0); 61060b57cec5SDimitry Andric return; 61070b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61080b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov2s_POST, AArch64::dsub0); 61090b57cec5SDimitry Andric return; 61100b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61110b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov4s_POST, AArch64::qsub0); 61120b57cec5SDimitry Andric return; 61130b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61140b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0); 61150b57cec5SDimitry Andric return; 61160b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61170b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov2d_POST, AArch64::qsub0); 61180b57cec5SDimitry Andric return; 61190b57cec5SDimitry Andric } 61200b57cec5SDimitry Andric break; 61210b57cec5SDimitry Andric } 61220b57cec5SDimitry Andric case AArch64ISD::LD3post: { 61230b57cec5SDimitry Andric if (VT == MVT::v8i8) { 61240b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev8b_POST, AArch64::dsub0); 61250b57cec5SDimitry Andric return; 61260b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 61270b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev16b_POST, AArch64::qsub0); 61280b57cec5SDimitry Andric return; 61295ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61300b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev4h_POST, AArch64::dsub0); 61310b57cec5SDimitry Andric return; 61325ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61330b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev8h_POST, AArch64::qsub0); 61340b57cec5SDimitry Andric return; 61350b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61360b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev2s_POST, AArch64::dsub0); 61370b57cec5SDimitry Andric return; 61380b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61390b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev4s_POST, AArch64::qsub0); 61400b57cec5SDimitry Andric return; 61410b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61420b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0); 61430b57cec5SDimitry Andric return; 61440b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61450b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev2d_POST, AArch64::qsub0); 61460b57cec5SDimitry Andric return; 61470b57cec5SDimitry Andric } 61480b57cec5SDimitry Andric break; 61490b57cec5SDimitry Andric } 61500b57cec5SDimitry Andric case AArch64ISD::LD4post: { 61510b57cec5SDimitry Andric if (VT == MVT::v8i8) { 61520b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv8b_POST, AArch64::dsub0); 61530b57cec5SDimitry Andric return; 61540b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 61550b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv16b_POST, AArch64::qsub0); 61560b57cec5SDimitry Andric return; 61575ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61580b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv4h_POST, AArch64::dsub0); 61590b57cec5SDimitry Andric return; 61605ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61610b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv8h_POST, AArch64::qsub0); 61620b57cec5SDimitry Andric return; 61630b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61640b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv2s_POST, AArch64::dsub0); 61650b57cec5SDimitry Andric return; 61660b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61670b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv4s_POST, AArch64::qsub0); 61680b57cec5SDimitry Andric return; 61690b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61700b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0); 61710b57cec5SDimitry Andric return; 61720b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61730b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv2d_POST, AArch64::qsub0); 61740b57cec5SDimitry Andric return; 61750b57cec5SDimitry Andric } 61760b57cec5SDimitry Andric break; 61770b57cec5SDimitry Andric } 61780b57cec5SDimitry Andric case AArch64ISD::LD1x2post: { 61790b57cec5SDimitry Andric if (VT == MVT::v8i8) { 61800b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov8b_POST, AArch64::dsub0); 61810b57cec5SDimitry Andric return; 61820b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 61830b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov16b_POST, AArch64::qsub0); 61840b57cec5SDimitry Andric return; 61855ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61860b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov4h_POST, AArch64::dsub0); 61870b57cec5SDimitry Andric return; 61885ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61890b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov8h_POST, AArch64::qsub0); 61900b57cec5SDimitry Andric return; 61910b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61920b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov2s_POST, AArch64::dsub0); 61930b57cec5SDimitry Andric return; 61940b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61950b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov4s_POST, AArch64::qsub0); 61960b57cec5SDimitry Andric return; 61970b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61980b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0); 61990b57cec5SDimitry Andric return; 62000b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62010b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov2d_POST, AArch64::qsub0); 62020b57cec5SDimitry Andric return; 62030b57cec5SDimitry Andric } 62040b57cec5SDimitry Andric break; 62050b57cec5SDimitry Andric } 62060b57cec5SDimitry Andric case AArch64ISD::LD1x3post: { 62070b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62080b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev8b_POST, AArch64::dsub0); 62090b57cec5SDimitry Andric return; 62100b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62110b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev16b_POST, AArch64::qsub0); 62120b57cec5SDimitry Andric return; 62135ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62140b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev4h_POST, AArch64::dsub0); 62150b57cec5SDimitry Andric return; 62165ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62170b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev8h_POST, AArch64::qsub0); 62180b57cec5SDimitry Andric return; 62190b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62200b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev2s_POST, AArch64::dsub0); 62210b57cec5SDimitry Andric return; 62220b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 62230b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev4s_POST, AArch64::qsub0); 62240b57cec5SDimitry Andric return; 62250b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 62260b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0); 62270b57cec5SDimitry Andric return; 62280b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62290b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev2d_POST, AArch64::qsub0); 62300b57cec5SDimitry Andric return; 62310b57cec5SDimitry Andric } 62320b57cec5SDimitry Andric break; 62330b57cec5SDimitry Andric } 62340b57cec5SDimitry Andric case AArch64ISD::LD1x4post: { 62350b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62360b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv8b_POST, AArch64::dsub0); 62370b57cec5SDimitry Andric return; 62380b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62390b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv16b_POST, AArch64::qsub0); 62400b57cec5SDimitry Andric return; 62415ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62420b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv4h_POST, AArch64::dsub0); 62430b57cec5SDimitry Andric return; 62445ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62450b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv8h_POST, AArch64::qsub0); 62460b57cec5SDimitry Andric return; 62470b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62480b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv2s_POST, AArch64::dsub0); 62490b57cec5SDimitry Andric return; 62500b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 62510b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv4s_POST, AArch64::qsub0); 62520b57cec5SDimitry Andric return; 62530b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 62540b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0); 62550b57cec5SDimitry Andric return; 62560b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62570b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv2d_POST, AArch64::qsub0); 62580b57cec5SDimitry Andric return; 62590b57cec5SDimitry Andric } 62600b57cec5SDimitry Andric break; 62610b57cec5SDimitry Andric } 62620b57cec5SDimitry Andric case AArch64ISD::LD1DUPpost: { 62630b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62640b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv8b_POST, AArch64::dsub0); 62650b57cec5SDimitry Andric return; 62660b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62670b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv16b_POST, AArch64::qsub0); 62680b57cec5SDimitry Andric return; 62695ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62700b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv4h_POST, AArch64::dsub0); 62710b57cec5SDimitry Andric return; 62725ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62730b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv8h_POST, AArch64::qsub0); 62740b57cec5SDimitry Andric return; 62750b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62760b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv2s_POST, AArch64::dsub0); 62770b57cec5SDimitry Andric return; 62780b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 62790b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv4s_POST, AArch64::qsub0); 62800b57cec5SDimitry Andric return; 62810b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 62820b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv1d_POST, AArch64::dsub0); 62830b57cec5SDimitry Andric return; 62840b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62850b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv2d_POST, AArch64::qsub0); 62860b57cec5SDimitry Andric return; 62870b57cec5SDimitry Andric } 62880b57cec5SDimitry Andric break; 62890b57cec5SDimitry Andric } 62900b57cec5SDimitry Andric case AArch64ISD::LD2DUPpost: { 62910b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62920b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv8b_POST, AArch64::dsub0); 62930b57cec5SDimitry Andric return; 62940b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62950b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv16b_POST, AArch64::qsub0); 62960b57cec5SDimitry Andric return; 62975ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62980b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv4h_POST, AArch64::dsub0); 62990b57cec5SDimitry Andric return; 63005ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 63010b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv8h_POST, AArch64::qsub0); 63020b57cec5SDimitry Andric return; 63030b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 63040b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv2s_POST, AArch64::dsub0); 63050b57cec5SDimitry Andric return; 63060b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 63070b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv4s_POST, AArch64::qsub0); 63080b57cec5SDimitry Andric return; 63090b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 63100b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv1d_POST, AArch64::dsub0); 63110b57cec5SDimitry Andric return; 63120b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 63130b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv2d_POST, AArch64::qsub0); 63140b57cec5SDimitry Andric return; 63150b57cec5SDimitry Andric } 63160b57cec5SDimitry Andric break; 63170b57cec5SDimitry Andric } 63180b57cec5SDimitry Andric case AArch64ISD::LD3DUPpost: { 63190b57cec5SDimitry Andric if (VT == MVT::v8i8) { 63200b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv8b_POST, AArch64::dsub0); 63210b57cec5SDimitry Andric return; 63220b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 63230b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv16b_POST, AArch64::qsub0); 63240b57cec5SDimitry Andric return; 63255ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 63260b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv4h_POST, AArch64::dsub0); 63270b57cec5SDimitry Andric return; 63285ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 63290b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv8h_POST, AArch64::qsub0); 63300b57cec5SDimitry Andric return; 63310b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 63320b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv2s_POST, AArch64::dsub0); 63330b57cec5SDimitry Andric return; 63340b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 63350b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv4s_POST, AArch64::qsub0); 63360b57cec5SDimitry Andric return; 63370b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 63380b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv1d_POST, AArch64::dsub0); 63390b57cec5SDimitry Andric return; 63400b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 63410b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv2d_POST, AArch64::qsub0); 63420b57cec5SDimitry Andric return; 63430b57cec5SDimitry Andric } 63440b57cec5SDimitry Andric break; 63450b57cec5SDimitry Andric } 63460b57cec5SDimitry Andric case AArch64ISD::LD4DUPpost: { 63470b57cec5SDimitry Andric if (VT == MVT::v8i8) { 63480b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv8b_POST, AArch64::dsub0); 63490b57cec5SDimitry Andric return; 63500b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 63510b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv16b_POST, AArch64::qsub0); 63520b57cec5SDimitry Andric return; 63535ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 63540b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv4h_POST, AArch64::dsub0); 63550b57cec5SDimitry Andric return; 63565ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 63570b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv8h_POST, AArch64::qsub0); 63580b57cec5SDimitry Andric return; 63590b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 63600b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv2s_POST, AArch64::dsub0); 63610b57cec5SDimitry Andric return; 63620b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 63630b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv4s_POST, AArch64::qsub0); 63640b57cec5SDimitry Andric return; 63650b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 63660b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv1d_POST, AArch64::dsub0); 63670b57cec5SDimitry Andric return; 63680b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 63690b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv2d_POST, AArch64::qsub0); 63700b57cec5SDimitry Andric return; 63710b57cec5SDimitry Andric } 63720b57cec5SDimitry Andric break; 63730b57cec5SDimitry Andric } 63740b57cec5SDimitry Andric case AArch64ISD::LD1LANEpost: { 63750b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 63760b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i8_POST); 63770b57cec5SDimitry Andric return; 63780b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 63795ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 63800b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i16_POST); 63810b57cec5SDimitry Andric return; 63820b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 63830b57cec5SDimitry Andric VT == MVT::v2f32) { 63840b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i32_POST); 63850b57cec5SDimitry Andric return; 63860b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 63870b57cec5SDimitry Andric VT == MVT::v1f64) { 63880b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i64_POST); 63890b57cec5SDimitry Andric return; 63900b57cec5SDimitry Andric } 63910b57cec5SDimitry Andric break; 63920b57cec5SDimitry Andric } 63930b57cec5SDimitry Andric case AArch64ISD::LD2LANEpost: { 63940b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 63950b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i8_POST); 63960b57cec5SDimitry Andric return; 63970b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 63985ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 63990b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i16_POST); 64000b57cec5SDimitry Andric return; 64010b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 64020b57cec5SDimitry Andric VT == MVT::v2f32) { 64030b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i32_POST); 64040b57cec5SDimitry Andric return; 64050b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 64060b57cec5SDimitry Andric VT == MVT::v1f64) { 64070b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i64_POST); 64080b57cec5SDimitry Andric return; 64090b57cec5SDimitry Andric } 64100b57cec5SDimitry Andric break; 64110b57cec5SDimitry Andric } 64120b57cec5SDimitry Andric case AArch64ISD::LD3LANEpost: { 64130b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 64140b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i8_POST); 64150b57cec5SDimitry Andric return; 64160b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 64175ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 64180b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i16_POST); 64190b57cec5SDimitry Andric return; 64200b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 64210b57cec5SDimitry Andric VT == MVT::v2f32) { 64220b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i32_POST); 64230b57cec5SDimitry Andric return; 64240b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 64250b57cec5SDimitry Andric VT == MVT::v1f64) { 64260b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i64_POST); 64270b57cec5SDimitry Andric return; 64280b57cec5SDimitry Andric } 64290b57cec5SDimitry Andric break; 64300b57cec5SDimitry Andric } 64310b57cec5SDimitry Andric case AArch64ISD::LD4LANEpost: { 64320b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 64330b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i8_POST); 64340b57cec5SDimitry Andric return; 64350b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 64365ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 64370b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i16_POST); 64380b57cec5SDimitry Andric return; 64390b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 64400b57cec5SDimitry Andric VT == MVT::v2f32) { 64410b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i32_POST); 64420b57cec5SDimitry Andric return; 64430b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 64440b57cec5SDimitry Andric VT == MVT::v1f64) { 64450b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i64_POST); 64460b57cec5SDimitry Andric return; 64470b57cec5SDimitry Andric } 64480b57cec5SDimitry Andric break; 64490b57cec5SDimitry Andric } 64500b57cec5SDimitry Andric case AArch64ISD::ST2post: { 64510b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 64520b57cec5SDimitry Andric if (VT == MVT::v8i8) { 64530b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov8b_POST); 64540b57cec5SDimitry Andric return; 64550b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 64560b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov16b_POST); 64570b57cec5SDimitry Andric return; 64585ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 64590b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov4h_POST); 64600b57cec5SDimitry Andric return; 64615ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 64620b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov8h_POST); 64630b57cec5SDimitry Andric return; 64640b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 64650b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov2s_POST); 64660b57cec5SDimitry Andric return; 64670b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 64680b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov4s_POST); 64690b57cec5SDimitry Andric return; 64700b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 64710b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov2d_POST); 64720b57cec5SDimitry Andric return; 64730b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 64740b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST); 64750b57cec5SDimitry Andric return; 64760b57cec5SDimitry Andric } 64770b57cec5SDimitry Andric break; 64780b57cec5SDimitry Andric } 64790b57cec5SDimitry Andric case AArch64ISD::ST3post: { 64800b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 64810b57cec5SDimitry Andric if (VT == MVT::v8i8) { 64820b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev8b_POST); 64830b57cec5SDimitry Andric return; 64840b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 64850b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev16b_POST); 64860b57cec5SDimitry Andric return; 64875ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 64880b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev4h_POST); 64890b57cec5SDimitry Andric return; 64905ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 64910b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev8h_POST); 64920b57cec5SDimitry Andric return; 64930b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 64940b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev2s_POST); 64950b57cec5SDimitry Andric return; 64960b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 64970b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev4s_POST); 64980b57cec5SDimitry Andric return; 64990b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65000b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev2d_POST); 65010b57cec5SDimitry Andric return; 65020b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65030b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST); 65040b57cec5SDimitry Andric return; 65050b57cec5SDimitry Andric } 65060b57cec5SDimitry Andric break; 65070b57cec5SDimitry Andric } 65080b57cec5SDimitry Andric case AArch64ISD::ST4post: { 65090b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65100b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65110b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv8b_POST); 65120b57cec5SDimitry Andric return; 65130b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65140b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv16b_POST); 65150b57cec5SDimitry Andric return; 65165ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65170b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv4h_POST); 65180b57cec5SDimitry Andric return; 65195ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 65200b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv8h_POST); 65210b57cec5SDimitry Andric return; 65220b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 65230b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv2s_POST); 65240b57cec5SDimitry Andric return; 65250b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 65260b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv4s_POST); 65270b57cec5SDimitry Andric return; 65280b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65290b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv2d_POST); 65300b57cec5SDimitry Andric return; 65310b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65320b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST); 65330b57cec5SDimitry Andric return; 65340b57cec5SDimitry Andric } 65350b57cec5SDimitry Andric break; 65360b57cec5SDimitry Andric } 65370b57cec5SDimitry Andric case AArch64ISD::ST1x2post: { 65380b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65390b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65400b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov8b_POST); 65410b57cec5SDimitry Andric return; 65420b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65430b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov16b_POST); 65440b57cec5SDimitry Andric return; 65455ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65460b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov4h_POST); 65470b57cec5SDimitry Andric return; 65485ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 65490b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov8h_POST); 65500b57cec5SDimitry Andric return; 65510b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 65520b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov2s_POST); 65530b57cec5SDimitry Andric return; 65540b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 65550b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov4s_POST); 65560b57cec5SDimitry Andric return; 65570b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65580b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST); 65590b57cec5SDimitry Andric return; 65600b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65610b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov2d_POST); 65620b57cec5SDimitry Andric return; 65630b57cec5SDimitry Andric } 65640b57cec5SDimitry Andric break; 65650b57cec5SDimitry Andric } 65660b57cec5SDimitry Andric case AArch64ISD::ST1x3post: { 65670b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65680b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65690b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev8b_POST); 65700b57cec5SDimitry Andric return; 65710b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65720b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev16b_POST); 65730b57cec5SDimitry Andric return; 65745ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65750b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev4h_POST); 65760b57cec5SDimitry Andric return; 65775ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16 ) { 65780b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev8h_POST); 65790b57cec5SDimitry Andric return; 65800b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 65810b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev2s_POST); 65820b57cec5SDimitry Andric return; 65830b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 65840b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev4s_POST); 65850b57cec5SDimitry Andric return; 65860b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65870b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST); 65880b57cec5SDimitry Andric return; 65890b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65900b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev2d_POST); 65910b57cec5SDimitry Andric return; 65920b57cec5SDimitry Andric } 65930b57cec5SDimitry Andric break; 65940b57cec5SDimitry Andric } 65950b57cec5SDimitry Andric case AArch64ISD::ST1x4post: { 65960b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65970b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65980b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv8b_POST); 65990b57cec5SDimitry Andric return; 66000b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 66010b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv16b_POST); 66020b57cec5SDimitry Andric return; 66035ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 66040b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv4h_POST); 66050b57cec5SDimitry Andric return; 66065ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 66070b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv8h_POST); 66080b57cec5SDimitry Andric return; 66090b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 66100b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv2s_POST); 66110b57cec5SDimitry Andric return; 66120b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 66130b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv4s_POST); 66140b57cec5SDimitry Andric return; 66150b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 66160b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST); 66170b57cec5SDimitry Andric return; 66180b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 66190b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv2d_POST); 66200b57cec5SDimitry Andric return; 66210b57cec5SDimitry Andric } 66220b57cec5SDimitry Andric break; 66230b57cec5SDimitry Andric } 66240b57cec5SDimitry Andric case AArch64ISD::ST2LANEpost: { 66250b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 66260b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 66270b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i8_POST); 66280b57cec5SDimitry Andric return; 66290b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 66305ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 66310b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i16_POST); 66320b57cec5SDimitry Andric return; 66330b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 66340b57cec5SDimitry Andric VT == MVT::v2f32) { 66350b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i32_POST); 66360b57cec5SDimitry Andric return; 66370b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 66380b57cec5SDimitry Andric VT == MVT::v1f64) { 66390b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i64_POST); 66400b57cec5SDimitry Andric return; 66410b57cec5SDimitry Andric } 66420b57cec5SDimitry Andric break; 66430b57cec5SDimitry Andric } 66440b57cec5SDimitry Andric case AArch64ISD::ST3LANEpost: { 66450b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 66460b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 66470b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i8_POST); 66480b57cec5SDimitry Andric return; 66490b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 66505ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 66510b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i16_POST); 66520b57cec5SDimitry Andric return; 66530b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 66540b57cec5SDimitry Andric VT == MVT::v2f32) { 66550b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i32_POST); 66560b57cec5SDimitry Andric return; 66570b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 66580b57cec5SDimitry Andric VT == MVT::v1f64) { 66590b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i64_POST); 66600b57cec5SDimitry Andric return; 66610b57cec5SDimitry Andric } 66620b57cec5SDimitry Andric break; 66630b57cec5SDimitry Andric } 66640b57cec5SDimitry Andric case AArch64ISD::ST4LANEpost: { 66650b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 66660b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 66670b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i8_POST); 66680b57cec5SDimitry Andric return; 66690b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 66705ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 66710b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i16_POST); 66720b57cec5SDimitry Andric return; 66730b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 66740b57cec5SDimitry Andric VT == MVT::v2f32) { 66750b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i32_POST); 66760b57cec5SDimitry Andric return; 66770b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 66780b57cec5SDimitry Andric VT == MVT::v1f64) { 66790b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i64_POST); 66800b57cec5SDimitry Andric return; 66810b57cec5SDimitry Andric } 66820b57cec5SDimitry Andric break; 66830b57cec5SDimitry Andric } 66845ffd83dbSDimitry Andric case AArch64ISD::SVE_LD2_MERGE_ZERO: { 66855ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6686979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B); 66875ffd83dbSDimitry Andric return; 66885ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 668981ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6690979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H); 66915ffd83dbSDimitry Andric return; 66925ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6693979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W); 66945ffd83dbSDimitry Andric return; 66955ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6696979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D); 66975ffd83dbSDimitry Andric return; 66985ffd83dbSDimitry Andric } 66995ffd83dbSDimitry Andric break; 67005ffd83dbSDimitry Andric } 67015ffd83dbSDimitry Andric case AArch64ISD::SVE_LD3_MERGE_ZERO: { 67025ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6703979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B); 67045ffd83dbSDimitry Andric return; 67055ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 670681ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6707979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H); 67085ffd83dbSDimitry Andric return; 67095ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6710979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W); 67115ffd83dbSDimitry Andric return; 67125ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6713979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D); 67145ffd83dbSDimitry Andric return; 67155ffd83dbSDimitry Andric } 67165ffd83dbSDimitry Andric break; 67175ffd83dbSDimitry Andric } 67185ffd83dbSDimitry Andric case AArch64ISD::SVE_LD4_MERGE_ZERO: { 67195ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6720979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B); 67215ffd83dbSDimitry Andric return; 67225ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 672381ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6724979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H); 67255ffd83dbSDimitry Andric return; 67265ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6727979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W); 67285ffd83dbSDimitry Andric return; 67295ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6730979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D); 67315ffd83dbSDimitry Andric return; 67325ffd83dbSDimitry Andric } 67335ffd83dbSDimitry Andric break; 67345ffd83dbSDimitry Andric } 67350b57cec5SDimitry Andric } 67360b57cec5SDimitry Andric 67370b57cec5SDimitry Andric // Select the default instruction 67380b57cec5SDimitry Andric SelectCode(Node); 67390b57cec5SDimitry Andric } 67400b57cec5SDimitry Andric 67410b57cec5SDimitry Andric /// createAArch64ISelDag - This pass converts a legalized DAG into a 67420b57cec5SDimitry Andric /// AArch64-specific DAG, ready for instruction scheduling. 67430b57cec5SDimitry Andric FunctionPass *llvm::createAArch64ISelDag(AArch64TargetMachine &TM, 6744*5f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 67450b57cec5SDimitry Andric return new AArch64DAGToDAGISel(TM, OptLevel); 67460b57cec5SDimitry Andric } 67475ffd83dbSDimitry Andric 67485ffd83dbSDimitry Andric /// When \p PredVT is a scalable vector predicate in the form 67495ffd83dbSDimitry Andric /// MVT::nx<M>xi1, it builds the correspondent scalable vector of 6750979e22ffSDimitry Andric /// integers MVT::nx<M>xi<bits> s.t. M x bits = 128. When targeting 6751979e22ffSDimitry Andric /// structured vectors (NumVec >1), the output data type is 6752979e22ffSDimitry Andric /// MVT::nx<M*NumVec>xi<bits> s.t. M x bits = 128. If the input 67535ffd83dbSDimitry Andric /// PredVT is not in the form MVT::nx<M>xi1, it returns an invalid 67545ffd83dbSDimitry Andric /// EVT. 6755979e22ffSDimitry Andric static EVT getPackedVectorTypeFromPredicateType(LLVMContext &Ctx, EVT PredVT, 6756979e22ffSDimitry Andric unsigned NumVec) { 6757979e22ffSDimitry Andric assert(NumVec > 0 && NumVec < 5 && "Invalid number of vectors."); 67585ffd83dbSDimitry Andric if (!PredVT.isScalableVector() || PredVT.getVectorElementType() != MVT::i1) 67595ffd83dbSDimitry Andric return EVT(); 67605ffd83dbSDimitry Andric 67615ffd83dbSDimitry Andric if (PredVT != MVT::nxv16i1 && PredVT != MVT::nxv8i1 && 67625ffd83dbSDimitry Andric PredVT != MVT::nxv4i1 && PredVT != MVT::nxv2i1) 67635ffd83dbSDimitry Andric return EVT(); 67645ffd83dbSDimitry Andric 67655ffd83dbSDimitry Andric ElementCount EC = PredVT.getVectorElementCount(); 6766e8d8bef9SDimitry Andric EVT ScalarVT = 6767e8d8bef9SDimitry Andric EVT::getIntegerVT(Ctx, AArch64::SVEBitsPerBlock / EC.getKnownMinValue()); 6768979e22ffSDimitry Andric EVT MemVT = EVT::getVectorVT(Ctx, ScalarVT, EC * NumVec); 6769979e22ffSDimitry Andric 67705ffd83dbSDimitry Andric return MemVT; 67715ffd83dbSDimitry Andric } 67725ffd83dbSDimitry Andric 67735ffd83dbSDimitry Andric /// Return the EVT of the data associated to a memory operation in \p 67745ffd83dbSDimitry Andric /// Root. If such EVT cannot be retrived, it returns an invalid EVT. 67755ffd83dbSDimitry Andric static EVT getMemVTFromNode(LLVMContext &Ctx, SDNode *Root) { 67765ffd83dbSDimitry Andric if (isa<MemSDNode>(Root)) 67775ffd83dbSDimitry Andric return cast<MemSDNode>(Root)->getMemoryVT(); 67785ffd83dbSDimitry Andric 67795ffd83dbSDimitry Andric if (isa<MemIntrinsicSDNode>(Root)) 67805ffd83dbSDimitry Andric return cast<MemIntrinsicSDNode>(Root)->getMemoryVT(); 67815ffd83dbSDimitry Andric 67825ffd83dbSDimitry Andric const unsigned Opcode = Root->getOpcode(); 67835ffd83dbSDimitry Andric // For custom ISD nodes, we have to look at them individually to extract the 67845ffd83dbSDimitry Andric // type of the data moved to/from memory. 67855ffd83dbSDimitry Andric switch (Opcode) { 67865ffd83dbSDimitry Andric case AArch64ISD::LD1_MERGE_ZERO: 67875ffd83dbSDimitry Andric case AArch64ISD::LD1S_MERGE_ZERO: 67885ffd83dbSDimitry Andric case AArch64ISD::LDNF1_MERGE_ZERO: 67895ffd83dbSDimitry Andric case AArch64ISD::LDNF1S_MERGE_ZERO: 67905ffd83dbSDimitry Andric return cast<VTSDNode>(Root->getOperand(3))->getVT(); 67915ffd83dbSDimitry Andric case AArch64ISD::ST1_PRED: 67925ffd83dbSDimitry Andric return cast<VTSDNode>(Root->getOperand(4))->getVT(); 6793979e22ffSDimitry Andric case AArch64ISD::SVE_LD2_MERGE_ZERO: 6794979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 6795979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/2); 6796979e22ffSDimitry Andric case AArch64ISD::SVE_LD3_MERGE_ZERO: 6797979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 6798979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/3); 6799979e22ffSDimitry Andric case AArch64ISD::SVE_LD4_MERGE_ZERO: 6800979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 6801979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/4); 68025ffd83dbSDimitry Andric default: 68035ffd83dbSDimitry Andric break; 68045ffd83dbSDimitry Andric } 68055ffd83dbSDimitry Andric 6806bdd1243dSDimitry Andric if (Opcode != ISD::INTRINSIC_VOID && Opcode != ISD::INTRINSIC_W_CHAIN) 68075ffd83dbSDimitry Andric return EVT(); 68085ffd83dbSDimitry Andric 6809bdd1243dSDimitry Andric switch (cast<ConstantSDNode>(Root->getOperand(1))->getZExtValue()) { 6810bdd1243dSDimitry Andric default: 6811bdd1243dSDimitry Andric return EVT(); 6812bdd1243dSDimitry Andric case Intrinsic::aarch64_sme_ldr: 6813bdd1243dSDimitry Andric case Intrinsic::aarch64_sme_str: 681481ad6265SDimitry Andric return MVT::nxv16i8; 6815bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_prf: 6816bdd1243dSDimitry Andric // We are using an SVE prefetch intrinsic. Type must be inferred from the 6817bdd1243dSDimitry Andric // width of the predicate. 68185ffd83dbSDimitry Andric return getPackedVectorTypeFromPredicateType( 6819979e22ffSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/1); 6820bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: 6821*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld2q_sret: 6822bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 6823bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/2); 6824*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st2q: 6825*5f757f3fSDimitry Andric return getPackedVectorTypeFromPredicateType( 6826*5f757f3fSDimitry Andric Ctx, Root->getOperand(4)->getValueType(0), /*NumVec=*/2); 6827bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: 6828*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld3q_sret: 6829bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 6830bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/3); 6831*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st3q: 6832*5f757f3fSDimitry Andric return getPackedVectorTypeFromPredicateType( 6833*5f757f3fSDimitry Andric Ctx, Root->getOperand(5)->getValueType(0), /*NumVec=*/3); 6834bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: 6835*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld4q_sret: 6836bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 6837bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/4); 6838*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st4q: 6839*5f757f3fSDimitry Andric return getPackedVectorTypeFromPredicateType( 6840*5f757f3fSDimitry Andric Ctx, Root->getOperand(6)->getValueType(0), /*NumVec=*/4); 6841*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld1udq: 6842*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st1udq: 6843*5f757f3fSDimitry Andric return EVT(MVT::nxv1i64); 6844*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld1uwq: 6845*5f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st1uwq: 6846*5f757f3fSDimitry Andric return EVT(MVT::nxv1i32); 6847bdd1243dSDimitry Andric } 68485ffd83dbSDimitry Andric } 68495ffd83dbSDimitry Andric 68505ffd83dbSDimitry Andric /// SelectAddrModeIndexedSVE - Attempt selection of the addressing mode: 68515ffd83dbSDimitry Andric /// Base + OffImm * sizeof(MemVT) for Min >= OffImm <= Max 68525ffd83dbSDimitry Andric /// where Root is the memory access using N for its address. 68535ffd83dbSDimitry Andric template <int64_t Min, int64_t Max> 68545ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexedSVE(SDNode *Root, SDValue N, 68555ffd83dbSDimitry Andric SDValue &Base, 68565ffd83dbSDimitry Andric SDValue &OffImm) { 68575ffd83dbSDimitry Andric const EVT MemVT = getMemVTFromNode(*(CurDAG->getContext()), Root); 6858349cc55cSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 685981ad6265SDimitry Andric const MachineFrameInfo &MFI = MF->getFrameInfo(); 6860349cc55cSDimitry Andric 6861349cc55cSDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 6862349cc55cSDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 686381ad6265SDimitry Andric // We can only encode VL scaled offsets, so only fold in frame indexes 686481ad6265SDimitry Andric // referencing SVE objects. 686506c3fb27SDimitry Andric if (MFI.getStackID(FI) == TargetStackID::ScalableVector) { 6866349cc55cSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 6867349cc55cSDimitry Andric OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 6868349cc55cSDimitry Andric return true; 6869349cc55cSDimitry Andric } 68705ffd83dbSDimitry Andric 687181ad6265SDimitry Andric return false; 687281ad6265SDimitry Andric } 687381ad6265SDimitry Andric 68745ffd83dbSDimitry Andric if (MemVT == EVT()) 68755ffd83dbSDimitry Andric return false; 68765ffd83dbSDimitry Andric 68775ffd83dbSDimitry Andric if (N.getOpcode() != ISD::ADD) 68785ffd83dbSDimitry Andric return false; 68795ffd83dbSDimitry Andric 68805ffd83dbSDimitry Andric SDValue VScale = N.getOperand(1); 68815ffd83dbSDimitry Andric if (VScale.getOpcode() != ISD::VSCALE) 68825ffd83dbSDimitry Andric return false; 68835ffd83dbSDimitry Andric 68845ffd83dbSDimitry Andric TypeSize TS = MemVT.getSizeInBits(); 6885bdd1243dSDimitry Andric int64_t MemWidthBytes = static_cast<int64_t>(TS.getKnownMinValue()) / 8; 68865ffd83dbSDimitry Andric int64_t MulImm = cast<ConstantSDNode>(VScale.getOperand(0))->getSExtValue(); 68875ffd83dbSDimitry Andric 68885ffd83dbSDimitry Andric if ((MulImm % MemWidthBytes) != 0) 68895ffd83dbSDimitry Andric return false; 68905ffd83dbSDimitry Andric 68915ffd83dbSDimitry Andric int64_t Offset = MulImm / MemWidthBytes; 68925ffd83dbSDimitry Andric if (Offset < Min || Offset > Max) 68935ffd83dbSDimitry Andric return false; 68945ffd83dbSDimitry Andric 68955ffd83dbSDimitry Andric Base = N.getOperand(0); 6896349cc55cSDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 6897349cc55cSDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 689881ad6265SDimitry Andric // We can only encode VL scaled offsets, so only fold in frame indexes 689981ad6265SDimitry Andric // referencing SVE objects. 690006c3fb27SDimitry Andric if (MFI.getStackID(FI) == TargetStackID::ScalableVector) 6901349cc55cSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 6902349cc55cSDimitry Andric } 6903349cc55cSDimitry Andric 69045ffd83dbSDimitry Andric OffImm = CurDAG->getTargetConstant(Offset, SDLoc(N), MVT::i64); 69055ffd83dbSDimitry Andric return true; 69065ffd83dbSDimitry Andric } 69075ffd83dbSDimitry Andric 69085ffd83dbSDimitry Andric /// Select register plus register addressing mode for SVE, with scaled 69095ffd83dbSDimitry Andric /// offset. 69105ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectSVERegRegAddrMode(SDValue N, unsigned Scale, 69115ffd83dbSDimitry Andric SDValue &Base, 69125ffd83dbSDimitry Andric SDValue &Offset) { 69135ffd83dbSDimitry Andric if (N.getOpcode() != ISD::ADD) 69145ffd83dbSDimitry Andric return false; 69155ffd83dbSDimitry Andric 69165ffd83dbSDimitry Andric // Process an ADD node. 69175ffd83dbSDimitry Andric const SDValue LHS = N.getOperand(0); 69185ffd83dbSDimitry Andric const SDValue RHS = N.getOperand(1); 69195ffd83dbSDimitry Andric 69205ffd83dbSDimitry Andric // 8 bit data does not come with the SHL node, so it is treated 69215ffd83dbSDimitry Andric // separately. 69225ffd83dbSDimitry Andric if (Scale == 0) { 69235ffd83dbSDimitry Andric Base = LHS; 69245ffd83dbSDimitry Andric Offset = RHS; 69255ffd83dbSDimitry Andric return true; 69265ffd83dbSDimitry Andric } 69275ffd83dbSDimitry Andric 6928fe6060f1SDimitry Andric if (auto C = dyn_cast<ConstantSDNode>(RHS)) { 6929fe6060f1SDimitry Andric int64_t ImmOff = C->getSExtValue(); 6930fe6060f1SDimitry Andric unsigned Size = 1 << Scale; 6931fe6060f1SDimitry Andric 6932fe6060f1SDimitry Andric // To use the reg+reg addressing mode, the immediate must be a multiple of 6933fe6060f1SDimitry Andric // the vector element's byte size. 6934fe6060f1SDimitry Andric if (ImmOff % Size) 6935fe6060f1SDimitry Andric return false; 6936fe6060f1SDimitry Andric 6937fe6060f1SDimitry Andric SDLoc DL(N); 6938fe6060f1SDimitry Andric Base = LHS; 6939fe6060f1SDimitry Andric Offset = CurDAG->getTargetConstant(ImmOff >> Scale, DL, MVT::i64); 6940fe6060f1SDimitry Andric SDValue Ops[] = {Offset}; 6941fe6060f1SDimitry Andric SDNode *MI = CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops); 6942fe6060f1SDimitry Andric Offset = SDValue(MI, 0); 6943fe6060f1SDimitry Andric return true; 6944fe6060f1SDimitry Andric } 6945fe6060f1SDimitry Andric 69465ffd83dbSDimitry Andric // Check if the RHS is a shift node with a constant. 69475ffd83dbSDimitry Andric if (RHS.getOpcode() != ISD::SHL) 69485ffd83dbSDimitry Andric return false; 69495ffd83dbSDimitry Andric 69505ffd83dbSDimitry Andric const SDValue ShiftRHS = RHS.getOperand(1); 69515ffd83dbSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(ShiftRHS)) 69525ffd83dbSDimitry Andric if (C->getZExtValue() == Scale) { 69535ffd83dbSDimitry Andric Base = LHS; 69545ffd83dbSDimitry Andric Offset = RHS.getOperand(0); 69555ffd83dbSDimitry Andric return true; 69565ffd83dbSDimitry Andric } 69575ffd83dbSDimitry Andric 69585ffd83dbSDimitry Andric return false; 69595ffd83dbSDimitry Andric } 6960fe6060f1SDimitry Andric 6961fe6060f1SDimitry Andric bool AArch64DAGToDAGISel::SelectAllActivePredicate(SDValue N) { 6962fe6060f1SDimitry Andric const AArch64TargetLowering *TLI = 6963fe6060f1SDimitry Andric static_cast<const AArch64TargetLowering *>(getTargetLowering()); 6964fe6060f1SDimitry Andric 696504eeddc0SDimitry Andric return TLI->isAllActivePredicate(*CurDAG, N); 6966fe6060f1SDimitry Andric } 696781ad6265SDimitry Andric 696806c3fb27SDimitry Andric bool AArch64DAGToDAGISel::SelectAnyPredicate(SDValue N) { 696906c3fb27SDimitry Andric EVT VT = N.getValueType(); 697006c3fb27SDimitry Andric return VT.isScalableVector() && VT.getVectorElementType() == MVT::i1; 697106c3fb27SDimitry Andric } 697206c3fb27SDimitry Andric 6973bdd1243dSDimitry Andric bool AArch64DAGToDAGISel::SelectSMETileSlice(SDValue N, unsigned MaxSize, 6974bdd1243dSDimitry Andric SDValue &Base, SDValue &Offset, 6975bdd1243dSDimitry Andric unsigned Scale) { 697606c3fb27SDimitry Andric // Try to untangle an ADD node into a 'reg + offset' 697706c3fb27SDimitry Andric if (N.getOpcode() == ISD::ADD) 697806c3fb27SDimitry Andric if (auto C = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 697981ad6265SDimitry Andric int64_t ImmOff = C->getSExtValue(); 698006c3fb27SDimitry Andric if ((ImmOff > 0 && ImmOff <= MaxSize && (ImmOff % Scale == 0))) { 698106c3fb27SDimitry Andric Base = N.getOperand(0); 6982bdd1243dSDimitry Andric Offset = CurDAG->getTargetConstant(ImmOff / Scale, SDLoc(N), MVT::i64); 698381ad6265SDimitry Andric return true; 698481ad6265SDimitry Andric } 698506c3fb27SDimitry Andric } 698681ad6265SDimitry Andric 698706c3fb27SDimitry Andric // By default, just match reg + 0. 698806c3fb27SDimitry Andric Base = N; 698906c3fb27SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 699006c3fb27SDimitry Andric return true; 699181ad6265SDimitry Andric } 6992