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, 525f757f3fSDimitry 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, 655f757f3fSDimitry 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 3295f757f3fSDimitry Andric template <unsigned BaseReg, unsigned Max> 3305f757f3fSDimitry Andric bool ImmToReg(SDValue N, SDValue &Imm) { 33181ad6265SDimitry Andric if (auto *CI = dyn_cast<ConstantSDNode>(N)) { 33281ad6265SDimitry Andric uint64_t C = CI->getZExtValue(); 3335f757f3fSDimitry Andric 3345f757f3fSDimitry Andric if (C > Max) 3355f757f3fSDimitry Andric return false; 3365f757f3fSDimitry 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 4075f757f3fSDimitry Andric void SelectMultiVectorLuti(SDNode *Node, unsigned NumOutVecs, unsigned Opc, 4085f757f3fSDimitry Andric uint32_t MaxImm); 4095f757f3fSDimitry 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 4385f757f3fSDimitry Andric bool trySelectXAR(SDNode *N); 4395f757f3fSDimitry 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); 4645f757f3fSDimitry Andric bool isWorthFoldingALU(SDValue V, bool LSL = false) const; 4655f757f3fSDimitry 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 4765f757f3fSDimitry Andric template<unsigned RegWidth> 4775f757f3fSDimitry Andric bool SelectCVTFixedPosRecipOperand(SDValue N, SDValue &FixedPos) { 4785f757f3fSDimitry Andric return SelectCVTFixedPosRecipOperand(N, FixedPos, RegWidth); 4795f757f3fSDimitry Andric } 4805f757f3fSDimitry Andric 4815f757f3fSDimitry Andric bool SelectCVTFixedPosRecipOperand(SDValue N, SDValue &FixedPos, 4825f757f3fSDimitry Andric unsigned Width); 4835f757f3fSDimitry 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( 5465f757f3fSDimitry Andric const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID, 5475f757f3fSDimitry Andric std::vector<SDValue> &OutOps) { 5480b57cec5SDimitry Andric switch(ConstraintID) { 5490b57cec5SDimitry Andric default: 5500b57cec5SDimitry Andric llvm_unreachable("Unexpected asm memory constraint"); 5515f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: 5525f757f3fSDimitry Andric case InlineAsm::ConstraintCode::o: 5535f757f3fSDimitry 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 583*1db9f3b2SDimitry Andric uint64_t Immed = N.getNode()->getAsZExtVal(); 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. 614*1db9f3b2SDimitry Andric uint64_t Immed = N.getNode()->getAsZExtVal(); 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 6755f757f3fSDimitry Andric /// Determine whether it is worth to fold V into an extended register addressing 6765f757f3fSDimitry Andric /// mode. 6775f757f3fSDimitry 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. 6845f757f3fSDimitry Andric if (Subtarget->hasAddrLSLFast() && V.getOpcode() == ISD::SHL && 6850b57cec5SDimitry Andric isWorthFoldingSHL(V)) 6860b57cec5SDimitry Andric return true; 6875f757f3fSDimitry 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 8325f757f3fSDimitry Andric /// Determine whether it is worth to fold V into an extended register of an 8335f757f3fSDimitry Andric /// Add/Sub. LSL means we are folding into an `add w0, w1, w2, lsl #N` 8345f757f3fSDimitry Andric /// instruction, and the shift should be treated as worth folding even if has 8355f757f3fSDimitry Andric /// multiple uses. 8365f757f3fSDimitry Andric bool AArch64DAGToDAGISel::isWorthFoldingALU(SDValue V, bool LSL) const { 8375f757f3fSDimitry Andric // Trivial if we are optimizing for code size or if there is only 8385f757f3fSDimitry Andric // one use of the value. 8395f757f3fSDimitry Andric if (CurDAG->shouldOptForSize() || V.hasOneUse()) 8405f757f3fSDimitry Andric return true; 8415f757f3fSDimitry Andric 8425f757f3fSDimitry Andric // If a subtarget has a fastpath LSL we can fold a logical shift into 8435f757f3fSDimitry Andric // the add/sub and save a cycle. 8445f757f3fSDimitry Andric if (LSL && Subtarget->hasALULSLFast() && V.getOpcode() == ISD::SHL && 8455f757f3fSDimitry Andric V.getConstantOperandVal(1) <= 4 && 8465f757f3fSDimitry Andric getExtendTypeForNode(V.getOperand(0)) == AArch64_AM::InvalidShiftExtend) 8475f757f3fSDimitry Andric return true; 8485f757f3fSDimitry Andric 8495f757f3fSDimitry Andric // It hurts otherwise, since the value will be reused. 8505f757f3fSDimitry Andric return false; 8515f757f3fSDimitry Andric } 8525f757f3fSDimitry Andric 8535f757f3fSDimitry Andric /// SelectShiftedRegister - Select a "shifted register" operand. If the value 8545f757f3fSDimitry Andric /// is not shifted, set the Shift operand to default of "LSL 0". The logical 8555f757f3fSDimitry Andric /// instructions allow the shifted register to be rotated, but the arithmetic 8565f757f3fSDimitry Andric /// instructions do not. The AllowROR parameter specifies whether ROR is 8575f757f3fSDimitry Andric /// supported. 8585f757f3fSDimitry Andric bool AArch64DAGToDAGISel::SelectShiftedRegister(SDValue N, bool AllowROR, 8595f757f3fSDimitry Andric SDValue &Reg, SDValue &Shift) { 8605f757f3fSDimitry Andric if (SelectShiftedRegisterFromAnd(N, Reg, Shift)) 8615f757f3fSDimitry Andric return true; 8625f757f3fSDimitry Andric 8635f757f3fSDimitry Andric AArch64_AM::ShiftExtendType ShType = getShiftTypeForNode(N); 8645f757f3fSDimitry Andric if (ShType == AArch64_AM::InvalidShiftExtend) 8655f757f3fSDimitry Andric return false; 8665f757f3fSDimitry Andric if (!AllowROR && ShType == AArch64_AM::ROR) 8675f757f3fSDimitry Andric return false; 8685f757f3fSDimitry Andric 8695f757f3fSDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 8705f757f3fSDimitry Andric unsigned BitSize = N.getValueSizeInBits(); 8715f757f3fSDimitry Andric unsigned Val = RHS->getZExtValue() & (BitSize - 1); 8725f757f3fSDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(ShType, Val); 8735f757f3fSDimitry Andric 8745f757f3fSDimitry Andric Reg = N.getOperand(0); 8755f757f3fSDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, SDLoc(N), MVT::i32); 8765f757f3fSDimitry Andric return isWorthFoldingALU(N, true); 8775f757f3fSDimitry Andric } 8785f757f3fSDimitry Andric 8795f757f3fSDimitry Andric return false; 8805f757f3fSDimitry Andric } 8815f757f3fSDimitry 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); 9625f757f3fSDimitry 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); 9865f757f3fSDimitry 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 10105f757f3fSDimitry Andric /// Check if the immediate offset is valid as a scaled immediate. 10115f757f3fSDimitry Andric static bool isValidAsScaledImmediate(int64_t Offset, unsigned Range, 10125f757f3fSDimitry Andric unsigned Size) { 10135f757f3fSDimitry Andric if ((Offset & (Size - 1)) == 0 && Offset >= 0 && 10145f757f3fSDimitry Andric Offset < (Range << Log2_32(Size))) 10155f757f3fSDimitry Andric return true; 10165f757f3fSDimitry Andric return false; 10175f757f3fSDimitry Andric } 10185f757f3fSDimitry 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); 11145f757f3fSDimitry 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 12065f757f3fSDimitry 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. 12345f757f3fSDimitry 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); 12645f757f3fSDimitry 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); 12765f757f3fSDimitry 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)) { 1329*1db9f3b2SDimitry Andric int64_t ImmOff = (int64_t)RHS->getAsZExtVal(); 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). 13335f757f3fSDimitry 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. 13465f757f3fSDimitry 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) { 18005f757f3fSDimitry 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 18725f757f3fSDimitry Andric void AArch64DAGToDAGISel::SelectMultiVectorLuti(SDNode *Node, 18735f757f3fSDimitry Andric unsigned NumOutVecs, 18745f757f3fSDimitry Andric unsigned Opc, uint32_t MaxImm) { 18755f757f3fSDimitry Andric if (ConstantSDNode *Imm = dyn_cast<ConstantSDNode>(Node->getOperand(4))) 18765f757f3fSDimitry Andric if (Imm->getZExtValue() > MaxImm) 18775f757f3fSDimitry Andric return; 18785f757f3fSDimitry Andric 18795f757f3fSDimitry Andric SDValue ZtValue; 18805f757f3fSDimitry Andric if (!ImmToReg<AArch64::ZT0, 0>(Node->getOperand(2), ZtValue)) 18815f757f3fSDimitry Andric return; 18825f757f3fSDimitry Andric SDValue Ops[] = {ZtValue, Node->getOperand(3), Node->getOperand(4)}; 18835f757f3fSDimitry Andric SDLoc DL(Node); 18845f757f3fSDimitry Andric EVT VT = Node->getValueType(0); 18855f757f3fSDimitry Andric 18865f757f3fSDimitry Andric SDNode *Instruction = 18875f757f3fSDimitry Andric CurDAG->getMachineNode(Opc, DL, {MVT::Untyped, MVT::Other}, Ops); 18885f757f3fSDimitry Andric SDValue SuperReg = SDValue(Instruction, 0); 18895f757f3fSDimitry Andric 18905f757f3fSDimitry Andric for (unsigned I = 0; I < NumOutVecs; ++I) 18915f757f3fSDimitry Andric ReplaceUses(SDValue(Node, I), CurDAG->getTargetExtractSubreg( 18925f757f3fSDimitry Andric AArch64::zsub0 + I, DL, VT, SuperReg)); 18935f757f3fSDimitry Andric 18945f757f3fSDimitry Andric // Copy chain 18955f757f3fSDimitry Andric unsigned ChainIdx = NumOutVecs; 18965f757f3fSDimitry Andric ReplaceUses(SDValue(Node, ChainIdx), SDValue(Instruction, 1)); 18975f757f3fSDimitry Andric CurDAG->RemoveDeadNode(Node); 18985f757f3fSDimitry Andric } 18995f757f3fSDimitry 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) 1953647cbc5dSDimitry Andric TileNum = N->getConstantOperandVal(2); 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 2148647cbc5dSDimitry Andric unsigned LaneNo = N->getConstantOperandVal(NumVecs + 2); 21490b57cec5SDimitry Andric 21500b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 21510b57cec5SDimitry Andric N->getOperand(NumVecs + 3), N->getOperand(0)}; 21520b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 21530b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 0); 21540b57cec5SDimitry Andric 21550b57cec5SDimitry Andric EVT WideVT = RegSeq.getOperand(1)->getValueType(0); 21560b57cec5SDimitry Andric static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1, 21570b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3 }; 21580b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) { 21590b57cec5SDimitry Andric SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, SuperReg); 21600b57cec5SDimitry Andric if (Narrow) 21610b57cec5SDimitry Andric NV = NarrowVector(NV, *CurDAG); 21620b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), NV); 21630b57cec5SDimitry Andric } 21640b57cec5SDimitry Andric 21650b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1)); 21660b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 21670b57cec5SDimitry Andric } 21680b57cec5SDimitry Andric 21690b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostLoadLane(SDNode *N, unsigned NumVecs, 21700b57cec5SDimitry Andric unsigned Opc) { 21710b57cec5SDimitry Andric SDLoc dl(N); 21720b57cec5SDimitry Andric EVT VT = N->getValueType(0); 21730b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 21740b57cec5SDimitry Andric 21750b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 21760b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 21770b57cec5SDimitry Andric 21780b57cec5SDimitry Andric if (Narrow) 21790b57cec5SDimitry Andric transform(Regs, Regs.begin(), 21800b57cec5SDimitry Andric WidenVector(*CurDAG)); 21810b57cec5SDimitry Andric 21820b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 21830b57cec5SDimitry Andric 21840b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 21850b57cec5SDimitry Andric RegSeq->getValueType(0), MVT::Other}; 21860b57cec5SDimitry Andric 2187647cbc5dSDimitry Andric unsigned LaneNo = N->getConstantOperandVal(NumVecs + 1); 21880b57cec5SDimitry Andric 21890b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, 21900b57cec5SDimitry Andric CurDAG->getTargetConstant(LaneNo, dl, 21910b57cec5SDimitry Andric MVT::i64), // Lane Number 21920b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Base register 21930b57cec5SDimitry Andric N->getOperand(NumVecs + 3), // Incremental 21940b57cec5SDimitry Andric N->getOperand(0)}; 21950b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 21960b57cec5SDimitry Andric 21970b57cec5SDimitry Andric // Update uses of the write back register 21980b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0)); 21990b57cec5SDimitry Andric 22000b57cec5SDimitry Andric // Update uses of the vector list 22010b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 1); 22020b57cec5SDimitry Andric if (NumVecs == 1) { 22030b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), 22040b57cec5SDimitry Andric Narrow ? NarrowVector(SuperReg, *CurDAG) : SuperReg); 22050b57cec5SDimitry Andric } else { 22060b57cec5SDimitry Andric EVT WideVT = RegSeq.getOperand(1)->getValueType(0); 22070b57cec5SDimitry Andric static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1, 22080b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3 }; 22090b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) { 22100b57cec5SDimitry Andric SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, 22110b57cec5SDimitry Andric SuperReg); 22120b57cec5SDimitry Andric if (Narrow) 22130b57cec5SDimitry Andric NV = NarrowVector(NV, *CurDAG); 22140b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), NV); 22150b57cec5SDimitry Andric } 22160b57cec5SDimitry Andric } 22170b57cec5SDimitry Andric 22180b57cec5SDimitry Andric // Update the Chain 22190b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2)); 22200b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 22210b57cec5SDimitry Andric } 22220b57cec5SDimitry Andric 22230b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectStoreLane(SDNode *N, unsigned NumVecs, 22240b57cec5SDimitry Andric unsigned Opc) { 22250b57cec5SDimitry Andric SDLoc dl(N); 22260b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 22270b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 22280b57cec5SDimitry Andric 22290b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 22300b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 22310b57cec5SDimitry Andric 22320b57cec5SDimitry Andric if (Narrow) 22330b57cec5SDimitry Andric transform(Regs, Regs.begin(), 22340b57cec5SDimitry Andric WidenVector(*CurDAG)); 22350b57cec5SDimitry Andric 22360b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 22370b57cec5SDimitry Andric 2238647cbc5dSDimitry Andric unsigned LaneNo = N->getConstantOperandVal(NumVecs + 2); 22390b57cec5SDimitry Andric 22400b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 22410b57cec5SDimitry Andric N->getOperand(NumVecs + 3), N->getOperand(0)}; 22420b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops); 22430b57cec5SDimitry Andric 22440b57cec5SDimitry Andric // Transfer memoperands. 22450b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 22460b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 22470b57cec5SDimitry Andric 22480b57cec5SDimitry Andric ReplaceNode(N, St); 22490b57cec5SDimitry Andric } 22500b57cec5SDimitry Andric 22510b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostStoreLane(SDNode *N, unsigned NumVecs, 22520b57cec5SDimitry Andric unsigned Opc) { 22530b57cec5SDimitry Andric SDLoc dl(N); 22540b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 22550b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 22560b57cec5SDimitry Andric 22570b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 22580b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 22590b57cec5SDimitry Andric 22600b57cec5SDimitry Andric if (Narrow) 22610b57cec5SDimitry Andric transform(Regs, Regs.begin(), 22620b57cec5SDimitry Andric WidenVector(*CurDAG)); 22630b57cec5SDimitry Andric 22640b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 22650b57cec5SDimitry Andric 22660b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 22670b57cec5SDimitry Andric MVT::Other}; 22680b57cec5SDimitry Andric 2269647cbc5dSDimitry Andric unsigned LaneNo = N->getConstantOperandVal(NumVecs + 1); 22700b57cec5SDimitry Andric 22710b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 22720b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Base Register 22730b57cec5SDimitry Andric N->getOperand(NumVecs + 3), // Incremental 22740b57cec5SDimitry Andric N->getOperand(0)}; 22750b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 22760b57cec5SDimitry Andric 22770b57cec5SDimitry Andric // Transfer memoperands. 22780b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 22790b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 22800b57cec5SDimitry Andric 22810b57cec5SDimitry Andric ReplaceNode(N, St); 22820b57cec5SDimitry Andric } 22830b57cec5SDimitry Andric 22840b57cec5SDimitry Andric static bool isBitfieldExtractOpFromAnd(SelectionDAG *CurDAG, SDNode *N, 22850b57cec5SDimitry Andric unsigned &Opc, SDValue &Opd0, 22860b57cec5SDimitry Andric unsigned &LSB, unsigned &MSB, 22870b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits, 22880b57cec5SDimitry Andric bool BiggerPattern) { 22890b57cec5SDimitry Andric assert(N->getOpcode() == ISD::AND && 22900b57cec5SDimitry Andric "N must be a AND operation to call this function"); 22910b57cec5SDimitry Andric 22920b57cec5SDimitry Andric EVT VT = N->getValueType(0); 22930b57cec5SDimitry Andric 22940b57cec5SDimitry Andric // Here we can test the type of VT and return false when the type does not 22950b57cec5SDimitry Andric // match, but since it is done prior to that call in the current context 22960b57cec5SDimitry Andric // we turned that into an assert to avoid redundant code. 22970b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 22980b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 22990b57cec5SDimitry Andric 23000b57cec5SDimitry Andric // FIXME: simplify-demanded-bits in DAGCombine will probably have 23010b57cec5SDimitry Andric // changed the AND node to a 32-bit mask operation. We'll have to 23020b57cec5SDimitry Andric // undo that as part of the transform here if we want to catch all 23030b57cec5SDimitry Andric // the opportunities. 23040b57cec5SDimitry Andric // Currently the NumberOfIgnoredLowBits argument helps to recover 2305bdd1243dSDimitry Andric // from these situations when matching bigger pattern (bitfield insert). 23060b57cec5SDimitry Andric 23070b57cec5SDimitry Andric // For unsigned extracts, check for a shift right and mask 23080b57cec5SDimitry Andric uint64_t AndImm = 0; 23090b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N, ISD::AND, AndImm)) 23100b57cec5SDimitry Andric return false; 23110b57cec5SDimitry Andric 23120b57cec5SDimitry Andric const SDNode *Op0 = N->getOperand(0).getNode(); 23130b57cec5SDimitry Andric 23140b57cec5SDimitry Andric // Because of simplify-demanded-bits in DAGCombine, the mask may have been 23150b57cec5SDimitry Andric // simplified. Try to undo that 23160b57cec5SDimitry Andric AndImm |= maskTrailingOnes<uint64_t>(NumberOfIgnoredLowBits); 23170b57cec5SDimitry Andric 23180b57cec5SDimitry Andric // The immediate is a mask of the low bits iff imm & (imm+1) == 0 23190b57cec5SDimitry Andric if (AndImm & (AndImm + 1)) 23200b57cec5SDimitry Andric return false; 23210b57cec5SDimitry Andric 23220b57cec5SDimitry Andric bool ClampMSB = false; 23230b57cec5SDimitry Andric uint64_t SrlImm = 0; 23240b57cec5SDimitry Andric // Handle the SRL + ANY_EXTEND case. 23250b57cec5SDimitry Andric if (VT == MVT::i64 && Op0->getOpcode() == ISD::ANY_EXTEND && 23260b57cec5SDimitry Andric isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, SrlImm)) { 23270b57cec5SDimitry Andric // Extend the incoming operand of the SRL to 64-bit. 23280b57cec5SDimitry Andric Opd0 = Widen(CurDAG, Op0->getOperand(0).getOperand(0)); 23290b57cec5SDimitry Andric // Make sure to clamp the MSB so that we preserve the semantics of the 23300b57cec5SDimitry Andric // original operations. 23310b57cec5SDimitry Andric ClampMSB = true; 23320b57cec5SDimitry Andric } else if (VT == MVT::i32 && Op0->getOpcode() == ISD::TRUNCATE && 23330b57cec5SDimitry Andric isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, 23340b57cec5SDimitry Andric SrlImm)) { 23350b57cec5SDimitry Andric // If the shift result was truncated, we can still combine them. 23360b57cec5SDimitry Andric Opd0 = Op0->getOperand(0).getOperand(0); 23370b57cec5SDimitry Andric 23380b57cec5SDimitry Andric // Use the type of SRL node. 23390b57cec5SDimitry Andric VT = Opd0->getValueType(0); 23400b57cec5SDimitry Andric } else if (isOpcWithIntImmediate(Op0, ISD::SRL, SrlImm)) { 23410b57cec5SDimitry Andric Opd0 = Op0->getOperand(0); 234281ad6265SDimitry Andric ClampMSB = (VT == MVT::i32); 23430b57cec5SDimitry Andric } else if (BiggerPattern) { 23440b57cec5SDimitry Andric // Let's pretend a 0 shift right has been performed. 23450b57cec5SDimitry Andric // The resulting code will be at least as good as the original one 23460b57cec5SDimitry Andric // plus it may expose more opportunities for bitfield insert pattern. 23470b57cec5SDimitry Andric // FIXME: Currently we limit this to the bigger pattern, because 23480b57cec5SDimitry Andric // some optimizations expect AND and not UBFM. 23490b57cec5SDimitry Andric Opd0 = N->getOperand(0); 23500b57cec5SDimitry Andric } else 23510b57cec5SDimitry Andric return false; 23520b57cec5SDimitry Andric 23530b57cec5SDimitry Andric // Bail out on large immediates. This happens when no proper 23540b57cec5SDimitry Andric // combining/constant folding was performed. 23550b57cec5SDimitry Andric if (!BiggerPattern && (SrlImm <= 0 || SrlImm >= VT.getSizeInBits())) { 23560b57cec5SDimitry Andric LLVM_DEBUG( 23570b57cec5SDimitry Andric (dbgs() << N 23580b57cec5SDimitry Andric << ": Found large shift immediate, this should not happen\n")); 23590b57cec5SDimitry Andric return false; 23600b57cec5SDimitry Andric } 23610b57cec5SDimitry Andric 23620b57cec5SDimitry Andric LSB = SrlImm; 236306c3fb27SDimitry Andric MSB = SrlImm + 236406c3fb27SDimitry Andric (VT == MVT::i32 ? llvm::countr_one<uint32_t>(AndImm) 236506c3fb27SDimitry Andric : llvm::countr_one<uint64_t>(AndImm)) - 23660b57cec5SDimitry Andric 1; 23670b57cec5SDimitry Andric if (ClampMSB) 23680b57cec5SDimitry Andric // Since we're moving the extend before the right shift operation, we need 23690b57cec5SDimitry Andric // to clamp the MSB to make sure we don't shift in undefined bits instead of 23700b57cec5SDimitry Andric // the zeros which would get shifted in with the original right shift 23710b57cec5SDimitry Andric // operation. 23720b57cec5SDimitry Andric MSB = MSB > 31 ? 31 : MSB; 23730b57cec5SDimitry Andric 23740b57cec5SDimitry Andric Opc = VT == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri; 23750b57cec5SDimitry Andric return true; 23760b57cec5SDimitry Andric } 23770b57cec5SDimitry Andric 23780b57cec5SDimitry Andric static bool isBitfieldExtractOpFromSExtInReg(SDNode *N, unsigned &Opc, 23790b57cec5SDimitry Andric SDValue &Opd0, unsigned &Immr, 23800b57cec5SDimitry Andric unsigned &Imms) { 23810b57cec5SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND_INREG); 23820b57cec5SDimitry Andric 23830b57cec5SDimitry Andric EVT VT = N->getValueType(0); 23840b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 23850b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 23860b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 23870b57cec5SDimitry Andric 23880b57cec5SDimitry Andric SDValue Op = N->getOperand(0); 23890b57cec5SDimitry Andric if (Op->getOpcode() == ISD::TRUNCATE) { 23900b57cec5SDimitry Andric Op = Op->getOperand(0); 23910b57cec5SDimitry Andric VT = Op->getValueType(0); 23920b57cec5SDimitry Andric BitWidth = VT.getSizeInBits(); 23930b57cec5SDimitry Andric } 23940b57cec5SDimitry Andric 23950b57cec5SDimitry Andric uint64_t ShiftImm; 23960b57cec5SDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRL, ShiftImm) && 23970b57cec5SDimitry Andric !isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm)) 23980b57cec5SDimitry Andric return false; 23990b57cec5SDimitry Andric 24000b57cec5SDimitry Andric unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits(); 24010b57cec5SDimitry Andric if (ShiftImm + Width > BitWidth) 24020b57cec5SDimitry Andric return false; 24030b57cec5SDimitry Andric 24040b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::SBFMWri : AArch64::SBFMXri; 24050b57cec5SDimitry Andric Opd0 = Op.getOperand(0); 24060b57cec5SDimitry Andric Immr = ShiftImm; 24070b57cec5SDimitry Andric Imms = ShiftImm + Width - 1; 24080b57cec5SDimitry Andric return true; 24090b57cec5SDimitry Andric } 24100b57cec5SDimitry Andric 24110b57cec5SDimitry Andric static bool isSeveralBitsExtractOpFromShr(SDNode *N, unsigned &Opc, 24120b57cec5SDimitry Andric SDValue &Opd0, unsigned &LSB, 24130b57cec5SDimitry Andric unsigned &MSB) { 24140b57cec5SDimitry Andric // We are looking for the following pattern which basically extracts several 24150b57cec5SDimitry Andric // continuous bits from the source value and places it from the LSB of the 24160b57cec5SDimitry Andric // destination value, all other bits of the destination value or set to zero: 24170b57cec5SDimitry Andric // 24180b57cec5SDimitry Andric // Value2 = AND Value, MaskImm 24190b57cec5SDimitry Andric // SRL Value2, ShiftImm 24200b57cec5SDimitry Andric // 24210b57cec5SDimitry Andric // with MaskImm >> ShiftImm to search for the bit width. 24220b57cec5SDimitry Andric // 24230b57cec5SDimitry Andric // This gets selected into a single UBFM: 24240b57cec5SDimitry Andric // 242506c3fb27SDimitry Andric // UBFM Value, ShiftImm, Log2_64(MaskImm) 24260b57cec5SDimitry Andric // 24270b57cec5SDimitry Andric 24280b57cec5SDimitry Andric if (N->getOpcode() != ISD::SRL) 24290b57cec5SDimitry Andric return false; 24300b57cec5SDimitry Andric 24310b57cec5SDimitry Andric uint64_t AndMask = 0; 24320b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, AndMask)) 24330b57cec5SDimitry Andric return false; 24340b57cec5SDimitry Andric 24350b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 24360b57cec5SDimitry Andric 24370b57cec5SDimitry Andric uint64_t SrlImm = 0; 24380b57cec5SDimitry Andric if (!isIntImmediate(N->getOperand(1), SrlImm)) 24390b57cec5SDimitry Andric return false; 24400b57cec5SDimitry Andric 24410b57cec5SDimitry Andric // Check whether we really have several bits extract here. 2442bdd1243dSDimitry Andric if (!isMask_64(AndMask >> SrlImm)) 24430b57cec5SDimitry Andric return false; 2444bdd1243dSDimitry Andric 2445bdd1243dSDimitry Andric Opc = N->getValueType(0) == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri; 2446bdd1243dSDimitry Andric LSB = SrlImm; 244706c3fb27SDimitry Andric MSB = llvm::Log2_64(AndMask); 2448bdd1243dSDimitry Andric return true; 24490b57cec5SDimitry Andric } 24500b57cec5SDimitry Andric 24510b57cec5SDimitry Andric static bool isBitfieldExtractOpFromShr(SDNode *N, unsigned &Opc, SDValue &Opd0, 24520b57cec5SDimitry Andric unsigned &Immr, unsigned &Imms, 24530b57cec5SDimitry Andric bool BiggerPattern) { 24540b57cec5SDimitry Andric assert((N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL) && 24550b57cec5SDimitry Andric "N must be a SHR/SRA operation to call this function"); 24560b57cec5SDimitry Andric 24570b57cec5SDimitry Andric EVT VT = N->getValueType(0); 24580b57cec5SDimitry Andric 24590b57cec5SDimitry Andric // Here we can test the type of VT and return false when the type does not 24600b57cec5SDimitry Andric // match, but since it is done prior to that call in the current context 24610b57cec5SDimitry Andric // we turned that into an assert to avoid redundant code. 24620b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 24630b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 24640b57cec5SDimitry Andric 24650b57cec5SDimitry Andric // Check for AND + SRL doing several bits extract. 24660b57cec5SDimitry Andric if (isSeveralBitsExtractOpFromShr(N, Opc, Opd0, Immr, Imms)) 24670b57cec5SDimitry Andric return true; 24680b57cec5SDimitry Andric 24690b57cec5SDimitry Andric // We're looking for a shift of a shift. 24700b57cec5SDimitry Andric uint64_t ShlImm = 0; 24710b57cec5SDimitry Andric uint64_t TruncBits = 0; 24720b57cec5SDimitry Andric if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, ShlImm)) { 24730b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 24740b57cec5SDimitry Andric } else if (VT == MVT::i32 && N->getOpcode() == ISD::SRL && 24750b57cec5SDimitry Andric N->getOperand(0).getNode()->getOpcode() == ISD::TRUNCATE) { 24760b57cec5SDimitry Andric // We are looking for a shift of truncate. Truncate from i64 to i32 could 24770b57cec5SDimitry Andric // be considered as setting high 32 bits as zero. Our strategy here is to 24780b57cec5SDimitry Andric // always generate 64bit UBFM. This consistency will help the CSE pass 24790b57cec5SDimitry Andric // later find more redundancy. 24800b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 24810b57cec5SDimitry Andric TruncBits = Opd0->getValueType(0).getSizeInBits() - VT.getSizeInBits(); 24820b57cec5SDimitry Andric VT = Opd0.getValueType(); 24830b57cec5SDimitry Andric assert(VT == MVT::i64 && "the promoted type should be i64"); 24840b57cec5SDimitry Andric } else if (BiggerPattern) { 24850b57cec5SDimitry Andric // Let's pretend a 0 shift left has been performed. 24860b57cec5SDimitry Andric // FIXME: Currently we limit this to the bigger pattern case, 24870b57cec5SDimitry Andric // because some optimizations expect AND and not UBFM 24880b57cec5SDimitry Andric Opd0 = N->getOperand(0); 24890b57cec5SDimitry Andric } else 24900b57cec5SDimitry Andric return false; 24910b57cec5SDimitry Andric 24920b57cec5SDimitry Andric // Missing combines/constant folding may have left us with strange 24930b57cec5SDimitry Andric // constants. 24940b57cec5SDimitry Andric if (ShlImm >= VT.getSizeInBits()) { 24950b57cec5SDimitry Andric LLVM_DEBUG( 24960b57cec5SDimitry Andric (dbgs() << N 24970b57cec5SDimitry Andric << ": Found large shift immediate, this should not happen\n")); 24980b57cec5SDimitry Andric return false; 24990b57cec5SDimitry Andric } 25000b57cec5SDimitry Andric 25010b57cec5SDimitry Andric uint64_t SrlImm = 0; 25020b57cec5SDimitry Andric if (!isIntImmediate(N->getOperand(1), SrlImm)) 25030b57cec5SDimitry Andric return false; 25040b57cec5SDimitry Andric 25050b57cec5SDimitry Andric assert(SrlImm > 0 && SrlImm < VT.getSizeInBits() && 25060b57cec5SDimitry Andric "bad amount in shift node!"); 25070b57cec5SDimitry Andric int immr = SrlImm - ShlImm; 25080b57cec5SDimitry Andric Immr = immr < 0 ? immr + VT.getSizeInBits() : immr; 25090b57cec5SDimitry Andric Imms = VT.getSizeInBits() - ShlImm - TruncBits - 1; 25100b57cec5SDimitry Andric // SRA requires a signed extraction 25110b57cec5SDimitry Andric if (VT == MVT::i32) 25120b57cec5SDimitry Andric Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMWri : AArch64::UBFMWri; 25130b57cec5SDimitry Andric else 25140b57cec5SDimitry Andric Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMXri : AArch64::UBFMXri; 25150b57cec5SDimitry Andric return true; 25160b57cec5SDimitry Andric } 25170b57cec5SDimitry Andric 25180b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldExtractOpFromSExt(SDNode *N) { 25190b57cec5SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND); 25200b57cec5SDimitry Andric 25210b57cec5SDimitry Andric EVT VT = N->getValueType(0); 25220b57cec5SDimitry Andric EVT NarrowVT = N->getOperand(0)->getValueType(0); 25230b57cec5SDimitry Andric if (VT != MVT::i64 || NarrowVT != MVT::i32) 25240b57cec5SDimitry Andric return false; 25250b57cec5SDimitry Andric 25260b57cec5SDimitry Andric uint64_t ShiftImm; 25270b57cec5SDimitry Andric SDValue Op = N->getOperand(0); 25280b57cec5SDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm)) 25290b57cec5SDimitry Andric return false; 25300b57cec5SDimitry Andric 25310b57cec5SDimitry Andric SDLoc dl(N); 25320b57cec5SDimitry Andric // Extend the incoming operand of the shift to 64-bits. 25330b57cec5SDimitry Andric SDValue Opd0 = Widen(CurDAG, Op.getOperand(0)); 25340b57cec5SDimitry Andric unsigned Immr = ShiftImm; 25350b57cec5SDimitry Andric unsigned Imms = NarrowVT.getSizeInBits() - 1; 25360b57cec5SDimitry Andric SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT), 25370b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, VT)}; 25380b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, AArch64::SBFMXri, VT, Ops); 25390b57cec5SDimitry Andric return true; 25400b57cec5SDimitry Andric } 25410b57cec5SDimitry Andric 25420b57cec5SDimitry Andric static bool isBitfieldExtractOp(SelectionDAG *CurDAG, SDNode *N, unsigned &Opc, 25430b57cec5SDimitry Andric SDValue &Opd0, unsigned &Immr, unsigned &Imms, 25440b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits = 0, 25450b57cec5SDimitry Andric bool BiggerPattern = false) { 25460b57cec5SDimitry Andric if (N->getValueType(0) != MVT::i32 && N->getValueType(0) != MVT::i64) 25470b57cec5SDimitry Andric return false; 25480b57cec5SDimitry Andric 25490b57cec5SDimitry Andric switch (N->getOpcode()) { 25500b57cec5SDimitry Andric default: 25510b57cec5SDimitry Andric if (!N->isMachineOpcode()) 25520b57cec5SDimitry Andric return false; 25530b57cec5SDimitry Andric break; 25540b57cec5SDimitry Andric case ISD::AND: 25550b57cec5SDimitry Andric return isBitfieldExtractOpFromAnd(CurDAG, N, Opc, Opd0, Immr, Imms, 25560b57cec5SDimitry Andric NumberOfIgnoredLowBits, BiggerPattern); 25570b57cec5SDimitry Andric case ISD::SRL: 25580b57cec5SDimitry Andric case ISD::SRA: 25590b57cec5SDimitry Andric return isBitfieldExtractOpFromShr(N, Opc, Opd0, Immr, Imms, BiggerPattern); 25600b57cec5SDimitry Andric 25610b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 25620b57cec5SDimitry Andric return isBitfieldExtractOpFromSExtInReg(N, Opc, Opd0, Immr, Imms); 25630b57cec5SDimitry Andric } 25640b57cec5SDimitry Andric 25650b57cec5SDimitry Andric unsigned NOpc = N->getMachineOpcode(); 25660b57cec5SDimitry Andric switch (NOpc) { 25670b57cec5SDimitry Andric default: 25680b57cec5SDimitry Andric return false; 25690b57cec5SDimitry Andric case AArch64::SBFMWri: 25700b57cec5SDimitry Andric case AArch64::UBFMWri: 25710b57cec5SDimitry Andric case AArch64::SBFMXri: 25720b57cec5SDimitry Andric case AArch64::UBFMXri: 25730b57cec5SDimitry Andric Opc = NOpc; 25740b57cec5SDimitry Andric Opd0 = N->getOperand(0); 2575647cbc5dSDimitry Andric Immr = N->getConstantOperandVal(1); 2576647cbc5dSDimitry Andric Imms = N->getConstantOperandVal(2); 25770b57cec5SDimitry Andric return true; 25780b57cec5SDimitry Andric } 25790b57cec5SDimitry Andric // Unreachable 25800b57cec5SDimitry Andric return false; 25810b57cec5SDimitry Andric } 25820b57cec5SDimitry Andric 25830b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldExtractOp(SDNode *N) { 25840b57cec5SDimitry Andric unsigned Opc, Immr, Imms; 25850b57cec5SDimitry Andric SDValue Opd0; 25860b57cec5SDimitry Andric if (!isBitfieldExtractOp(CurDAG, N, Opc, Opd0, Immr, Imms)) 25870b57cec5SDimitry Andric return false; 25880b57cec5SDimitry Andric 25890b57cec5SDimitry Andric EVT VT = N->getValueType(0); 25900b57cec5SDimitry Andric SDLoc dl(N); 25910b57cec5SDimitry Andric 25920b57cec5SDimitry Andric // If the bit extract operation is 64bit but the original type is 32bit, we 25930b57cec5SDimitry Andric // need to add one EXTRACT_SUBREG. 25940b57cec5SDimitry Andric if ((Opc == AArch64::SBFMXri || Opc == AArch64::UBFMXri) && VT == MVT::i32) { 25950b57cec5SDimitry Andric SDValue Ops64[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, MVT::i64), 25960b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, MVT::i64)}; 25970b57cec5SDimitry Andric 25980b57cec5SDimitry Andric SDNode *BFM = CurDAG->getMachineNode(Opc, dl, MVT::i64, Ops64); 259906c3fb27SDimitry Andric SDValue Inner = CurDAG->getTargetExtractSubreg(AArch64::sub_32, dl, 260006c3fb27SDimitry Andric MVT::i32, SDValue(BFM, 0)); 260106c3fb27SDimitry Andric ReplaceNode(N, Inner.getNode()); 26020b57cec5SDimitry Andric return true; 26030b57cec5SDimitry Andric } 26040b57cec5SDimitry Andric 26050b57cec5SDimitry Andric SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT), 26060b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, VT)}; 26070b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 26080b57cec5SDimitry Andric return true; 26090b57cec5SDimitry Andric } 26100b57cec5SDimitry Andric 26110b57cec5SDimitry Andric /// Does DstMask form a complementary pair with the mask provided by 26120b57cec5SDimitry Andric /// BitsToBeInserted, suitable for use in a BFI instruction. Roughly speaking, 26130b57cec5SDimitry Andric /// this asks whether DstMask zeroes precisely those bits that will be set by 26140b57cec5SDimitry Andric /// the other half. 26150b57cec5SDimitry Andric static bool isBitfieldDstMask(uint64_t DstMask, const APInt &BitsToBeInserted, 26160b57cec5SDimitry Andric unsigned NumberOfIgnoredHighBits, EVT VT) { 26170b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 26180b57cec5SDimitry Andric "i32 or i64 mask type expected!"); 26190b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits() - NumberOfIgnoredHighBits; 26200b57cec5SDimitry Andric 26210b57cec5SDimitry Andric APInt SignificantDstMask = APInt(BitWidth, DstMask); 26220b57cec5SDimitry Andric APInt SignificantBitsToBeInserted = BitsToBeInserted.zextOrTrunc(BitWidth); 26230b57cec5SDimitry Andric 26240b57cec5SDimitry Andric return (SignificantDstMask & SignificantBitsToBeInserted) == 0 && 2625349cc55cSDimitry Andric (SignificantDstMask | SignificantBitsToBeInserted).isAllOnes(); 26260b57cec5SDimitry Andric } 26270b57cec5SDimitry Andric 26280b57cec5SDimitry Andric // Look for bits that will be useful for later uses. 26290b57cec5SDimitry Andric // A bit is consider useless as soon as it is dropped and never used 26300b57cec5SDimitry Andric // before it as been dropped. 26310b57cec5SDimitry Andric // E.g., looking for useful bit of x 26320b57cec5SDimitry Andric // 1. y = x & 0x7 26330b57cec5SDimitry Andric // 2. z = y >> 2 26340b57cec5SDimitry Andric // After #1, x useful bits are 0x7, then the useful bits of x, live through 26350b57cec5SDimitry Andric // y. 26360b57cec5SDimitry Andric // After #2, the useful bits of x are 0x4. 26370b57cec5SDimitry Andric // However, if x is used on an unpredicatable instruction, then all its bits 26380b57cec5SDimitry Andric // are useful. 26390b57cec5SDimitry Andric // E.g. 26400b57cec5SDimitry Andric // 1. y = x & 0x7 26410b57cec5SDimitry Andric // 2. z = y >> 2 26420b57cec5SDimitry Andric // 3. str x, [@x] 26430b57cec5SDimitry Andric static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth = 0); 26440b57cec5SDimitry Andric 26450b57cec5SDimitry Andric static void getUsefulBitsFromAndWithImmediate(SDValue Op, APInt &UsefulBits, 26460b57cec5SDimitry Andric unsigned Depth) { 26470b57cec5SDimitry Andric uint64_t Imm = 26480b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue(); 26490b57cec5SDimitry Andric Imm = AArch64_AM::decodeLogicalImmediate(Imm, UsefulBits.getBitWidth()); 26500b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), Imm); 26510b57cec5SDimitry Andric getUsefulBits(Op, UsefulBits, Depth + 1); 26520b57cec5SDimitry Andric } 26530b57cec5SDimitry Andric 26540b57cec5SDimitry Andric static void getUsefulBitsFromBitfieldMoveOpd(SDValue Op, APInt &UsefulBits, 26550b57cec5SDimitry Andric uint64_t Imm, uint64_t MSB, 26560b57cec5SDimitry Andric unsigned Depth) { 26570b57cec5SDimitry Andric // inherit the bitwidth value 26580b57cec5SDimitry Andric APInt OpUsefulBits(UsefulBits); 26590b57cec5SDimitry Andric OpUsefulBits = 1; 26600b57cec5SDimitry Andric 26610b57cec5SDimitry Andric if (MSB >= Imm) { 26620b57cec5SDimitry Andric OpUsefulBits <<= MSB - Imm + 1; 26630b57cec5SDimitry Andric --OpUsefulBits; 26640b57cec5SDimitry Andric // The interesting part will be in the lower part of the result 26650b57cec5SDimitry Andric getUsefulBits(Op, OpUsefulBits, Depth + 1); 26660b57cec5SDimitry Andric // The interesting part was starting at Imm in the argument 26670b57cec5SDimitry Andric OpUsefulBits <<= Imm; 26680b57cec5SDimitry Andric } else { 26690b57cec5SDimitry Andric OpUsefulBits <<= MSB + 1; 26700b57cec5SDimitry Andric --OpUsefulBits; 26710b57cec5SDimitry Andric // The interesting part will be shifted in the result 26720b57cec5SDimitry Andric OpUsefulBits <<= OpUsefulBits.getBitWidth() - Imm; 26730b57cec5SDimitry Andric getUsefulBits(Op, OpUsefulBits, Depth + 1); 26740b57cec5SDimitry Andric // The interesting part was at zero in the argument 26750b57cec5SDimitry Andric OpUsefulBits.lshrInPlace(OpUsefulBits.getBitWidth() - Imm); 26760b57cec5SDimitry Andric } 26770b57cec5SDimitry Andric 26780b57cec5SDimitry Andric UsefulBits &= OpUsefulBits; 26790b57cec5SDimitry Andric } 26800b57cec5SDimitry Andric 26810b57cec5SDimitry Andric static void getUsefulBitsFromUBFM(SDValue Op, APInt &UsefulBits, 26820b57cec5SDimitry Andric unsigned Depth) { 26830b57cec5SDimitry Andric uint64_t Imm = 26840b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue(); 26850b57cec5SDimitry Andric uint64_t MSB = 26860b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 26870b57cec5SDimitry Andric 26880b57cec5SDimitry Andric getUsefulBitsFromBitfieldMoveOpd(Op, UsefulBits, Imm, MSB, Depth); 26890b57cec5SDimitry Andric } 26900b57cec5SDimitry Andric 26910b57cec5SDimitry Andric static void getUsefulBitsFromOrWithShiftedReg(SDValue Op, APInt &UsefulBits, 26920b57cec5SDimitry Andric unsigned Depth) { 26930b57cec5SDimitry Andric uint64_t ShiftTypeAndValue = 26940b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 26950b57cec5SDimitry Andric APInt Mask(UsefulBits); 26960b57cec5SDimitry Andric Mask.clearAllBits(); 26970b57cec5SDimitry Andric Mask.flipAllBits(); 26980b57cec5SDimitry Andric 26990b57cec5SDimitry Andric if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSL) { 27000b57cec5SDimitry Andric // Shift Left 27010b57cec5SDimitry Andric uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue); 27020b57cec5SDimitry Andric Mask <<= ShiftAmt; 27030b57cec5SDimitry Andric getUsefulBits(Op, Mask, Depth + 1); 27040b57cec5SDimitry Andric Mask.lshrInPlace(ShiftAmt); 27050b57cec5SDimitry Andric } else if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSR) { 27060b57cec5SDimitry Andric // Shift Right 27070b57cec5SDimitry Andric // We do not handle AArch64_AM::ASR, because the sign will change the 27080b57cec5SDimitry Andric // number of useful bits 27090b57cec5SDimitry Andric uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue); 27100b57cec5SDimitry Andric Mask.lshrInPlace(ShiftAmt); 27110b57cec5SDimitry Andric getUsefulBits(Op, Mask, Depth + 1); 27120b57cec5SDimitry Andric Mask <<= ShiftAmt; 27130b57cec5SDimitry Andric } else 27140b57cec5SDimitry Andric return; 27150b57cec5SDimitry Andric 27160b57cec5SDimitry Andric UsefulBits &= Mask; 27170b57cec5SDimitry Andric } 27180b57cec5SDimitry Andric 27190b57cec5SDimitry Andric static void getUsefulBitsFromBFM(SDValue Op, SDValue Orig, APInt &UsefulBits, 27200b57cec5SDimitry Andric unsigned Depth) { 27210b57cec5SDimitry Andric uint64_t Imm = 27220b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 27230b57cec5SDimitry Andric uint64_t MSB = 27240b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(3).getNode())->getZExtValue(); 27250b57cec5SDimitry Andric 27260b57cec5SDimitry Andric APInt OpUsefulBits(UsefulBits); 27270b57cec5SDimitry Andric OpUsefulBits = 1; 27280b57cec5SDimitry Andric 27290b57cec5SDimitry Andric APInt ResultUsefulBits(UsefulBits.getBitWidth(), 0); 27300b57cec5SDimitry Andric ResultUsefulBits.flipAllBits(); 27310b57cec5SDimitry Andric APInt Mask(UsefulBits.getBitWidth(), 0); 27320b57cec5SDimitry Andric 27330b57cec5SDimitry Andric getUsefulBits(Op, ResultUsefulBits, Depth + 1); 27340b57cec5SDimitry Andric 27350b57cec5SDimitry Andric if (MSB >= Imm) { 27360b57cec5SDimitry Andric // The instruction is a BFXIL. 27370b57cec5SDimitry Andric uint64_t Width = MSB - Imm + 1; 27380b57cec5SDimitry Andric uint64_t LSB = Imm; 27390b57cec5SDimitry Andric 27400b57cec5SDimitry Andric OpUsefulBits <<= Width; 27410b57cec5SDimitry Andric --OpUsefulBits; 27420b57cec5SDimitry Andric 27430b57cec5SDimitry Andric if (Op.getOperand(1) == Orig) { 27440b57cec5SDimitry Andric // Copy the low bits from the result to bits starting from LSB. 27450b57cec5SDimitry Andric Mask = ResultUsefulBits & OpUsefulBits; 27460b57cec5SDimitry Andric Mask <<= LSB; 27470b57cec5SDimitry Andric } 27480b57cec5SDimitry Andric 27490b57cec5SDimitry Andric if (Op.getOperand(0) == Orig) 27500b57cec5SDimitry Andric // Bits starting from LSB in the input contribute to the result. 27510b57cec5SDimitry Andric Mask |= (ResultUsefulBits & ~OpUsefulBits); 27520b57cec5SDimitry Andric } else { 27530b57cec5SDimitry Andric // The instruction is a BFI. 27540b57cec5SDimitry Andric uint64_t Width = MSB + 1; 27550b57cec5SDimitry Andric uint64_t LSB = UsefulBits.getBitWidth() - Imm; 27560b57cec5SDimitry Andric 27570b57cec5SDimitry Andric OpUsefulBits <<= Width; 27580b57cec5SDimitry Andric --OpUsefulBits; 27590b57cec5SDimitry Andric OpUsefulBits <<= LSB; 27600b57cec5SDimitry Andric 27610b57cec5SDimitry Andric if (Op.getOperand(1) == Orig) { 27620b57cec5SDimitry Andric // Copy the bits from the result to the zero bits. 27630b57cec5SDimitry Andric Mask = ResultUsefulBits & OpUsefulBits; 27640b57cec5SDimitry Andric Mask.lshrInPlace(LSB); 27650b57cec5SDimitry Andric } 27660b57cec5SDimitry Andric 27670b57cec5SDimitry Andric if (Op.getOperand(0) == Orig) 27680b57cec5SDimitry Andric Mask |= (ResultUsefulBits & ~OpUsefulBits); 27690b57cec5SDimitry Andric } 27700b57cec5SDimitry Andric 27710b57cec5SDimitry Andric UsefulBits &= Mask; 27720b57cec5SDimitry Andric } 27730b57cec5SDimitry Andric 27740b57cec5SDimitry Andric static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits, 27750b57cec5SDimitry Andric SDValue Orig, unsigned Depth) { 27760b57cec5SDimitry Andric 27770b57cec5SDimitry Andric // Users of this node should have already been instruction selected 27780b57cec5SDimitry Andric // FIXME: Can we turn that into an assert? 27790b57cec5SDimitry Andric if (!UserNode->isMachineOpcode()) 27800b57cec5SDimitry Andric return; 27810b57cec5SDimitry Andric 27820b57cec5SDimitry Andric switch (UserNode->getMachineOpcode()) { 27830b57cec5SDimitry Andric default: 27840b57cec5SDimitry Andric return; 27850b57cec5SDimitry Andric case AArch64::ANDSWri: 27860b57cec5SDimitry Andric case AArch64::ANDSXri: 27870b57cec5SDimitry Andric case AArch64::ANDWri: 27880b57cec5SDimitry Andric case AArch64::ANDXri: 27890b57cec5SDimitry Andric // We increment Depth only when we call the getUsefulBits 27900b57cec5SDimitry Andric return getUsefulBitsFromAndWithImmediate(SDValue(UserNode, 0), UsefulBits, 27910b57cec5SDimitry Andric Depth); 27920b57cec5SDimitry Andric case AArch64::UBFMWri: 27930b57cec5SDimitry Andric case AArch64::UBFMXri: 27940b57cec5SDimitry Andric return getUsefulBitsFromUBFM(SDValue(UserNode, 0), UsefulBits, Depth); 27950b57cec5SDimitry Andric 27960b57cec5SDimitry Andric case AArch64::ORRWrs: 27970b57cec5SDimitry Andric case AArch64::ORRXrs: 2798fe6060f1SDimitry Andric if (UserNode->getOperand(0) != Orig && UserNode->getOperand(1) == Orig) 2799fe6060f1SDimitry Andric getUsefulBitsFromOrWithShiftedReg(SDValue(UserNode, 0), UsefulBits, 28000b57cec5SDimitry Andric Depth); 2801fe6060f1SDimitry Andric return; 28020b57cec5SDimitry Andric case AArch64::BFMWri: 28030b57cec5SDimitry Andric case AArch64::BFMXri: 28040b57cec5SDimitry Andric return getUsefulBitsFromBFM(SDValue(UserNode, 0), Orig, UsefulBits, Depth); 28050b57cec5SDimitry Andric 28060b57cec5SDimitry Andric case AArch64::STRBBui: 28070b57cec5SDimitry Andric case AArch64::STURBBi: 28080b57cec5SDimitry Andric if (UserNode->getOperand(0) != Orig) 28090b57cec5SDimitry Andric return; 28100b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xff); 28110b57cec5SDimitry Andric return; 28120b57cec5SDimitry Andric 28130b57cec5SDimitry Andric case AArch64::STRHHui: 28140b57cec5SDimitry Andric case AArch64::STURHHi: 28150b57cec5SDimitry Andric if (UserNode->getOperand(0) != Orig) 28160b57cec5SDimitry Andric return; 28170b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xffff); 28180b57cec5SDimitry Andric return; 28190b57cec5SDimitry Andric } 28200b57cec5SDimitry Andric } 28210b57cec5SDimitry Andric 28220b57cec5SDimitry Andric static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth) { 28238bcb0991SDimitry Andric if (Depth >= SelectionDAG::MaxRecursionDepth) 28240b57cec5SDimitry Andric return; 28250b57cec5SDimitry Andric // Initialize UsefulBits 28260b57cec5SDimitry Andric if (!Depth) { 28270b57cec5SDimitry Andric unsigned Bitwidth = Op.getScalarValueSizeInBits(); 28280b57cec5SDimitry Andric // At the beginning, assume every produced bits is useful 28290b57cec5SDimitry Andric UsefulBits = APInt(Bitwidth, 0); 28300b57cec5SDimitry Andric UsefulBits.flipAllBits(); 28310b57cec5SDimitry Andric } 28320b57cec5SDimitry Andric APInt UsersUsefulBits(UsefulBits.getBitWidth(), 0); 28330b57cec5SDimitry Andric 28340b57cec5SDimitry Andric for (SDNode *Node : Op.getNode()->uses()) { 28350b57cec5SDimitry Andric // A use cannot produce useful bits 28360b57cec5SDimitry Andric APInt UsefulBitsForUse = APInt(UsefulBits); 28370b57cec5SDimitry Andric getUsefulBitsForUse(Node, UsefulBitsForUse, Op, Depth); 28380b57cec5SDimitry Andric UsersUsefulBits |= UsefulBitsForUse; 28390b57cec5SDimitry Andric } 28400b57cec5SDimitry Andric // UsefulBits contains the produced bits that are meaningful for the 28410b57cec5SDimitry Andric // current definition, thus a user cannot make a bit meaningful at 28420b57cec5SDimitry Andric // this point 28430b57cec5SDimitry Andric UsefulBits &= UsersUsefulBits; 28440b57cec5SDimitry Andric } 28450b57cec5SDimitry Andric 28460b57cec5SDimitry Andric /// Create a machine node performing a notional SHL of Op by ShlAmount. If 28470b57cec5SDimitry Andric /// ShlAmount is negative, do a (logical) right-shift instead. If ShlAmount is 28480b57cec5SDimitry Andric /// 0, return Op unchanged. 28490b57cec5SDimitry Andric static SDValue getLeftShift(SelectionDAG *CurDAG, SDValue Op, int ShlAmount) { 28500b57cec5SDimitry Andric if (ShlAmount == 0) 28510b57cec5SDimitry Andric return Op; 28520b57cec5SDimitry Andric 28530b57cec5SDimitry Andric EVT VT = Op.getValueType(); 28540b57cec5SDimitry Andric SDLoc dl(Op); 28550b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 28560b57cec5SDimitry Andric unsigned UBFMOpc = BitWidth == 32 ? AArch64::UBFMWri : AArch64::UBFMXri; 28570b57cec5SDimitry Andric 28580b57cec5SDimitry Andric SDNode *ShiftNode; 28590b57cec5SDimitry Andric if (ShlAmount > 0) { 28600b57cec5SDimitry Andric // LSL wD, wN, #Amt == UBFM wD, wN, #32-Amt, #31-Amt 28610b57cec5SDimitry Andric ShiftNode = CurDAG->getMachineNode( 28620b57cec5SDimitry Andric UBFMOpc, dl, VT, Op, 28630b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - ShlAmount, dl, VT), 28640b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1 - ShlAmount, dl, VT)); 28650b57cec5SDimitry Andric } else { 28660b57cec5SDimitry Andric // LSR wD, wN, #Amt == UBFM wD, wN, #Amt, #32-1 28670b57cec5SDimitry Andric assert(ShlAmount < 0 && "expected right shift"); 28680b57cec5SDimitry Andric int ShrAmount = -ShlAmount; 28690b57cec5SDimitry Andric ShiftNode = CurDAG->getMachineNode( 28700b57cec5SDimitry Andric UBFMOpc, dl, VT, Op, CurDAG->getTargetConstant(ShrAmount, dl, VT), 28710b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1, dl, VT)); 28720b57cec5SDimitry Andric } 28730b57cec5SDimitry Andric 28740b57cec5SDimitry Andric return SDValue(ShiftNode, 0); 28750b57cec5SDimitry Andric } 28760b57cec5SDimitry Andric 2877bdd1243dSDimitry Andric // For bit-field-positioning pattern "(and (shl VAL, N), ShiftedMask)". 2878bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, 28790b57cec5SDimitry Andric bool BiggerPattern, 2880bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2881bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2882bdd1243dSDimitry Andric int &Width); 2883bdd1243dSDimitry Andric 2884bdd1243dSDimitry Andric // For bit-field-positioning pattern "shl VAL, N)". 2885bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, 2886bdd1243dSDimitry Andric bool BiggerPattern, 2887bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2888bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2889bdd1243dSDimitry Andric int &Width); 2890bdd1243dSDimitry Andric 2891bdd1243dSDimitry Andric /// Does this tree qualify as an attempt to move a bitfield into position, 2892bdd1243dSDimitry Andric /// essentially "(and (shl VAL, N), Mask)" or (shl VAL, N). 2893bdd1243dSDimitry Andric static bool isBitfieldPositioningOp(SelectionDAG *CurDAG, SDValue Op, 2894bdd1243dSDimitry Andric bool BiggerPattern, SDValue &Src, 2895bdd1243dSDimitry Andric int &DstLSB, int &Width) { 28960b57cec5SDimitry Andric EVT VT = Op.getValueType(); 28970b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 28980b57cec5SDimitry Andric (void)BitWidth; 28990b57cec5SDimitry Andric assert(BitWidth == 32 || BitWidth == 64); 29000b57cec5SDimitry Andric 29010b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(Op); 29020b57cec5SDimitry Andric 29030b57cec5SDimitry Andric // Non-zero in the sense that they're not provably zero, which is the key 29040b57cec5SDimitry Andric // point if we want to use this value 2905bdd1243dSDimitry Andric const uint64_t NonZeroBits = (~Known.Zero).getZExtValue(); 29060b57cec5SDimitry Andric if (!isShiftedMask_64(NonZeroBits)) 29070b57cec5SDimitry Andric return false; 29080b57cec5SDimitry Andric 2909bdd1243dSDimitry Andric switch (Op.getOpcode()) { 2910bdd1243dSDimitry Andric default: 2911bdd1243dSDimitry Andric break; 2912bdd1243dSDimitry Andric case ISD::AND: 2913bdd1243dSDimitry Andric return isBitfieldPositioningOpFromAnd(CurDAG, Op, BiggerPattern, 2914bdd1243dSDimitry Andric NonZeroBits, Src, DstLSB, Width); 2915bdd1243dSDimitry Andric case ISD::SHL: 2916bdd1243dSDimitry Andric return isBitfieldPositioningOpFromShl(CurDAG, Op, BiggerPattern, 2917bdd1243dSDimitry Andric NonZeroBits, Src, DstLSB, Width); 2918bdd1243dSDimitry Andric } 2919bdd1243dSDimitry Andric 2920bdd1243dSDimitry Andric return false; 2921bdd1243dSDimitry Andric } 2922bdd1243dSDimitry Andric 2923bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, 2924bdd1243dSDimitry Andric bool BiggerPattern, 2925bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2926bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2927bdd1243dSDimitry Andric int &Width) { 2928bdd1243dSDimitry Andric assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed"); 2929bdd1243dSDimitry Andric 2930bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 2931bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 2932bdd1243dSDimitry Andric "Caller guarantees VT is one of i32 or i64"); 2933bdd1243dSDimitry Andric (void)VT; 2934bdd1243dSDimitry Andric 2935bdd1243dSDimitry Andric uint64_t AndImm; 2936bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::AND, AndImm)) 2937bdd1243dSDimitry Andric return false; 2938bdd1243dSDimitry Andric 2939bdd1243dSDimitry Andric // If (~AndImm & NonZeroBits) is not zero at POS, we know that 2940bdd1243dSDimitry Andric // 1) (AndImm & (1 << POS) == 0) 2941bdd1243dSDimitry Andric // 2) the result of AND is not zero at POS bit (according to NonZeroBits) 2942bdd1243dSDimitry Andric // 2943bdd1243dSDimitry Andric // 1) and 2) don't agree so something must be wrong (e.g., in 2944bdd1243dSDimitry Andric // 'SelectionDAG::computeKnownBits') 2945bdd1243dSDimitry Andric assert((~AndImm & NonZeroBits) == 0 && 2946bdd1243dSDimitry Andric "Something must be wrong (e.g., in SelectionDAG::computeKnownBits)"); 2947bdd1243dSDimitry Andric 2948bdd1243dSDimitry Andric SDValue AndOp0 = Op.getOperand(0); 2949bdd1243dSDimitry Andric 2950bdd1243dSDimitry Andric uint64_t ShlImm; 2951bdd1243dSDimitry Andric SDValue ShlOp0; 2952bdd1243dSDimitry Andric if (isOpcWithIntImmediate(AndOp0.getNode(), ISD::SHL, ShlImm)) { 2953bdd1243dSDimitry Andric // For pattern "and(shl(val, N), shifted-mask)", 'ShlOp0' is set to 'val'. 2954bdd1243dSDimitry Andric ShlOp0 = AndOp0.getOperand(0); 2955bdd1243dSDimitry Andric } else if (VT == MVT::i64 && AndOp0.getOpcode() == ISD::ANY_EXTEND && 2956bdd1243dSDimitry Andric isOpcWithIntImmediate(AndOp0.getOperand(0).getNode(), ISD::SHL, 2957bdd1243dSDimitry Andric ShlImm)) { 2958bdd1243dSDimitry Andric // For pattern "and(any_extend(shl(val, N)), shifted-mask)" 2959bdd1243dSDimitry Andric 2960bdd1243dSDimitry Andric // ShlVal == shl(val, N), which is a left shift on a smaller type. 2961bdd1243dSDimitry Andric SDValue ShlVal = AndOp0.getOperand(0); 2962bdd1243dSDimitry Andric 2963bdd1243dSDimitry Andric // Since this is after type legalization and ShlVal is extended to MVT::i64, 2964bdd1243dSDimitry Andric // expect VT to be MVT::i32. 2965bdd1243dSDimitry Andric assert((ShlVal.getValueType() == MVT::i32) && "Expect VT to be MVT::i32."); 2966bdd1243dSDimitry Andric 2967bdd1243dSDimitry Andric // Widens 'val' to MVT::i64 as the source of bit field positioning. 2968bdd1243dSDimitry Andric ShlOp0 = Widen(CurDAG, ShlVal.getOperand(0)); 2969bdd1243dSDimitry Andric } else 2970bdd1243dSDimitry Andric return false; 2971bdd1243dSDimitry Andric 2972bdd1243dSDimitry Andric // For !BiggerPattern, bail out if the AndOp0 has more than one use, since 2973bdd1243dSDimitry Andric // then we'll end up generating AndOp0+UBFIZ instead of just keeping 2974bdd1243dSDimitry Andric // AndOp0+AND. 2975bdd1243dSDimitry Andric if (!BiggerPattern && !AndOp0.hasOneUse()) 2976bdd1243dSDimitry Andric return false; 2977bdd1243dSDimitry Andric 297806c3fb27SDimitry Andric DstLSB = llvm::countr_zero(NonZeroBits); 297906c3fb27SDimitry Andric Width = llvm::countr_one(NonZeroBits >> DstLSB); 2980bdd1243dSDimitry Andric 2981bdd1243dSDimitry Andric // Bail out on large Width. This happens when no proper combining / constant 2982bdd1243dSDimitry Andric // folding was performed. 2983bdd1243dSDimitry Andric if (Width >= (int)VT.getSizeInBits()) { 2984bdd1243dSDimitry Andric // If VT is i64, Width > 64 is insensible since NonZeroBits is uint64_t, and 2985bdd1243dSDimitry Andric // Width == 64 indicates a missed dag-combine from "(and val, AllOnes)" to 2986bdd1243dSDimitry Andric // "val". 2987bdd1243dSDimitry Andric // If VT is i32, what Width >= 32 means: 2988bdd1243dSDimitry Andric // - For "(and (any_extend(shl val, N)), shifted-mask)", the`and` Op 2989bdd1243dSDimitry Andric // demands at least 'Width' bits (after dag-combiner). This together with 2990bdd1243dSDimitry Andric // `any_extend` Op (undefined higher bits) indicates missed combination 2991bdd1243dSDimitry Andric // when lowering the 'and' IR instruction to an machine IR instruction. 2992bdd1243dSDimitry Andric LLVM_DEBUG( 2993bdd1243dSDimitry Andric dbgs() 2994bdd1243dSDimitry Andric << "Found large Width in bit-field-positioning -- this indicates no " 2995bdd1243dSDimitry Andric "proper combining / constant folding was performed\n"); 2996bdd1243dSDimitry Andric return false; 2997bdd1243dSDimitry Andric } 29980b57cec5SDimitry Andric 29990b57cec5SDimitry Andric // BFI encompasses sufficiently many nodes that it's worth inserting an extra 30000b57cec5SDimitry Andric // LSL/LSR if the mask in NonZeroBits doesn't quite match up with the ISD::SHL 30010b57cec5SDimitry Andric // amount. BiggerPattern is true when this pattern is being matched for BFI, 30020b57cec5SDimitry Andric // BiggerPattern is false when this pattern is being matched for UBFIZ, in 30030b57cec5SDimitry Andric // which case it is not profitable to insert an extra shift. 3004bdd1243dSDimitry Andric if (ShlImm != uint64_t(DstLSB) && !BiggerPattern) 30050b57cec5SDimitry Andric return false; 30060b57cec5SDimitry Andric 3007bdd1243dSDimitry Andric Src = getLeftShift(CurDAG, ShlOp0, ShlImm - DstLSB); 3008bdd1243dSDimitry Andric return true; 3009bdd1243dSDimitry Andric } 3010bdd1243dSDimitry Andric 3011bdd1243dSDimitry Andric // For node (shl (and val, mask), N)), returns true if the node is equivalent to 3012bdd1243dSDimitry Andric // UBFIZ. 3013bdd1243dSDimitry Andric static bool isSeveralBitsPositioningOpFromShl(const uint64_t ShlImm, SDValue Op, 3014bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 3015bdd1243dSDimitry Andric int &Width) { 3016bdd1243dSDimitry Andric // Caller should have verified that N is a left shift with constant shift 3017bdd1243dSDimitry Andric // amount; asserts that. 3018bdd1243dSDimitry Andric assert(Op.getOpcode() == ISD::SHL && 3019bdd1243dSDimitry Andric "Op.getNode() should be a SHL node to call this function"); 3020bdd1243dSDimitry Andric assert(isIntImmediateEq(Op.getOperand(1), ShlImm) && 3021bdd1243dSDimitry Andric "Op.getNode() should shift ShlImm to call this function"); 3022bdd1243dSDimitry Andric 3023bdd1243dSDimitry Andric uint64_t AndImm = 0; 3024bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 3025bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op0.getNode(), ISD::AND, AndImm)) 3026bdd1243dSDimitry Andric return false; 3027bdd1243dSDimitry Andric 3028bdd1243dSDimitry Andric const uint64_t ShiftedAndImm = ((AndImm << ShlImm) >> ShlImm); 3029bdd1243dSDimitry Andric if (isMask_64(ShiftedAndImm)) { 3030bdd1243dSDimitry Andric // AndImm is a superset of (AllOnes >> ShlImm); in other words, AndImm 3031bdd1243dSDimitry Andric // should end with Mask, and could be prefixed with random bits if those 3032bdd1243dSDimitry Andric // bits are shifted out. 3033bdd1243dSDimitry Andric // 3034bdd1243dSDimitry Andric // For example, xyz11111 (with {x,y,z} being 0 or 1) is fine if ShlImm >= 3; 3035bdd1243dSDimitry Andric // the AND result corresponding to those bits are shifted out, so it's fine 3036bdd1243dSDimitry Andric // to not extract them. 303706c3fb27SDimitry Andric Width = llvm::countr_one(ShiftedAndImm); 3038bdd1243dSDimitry Andric DstLSB = ShlImm; 3039bdd1243dSDimitry Andric Src = Op0.getOperand(0); 3040bdd1243dSDimitry Andric return true; 3041bdd1243dSDimitry Andric } 3042bdd1243dSDimitry Andric return false; 3043bdd1243dSDimitry Andric } 3044bdd1243dSDimitry Andric 3045bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, 3046bdd1243dSDimitry Andric bool BiggerPattern, 3047bdd1243dSDimitry Andric const uint64_t NonZeroBits, 3048bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 3049bdd1243dSDimitry Andric int &Width) { 3050bdd1243dSDimitry Andric assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed"); 3051bdd1243dSDimitry Andric 3052bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 3053bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3054bdd1243dSDimitry Andric "Caller guarantees that type is i32 or i64"); 3055bdd1243dSDimitry Andric (void)VT; 3056bdd1243dSDimitry Andric 3057bdd1243dSDimitry Andric uint64_t ShlImm; 3058bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SHL, ShlImm)) 3059bdd1243dSDimitry Andric return false; 3060bdd1243dSDimitry Andric 3061bdd1243dSDimitry Andric if (!BiggerPattern && !Op.hasOneUse()) 3062bdd1243dSDimitry Andric return false; 3063bdd1243dSDimitry Andric 3064bdd1243dSDimitry Andric if (isSeveralBitsPositioningOpFromShl(ShlImm, Op, Src, DstLSB, Width)) 3065bdd1243dSDimitry Andric return true; 3066bdd1243dSDimitry Andric 306706c3fb27SDimitry Andric DstLSB = llvm::countr_zero(NonZeroBits); 306806c3fb27SDimitry Andric Width = llvm::countr_one(NonZeroBits >> DstLSB); 3069bdd1243dSDimitry Andric 3070bdd1243dSDimitry Andric if (ShlImm != uint64_t(DstLSB) && !BiggerPattern) 3071bdd1243dSDimitry Andric return false; 3072bdd1243dSDimitry Andric 3073bdd1243dSDimitry Andric Src = getLeftShift(CurDAG, Op.getOperand(0), ShlImm - DstLSB); 30740b57cec5SDimitry Andric return true; 30750b57cec5SDimitry Andric } 30760b57cec5SDimitry Andric 30770b57cec5SDimitry Andric static bool isShiftedMask(uint64_t Mask, EVT VT) { 30780b57cec5SDimitry Andric assert(VT == MVT::i32 || VT == MVT::i64); 30790b57cec5SDimitry Andric if (VT == MVT::i32) 30800b57cec5SDimitry Andric return isShiftedMask_32(Mask); 30810b57cec5SDimitry Andric return isShiftedMask_64(Mask); 30820b57cec5SDimitry Andric } 30830b57cec5SDimitry Andric 30840b57cec5SDimitry Andric // Generate a BFI/BFXIL from 'or (and X, MaskImm), OrImm' iff the value being 30850b57cec5SDimitry Andric // inserted only sets known zero bits. 30860b57cec5SDimitry Andric static bool tryBitfieldInsertOpFromOrAndImm(SDNode *N, SelectionDAG *CurDAG) { 30870b57cec5SDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); 30880b57cec5SDimitry Andric 30890b57cec5SDimitry Andric EVT VT = N->getValueType(0); 30900b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 30910b57cec5SDimitry Andric return false; 30920b57cec5SDimitry Andric 30930b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 30940b57cec5SDimitry Andric 30950b57cec5SDimitry Andric uint64_t OrImm; 30960b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N, ISD::OR, OrImm)) 30970b57cec5SDimitry Andric return false; 30980b57cec5SDimitry Andric 30990b57cec5SDimitry Andric // Skip this transformation if the ORR immediate can be encoded in the ORR. 31000b57cec5SDimitry Andric // Otherwise, we'll trade an AND+ORR for ORR+BFI/BFXIL, which is most likely 31010b57cec5SDimitry Andric // performance neutral. 31020b57cec5SDimitry Andric if (AArch64_AM::isLogicalImmediate(OrImm, BitWidth)) 31030b57cec5SDimitry Andric return false; 31040b57cec5SDimitry Andric 31050b57cec5SDimitry Andric uint64_t MaskImm; 31060b57cec5SDimitry Andric SDValue And = N->getOperand(0); 31070b57cec5SDimitry Andric // Must be a single use AND with an immediate operand. 31080b57cec5SDimitry Andric if (!And.hasOneUse() || 31090b57cec5SDimitry Andric !isOpcWithIntImmediate(And.getNode(), ISD::AND, MaskImm)) 31100b57cec5SDimitry Andric return false; 31110b57cec5SDimitry Andric 31120b57cec5SDimitry Andric // Compute the Known Zero for the AND as this allows us to catch more general 31130b57cec5SDimitry Andric // cases than just looking for AND with imm. 31140b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(And); 31150b57cec5SDimitry Andric 31160b57cec5SDimitry Andric // Non-zero in the sense that they're not provably zero, which is the key 31170b57cec5SDimitry Andric // point if we want to use this value. 31180b57cec5SDimitry Andric uint64_t NotKnownZero = (~Known.Zero).getZExtValue(); 31190b57cec5SDimitry Andric 31200b57cec5SDimitry Andric // The KnownZero mask must be a shifted mask (e.g., 1110..011, 11100..00). 31210b57cec5SDimitry Andric if (!isShiftedMask(Known.Zero.getZExtValue(), VT)) 31220b57cec5SDimitry Andric return false; 31230b57cec5SDimitry Andric 31240b57cec5SDimitry Andric // The bits being inserted must only set those bits that are known to be zero. 31250b57cec5SDimitry Andric if ((OrImm & NotKnownZero) != 0) { 31260b57cec5SDimitry Andric // FIXME: It's okay if the OrImm sets NotKnownZero bits to 1, but we don't 31270b57cec5SDimitry Andric // currently handle this case. 31280b57cec5SDimitry Andric return false; 31290b57cec5SDimitry Andric } 31300b57cec5SDimitry Andric 31310b57cec5SDimitry Andric // BFI/BFXIL dst, src, #lsb, #width. 313206c3fb27SDimitry Andric int LSB = llvm::countr_one(NotKnownZero); 313306c3fb27SDimitry Andric int Width = BitWidth - APInt(BitWidth, NotKnownZero).popcount(); 31340b57cec5SDimitry Andric 31350b57cec5SDimitry Andric // BFI/BFXIL is an alias of BFM, so translate to BFM operands. 31360b57cec5SDimitry Andric unsigned ImmR = (BitWidth - LSB) % BitWidth; 31370b57cec5SDimitry Andric unsigned ImmS = Width - 1; 31380b57cec5SDimitry Andric 31390b57cec5SDimitry Andric // If we're creating a BFI instruction avoid cases where we need more 31400b57cec5SDimitry Andric // instructions to materialize the BFI constant as compared to the original 31410b57cec5SDimitry Andric // ORR. A BFXIL will use the same constant as the original ORR, so the code 31420b57cec5SDimitry Andric // should be no worse in this case. 31430b57cec5SDimitry Andric bool IsBFI = LSB != 0; 31440b57cec5SDimitry Andric uint64_t BFIImm = OrImm >> LSB; 31450b57cec5SDimitry Andric if (IsBFI && !AArch64_AM::isLogicalImmediate(BFIImm, BitWidth)) { 31460b57cec5SDimitry Andric // We have a BFI instruction and we know the constant can't be materialized 31470b57cec5SDimitry Andric // with a ORR-immediate with the zero register. 31480b57cec5SDimitry Andric unsigned OrChunks = 0, BFIChunks = 0; 31490b57cec5SDimitry Andric for (unsigned Shift = 0; Shift < BitWidth; Shift += 16) { 31500b57cec5SDimitry Andric if (((OrImm >> Shift) & 0xFFFF) != 0) 31510b57cec5SDimitry Andric ++OrChunks; 31520b57cec5SDimitry Andric if (((BFIImm >> Shift) & 0xFFFF) != 0) 31530b57cec5SDimitry Andric ++BFIChunks; 31540b57cec5SDimitry Andric } 31550b57cec5SDimitry Andric if (BFIChunks > OrChunks) 31560b57cec5SDimitry Andric return false; 31570b57cec5SDimitry Andric } 31580b57cec5SDimitry Andric 31590b57cec5SDimitry Andric // Materialize the constant to be inserted. 31600b57cec5SDimitry Andric SDLoc DL(N); 31610b57cec5SDimitry Andric unsigned MOVIOpc = VT == MVT::i32 ? AArch64::MOVi32imm : AArch64::MOVi64imm; 31620b57cec5SDimitry Andric SDNode *MOVI = CurDAG->getMachineNode( 31630b57cec5SDimitry Andric MOVIOpc, DL, VT, CurDAG->getTargetConstant(BFIImm, DL, VT)); 31640b57cec5SDimitry Andric 31650b57cec5SDimitry Andric // Create the BFI/BFXIL instruction. 31660b57cec5SDimitry Andric SDValue Ops[] = {And.getOperand(0), SDValue(MOVI, 0), 31670b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmR, DL, VT), 31680b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 31690b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 31700b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 31710b57cec5SDimitry Andric return true; 31720b57cec5SDimitry Andric } 31730b57cec5SDimitry Andric 3174bdd1243dSDimitry Andric static bool isWorthFoldingIntoOrrWithShift(SDValue Dst, SelectionDAG *CurDAG, 3175bdd1243dSDimitry Andric SDValue &ShiftedOperand, 3176bdd1243dSDimitry Andric uint64_t &EncodedShiftImm) { 3177bdd1243dSDimitry Andric // Avoid folding Dst into ORR-with-shift if Dst has other uses than ORR. 3178bdd1243dSDimitry Andric if (!Dst.hasOneUse()) 3179bdd1243dSDimitry Andric return false; 3180bdd1243dSDimitry Andric 3181bdd1243dSDimitry Andric EVT VT = Dst.getValueType(); 3182bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3183bdd1243dSDimitry Andric "Caller should guarantee that VT is one of i32 or i64"); 3184bdd1243dSDimitry Andric const unsigned SizeInBits = VT.getSizeInBits(); 3185bdd1243dSDimitry Andric 3186bdd1243dSDimitry Andric SDLoc DL(Dst.getNode()); 3187bdd1243dSDimitry Andric uint64_t AndImm, ShlImm; 3188bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::AND, AndImm) && 3189bdd1243dSDimitry Andric isShiftedMask_64(AndImm)) { 3190bdd1243dSDimitry Andric // Avoid transforming 'DstOp0' if it has other uses than the AND node. 3191bdd1243dSDimitry Andric SDValue DstOp0 = Dst.getOperand(0); 3192bdd1243dSDimitry Andric if (!DstOp0.hasOneUse()) 3193bdd1243dSDimitry Andric return false; 3194bdd1243dSDimitry Andric 3195bdd1243dSDimitry Andric // An example to illustrate the transformation 3196bdd1243dSDimitry Andric // From: 3197bdd1243dSDimitry Andric // lsr x8, x1, #1 3198bdd1243dSDimitry Andric // and x8, x8, #0x3f80 3199bdd1243dSDimitry Andric // bfxil x8, x1, #0, #7 3200bdd1243dSDimitry Andric // To: 3201bdd1243dSDimitry Andric // and x8, x23, #0x7f 3202bdd1243dSDimitry Andric // ubfx x9, x23, #8, #7 3203bdd1243dSDimitry Andric // orr x23, x8, x9, lsl #7 3204bdd1243dSDimitry Andric // 3205bdd1243dSDimitry Andric // The number of instructions remains the same, but ORR is faster than BFXIL 3206bdd1243dSDimitry Andric // on many AArch64 processors (or as good as BFXIL if not faster). Besides, 3207bdd1243dSDimitry Andric // the dependency chain is improved after the transformation. 3208bdd1243dSDimitry Andric uint64_t SrlImm; 3209bdd1243dSDimitry Andric if (isOpcWithIntImmediate(DstOp0.getNode(), ISD::SRL, SrlImm)) { 321006c3fb27SDimitry Andric uint64_t NumTrailingZeroInShiftedMask = llvm::countr_zero(AndImm); 3211bdd1243dSDimitry Andric if ((SrlImm + NumTrailingZeroInShiftedMask) < SizeInBits) { 3212bdd1243dSDimitry Andric unsigned MaskWidth = 321306c3fb27SDimitry Andric llvm::countr_one(AndImm >> NumTrailingZeroInShiftedMask); 3214bdd1243dSDimitry Andric unsigned UBFMOpc = 3215bdd1243dSDimitry Andric (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 3216bdd1243dSDimitry Andric SDNode *UBFMNode = CurDAG->getMachineNode( 3217bdd1243dSDimitry Andric UBFMOpc, DL, VT, DstOp0.getOperand(0), 3218bdd1243dSDimitry Andric CurDAG->getTargetConstant(SrlImm + NumTrailingZeroInShiftedMask, DL, 3219bdd1243dSDimitry Andric VT), 3220bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3221bdd1243dSDimitry Andric SrlImm + NumTrailingZeroInShiftedMask + MaskWidth - 1, DL, VT)); 3222bdd1243dSDimitry Andric ShiftedOperand = SDValue(UBFMNode, 0); 3223bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm( 3224bdd1243dSDimitry Andric AArch64_AM::LSL, NumTrailingZeroInShiftedMask); 3225bdd1243dSDimitry Andric return true; 3226bdd1243dSDimitry Andric } 3227bdd1243dSDimitry Andric } 3228bdd1243dSDimitry Andric return false; 3229bdd1243dSDimitry Andric } 3230bdd1243dSDimitry Andric 3231bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::SHL, ShlImm)) { 3232bdd1243dSDimitry Andric ShiftedOperand = Dst.getOperand(0); 3233bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm); 3234bdd1243dSDimitry Andric return true; 3235bdd1243dSDimitry Andric } 3236bdd1243dSDimitry Andric 3237bdd1243dSDimitry Andric uint64_t SrlImm; 3238bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::SRL, SrlImm)) { 3239bdd1243dSDimitry Andric ShiftedOperand = Dst.getOperand(0); 3240bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm); 3241bdd1243dSDimitry Andric return true; 3242bdd1243dSDimitry Andric } 3243bdd1243dSDimitry Andric return false; 3244bdd1243dSDimitry Andric } 3245bdd1243dSDimitry Andric 3246bdd1243dSDimitry Andric // Given an 'ISD::OR' node that is going to be selected as BFM, analyze 3247bdd1243dSDimitry Andric // the operands and select it to AArch64::ORR with shifted registers if 3248bdd1243dSDimitry Andric // that's more efficient. Returns true iff selection to AArch64::ORR happens. 3249bdd1243dSDimitry Andric static bool tryOrrWithShift(SDNode *N, SDValue OrOpd0, SDValue OrOpd1, 3250bdd1243dSDimitry Andric SDValue Src, SDValue Dst, SelectionDAG *CurDAG, 3251bdd1243dSDimitry Andric const bool BiggerPattern) { 3252bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 3253bdd1243dSDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect N to be an OR node"); 3254bdd1243dSDimitry Andric assert(((N->getOperand(0) == OrOpd0 && N->getOperand(1) == OrOpd1) || 3255bdd1243dSDimitry Andric (N->getOperand(1) == OrOpd0 && N->getOperand(0) == OrOpd1)) && 3256bdd1243dSDimitry Andric "Expect OrOpd0 and OrOpd1 to be operands of ISD::OR"); 3257bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3258bdd1243dSDimitry Andric "Expect result type to be i32 or i64 since N is combinable to BFM"); 3259bdd1243dSDimitry Andric SDLoc DL(N); 3260bdd1243dSDimitry Andric 3261bdd1243dSDimitry Andric // Bail out if BFM simplifies away one node in BFM Dst. 3262bdd1243dSDimitry Andric if (OrOpd1 != Dst) 3263bdd1243dSDimitry Andric return false; 3264bdd1243dSDimitry Andric 3265bdd1243dSDimitry Andric const unsigned OrrOpc = (VT == MVT::i32) ? AArch64::ORRWrs : AArch64::ORRXrs; 3266bdd1243dSDimitry Andric // For "BFM Rd, Rn, #immr, #imms", it's known that BFM simplifies away fewer 3267bdd1243dSDimitry Andric // nodes from Rn (or inserts additional shift node) if BiggerPattern is true. 3268bdd1243dSDimitry Andric if (BiggerPattern) { 3269bdd1243dSDimitry Andric uint64_t SrcAndImm; 3270bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::AND, SrcAndImm) && 3271bdd1243dSDimitry Andric isMask_64(SrcAndImm) && OrOpd0.getOperand(0) == Src) { 3272bdd1243dSDimitry Andric // OrOpd0 = AND Src, #Mask 3273bdd1243dSDimitry Andric // So BFM simplifies away one AND node from Src and doesn't simplify away 3274bdd1243dSDimitry Andric // nodes from Dst. If ORR with left-shifted operand also simplifies away 3275bdd1243dSDimitry Andric // one node (from Rd), ORR is better since it has higher throughput and 3276bdd1243dSDimitry Andric // smaller latency than BFM on many AArch64 processors (and for the rest 3277bdd1243dSDimitry Andric // ORR is at least as good as BFM). 3278bdd1243dSDimitry Andric SDValue ShiftedOperand; 3279bdd1243dSDimitry Andric uint64_t EncodedShiftImm; 3280bdd1243dSDimitry Andric if (isWorthFoldingIntoOrrWithShift(Dst, CurDAG, ShiftedOperand, 3281bdd1243dSDimitry Andric EncodedShiftImm)) { 3282bdd1243dSDimitry Andric SDValue Ops[] = {OrOpd0, ShiftedOperand, 3283bdd1243dSDimitry Andric CurDAG->getTargetConstant(EncodedShiftImm, DL, VT)}; 3284bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3285bdd1243dSDimitry Andric return true; 3286bdd1243dSDimitry Andric } 3287bdd1243dSDimitry Andric } 3288bdd1243dSDimitry Andric return false; 3289bdd1243dSDimitry Andric } 3290bdd1243dSDimitry Andric 3291bdd1243dSDimitry Andric assert((!BiggerPattern) && "BiggerPattern should be handled above"); 3292bdd1243dSDimitry Andric 3293bdd1243dSDimitry Andric uint64_t ShlImm; 3294bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SHL, ShlImm)) { 3295bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == Src && OrOpd0.hasOneUse()) { 3296bdd1243dSDimitry Andric SDValue Ops[] = { 3297bdd1243dSDimitry Andric Dst, Src, 3298bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3299bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm), DL, VT)}; 3300bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3301bdd1243dSDimitry Andric return true; 3302bdd1243dSDimitry Andric } 3303bdd1243dSDimitry Andric 3304bdd1243dSDimitry Andric // Select the following pattern to left-shifted operand rather than BFI. 3305bdd1243dSDimitry Andric // %val1 = op .. 3306bdd1243dSDimitry Andric // %val2 = shl %val1, #imm 3307bdd1243dSDimitry Andric // %res = or %val1, %val2 3308bdd1243dSDimitry Andric // 3309bdd1243dSDimitry Andric // If N is selected to be BFI, we know that 3310bdd1243dSDimitry Andric // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into 3311bdd1243dSDimitry Andric // BFI) 2) OrOpd1 would be the destination operand (i.e., preserved) 3312bdd1243dSDimitry Andric // 3313bdd1243dSDimitry Andric // Instead of selecting N to BFI, fold OrOpd0 as a left shift directly. 3314bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == OrOpd1) { 3315bdd1243dSDimitry Andric SDValue Ops[] = { 3316bdd1243dSDimitry Andric OrOpd1, OrOpd1, 3317bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3318bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm), DL, VT)}; 3319bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3320bdd1243dSDimitry Andric return true; 3321bdd1243dSDimitry Andric } 3322bdd1243dSDimitry Andric } 3323bdd1243dSDimitry Andric 3324bdd1243dSDimitry Andric uint64_t SrlImm; 3325bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SRL, SrlImm)) { 3326bdd1243dSDimitry Andric // Select the following pattern to right-shifted operand rather than BFXIL. 3327bdd1243dSDimitry Andric // %val1 = op .. 3328bdd1243dSDimitry Andric // %val2 = lshr %val1, #imm 3329bdd1243dSDimitry Andric // %res = or %val1, %val2 3330bdd1243dSDimitry Andric // 3331bdd1243dSDimitry Andric // If N is selected to be BFXIL, we know that 3332bdd1243dSDimitry Andric // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into 3333bdd1243dSDimitry Andric // BFXIL) 2) OrOpd1 would be the destination operand (i.e., preserved) 3334bdd1243dSDimitry Andric // 3335bdd1243dSDimitry Andric // Instead of selecting N to BFXIL, fold OrOpd0 as a right shift directly. 3336bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == OrOpd1) { 3337bdd1243dSDimitry Andric SDValue Ops[] = { 3338bdd1243dSDimitry Andric OrOpd1, OrOpd1, 3339bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3340bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm), DL, VT)}; 3341bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3342bdd1243dSDimitry Andric return true; 3343bdd1243dSDimitry Andric } 3344bdd1243dSDimitry Andric } 3345bdd1243dSDimitry Andric 3346bdd1243dSDimitry Andric return false; 3347bdd1243dSDimitry Andric } 3348bdd1243dSDimitry Andric 33490b57cec5SDimitry Andric static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits, 33500b57cec5SDimitry Andric SelectionDAG *CurDAG) { 33510b57cec5SDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); 33520b57cec5SDimitry Andric 33530b57cec5SDimitry Andric EVT VT = N->getValueType(0); 33540b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 33550b57cec5SDimitry Andric return false; 33560b57cec5SDimitry Andric 33570b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 33580b57cec5SDimitry Andric 33590b57cec5SDimitry Andric // Because of simplify-demanded-bits in DAGCombine, involved masks may not 33600b57cec5SDimitry Andric // have the expected shape. Try to undo that. 33610b57cec5SDimitry Andric 336206c3fb27SDimitry Andric unsigned NumberOfIgnoredLowBits = UsefulBits.countr_zero(); 336306c3fb27SDimitry Andric unsigned NumberOfIgnoredHighBits = UsefulBits.countl_zero(); 33640b57cec5SDimitry Andric 33650b57cec5SDimitry Andric // Given a OR operation, check if we have the following pattern 33660b57cec5SDimitry Andric // ubfm c, b, imm, imm2 (or something that does the same jobs, see 33670b57cec5SDimitry Andric // isBitfieldExtractOp) 33680b57cec5SDimitry Andric // d = e & mask2 ; where mask is a binary sequence of 1..10..0 and 33690b57cec5SDimitry Andric // countTrailingZeros(mask2) == imm2 - imm + 1 33700b57cec5SDimitry Andric // f = d | c 33710b57cec5SDimitry Andric // if yes, replace the OR instruction with: 33720b57cec5SDimitry Andric // f = BFM Opd0, Opd1, LSB, MSB ; where LSB = imm, and MSB = imm2 33730b57cec5SDimitry Andric 33740b57cec5SDimitry Andric // OR is commutative, check all combinations of operand order and values of 33750b57cec5SDimitry Andric // BiggerPattern, i.e. 33760b57cec5SDimitry Andric // Opd0, Opd1, BiggerPattern=false 33770b57cec5SDimitry Andric // Opd1, Opd0, BiggerPattern=false 33780b57cec5SDimitry Andric // Opd0, Opd1, BiggerPattern=true 33790b57cec5SDimitry Andric // Opd1, Opd0, BiggerPattern=true 33800b57cec5SDimitry Andric // Several of these combinations may match, so check with BiggerPattern=false 33810b57cec5SDimitry Andric // first since that will produce better results by matching more instructions 33820b57cec5SDimitry Andric // and/or inserting fewer extra instructions. 33830b57cec5SDimitry Andric for (int I = 0; I < 4; ++I) { 33840b57cec5SDimitry Andric 33850b57cec5SDimitry Andric SDValue Dst, Src; 33860b57cec5SDimitry Andric unsigned ImmR, ImmS; 33870b57cec5SDimitry Andric bool BiggerPattern = I / 2; 33880b57cec5SDimitry Andric SDValue OrOpd0Val = N->getOperand(I % 2); 33890b57cec5SDimitry Andric SDNode *OrOpd0 = OrOpd0Val.getNode(); 33900b57cec5SDimitry Andric SDValue OrOpd1Val = N->getOperand((I + 1) % 2); 33910b57cec5SDimitry Andric SDNode *OrOpd1 = OrOpd1Val.getNode(); 33920b57cec5SDimitry Andric 33930b57cec5SDimitry Andric unsigned BFXOpc; 33940b57cec5SDimitry Andric int DstLSB, Width; 33950b57cec5SDimitry Andric if (isBitfieldExtractOp(CurDAG, OrOpd0, BFXOpc, Src, ImmR, ImmS, 33960b57cec5SDimitry Andric NumberOfIgnoredLowBits, BiggerPattern)) { 33970b57cec5SDimitry Andric // Check that the returned opcode is compatible with the pattern, 33980b57cec5SDimitry Andric // i.e., same type and zero extended (U and not S) 33990b57cec5SDimitry Andric if ((BFXOpc != AArch64::UBFMXri && VT == MVT::i64) || 34000b57cec5SDimitry Andric (BFXOpc != AArch64::UBFMWri && VT == MVT::i32)) 34010b57cec5SDimitry Andric continue; 34020b57cec5SDimitry Andric 34030b57cec5SDimitry Andric // Compute the width of the bitfield insertion 34040b57cec5SDimitry Andric DstLSB = 0; 34050b57cec5SDimitry Andric Width = ImmS - ImmR + 1; 34060b57cec5SDimitry Andric // FIXME: This constraint is to catch bitfield insertion we may 34070b57cec5SDimitry Andric // want to widen the pattern if we want to grab general bitfied 34080b57cec5SDimitry Andric // move case 34090b57cec5SDimitry Andric if (Width <= 0) 34100b57cec5SDimitry Andric continue; 34110b57cec5SDimitry Andric 34120b57cec5SDimitry Andric // If the mask on the insertee is correct, we have a BFXIL operation. We 34130b57cec5SDimitry Andric // can share the ImmR and ImmS values from the already-computed UBFM. 34140b57cec5SDimitry Andric } else if (isBitfieldPositioningOp(CurDAG, OrOpd0Val, 34150b57cec5SDimitry Andric BiggerPattern, 34160b57cec5SDimitry Andric Src, DstLSB, Width)) { 34170b57cec5SDimitry Andric ImmR = (BitWidth - DstLSB) % BitWidth; 34180b57cec5SDimitry Andric ImmS = Width - 1; 34190b57cec5SDimitry Andric } else 34200b57cec5SDimitry Andric continue; 34210b57cec5SDimitry Andric 34220b57cec5SDimitry Andric // Check the second part of the pattern 34230b57cec5SDimitry Andric EVT VT = OrOpd1Val.getValueType(); 34240b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && "unexpected OR operand"); 34250b57cec5SDimitry Andric 34260b57cec5SDimitry Andric // Compute the Known Zero for the candidate of the first operand. 34270b57cec5SDimitry Andric // This allows to catch more general case than just looking for 34280b57cec5SDimitry Andric // AND with imm. Indeed, simplify-demanded-bits may have removed 34290b57cec5SDimitry Andric // the AND instruction because it proves it was useless. 34300b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(OrOpd1Val); 34310b57cec5SDimitry Andric 34320b57cec5SDimitry Andric // Check if there is enough room for the second operand to appear 34330b57cec5SDimitry Andric // in the first one 34340b57cec5SDimitry Andric APInt BitsToBeInserted = 34350b57cec5SDimitry Andric APInt::getBitsSet(Known.getBitWidth(), DstLSB, DstLSB + Width); 34360b57cec5SDimitry Andric 34370b57cec5SDimitry Andric if ((BitsToBeInserted & ~Known.Zero) != 0) 34380b57cec5SDimitry Andric continue; 34390b57cec5SDimitry Andric 34400b57cec5SDimitry Andric // Set the first operand 34410b57cec5SDimitry Andric uint64_t Imm; 34420b57cec5SDimitry Andric if (isOpcWithIntImmediate(OrOpd1, ISD::AND, Imm) && 34430b57cec5SDimitry Andric isBitfieldDstMask(Imm, BitsToBeInserted, NumberOfIgnoredHighBits, VT)) 34440b57cec5SDimitry Andric // In that case, we can eliminate the AND 34450b57cec5SDimitry Andric Dst = OrOpd1->getOperand(0); 34460b57cec5SDimitry Andric else 34470b57cec5SDimitry Andric // Maybe the AND has been removed by simplify-demanded-bits 34480b57cec5SDimitry Andric // or is useful because it discards more bits 34490b57cec5SDimitry Andric Dst = OrOpd1Val; 34500b57cec5SDimitry Andric 3451bdd1243dSDimitry Andric // Before selecting ISD::OR node to AArch64::BFM, see if an AArch64::ORR 3452bdd1243dSDimitry Andric // with shifted operand is more efficient. 3453bdd1243dSDimitry Andric if (tryOrrWithShift(N, OrOpd0Val, OrOpd1Val, Src, Dst, CurDAG, 3454bdd1243dSDimitry Andric BiggerPattern)) 3455bdd1243dSDimitry Andric return true; 3456bdd1243dSDimitry Andric 34570b57cec5SDimitry Andric // both parts match 34580b57cec5SDimitry Andric SDLoc DL(N); 34590b57cec5SDimitry Andric SDValue Ops[] = {Dst, Src, CurDAG->getTargetConstant(ImmR, DL, VT), 34600b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 34610b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 34620b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 34630b57cec5SDimitry Andric return true; 34640b57cec5SDimitry Andric } 34650b57cec5SDimitry Andric 34660b57cec5SDimitry Andric // Generate a BFXIL from 'or (and X, Mask0Imm), (and Y, Mask1Imm)' iff 34670b57cec5SDimitry Andric // Mask0Imm and ~Mask1Imm are equivalent and one of the MaskImms is a shifted 34680b57cec5SDimitry Andric // mask (e.g., 0x000ffff0). 34690b57cec5SDimitry Andric uint64_t Mask0Imm, Mask1Imm; 34700b57cec5SDimitry Andric SDValue And0 = N->getOperand(0); 34710b57cec5SDimitry Andric SDValue And1 = N->getOperand(1); 34720b57cec5SDimitry Andric if (And0.hasOneUse() && And1.hasOneUse() && 34730b57cec5SDimitry Andric isOpcWithIntImmediate(And0.getNode(), ISD::AND, Mask0Imm) && 34740b57cec5SDimitry Andric isOpcWithIntImmediate(And1.getNode(), ISD::AND, Mask1Imm) && 34750b57cec5SDimitry Andric APInt(BitWidth, Mask0Imm) == ~APInt(BitWidth, Mask1Imm) && 34760b57cec5SDimitry Andric (isShiftedMask(Mask0Imm, VT) || isShiftedMask(Mask1Imm, VT))) { 34770b57cec5SDimitry Andric 34780b57cec5SDimitry Andric // ORR is commutative, so canonicalize to the form 'or (and X, Mask0Imm), 34790b57cec5SDimitry Andric // (and Y, Mask1Imm)' where Mask1Imm is the shifted mask masking off the 34800b57cec5SDimitry Andric // bits to be inserted. 34810b57cec5SDimitry Andric if (isShiftedMask(Mask0Imm, VT)) { 34820b57cec5SDimitry Andric std::swap(And0, And1); 34830b57cec5SDimitry Andric std::swap(Mask0Imm, Mask1Imm); 34840b57cec5SDimitry Andric } 34850b57cec5SDimitry Andric 34860b57cec5SDimitry Andric SDValue Src = And1->getOperand(0); 34870b57cec5SDimitry Andric SDValue Dst = And0->getOperand(0); 348806c3fb27SDimitry Andric unsigned LSB = llvm::countr_zero(Mask1Imm); 348906c3fb27SDimitry Andric int Width = BitWidth - APInt(BitWidth, Mask0Imm).popcount(); 34900b57cec5SDimitry Andric 34910b57cec5SDimitry Andric // The BFXIL inserts the low-order bits from a source register, so right 34920b57cec5SDimitry Andric // shift the needed bits into place. 34930b57cec5SDimitry Andric SDLoc DL(N); 34940b57cec5SDimitry Andric unsigned ShiftOpc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 349581ad6265SDimitry Andric uint64_t LsrImm = LSB; 349681ad6265SDimitry Andric if (Src->hasOneUse() && 349781ad6265SDimitry Andric isOpcWithIntImmediate(Src.getNode(), ISD::SRL, LsrImm) && 349881ad6265SDimitry Andric (LsrImm + LSB) < BitWidth) { 349981ad6265SDimitry Andric Src = Src->getOperand(0); 350081ad6265SDimitry Andric LsrImm += LSB; 350181ad6265SDimitry Andric } 350281ad6265SDimitry Andric 35030b57cec5SDimitry Andric SDNode *LSR = CurDAG->getMachineNode( 350481ad6265SDimitry Andric ShiftOpc, DL, VT, Src, CurDAG->getTargetConstant(LsrImm, DL, VT), 35050b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1, DL, VT)); 35060b57cec5SDimitry Andric 35070b57cec5SDimitry Andric // BFXIL is an alias of BFM, so translate to BFM operands. 35080b57cec5SDimitry Andric unsigned ImmR = (BitWidth - LSB) % BitWidth; 35090b57cec5SDimitry Andric unsigned ImmS = Width - 1; 35100b57cec5SDimitry Andric 35110b57cec5SDimitry Andric // Create the BFXIL instruction. 35120b57cec5SDimitry Andric SDValue Ops[] = {Dst, SDValue(LSR, 0), 35130b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmR, DL, VT), 35140b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 35150b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 35160b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 35170b57cec5SDimitry Andric return true; 35180b57cec5SDimitry Andric } 35190b57cec5SDimitry Andric 35200b57cec5SDimitry Andric return false; 35210b57cec5SDimitry Andric } 35220b57cec5SDimitry Andric 35230b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) { 35240b57cec5SDimitry Andric if (N->getOpcode() != ISD::OR) 35250b57cec5SDimitry Andric return false; 35260b57cec5SDimitry Andric 35270b57cec5SDimitry Andric APInt NUsefulBits; 35280b57cec5SDimitry Andric getUsefulBits(SDValue(N, 0), NUsefulBits); 35290b57cec5SDimitry Andric 35300b57cec5SDimitry Andric // If all bits are not useful, just return UNDEF. 35310b57cec5SDimitry Andric if (!NUsefulBits) { 35320b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); 35330b57cec5SDimitry Andric return true; 35340b57cec5SDimitry Andric } 35350b57cec5SDimitry Andric 35360b57cec5SDimitry Andric if (tryBitfieldInsertOpFromOr(N, NUsefulBits, CurDAG)) 35370b57cec5SDimitry Andric return true; 35380b57cec5SDimitry Andric 35390b57cec5SDimitry Andric return tryBitfieldInsertOpFromOrAndImm(N, CurDAG); 35400b57cec5SDimitry Andric } 35410b57cec5SDimitry Andric 35420b57cec5SDimitry Andric /// SelectBitfieldInsertInZeroOp - Match a UBFIZ instruction that is the 35430b57cec5SDimitry Andric /// equivalent of a left shift by a constant amount followed by an and masking 35440b57cec5SDimitry Andric /// out a contiguous set of bits. 35450b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldInsertInZeroOp(SDNode *N) { 35460b57cec5SDimitry Andric if (N->getOpcode() != ISD::AND) 35470b57cec5SDimitry Andric return false; 35480b57cec5SDimitry Andric 35490b57cec5SDimitry Andric EVT VT = N->getValueType(0); 35500b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 35510b57cec5SDimitry Andric return false; 35520b57cec5SDimitry Andric 35530b57cec5SDimitry Andric SDValue Op0; 35540b57cec5SDimitry Andric int DstLSB, Width; 35550b57cec5SDimitry Andric if (!isBitfieldPositioningOp(CurDAG, SDValue(N, 0), /*BiggerPattern=*/false, 35560b57cec5SDimitry Andric Op0, DstLSB, Width)) 35570b57cec5SDimitry Andric return false; 35580b57cec5SDimitry Andric 35590b57cec5SDimitry Andric // ImmR is the rotate right amount. 35600b57cec5SDimitry Andric unsigned ImmR = (VT.getSizeInBits() - DstLSB) % VT.getSizeInBits(); 35610b57cec5SDimitry Andric // ImmS is the most significant bit of the source to be moved. 35620b57cec5SDimitry Andric unsigned ImmS = Width - 1; 35630b57cec5SDimitry Andric 35640b57cec5SDimitry Andric SDLoc DL(N); 35650b57cec5SDimitry Andric SDValue Ops[] = {Op0, CurDAG->getTargetConstant(ImmR, DL, VT), 35660b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 35670b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 35680b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 35690b57cec5SDimitry Andric return true; 35700b57cec5SDimitry Andric } 35710b57cec5SDimitry Andric 35720b57cec5SDimitry Andric /// tryShiftAmountMod - Take advantage of built-in mod of shift amount in 35730b57cec5SDimitry Andric /// variable shift/rotate instructions. 35740b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryShiftAmountMod(SDNode *N) { 35750b57cec5SDimitry Andric EVT VT = N->getValueType(0); 35760b57cec5SDimitry Andric 35770b57cec5SDimitry Andric unsigned Opc; 35780b57cec5SDimitry Andric switch (N->getOpcode()) { 35790b57cec5SDimitry Andric case ISD::ROTR: 35800b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::RORVWr : AArch64::RORVXr; 35810b57cec5SDimitry Andric break; 35820b57cec5SDimitry Andric case ISD::SHL: 35830b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::LSLVWr : AArch64::LSLVXr; 35840b57cec5SDimitry Andric break; 35850b57cec5SDimitry Andric case ISD::SRL: 35860b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::LSRVWr : AArch64::LSRVXr; 35870b57cec5SDimitry Andric break; 35880b57cec5SDimitry Andric case ISD::SRA: 35890b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::ASRVWr : AArch64::ASRVXr; 35900b57cec5SDimitry Andric break; 35910b57cec5SDimitry Andric default: 35920b57cec5SDimitry Andric return false; 35930b57cec5SDimitry Andric } 35940b57cec5SDimitry Andric 35950b57cec5SDimitry Andric uint64_t Size; 35960b57cec5SDimitry Andric uint64_t Bits; 35970b57cec5SDimitry Andric if (VT == MVT::i32) { 35980b57cec5SDimitry Andric Bits = 5; 35990b57cec5SDimitry Andric Size = 32; 36000b57cec5SDimitry Andric } else if (VT == MVT::i64) { 36010b57cec5SDimitry Andric Bits = 6; 36020b57cec5SDimitry Andric Size = 64; 36030b57cec5SDimitry Andric } else 36040b57cec5SDimitry Andric return false; 36050b57cec5SDimitry Andric 36060b57cec5SDimitry Andric SDValue ShiftAmt = N->getOperand(1); 36070b57cec5SDimitry Andric SDLoc DL(N); 36080b57cec5SDimitry Andric SDValue NewShiftAmt; 36090b57cec5SDimitry Andric 36100b57cec5SDimitry Andric // Skip over an extend of the shift amount. 36110b57cec5SDimitry Andric if (ShiftAmt->getOpcode() == ISD::ZERO_EXTEND || 36120b57cec5SDimitry Andric ShiftAmt->getOpcode() == ISD::ANY_EXTEND) 36130b57cec5SDimitry Andric ShiftAmt = ShiftAmt->getOperand(0); 36140b57cec5SDimitry Andric 36150b57cec5SDimitry Andric if (ShiftAmt->getOpcode() == ISD::ADD || ShiftAmt->getOpcode() == ISD::SUB) { 36160b57cec5SDimitry Andric SDValue Add0 = ShiftAmt->getOperand(0); 36170b57cec5SDimitry Andric SDValue Add1 = ShiftAmt->getOperand(1); 36180b57cec5SDimitry Andric uint64_t Add0Imm; 36190b57cec5SDimitry Andric uint64_t Add1Imm; 362081ad6265SDimitry Andric if (isIntImmediate(Add1, Add1Imm) && (Add1Imm % Size == 0)) { 36210b57cec5SDimitry Andric // If we are shifting by X+/-N where N == 0 mod Size, then just shift by X 36220b57cec5SDimitry Andric // to avoid the ADD/SUB. 36230b57cec5SDimitry Andric NewShiftAmt = Add0; 362481ad6265SDimitry Andric } else if (ShiftAmt->getOpcode() == ISD::SUB && 36250b57cec5SDimitry Andric isIntImmediate(Add0, Add0Imm) && Add0Imm != 0 && 36260b57cec5SDimitry Andric (Add0Imm % Size == 0)) { 362781ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X 362881ad6265SDimitry Andric // to generate a NEG instead of a SUB from a constant. 36290b57cec5SDimitry Andric unsigned NegOpc; 36300b57cec5SDimitry Andric unsigned ZeroReg; 36310b57cec5SDimitry Andric EVT SubVT = ShiftAmt->getValueType(0); 36320b57cec5SDimitry Andric if (SubVT == MVT::i32) { 36330b57cec5SDimitry Andric NegOpc = AArch64::SUBWrr; 36340b57cec5SDimitry Andric ZeroReg = AArch64::WZR; 36350b57cec5SDimitry Andric } else { 36360b57cec5SDimitry Andric assert(SubVT == MVT::i64); 36370b57cec5SDimitry Andric NegOpc = AArch64::SUBXrr; 36380b57cec5SDimitry Andric ZeroReg = AArch64::XZR; 36390b57cec5SDimitry Andric } 36400b57cec5SDimitry Andric SDValue Zero = 36410b57cec5SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT); 36420b57cec5SDimitry Andric MachineSDNode *Neg = 36430b57cec5SDimitry Andric CurDAG->getMachineNode(NegOpc, DL, SubVT, Zero, Add1); 36440b57cec5SDimitry Andric NewShiftAmt = SDValue(Neg, 0); 364581ad6265SDimitry Andric } else if (ShiftAmt->getOpcode() == ISD::SUB && 364681ad6265SDimitry Andric isIntImmediate(Add0, Add0Imm) && (Add0Imm % Size == Size - 1)) { 364781ad6265SDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 364881ad6265SDimitry Andric // to generate a NOT instead of a SUB from a constant. 364981ad6265SDimitry Andric unsigned NotOpc; 365081ad6265SDimitry Andric unsigned ZeroReg; 365181ad6265SDimitry Andric EVT SubVT = ShiftAmt->getValueType(0); 365281ad6265SDimitry Andric if (SubVT == MVT::i32) { 365381ad6265SDimitry Andric NotOpc = AArch64::ORNWrr; 365481ad6265SDimitry Andric ZeroReg = AArch64::WZR; 365581ad6265SDimitry Andric } else { 365681ad6265SDimitry Andric assert(SubVT == MVT::i64); 365781ad6265SDimitry Andric NotOpc = AArch64::ORNXrr; 365881ad6265SDimitry Andric ZeroReg = AArch64::XZR; 365981ad6265SDimitry Andric } 366081ad6265SDimitry Andric SDValue Zero = 366181ad6265SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT); 366281ad6265SDimitry Andric MachineSDNode *Not = 366381ad6265SDimitry Andric CurDAG->getMachineNode(NotOpc, DL, SubVT, Zero, Add1); 366481ad6265SDimitry Andric NewShiftAmt = SDValue(Not, 0); 36650b57cec5SDimitry Andric } else 36660b57cec5SDimitry Andric return false; 36670b57cec5SDimitry Andric } else { 36680b57cec5SDimitry Andric // If the shift amount is masked with an AND, check that the mask covers the 36690b57cec5SDimitry Andric // bits that are implicitly ANDed off by the above opcodes and if so, skip 36700b57cec5SDimitry Andric // the AND. 36710b57cec5SDimitry Andric uint64_t MaskImm; 36725ffd83dbSDimitry Andric if (!isOpcWithIntImmediate(ShiftAmt.getNode(), ISD::AND, MaskImm) && 36735ffd83dbSDimitry Andric !isOpcWithIntImmediate(ShiftAmt.getNode(), AArch64ISD::ANDS, MaskImm)) 36740b57cec5SDimitry Andric return false; 36750b57cec5SDimitry Andric 367606c3fb27SDimitry Andric if ((unsigned)llvm::countr_one(MaskImm) < Bits) 36770b57cec5SDimitry Andric return false; 36780b57cec5SDimitry Andric 36790b57cec5SDimitry Andric NewShiftAmt = ShiftAmt->getOperand(0); 36800b57cec5SDimitry Andric } 36810b57cec5SDimitry Andric 36820b57cec5SDimitry Andric // Narrow/widen the shift amount to match the size of the shift operation. 36830b57cec5SDimitry Andric if (VT == MVT::i32) 36840b57cec5SDimitry Andric NewShiftAmt = narrowIfNeeded(CurDAG, NewShiftAmt); 36850b57cec5SDimitry Andric else if (VT == MVT::i64 && NewShiftAmt->getValueType(0) == MVT::i32) { 36860b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, DL, MVT::i32); 36870b57cec5SDimitry Andric MachineSDNode *Ext = CurDAG->getMachineNode( 36880b57cec5SDimitry Andric AArch64::SUBREG_TO_REG, DL, VT, 36890b57cec5SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i64), NewShiftAmt, SubReg); 36900b57cec5SDimitry Andric NewShiftAmt = SDValue(Ext, 0); 36910b57cec5SDimitry Andric } 36920b57cec5SDimitry Andric 36930b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(0), NewShiftAmt}; 36940b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 36950b57cec5SDimitry Andric return true; 36960b57cec5SDimitry Andric } 36970b57cec5SDimitry Andric 36985f757f3fSDimitry Andric static bool checkCVTFixedPointOperandWithFBits(SelectionDAG *CurDAG, SDValue N, 36995f757f3fSDimitry Andric SDValue &FixedPos, 37005f757f3fSDimitry Andric unsigned RegWidth, 37015f757f3fSDimitry Andric bool isReciprocal) { 37020b57cec5SDimitry Andric APFloat FVal(0.0); 37030b57cec5SDimitry Andric if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N)) 37040b57cec5SDimitry Andric FVal = CN->getValueAPF(); 37050b57cec5SDimitry Andric else if (LoadSDNode *LN = dyn_cast<LoadSDNode>(N)) { 37060b57cec5SDimitry Andric // Some otherwise illegal constants are allowed in this case. 37070b57cec5SDimitry Andric if (LN->getOperand(1).getOpcode() != AArch64ISD::ADDlow || 37080b57cec5SDimitry Andric !isa<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1))) 37090b57cec5SDimitry Andric return false; 37100b57cec5SDimitry Andric 37110b57cec5SDimitry Andric ConstantPoolSDNode *CN = 37120b57cec5SDimitry Andric dyn_cast<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1)); 37130b57cec5SDimitry Andric FVal = cast<ConstantFP>(CN->getConstVal())->getValueAPF(); 37140b57cec5SDimitry Andric } else 37150b57cec5SDimitry Andric return false; 37160b57cec5SDimitry Andric 37170b57cec5SDimitry Andric // An FCVT[SU] instruction performs: convertToInt(Val * 2^fbits) where fbits 37180b57cec5SDimitry Andric // is between 1 and 32 for a destination w-register, or 1 and 64 for an 37190b57cec5SDimitry Andric // x-register. 37200b57cec5SDimitry Andric // 37210b57cec5SDimitry Andric // By this stage, we've detected (fp_to_[su]int (fmul Val, THIS_NODE)) so we 37220b57cec5SDimitry Andric // want THIS_NODE to be 2^fbits. This is much easier to deal with using 37230b57cec5SDimitry Andric // integers. 37240b57cec5SDimitry Andric bool IsExact; 37250b57cec5SDimitry Andric 37265f757f3fSDimitry Andric if (isReciprocal) 37275f757f3fSDimitry Andric if (!FVal.getExactInverse(&FVal)) 37285f757f3fSDimitry Andric return false; 37295f757f3fSDimitry Andric 37300b57cec5SDimitry Andric // fbits is between 1 and 64 in the worst-case, which means the fmul 37310b57cec5SDimitry Andric // could have 2^64 as an actual operand. Need 65 bits of precision. 37320b57cec5SDimitry Andric APSInt IntVal(65, true); 37330b57cec5SDimitry Andric FVal.convertToInteger(IntVal, APFloat::rmTowardZero, &IsExact); 37340b57cec5SDimitry Andric 37350b57cec5SDimitry Andric // N.b. isPowerOf2 also checks for > 0. 37365f757f3fSDimitry Andric if (!IsExact || !IntVal.isPowerOf2()) 37375f757f3fSDimitry Andric return false; 37380b57cec5SDimitry Andric unsigned FBits = IntVal.logBase2(); 37390b57cec5SDimitry Andric 37400b57cec5SDimitry Andric // Checks above should have guaranteed that we haven't lost information in 37410b57cec5SDimitry Andric // finding FBits, but it must still be in range. 37420b57cec5SDimitry Andric if (FBits == 0 || FBits > RegWidth) return false; 37430b57cec5SDimitry Andric 37440b57cec5SDimitry Andric FixedPos = CurDAG->getTargetConstant(FBits, SDLoc(N), MVT::i32); 37450b57cec5SDimitry Andric return true; 37460b57cec5SDimitry Andric } 37470b57cec5SDimitry Andric 37485f757f3fSDimitry Andric bool AArch64DAGToDAGISel::SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, 37495f757f3fSDimitry Andric unsigned RegWidth) { 37505f757f3fSDimitry Andric return checkCVTFixedPointOperandWithFBits(CurDAG, N, FixedPos, RegWidth, 37515f757f3fSDimitry Andric false); 37525f757f3fSDimitry Andric } 37535f757f3fSDimitry Andric 37545f757f3fSDimitry Andric bool AArch64DAGToDAGISel::SelectCVTFixedPosRecipOperand(SDValue N, 37555f757f3fSDimitry Andric SDValue &FixedPos, 37565f757f3fSDimitry Andric unsigned RegWidth) { 37575f757f3fSDimitry Andric return checkCVTFixedPointOperandWithFBits(CurDAG, N, FixedPos, RegWidth, 37585f757f3fSDimitry Andric true); 37595f757f3fSDimitry Andric } 37605f757f3fSDimitry Andric 37610b57cec5SDimitry Andric // Inspects a register string of the form o0:op1:CRn:CRm:op2 gets the fields 37620b57cec5SDimitry Andric // of the string and obtains the integer values from them and combines these 37630b57cec5SDimitry Andric // into a single value to be used in the MRS/MSR instruction. 37640b57cec5SDimitry Andric static int getIntOperandFromRegisterString(StringRef RegString) { 37650b57cec5SDimitry Andric SmallVector<StringRef, 5> Fields; 37660b57cec5SDimitry Andric RegString.split(Fields, ':'); 37670b57cec5SDimitry Andric 37680b57cec5SDimitry Andric if (Fields.size() == 1) 37690b57cec5SDimitry Andric return -1; 37700b57cec5SDimitry Andric 37710b57cec5SDimitry Andric assert(Fields.size() == 5 37720b57cec5SDimitry Andric && "Invalid number of fields in read register string"); 37730b57cec5SDimitry Andric 37740b57cec5SDimitry Andric SmallVector<int, 5> Ops; 37750b57cec5SDimitry Andric bool AllIntFields = true; 37760b57cec5SDimitry Andric 37770b57cec5SDimitry Andric for (StringRef Field : Fields) { 37780b57cec5SDimitry Andric unsigned IntField; 37790b57cec5SDimitry Andric AllIntFields &= !Field.getAsInteger(10, IntField); 37800b57cec5SDimitry Andric Ops.push_back(IntField); 37810b57cec5SDimitry Andric } 37820b57cec5SDimitry Andric 37830b57cec5SDimitry Andric assert(AllIntFields && 37840b57cec5SDimitry Andric "Unexpected non-integer value in special register string."); 3785fe6060f1SDimitry Andric (void)AllIntFields; 37860b57cec5SDimitry Andric 37870b57cec5SDimitry Andric // Need to combine the integer fields of the string into a single value 37880b57cec5SDimitry Andric // based on the bit encoding of MRS/MSR instruction. 37890b57cec5SDimitry Andric return (Ops[0] << 14) | (Ops[1] << 11) | (Ops[2] << 7) | 37900b57cec5SDimitry Andric (Ops[3] << 3) | (Ops[4]); 37910b57cec5SDimitry Andric } 37920b57cec5SDimitry Andric 37930b57cec5SDimitry Andric // Lower the read_register intrinsic to an MRS instruction node if the special 37940b57cec5SDimitry Andric // register string argument is either of the form detailed in the ALCE (the 37950b57cec5SDimitry Andric // form described in getIntOperandsFromRegsterString) or is a named register 37960b57cec5SDimitry Andric // known by the MRS SysReg mapper. 37970b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryReadRegister(SDNode *N) { 3798349cc55cSDimitry Andric const auto *MD = cast<MDNodeSDNode>(N->getOperand(1)); 3799349cc55cSDimitry Andric const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0)); 38000b57cec5SDimitry Andric SDLoc DL(N); 38010b57cec5SDimitry Andric 3802bdd1243dSDimitry Andric bool ReadIs128Bit = N->getOpcode() == AArch64ISD::MRRS; 38030b57cec5SDimitry Andric 3804bdd1243dSDimitry Andric unsigned Opcode64Bit = AArch64::MRS; 3805bdd1243dSDimitry Andric int Imm = getIntOperandFromRegisterString(RegString->getString()); 3806bdd1243dSDimitry Andric if (Imm == -1) { 3807bdd1243dSDimitry Andric // No match, Use the sysreg mapper to map the remaining possible strings to 3808bdd1243dSDimitry Andric // the value for the register to be used for the instruction operand. 3809bdd1243dSDimitry Andric const auto *TheReg = 3810bdd1243dSDimitry Andric AArch64SysReg::lookupSysRegByName(RegString->getString()); 38110b57cec5SDimitry Andric if (TheReg && TheReg->Readable && 38120b57cec5SDimitry Andric TheReg->haveFeatures(Subtarget->getFeatureBits())) 3813bdd1243dSDimitry Andric Imm = TheReg->Encoding; 38140b57cec5SDimitry Andric else 3815bdd1243dSDimitry Andric Imm = AArch64SysReg::parseGenericRegister(RegString->getString()); 38160b57cec5SDimitry Andric 3817bdd1243dSDimitry Andric if (Imm == -1) { 3818bdd1243dSDimitry Andric // Still no match, see if this is "pc" or give up. 3819bdd1243dSDimitry Andric if (!ReadIs128Bit && RegString->getString() == "pc") { 3820bdd1243dSDimitry Andric Opcode64Bit = AArch64::ADR; 3821bdd1243dSDimitry Andric Imm = 0; 3822bdd1243dSDimitry Andric } else { 38230b57cec5SDimitry Andric return false; 38240b57cec5SDimitry Andric } 3825bdd1243dSDimitry Andric } 3826bdd1243dSDimitry Andric } 3827bdd1243dSDimitry Andric 3828bdd1243dSDimitry Andric SDValue InChain = N->getOperand(0); 3829bdd1243dSDimitry Andric SDValue SysRegImm = CurDAG->getTargetConstant(Imm, DL, MVT::i32); 3830bdd1243dSDimitry Andric if (!ReadIs128Bit) { 3831bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, Opcode64Bit, MVT::i64, MVT::Other /* Chain */, 3832bdd1243dSDimitry Andric {SysRegImm, InChain}); 3833bdd1243dSDimitry Andric } else { 3834bdd1243dSDimitry Andric SDNode *MRRS = CurDAG->getMachineNode( 3835bdd1243dSDimitry Andric AArch64::MRRS, DL, 3836bdd1243dSDimitry Andric {MVT::Untyped /* XSeqPair */, MVT::Other /* Chain */}, 3837bdd1243dSDimitry Andric {SysRegImm, InChain}); 3838bdd1243dSDimitry Andric 3839bdd1243dSDimitry Andric // Sysregs are not endian. The even register always contains the low half 3840bdd1243dSDimitry Andric // of the register. 3841bdd1243dSDimitry Andric SDValue Lo = CurDAG->getTargetExtractSubreg(AArch64::sube64, DL, MVT::i64, 3842bdd1243dSDimitry Andric SDValue(MRRS, 0)); 3843bdd1243dSDimitry Andric SDValue Hi = CurDAG->getTargetExtractSubreg(AArch64::subo64, DL, MVT::i64, 3844bdd1243dSDimitry Andric SDValue(MRRS, 0)); 3845bdd1243dSDimitry Andric SDValue OutChain = SDValue(MRRS, 1); 3846bdd1243dSDimitry Andric 3847bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 0), Lo); 3848bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 1), Hi); 3849bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 2), OutChain); 3850bdd1243dSDimitry Andric }; 3851bdd1243dSDimitry Andric return true; 3852bdd1243dSDimitry Andric } 38530b57cec5SDimitry Andric 38540b57cec5SDimitry Andric // Lower the write_register intrinsic to an MSR instruction node if the special 38550b57cec5SDimitry Andric // register string argument is either of the form detailed in the ALCE (the 38560b57cec5SDimitry Andric // form described in getIntOperandsFromRegsterString) or is a named register 38570b57cec5SDimitry Andric // known by the MSR SysReg mapper. 38580b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) { 3859349cc55cSDimitry Andric const auto *MD = cast<MDNodeSDNode>(N->getOperand(1)); 3860349cc55cSDimitry Andric const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0)); 38610b57cec5SDimitry Andric SDLoc DL(N); 38620b57cec5SDimitry Andric 3863bdd1243dSDimitry Andric bool WriteIs128Bit = N->getOpcode() == AArch64ISD::MSRR; 38640b57cec5SDimitry Andric 3865bdd1243dSDimitry Andric if (!WriteIs128Bit) { 3866bdd1243dSDimitry Andric // Check if the register was one of those allowed as the pstatefield value 3867bdd1243dSDimitry Andric // in the MSR (immediate) instruction. To accept the values allowed in the 38680b57cec5SDimitry Andric // pstatefield for the MSR (immediate) instruction, we also require that an 38690b57cec5SDimitry Andric // immediate value has been provided as an argument, we know that this is 38700b57cec5SDimitry Andric // the case as it has been ensured by semantic checking. 3871bdd1243dSDimitry Andric auto trySelectPState = [&](auto PMapper, unsigned State) { 38720b57cec5SDimitry Andric if (PMapper) { 3873bdd1243dSDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(2)) && 3874bdd1243dSDimitry Andric "Expected a constant integer expression."); 38750b57cec5SDimitry Andric unsigned Reg = PMapper->Encoding; 3876647cbc5dSDimitry Andric uint64_t Immed = N->getConstantOperandVal(2); 3877bdd1243dSDimitry Andric CurDAG->SelectNodeTo( 3878bdd1243dSDimitry Andric N, State, MVT::Other, CurDAG->getTargetConstant(Reg, DL, MVT::i32), 3879bdd1243dSDimitry Andric CurDAG->getTargetConstant(Immed, DL, MVT::i16), N->getOperand(0)); 3880bdd1243dSDimitry Andric return true; 38810b57cec5SDimitry Andric } 3882bdd1243dSDimitry Andric return false; 3883bdd1243dSDimitry Andric }; 3884bdd1243dSDimitry Andric 3885bdd1243dSDimitry Andric if (trySelectPState( 3886bdd1243dSDimitry Andric AArch64PState::lookupPStateImm0_15ByName(RegString->getString()), 3887bdd1243dSDimitry Andric AArch64::MSRpstateImm4)) 3888bdd1243dSDimitry Andric return true; 3889bdd1243dSDimitry Andric if (trySelectPState( 3890bdd1243dSDimitry Andric AArch64PState::lookupPStateImm0_1ByName(RegString->getString()), 3891bdd1243dSDimitry Andric AArch64::MSRpstateImm1)) 38920b57cec5SDimitry Andric return true; 38930b57cec5SDimitry Andric } 38940b57cec5SDimitry Andric 3895bdd1243dSDimitry Andric int Imm = getIntOperandFromRegisterString(RegString->getString()); 3896bdd1243dSDimitry Andric if (Imm == -1) { 38970b57cec5SDimitry Andric // Use the sysreg mapper to attempt to map the remaining possible strings 38980b57cec5SDimitry Andric // to the value for the register to be used for the MSR (register) 38990b57cec5SDimitry Andric // instruction operand. 39000b57cec5SDimitry Andric auto TheReg = AArch64SysReg::lookupSysRegByName(RegString->getString()); 39010b57cec5SDimitry Andric if (TheReg && TheReg->Writeable && 39020b57cec5SDimitry Andric TheReg->haveFeatures(Subtarget->getFeatureBits())) 3903bdd1243dSDimitry Andric Imm = TheReg->Encoding; 39040b57cec5SDimitry Andric else 3905bdd1243dSDimitry Andric Imm = AArch64SysReg::parseGenericRegister(RegString->getString()); 3906bdd1243dSDimitry Andric 3907bdd1243dSDimitry Andric if (Imm == -1) 3908bdd1243dSDimitry Andric return false; 39090b57cec5SDimitry Andric } 39100b57cec5SDimitry Andric 3911bdd1243dSDimitry Andric SDValue InChain = N->getOperand(0); 3912bdd1243dSDimitry Andric if (!WriteIs128Bit) { 3913bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::MSR, MVT::Other, 3914bdd1243dSDimitry Andric CurDAG->getTargetConstant(Imm, DL, MVT::i32), 3915bdd1243dSDimitry Andric N->getOperand(2), InChain); 3916bdd1243dSDimitry Andric } else { 3917bdd1243dSDimitry Andric // No endian swap. The lower half always goes into the even subreg, and the 3918bdd1243dSDimitry Andric // higher half always into the odd supreg. 3919bdd1243dSDimitry Andric SDNode *Pair = CurDAG->getMachineNode( 3920bdd1243dSDimitry Andric TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped /* XSeqPair */, 3921bdd1243dSDimitry Andric {CurDAG->getTargetConstant(AArch64::XSeqPairsClassRegClass.getID(), DL, 3922bdd1243dSDimitry Andric MVT::i32), 3923bdd1243dSDimitry Andric N->getOperand(2), 3924bdd1243dSDimitry Andric CurDAG->getTargetConstant(AArch64::sube64, DL, MVT::i32), 3925bdd1243dSDimitry Andric N->getOperand(3), 3926bdd1243dSDimitry Andric CurDAG->getTargetConstant(AArch64::subo64, DL, MVT::i32)}); 3927bdd1243dSDimitry Andric 3928bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::MSRR, MVT::Other, 3929bdd1243dSDimitry Andric CurDAG->getTargetConstant(Imm, DL, MVT::i32), 3930bdd1243dSDimitry Andric SDValue(Pair, 0), InChain); 3931bdd1243dSDimitry Andric } 3932bdd1243dSDimitry Andric 3933bdd1243dSDimitry Andric return true; 39340b57cec5SDimitry Andric } 39350b57cec5SDimitry Andric 39360b57cec5SDimitry Andric /// We've got special pseudo-instructions for these 39370b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) { 39380b57cec5SDimitry Andric unsigned Opcode; 39390b57cec5SDimitry Andric EVT MemTy = cast<MemSDNode>(N)->getMemoryVT(); 39400b57cec5SDimitry Andric 39410b57cec5SDimitry Andric // Leave IR for LSE if subtarget supports it. 39420b57cec5SDimitry Andric if (Subtarget->hasLSE()) return false; 39430b57cec5SDimitry Andric 39440b57cec5SDimitry Andric if (MemTy == MVT::i8) 39450b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_8; 39460b57cec5SDimitry Andric else if (MemTy == MVT::i16) 39470b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_16; 39480b57cec5SDimitry Andric else if (MemTy == MVT::i32) 39490b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_32; 39500b57cec5SDimitry Andric else if (MemTy == MVT::i64) 39510b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_64; 39520b57cec5SDimitry Andric else 39530b57cec5SDimitry Andric llvm_unreachable("Unknown AtomicCmpSwap type"); 39540b57cec5SDimitry Andric 39550b57cec5SDimitry Andric MVT RegTy = MemTy == MVT::i64 ? MVT::i64 : MVT::i32; 39560b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3), 39570b57cec5SDimitry Andric N->getOperand(0)}; 39580b57cec5SDimitry Andric SDNode *CmpSwap = CurDAG->getMachineNode( 39590b57cec5SDimitry Andric Opcode, SDLoc(N), 39600b57cec5SDimitry Andric CurDAG->getVTList(RegTy, MVT::i32, MVT::Other), Ops); 39610b57cec5SDimitry Andric 39620b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand(); 39630b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp}); 39640b57cec5SDimitry Andric 39650b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0)); 39660b57cec5SDimitry Andric ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2)); 39670b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 39680b57cec5SDimitry Andric 39690b57cec5SDimitry Andric return true; 39700b57cec5SDimitry Andric } 39710b57cec5SDimitry Andric 397281ad6265SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm, 397381ad6265SDimitry Andric SDValue &Shift) { 397481ad6265SDimitry Andric if (!isa<ConstantSDNode>(N)) 39755ffd83dbSDimitry Andric return false; 39765ffd83dbSDimitry Andric 39775ffd83dbSDimitry Andric SDLoc DL(N); 397881ad6265SDimitry Andric uint64_t Val = cast<ConstantSDNode>(N) 397981ad6265SDimitry Andric ->getAPIntValue() 398081ad6265SDimitry Andric .trunc(VT.getFixedSizeInBits()) 398181ad6265SDimitry Andric .getZExtValue(); 3982480093f4SDimitry Andric 3983480093f4SDimitry Andric switch (VT.SimpleTy) { 3984480093f4SDimitry Andric case MVT::i8: 398581ad6265SDimitry Andric // All immediates are supported. 3986fe6060f1SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 398781ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32); 3988fe6060f1SDimitry Andric return true; 3989fe6060f1SDimitry Andric case MVT::i16: 3990480093f4SDimitry Andric case MVT::i32: 3991480093f4SDimitry Andric case MVT::i64: 399281ad6265SDimitry Andric // Support 8bit unsigned immediates. 399381ad6265SDimitry Andric if (Val <= 255) { 3994480093f4SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 399581ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32); 3996480093f4SDimitry Andric return true; 399781ad6265SDimitry Andric } 399881ad6265SDimitry Andric // Support 16bit unsigned immediates that are a multiple of 256. 399981ad6265SDimitry Andric if (Val <= 65280 && Val % 256 == 0) { 4000480093f4SDimitry Andric Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); 400181ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val >> 8, DL, MVT::i32); 4002480093f4SDimitry Andric return true; 4003480093f4SDimitry Andric } 4004480093f4SDimitry Andric break; 4005480093f4SDimitry Andric default: 4006480093f4SDimitry Andric break; 4007480093f4SDimitry Andric } 400881ad6265SDimitry Andric 400981ad6265SDimitry Andric return false; 401081ad6265SDimitry Andric } 401181ad6265SDimitry Andric 401281ad6265SDimitry Andric bool AArch64DAGToDAGISel::SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm, 401381ad6265SDimitry Andric SDValue &Shift) { 401481ad6265SDimitry Andric if (!isa<ConstantSDNode>(N)) 401581ad6265SDimitry Andric return false; 401681ad6265SDimitry Andric 401781ad6265SDimitry Andric SDLoc DL(N); 401881ad6265SDimitry Andric int64_t Val = cast<ConstantSDNode>(N) 401981ad6265SDimitry Andric ->getAPIntValue() 402081ad6265SDimitry Andric .trunc(VT.getFixedSizeInBits()) 402181ad6265SDimitry Andric .getSExtValue(); 402281ad6265SDimitry Andric 402381ad6265SDimitry Andric switch (VT.SimpleTy) { 402481ad6265SDimitry Andric case MVT::i8: 402581ad6265SDimitry Andric // All immediates are supported. 402681ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 402781ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val & 0xFF, DL, MVT::i32); 402881ad6265SDimitry Andric return true; 402981ad6265SDimitry Andric case MVT::i16: 403081ad6265SDimitry Andric case MVT::i32: 403181ad6265SDimitry Andric case MVT::i64: 403281ad6265SDimitry Andric // Support 8bit signed immediates. 403381ad6265SDimitry Andric if (Val >= -128 && Val <= 127) { 403481ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 403581ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val & 0xFF, DL, MVT::i32); 403681ad6265SDimitry Andric return true; 403781ad6265SDimitry Andric } 403881ad6265SDimitry Andric // Support 16bit signed immediates that are a multiple of 256. 403981ad6265SDimitry Andric if (Val >= -32768 && Val <= 32512 && Val % 256 == 0) { 404081ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); 404181ad6265SDimitry Andric Imm = CurDAG->getTargetConstant((Val >> 8) & 0xFF, DL, MVT::i32); 404281ad6265SDimitry Andric return true; 404381ad6265SDimitry Andric } 404481ad6265SDimitry Andric break; 404581ad6265SDimitry Andric default: 404681ad6265SDimitry Andric break; 4047480093f4SDimitry Andric } 4048480093f4SDimitry Andric 4049480093f4SDimitry Andric return false; 4050480093f4SDimitry Andric } 4051480093f4SDimitry Andric 4052480093f4SDimitry Andric bool AArch64DAGToDAGISel::SelectSVESignedArithImm(SDValue N, SDValue &Imm) { 4053480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 4054480093f4SDimitry Andric int64_t ImmVal = CNode->getSExtValue(); 4055480093f4SDimitry Andric SDLoc DL(N); 40565ffd83dbSDimitry Andric if (ImmVal >= -128 && ImmVal < 128) { 4057480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32); 4058480093f4SDimitry Andric return true; 4059480093f4SDimitry Andric } 4060480093f4SDimitry Andric } 4061480093f4SDimitry Andric return false; 4062480093f4SDimitry Andric } 4063480093f4SDimitry Andric 4064e8d8bef9SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm) { 4065480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 4066e8d8bef9SDimitry Andric uint64_t ImmVal = CNode->getZExtValue(); 4067e8d8bef9SDimitry Andric 4068e8d8bef9SDimitry Andric switch (VT.SimpleTy) { 4069e8d8bef9SDimitry Andric case MVT::i8: 4070e8d8bef9SDimitry Andric ImmVal &= 0xFF; 4071e8d8bef9SDimitry Andric break; 4072e8d8bef9SDimitry Andric case MVT::i16: 4073e8d8bef9SDimitry Andric ImmVal &= 0xFFFF; 4074e8d8bef9SDimitry Andric break; 4075e8d8bef9SDimitry Andric case MVT::i32: 4076e8d8bef9SDimitry Andric ImmVal &= 0xFFFFFFFF; 4077e8d8bef9SDimitry Andric break; 4078e8d8bef9SDimitry Andric case MVT::i64: 4079e8d8bef9SDimitry Andric break; 4080e8d8bef9SDimitry Andric default: 4081e8d8bef9SDimitry Andric llvm_unreachable("Unexpected type"); 4082e8d8bef9SDimitry Andric } 4083e8d8bef9SDimitry Andric 4084480093f4SDimitry Andric if (ImmVal < 256) { 4085e8d8bef9SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32); 4086480093f4SDimitry Andric return true; 4087480093f4SDimitry Andric } 4088480093f4SDimitry Andric } 4089480093f4SDimitry Andric return false; 4090480093f4SDimitry Andric } 4091480093f4SDimitry Andric 4092fe6060f1SDimitry Andric bool AArch64DAGToDAGISel::SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm, 4093fe6060f1SDimitry Andric bool Invert) { 4094480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 4095480093f4SDimitry Andric uint64_t ImmVal = CNode->getZExtValue(); 4096480093f4SDimitry Andric SDLoc DL(N); 4097480093f4SDimitry Andric 4098fe6060f1SDimitry Andric if (Invert) 4099fe6060f1SDimitry Andric ImmVal = ~ImmVal; 4100fe6060f1SDimitry Andric 4101480093f4SDimitry Andric // Shift mask depending on type size. 4102480093f4SDimitry Andric switch (VT.SimpleTy) { 4103480093f4SDimitry Andric case MVT::i8: 4104480093f4SDimitry Andric ImmVal &= 0xFF; 4105480093f4SDimitry Andric ImmVal |= ImmVal << 8; 4106480093f4SDimitry Andric ImmVal |= ImmVal << 16; 4107480093f4SDimitry Andric ImmVal |= ImmVal << 32; 4108480093f4SDimitry Andric break; 4109480093f4SDimitry Andric case MVT::i16: 4110480093f4SDimitry Andric ImmVal &= 0xFFFF; 4111480093f4SDimitry Andric ImmVal |= ImmVal << 16; 4112480093f4SDimitry Andric ImmVal |= ImmVal << 32; 4113480093f4SDimitry Andric break; 4114480093f4SDimitry Andric case MVT::i32: 4115480093f4SDimitry Andric ImmVal &= 0xFFFFFFFF; 4116480093f4SDimitry Andric ImmVal |= ImmVal << 32; 4117480093f4SDimitry Andric break; 4118480093f4SDimitry Andric case MVT::i64: 4119480093f4SDimitry Andric break; 4120480093f4SDimitry Andric default: 4121480093f4SDimitry Andric llvm_unreachable("Unexpected type"); 4122480093f4SDimitry Andric } 4123480093f4SDimitry Andric 4124480093f4SDimitry Andric uint64_t encoding; 4125480093f4SDimitry Andric if (AArch64_AM::processLogicalImmediate(ImmVal, 64, encoding)) { 4126480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(encoding, DL, MVT::i64); 4127480093f4SDimitry Andric return true; 4128480093f4SDimitry Andric } 4129480093f4SDimitry Andric } 4130480093f4SDimitry Andric return false; 4131480093f4SDimitry Andric } 4132480093f4SDimitry Andric 4133e8d8bef9SDimitry Andric // SVE shift intrinsics allow shift amounts larger than the element's bitwidth. 4134e8d8bef9SDimitry Andric // Rather than attempt to normalise everything we can sometimes saturate the 4135e8d8bef9SDimitry Andric // shift amount during selection. This function also allows for consistent 4136e8d8bef9SDimitry Andric // isel patterns by ensuring the resulting "Imm" node is of the i32 type 4137e8d8bef9SDimitry Andric // required by the instructions. 4138e8d8bef9SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEShiftImm(SDValue N, uint64_t Low, 4139e8d8bef9SDimitry Andric uint64_t High, bool AllowSaturation, 4140e8d8bef9SDimitry Andric SDValue &Imm) { 41415ffd83dbSDimitry Andric if (auto *CN = dyn_cast<ConstantSDNode>(N)) { 41425ffd83dbSDimitry Andric uint64_t ImmVal = CN->getZExtValue(); 41435ffd83dbSDimitry Andric 4144e8d8bef9SDimitry Andric // Reject shift amounts that are too small. 4145e8d8bef9SDimitry Andric if (ImmVal < Low) 4146e8d8bef9SDimitry Andric return false; 4147e8d8bef9SDimitry Andric 4148e8d8bef9SDimitry Andric // Reject or saturate shift amounts that are too big. 4149e8d8bef9SDimitry Andric if (ImmVal > High) { 4150e8d8bef9SDimitry Andric if (!AllowSaturation) 4151e8d8bef9SDimitry Andric return false; 4152e8d8bef9SDimitry Andric ImmVal = High; 41535ffd83dbSDimitry Andric } 4154e8d8bef9SDimitry Andric 4155e8d8bef9SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32); 4156e8d8bef9SDimitry Andric return true; 41575ffd83dbSDimitry Andric } 41585ffd83dbSDimitry Andric 41595ffd83dbSDimitry Andric return false; 41605ffd83dbSDimitry Andric } 41615ffd83dbSDimitry Andric 41620b57cec5SDimitry Andric bool AArch64DAGToDAGISel::trySelectStackSlotTagP(SDNode *N) { 41630b57cec5SDimitry Andric // tagp(FrameIndex, IRGstack, tag_offset): 41640b57cec5SDimitry Andric // since the offset between FrameIndex and IRGstack is a compile-time 41650b57cec5SDimitry Andric // constant, this can be lowered to a single ADDG instruction. 41660b57cec5SDimitry Andric if (!(isa<FrameIndexSDNode>(N->getOperand(1)))) { 41670b57cec5SDimitry Andric return false; 41680b57cec5SDimitry Andric } 41690b57cec5SDimitry Andric 41700b57cec5SDimitry Andric SDValue IRG_SP = N->getOperand(2); 41710b57cec5SDimitry Andric if (IRG_SP->getOpcode() != ISD::INTRINSIC_W_CHAIN || 4172647cbc5dSDimitry Andric IRG_SP->getConstantOperandVal(1) != Intrinsic::aarch64_irg_sp) { 41730b57cec5SDimitry Andric return false; 41740b57cec5SDimitry Andric } 41750b57cec5SDimitry Andric 41760b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 41770b57cec5SDimitry Andric SDLoc DL(N); 41780b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N->getOperand(1))->getIndex(); 41790b57cec5SDimitry Andric SDValue FiOp = CurDAG->getTargetFrameIndex( 41800b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 4181647cbc5dSDimitry Andric int TagOffset = N->getConstantOperandVal(3); 41820b57cec5SDimitry Andric 41830b57cec5SDimitry Andric SDNode *Out = CurDAG->getMachineNode( 41840b57cec5SDimitry Andric AArch64::TAGPstack, DL, MVT::i64, 41850b57cec5SDimitry Andric {FiOp, CurDAG->getTargetConstant(0, DL, MVT::i64), N->getOperand(2), 41860b57cec5SDimitry Andric CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)}); 41870b57cec5SDimitry Andric ReplaceNode(N, Out); 41880b57cec5SDimitry Andric return true; 41890b57cec5SDimitry Andric } 41900b57cec5SDimitry Andric 41910b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectTagP(SDNode *N) { 41920b57cec5SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(3)) && 41930b57cec5SDimitry Andric "llvm.aarch64.tagp third argument must be an immediate"); 41940b57cec5SDimitry Andric if (trySelectStackSlotTagP(N)) 41950b57cec5SDimitry Andric return; 41960b57cec5SDimitry Andric // FIXME: above applies in any case when offset between Op1 and Op2 is a 41970b57cec5SDimitry Andric // compile-time constant, not just for stack allocations. 41980b57cec5SDimitry Andric 41990b57cec5SDimitry Andric // General case for unrelated pointers in Op1 and Op2. 42000b57cec5SDimitry Andric SDLoc DL(N); 4201647cbc5dSDimitry Andric int TagOffset = N->getConstantOperandVal(3); 42020b57cec5SDimitry Andric SDNode *N1 = CurDAG->getMachineNode(AArch64::SUBP, DL, MVT::i64, 42030b57cec5SDimitry Andric {N->getOperand(1), N->getOperand(2)}); 42040b57cec5SDimitry Andric SDNode *N2 = CurDAG->getMachineNode(AArch64::ADDXrr, DL, MVT::i64, 42050b57cec5SDimitry Andric {SDValue(N1, 0), N->getOperand(2)}); 42060b57cec5SDimitry Andric SDNode *N3 = CurDAG->getMachineNode( 42070b57cec5SDimitry Andric AArch64::ADDG, DL, MVT::i64, 42080b57cec5SDimitry Andric {SDValue(N2, 0), CurDAG->getTargetConstant(0, DL, MVT::i64), 42090b57cec5SDimitry Andric CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)}); 42100b57cec5SDimitry Andric ReplaceNode(N, N3); 42110b57cec5SDimitry Andric } 42120b57cec5SDimitry Andric 421306c3fb27SDimitry Andric bool AArch64DAGToDAGISel::trySelectCastFixedLengthToScalableVector(SDNode *N) { 421406c3fb27SDimitry Andric assert(N->getOpcode() == ISD::INSERT_SUBVECTOR && "Invalid Node!"); 42155ffd83dbSDimitry Andric 421606c3fb27SDimitry Andric // Bail when not a "cast" like insert_subvector. 4217647cbc5dSDimitry Andric if (N->getConstantOperandVal(2) != 0) 421806c3fb27SDimitry Andric return false; 421906c3fb27SDimitry Andric if (!N->getOperand(0).isUndef()) 422006c3fb27SDimitry Andric return false; 42215ffd83dbSDimitry Andric 422206c3fb27SDimitry Andric // Bail when normal isel should do the job. 422306c3fb27SDimitry Andric EVT VT = N->getValueType(0); 422406c3fb27SDimitry Andric EVT InVT = N->getOperand(1).getValueType(); 422506c3fb27SDimitry Andric if (VT.isFixedLengthVector() || InVT.isScalableVector()) 422606c3fb27SDimitry Andric return false; 422706c3fb27SDimitry Andric if (InVT.getSizeInBits() <= 128) 422806c3fb27SDimitry Andric return false; 422906c3fb27SDimitry Andric 423006c3fb27SDimitry Andric // NOTE: We can only get here when doing fixed length SVE code generation. 423106c3fb27SDimitry Andric // We do manual selection because the types involved are not linked to real 423206c3fb27SDimitry Andric // registers (despite being legal) and must be coerced into SVE registers. 423306c3fb27SDimitry Andric 423406c3fb27SDimitry Andric assert(VT.getSizeInBits().getKnownMinValue() == AArch64::SVEBitsPerBlock && 42355ffd83dbSDimitry Andric "Expected to insert into a packed scalable vector!"); 42365ffd83dbSDimitry Andric 423706c3fb27SDimitry Andric SDLoc DL(N); 423806c3fb27SDimitry Andric auto RC = CurDAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64); 423906c3fb27SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, 424006c3fb27SDimitry Andric N->getOperand(1), RC)); 424106c3fb27SDimitry Andric return true; 42425ffd83dbSDimitry Andric } 424306c3fb27SDimitry Andric 424406c3fb27SDimitry Andric bool AArch64DAGToDAGISel::trySelectCastScalableToFixedLengthVector(SDNode *N) { 424506c3fb27SDimitry Andric assert(N->getOpcode() == ISD::EXTRACT_SUBVECTOR && "Invalid Node!"); 424606c3fb27SDimitry Andric 424706c3fb27SDimitry Andric // Bail when not a "cast" like extract_subvector. 4248647cbc5dSDimitry Andric if (N->getConstantOperandVal(1) != 0) 424906c3fb27SDimitry Andric return false; 425006c3fb27SDimitry Andric 425106c3fb27SDimitry Andric // Bail when normal isel can do the job. 425206c3fb27SDimitry Andric EVT VT = N->getValueType(0); 425306c3fb27SDimitry Andric EVT InVT = N->getOperand(0).getValueType(); 425406c3fb27SDimitry Andric if (VT.isScalableVector() || InVT.isFixedLengthVector()) 425506c3fb27SDimitry Andric return false; 425606c3fb27SDimitry Andric if (VT.getSizeInBits() <= 128) 425706c3fb27SDimitry Andric return false; 425806c3fb27SDimitry Andric 425906c3fb27SDimitry Andric // NOTE: We can only get here when doing fixed length SVE code generation. 426006c3fb27SDimitry Andric // We do manual selection because the types involved are not linked to real 426106c3fb27SDimitry Andric // registers (despite being legal) and must be coerced into SVE registers. 426206c3fb27SDimitry Andric 426306c3fb27SDimitry Andric assert(InVT.getSizeInBits().getKnownMinValue() == AArch64::SVEBitsPerBlock && 426406c3fb27SDimitry Andric "Expected to extract from a packed scalable vector!"); 426506c3fb27SDimitry Andric 426606c3fb27SDimitry Andric SDLoc DL(N); 426706c3fb27SDimitry Andric auto RC = CurDAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64); 426806c3fb27SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, 426906c3fb27SDimitry Andric N->getOperand(0), RC)); 427006c3fb27SDimitry Andric return true; 42715ffd83dbSDimitry Andric } 42725ffd83dbSDimitry Andric 42735f757f3fSDimitry Andric bool AArch64DAGToDAGISel::trySelectXAR(SDNode *N) { 42745f757f3fSDimitry Andric assert(N->getOpcode() == ISD::OR && "Expected OR instruction"); 42755f757f3fSDimitry Andric 42765f757f3fSDimitry Andric SDValue N0 = N->getOperand(0); 42775f757f3fSDimitry Andric SDValue N1 = N->getOperand(1); 42785f757f3fSDimitry Andric 42795f757f3fSDimitry Andric if (N0->getOpcode() != AArch64ISD::VSHL || 42805f757f3fSDimitry Andric N1->getOpcode() != AArch64ISD::VLSHR) 42815f757f3fSDimitry Andric return false; 42825f757f3fSDimitry Andric 42835f757f3fSDimitry Andric if (N0->getOperand(0) != N1->getOperand(0) || 42845f757f3fSDimitry Andric N1->getOperand(0)->getOpcode() != ISD::XOR) 42855f757f3fSDimitry Andric return false; 42865f757f3fSDimitry Andric 42875f757f3fSDimitry Andric SDValue XOR = N0.getOperand(0); 42885f757f3fSDimitry Andric SDValue R1 = XOR.getOperand(0); 42895f757f3fSDimitry Andric SDValue R2 = XOR.getOperand(1); 42905f757f3fSDimitry Andric 42915f757f3fSDimitry Andric unsigned HsAmt = N0.getConstantOperandVal(1); 42925f757f3fSDimitry Andric unsigned ShAmt = N1.getConstantOperandVal(1); 42935f757f3fSDimitry Andric 42945f757f3fSDimitry Andric SDLoc DL = SDLoc(N0.getOperand(1)); 42955f757f3fSDimitry Andric SDValue Imm = CurDAG->getTargetConstant( 42965f757f3fSDimitry Andric ShAmt, DL, N0.getOperand(1).getValueType(), false); 42975f757f3fSDimitry Andric 42985f757f3fSDimitry Andric if (ShAmt + HsAmt != 64) 42995f757f3fSDimitry Andric return false; 43005f757f3fSDimitry Andric 43015f757f3fSDimitry Andric SDValue Ops[] = {R1, R2, Imm}; 43025f757f3fSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::XAR, N0.getValueType(), Ops); 43035f757f3fSDimitry Andric 43045f757f3fSDimitry Andric return true; 43055f757f3fSDimitry Andric } 43065f757f3fSDimitry Andric 43070b57cec5SDimitry Andric void AArch64DAGToDAGISel::Select(SDNode *Node) { 43080b57cec5SDimitry Andric // If we have a custom node, we already have selected! 43090b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 43100b57cec5SDimitry Andric LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 43110b57cec5SDimitry Andric Node->setNodeId(-1); 43120b57cec5SDimitry Andric return; 43130b57cec5SDimitry Andric } 43140b57cec5SDimitry Andric 43150b57cec5SDimitry Andric // Few custom selection stuff. 43160b57cec5SDimitry Andric EVT VT = Node->getValueType(0); 43170b57cec5SDimitry Andric 43180b57cec5SDimitry Andric switch (Node->getOpcode()) { 43190b57cec5SDimitry Andric default: 43200b57cec5SDimitry Andric break; 43210b57cec5SDimitry Andric 43220b57cec5SDimitry Andric case ISD::ATOMIC_CMP_SWAP: 43230b57cec5SDimitry Andric if (SelectCMP_SWAP(Node)) 43240b57cec5SDimitry Andric return; 43250b57cec5SDimitry Andric break; 43260b57cec5SDimitry Andric 43270b57cec5SDimitry Andric case ISD::READ_REGISTER: 4328bdd1243dSDimitry Andric case AArch64ISD::MRRS: 43290b57cec5SDimitry Andric if (tryReadRegister(Node)) 43300b57cec5SDimitry Andric return; 43310b57cec5SDimitry Andric break; 43320b57cec5SDimitry Andric 43330b57cec5SDimitry Andric case ISD::WRITE_REGISTER: 4334bdd1243dSDimitry Andric case AArch64ISD::MSRR: 43350b57cec5SDimitry Andric if (tryWriteRegister(Node)) 43360b57cec5SDimitry Andric return; 43370b57cec5SDimitry Andric break; 43380b57cec5SDimitry Andric 43390b57cec5SDimitry Andric case ISD::LOAD: { 43400b57cec5SDimitry Andric // Try to select as an indexed load. Fall through to normal processing 43410b57cec5SDimitry Andric // if we can't. 43420b57cec5SDimitry Andric if (tryIndexedLoad(Node)) 43430b57cec5SDimitry Andric return; 43440b57cec5SDimitry Andric break; 43450b57cec5SDimitry Andric } 43460b57cec5SDimitry Andric 43470b57cec5SDimitry Andric case ISD::SRL: 43480b57cec5SDimitry Andric case ISD::AND: 43490b57cec5SDimitry Andric case ISD::SRA: 43500b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 43510b57cec5SDimitry Andric if (tryBitfieldExtractOp(Node)) 43520b57cec5SDimitry Andric return; 43530b57cec5SDimitry Andric if (tryBitfieldInsertInZeroOp(Node)) 43540b57cec5SDimitry Andric return; 4355bdd1243dSDimitry Andric [[fallthrough]]; 43560b57cec5SDimitry Andric case ISD::ROTR: 43570b57cec5SDimitry Andric case ISD::SHL: 43580b57cec5SDimitry Andric if (tryShiftAmountMod(Node)) 43590b57cec5SDimitry Andric return; 43600b57cec5SDimitry Andric break; 43610b57cec5SDimitry Andric 43620b57cec5SDimitry Andric case ISD::SIGN_EXTEND: 43630b57cec5SDimitry Andric if (tryBitfieldExtractOpFromSExt(Node)) 43640b57cec5SDimitry Andric return; 43650b57cec5SDimitry Andric break; 43660b57cec5SDimitry Andric 43670b57cec5SDimitry Andric case ISD::OR: 43680b57cec5SDimitry Andric if (tryBitfieldInsertOp(Node)) 43690b57cec5SDimitry Andric return; 43705f757f3fSDimitry Andric if (Subtarget->hasSHA3() && trySelectXAR(Node)) 43715f757f3fSDimitry Andric return; 43720b57cec5SDimitry Andric break; 43730b57cec5SDimitry Andric 43745ffd83dbSDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 437506c3fb27SDimitry Andric if (trySelectCastScalableToFixedLengthVector(Node)) 43765ffd83dbSDimitry Andric return; 437706c3fb27SDimitry Andric break; 43785ffd83dbSDimitry Andric } 43795ffd83dbSDimitry Andric 43805ffd83dbSDimitry Andric case ISD::INSERT_SUBVECTOR: { 438106c3fb27SDimitry Andric if (trySelectCastFixedLengthToScalableVector(Node)) 43825ffd83dbSDimitry Andric return; 438306c3fb27SDimitry Andric break; 43845ffd83dbSDimitry Andric } 43855ffd83dbSDimitry Andric 43860b57cec5SDimitry Andric case ISD::Constant: { 43870b57cec5SDimitry Andric // Materialize zero constants as copies from WZR/XZR. This allows 43880b57cec5SDimitry Andric // the coalescer to propagate these into other instructions. 43890b57cec5SDimitry Andric ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node); 4390349cc55cSDimitry Andric if (ConstNode->isZero()) { 43910b57cec5SDimitry Andric if (VT == MVT::i32) { 43920b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg( 43930b57cec5SDimitry Andric CurDAG->getEntryNode(), SDLoc(Node), AArch64::WZR, MVT::i32); 43940b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 43950b57cec5SDimitry Andric return; 43960b57cec5SDimitry Andric } else if (VT == MVT::i64) { 43970b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg( 43980b57cec5SDimitry Andric CurDAG->getEntryNode(), SDLoc(Node), AArch64::XZR, MVT::i64); 43990b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 44000b57cec5SDimitry Andric return; 44010b57cec5SDimitry Andric } 44020b57cec5SDimitry Andric } 44030b57cec5SDimitry Andric break; 44040b57cec5SDimitry Andric } 44050b57cec5SDimitry Andric 44060b57cec5SDimitry Andric case ISD::FrameIndex: { 44070b57cec5SDimitry Andric // Selects to ADDXri FI, 0 which in turn will become ADDXri SP, imm. 44080b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 44090b57cec5SDimitry Andric unsigned Shifter = AArch64_AM::getShifterImm(AArch64_AM::LSL, 0); 44100b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 44110b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex( 44120b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 44130b57cec5SDimitry Andric SDLoc DL(Node); 44140b57cec5SDimitry Andric SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, DL, MVT::i32), 44150b57cec5SDimitry Andric CurDAG->getTargetConstant(Shifter, DL, MVT::i32) }; 44160b57cec5SDimitry Andric CurDAG->SelectNodeTo(Node, AArch64::ADDXri, MVT::i64, Ops); 44170b57cec5SDimitry Andric return; 44180b57cec5SDimitry Andric } 44190b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 4420647cbc5dSDimitry Andric unsigned IntNo = Node->getConstantOperandVal(1); 44210b57cec5SDimitry Andric switch (IntNo) { 44220b57cec5SDimitry Andric default: 44230b57cec5SDimitry Andric break; 44240b57cec5SDimitry Andric case Intrinsic::aarch64_ldaxp: 44250b57cec5SDimitry Andric case Intrinsic::aarch64_ldxp: { 44260b57cec5SDimitry Andric unsigned Op = 44270b57cec5SDimitry Andric IntNo == Intrinsic::aarch64_ldaxp ? AArch64::LDAXPX : AArch64::LDXPX; 44280b57cec5SDimitry Andric SDValue MemAddr = Node->getOperand(2); 44290b57cec5SDimitry Andric SDLoc DL(Node); 44300b57cec5SDimitry Andric SDValue Chain = Node->getOperand(0); 44310b57cec5SDimitry Andric 44320b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Op, DL, MVT::i64, MVT::i64, 44330b57cec5SDimitry Andric MVT::Other, MemAddr, Chain); 44340b57cec5SDimitry Andric 44350b57cec5SDimitry Andric // Transfer memoperands. 44360b57cec5SDimitry Andric MachineMemOperand *MemOp = 44370b57cec5SDimitry Andric cast<MemIntrinsicSDNode>(Node)->getMemOperand(); 44380b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp}); 44390b57cec5SDimitry Andric ReplaceNode(Node, Ld); 44400b57cec5SDimitry Andric return; 44410b57cec5SDimitry Andric } 44420b57cec5SDimitry Andric case Intrinsic::aarch64_stlxp: 44430b57cec5SDimitry Andric case Intrinsic::aarch64_stxp: { 44440b57cec5SDimitry Andric unsigned Op = 44450b57cec5SDimitry Andric IntNo == Intrinsic::aarch64_stlxp ? AArch64::STLXPX : AArch64::STXPX; 44460b57cec5SDimitry Andric SDLoc DL(Node); 44470b57cec5SDimitry Andric SDValue Chain = Node->getOperand(0); 44480b57cec5SDimitry Andric SDValue ValLo = Node->getOperand(2); 44490b57cec5SDimitry Andric SDValue ValHi = Node->getOperand(3); 44500b57cec5SDimitry Andric SDValue MemAddr = Node->getOperand(4); 44510b57cec5SDimitry Andric 44520b57cec5SDimitry Andric // Place arguments in the right order. 44530b57cec5SDimitry Andric SDValue Ops[] = {ValLo, ValHi, MemAddr, Chain}; 44540b57cec5SDimitry Andric 44550b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Op, DL, MVT::i32, MVT::Other, Ops); 44560b57cec5SDimitry Andric // Transfer memoperands. 44570b57cec5SDimitry Andric MachineMemOperand *MemOp = 44580b57cec5SDimitry Andric cast<MemIntrinsicSDNode>(Node)->getMemOperand(); 44590b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 44600b57cec5SDimitry Andric 44610b57cec5SDimitry Andric ReplaceNode(Node, St); 44620b57cec5SDimitry Andric return; 44630b57cec5SDimitry Andric } 44640b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x2: 44650b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44660b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov8b, AArch64::dsub0); 44670b57cec5SDimitry Andric return; 44680b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44690b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov16b, AArch64::qsub0); 44700b57cec5SDimitry Andric return; 44715ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44720b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov4h, AArch64::dsub0); 44730b57cec5SDimitry Andric return; 44745ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 44750b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov8h, AArch64::qsub0); 44760b57cec5SDimitry Andric return; 44770b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 44780b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov2s, AArch64::dsub0); 44790b57cec5SDimitry Andric return; 44800b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 44810b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov4s, AArch64::qsub0); 44820b57cec5SDimitry Andric return; 44830b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 44840b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0); 44850b57cec5SDimitry Andric return; 44860b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 44870b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov2d, AArch64::qsub0); 44880b57cec5SDimitry Andric return; 44890b57cec5SDimitry Andric } 44900b57cec5SDimitry Andric break; 44910b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x3: 44920b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44930b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev8b, AArch64::dsub0); 44940b57cec5SDimitry Andric return; 44950b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44960b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev16b, AArch64::qsub0); 44970b57cec5SDimitry Andric return; 44985ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44990b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev4h, AArch64::dsub0); 45000b57cec5SDimitry Andric return; 45015ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45020b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev8h, AArch64::qsub0); 45030b57cec5SDimitry Andric return; 45040b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45050b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev2s, AArch64::dsub0); 45060b57cec5SDimitry Andric return; 45070b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45080b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev4s, AArch64::qsub0); 45090b57cec5SDimitry Andric return; 45100b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45110b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0); 45120b57cec5SDimitry Andric return; 45130b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45140b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev2d, AArch64::qsub0); 45150b57cec5SDimitry Andric return; 45160b57cec5SDimitry Andric } 45170b57cec5SDimitry Andric break; 45180b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x4: 45190b57cec5SDimitry Andric if (VT == MVT::v8i8) { 45200b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv8b, AArch64::dsub0); 45210b57cec5SDimitry Andric return; 45220b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45230b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv16b, AArch64::qsub0); 45240b57cec5SDimitry Andric return; 45255ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45260b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv4h, AArch64::dsub0); 45270b57cec5SDimitry Andric return; 45285ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45290b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv8h, AArch64::qsub0); 45300b57cec5SDimitry Andric return; 45310b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45320b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv2s, AArch64::dsub0); 45330b57cec5SDimitry Andric return; 45340b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45350b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv4s, AArch64::qsub0); 45360b57cec5SDimitry Andric return; 45370b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45380b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0); 45390b57cec5SDimitry Andric return; 45400b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45410b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv2d, AArch64::qsub0); 45420b57cec5SDimitry Andric return; 45430b57cec5SDimitry Andric } 45440b57cec5SDimitry Andric break; 45450b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2: 45460b57cec5SDimitry Andric if (VT == MVT::v8i8) { 45470b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov8b, AArch64::dsub0); 45480b57cec5SDimitry Andric return; 45490b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45500b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov16b, AArch64::qsub0); 45510b57cec5SDimitry Andric return; 45525ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45530b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov4h, AArch64::dsub0); 45540b57cec5SDimitry Andric return; 45555ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45560b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov8h, AArch64::qsub0); 45570b57cec5SDimitry Andric return; 45580b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45590b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov2s, AArch64::dsub0); 45600b57cec5SDimitry Andric return; 45610b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45620b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov4s, AArch64::qsub0); 45630b57cec5SDimitry Andric return; 45640b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45650b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0); 45660b57cec5SDimitry Andric return; 45670b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45680b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov2d, AArch64::qsub0); 45690b57cec5SDimitry Andric return; 45700b57cec5SDimitry Andric } 45710b57cec5SDimitry Andric break; 45720b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3: 45730b57cec5SDimitry Andric if (VT == MVT::v8i8) { 45740b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev8b, AArch64::dsub0); 45750b57cec5SDimitry Andric return; 45760b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 45770b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev16b, AArch64::qsub0); 45780b57cec5SDimitry Andric return; 45795ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 45800b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev4h, AArch64::dsub0); 45810b57cec5SDimitry Andric return; 45825ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 45830b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev8h, AArch64::qsub0); 45840b57cec5SDimitry Andric return; 45850b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45860b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev2s, AArch64::dsub0); 45870b57cec5SDimitry Andric return; 45880b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45890b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev4s, AArch64::qsub0); 45900b57cec5SDimitry Andric return; 45910b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45920b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0); 45930b57cec5SDimitry Andric return; 45940b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45950b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev2d, AArch64::qsub0); 45960b57cec5SDimitry Andric return; 45970b57cec5SDimitry Andric } 45980b57cec5SDimitry Andric break; 45990b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4: 46000b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46010b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv8b, AArch64::dsub0); 46020b57cec5SDimitry Andric return; 46030b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46040b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv16b, AArch64::qsub0); 46050b57cec5SDimitry Andric return; 46065ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46070b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv4h, AArch64::dsub0); 46080b57cec5SDimitry Andric return; 46095ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46100b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv8h, AArch64::qsub0); 46110b57cec5SDimitry Andric return; 46120b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46130b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv2s, AArch64::dsub0); 46140b57cec5SDimitry Andric return; 46150b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46160b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv4s, AArch64::qsub0); 46170b57cec5SDimitry Andric return; 46180b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 46190b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0); 46200b57cec5SDimitry Andric return; 46210b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46220b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv2d, AArch64::qsub0); 46230b57cec5SDimitry Andric return; 46240b57cec5SDimitry Andric } 46250b57cec5SDimitry Andric break; 46260b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2r: 46270b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46280b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv8b, AArch64::dsub0); 46290b57cec5SDimitry Andric return; 46300b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46310b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv16b, AArch64::qsub0); 46320b57cec5SDimitry Andric return; 46335ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46340b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv4h, AArch64::dsub0); 46350b57cec5SDimitry Andric return; 46365ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46370b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv8h, AArch64::qsub0); 46380b57cec5SDimitry Andric return; 46390b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46400b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv2s, AArch64::dsub0); 46410b57cec5SDimitry Andric return; 46420b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46430b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv4s, AArch64::qsub0); 46440b57cec5SDimitry Andric return; 46450b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 46460b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv1d, AArch64::dsub0); 46470b57cec5SDimitry Andric return; 46480b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46490b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv2d, AArch64::qsub0); 46500b57cec5SDimitry Andric return; 46510b57cec5SDimitry Andric } 46520b57cec5SDimitry Andric break; 46530b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3r: 46540b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46550b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv8b, AArch64::dsub0); 46560b57cec5SDimitry Andric return; 46570b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46580b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv16b, AArch64::qsub0); 46590b57cec5SDimitry Andric return; 46605ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46610b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv4h, AArch64::dsub0); 46620b57cec5SDimitry Andric return; 46635ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46640b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv8h, AArch64::qsub0); 46650b57cec5SDimitry Andric return; 46660b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46670b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv2s, AArch64::dsub0); 46680b57cec5SDimitry Andric return; 46690b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46700b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv4s, AArch64::qsub0); 46710b57cec5SDimitry Andric return; 46720b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 46730b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv1d, AArch64::dsub0); 46740b57cec5SDimitry Andric return; 46750b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 46760b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv2d, AArch64::qsub0); 46770b57cec5SDimitry Andric return; 46780b57cec5SDimitry Andric } 46790b57cec5SDimitry Andric break; 46800b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4r: 46810b57cec5SDimitry Andric if (VT == MVT::v8i8) { 46820b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv8b, AArch64::dsub0); 46830b57cec5SDimitry Andric return; 46840b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 46850b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv16b, AArch64::qsub0); 46860b57cec5SDimitry Andric return; 46875ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 46880b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv4h, AArch64::dsub0); 46890b57cec5SDimitry Andric return; 46905ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 46910b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv8h, AArch64::qsub0); 46920b57cec5SDimitry Andric return; 46930b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 46940b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv2s, AArch64::dsub0); 46950b57cec5SDimitry Andric return; 46960b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 46970b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv4s, AArch64::qsub0); 46980b57cec5SDimitry Andric return; 46990b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 47000b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv1d, AArch64::dsub0); 47010b57cec5SDimitry Andric return; 47020b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 47030b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv2d, AArch64::qsub0); 47040b57cec5SDimitry Andric return; 47050b57cec5SDimitry Andric } 47060b57cec5SDimitry Andric break; 47070b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2lane: 47080b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 47090b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i8); 47100b57cec5SDimitry Andric return; 47110b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 47125ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 47130b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i16); 47140b57cec5SDimitry Andric return; 47150b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 47160b57cec5SDimitry Andric VT == MVT::v2f32) { 47170b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i32); 47180b57cec5SDimitry Andric return; 47190b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 47200b57cec5SDimitry Andric VT == MVT::v1f64) { 47210b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i64); 47220b57cec5SDimitry Andric return; 47230b57cec5SDimitry Andric } 47240b57cec5SDimitry Andric break; 47250b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3lane: 47260b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 47270b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i8); 47280b57cec5SDimitry Andric return; 47290b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 47305ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 47310b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i16); 47320b57cec5SDimitry Andric return; 47330b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 47340b57cec5SDimitry Andric VT == MVT::v2f32) { 47350b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i32); 47360b57cec5SDimitry Andric return; 47370b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 47380b57cec5SDimitry Andric VT == MVT::v1f64) { 47390b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i64); 47400b57cec5SDimitry Andric return; 47410b57cec5SDimitry Andric } 47420b57cec5SDimitry Andric break; 47430b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4lane: 47440b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 47450b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i8); 47460b57cec5SDimitry Andric return; 47470b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 47485ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 47490b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i16); 47500b57cec5SDimitry Andric return; 47510b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 47520b57cec5SDimitry Andric VT == MVT::v2f32) { 47530b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i32); 47540b57cec5SDimitry Andric return; 47550b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 47560b57cec5SDimitry Andric VT == MVT::v1f64) { 47570b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i64); 47580b57cec5SDimitry Andric return; 47590b57cec5SDimitry Andric } 47600b57cec5SDimitry Andric break; 4761e8d8bef9SDimitry Andric case Intrinsic::aarch64_ld64b: 4762e8d8bef9SDimitry Andric SelectLoad(Node, 8, AArch64::LD64B, AArch64::x8sub_0); 4763e8d8bef9SDimitry Andric return; 47645f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld2q_sret: { 47655f757f3fSDimitry Andric SelectPredicatedLoad(Node, 2, 4, AArch64::LD2Q_IMM, AArch64::LD2Q, true); 47665f757f3fSDimitry Andric return; 47675f757f3fSDimitry Andric } 47685f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld3q_sret: { 47695f757f3fSDimitry Andric SelectPredicatedLoad(Node, 3, 4, AArch64::LD3Q_IMM, AArch64::LD3Q, true); 47705f757f3fSDimitry Andric return; 47715f757f3fSDimitry Andric } 47725f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld4q_sret: { 47735f757f3fSDimitry Andric SelectPredicatedLoad(Node, 4, 4, AArch64::LD4Q_IMM, AArch64::LD4Q, true); 47745f757f3fSDimitry Andric return; 47755f757f3fSDimitry Andric } 4776349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: { 4777349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4778349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B, 4779349cc55cSDimitry Andric true); 4780349cc55cSDimitry Andric return; 4781349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 478281ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4783349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H, 4784349cc55cSDimitry Andric true); 4785349cc55cSDimitry Andric return; 4786349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4787349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W, 4788349cc55cSDimitry Andric true); 4789349cc55cSDimitry Andric return; 4790349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4791349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D, 4792349cc55cSDimitry Andric true); 4793349cc55cSDimitry Andric return; 4794349cc55cSDimitry Andric } 4795349cc55cSDimitry Andric break; 4796349cc55cSDimitry Andric } 479706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ld1_pn_x2: { 479806c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 47995f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48005f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48015f757f3fSDimitry Andric Node, 2, 0, AArch64::LD1B_2Z_IMM_PSEUDO, AArch64::LD1B_2Z_PSEUDO); 48025f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48035f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 0, AArch64::LD1B_2Z_IMM, 48045f757f3fSDimitry Andric AArch64::LD1B_2Z); 48055f757f3fSDimitry Andric else 48065f757f3fSDimitry Andric break; 480706c3fb27SDimitry Andric return; 480806c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 480906c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 48105f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48115f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48125f757f3fSDimitry Andric Node, 2, 1, AArch64::LD1H_2Z_IMM_PSEUDO, AArch64::LD1H_2Z_PSEUDO); 48135f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48145f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 1, AArch64::LD1H_2Z_IMM, 48155f757f3fSDimitry Andric AArch64::LD1H_2Z); 48165f757f3fSDimitry Andric else 48175f757f3fSDimitry Andric break; 481806c3fb27SDimitry Andric return; 481906c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 48205f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48215f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48225f757f3fSDimitry Andric Node, 2, 2, AArch64::LD1W_2Z_IMM_PSEUDO, AArch64::LD1W_2Z_PSEUDO); 48235f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48245f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 2, AArch64::LD1W_2Z_IMM, 48255f757f3fSDimitry Andric AArch64::LD1W_2Z); 48265f757f3fSDimitry Andric else 48275f757f3fSDimitry Andric break; 482806c3fb27SDimitry Andric return; 482906c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 48305f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48315f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48325f757f3fSDimitry Andric Node, 2, 3, AArch64::LD1D_2Z_IMM_PSEUDO, AArch64::LD1D_2Z_PSEUDO); 48335f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48345f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 3, AArch64::LD1D_2Z_IMM, 48355f757f3fSDimitry Andric AArch64::LD1D_2Z); 48365f757f3fSDimitry Andric else 48375f757f3fSDimitry Andric break; 483806c3fb27SDimitry Andric return; 483906c3fb27SDimitry Andric } 484006c3fb27SDimitry Andric break; 484106c3fb27SDimitry Andric } 484206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ld1_pn_x4: { 484306c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 48445f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48455f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48465f757f3fSDimitry Andric Node, 4, 0, AArch64::LD1B_4Z_IMM_PSEUDO, AArch64::LD1B_4Z_PSEUDO); 48475f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48485f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 0, AArch64::LD1B_4Z_IMM, 48495f757f3fSDimitry Andric AArch64::LD1B_4Z); 48505f757f3fSDimitry Andric else 48515f757f3fSDimitry Andric break; 485206c3fb27SDimitry Andric return; 485306c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 485406c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 48555f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48565f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48575f757f3fSDimitry Andric Node, 4, 1, AArch64::LD1H_4Z_IMM_PSEUDO, AArch64::LD1H_4Z_PSEUDO); 48585f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48595f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 1, AArch64::LD1H_4Z_IMM, 48605f757f3fSDimitry Andric AArch64::LD1H_4Z); 48615f757f3fSDimitry Andric else 48625f757f3fSDimitry Andric break; 486306c3fb27SDimitry Andric return; 486406c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 48655f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48665f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48675f757f3fSDimitry Andric Node, 4, 2, AArch64::LD1W_4Z_IMM_PSEUDO, AArch64::LD1W_4Z_PSEUDO); 48685f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48695f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 2, AArch64::LD1W_4Z_IMM, 48705f757f3fSDimitry Andric AArch64::LD1W_4Z); 48715f757f3fSDimitry Andric else 48725f757f3fSDimitry Andric break; 487306c3fb27SDimitry Andric return; 487406c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 48755f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48765f757f3fSDimitry Andric SelectContiguousMultiVectorLoad( 48775f757f3fSDimitry Andric Node, 4, 3, AArch64::LD1D_4Z_IMM_PSEUDO, AArch64::LD1D_4Z_PSEUDO); 48785f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48795f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 3, AArch64::LD1D_4Z_IMM, 48805f757f3fSDimitry Andric AArch64::LD1D_4Z); 48815f757f3fSDimitry Andric else 48825f757f3fSDimitry Andric break; 488306c3fb27SDimitry Andric return; 488406c3fb27SDimitry Andric } 488506c3fb27SDimitry Andric break; 488606c3fb27SDimitry Andric } 488706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ldnt1_pn_x2: { 488806c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 48895f757f3fSDimitry Andric if (Subtarget->hasSME2()) 48905f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 0, 48915f757f3fSDimitry Andric AArch64::LDNT1B_2Z_IMM_PSEUDO, 48925f757f3fSDimitry Andric AArch64::LDNT1B_2Z_PSEUDO); 48935f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 48945f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 0, AArch64::LDNT1B_2Z_IMM, 48955f757f3fSDimitry Andric AArch64::LDNT1B_2Z); 48965f757f3fSDimitry Andric else 48975f757f3fSDimitry Andric break; 489806c3fb27SDimitry Andric return; 489906c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 490006c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 49015f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49025f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 1, 49035f757f3fSDimitry Andric AArch64::LDNT1H_2Z_IMM_PSEUDO, 49045f757f3fSDimitry Andric AArch64::LDNT1H_2Z_PSEUDO); 49055f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49065f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 1, AArch64::LDNT1H_2Z_IMM, 49075f757f3fSDimitry Andric AArch64::LDNT1H_2Z); 49085f757f3fSDimitry Andric else 49095f757f3fSDimitry Andric break; 491006c3fb27SDimitry Andric return; 491106c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 49125f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49135f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 2, 49145f757f3fSDimitry Andric AArch64::LDNT1W_2Z_IMM_PSEUDO, 49155f757f3fSDimitry Andric AArch64::LDNT1W_2Z_PSEUDO); 49165f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49175f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 2, AArch64::LDNT1W_2Z_IMM, 49185f757f3fSDimitry Andric AArch64::LDNT1W_2Z); 49195f757f3fSDimitry Andric else 49205f757f3fSDimitry Andric break; 492106c3fb27SDimitry Andric return; 492206c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 49235f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49245f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 3, 49255f757f3fSDimitry Andric AArch64::LDNT1D_2Z_IMM_PSEUDO, 49265f757f3fSDimitry Andric AArch64::LDNT1D_2Z_PSEUDO); 49275f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49285f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 2, 3, AArch64::LDNT1D_2Z_IMM, 49295f757f3fSDimitry Andric AArch64::LDNT1D_2Z); 49305f757f3fSDimitry Andric else 49315f757f3fSDimitry Andric break; 493206c3fb27SDimitry Andric return; 493306c3fb27SDimitry Andric } 493406c3fb27SDimitry Andric break; 493506c3fb27SDimitry Andric } 493606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_ldnt1_pn_x4: { 493706c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 49385f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49395f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 0, 49405f757f3fSDimitry Andric AArch64::LDNT1B_4Z_IMM_PSEUDO, 49415f757f3fSDimitry Andric AArch64::LDNT1B_4Z_PSEUDO); 49425f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49435f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 0, AArch64::LDNT1B_4Z_IMM, 49445f757f3fSDimitry Andric AArch64::LDNT1B_4Z); 49455f757f3fSDimitry Andric else 49465f757f3fSDimitry Andric break; 494706c3fb27SDimitry Andric return; 494806c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 494906c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 49505f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49515f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 1, 49525f757f3fSDimitry Andric AArch64::LDNT1H_4Z_IMM_PSEUDO, 49535f757f3fSDimitry Andric AArch64::LDNT1H_4Z_PSEUDO); 49545f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49555f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 1, AArch64::LDNT1H_4Z_IMM, 49565f757f3fSDimitry Andric AArch64::LDNT1H_4Z); 49575f757f3fSDimitry Andric else 49585f757f3fSDimitry Andric break; 495906c3fb27SDimitry Andric return; 496006c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 49615f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49625f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 2, 49635f757f3fSDimitry Andric AArch64::LDNT1W_4Z_IMM_PSEUDO, 49645f757f3fSDimitry Andric AArch64::LDNT1W_4Z_PSEUDO); 49655f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49665f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 2, AArch64::LDNT1W_4Z_IMM, 49675f757f3fSDimitry Andric AArch64::LDNT1W_4Z); 49685f757f3fSDimitry Andric else 49695f757f3fSDimitry Andric break; 497006c3fb27SDimitry Andric return; 497106c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 49725f757f3fSDimitry Andric if (Subtarget->hasSME2()) 49735f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 3, 49745f757f3fSDimitry Andric AArch64::LDNT1D_4Z_IMM_PSEUDO, 49755f757f3fSDimitry Andric AArch64::LDNT1D_4Z_PSEUDO); 49765f757f3fSDimitry Andric else if (Subtarget->hasSVE2p1()) 49775f757f3fSDimitry Andric SelectContiguousMultiVectorLoad(Node, 4, 3, AArch64::LDNT1D_4Z_IMM, 49785f757f3fSDimitry Andric AArch64::LDNT1D_4Z); 49795f757f3fSDimitry Andric else 49805f757f3fSDimitry Andric break; 498106c3fb27SDimitry Andric return; 498206c3fb27SDimitry Andric } 498306c3fb27SDimitry Andric break; 498406c3fb27SDimitry Andric } 4985349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: { 4986349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4987349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B, 4988349cc55cSDimitry Andric true); 4989349cc55cSDimitry Andric return; 4990349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 499181ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4992349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H, 4993349cc55cSDimitry Andric true); 4994349cc55cSDimitry Andric return; 4995349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4996349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W, 4997349cc55cSDimitry Andric true); 4998349cc55cSDimitry Andric return; 4999349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5000349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D, 5001349cc55cSDimitry Andric true); 5002349cc55cSDimitry Andric return; 5003349cc55cSDimitry Andric } 5004349cc55cSDimitry Andric break; 5005349cc55cSDimitry Andric } 5006349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: { 5007349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 5008349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B, 5009349cc55cSDimitry Andric true); 5010349cc55cSDimitry Andric return; 5011349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 501281ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5013349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H, 5014349cc55cSDimitry Andric true); 5015349cc55cSDimitry Andric return; 5016349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5017349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W, 5018349cc55cSDimitry Andric true); 5019349cc55cSDimitry Andric return; 5020349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5021349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D, 5022349cc55cSDimitry Andric true); 5023349cc55cSDimitry Andric return; 5024349cc55cSDimitry Andric } 5025349cc55cSDimitry Andric break; 5026349cc55cSDimitry Andric } 502706c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_hor_vg2: { 502806c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 502906c3fb27SDimitry Andric SelectMultiVectorMove<14, 2>(Node, 2, AArch64::ZAB0, 503006c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_B); 503106c3fb27SDimitry Andric return; 503206c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 503306c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 503406c3fb27SDimitry Andric SelectMultiVectorMove<6, 2>(Node, 2, AArch64::ZAH0, 503506c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_H); 503606c3fb27SDimitry Andric return; 503706c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 503806c3fb27SDimitry Andric SelectMultiVectorMove<2, 2>(Node, 2, AArch64::ZAS0, 503906c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_S); 504006c3fb27SDimitry Andric return; 504106c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 504206c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 2, AArch64::ZAD0, 504306c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_H_D); 504406c3fb27SDimitry Andric return; 504506c3fb27SDimitry Andric } 504606c3fb27SDimitry Andric break; 504706c3fb27SDimitry Andric } 504806c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_ver_vg2: { 504906c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 505006c3fb27SDimitry Andric SelectMultiVectorMove<14, 2>(Node, 2, AArch64::ZAB0, 505106c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_B); 505206c3fb27SDimitry Andric return; 505306c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 505406c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 505506c3fb27SDimitry Andric SelectMultiVectorMove<6, 2>(Node, 2, AArch64::ZAH0, 505606c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_H); 505706c3fb27SDimitry Andric return; 505806c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 505906c3fb27SDimitry Andric SelectMultiVectorMove<2, 2>(Node, 2, AArch64::ZAS0, 506006c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_S); 506106c3fb27SDimitry Andric return; 506206c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 506306c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 2, AArch64::ZAD0, 506406c3fb27SDimitry Andric AArch64::MOVA_2ZMXI_V_D); 506506c3fb27SDimitry Andric return; 506606c3fb27SDimitry Andric } 506706c3fb27SDimitry Andric break; 506806c3fb27SDimitry Andric } 506906c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_hor_vg4: { 507006c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 507106c3fb27SDimitry Andric SelectMultiVectorMove<12, 4>(Node, 4, AArch64::ZAB0, 507206c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_B); 507306c3fb27SDimitry Andric return; 507406c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 507506c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 507606c3fb27SDimitry Andric SelectMultiVectorMove<4, 4>(Node, 4, AArch64::ZAH0, 507706c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_H); 507806c3fb27SDimitry Andric return; 507906c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 508006c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 4, AArch64::ZAS0, 508106c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_S); 508206c3fb27SDimitry Andric return; 508306c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 508406c3fb27SDimitry Andric SelectMultiVectorMove<0, 2>(Node, 4, AArch64::ZAD0, 508506c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_H_D); 508606c3fb27SDimitry Andric return; 508706c3fb27SDimitry Andric } 508806c3fb27SDimitry Andric break; 508906c3fb27SDimitry Andric } 509006c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_ver_vg4: { 509106c3fb27SDimitry Andric if (VT == MVT::nxv16i8) { 509206c3fb27SDimitry Andric SelectMultiVectorMove<12, 4>(Node, 4, AArch64::ZAB0, 509306c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_B); 509406c3fb27SDimitry Andric return; 509506c3fb27SDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 509606c3fb27SDimitry Andric VT == MVT::nxv8bf16) { 509706c3fb27SDimitry Andric SelectMultiVectorMove<4, 4>(Node, 4, AArch64::ZAH0, 509806c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_H); 509906c3fb27SDimitry Andric return; 510006c3fb27SDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 510106c3fb27SDimitry Andric SelectMultiVectorMove<0, 4>(Node, 4, AArch64::ZAS0, 510206c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_S); 510306c3fb27SDimitry Andric return; 510406c3fb27SDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 510506c3fb27SDimitry Andric SelectMultiVectorMove<0, 4>(Node, 4, AArch64::ZAD0, 510606c3fb27SDimitry Andric AArch64::MOVA_4ZMXI_V_D); 510706c3fb27SDimitry Andric return; 510806c3fb27SDimitry Andric } 510906c3fb27SDimitry Andric break; 511006c3fb27SDimitry Andric } 511106c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_vg1x2: { 511206c3fb27SDimitry Andric SelectMultiVectorMove<7, 1>(Node, 2, AArch64::ZA, 511306c3fb27SDimitry Andric AArch64::MOVA_VG2_2ZMXI); 511406c3fb27SDimitry Andric return; 511506c3fb27SDimitry Andric } 511606c3fb27SDimitry Andric case Intrinsic::aarch64_sme_read_vg1x4: { 511706c3fb27SDimitry Andric SelectMultiVectorMove<7, 1>(Node, 4, AArch64::ZA, 511806c3fb27SDimitry Andric AArch64::MOVA_VG4_4ZMXI); 511906c3fb27SDimitry Andric return; 512006c3fb27SDimitry Andric } 5121fcaf7f86SDimitry Andric case Intrinsic::swift_async_context_addr: { 5122fcaf7f86SDimitry Andric SDLoc DL(Node); 5123fcaf7f86SDimitry Andric SDValue Chain = Node->getOperand(0); 5124fcaf7f86SDimitry Andric SDValue CopyFP = CurDAG->getCopyFromReg(Chain, DL, AArch64::FP, MVT::i64); 5125fcaf7f86SDimitry Andric SDValue Res = SDValue( 5126fcaf7f86SDimitry Andric CurDAG->getMachineNode(AArch64::SUBXri, DL, MVT::i64, CopyFP, 5127fcaf7f86SDimitry Andric CurDAG->getTargetConstant(8, DL, MVT::i32), 5128fcaf7f86SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i32)), 5129fcaf7f86SDimitry Andric 0); 5130fcaf7f86SDimitry Andric ReplaceUses(SDValue(Node, 0), Res); 5131fcaf7f86SDimitry Andric ReplaceUses(SDValue(Node, 1), CopyFP.getValue(1)); 5132fcaf7f86SDimitry Andric CurDAG->RemoveDeadNode(Node); 5133fcaf7f86SDimitry Andric 5134fcaf7f86SDimitry Andric auto &MF = CurDAG->getMachineFunction(); 5135fcaf7f86SDimitry Andric MF.getFrameInfo().setFrameAddressIsTaken(true); 5136fcaf7f86SDimitry Andric MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); 5137fcaf7f86SDimitry Andric return; 5138fcaf7f86SDimitry Andric } 51395f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti2_lane_zt_x4: { 51405f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 51415f757f3fSDimitry Andric Node->getValueType(0), 51425f757f3fSDimitry Andric {AArch64::LUTI2_4ZTZI_B, AArch64::LUTI2_4ZTZI_H, 51435f757f3fSDimitry Andric AArch64::LUTI2_4ZTZI_S})) 51445f757f3fSDimitry Andric // Second Immediate must be <= 3: 51455f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 4, Opc, 3); 51465f757f3fSDimitry Andric return; 51475f757f3fSDimitry Andric } 51485f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti4_lane_zt_x4: { 51495f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 51505f757f3fSDimitry Andric Node->getValueType(0), 51515f757f3fSDimitry Andric {0, AArch64::LUTI4_4ZTZI_H, AArch64::LUTI4_4ZTZI_S})) 51525f757f3fSDimitry Andric // Second Immediate must be <= 1: 51535f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 4, Opc, 1); 51545f757f3fSDimitry Andric return; 51555f757f3fSDimitry Andric } 51565f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti2_lane_zt_x2: { 51575f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 51585f757f3fSDimitry Andric Node->getValueType(0), 51595f757f3fSDimitry Andric {AArch64::LUTI2_2ZTZI_B, AArch64::LUTI2_2ZTZI_H, 51605f757f3fSDimitry Andric AArch64::LUTI2_2ZTZI_S})) 51615f757f3fSDimitry Andric // Second Immediate must be <= 7: 51625f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 2, Opc, 7); 51635f757f3fSDimitry Andric return; 51645f757f3fSDimitry Andric } 51655f757f3fSDimitry Andric case Intrinsic::aarch64_sme_luti4_lane_zt_x2: { 51665f757f3fSDimitry Andric if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 51675f757f3fSDimitry Andric Node->getValueType(0), 51685f757f3fSDimitry Andric {AArch64::LUTI4_2ZTZI_B, AArch64::LUTI4_2ZTZI_H, 51695f757f3fSDimitry Andric AArch64::LUTI4_2ZTZI_S})) 51705f757f3fSDimitry Andric // Second Immediate must be <= 3: 51715f757f3fSDimitry Andric SelectMultiVectorLuti(Node, 2, Opc, 3); 51725f757f3fSDimitry Andric return; 51735f757f3fSDimitry Andric } 51740b57cec5SDimitry Andric } 51750b57cec5SDimitry Andric } break; 51760b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 5177647cbc5dSDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 51780b57cec5SDimitry Andric switch (IntNo) { 51790b57cec5SDimitry Andric default: 51800b57cec5SDimitry Andric break; 51810b57cec5SDimitry Andric case Intrinsic::aarch64_tagp: 51820b57cec5SDimitry Andric SelectTagP(Node); 51830b57cec5SDimitry Andric return; 51840b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl2: 51850b57cec5SDimitry Andric SelectTable(Node, 2, 51860b57cec5SDimitry Andric VT == MVT::v8i8 ? AArch64::TBLv8i8Two : AArch64::TBLv16i8Two, 51870b57cec5SDimitry Andric false); 51880b57cec5SDimitry Andric return; 51890b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl3: 51900b57cec5SDimitry Andric SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBLv8i8Three 51910b57cec5SDimitry Andric : AArch64::TBLv16i8Three, 51920b57cec5SDimitry Andric false); 51930b57cec5SDimitry Andric return; 51940b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl4: 51950b57cec5SDimitry Andric SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBLv8i8Four 51960b57cec5SDimitry Andric : AArch64::TBLv16i8Four, 51970b57cec5SDimitry Andric false); 51980b57cec5SDimitry Andric return; 51990b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx2: 52000b57cec5SDimitry Andric SelectTable(Node, 2, 52010b57cec5SDimitry Andric VT == MVT::v8i8 ? AArch64::TBXv8i8Two : AArch64::TBXv16i8Two, 52020b57cec5SDimitry Andric true); 52030b57cec5SDimitry Andric return; 52040b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx3: 52050b57cec5SDimitry Andric SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBXv8i8Three 52060b57cec5SDimitry Andric : AArch64::TBXv16i8Three, 52070b57cec5SDimitry Andric true); 52080b57cec5SDimitry Andric return; 52090b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx4: 52100b57cec5SDimitry Andric SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBXv8i8Four 52110b57cec5SDimitry Andric : AArch64::TBXv16i8Four, 52120b57cec5SDimitry Andric true); 52130b57cec5SDimitry Andric return; 521406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_single_x2: 521506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 521606c3fb27SDimitry Andric Node->getValueType(0), 521706c3fb27SDimitry Andric {AArch64::SRSHL_VG2_2ZZ_B, AArch64::SRSHL_VG2_2ZZ_H, 521806c3fb27SDimitry Andric AArch64::SRSHL_VG2_2ZZ_S, AArch64::SRSHL_VG2_2ZZ_D})) 521906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 52200b57cec5SDimitry Andric return; 522106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_single_x4: 522206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 522306c3fb27SDimitry Andric Node->getValueType(0), 522406c3fb27SDimitry Andric {AArch64::SRSHL_VG4_4ZZ_B, AArch64::SRSHL_VG4_4ZZ_H, 522506c3fb27SDimitry Andric AArch64::SRSHL_VG4_4ZZ_S, AArch64::SRSHL_VG4_4ZZ_D})) 522606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 522706c3fb27SDimitry Andric return; 522806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_single_x2: 522906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 523006c3fb27SDimitry Andric Node->getValueType(0), 523106c3fb27SDimitry Andric {AArch64::URSHL_VG2_2ZZ_B, AArch64::URSHL_VG2_2ZZ_H, 523206c3fb27SDimitry Andric AArch64::URSHL_VG2_2ZZ_S, AArch64::URSHL_VG2_2ZZ_D})) 523306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 523406c3fb27SDimitry Andric return; 523506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_single_x4: 523606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 523706c3fb27SDimitry Andric Node->getValueType(0), 523806c3fb27SDimitry Andric {AArch64::URSHL_VG4_4ZZ_B, AArch64::URSHL_VG4_4ZZ_H, 523906c3fb27SDimitry Andric AArch64::URSHL_VG4_4ZZ_S, AArch64::URSHL_VG4_4ZZ_D})) 524006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 524106c3fb27SDimitry Andric return; 524206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_x2: 524306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 524406c3fb27SDimitry Andric Node->getValueType(0), 524506c3fb27SDimitry Andric {AArch64::SRSHL_VG2_2Z2Z_B, AArch64::SRSHL_VG2_2Z2Z_H, 524606c3fb27SDimitry Andric AArch64::SRSHL_VG2_2Z2Z_S, AArch64::SRSHL_VG2_2Z2Z_D})) 524706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 524806c3fb27SDimitry Andric return; 524906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_srshl_x4: 525006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 525106c3fb27SDimitry Andric Node->getValueType(0), 525206c3fb27SDimitry Andric {AArch64::SRSHL_VG4_4Z4Z_B, AArch64::SRSHL_VG4_4Z4Z_H, 525306c3fb27SDimitry Andric AArch64::SRSHL_VG4_4Z4Z_S, AArch64::SRSHL_VG4_4Z4Z_D})) 525406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 525506c3fb27SDimitry Andric return; 525606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_x2: 525706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 525806c3fb27SDimitry Andric Node->getValueType(0), 525906c3fb27SDimitry Andric {AArch64::URSHL_VG2_2Z2Z_B, AArch64::URSHL_VG2_2Z2Z_H, 526006c3fb27SDimitry Andric AArch64::URSHL_VG2_2Z2Z_S, AArch64::URSHL_VG2_2Z2Z_D})) 526106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 526206c3fb27SDimitry Andric return; 526306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_urshl_x4: 526406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 526506c3fb27SDimitry Andric Node->getValueType(0), 526606c3fb27SDimitry Andric {AArch64::URSHL_VG4_4Z4Z_B, AArch64::URSHL_VG4_4Z4Z_H, 526706c3fb27SDimitry Andric AArch64::URSHL_VG4_4Z4Z_S, AArch64::URSHL_VG4_4Z4Z_D})) 526806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 526906c3fb27SDimitry Andric return; 527006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_single_vgx2: 527106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 527206c3fb27SDimitry Andric Node->getValueType(0), 527306c3fb27SDimitry Andric {AArch64::SQDMULH_VG2_2ZZ_B, AArch64::SQDMULH_VG2_2ZZ_H, 527406c3fb27SDimitry Andric AArch64::SQDMULH_VG2_2ZZ_S, AArch64::SQDMULH_VG2_2ZZ_D})) 527506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 527606c3fb27SDimitry Andric return; 527706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_single_vgx4: 527806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 527906c3fb27SDimitry Andric Node->getValueType(0), 528006c3fb27SDimitry Andric {AArch64::SQDMULH_VG4_4ZZ_B, AArch64::SQDMULH_VG4_4ZZ_H, 528106c3fb27SDimitry Andric AArch64::SQDMULH_VG4_4ZZ_S, AArch64::SQDMULH_VG4_4ZZ_D})) 528206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 528306c3fb27SDimitry Andric return; 528406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_vgx2: 528506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 528606c3fb27SDimitry Andric Node->getValueType(0), 528706c3fb27SDimitry Andric {AArch64::SQDMULH_VG2_2Z2Z_B, AArch64::SQDMULH_VG2_2Z2Z_H, 528806c3fb27SDimitry Andric AArch64::SQDMULH_VG2_2Z2Z_S, AArch64::SQDMULH_VG2_2Z2Z_D})) 528906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 529006c3fb27SDimitry Andric return; 529106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sqdmulh_vgx4: 529206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 529306c3fb27SDimitry Andric Node->getValueType(0), 529406c3fb27SDimitry Andric {AArch64::SQDMULH_VG4_4Z4Z_B, AArch64::SQDMULH_VG4_4Z4Z_H, 529506c3fb27SDimitry Andric AArch64::SQDMULH_VG4_4Z4Z_S, AArch64::SQDMULH_VG4_4Z4Z_D})) 529606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 529706c3fb27SDimitry Andric return; 5298bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilege_x2: 5299bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5300bdd1243dSDimitry Andric Node->getValueType(0), 5301bdd1243dSDimitry Andric {AArch64::WHILEGE_2PXX_B, AArch64::WHILEGE_2PXX_H, 5302bdd1243dSDimitry Andric AArch64::WHILEGE_2PXX_S, AArch64::WHILEGE_2PXX_D})) 5303bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5304bdd1243dSDimitry Andric return; 5305bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilegt_x2: 5306bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5307bdd1243dSDimitry Andric Node->getValueType(0), 5308bdd1243dSDimitry Andric {AArch64::WHILEGT_2PXX_B, AArch64::WHILEGT_2PXX_H, 5309bdd1243dSDimitry Andric AArch64::WHILEGT_2PXX_S, AArch64::WHILEGT_2PXX_D})) 5310bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5311bdd1243dSDimitry Andric return; 5312bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilehi_x2: 5313bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5314bdd1243dSDimitry Andric Node->getValueType(0), 5315bdd1243dSDimitry Andric {AArch64::WHILEHI_2PXX_B, AArch64::WHILEHI_2PXX_H, 5316bdd1243dSDimitry Andric AArch64::WHILEHI_2PXX_S, AArch64::WHILEHI_2PXX_D})) 5317bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5318bdd1243dSDimitry Andric return; 5319bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilehs_x2: 5320bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5321bdd1243dSDimitry Andric Node->getValueType(0), 5322bdd1243dSDimitry Andric {AArch64::WHILEHS_2PXX_B, AArch64::WHILEHS_2PXX_H, 5323bdd1243dSDimitry Andric AArch64::WHILEHS_2PXX_S, AArch64::WHILEHS_2PXX_D})) 5324bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5325bdd1243dSDimitry Andric return; 5326bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilele_x2: 5327bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5328bdd1243dSDimitry Andric Node->getValueType(0), 5329bdd1243dSDimitry Andric {AArch64::WHILELE_2PXX_B, AArch64::WHILELE_2PXX_H, 5330bdd1243dSDimitry Andric AArch64::WHILELE_2PXX_S, AArch64::WHILELE_2PXX_D})) 5331bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5332bdd1243dSDimitry Andric return; 5333bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilelo_x2: 5334bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5335bdd1243dSDimitry Andric Node->getValueType(0), 5336bdd1243dSDimitry Andric {AArch64::WHILELO_2PXX_B, AArch64::WHILELO_2PXX_H, 5337bdd1243dSDimitry Andric AArch64::WHILELO_2PXX_S, AArch64::WHILELO_2PXX_D})) 5338bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5339bdd1243dSDimitry Andric return; 5340bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilels_x2: 5341bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5342bdd1243dSDimitry Andric Node->getValueType(0), 5343bdd1243dSDimitry Andric {AArch64::WHILELS_2PXX_B, AArch64::WHILELS_2PXX_H, 5344bdd1243dSDimitry Andric AArch64::WHILELS_2PXX_S, AArch64::WHILELS_2PXX_D})) 5345bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5346bdd1243dSDimitry Andric return; 5347bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilelt_x2: 5348bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 5349bdd1243dSDimitry Andric Node->getValueType(0), 5350bdd1243dSDimitry Andric {AArch64::WHILELT_2PXX_B, AArch64::WHILELT_2PXX_H, 5351bdd1243dSDimitry Andric AArch64::WHILELT_2PXX_S, AArch64::WHILELT_2PXX_D})) 5352bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 5353bdd1243dSDimitry Andric return; 535406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_single_x2: 535506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 535606c3fb27SDimitry Andric Node->getValueType(0), 535706c3fb27SDimitry Andric {AArch64::SMAX_VG2_2ZZ_B, AArch64::SMAX_VG2_2ZZ_H, 535806c3fb27SDimitry Andric AArch64::SMAX_VG2_2ZZ_S, AArch64::SMAX_VG2_2ZZ_D})) 535906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 536006c3fb27SDimitry Andric return; 536106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_single_x2: 536206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 536306c3fb27SDimitry Andric Node->getValueType(0), 536406c3fb27SDimitry Andric {AArch64::UMAX_VG2_2ZZ_B, AArch64::UMAX_VG2_2ZZ_H, 536506c3fb27SDimitry Andric AArch64::UMAX_VG2_2ZZ_S, AArch64::UMAX_VG2_2ZZ_D})) 536606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 536706c3fb27SDimitry Andric return; 536806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_single_x2: 536906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 537006c3fb27SDimitry Andric Node->getValueType(0), 537106c3fb27SDimitry Andric {0, AArch64::FMAX_VG2_2ZZ_H, AArch64::FMAX_VG2_2ZZ_S, 537206c3fb27SDimitry Andric AArch64::FMAX_VG2_2ZZ_D})) 537306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 537406c3fb27SDimitry Andric return; 537506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_single_x4: 537606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 537706c3fb27SDimitry Andric Node->getValueType(0), 537806c3fb27SDimitry Andric {AArch64::SMAX_VG4_4ZZ_B, AArch64::SMAX_VG4_4ZZ_H, 537906c3fb27SDimitry Andric AArch64::SMAX_VG4_4ZZ_S, AArch64::SMAX_VG4_4ZZ_D})) 538006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 538106c3fb27SDimitry Andric return; 538206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_single_x4: 538306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 538406c3fb27SDimitry Andric Node->getValueType(0), 538506c3fb27SDimitry Andric {AArch64::UMAX_VG4_4ZZ_B, AArch64::UMAX_VG4_4ZZ_H, 538606c3fb27SDimitry Andric AArch64::UMAX_VG4_4ZZ_S, AArch64::UMAX_VG4_4ZZ_D})) 538706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 538806c3fb27SDimitry Andric return; 538906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_single_x4: 539006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 539106c3fb27SDimitry Andric Node->getValueType(0), 539206c3fb27SDimitry Andric {0, AArch64::FMAX_VG4_4ZZ_H, AArch64::FMAX_VG4_4ZZ_S, 539306c3fb27SDimitry Andric AArch64::FMAX_VG4_4ZZ_D})) 539406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 539506c3fb27SDimitry Andric return; 539606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_single_x2: 539706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 539806c3fb27SDimitry Andric Node->getValueType(0), 539906c3fb27SDimitry Andric {AArch64::SMIN_VG2_2ZZ_B, AArch64::SMIN_VG2_2ZZ_H, 540006c3fb27SDimitry Andric AArch64::SMIN_VG2_2ZZ_S, AArch64::SMIN_VG2_2ZZ_D})) 540106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 540206c3fb27SDimitry Andric return; 540306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_single_x2: 540406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 540506c3fb27SDimitry Andric Node->getValueType(0), 540606c3fb27SDimitry Andric {AArch64::UMIN_VG2_2ZZ_B, AArch64::UMIN_VG2_2ZZ_H, 540706c3fb27SDimitry Andric AArch64::UMIN_VG2_2ZZ_S, AArch64::UMIN_VG2_2ZZ_D})) 540806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 540906c3fb27SDimitry Andric return; 541006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_single_x2: 541106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 541206c3fb27SDimitry Andric Node->getValueType(0), 541306c3fb27SDimitry Andric {0, AArch64::FMIN_VG2_2ZZ_H, AArch64::FMIN_VG2_2ZZ_S, 541406c3fb27SDimitry Andric AArch64::FMIN_VG2_2ZZ_D})) 541506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 541606c3fb27SDimitry Andric return; 541706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_single_x4: 541806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 541906c3fb27SDimitry Andric Node->getValueType(0), 542006c3fb27SDimitry Andric {AArch64::SMIN_VG4_4ZZ_B, AArch64::SMIN_VG4_4ZZ_H, 542106c3fb27SDimitry Andric AArch64::SMIN_VG4_4ZZ_S, AArch64::SMIN_VG4_4ZZ_D})) 542206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 542306c3fb27SDimitry Andric return; 542406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_single_x4: 542506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 542606c3fb27SDimitry Andric Node->getValueType(0), 542706c3fb27SDimitry Andric {AArch64::UMIN_VG4_4ZZ_B, AArch64::UMIN_VG4_4ZZ_H, 542806c3fb27SDimitry Andric AArch64::UMIN_VG4_4ZZ_S, AArch64::UMIN_VG4_4ZZ_D})) 542906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 543006c3fb27SDimitry Andric return; 543106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_single_x4: 543206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 543306c3fb27SDimitry Andric Node->getValueType(0), 543406c3fb27SDimitry Andric {0, AArch64::FMIN_VG4_4ZZ_H, AArch64::FMIN_VG4_4ZZ_S, 543506c3fb27SDimitry Andric AArch64::FMIN_VG4_4ZZ_D})) 543606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 543706c3fb27SDimitry Andric return; 543806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_x2: 543906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 544006c3fb27SDimitry Andric Node->getValueType(0), 544106c3fb27SDimitry Andric {AArch64::SMAX_VG2_2Z2Z_B, AArch64::SMAX_VG2_2Z2Z_H, 544206c3fb27SDimitry Andric AArch64::SMAX_VG2_2Z2Z_S, AArch64::SMAX_VG2_2Z2Z_D})) 544306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 544406c3fb27SDimitry Andric return; 544506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_x2: 544606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 544706c3fb27SDimitry Andric Node->getValueType(0), 544806c3fb27SDimitry Andric {AArch64::UMAX_VG2_2Z2Z_B, AArch64::UMAX_VG2_2Z2Z_H, 544906c3fb27SDimitry Andric AArch64::UMAX_VG2_2Z2Z_S, AArch64::UMAX_VG2_2Z2Z_D})) 545006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 545106c3fb27SDimitry Andric return; 545206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_x2: 545306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 545406c3fb27SDimitry Andric Node->getValueType(0), 545506c3fb27SDimitry Andric {0, AArch64::FMAX_VG2_2Z2Z_H, AArch64::FMAX_VG2_2Z2Z_S, 545606c3fb27SDimitry Andric AArch64::FMAX_VG2_2Z2Z_D})) 545706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 545806c3fb27SDimitry Andric return; 545906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smax_x4: 546006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 546106c3fb27SDimitry Andric Node->getValueType(0), 546206c3fb27SDimitry Andric {AArch64::SMAX_VG4_4Z4Z_B, AArch64::SMAX_VG4_4Z4Z_H, 546306c3fb27SDimitry Andric AArch64::SMAX_VG4_4Z4Z_S, AArch64::SMAX_VG4_4Z4Z_D})) 546406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 546506c3fb27SDimitry Andric return; 546606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umax_x4: 546706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 546806c3fb27SDimitry Andric Node->getValueType(0), 546906c3fb27SDimitry Andric {AArch64::UMAX_VG4_4Z4Z_B, AArch64::UMAX_VG4_4Z4Z_H, 547006c3fb27SDimitry Andric AArch64::UMAX_VG4_4Z4Z_S, AArch64::UMAX_VG4_4Z4Z_D})) 547106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 547206c3fb27SDimitry Andric return; 547306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmax_x4: 547406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 547506c3fb27SDimitry Andric Node->getValueType(0), 547606c3fb27SDimitry Andric {0, AArch64::FMAX_VG4_4Z4Z_H, AArch64::FMAX_VG4_4Z4Z_S, 547706c3fb27SDimitry Andric AArch64::FMAX_VG4_4Z4Z_D})) 547806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 547906c3fb27SDimitry Andric return; 548006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_x2: 548106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 548206c3fb27SDimitry Andric Node->getValueType(0), 548306c3fb27SDimitry Andric {AArch64::SMIN_VG2_2Z2Z_B, AArch64::SMIN_VG2_2Z2Z_H, 548406c3fb27SDimitry Andric AArch64::SMIN_VG2_2Z2Z_S, AArch64::SMIN_VG2_2Z2Z_D})) 548506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 548606c3fb27SDimitry Andric return; 548706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_x2: 548806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 548906c3fb27SDimitry Andric Node->getValueType(0), 549006c3fb27SDimitry Andric {AArch64::UMIN_VG2_2Z2Z_B, AArch64::UMIN_VG2_2Z2Z_H, 549106c3fb27SDimitry Andric AArch64::UMIN_VG2_2Z2Z_S, AArch64::UMIN_VG2_2Z2Z_D})) 549206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 549306c3fb27SDimitry Andric return; 549406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_x2: 549506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 549606c3fb27SDimitry Andric Node->getValueType(0), 549706c3fb27SDimitry Andric {0, AArch64::FMIN_VG2_2Z2Z_H, AArch64::FMIN_VG2_2Z2Z_S, 549806c3fb27SDimitry Andric AArch64::FMIN_VG2_2Z2Z_D})) 549906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 550006c3fb27SDimitry Andric return; 550106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_smin_x4: 550206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 550306c3fb27SDimitry Andric Node->getValueType(0), 550406c3fb27SDimitry Andric {AArch64::SMIN_VG4_4Z4Z_B, AArch64::SMIN_VG4_4Z4Z_H, 550506c3fb27SDimitry Andric AArch64::SMIN_VG4_4Z4Z_S, AArch64::SMIN_VG4_4Z4Z_D})) 550606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 550706c3fb27SDimitry Andric return; 550806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_umin_x4: 550906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 551006c3fb27SDimitry Andric Node->getValueType(0), 551106c3fb27SDimitry Andric {AArch64::UMIN_VG4_4Z4Z_B, AArch64::UMIN_VG4_4Z4Z_H, 551206c3fb27SDimitry Andric AArch64::UMIN_VG4_4Z4Z_S, AArch64::UMIN_VG4_4Z4Z_D})) 551306c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 551406c3fb27SDimitry Andric return; 551506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmin_x4: 551606c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 551706c3fb27SDimitry Andric Node->getValueType(0), 551806c3fb27SDimitry Andric {0, AArch64::FMIN_VG4_4Z4Z_H, AArch64::FMIN_VG4_4Z4Z_S, 551906c3fb27SDimitry Andric AArch64::FMIN_VG4_4Z4Z_D})) 552006c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 552106c3fb27SDimitry Andric return; 552206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_single_x2 : 552306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 552406c3fb27SDimitry Andric Node->getValueType(0), 552506c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG2_2ZZ_H, AArch64::FMAXNM_VG2_2ZZ_S, 552606c3fb27SDimitry Andric AArch64::FMAXNM_VG2_2ZZ_D})) 552706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 552806c3fb27SDimitry Andric return; 552906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_single_x4 : 553006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 553106c3fb27SDimitry Andric Node->getValueType(0), 553206c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG4_4ZZ_H, AArch64::FMAXNM_VG4_4ZZ_S, 553306c3fb27SDimitry Andric AArch64::FMAXNM_VG4_4ZZ_D})) 553406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 553506c3fb27SDimitry Andric return; 553606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_single_x2: 553706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 553806c3fb27SDimitry Andric Node->getValueType(0), 553906c3fb27SDimitry Andric {0, AArch64::FMINNM_VG2_2ZZ_H, AArch64::FMINNM_VG2_2ZZ_S, 554006c3fb27SDimitry Andric AArch64::FMINNM_VG2_2ZZ_D})) 554106c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 554206c3fb27SDimitry Andric return; 554306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_single_x4: 554406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 554506c3fb27SDimitry Andric Node->getValueType(0), 554606c3fb27SDimitry Andric {0, AArch64::FMINNM_VG4_4ZZ_H, AArch64::FMINNM_VG4_4ZZ_S, 554706c3fb27SDimitry Andric AArch64::FMINNM_VG4_4ZZ_D})) 554806c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 554906c3fb27SDimitry Andric return; 555006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_x2: 555106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 555206c3fb27SDimitry Andric Node->getValueType(0), 555306c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG2_2Z2Z_H, AArch64::FMAXNM_VG2_2Z2Z_S, 555406c3fb27SDimitry Andric AArch64::FMAXNM_VG2_2Z2Z_D})) 555506c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 555606c3fb27SDimitry Andric return; 555706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fmaxnm_x4: 555806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 555906c3fb27SDimitry Andric Node->getValueType(0), 556006c3fb27SDimitry Andric {0, AArch64::FMAXNM_VG4_4Z4Z_H, AArch64::FMAXNM_VG4_4Z4Z_S, 556106c3fb27SDimitry Andric AArch64::FMAXNM_VG4_4Z4Z_D})) 556206c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 556306c3fb27SDimitry Andric return; 556406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_x2: 556506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 556606c3fb27SDimitry Andric Node->getValueType(0), 556706c3fb27SDimitry Andric {0, AArch64::FMINNM_VG2_2Z2Z_H, AArch64::FMINNM_VG2_2Z2Z_S, 556806c3fb27SDimitry Andric AArch64::FMINNM_VG2_2Z2Z_D})) 556906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op); 557006c3fb27SDimitry Andric return; 557106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fminnm_x4: 557206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 557306c3fb27SDimitry Andric Node->getValueType(0), 557406c3fb27SDimitry Andric {0, AArch64::FMINNM_VG4_4Z4Z_H, AArch64::FMINNM_VG4_4Z4Z_S, 557506c3fb27SDimitry Andric AArch64::FMINNM_VG4_4Z4Z_D})) 557606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op); 557706c3fb27SDimitry Andric return; 5578bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvts_x2: 5579bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::FCVTZS_2Z2Z_StoS); 5580bdd1243dSDimitry Andric return; 5581bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_scvtf_x2: 5582bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::SCVTF_2Z2Z_StoS); 5583bdd1243dSDimitry Andric return; 5584bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvtu_x2: 5585bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::FCVTZU_2Z2Z_StoS); 5586bdd1243dSDimitry Andric return; 5587bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ucvtf_x2: 5588bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::UCVTF_2Z2Z_StoS); 5589bdd1243dSDimitry Andric return; 5590bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvts_x4: 5591bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::FCVTZS_4Z4Z_StoS); 5592bdd1243dSDimitry Andric return; 5593bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_scvtf_x4: 5594bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::SCVTF_4Z4Z_StoS); 5595bdd1243dSDimitry Andric return; 5596bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvtu_x4: 5597bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::FCVTZU_4Z4Z_StoS); 5598bdd1243dSDimitry Andric return; 5599bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ucvtf_x4: 5600bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::UCVTF_4Z4Z_StoS); 5601bdd1243dSDimitry Andric return; 560206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sclamp_single_x2: 560306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 560406c3fb27SDimitry Andric Node->getValueType(0), 560506c3fb27SDimitry Andric {AArch64::SCLAMP_VG2_2Z2Z_B, AArch64::SCLAMP_VG2_2Z2Z_H, 560606c3fb27SDimitry Andric AArch64::SCLAMP_VG2_2Z2Z_S, AArch64::SCLAMP_VG2_2Z2Z_D})) 560706c3fb27SDimitry Andric SelectClamp(Node, 2, Op); 560806c3fb27SDimitry Andric return; 560906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uclamp_single_x2: 561006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 561106c3fb27SDimitry Andric Node->getValueType(0), 561206c3fb27SDimitry Andric {AArch64::UCLAMP_VG2_2Z2Z_B, AArch64::UCLAMP_VG2_2Z2Z_H, 561306c3fb27SDimitry Andric AArch64::UCLAMP_VG2_2Z2Z_S, AArch64::UCLAMP_VG2_2Z2Z_D})) 561406c3fb27SDimitry Andric SelectClamp(Node, 2, Op); 561506c3fb27SDimitry Andric return; 561606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fclamp_single_x2: 561706c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 561806c3fb27SDimitry Andric Node->getValueType(0), 561906c3fb27SDimitry Andric {0, AArch64::FCLAMP_VG2_2Z2Z_H, AArch64::FCLAMP_VG2_2Z2Z_S, 562006c3fb27SDimitry Andric AArch64::FCLAMP_VG2_2Z2Z_D})) 562106c3fb27SDimitry Andric SelectClamp(Node, 2, Op); 562206c3fb27SDimitry Andric return; 562306c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sclamp_single_x4: 562406c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 562506c3fb27SDimitry Andric Node->getValueType(0), 562606c3fb27SDimitry Andric {AArch64::SCLAMP_VG4_4Z4Z_B, AArch64::SCLAMP_VG4_4Z4Z_H, 562706c3fb27SDimitry Andric AArch64::SCLAMP_VG4_4Z4Z_S, AArch64::SCLAMP_VG4_4Z4Z_D})) 562806c3fb27SDimitry Andric SelectClamp(Node, 4, Op); 562906c3fb27SDimitry Andric return; 563006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uclamp_single_x4: 563106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 563206c3fb27SDimitry Andric Node->getValueType(0), 563306c3fb27SDimitry Andric {AArch64::UCLAMP_VG4_4Z4Z_B, AArch64::UCLAMP_VG4_4Z4Z_H, 563406c3fb27SDimitry Andric AArch64::UCLAMP_VG4_4Z4Z_S, AArch64::UCLAMP_VG4_4Z4Z_D})) 563506c3fb27SDimitry Andric SelectClamp(Node, 4, Op); 563606c3fb27SDimitry Andric return; 563706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_fclamp_single_x4: 563806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::FP>( 563906c3fb27SDimitry Andric Node->getValueType(0), 564006c3fb27SDimitry Andric {0, AArch64::FCLAMP_VG4_4Z4Z_H, AArch64::FCLAMP_VG4_4Z4Z_S, 564106c3fb27SDimitry Andric AArch64::FCLAMP_VG4_4Z4Z_D})) 564206c3fb27SDimitry Andric SelectClamp(Node, 4, Op); 564306c3fb27SDimitry Andric return; 564406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_add_single_x2: 564506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 564606c3fb27SDimitry Andric Node->getValueType(0), 564706c3fb27SDimitry Andric {AArch64::ADD_VG2_2ZZ_B, AArch64::ADD_VG2_2ZZ_H, 564806c3fb27SDimitry Andric AArch64::ADD_VG2_2ZZ_S, AArch64::ADD_VG2_2ZZ_D})) 564906c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, false, Op); 565006c3fb27SDimitry Andric return; 565106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_add_single_x4: 565206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 565306c3fb27SDimitry Andric Node->getValueType(0), 565406c3fb27SDimitry Andric {AArch64::ADD_VG4_4ZZ_B, AArch64::ADD_VG4_4ZZ_H, 565506c3fb27SDimitry Andric AArch64::ADD_VG4_4ZZ_S, AArch64::ADD_VG4_4ZZ_D})) 565606c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, false, Op); 565706c3fb27SDimitry Andric return; 565806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zip_x2: 565906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 566006c3fb27SDimitry Andric Node->getValueType(0), 566106c3fb27SDimitry Andric {AArch64::ZIP_VG2_2ZZZ_B, AArch64::ZIP_VG2_2ZZZ_H, 566206c3fb27SDimitry Andric AArch64::ZIP_VG2_2ZZZ_S, AArch64::ZIP_VG2_2ZZZ_D})) 566306c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 566406c3fb27SDimitry Andric return; 566506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zipq_x2: 566606c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, 566706c3fb27SDimitry Andric AArch64::ZIP_VG2_2ZZZ_Q); 566806c3fb27SDimitry Andric return; 566906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zip_x4: 567006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 567106c3fb27SDimitry Andric Node->getValueType(0), 567206c3fb27SDimitry Andric {AArch64::ZIP_VG4_4Z4Z_B, AArch64::ZIP_VG4_4Z4Z_H, 567306c3fb27SDimitry Andric AArch64::ZIP_VG4_4Z4Z_S, AArch64::ZIP_VG4_4Z4Z_D})) 567406c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 567506c3fb27SDimitry Andric return; 567606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_zipq_x4: 567706c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, 567806c3fb27SDimitry Andric AArch64::ZIP_VG4_4Z4Z_Q); 567906c3fb27SDimitry Andric return; 568006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzp_x2: 568106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 568206c3fb27SDimitry Andric Node->getValueType(0), 568306c3fb27SDimitry Andric {AArch64::UZP_VG2_2ZZZ_B, AArch64::UZP_VG2_2ZZZ_H, 568406c3fb27SDimitry Andric AArch64::UZP_VG2_2ZZZ_S, AArch64::UZP_VG2_2ZZZ_D})) 568506c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 568606c3fb27SDimitry Andric return; 568706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzpq_x2: 568806c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, 568906c3fb27SDimitry Andric AArch64::UZP_VG2_2ZZZ_Q); 569006c3fb27SDimitry Andric return; 569106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzp_x4: 569206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 569306c3fb27SDimitry Andric Node->getValueType(0), 569406c3fb27SDimitry Andric {AArch64::UZP_VG4_4Z4Z_B, AArch64::UZP_VG4_4Z4Z_H, 569506c3fb27SDimitry Andric AArch64::UZP_VG4_4Z4Z_S, AArch64::UZP_VG4_4Z4Z_D})) 569606c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 569706c3fb27SDimitry Andric return; 569806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uzpq_x4: 569906c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, 570006c3fb27SDimitry Andric AArch64::UZP_VG4_4Z4Z_Q); 570106c3fb27SDimitry Andric return; 570206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sel_x2: 570306c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 570406c3fb27SDimitry Andric Node->getValueType(0), 570506c3fb27SDimitry Andric {AArch64::SEL_VG2_2ZC2Z2Z_B, AArch64::SEL_VG2_2ZC2Z2Z_H, 570606c3fb27SDimitry Andric AArch64::SEL_VG2_2ZC2Z2Z_S, AArch64::SEL_VG2_2ZC2Z2Z_D})) 570706c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 2, true, Op, /*HasPred=*/true); 570806c3fb27SDimitry Andric return; 570906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sel_x4: 571006c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 571106c3fb27SDimitry Andric Node->getValueType(0), 571206c3fb27SDimitry Andric {AArch64::SEL_VG4_4ZC4Z4Z_B, AArch64::SEL_VG4_4ZC4Z4Z_H, 571306c3fb27SDimitry Andric AArch64::SEL_VG4_4ZC4Z4Z_S, AArch64::SEL_VG4_4ZC4Z4Z_D})) 571406c3fb27SDimitry Andric SelectDestructiveMultiIntrinsic(Node, 4, true, Op, /*HasPred=*/true); 571506c3fb27SDimitry Andric return; 571606c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frinta_x2: 571706c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTA_2Z2Z_S); 571806c3fb27SDimitry Andric return; 571906c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frinta_x4: 572006c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTA_4Z4Z_S); 572106c3fb27SDimitry Andric return; 572206c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintm_x2: 572306c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTM_2Z2Z_S); 572406c3fb27SDimitry Andric return; 572506c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintm_x4: 572606c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTM_4Z4Z_S); 572706c3fb27SDimitry Andric return; 572806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintn_x2: 572906c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTN_2Z2Z_S); 573006c3fb27SDimitry Andric return; 573106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintn_x4: 573206c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTN_4Z4Z_S); 573306c3fb27SDimitry Andric return; 573406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintp_x2: 573506c3fb27SDimitry Andric SelectFrintFromVT(Node, 2, AArch64::FRINTP_2Z2Z_S); 573606c3fb27SDimitry Andric return; 573706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_frintp_x4: 573806c3fb27SDimitry Andric SelectFrintFromVT(Node, 4, AArch64::FRINTP_4Z4Z_S); 573906c3fb27SDimitry Andric return; 574006c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sunpk_x2: 574106c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 574206c3fb27SDimitry Andric Node->getValueType(0), 574306c3fb27SDimitry Andric {0, AArch64::SUNPK_VG2_2ZZ_H, AArch64::SUNPK_VG2_2ZZ_S, 574406c3fb27SDimitry Andric AArch64::SUNPK_VG2_2ZZ_D})) 574506c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 574606c3fb27SDimitry Andric return; 574706c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uunpk_x2: 574806c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 574906c3fb27SDimitry Andric Node->getValueType(0), 575006c3fb27SDimitry Andric {0, AArch64::UUNPK_VG2_2ZZ_H, AArch64::UUNPK_VG2_2ZZ_S, 575106c3fb27SDimitry Andric AArch64::UUNPK_VG2_2ZZ_D})) 575206c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 2, /*IsTupleInput=*/false, Op); 575306c3fb27SDimitry Andric return; 575406c3fb27SDimitry Andric case Intrinsic::aarch64_sve_sunpk_x4: 575506c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 575606c3fb27SDimitry Andric Node->getValueType(0), 575706c3fb27SDimitry Andric {0, AArch64::SUNPK_VG4_4Z2Z_H, AArch64::SUNPK_VG4_4Z2Z_S, 575806c3fb27SDimitry Andric AArch64::SUNPK_VG4_4Z2Z_D})) 575906c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 576006c3fb27SDimitry Andric return; 576106c3fb27SDimitry Andric case Intrinsic::aarch64_sve_uunpk_x4: 576206c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int>( 576306c3fb27SDimitry Andric Node->getValueType(0), 576406c3fb27SDimitry Andric {0, AArch64::UUNPK_VG4_4Z2Z_H, AArch64::UUNPK_VG4_4Z2Z_S, 576506c3fb27SDimitry Andric AArch64::UUNPK_VG4_4Z2Z_D})) 576606c3fb27SDimitry Andric SelectUnaryMultiIntrinsic(Node, 4, /*IsTupleInput=*/true, Op); 576706c3fb27SDimitry Andric return; 576806c3fb27SDimitry Andric case Intrinsic::aarch64_sve_pext_x2: { 576906c3fb27SDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::AnyType>( 577006c3fb27SDimitry Andric Node->getValueType(0), 577106c3fb27SDimitry Andric {AArch64::PEXT_2PCI_B, AArch64::PEXT_2PCI_H, AArch64::PEXT_2PCI_S, 577206c3fb27SDimitry Andric AArch64::PEXT_2PCI_D})) 577306c3fb27SDimitry Andric SelectPExtPair(Node, Op); 577406c3fb27SDimitry Andric return; 577506c3fb27SDimitry Andric } 57760b57cec5SDimitry Andric } 57770b57cec5SDimitry Andric break; 57780b57cec5SDimitry Andric } 57790b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: { 5780647cbc5dSDimitry Andric unsigned IntNo = Node->getConstantOperandVal(1); 57810b57cec5SDimitry Andric if (Node->getNumOperands() >= 3) 57820b57cec5SDimitry Andric VT = Node->getOperand(2)->getValueType(0); 57830b57cec5SDimitry Andric switch (IntNo) { 57840b57cec5SDimitry Andric default: 57850b57cec5SDimitry Andric break; 57860b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x2: { 57870b57cec5SDimitry Andric if (VT == MVT::v8i8) { 57880b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov8b); 57890b57cec5SDimitry Andric return; 57900b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 57910b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov16b); 57920b57cec5SDimitry Andric return; 57935ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 57945ffd83dbSDimitry Andric VT == MVT::v4bf16) { 57950b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov4h); 57960b57cec5SDimitry Andric return; 57975ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 57985ffd83dbSDimitry Andric VT == MVT::v8bf16) { 57990b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov8h); 58000b57cec5SDimitry Andric return; 58010b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58020b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov2s); 58030b57cec5SDimitry Andric return; 58040b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58050b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov4s); 58060b57cec5SDimitry Andric return; 58070b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58080b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov2d); 58090b57cec5SDimitry Andric return; 58100b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 58110b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov1d); 58120b57cec5SDimitry Andric return; 58130b57cec5SDimitry Andric } 58140b57cec5SDimitry Andric break; 58150b57cec5SDimitry Andric } 58160b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x3: { 58170b57cec5SDimitry Andric if (VT == MVT::v8i8) { 58180b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev8b); 58190b57cec5SDimitry Andric return; 58200b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 58210b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev16b); 58220b57cec5SDimitry Andric return; 58235ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 58245ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58250b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev4h); 58260b57cec5SDimitry Andric return; 58275ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58285ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58290b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev8h); 58300b57cec5SDimitry Andric return; 58310b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58320b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev2s); 58330b57cec5SDimitry Andric return; 58340b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58350b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev4s); 58360b57cec5SDimitry Andric return; 58370b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58380b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev2d); 58390b57cec5SDimitry Andric return; 58400b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 58410b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev1d); 58420b57cec5SDimitry Andric return; 58430b57cec5SDimitry Andric } 58440b57cec5SDimitry Andric break; 58450b57cec5SDimitry Andric } 58460b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x4: { 58470b57cec5SDimitry Andric if (VT == MVT::v8i8) { 58480b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv8b); 58490b57cec5SDimitry Andric return; 58500b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 58510b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv16b); 58520b57cec5SDimitry Andric return; 58535ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 58545ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58550b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv4h); 58560b57cec5SDimitry Andric return; 58575ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58585ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58590b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv8h); 58600b57cec5SDimitry Andric return; 58610b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58620b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv2s); 58630b57cec5SDimitry Andric return; 58640b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58650b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv4s); 58660b57cec5SDimitry Andric return; 58670b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58680b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv2d); 58690b57cec5SDimitry Andric return; 58700b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 58710b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv1d); 58720b57cec5SDimitry Andric return; 58730b57cec5SDimitry Andric } 58740b57cec5SDimitry Andric break; 58750b57cec5SDimitry Andric } 58760b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st2: { 58770b57cec5SDimitry Andric if (VT == MVT::v8i8) { 58780b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov8b); 58790b57cec5SDimitry Andric return; 58800b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 58810b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov16b); 58820b57cec5SDimitry Andric return; 58835ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 58845ffd83dbSDimitry Andric VT == MVT::v4bf16) { 58850b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov4h); 58860b57cec5SDimitry Andric return; 58875ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 58885ffd83dbSDimitry Andric VT == MVT::v8bf16) { 58890b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov8h); 58900b57cec5SDimitry Andric return; 58910b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 58920b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov2s); 58930b57cec5SDimitry Andric return; 58940b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 58950b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov4s); 58960b57cec5SDimitry Andric return; 58970b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 58980b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov2d); 58990b57cec5SDimitry Andric return; 59000b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 59010b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov1d); 59020b57cec5SDimitry Andric return; 59030b57cec5SDimitry Andric } 59040b57cec5SDimitry Andric break; 59050b57cec5SDimitry Andric } 59060b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st3: { 59070b57cec5SDimitry Andric if (VT == MVT::v8i8) { 59080b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev8b); 59090b57cec5SDimitry Andric return; 59100b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 59110b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev16b); 59120b57cec5SDimitry Andric return; 59135ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 59145ffd83dbSDimitry Andric VT == MVT::v4bf16) { 59150b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev4h); 59160b57cec5SDimitry Andric return; 59175ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 59185ffd83dbSDimitry Andric VT == MVT::v8bf16) { 59190b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev8h); 59200b57cec5SDimitry Andric return; 59210b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 59220b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev2s); 59230b57cec5SDimitry Andric return; 59240b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 59250b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev4s); 59260b57cec5SDimitry Andric return; 59270b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 59280b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev2d); 59290b57cec5SDimitry Andric return; 59300b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 59310b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev1d); 59320b57cec5SDimitry Andric return; 59330b57cec5SDimitry Andric } 59340b57cec5SDimitry Andric break; 59350b57cec5SDimitry Andric } 59360b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st4: { 59370b57cec5SDimitry Andric if (VT == MVT::v8i8) { 59380b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv8b); 59390b57cec5SDimitry Andric return; 59400b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 59410b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv16b); 59420b57cec5SDimitry Andric return; 59435ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 59445ffd83dbSDimitry Andric VT == MVT::v4bf16) { 59450b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv4h); 59460b57cec5SDimitry Andric return; 59475ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 59485ffd83dbSDimitry Andric VT == MVT::v8bf16) { 59490b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv8h); 59500b57cec5SDimitry Andric return; 59510b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 59520b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv2s); 59530b57cec5SDimitry Andric return; 59540b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 59550b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv4s); 59560b57cec5SDimitry Andric return; 59570b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 59580b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv2d); 59590b57cec5SDimitry Andric return; 59600b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 59610b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv1d); 59620b57cec5SDimitry Andric return; 59630b57cec5SDimitry Andric } 59640b57cec5SDimitry Andric break; 59650b57cec5SDimitry Andric } 59660b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st2lane: { 59670b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 59680b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i8); 59690b57cec5SDimitry Andric return; 59700b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 59715ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 59720b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i16); 59730b57cec5SDimitry Andric return; 59740b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 59750b57cec5SDimitry Andric VT == MVT::v2f32) { 59760b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i32); 59770b57cec5SDimitry Andric return; 59780b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 59790b57cec5SDimitry Andric VT == MVT::v1f64) { 59800b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i64); 59810b57cec5SDimitry Andric return; 59820b57cec5SDimitry Andric } 59830b57cec5SDimitry Andric break; 59840b57cec5SDimitry Andric } 59850b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st3lane: { 59860b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 59870b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i8); 59880b57cec5SDimitry Andric return; 59890b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 59905ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 59910b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i16); 59920b57cec5SDimitry Andric return; 59930b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 59940b57cec5SDimitry Andric VT == MVT::v2f32) { 59950b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i32); 59960b57cec5SDimitry Andric return; 59970b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 59980b57cec5SDimitry Andric VT == MVT::v1f64) { 59990b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i64); 60000b57cec5SDimitry Andric return; 60010b57cec5SDimitry Andric } 60020b57cec5SDimitry Andric break; 60030b57cec5SDimitry Andric } 60040b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st4lane: { 60050b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 60060b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i8); 60070b57cec5SDimitry Andric return; 60080b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 60095ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 60100b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i16); 60110b57cec5SDimitry Andric return; 60120b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 60130b57cec5SDimitry Andric VT == MVT::v2f32) { 60140b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i32); 60150b57cec5SDimitry Andric return; 60160b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 60170b57cec5SDimitry Andric VT == MVT::v1f64) { 60180b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i64); 60190b57cec5SDimitry Andric return; 60200b57cec5SDimitry Andric } 60210b57cec5SDimitry Andric break; 60220b57cec5SDimitry Andric } 60235f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st2q: { 60245f757f3fSDimitry Andric SelectPredicatedStore(Node, 2, 4, AArch64::ST2Q, AArch64::ST2Q_IMM); 60255f757f3fSDimitry Andric return; 60265f757f3fSDimitry Andric } 60275f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st3q: { 60285f757f3fSDimitry Andric SelectPredicatedStore(Node, 3, 4, AArch64::ST3Q, AArch64::ST3Q_IMM); 60295f757f3fSDimitry Andric return; 60305f757f3fSDimitry Andric } 60315f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st4q: { 60325f757f3fSDimitry Andric SelectPredicatedStore(Node, 4, 4, AArch64::ST4Q, AArch64::ST4Q_IMM); 60335f757f3fSDimitry Andric return; 60345f757f3fSDimitry Andric } 60355ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st2: { 60365ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6037979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 0, AArch64::ST2B, AArch64::ST2B_IMM); 60385ffd83dbSDimitry Andric return; 60395ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 604081ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6041979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 1, AArch64::ST2H, AArch64::ST2H_IMM); 60425ffd83dbSDimitry Andric return; 60435ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6044979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 2, AArch64::ST2W, AArch64::ST2W_IMM); 60455ffd83dbSDimitry Andric return; 60465ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6047979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 3, AArch64::ST2D, AArch64::ST2D_IMM); 60485ffd83dbSDimitry Andric return; 60495ffd83dbSDimitry Andric } 60505ffd83dbSDimitry Andric break; 60515ffd83dbSDimitry Andric } 60525ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st3: { 60535ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6054979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 0, AArch64::ST3B, AArch64::ST3B_IMM); 60555ffd83dbSDimitry Andric return; 60565ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 605781ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6058979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 1, AArch64::ST3H, AArch64::ST3H_IMM); 60595ffd83dbSDimitry Andric return; 60605ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6061979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 2, AArch64::ST3W, AArch64::ST3W_IMM); 60625ffd83dbSDimitry Andric return; 60635ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6064979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 3, AArch64::ST3D, AArch64::ST3D_IMM); 60655ffd83dbSDimitry Andric return; 60665ffd83dbSDimitry Andric } 60675ffd83dbSDimitry Andric break; 60685ffd83dbSDimitry Andric } 60695ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st4: { 60705ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6071979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 0, AArch64::ST4B, AArch64::ST4B_IMM); 60725ffd83dbSDimitry Andric return; 60735ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 607481ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6075979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 1, AArch64::ST4H, AArch64::ST4H_IMM); 60765ffd83dbSDimitry Andric return; 60775ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6078979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 2, AArch64::ST4W, AArch64::ST4W_IMM); 60795ffd83dbSDimitry Andric return; 60805ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6081979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 3, AArch64::ST4D, AArch64::ST4D_IMM); 60825ffd83dbSDimitry Andric return; 60835ffd83dbSDimitry Andric } 60845ffd83dbSDimitry Andric break; 60855ffd83dbSDimitry Andric } 60860b57cec5SDimitry Andric } 60870b57cec5SDimitry Andric break; 60880b57cec5SDimitry Andric } 60890b57cec5SDimitry Andric case AArch64ISD::LD2post: { 60900b57cec5SDimitry Andric if (VT == MVT::v8i8) { 60910b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov8b_POST, AArch64::dsub0); 60920b57cec5SDimitry Andric return; 60930b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 60940b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov16b_POST, AArch64::qsub0); 60950b57cec5SDimitry Andric return; 60965ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 60970b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov4h_POST, AArch64::dsub0); 60980b57cec5SDimitry Andric return; 60995ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61000b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov8h_POST, AArch64::qsub0); 61010b57cec5SDimitry Andric return; 61020b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61030b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov2s_POST, AArch64::dsub0); 61040b57cec5SDimitry Andric return; 61050b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61060b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov4s_POST, AArch64::qsub0); 61070b57cec5SDimitry Andric return; 61080b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61090b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0); 61100b57cec5SDimitry Andric return; 61110b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61120b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov2d_POST, AArch64::qsub0); 61130b57cec5SDimitry Andric return; 61140b57cec5SDimitry Andric } 61150b57cec5SDimitry Andric break; 61160b57cec5SDimitry Andric } 61170b57cec5SDimitry Andric case AArch64ISD::LD3post: { 61180b57cec5SDimitry Andric if (VT == MVT::v8i8) { 61190b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev8b_POST, AArch64::dsub0); 61200b57cec5SDimitry Andric return; 61210b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 61220b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev16b_POST, AArch64::qsub0); 61230b57cec5SDimitry Andric return; 61245ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61250b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev4h_POST, AArch64::dsub0); 61260b57cec5SDimitry Andric return; 61275ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61280b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev8h_POST, AArch64::qsub0); 61290b57cec5SDimitry Andric return; 61300b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61310b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev2s_POST, AArch64::dsub0); 61320b57cec5SDimitry Andric return; 61330b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61340b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev4s_POST, AArch64::qsub0); 61350b57cec5SDimitry Andric return; 61360b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61370b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0); 61380b57cec5SDimitry Andric return; 61390b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61400b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev2d_POST, AArch64::qsub0); 61410b57cec5SDimitry Andric return; 61420b57cec5SDimitry Andric } 61430b57cec5SDimitry Andric break; 61440b57cec5SDimitry Andric } 61450b57cec5SDimitry Andric case AArch64ISD::LD4post: { 61460b57cec5SDimitry Andric if (VT == MVT::v8i8) { 61470b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv8b_POST, AArch64::dsub0); 61480b57cec5SDimitry Andric return; 61490b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 61500b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv16b_POST, AArch64::qsub0); 61510b57cec5SDimitry Andric return; 61525ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61530b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv4h_POST, AArch64::dsub0); 61540b57cec5SDimitry Andric return; 61555ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61560b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv8h_POST, AArch64::qsub0); 61570b57cec5SDimitry Andric return; 61580b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61590b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv2s_POST, AArch64::dsub0); 61600b57cec5SDimitry Andric return; 61610b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61620b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv4s_POST, AArch64::qsub0); 61630b57cec5SDimitry Andric return; 61640b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61650b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0); 61660b57cec5SDimitry Andric return; 61670b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61680b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv2d_POST, AArch64::qsub0); 61690b57cec5SDimitry Andric return; 61700b57cec5SDimitry Andric } 61710b57cec5SDimitry Andric break; 61720b57cec5SDimitry Andric } 61730b57cec5SDimitry Andric case AArch64ISD::LD1x2post: { 61740b57cec5SDimitry Andric if (VT == MVT::v8i8) { 61750b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov8b_POST, AArch64::dsub0); 61760b57cec5SDimitry Andric return; 61770b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 61780b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov16b_POST, AArch64::qsub0); 61790b57cec5SDimitry Andric return; 61805ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 61810b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov4h_POST, AArch64::dsub0); 61820b57cec5SDimitry Andric return; 61835ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 61840b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov8h_POST, AArch64::qsub0); 61850b57cec5SDimitry Andric return; 61860b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 61870b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov2s_POST, AArch64::dsub0); 61880b57cec5SDimitry Andric return; 61890b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 61900b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov4s_POST, AArch64::qsub0); 61910b57cec5SDimitry Andric return; 61920b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 61930b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0); 61940b57cec5SDimitry Andric return; 61950b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 61960b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov2d_POST, AArch64::qsub0); 61970b57cec5SDimitry Andric return; 61980b57cec5SDimitry Andric } 61990b57cec5SDimitry Andric break; 62000b57cec5SDimitry Andric } 62010b57cec5SDimitry Andric case AArch64ISD::LD1x3post: { 62020b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62030b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev8b_POST, AArch64::dsub0); 62040b57cec5SDimitry Andric return; 62050b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62060b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev16b_POST, AArch64::qsub0); 62070b57cec5SDimitry Andric return; 62085ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62090b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev4h_POST, AArch64::dsub0); 62100b57cec5SDimitry Andric return; 62115ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62120b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev8h_POST, AArch64::qsub0); 62130b57cec5SDimitry Andric return; 62140b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62150b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev2s_POST, AArch64::dsub0); 62160b57cec5SDimitry Andric return; 62170b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 62180b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev4s_POST, AArch64::qsub0); 62190b57cec5SDimitry Andric return; 62200b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 62210b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0); 62220b57cec5SDimitry Andric return; 62230b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62240b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev2d_POST, AArch64::qsub0); 62250b57cec5SDimitry Andric return; 62260b57cec5SDimitry Andric } 62270b57cec5SDimitry Andric break; 62280b57cec5SDimitry Andric } 62290b57cec5SDimitry Andric case AArch64ISD::LD1x4post: { 62300b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62310b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv8b_POST, AArch64::dsub0); 62320b57cec5SDimitry Andric return; 62330b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62340b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv16b_POST, AArch64::qsub0); 62350b57cec5SDimitry Andric return; 62365ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62370b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv4h_POST, AArch64::dsub0); 62380b57cec5SDimitry Andric return; 62395ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62400b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv8h_POST, AArch64::qsub0); 62410b57cec5SDimitry Andric return; 62420b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62430b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv2s_POST, AArch64::dsub0); 62440b57cec5SDimitry Andric return; 62450b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 62460b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv4s_POST, AArch64::qsub0); 62470b57cec5SDimitry Andric return; 62480b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 62490b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0); 62500b57cec5SDimitry Andric return; 62510b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62520b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv2d_POST, AArch64::qsub0); 62530b57cec5SDimitry Andric return; 62540b57cec5SDimitry Andric } 62550b57cec5SDimitry Andric break; 62560b57cec5SDimitry Andric } 62570b57cec5SDimitry Andric case AArch64ISD::LD1DUPpost: { 62580b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62590b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv8b_POST, AArch64::dsub0); 62600b57cec5SDimitry Andric return; 62610b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62620b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv16b_POST, AArch64::qsub0); 62630b57cec5SDimitry Andric return; 62645ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62650b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv4h_POST, AArch64::dsub0); 62660b57cec5SDimitry Andric return; 62675ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62680b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv8h_POST, AArch64::qsub0); 62690b57cec5SDimitry Andric return; 62700b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62710b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv2s_POST, AArch64::dsub0); 62720b57cec5SDimitry Andric return; 62730b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 62740b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv4s_POST, AArch64::qsub0); 62750b57cec5SDimitry Andric return; 62760b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 62770b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv1d_POST, AArch64::dsub0); 62780b57cec5SDimitry Andric return; 62790b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 62800b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv2d_POST, AArch64::qsub0); 62810b57cec5SDimitry Andric return; 62820b57cec5SDimitry Andric } 62830b57cec5SDimitry Andric break; 62840b57cec5SDimitry Andric } 62850b57cec5SDimitry Andric case AArch64ISD::LD2DUPpost: { 62860b57cec5SDimitry Andric if (VT == MVT::v8i8) { 62870b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv8b_POST, AArch64::dsub0); 62880b57cec5SDimitry Andric return; 62890b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 62900b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv16b_POST, AArch64::qsub0); 62910b57cec5SDimitry Andric return; 62925ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 62930b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv4h_POST, AArch64::dsub0); 62940b57cec5SDimitry Andric return; 62955ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 62960b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv8h_POST, AArch64::qsub0); 62970b57cec5SDimitry Andric return; 62980b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 62990b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv2s_POST, AArch64::dsub0); 63000b57cec5SDimitry Andric return; 63010b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 63020b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv4s_POST, AArch64::qsub0); 63030b57cec5SDimitry Andric return; 63040b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 63050b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv1d_POST, AArch64::dsub0); 63060b57cec5SDimitry Andric return; 63070b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 63080b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv2d_POST, AArch64::qsub0); 63090b57cec5SDimitry Andric return; 63100b57cec5SDimitry Andric } 63110b57cec5SDimitry Andric break; 63120b57cec5SDimitry Andric } 63130b57cec5SDimitry Andric case AArch64ISD::LD3DUPpost: { 63140b57cec5SDimitry Andric if (VT == MVT::v8i8) { 63150b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv8b_POST, AArch64::dsub0); 63160b57cec5SDimitry Andric return; 63170b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 63180b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv16b_POST, AArch64::qsub0); 63190b57cec5SDimitry Andric return; 63205ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 63210b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv4h_POST, AArch64::dsub0); 63220b57cec5SDimitry Andric return; 63235ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 63240b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv8h_POST, AArch64::qsub0); 63250b57cec5SDimitry Andric return; 63260b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 63270b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv2s_POST, AArch64::dsub0); 63280b57cec5SDimitry Andric return; 63290b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 63300b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv4s_POST, AArch64::qsub0); 63310b57cec5SDimitry Andric return; 63320b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 63330b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv1d_POST, AArch64::dsub0); 63340b57cec5SDimitry Andric return; 63350b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 63360b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv2d_POST, AArch64::qsub0); 63370b57cec5SDimitry Andric return; 63380b57cec5SDimitry Andric } 63390b57cec5SDimitry Andric break; 63400b57cec5SDimitry Andric } 63410b57cec5SDimitry Andric case AArch64ISD::LD4DUPpost: { 63420b57cec5SDimitry Andric if (VT == MVT::v8i8) { 63430b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv8b_POST, AArch64::dsub0); 63440b57cec5SDimitry Andric return; 63450b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 63460b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv16b_POST, AArch64::qsub0); 63470b57cec5SDimitry Andric return; 63485ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 63490b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv4h_POST, AArch64::dsub0); 63500b57cec5SDimitry Andric return; 63515ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 63520b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv8h_POST, AArch64::qsub0); 63530b57cec5SDimitry Andric return; 63540b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 63550b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv2s_POST, AArch64::dsub0); 63560b57cec5SDimitry Andric return; 63570b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 63580b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv4s_POST, AArch64::qsub0); 63590b57cec5SDimitry Andric return; 63600b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 63610b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv1d_POST, AArch64::dsub0); 63620b57cec5SDimitry Andric return; 63630b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 63640b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv2d_POST, AArch64::qsub0); 63650b57cec5SDimitry Andric return; 63660b57cec5SDimitry Andric } 63670b57cec5SDimitry Andric break; 63680b57cec5SDimitry Andric } 63690b57cec5SDimitry Andric case AArch64ISD::LD1LANEpost: { 63700b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 63710b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i8_POST); 63720b57cec5SDimitry Andric return; 63730b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 63745ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 63750b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i16_POST); 63760b57cec5SDimitry Andric return; 63770b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 63780b57cec5SDimitry Andric VT == MVT::v2f32) { 63790b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i32_POST); 63800b57cec5SDimitry Andric return; 63810b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 63820b57cec5SDimitry Andric VT == MVT::v1f64) { 63830b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i64_POST); 63840b57cec5SDimitry Andric return; 63850b57cec5SDimitry Andric } 63860b57cec5SDimitry Andric break; 63870b57cec5SDimitry Andric } 63880b57cec5SDimitry Andric case AArch64ISD::LD2LANEpost: { 63890b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 63900b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i8_POST); 63910b57cec5SDimitry Andric return; 63920b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 63935ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 63940b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i16_POST); 63950b57cec5SDimitry Andric return; 63960b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 63970b57cec5SDimitry Andric VT == MVT::v2f32) { 63980b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i32_POST); 63990b57cec5SDimitry Andric return; 64000b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 64010b57cec5SDimitry Andric VT == MVT::v1f64) { 64020b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i64_POST); 64030b57cec5SDimitry Andric return; 64040b57cec5SDimitry Andric } 64050b57cec5SDimitry Andric break; 64060b57cec5SDimitry Andric } 64070b57cec5SDimitry Andric case AArch64ISD::LD3LANEpost: { 64080b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 64090b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i8_POST); 64100b57cec5SDimitry Andric return; 64110b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 64125ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 64130b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i16_POST); 64140b57cec5SDimitry Andric return; 64150b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 64160b57cec5SDimitry Andric VT == MVT::v2f32) { 64170b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i32_POST); 64180b57cec5SDimitry Andric return; 64190b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 64200b57cec5SDimitry Andric VT == MVT::v1f64) { 64210b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i64_POST); 64220b57cec5SDimitry Andric return; 64230b57cec5SDimitry Andric } 64240b57cec5SDimitry Andric break; 64250b57cec5SDimitry Andric } 64260b57cec5SDimitry Andric case AArch64ISD::LD4LANEpost: { 64270b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 64280b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i8_POST); 64290b57cec5SDimitry Andric return; 64300b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 64315ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 64320b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i16_POST); 64330b57cec5SDimitry Andric return; 64340b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 64350b57cec5SDimitry Andric VT == MVT::v2f32) { 64360b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i32_POST); 64370b57cec5SDimitry Andric return; 64380b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 64390b57cec5SDimitry Andric VT == MVT::v1f64) { 64400b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i64_POST); 64410b57cec5SDimitry Andric return; 64420b57cec5SDimitry Andric } 64430b57cec5SDimitry Andric break; 64440b57cec5SDimitry Andric } 64450b57cec5SDimitry Andric case AArch64ISD::ST2post: { 64460b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 64470b57cec5SDimitry Andric if (VT == MVT::v8i8) { 64480b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov8b_POST); 64490b57cec5SDimitry Andric return; 64500b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 64510b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov16b_POST); 64520b57cec5SDimitry Andric return; 64535ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 64540b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov4h_POST); 64550b57cec5SDimitry Andric return; 64565ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 64570b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov8h_POST); 64580b57cec5SDimitry Andric return; 64590b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 64600b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov2s_POST); 64610b57cec5SDimitry Andric return; 64620b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 64630b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov4s_POST); 64640b57cec5SDimitry Andric return; 64650b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 64660b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov2d_POST); 64670b57cec5SDimitry Andric return; 64680b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 64690b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST); 64700b57cec5SDimitry Andric return; 64710b57cec5SDimitry Andric } 64720b57cec5SDimitry Andric break; 64730b57cec5SDimitry Andric } 64740b57cec5SDimitry Andric case AArch64ISD::ST3post: { 64750b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 64760b57cec5SDimitry Andric if (VT == MVT::v8i8) { 64770b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev8b_POST); 64780b57cec5SDimitry Andric return; 64790b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 64800b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev16b_POST); 64810b57cec5SDimitry Andric return; 64825ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 64830b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev4h_POST); 64840b57cec5SDimitry Andric return; 64855ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 64860b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev8h_POST); 64870b57cec5SDimitry Andric return; 64880b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 64890b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev2s_POST); 64900b57cec5SDimitry Andric return; 64910b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 64920b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev4s_POST); 64930b57cec5SDimitry Andric return; 64940b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 64950b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev2d_POST); 64960b57cec5SDimitry Andric return; 64970b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 64980b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST); 64990b57cec5SDimitry Andric return; 65000b57cec5SDimitry Andric } 65010b57cec5SDimitry Andric break; 65020b57cec5SDimitry Andric } 65030b57cec5SDimitry Andric case AArch64ISD::ST4post: { 65040b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65050b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65060b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv8b_POST); 65070b57cec5SDimitry Andric return; 65080b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65090b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv16b_POST); 65100b57cec5SDimitry Andric return; 65115ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65120b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv4h_POST); 65130b57cec5SDimitry Andric return; 65145ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 65150b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv8h_POST); 65160b57cec5SDimitry Andric return; 65170b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 65180b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv2s_POST); 65190b57cec5SDimitry Andric return; 65200b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 65210b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv4s_POST); 65220b57cec5SDimitry Andric return; 65230b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65240b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv2d_POST); 65250b57cec5SDimitry Andric return; 65260b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65270b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST); 65280b57cec5SDimitry Andric return; 65290b57cec5SDimitry Andric } 65300b57cec5SDimitry Andric break; 65310b57cec5SDimitry Andric } 65320b57cec5SDimitry Andric case AArch64ISD::ST1x2post: { 65330b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65340b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65350b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov8b_POST); 65360b57cec5SDimitry Andric return; 65370b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65380b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov16b_POST); 65390b57cec5SDimitry Andric return; 65405ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65410b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov4h_POST); 65420b57cec5SDimitry Andric return; 65435ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 65440b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov8h_POST); 65450b57cec5SDimitry Andric return; 65460b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 65470b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov2s_POST); 65480b57cec5SDimitry Andric return; 65490b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 65500b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov4s_POST); 65510b57cec5SDimitry Andric return; 65520b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65530b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST); 65540b57cec5SDimitry Andric return; 65550b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65560b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov2d_POST); 65570b57cec5SDimitry Andric return; 65580b57cec5SDimitry Andric } 65590b57cec5SDimitry Andric break; 65600b57cec5SDimitry Andric } 65610b57cec5SDimitry Andric case AArch64ISD::ST1x3post: { 65620b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65630b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65640b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev8b_POST); 65650b57cec5SDimitry Andric return; 65660b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65670b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev16b_POST); 65680b57cec5SDimitry Andric return; 65695ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65700b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev4h_POST); 65710b57cec5SDimitry Andric return; 65725ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16 ) { 65730b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev8h_POST); 65740b57cec5SDimitry Andric return; 65750b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 65760b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev2s_POST); 65770b57cec5SDimitry Andric return; 65780b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 65790b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev4s_POST); 65800b57cec5SDimitry Andric return; 65810b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 65820b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST); 65830b57cec5SDimitry Andric return; 65840b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 65850b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev2d_POST); 65860b57cec5SDimitry Andric return; 65870b57cec5SDimitry Andric } 65880b57cec5SDimitry Andric break; 65890b57cec5SDimitry Andric } 65900b57cec5SDimitry Andric case AArch64ISD::ST1x4post: { 65910b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 65920b57cec5SDimitry Andric if (VT == MVT::v8i8) { 65930b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv8b_POST); 65940b57cec5SDimitry Andric return; 65950b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 65960b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv16b_POST); 65970b57cec5SDimitry Andric return; 65985ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 65990b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv4h_POST); 66000b57cec5SDimitry Andric return; 66015ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 66020b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv8h_POST); 66030b57cec5SDimitry Andric return; 66040b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 66050b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv2s_POST); 66060b57cec5SDimitry Andric return; 66070b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 66080b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv4s_POST); 66090b57cec5SDimitry Andric return; 66100b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 66110b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST); 66120b57cec5SDimitry Andric return; 66130b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 66140b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv2d_POST); 66150b57cec5SDimitry Andric return; 66160b57cec5SDimitry Andric } 66170b57cec5SDimitry Andric break; 66180b57cec5SDimitry Andric } 66190b57cec5SDimitry Andric case AArch64ISD::ST2LANEpost: { 66200b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 66210b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 66220b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i8_POST); 66230b57cec5SDimitry Andric return; 66240b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 66255ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 66260b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i16_POST); 66270b57cec5SDimitry Andric return; 66280b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 66290b57cec5SDimitry Andric VT == MVT::v2f32) { 66300b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i32_POST); 66310b57cec5SDimitry Andric return; 66320b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 66330b57cec5SDimitry Andric VT == MVT::v1f64) { 66340b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i64_POST); 66350b57cec5SDimitry Andric return; 66360b57cec5SDimitry Andric } 66370b57cec5SDimitry Andric break; 66380b57cec5SDimitry Andric } 66390b57cec5SDimitry Andric case AArch64ISD::ST3LANEpost: { 66400b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 66410b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 66420b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i8_POST); 66430b57cec5SDimitry Andric return; 66440b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 66455ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 66460b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i16_POST); 66470b57cec5SDimitry Andric return; 66480b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 66490b57cec5SDimitry Andric VT == MVT::v2f32) { 66500b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i32_POST); 66510b57cec5SDimitry Andric return; 66520b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 66530b57cec5SDimitry Andric VT == MVT::v1f64) { 66540b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i64_POST); 66550b57cec5SDimitry Andric return; 66560b57cec5SDimitry Andric } 66570b57cec5SDimitry Andric break; 66580b57cec5SDimitry Andric } 66590b57cec5SDimitry Andric case AArch64ISD::ST4LANEpost: { 66600b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 66610b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 66620b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i8_POST); 66630b57cec5SDimitry Andric return; 66640b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 66655ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 66660b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i16_POST); 66670b57cec5SDimitry Andric return; 66680b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 66690b57cec5SDimitry Andric VT == MVT::v2f32) { 66700b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i32_POST); 66710b57cec5SDimitry Andric return; 66720b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 66730b57cec5SDimitry Andric VT == MVT::v1f64) { 66740b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i64_POST); 66750b57cec5SDimitry Andric return; 66760b57cec5SDimitry Andric } 66770b57cec5SDimitry Andric break; 66780b57cec5SDimitry Andric } 66795ffd83dbSDimitry Andric case AArch64ISD::SVE_LD2_MERGE_ZERO: { 66805ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6681979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B); 66825ffd83dbSDimitry Andric return; 66835ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 668481ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6685979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H); 66865ffd83dbSDimitry Andric return; 66875ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6688979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W); 66895ffd83dbSDimitry Andric return; 66905ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6691979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D); 66925ffd83dbSDimitry Andric return; 66935ffd83dbSDimitry Andric } 66945ffd83dbSDimitry Andric break; 66955ffd83dbSDimitry Andric } 66965ffd83dbSDimitry Andric case AArch64ISD::SVE_LD3_MERGE_ZERO: { 66975ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6698979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B); 66995ffd83dbSDimitry Andric return; 67005ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 670181ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6702979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H); 67035ffd83dbSDimitry Andric return; 67045ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6705979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W); 67065ffd83dbSDimitry Andric return; 67075ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6708979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D); 67095ffd83dbSDimitry Andric return; 67105ffd83dbSDimitry Andric } 67115ffd83dbSDimitry Andric break; 67125ffd83dbSDimitry Andric } 67135ffd83dbSDimitry Andric case AArch64ISD::SVE_LD4_MERGE_ZERO: { 67145ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 6715979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B); 67165ffd83dbSDimitry Andric return; 67175ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 671881ad6265SDimitry Andric VT == MVT::nxv8bf16) { 6719979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H); 67205ffd83dbSDimitry Andric return; 67215ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 6722979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W); 67235ffd83dbSDimitry Andric return; 67245ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 6725979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D); 67265ffd83dbSDimitry Andric return; 67275ffd83dbSDimitry Andric } 67285ffd83dbSDimitry Andric break; 67295ffd83dbSDimitry Andric } 67300b57cec5SDimitry Andric } 67310b57cec5SDimitry Andric 67320b57cec5SDimitry Andric // Select the default instruction 67330b57cec5SDimitry Andric SelectCode(Node); 67340b57cec5SDimitry Andric } 67350b57cec5SDimitry Andric 67360b57cec5SDimitry Andric /// createAArch64ISelDag - This pass converts a legalized DAG into a 67370b57cec5SDimitry Andric /// AArch64-specific DAG, ready for instruction scheduling. 67380b57cec5SDimitry Andric FunctionPass *llvm::createAArch64ISelDag(AArch64TargetMachine &TM, 67395f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 67400b57cec5SDimitry Andric return new AArch64DAGToDAGISel(TM, OptLevel); 67410b57cec5SDimitry Andric } 67425ffd83dbSDimitry Andric 67435ffd83dbSDimitry Andric /// When \p PredVT is a scalable vector predicate in the form 67445ffd83dbSDimitry Andric /// MVT::nx<M>xi1, it builds the correspondent scalable vector of 6745979e22ffSDimitry Andric /// integers MVT::nx<M>xi<bits> s.t. M x bits = 128. When targeting 6746979e22ffSDimitry Andric /// structured vectors (NumVec >1), the output data type is 6747979e22ffSDimitry Andric /// MVT::nx<M*NumVec>xi<bits> s.t. M x bits = 128. If the input 67485ffd83dbSDimitry Andric /// PredVT is not in the form MVT::nx<M>xi1, it returns an invalid 67495ffd83dbSDimitry Andric /// EVT. 6750979e22ffSDimitry Andric static EVT getPackedVectorTypeFromPredicateType(LLVMContext &Ctx, EVT PredVT, 6751979e22ffSDimitry Andric unsigned NumVec) { 6752979e22ffSDimitry Andric assert(NumVec > 0 && NumVec < 5 && "Invalid number of vectors."); 67535ffd83dbSDimitry Andric if (!PredVT.isScalableVector() || PredVT.getVectorElementType() != MVT::i1) 67545ffd83dbSDimitry Andric return EVT(); 67555ffd83dbSDimitry Andric 67565ffd83dbSDimitry Andric if (PredVT != MVT::nxv16i1 && PredVT != MVT::nxv8i1 && 67575ffd83dbSDimitry Andric PredVT != MVT::nxv4i1 && PredVT != MVT::nxv2i1) 67585ffd83dbSDimitry Andric return EVT(); 67595ffd83dbSDimitry Andric 67605ffd83dbSDimitry Andric ElementCount EC = PredVT.getVectorElementCount(); 6761e8d8bef9SDimitry Andric EVT ScalarVT = 6762e8d8bef9SDimitry Andric EVT::getIntegerVT(Ctx, AArch64::SVEBitsPerBlock / EC.getKnownMinValue()); 6763979e22ffSDimitry Andric EVT MemVT = EVT::getVectorVT(Ctx, ScalarVT, EC * NumVec); 6764979e22ffSDimitry Andric 67655ffd83dbSDimitry Andric return MemVT; 67665ffd83dbSDimitry Andric } 67675ffd83dbSDimitry Andric 67685ffd83dbSDimitry Andric /// Return the EVT of the data associated to a memory operation in \p 67695ffd83dbSDimitry Andric /// Root. If such EVT cannot be retrived, it returns an invalid EVT. 67705ffd83dbSDimitry Andric static EVT getMemVTFromNode(LLVMContext &Ctx, SDNode *Root) { 67715ffd83dbSDimitry Andric if (isa<MemSDNode>(Root)) 67725ffd83dbSDimitry Andric return cast<MemSDNode>(Root)->getMemoryVT(); 67735ffd83dbSDimitry Andric 67745ffd83dbSDimitry Andric if (isa<MemIntrinsicSDNode>(Root)) 67755ffd83dbSDimitry Andric return cast<MemIntrinsicSDNode>(Root)->getMemoryVT(); 67765ffd83dbSDimitry Andric 67775ffd83dbSDimitry Andric const unsigned Opcode = Root->getOpcode(); 67785ffd83dbSDimitry Andric // For custom ISD nodes, we have to look at them individually to extract the 67795ffd83dbSDimitry Andric // type of the data moved to/from memory. 67805ffd83dbSDimitry Andric switch (Opcode) { 67815ffd83dbSDimitry Andric case AArch64ISD::LD1_MERGE_ZERO: 67825ffd83dbSDimitry Andric case AArch64ISD::LD1S_MERGE_ZERO: 67835ffd83dbSDimitry Andric case AArch64ISD::LDNF1_MERGE_ZERO: 67845ffd83dbSDimitry Andric case AArch64ISD::LDNF1S_MERGE_ZERO: 67855ffd83dbSDimitry Andric return cast<VTSDNode>(Root->getOperand(3))->getVT(); 67865ffd83dbSDimitry Andric case AArch64ISD::ST1_PRED: 67875ffd83dbSDimitry Andric return cast<VTSDNode>(Root->getOperand(4))->getVT(); 6788979e22ffSDimitry Andric case AArch64ISD::SVE_LD2_MERGE_ZERO: 6789979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 6790979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/2); 6791979e22ffSDimitry Andric case AArch64ISD::SVE_LD3_MERGE_ZERO: 6792979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 6793979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/3); 6794979e22ffSDimitry Andric case AArch64ISD::SVE_LD4_MERGE_ZERO: 6795979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 6796979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/4); 67975ffd83dbSDimitry Andric default: 67985ffd83dbSDimitry Andric break; 67995ffd83dbSDimitry Andric } 68005ffd83dbSDimitry Andric 6801bdd1243dSDimitry Andric if (Opcode != ISD::INTRINSIC_VOID && Opcode != ISD::INTRINSIC_W_CHAIN) 68025ffd83dbSDimitry Andric return EVT(); 68035ffd83dbSDimitry Andric 6804647cbc5dSDimitry Andric switch (Root->getConstantOperandVal(1)) { 6805bdd1243dSDimitry Andric default: 6806bdd1243dSDimitry Andric return EVT(); 6807bdd1243dSDimitry Andric case Intrinsic::aarch64_sme_ldr: 6808bdd1243dSDimitry Andric case Intrinsic::aarch64_sme_str: 680981ad6265SDimitry Andric return MVT::nxv16i8; 6810bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_prf: 6811bdd1243dSDimitry Andric // We are using an SVE prefetch intrinsic. Type must be inferred from the 6812bdd1243dSDimitry Andric // width of the predicate. 68135ffd83dbSDimitry Andric return getPackedVectorTypeFromPredicateType( 6814979e22ffSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/1); 6815bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: 68165f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld2q_sret: 6817bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 6818bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/2); 68195f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st2q: 68205f757f3fSDimitry Andric return getPackedVectorTypeFromPredicateType( 68215f757f3fSDimitry Andric Ctx, Root->getOperand(4)->getValueType(0), /*NumVec=*/2); 6822bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: 68235f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld3q_sret: 6824bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 6825bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/3); 68265f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st3q: 68275f757f3fSDimitry Andric return getPackedVectorTypeFromPredicateType( 68285f757f3fSDimitry Andric Ctx, Root->getOperand(5)->getValueType(0), /*NumVec=*/3); 6829bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: 68305f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld4q_sret: 6831bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 6832bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/4); 68335f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st4q: 68345f757f3fSDimitry Andric return getPackedVectorTypeFromPredicateType( 68355f757f3fSDimitry Andric Ctx, Root->getOperand(6)->getValueType(0), /*NumVec=*/4); 68365f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld1udq: 68375f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st1udq: 68385f757f3fSDimitry Andric return EVT(MVT::nxv1i64); 68395f757f3fSDimitry Andric case Intrinsic::aarch64_sve_ld1uwq: 68405f757f3fSDimitry Andric case Intrinsic::aarch64_sve_st1uwq: 68415f757f3fSDimitry Andric return EVT(MVT::nxv1i32); 6842bdd1243dSDimitry Andric } 68435ffd83dbSDimitry Andric } 68445ffd83dbSDimitry Andric 68455ffd83dbSDimitry Andric /// SelectAddrModeIndexedSVE - Attempt selection of the addressing mode: 68465ffd83dbSDimitry Andric /// Base + OffImm * sizeof(MemVT) for Min >= OffImm <= Max 68475ffd83dbSDimitry Andric /// where Root is the memory access using N for its address. 68485ffd83dbSDimitry Andric template <int64_t Min, int64_t Max> 68495ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexedSVE(SDNode *Root, SDValue N, 68505ffd83dbSDimitry Andric SDValue &Base, 68515ffd83dbSDimitry Andric SDValue &OffImm) { 68525ffd83dbSDimitry Andric const EVT MemVT = getMemVTFromNode(*(CurDAG->getContext()), Root); 6853349cc55cSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 685481ad6265SDimitry Andric const MachineFrameInfo &MFI = MF->getFrameInfo(); 6855349cc55cSDimitry Andric 6856349cc55cSDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 6857349cc55cSDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 685881ad6265SDimitry Andric // We can only encode VL scaled offsets, so only fold in frame indexes 685981ad6265SDimitry Andric // referencing SVE objects. 686006c3fb27SDimitry Andric if (MFI.getStackID(FI) == TargetStackID::ScalableVector) { 6861349cc55cSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 6862349cc55cSDimitry Andric OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 6863349cc55cSDimitry Andric return true; 6864349cc55cSDimitry Andric } 68655ffd83dbSDimitry Andric 686681ad6265SDimitry Andric return false; 686781ad6265SDimitry Andric } 686881ad6265SDimitry Andric 68695ffd83dbSDimitry Andric if (MemVT == EVT()) 68705ffd83dbSDimitry Andric return false; 68715ffd83dbSDimitry Andric 68725ffd83dbSDimitry Andric if (N.getOpcode() != ISD::ADD) 68735ffd83dbSDimitry Andric return false; 68745ffd83dbSDimitry Andric 68755ffd83dbSDimitry Andric SDValue VScale = N.getOperand(1); 68765ffd83dbSDimitry Andric if (VScale.getOpcode() != ISD::VSCALE) 68775ffd83dbSDimitry Andric return false; 68785ffd83dbSDimitry Andric 68795ffd83dbSDimitry Andric TypeSize TS = MemVT.getSizeInBits(); 6880bdd1243dSDimitry Andric int64_t MemWidthBytes = static_cast<int64_t>(TS.getKnownMinValue()) / 8; 68815ffd83dbSDimitry Andric int64_t MulImm = cast<ConstantSDNode>(VScale.getOperand(0))->getSExtValue(); 68825ffd83dbSDimitry Andric 68835ffd83dbSDimitry Andric if ((MulImm % MemWidthBytes) != 0) 68845ffd83dbSDimitry Andric return false; 68855ffd83dbSDimitry Andric 68865ffd83dbSDimitry Andric int64_t Offset = MulImm / MemWidthBytes; 68875ffd83dbSDimitry Andric if (Offset < Min || Offset > Max) 68885ffd83dbSDimitry Andric return false; 68895ffd83dbSDimitry Andric 68905ffd83dbSDimitry Andric Base = N.getOperand(0); 6891349cc55cSDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 6892349cc55cSDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 689381ad6265SDimitry Andric // We can only encode VL scaled offsets, so only fold in frame indexes 689481ad6265SDimitry Andric // referencing SVE objects. 689506c3fb27SDimitry Andric if (MFI.getStackID(FI) == TargetStackID::ScalableVector) 6896349cc55cSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 6897349cc55cSDimitry Andric } 6898349cc55cSDimitry Andric 68995ffd83dbSDimitry Andric OffImm = CurDAG->getTargetConstant(Offset, SDLoc(N), MVT::i64); 69005ffd83dbSDimitry Andric return true; 69015ffd83dbSDimitry Andric } 69025ffd83dbSDimitry Andric 69035ffd83dbSDimitry Andric /// Select register plus register addressing mode for SVE, with scaled 69045ffd83dbSDimitry Andric /// offset. 69055ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectSVERegRegAddrMode(SDValue N, unsigned Scale, 69065ffd83dbSDimitry Andric SDValue &Base, 69075ffd83dbSDimitry Andric SDValue &Offset) { 69085ffd83dbSDimitry Andric if (N.getOpcode() != ISD::ADD) 69095ffd83dbSDimitry Andric return false; 69105ffd83dbSDimitry Andric 69115ffd83dbSDimitry Andric // Process an ADD node. 69125ffd83dbSDimitry Andric const SDValue LHS = N.getOperand(0); 69135ffd83dbSDimitry Andric const SDValue RHS = N.getOperand(1); 69145ffd83dbSDimitry Andric 69155ffd83dbSDimitry Andric // 8 bit data does not come with the SHL node, so it is treated 69165ffd83dbSDimitry Andric // separately. 69175ffd83dbSDimitry Andric if (Scale == 0) { 69185ffd83dbSDimitry Andric Base = LHS; 69195ffd83dbSDimitry Andric Offset = RHS; 69205ffd83dbSDimitry Andric return true; 69215ffd83dbSDimitry Andric } 69225ffd83dbSDimitry Andric 6923fe6060f1SDimitry Andric if (auto C = dyn_cast<ConstantSDNode>(RHS)) { 6924fe6060f1SDimitry Andric int64_t ImmOff = C->getSExtValue(); 6925fe6060f1SDimitry Andric unsigned Size = 1 << Scale; 6926fe6060f1SDimitry Andric 6927fe6060f1SDimitry Andric // To use the reg+reg addressing mode, the immediate must be a multiple of 6928fe6060f1SDimitry Andric // the vector element's byte size. 6929fe6060f1SDimitry Andric if (ImmOff % Size) 6930fe6060f1SDimitry Andric return false; 6931fe6060f1SDimitry Andric 6932fe6060f1SDimitry Andric SDLoc DL(N); 6933fe6060f1SDimitry Andric Base = LHS; 6934fe6060f1SDimitry Andric Offset = CurDAG->getTargetConstant(ImmOff >> Scale, DL, MVT::i64); 6935fe6060f1SDimitry Andric SDValue Ops[] = {Offset}; 6936fe6060f1SDimitry Andric SDNode *MI = CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops); 6937fe6060f1SDimitry Andric Offset = SDValue(MI, 0); 6938fe6060f1SDimitry Andric return true; 6939fe6060f1SDimitry Andric } 6940fe6060f1SDimitry Andric 69415ffd83dbSDimitry Andric // Check if the RHS is a shift node with a constant. 69425ffd83dbSDimitry Andric if (RHS.getOpcode() != ISD::SHL) 69435ffd83dbSDimitry Andric return false; 69445ffd83dbSDimitry Andric 69455ffd83dbSDimitry Andric const SDValue ShiftRHS = RHS.getOperand(1); 69465ffd83dbSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(ShiftRHS)) 69475ffd83dbSDimitry Andric if (C->getZExtValue() == Scale) { 69485ffd83dbSDimitry Andric Base = LHS; 69495ffd83dbSDimitry Andric Offset = RHS.getOperand(0); 69505ffd83dbSDimitry Andric return true; 69515ffd83dbSDimitry Andric } 69525ffd83dbSDimitry Andric 69535ffd83dbSDimitry Andric return false; 69545ffd83dbSDimitry Andric } 6955fe6060f1SDimitry Andric 6956fe6060f1SDimitry Andric bool AArch64DAGToDAGISel::SelectAllActivePredicate(SDValue N) { 6957fe6060f1SDimitry Andric const AArch64TargetLowering *TLI = 6958fe6060f1SDimitry Andric static_cast<const AArch64TargetLowering *>(getTargetLowering()); 6959fe6060f1SDimitry Andric 696004eeddc0SDimitry Andric return TLI->isAllActivePredicate(*CurDAG, N); 6961fe6060f1SDimitry Andric } 696281ad6265SDimitry Andric 696306c3fb27SDimitry Andric bool AArch64DAGToDAGISel::SelectAnyPredicate(SDValue N) { 696406c3fb27SDimitry Andric EVT VT = N.getValueType(); 696506c3fb27SDimitry Andric return VT.isScalableVector() && VT.getVectorElementType() == MVT::i1; 696606c3fb27SDimitry Andric } 696706c3fb27SDimitry Andric 6968bdd1243dSDimitry Andric bool AArch64DAGToDAGISel::SelectSMETileSlice(SDValue N, unsigned MaxSize, 6969bdd1243dSDimitry Andric SDValue &Base, SDValue &Offset, 6970bdd1243dSDimitry Andric unsigned Scale) { 697106c3fb27SDimitry Andric // Try to untangle an ADD node into a 'reg + offset' 697206c3fb27SDimitry Andric if (N.getOpcode() == ISD::ADD) 697306c3fb27SDimitry Andric if (auto C = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 697481ad6265SDimitry Andric int64_t ImmOff = C->getSExtValue(); 697506c3fb27SDimitry Andric if ((ImmOff > 0 && ImmOff <= MaxSize && (ImmOff % Scale == 0))) { 697606c3fb27SDimitry Andric Base = N.getOperand(0); 6977bdd1243dSDimitry Andric Offset = CurDAG->getTargetConstant(ImmOff / Scale, SDLoc(N), MVT::i64); 697881ad6265SDimitry Andric return true; 697981ad6265SDimitry Andric } 698006c3fb27SDimitry Andric } 698181ad6265SDimitry Andric 698206c3fb27SDimitry Andric // By default, just match reg + 0. 698306c3fb27SDimitry Andric Base = N; 698406c3fb27SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 698506c3fb27SDimitry Andric return true; 698681ad6265SDimitry Andric } 6987