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" 17*bdd1243dSDimitry 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" 32*bdd1243dSDimitry 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: 47*bdd1243dSDimitry Andric static char ID; 48*bdd1243dSDimitry Andric 49*bdd1243dSDimitry Andric AArch64DAGToDAGISel() = delete; 50*bdd1243dSDimitry Andric 510b57cec5SDimitry Andric explicit AArch64DAGToDAGISel(AArch64TargetMachine &tm, 520b57cec5SDimitry Andric CodeGenOpt::Level OptLevel) 53*bdd1243dSDimitry 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, 650b57cec5SDimitry Andric unsigned 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 tryMLAV64LaneV128(SDNode *N); 720b57cec5SDimitry Andric bool tryMULLV64LaneV128(unsigned IntNo, SDNode *N); 730b57cec5SDimitry Andric bool SelectArithExtendedRegister(SDValue N, SDValue &Reg, SDValue &Shift); 74fcaf7f86SDimitry Andric bool SelectArithUXTXRegister(SDValue N, SDValue &Reg, SDValue &Shift); 750b57cec5SDimitry Andric bool SelectArithImmed(SDValue N, SDValue &Val, SDValue &Shift); 760b57cec5SDimitry Andric bool SelectNegArithImmed(SDValue N, SDValue &Val, SDValue &Shift); 770b57cec5SDimitry Andric bool SelectArithShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) { 780b57cec5SDimitry Andric return SelectShiftedRegister(N, false, Reg, Shift); 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric bool SelectLogicalShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) { 810b57cec5SDimitry Andric return SelectShiftedRegister(N, true, Reg, Shift); 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric bool SelectAddrModeIndexed7S8(SDValue N, SDValue &Base, SDValue &OffImm) { 840b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 1, Base, OffImm); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric bool SelectAddrModeIndexed7S16(SDValue N, SDValue &Base, SDValue &OffImm) { 870b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 2, Base, OffImm); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric bool SelectAddrModeIndexed7S32(SDValue N, SDValue &Base, SDValue &OffImm) { 900b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 4, Base, OffImm); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric bool SelectAddrModeIndexed7S64(SDValue N, SDValue &Base, SDValue &OffImm) { 930b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 8, Base, OffImm); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric bool SelectAddrModeIndexed7S128(SDValue N, SDValue &Base, SDValue &OffImm) { 960b57cec5SDimitry Andric return SelectAddrModeIndexed7S(N, 16, Base, OffImm); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric bool SelectAddrModeIndexedS9S128(SDValue N, SDValue &Base, SDValue &OffImm) { 990b57cec5SDimitry Andric return SelectAddrModeIndexedBitWidth(N, true, 9, 16, Base, OffImm); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric bool SelectAddrModeIndexedU6S128(SDValue N, SDValue &Base, SDValue &OffImm) { 1020b57cec5SDimitry Andric return SelectAddrModeIndexedBitWidth(N, false, 6, 16, Base, OffImm); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric bool SelectAddrModeIndexed8(SDValue N, SDValue &Base, SDValue &OffImm) { 1050b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 1, Base, OffImm); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric bool SelectAddrModeIndexed16(SDValue N, SDValue &Base, SDValue &OffImm) { 1080b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 2, Base, OffImm); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric bool SelectAddrModeIndexed32(SDValue N, SDValue &Base, SDValue &OffImm) { 1110b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 4, Base, OffImm); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric bool SelectAddrModeIndexed64(SDValue N, SDValue &Base, SDValue &OffImm) { 1140b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 8, Base, OffImm); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric bool SelectAddrModeIndexed128(SDValue N, SDValue &Base, SDValue &OffImm) { 1170b57cec5SDimitry Andric return SelectAddrModeIndexed(N, 16, Base, OffImm); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric bool SelectAddrModeUnscaled8(SDValue N, SDValue &Base, SDValue &OffImm) { 1200b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 1, Base, OffImm); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric bool SelectAddrModeUnscaled16(SDValue N, SDValue &Base, SDValue &OffImm) { 1230b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 2, Base, OffImm); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric bool SelectAddrModeUnscaled32(SDValue N, SDValue &Base, SDValue &OffImm) { 1260b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 4, Base, OffImm); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric bool SelectAddrModeUnscaled64(SDValue N, SDValue &Base, SDValue &OffImm) { 1290b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 8, Base, OffImm); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric bool SelectAddrModeUnscaled128(SDValue N, SDValue &Base, SDValue &OffImm) { 1320b57cec5SDimitry Andric return SelectAddrModeUnscaled(N, 16, Base, OffImm); 1330b57cec5SDimitry Andric } 134fe6060f1SDimitry Andric template <unsigned Size, unsigned Max> 135fe6060f1SDimitry Andric bool SelectAddrModeIndexedUImm(SDValue N, SDValue &Base, SDValue &OffImm) { 136fe6060f1SDimitry Andric // Test if there is an appropriate addressing mode and check if the 137fe6060f1SDimitry Andric // immediate fits. 138fe6060f1SDimitry Andric bool Found = SelectAddrModeIndexed(N, Size, Base, OffImm); 139fe6060f1SDimitry Andric if (Found) { 140fe6060f1SDimitry Andric if (auto *CI = dyn_cast<ConstantSDNode>(OffImm)) { 141fe6060f1SDimitry Andric int64_t C = CI->getSExtValue(); 142fe6060f1SDimitry Andric if (C <= Max) 143fe6060f1SDimitry Andric return true; 144fe6060f1SDimitry Andric } 145fe6060f1SDimitry Andric } 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric // Otherwise, base only, materialize address in register. 148fe6060f1SDimitry Andric Base = N; 149fe6060f1SDimitry Andric OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 150fe6060f1SDimitry Andric return true; 151fe6060f1SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric template<int Width> 1540b57cec5SDimitry Andric bool SelectAddrModeWRO(SDValue N, SDValue &Base, SDValue &Offset, 1550b57cec5SDimitry Andric SDValue &SignExtend, SDValue &DoShift) { 1560b57cec5SDimitry Andric return SelectAddrModeWRO(N, Width / 8, Base, Offset, SignExtend, DoShift); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric template<int Width> 1600b57cec5SDimitry Andric bool SelectAddrModeXRO(SDValue N, SDValue &Base, SDValue &Offset, 1610b57cec5SDimitry Andric SDValue &SignExtend, SDValue &DoShift) { 1620b57cec5SDimitry Andric return SelectAddrModeXRO(N, Width / 8, Base, Offset, SignExtend, DoShift); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 16581ad6265SDimitry Andric bool SelectExtractHigh(SDValue N, SDValue &Res) { 16681ad6265SDimitry Andric if (Subtarget->isLittleEndian() && N->getOpcode() == ISD::BITCAST) 16781ad6265SDimitry Andric N = N->getOperand(0); 16881ad6265SDimitry Andric if (N->getOpcode() != ISD::EXTRACT_SUBVECTOR || 16981ad6265SDimitry Andric !isa<ConstantSDNode>(N->getOperand(1))) 17081ad6265SDimitry Andric return false; 17181ad6265SDimitry Andric EVT VT = N->getValueType(0); 17281ad6265SDimitry Andric EVT LVT = N->getOperand(0).getValueType(); 17381ad6265SDimitry Andric unsigned Index = N->getConstantOperandVal(1); 17481ad6265SDimitry Andric if (!VT.is64BitVector() || !LVT.is128BitVector() || 17581ad6265SDimitry Andric Index != VT.getVectorNumElements()) 17681ad6265SDimitry Andric return false; 17781ad6265SDimitry Andric Res = N->getOperand(0); 17881ad6265SDimitry Andric return true; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 181*bdd1243dSDimitry Andric bool SelectRoundingVLShr(SDValue N, SDValue &Res1, SDValue &Res2) { 182*bdd1243dSDimitry Andric if (N.getOpcode() != AArch64ISD::VLSHR) 183*bdd1243dSDimitry Andric return false; 184*bdd1243dSDimitry Andric SDValue Op = N->getOperand(0); 185*bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 186*bdd1243dSDimitry Andric unsigned ShtAmt = N->getConstantOperandVal(1); 187*bdd1243dSDimitry Andric if (ShtAmt > VT.getScalarSizeInBits() / 2 || Op.getOpcode() != ISD::ADD) 188*bdd1243dSDimitry Andric return false; 189*bdd1243dSDimitry Andric 190*bdd1243dSDimitry Andric APInt Imm; 191*bdd1243dSDimitry Andric if (Op.getOperand(1).getOpcode() == AArch64ISD::MOVIshift) 192*bdd1243dSDimitry Andric Imm = APInt(VT.getScalarSizeInBits(), 193*bdd1243dSDimitry Andric Op.getOperand(1).getConstantOperandVal(0) 194*bdd1243dSDimitry Andric << Op.getOperand(1).getConstantOperandVal(1)); 195*bdd1243dSDimitry Andric else if (Op.getOperand(1).getOpcode() == AArch64ISD::DUP && 196*bdd1243dSDimitry Andric isa<ConstantSDNode>(Op.getOperand(1).getOperand(0))) 197*bdd1243dSDimitry Andric Imm = APInt(VT.getScalarSizeInBits(), 198*bdd1243dSDimitry Andric Op.getOperand(1).getConstantOperandVal(0)); 199*bdd1243dSDimitry Andric else 200*bdd1243dSDimitry Andric return false; 201*bdd1243dSDimitry Andric 202*bdd1243dSDimitry Andric if (Imm != 1ULL << (ShtAmt - 1)) 203*bdd1243dSDimitry Andric return false; 204*bdd1243dSDimitry Andric 205*bdd1243dSDimitry Andric Res1 = Op.getOperand(0); 206*bdd1243dSDimitry Andric Res2 = CurDAG->getTargetConstant(ShtAmt, SDLoc(N), MVT::i32); 207*bdd1243dSDimitry Andric return true; 208*bdd1243dSDimitry Andric } 209*bdd1243dSDimitry Andric 210480093f4SDimitry Andric bool SelectDupZeroOrUndef(SDValue N) { 211480093f4SDimitry Andric switch(N->getOpcode()) { 212480093f4SDimitry Andric case ISD::UNDEF: 213480093f4SDimitry Andric return true; 214480093f4SDimitry Andric case AArch64ISD::DUP: 215480093f4SDimitry Andric case ISD::SPLAT_VECTOR: { 216480093f4SDimitry Andric auto Opnd0 = N->getOperand(0); 217*bdd1243dSDimitry Andric if (isNullConstant(Opnd0)) 218480093f4SDimitry Andric return true; 219*bdd1243dSDimitry Andric if (isNullFPConstant(Opnd0)) 220480093f4SDimitry Andric return true; 221480093f4SDimitry Andric break; 222480093f4SDimitry Andric } 223480093f4SDimitry Andric default: 224480093f4SDimitry Andric break; 225480093f4SDimitry Andric } 226480093f4SDimitry Andric 227480093f4SDimitry Andric return false; 228480093f4SDimitry Andric } 229480093f4SDimitry Andric 2305ffd83dbSDimitry Andric bool SelectDupZero(SDValue N) { 2315ffd83dbSDimitry Andric switch(N->getOpcode()) { 2325ffd83dbSDimitry Andric case AArch64ISD::DUP: 2335ffd83dbSDimitry Andric case ISD::SPLAT_VECTOR: { 2345ffd83dbSDimitry Andric auto Opnd0 = N->getOperand(0); 235*bdd1243dSDimitry Andric if (isNullConstant(Opnd0)) 2365ffd83dbSDimitry Andric return true; 237*bdd1243dSDimitry Andric if (isNullFPConstant(Opnd0)) 2385ffd83dbSDimitry Andric return true; 2395ffd83dbSDimitry Andric break; 2405ffd83dbSDimitry Andric } 2415ffd83dbSDimitry Andric } 2425ffd83dbSDimitry Andric 2435ffd83dbSDimitry Andric return false; 2445ffd83dbSDimitry Andric } 2455ffd83dbSDimitry Andric 246480093f4SDimitry Andric template<MVT::SimpleValueType VT> 247480093f4SDimitry Andric bool SelectSVEAddSubImm(SDValue N, SDValue &Imm, SDValue &Shift) { 248480093f4SDimitry Andric return SelectSVEAddSubImm(N, VT, Imm, Shift); 249480093f4SDimitry Andric } 250480093f4SDimitry Andric 25181ad6265SDimitry Andric template <MVT::SimpleValueType VT> 25281ad6265SDimitry Andric bool SelectSVECpyDupImm(SDValue N, SDValue &Imm, SDValue &Shift) { 25381ad6265SDimitry Andric return SelectSVECpyDupImm(N, VT, Imm, Shift); 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric 256fe6060f1SDimitry Andric template <MVT::SimpleValueType VT, bool Invert = false> 257480093f4SDimitry Andric bool SelectSVELogicalImm(SDValue N, SDValue &Imm) { 258fe6060f1SDimitry Andric return SelectSVELogicalImm(N, VT, Imm, Invert); 259480093f4SDimitry Andric } 260480093f4SDimitry Andric 261e8d8bef9SDimitry Andric template <MVT::SimpleValueType VT> 262e8d8bef9SDimitry Andric bool SelectSVEArithImm(SDValue N, SDValue &Imm) { 263e8d8bef9SDimitry Andric return SelectSVEArithImm(N, VT, Imm); 264e8d8bef9SDimitry Andric } 265e8d8bef9SDimitry Andric 266e8d8bef9SDimitry Andric template <unsigned Low, unsigned High, bool AllowSaturation = false> 267e8d8bef9SDimitry Andric bool SelectSVEShiftImm(SDValue N, SDValue &Imm) { 268e8d8bef9SDimitry Andric return SelectSVEShiftImm(N, Low, High, AllowSaturation, Imm); 2695ffd83dbSDimitry Andric } 2705ffd83dbSDimitry Andric 27181ad6265SDimitry Andric bool SelectSVEShiftSplatImmR(SDValue N, SDValue &Imm) { 27281ad6265SDimitry Andric if (N->getOpcode() != ISD::SPLAT_VECTOR) 27381ad6265SDimitry Andric return false; 27481ad6265SDimitry Andric 27581ad6265SDimitry Andric EVT EltVT = N->getValueType(0).getVectorElementType(); 27681ad6265SDimitry Andric return SelectSVEShiftImm(N->getOperand(0), /* Low */ 1, 27781ad6265SDimitry Andric /* High */ EltVT.getFixedSizeInBits(), 27881ad6265SDimitry Andric /* AllowSaturation */ true, Imm); 27981ad6265SDimitry Andric } 28081ad6265SDimitry Andric 281480093f4SDimitry Andric // Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N. 282480093f4SDimitry Andric template<signed Min, signed Max, signed Scale, bool Shift> 283480093f4SDimitry Andric bool SelectCntImm(SDValue N, SDValue &Imm) { 284480093f4SDimitry Andric if (!isa<ConstantSDNode>(N)) 285480093f4SDimitry Andric return false; 286480093f4SDimitry Andric 287480093f4SDimitry Andric int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue(); 288480093f4SDimitry Andric if (Shift) 289480093f4SDimitry Andric MulImm = 1LL << MulImm; 290480093f4SDimitry Andric 291480093f4SDimitry Andric if ((MulImm % std::abs(Scale)) != 0) 292480093f4SDimitry Andric return false; 293480093f4SDimitry Andric 294480093f4SDimitry Andric MulImm /= Scale; 295480093f4SDimitry Andric if ((MulImm >= Min) && (MulImm <= Max)) { 296480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(MulImm, SDLoc(N), MVT::i32); 297480093f4SDimitry Andric return true; 298480093f4SDimitry Andric } 299480093f4SDimitry Andric 300480093f4SDimitry Andric return false; 301480093f4SDimitry Andric } 3020b57cec5SDimitry Andric 303fe6060f1SDimitry Andric template <signed Max, signed Scale> 304fe6060f1SDimitry Andric bool SelectEXTImm(SDValue N, SDValue &Imm) { 305fe6060f1SDimitry Andric if (!isa<ConstantSDNode>(N)) 306fe6060f1SDimitry Andric return false; 307fe6060f1SDimitry Andric 308fe6060f1SDimitry Andric int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue(); 309fe6060f1SDimitry Andric 310fe6060f1SDimitry Andric if (MulImm >= 0 && MulImm <= Max) { 311fe6060f1SDimitry Andric MulImm *= Scale; 312fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(MulImm, SDLoc(N), MVT::i32); 313fe6060f1SDimitry Andric return true; 314fe6060f1SDimitry Andric } 315fe6060f1SDimitry Andric 316fe6060f1SDimitry Andric return false; 317fe6060f1SDimitry Andric } 318fe6060f1SDimitry Andric 31981ad6265SDimitry Andric template <unsigned BaseReg> bool ImmToTile(SDValue N, SDValue &Imm) { 32081ad6265SDimitry Andric if (auto *CI = dyn_cast<ConstantSDNode>(N)) { 32181ad6265SDimitry Andric uint64_t C = CI->getZExtValue(); 32281ad6265SDimitry Andric Imm = CurDAG->getRegister(BaseReg + C, MVT::Other); 32381ad6265SDimitry Andric return true; 32481ad6265SDimitry Andric } 32581ad6265SDimitry Andric return false; 32681ad6265SDimitry Andric } 32781ad6265SDimitry Andric 3280b57cec5SDimitry Andric /// Form sequences of consecutive 64/128-bit registers for use in NEON 3290b57cec5SDimitry Andric /// instructions making use of a vector-list (e.g. ldN, tbl). Vecs must have 3300b57cec5SDimitry Andric /// between 1 and 4 elements. If it contains a single element that is returned 3310b57cec5SDimitry Andric /// unchanged; otherwise a REG_SEQUENCE value is returned. 3320b57cec5SDimitry Andric SDValue createDTuple(ArrayRef<SDValue> Vecs); 3330b57cec5SDimitry Andric SDValue createQTuple(ArrayRef<SDValue> Vecs); 3345ffd83dbSDimitry Andric // Form a sequence of SVE registers for instructions using list of vectors, 3355ffd83dbSDimitry Andric // e.g. structured loads and stores (ldN, stN). 3365ffd83dbSDimitry Andric SDValue createZTuple(ArrayRef<SDValue> Vecs); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric /// Generic helper for the createDTuple/createQTuple 3390b57cec5SDimitry Andric /// functions. Those should almost always be called instead. 3400b57cec5SDimitry Andric SDValue createTuple(ArrayRef<SDValue> Vecs, const unsigned RegClassIDs[], 3410b57cec5SDimitry Andric const unsigned SubRegs[]); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric void SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc, bool isExt); 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric bool tryIndexedLoad(SDNode *N); 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric bool trySelectStackSlotTagP(SDNode *N); 3480b57cec5SDimitry Andric void SelectTagP(SDNode *N); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric void SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc, 3510b57cec5SDimitry Andric unsigned SubRegIdx); 3520b57cec5SDimitry Andric void SelectPostLoad(SDNode *N, unsigned NumVecs, unsigned Opc, 3530b57cec5SDimitry Andric unsigned SubRegIdx); 3540b57cec5SDimitry Andric void SelectLoadLane(SDNode *N, unsigned NumVecs, unsigned Opc); 3550b57cec5SDimitry Andric void SelectPostLoadLane(SDNode *N, unsigned NumVecs, unsigned Opc); 356979e22ffSDimitry Andric void SelectPredicatedLoad(SDNode *N, unsigned NumVecs, unsigned Scale, 357349cc55cSDimitry Andric unsigned Opc_rr, unsigned Opc_ri, 358349cc55cSDimitry Andric bool IsIntr = false); 359*bdd1243dSDimitry Andric void SelectWhilePair(SDNode *N, unsigned Opc); 360*bdd1243dSDimitry Andric void SelectCVTIntrinsic(SDNode *N, unsigned NumVecs, unsigned Opcode); 3615ffd83dbSDimitry Andric 3625ffd83dbSDimitry Andric bool SelectAddrModeFrameIndexSVE(SDValue N, SDValue &Base, SDValue &OffImm); 3635ffd83dbSDimitry Andric /// SVE Reg+Imm addressing mode. 3645ffd83dbSDimitry Andric template <int64_t Min, int64_t Max> 3655ffd83dbSDimitry Andric bool SelectAddrModeIndexedSVE(SDNode *Root, SDValue N, SDValue &Base, 3665ffd83dbSDimitry Andric SDValue &OffImm); 3675ffd83dbSDimitry Andric /// SVE Reg+Reg address mode. 3685ffd83dbSDimitry Andric template <unsigned Scale> 3695ffd83dbSDimitry Andric bool SelectSVERegRegAddrMode(SDValue N, SDValue &Base, SDValue &Offset) { 3705ffd83dbSDimitry Andric return SelectSVERegRegAddrMode(N, Scale, Base, Offset); 3715ffd83dbSDimitry Andric } 3720b57cec5SDimitry Andric 373*bdd1243dSDimitry Andric template <unsigned MaxIdx, unsigned Scale> 37481ad6265SDimitry Andric bool SelectSMETileSlice(SDValue N, SDValue &Vector, SDValue &Offset) { 375*bdd1243dSDimitry Andric return SelectSMETileSlice(N, MaxIdx, Vector, Offset, Scale); 37681ad6265SDimitry Andric } 37781ad6265SDimitry Andric 3780b57cec5SDimitry Andric void SelectStore(SDNode *N, unsigned NumVecs, unsigned Opc); 3790b57cec5SDimitry Andric void SelectPostStore(SDNode *N, unsigned NumVecs, unsigned Opc); 3800b57cec5SDimitry Andric void SelectStoreLane(SDNode *N, unsigned NumVecs, unsigned Opc); 3810b57cec5SDimitry Andric void SelectPostStoreLane(SDNode *N, unsigned NumVecs, unsigned Opc); 382979e22ffSDimitry Andric void SelectPredicatedStore(SDNode *N, unsigned NumVecs, unsigned Scale, 383979e22ffSDimitry Andric unsigned Opc_rr, unsigned Opc_ri); 3845ffd83dbSDimitry Andric std::tuple<unsigned, SDValue, SDValue> 385979e22ffSDimitry Andric findAddrModeSVELoadStore(SDNode *N, unsigned Opc_rr, unsigned Opc_ri, 386979e22ffSDimitry Andric const SDValue &OldBase, const SDValue &OldOffset, 387979e22ffSDimitry Andric unsigned Scale); 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric bool tryBitfieldExtractOp(SDNode *N); 3900b57cec5SDimitry Andric bool tryBitfieldExtractOpFromSExt(SDNode *N); 3910b57cec5SDimitry Andric bool tryBitfieldInsertOp(SDNode *N); 3920b57cec5SDimitry Andric bool tryBitfieldInsertInZeroOp(SDNode *N); 3930b57cec5SDimitry Andric bool tryShiftAmountMod(SDNode *N); 394480093f4SDimitry Andric bool tryHighFPExt(SDNode *N); 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric bool tryReadRegister(SDNode *N); 3970b57cec5SDimitry Andric bool tryWriteRegister(SDNode *N); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric // Include the pieces autogenerated from the target description. 4000b57cec5SDimitry Andric #include "AArch64GenDAGISel.inc" 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric private: 4030b57cec5SDimitry Andric bool SelectShiftedRegister(SDValue N, bool AllowROR, SDValue &Reg, 4040b57cec5SDimitry Andric SDValue &Shift); 405*bdd1243dSDimitry Andric bool SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg, SDValue &Shift); 4060b57cec5SDimitry Andric bool SelectAddrModeIndexed7S(SDValue N, unsigned Size, SDValue &Base, 4070b57cec5SDimitry Andric SDValue &OffImm) { 4080b57cec5SDimitry Andric return SelectAddrModeIndexedBitWidth(N, true, 7, Size, Base, OffImm); 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric bool SelectAddrModeIndexedBitWidth(SDValue N, bool IsSignedImm, unsigned BW, 4110b57cec5SDimitry Andric unsigned Size, SDValue &Base, 4120b57cec5SDimitry Andric SDValue &OffImm); 4130b57cec5SDimitry Andric bool SelectAddrModeIndexed(SDValue N, unsigned Size, SDValue &Base, 4140b57cec5SDimitry Andric SDValue &OffImm); 4150b57cec5SDimitry Andric bool SelectAddrModeUnscaled(SDValue N, unsigned Size, SDValue &Base, 4160b57cec5SDimitry Andric SDValue &OffImm); 4170b57cec5SDimitry Andric bool SelectAddrModeWRO(SDValue N, unsigned Size, SDValue &Base, 4180b57cec5SDimitry Andric SDValue &Offset, SDValue &SignExtend, 4190b57cec5SDimitry Andric SDValue &DoShift); 4200b57cec5SDimitry Andric bool SelectAddrModeXRO(SDValue N, unsigned Size, SDValue &Base, 4210b57cec5SDimitry Andric SDValue &Offset, SDValue &SignExtend, 4220b57cec5SDimitry Andric SDValue &DoShift); 4230b57cec5SDimitry Andric bool isWorthFolding(SDValue V) const; 4240b57cec5SDimitry Andric bool SelectExtendedSHL(SDValue N, unsigned Size, bool WantExtend, 4250b57cec5SDimitry Andric SDValue &Offset, SDValue &SignExtend); 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric template<unsigned RegWidth> 4280b57cec5SDimitry Andric bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos) { 4290b57cec5SDimitry Andric return SelectCVTFixedPosOperand(N, FixedPos, RegWidth); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, unsigned Width); 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric bool SelectCMP_SWAP(SDNode *N); 4350b57cec5SDimitry Andric 436480093f4SDimitry Andric bool SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift); 43781ad6265SDimitry Andric bool SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm, SDValue &Shift); 438fe6060f1SDimitry Andric bool SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm, bool Invert); 439480093f4SDimitry Andric 440480093f4SDimitry Andric bool SelectSVESignedArithImm(SDValue N, SDValue &Imm); 441e8d8bef9SDimitry Andric bool SelectSVEShiftImm(SDValue N, uint64_t Low, uint64_t High, 442e8d8bef9SDimitry Andric bool AllowSaturation, SDValue &Imm); 443480093f4SDimitry Andric 444e8d8bef9SDimitry Andric bool SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm); 4455ffd83dbSDimitry Andric bool SelectSVERegRegAddrMode(SDValue N, unsigned Scale, SDValue &Base, 4465ffd83dbSDimitry Andric SDValue &Offset); 447*bdd1243dSDimitry Andric bool SelectSMETileSlice(SDValue N, unsigned MaxSize, SDValue &Vector, 448*bdd1243dSDimitry Andric SDValue &Offset, unsigned Scale = 1); 449fe6060f1SDimitry Andric 450fe6060f1SDimitry Andric bool SelectAllActivePredicate(SDValue N); 4510b57cec5SDimitry Andric }; 4520b57cec5SDimitry Andric } // end anonymous namespace 4530b57cec5SDimitry Andric 454*bdd1243dSDimitry Andric char AArch64DAGToDAGISel::ID = 0; 455*bdd1243dSDimitry Andric 456*bdd1243dSDimitry Andric INITIALIZE_PASS(AArch64DAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 457*bdd1243dSDimitry Andric 4580b57cec5SDimitry Andric /// isIntImmediate - This method tests to see if the node is a constant 4590b57cec5SDimitry Andric /// operand. If so Imm will receive the 32-bit value. 4600b57cec5SDimitry Andric static bool isIntImmediate(const SDNode *N, uint64_t &Imm) { 4610b57cec5SDimitry Andric if (const ConstantSDNode *C = dyn_cast<const ConstantSDNode>(N)) { 4620b57cec5SDimitry Andric Imm = C->getZExtValue(); 4630b57cec5SDimitry Andric return true; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric return false; 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric // isIntImmediate - This method tests to see if a constant operand. 4690b57cec5SDimitry Andric // If so Imm will receive the value. 4700b57cec5SDimitry Andric static bool isIntImmediate(SDValue N, uint64_t &Imm) { 4710b57cec5SDimitry Andric return isIntImmediate(N.getNode(), Imm); 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric // isOpcWithIntImmediate - This method tests to see if the node is a specific 4750b57cec5SDimitry Andric // opcode and that it has a immediate integer right operand. 4760b57cec5SDimitry Andric // If so Imm will receive the 32 bit value. 4770b57cec5SDimitry Andric static bool isOpcWithIntImmediate(const SDNode *N, unsigned Opc, 4780b57cec5SDimitry Andric uint64_t &Imm) { 4790b57cec5SDimitry Andric return N->getOpcode() == Opc && 4800b57cec5SDimitry Andric isIntImmediate(N->getOperand(1).getNode(), Imm); 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 483*bdd1243dSDimitry Andric // isIntImmediateEq - This method tests to see if N is a constant operand that 484*bdd1243dSDimitry Andric // is equivalent to 'ImmExpected'. 485*bdd1243dSDimitry Andric #ifndef NDEBUG 486*bdd1243dSDimitry Andric static bool isIntImmediateEq(SDValue N, const uint64_t ImmExpected) { 487*bdd1243dSDimitry Andric uint64_t Imm; 488*bdd1243dSDimitry Andric if (!isIntImmediate(N.getNode(), Imm)) 489*bdd1243dSDimitry Andric return false; 490*bdd1243dSDimitry Andric return Imm == ImmExpected; 491*bdd1243dSDimitry Andric } 492*bdd1243dSDimitry Andric #endif 493*bdd1243dSDimitry Andric 4940b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectInlineAsmMemoryOperand( 4950b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 4960b57cec5SDimitry Andric switch(ConstraintID) { 4970b57cec5SDimitry Andric default: 4980b57cec5SDimitry Andric llvm_unreachable("Unexpected asm memory constraint"); 4990b57cec5SDimitry Andric case InlineAsm::Constraint_m: 500fe6060f1SDimitry Andric case InlineAsm::Constraint_o: 5010b57cec5SDimitry Andric case InlineAsm::Constraint_Q: 5020b57cec5SDimitry Andric // We need to make sure that this one operand does not end up in XZR, thus 5030b57cec5SDimitry Andric // require the address to be in a PointerRegClass register. 5040b57cec5SDimitry Andric const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); 5050b57cec5SDimitry Andric const TargetRegisterClass *TRC = TRI->getPointerRegClass(*MF); 5060b57cec5SDimitry Andric SDLoc dl(Op); 5070b57cec5SDimitry Andric SDValue RC = CurDAG->getTargetConstant(TRC->getID(), dl, MVT::i64); 5080b57cec5SDimitry Andric SDValue NewOp = 5090b57cec5SDimitry Andric SDValue(CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 5100b57cec5SDimitry Andric dl, Op.getValueType(), 5110b57cec5SDimitry Andric Op, RC), 0); 5120b57cec5SDimitry Andric OutOps.push_back(NewOp); 5130b57cec5SDimitry Andric return false; 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric return true; 5160b57cec5SDimitry Andric } 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric /// SelectArithImmed - Select an immediate value that can be represented as 5190b57cec5SDimitry Andric /// a 12-bit value shifted left by either 0 or 12. If so, return true with 5200b57cec5SDimitry Andric /// Val set to the 12-bit value and Shift set to the shifter operand. 5210b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectArithImmed(SDValue N, SDValue &Val, 5220b57cec5SDimitry Andric SDValue &Shift) { 5230b57cec5SDimitry Andric // This function is called from the addsub_shifted_imm ComplexPattern, 5240b57cec5SDimitry Andric // which lists [imm] as the list of opcode it's interested in, however 5250b57cec5SDimitry Andric // we still need to check whether the operand is actually an immediate 5260b57cec5SDimitry Andric // here because the ComplexPattern opcode list is only used in 5270b57cec5SDimitry Andric // root-level opcode matching. 5280b57cec5SDimitry Andric if (!isa<ConstantSDNode>(N.getNode())) 5290b57cec5SDimitry Andric return false; 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric uint64_t Immed = cast<ConstantSDNode>(N.getNode())->getZExtValue(); 5320b57cec5SDimitry Andric unsigned ShiftAmt; 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric if (Immed >> 12 == 0) { 5350b57cec5SDimitry Andric ShiftAmt = 0; 5360b57cec5SDimitry Andric } else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) { 5370b57cec5SDimitry Andric ShiftAmt = 12; 5380b57cec5SDimitry Andric Immed = Immed >> 12; 5390b57cec5SDimitry Andric } else 5400b57cec5SDimitry Andric return false; 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt); 5430b57cec5SDimitry Andric SDLoc dl(N); 5440b57cec5SDimitry Andric Val = CurDAG->getTargetConstant(Immed, dl, MVT::i32); 5450b57cec5SDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, dl, MVT::i32); 5460b57cec5SDimitry Andric return true; 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric /// SelectNegArithImmed - As above, but negates the value before trying to 5500b57cec5SDimitry Andric /// select it. 5510b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectNegArithImmed(SDValue N, SDValue &Val, 5520b57cec5SDimitry Andric SDValue &Shift) { 5530b57cec5SDimitry Andric // This function is called from the addsub_shifted_imm ComplexPattern, 5540b57cec5SDimitry Andric // which lists [imm] as the list of opcode it's interested in, however 5550b57cec5SDimitry Andric // we still need to check whether the operand is actually an immediate 5560b57cec5SDimitry Andric // here because the ComplexPattern opcode list is only used in 5570b57cec5SDimitry Andric // root-level opcode matching. 5580b57cec5SDimitry Andric if (!isa<ConstantSDNode>(N.getNode())) 5590b57cec5SDimitry Andric return false; 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric // The immediate operand must be a 24-bit zero-extended immediate. 5620b57cec5SDimitry Andric uint64_t Immed = cast<ConstantSDNode>(N.getNode())->getZExtValue(); 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric // This negation is almost always valid, but "cmp wN, #0" and "cmn wN, #0" 5650b57cec5SDimitry Andric // have the opposite effect on the C flag, so this pattern mustn't match under 5660b57cec5SDimitry Andric // those circumstances. 5670b57cec5SDimitry Andric if (Immed == 0) 5680b57cec5SDimitry Andric return false; 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric if (N.getValueType() == MVT::i32) 5710b57cec5SDimitry Andric Immed = ~((uint32_t)Immed) + 1; 5720b57cec5SDimitry Andric else 5730b57cec5SDimitry Andric Immed = ~Immed + 1ULL; 5740b57cec5SDimitry Andric if (Immed & 0xFFFFFFFFFF000000ULL) 5750b57cec5SDimitry Andric return false; 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric Immed &= 0xFFFFFFULL; 5780b57cec5SDimitry Andric return SelectArithImmed(CurDAG->getConstant(Immed, SDLoc(N), MVT::i32), Val, 5790b57cec5SDimitry Andric Shift); 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric /// getShiftTypeForNode - Translate a shift node to the corresponding 5830b57cec5SDimitry Andric /// ShiftType value. 5840b57cec5SDimitry Andric static AArch64_AM::ShiftExtendType getShiftTypeForNode(SDValue N) { 5850b57cec5SDimitry Andric switch (N.getOpcode()) { 5860b57cec5SDimitry Andric default: 5870b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 5880b57cec5SDimitry Andric case ISD::SHL: 5890b57cec5SDimitry Andric return AArch64_AM::LSL; 5900b57cec5SDimitry Andric case ISD::SRL: 5910b57cec5SDimitry Andric return AArch64_AM::LSR; 5920b57cec5SDimitry Andric case ISD::SRA: 5930b57cec5SDimitry Andric return AArch64_AM::ASR; 5940b57cec5SDimitry Andric case ISD::ROTR: 5950b57cec5SDimitry Andric return AArch64_AM::ROR; 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric } 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric /// Determine whether it is worth it to fold SHL into the addressing 6000b57cec5SDimitry Andric /// mode. 6010b57cec5SDimitry Andric static bool isWorthFoldingSHL(SDValue V) { 6020b57cec5SDimitry Andric assert(V.getOpcode() == ISD::SHL && "invalid opcode"); 6030b57cec5SDimitry Andric // It is worth folding logical shift of up to three places. 6040b57cec5SDimitry Andric auto *CSD = dyn_cast<ConstantSDNode>(V.getOperand(1)); 6050b57cec5SDimitry Andric if (!CSD) 6060b57cec5SDimitry Andric return false; 6070b57cec5SDimitry Andric unsigned ShiftVal = CSD->getZExtValue(); 6080b57cec5SDimitry Andric if (ShiftVal > 3) 6090b57cec5SDimitry Andric return false; 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric // Check if this particular node is reused in any non-memory related 6120b57cec5SDimitry Andric // operation. If yes, do not try to fold this node into the address 6130b57cec5SDimitry Andric // computation, since the computation will be kept. 6140b57cec5SDimitry Andric const SDNode *Node = V.getNode(); 6150b57cec5SDimitry Andric for (SDNode *UI : Node->uses()) 6160b57cec5SDimitry Andric if (!isa<MemSDNode>(*UI)) 6170b57cec5SDimitry Andric for (SDNode *UII : UI->uses()) 6180b57cec5SDimitry Andric if (!isa<MemSDNode>(*UII)) 6190b57cec5SDimitry Andric return false; 6200b57cec5SDimitry Andric return true; 6210b57cec5SDimitry Andric } 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric /// Determine whether it is worth to fold V into an extended register. 6240b57cec5SDimitry Andric bool AArch64DAGToDAGISel::isWorthFolding(SDValue V) const { 6250b57cec5SDimitry Andric // Trivial if we are optimizing for code size or if there is only 6260b57cec5SDimitry Andric // one use of the value. 627480093f4SDimitry Andric if (CurDAG->shouldOptForSize() || V.hasOneUse()) 6280b57cec5SDimitry Andric return true; 6290b57cec5SDimitry Andric // If a subtarget has a fastpath LSL we can fold a logical shift into 6300b57cec5SDimitry Andric // the addressing mode and save a cycle. 6310b57cec5SDimitry Andric if (Subtarget->hasLSLFast() && V.getOpcode() == ISD::SHL && 6320b57cec5SDimitry Andric isWorthFoldingSHL(V)) 6330b57cec5SDimitry Andric return true; 6340b57cec5SDimitry Andric if (Subtarget->hasLSLFast() && V.getOpcode() == ISD::ADD) { 6350b57cec5SDimitry Andric const SDValue LHS = V.getOperand(0); 6360b57cec5SDimitry Andric const SDValue RHS = V.getOperand(1); 6370b57cec5SDimitry Andric if (LHS.getOpcode() == ISD::SHL && isWorthFoldingSHL(LHS)) 6380b57cec5SDimitry Andric return true; 6390b57cec5SDimitry Andric if (RHS.getOpcode() == ISD::SHL && isWorthFoldingSHL(RHS)) 6400b57cec5SDimitry Andric return true; 6410b57cec5SDimitry Andric } 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric // It hurts otherwise, since the value will be reused. 6440b57cec5SDimitry Andric return false; 6450b57cec5SDimitry Andric } 6460b57cec5SDimitry Andric 647*bdd1243dSDimitry Andric /// and (shl/srl/sra, x, c), mask --> shl (srl/sra, x, c1), c2 648*bdd1243dSDimitry Andric /// to select more shifted register 649*bdd1243dSDimitry Andric bool AArch64DAGToDAGISel::SelectShiftedRegisterFromAnd(SDValue N, SDValue &Reg, 650*bdd1243dSDimitry Andric SDValue &Shift) { 651*bdd1243dSDimitry Andric EVT VT = N.getValueType(); 652*bdd1243dSDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 653*bdd1243dSDimitry Andric return false; 654*bdd1243dSDimitry Andric 655*bdd1243dSDimitry Andric if (N->getOpcode() != ISD::AND || !N->hasOneUse()) 656*bdd1243dSDimitry Andric return false; 657*bdd1243dSDimitry Andric SDValue LHS = N.getOperand(0); 658*bdd1243dSDimitry Andric if (!LHS->hasOneUse()) 659*bdd1243dSDimitry Andric return false; 660*bdd1243dSDimitry Andric 661*bdd1243dSDimitry Andric unsigned LHSOpcode = LHS->getOpcode(); 662*bdd1243dSDimitry Andric if (LHSOpcode != ISD::SHL && LHSOpcode != ISD::SRL && LHSOpcode != ISD::SRA) 663*bdd1243dSDimitry Andric return false; 664*bdd1243dSDimitry Andric 665*bdd1243dSDimitry Andric ConstantSDNode *ShiftAmtNode = dyn_cast<ConstantSDNode>(LHS.getOperand(1)); 666*bdd1243dSDimitry Andric if (!ShiftAmtNode) 667*bdd1243dSDimitry Andric return false; 668*bdd1243dSDimitry Andric 669*bdd1243dSDimitry Andric uint64_t ShiftAmtC = ShiftAmtNode->getZExtValue(); 670*bdd1243dSDimitry Andric ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(N.getOperand(1)); 671*bdd1243dSDimitry Andric if (!RHSC) 672*bdd1243dSDimitry Andric return false; 673*bdd1243dSDimitry Andric 674*bdd1243dSDimitry Andric APInt AndMask = RHSC->getAPIntValue(); 675*bdd1243dSDimitry Andric unsigned LowZBits, MaskLen; 676*bdd1243dSDimitry Andric if (!AndMask.isShiftedMask(LowZBits, MaskLen)) 677*bdd1243dSDimitry Andric return false; 678*bdd1243dSDimitry Andric 679*bdd1243dSDimitry Andric unsigned BitWidth = N.getValueSizeInBits(); 680*bdd1243dSDimitry Andric SDLoc DL(LHS); 681*bdd1243dSDimitry Andric uint64_t NewShiftC; 682*bdd1243dSDimitry Andric unsigned NewShiftOp; 683*bdd1243dSDimitry Andric if (LHSOpcode == ISD::SHL) { 684*bdd1243dSDimitry Andric // LowZBits <= ShiftAmtC will fall into isBitfieldPositioningOp 685*bdd1243dSDimitry Andric // BitWidth != LowZBits + MaskLen doesn't match the pattern 686*bdd1243dSDimitry Andric if (LowZBits <= ShiftAmtC || (BitWidth != LowZBits + MaskLen)) 687*bdd1243dSDimitry Andric return false; 688*bdd1243dSDimitry Andric 689*bdd1243dSDimitry Andric NewShiftC = LowZBits - ShiftAmtC; 690*bdd1243dSDimitry Andric NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri; 691*bdd1243dSDimitry Andric } else { 692*bdd1243dSDimitry Andric if (LowZBits == 0) 693*bdd1243dSDimitry Andric return false; 694*bdd1243dSDimitry Andric 695*bdd1243dSDimitry Andric // NewShiftC >= BitWidth will fall into isBitfieldExtractOp 696*bdd1243dSDimitry Andric NewShiftC = LowZBits + ShiftAmtC; 697*bdd1243dSDimitry Andric if (NewShiftC >= BitWidth) 698*bdd1243dSDimitry Andric return false; 699*bdd1243dSDimitry Andric 700*bdd1243dSDimitry Andric // SRA need all high bits 701*bdd1243dSDimitry Andric if (LHSOpcode == ISD::SRA && (BitWidth != (LowZBits + MaskLen))) 702*bdd1243dSDimitry Andric return false; 703*bdd1243dSDimitry Andric 704*bdd1243dSDimitry Andric // SRL high bits can be 0 or 1 705*bdd1243dSDimitry Andric if (LHSOpcode == ISD::SRL && (BitWidth > (NewShiftC + MaskLen))) 706*bdd1243dSDimitry Andric return false; 707*bdd1243dSDimitry Andric 708*bdd1243dSDimitry Andric if (LHSOpcode == ISD::SRL) 709*bdd1243dSDimitry Andric NewShiftOp = VT == MVT::i64 ? AArch64::UBFMXri : AArch64::UBFMWri; 710*bdd1243dSDimitry Andric else 711*bdd1243dSDimitry Andric NewShiftOp = VT == MVT::i64 ? AArch64::SBFMXri : AArch64::SBFMWri; 712*bdd1243dSDimitry Andric } 713*bdd1243dSDimitry Andric 714*bdd1243dSDimitry Andric assert(NewShiftC < BitWidth && "Invalid shift amount"); 715*bdd1243dSDimitry Andric SDValue NewShiftAmt = CurDAG->getTargetConstant(NewShiftC, DL, VT); 716*bdd1243dSDimitry Andric SDValue BitWidthMinus1 = CurDAG->getTargetConstant(BitWidth - 1, DL, VT); 717*bdd1243dSDimitry Andric Reg = SDValue(CurDAG->getMachineNode(NewShiftOp, DL, VT, LHS->getOperand(0), 718*bdd1243dSDimitry Andric NewShiftAmt, BitWidthMinus1), 719*bdd1243dSDimitry Andric 0); 720*bdd1243dSDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, LowZBits); 721*bdd1243dSDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, DL, MVT::i32); 722*bdd1243dSDimitry Andric return true; 723*bdd1243dSDimitry Andric } 724*bdd1243dSDimitry Andric 7250b57cec5SDimitry Andric /// SelectShiftedRegister - Select a "shifted register" operand. If the value 7260b57cec5SDimitry Andric /// is not shifted, set the Shift operand to default of "LSL 0". The logical 7270b57cec5SDimitry Andric /// instructions allow the shifted register to be rotated, but the arithmetic 7280b57cec5SDimitry Andric /// instructions do not. The AllowROR parameter specifies whether ROR is 7290b57cec5SDimitry Andric /// supported. 7300b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectShiftedRegister(SDValue N, bool AllowROR, 7310b57cec5SDimitry Andric SDValue &Reg, SDValue &Shift) { 732*bdd1243dSDimitry Andric if (SelectShiftedRegisterFromAnd(N, Reg, Shift)) 733*bdd1243dSDimitry Andric return true; 734*bdd1243dSDimitry Andric 7350b57cec5SDimitry Andric AArch64_AM::ShiftExtendType ShType = getShiftTypeForNode(N); 7360b57cec5SDimitry Andric if (ShType == AArch64_AM::InvalidShiftExtend) 7370b57cec5SDimitry Andric return false; 7380b57cec5SDimitry Andric if (!AllowROR && ShType == AArch64_AM::ROR) 7390b57cec5SDimitry Andric return false; 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 7420b57cec5SDimitry Andric unsigned BitSize = N.getValueSizeInBits(); 7430b57cec5SDimitry Andric unsigned Val = RHS->getZExtValue() & (BitSize - 1); 7440b57cec5SDimitry Andric unsigned ShVal = AArch64_AM::getShifterImm(ShType, Val); 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric Reg = N.getOperand(0); 7470b57cec5SDimitry Andric Shift = CurDAG->getTargetConstant(ShVal, SDLoc(N), MVT::i32); 7480b57cec5SDimitry Andric return isWorthFolding(N); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric return false; 7520b57cec5SDimitry Andric } 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric /// getExtendTypeForNode - Translate an extend node to the corresponding 7550b57cec5SDimitry Andric /// ExtendType value. 7560b57cec5SDimitry Andric static AArch64_AM::ShiftExtendType 7570b57cec5SDimitry Andric getExtendTypeForNode(SDValue N, bool IsLoadStore = false) { 7580b57cec5SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND || 7590b57cec5SDimitry Andric N.getOpcode() == ISD::SIGN_EXTEND_INREG) { 7600b57cec5SDimitry Andric EVT SrcVT; 7610b57cec5SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG) 7620b57cec5SDimitry Andric SrcVT = cast<VTSDNode>(N.getOperand(1))->getVT(); 7630b57cec5SDimitry Andric else 7640b57cec5SDimitry Andric SrcVT = N.getOperand(0).getValueType(); 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric if (!IsLoadStore && SrcVT == MVT::i8) 7670b57cec5SDimitry Andric return AArch64_AM::SXTB; 7680b57cec5SDimitry Andric else if (!IsLoadStore && SrcVT == MVT::i16) 7690b57cec5SDimitry Andric return AArch64_AM::SXTH; 7700b57cec5SDimitry Andric else if (SrcVT == MVT::i32) 7710b57cec5SDimitry Andric return AArch64_AM::SXTW; 7720b57cec5SDimitry Andric assert(SrcVT != MVT::i64 && "extend from 64-bits?"); 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 7750b57cec5SDimitry Andric } else if (N.getOpcode() == ISD::ZERO_EXTEND || 7760b57cec5SDimitry Andric N.getOpcode() == ISD::ANY_EXTEND) { 7770b57cec5SDimitry Andric EVT SrcVT = N.getOperand(0).getValueType(); 7780b57cec5SDimitry Andric if (!IsLoadStore && SrcVT == MVT::i8) 7790b57cec5SDimitry Andric return AArch64_AM::UXTB; 7800b57cec5SDimitry Andric else if (!IsLoadStore && SrcVT == MVT::i16) 7810b57cec5SDimitry Andric return AArch64_AM::UXTH; 7820b57cec5SDimitry Andric else if (SrcVT == MVT::i32) 7830b57cec5SDimitry Andric return AArch64_AM::UXTW; 7840b57cec5SDimitry Andric assert(SrcVT != MVT::i64 && "extend from 64-bits?"); 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 7870b57cec5SDimitry Andric } else if (N.getOpcode() == ISD::AND) { 7880b57cec5SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 7890b57cec5SDimitry Andric if (!CSD) 7900b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 7910b57cec5SDimitry Andric uint64_t AndMask = CSD->getZExtValue(); 7920b57cec5SDimitry Andric 7930b57cec5SDimitry Andric switch (AndMask) { 7940b57cec5SDimitry Andric default: 7950b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 7960b57cec5SDimitry Andric case 0xFF: 7970b57cec5SDimitry Andric return !IsLoadStore ? AArch64_AM::UXTB : AArch64_AM::InvalidShiftExtend; 7980b57cec5SDimitry Andric case 0xFFFF: 7990b57cec5SDimitry Andric return !IsLoadStore ? AArch64_AM::UXTH : AArch64_AM::InvalidShiftExtend; 8000b57cec5SDimitry Andric case 0xFFFFFFFF: 8010b57cec5SDimitry Andric return AArch64_AM::UXTW; 8020b57cec5SDimitry Andric } 8030b57cec5SDimitry Andric } 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric return AArch64_AM::InvalidShiftExtend; 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric // Helper for SelectMLAV64LaneV128 - Recognize high lane extracts. 8090b57cec5SDimitry Andric static bool checkHighLaneIndex(SDNode *DL, SDValue &LaneOp, int &LaneIdx) { 8100b57cec5SDimitry Andric if (DL->getOpcode() != AArch64ISD::DUPLANE16 && 8110b57cec5SDimitry Andric DL->getOpcode() != AArch64ISD::DUPLANE32) 8120b57cec5SDimitry Andric return false; 8130b57cec5SDimitry Andric 8140b57cec5SDimitry Andric SDValue SV = DL->getOperand(0); 8150b57cec5SDimitry Andric if (SV.getOpcode() != ISD::INSERT_SUBVECTOR) 8160b57cec5SDimitry Andric return false; 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric SDValue EV = SV.getOperand(1); 8190b57cec5SDimitry Andric if (EV.getOpcode() != ISD::EXTRACT_SUBVECTOR) 8200b57cec5SDimitry Andric return false; 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric ConstantSDNode *DLidx = cast<ConstantSDNode>(DL->getOperand(1).getNode()); 8230b57cec5SDimitry Andric ConstantSDNode *EVidx = cast<ConstantSDNode>(EV.getOperand(1).getNode()); 8240b57cec5SDimitry Andric LaneIdx = DLidx->getSExtValue() + EVidx->getSExtValue(); 8250b57cec5SDimitry Andric LaneOp = EV.getOperand(0); 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric return true; 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric // Helper for SelectOpcV64LaneV128 - Recognize operations where one operand is a 8310b57cec5SDimitry Andric // high lane extract. 8320b57cec5SDimitry Andric static bool checkV64LaneV128(SDValue Op0, SDValue Op1, SDValue &StdOp, 8330b57cec5SDimitry Andric SDValue &LaneOp, int &LaneIdx) { 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric if (!checkHighLaneIndex(Op0.getNode(), LaneOp, LaneIdx)) { 8360b57cec5SDimitry Andric std::swap(Op0, Op1); 8370b57cec5SDimitry Andric if (!checkHighLaneIndex(Op0.getNode(), LaneOp, LaneIdx)) 8380b57cec5SDimitry Andric return false; 8390b57cec5SDimitry Andric } 8400b57cec5SDimitry Andric StdOp = Op1; 8410b57cec5SDimitry Andric return true; 8420b57cec5SDimitry Andric } 8430b57cec5SDimitry Andric 8440b57cec5SDimitry Andric /// SelectMLAV64LaneV128 - AArch64 supports vector MLAs where one multiplicand 8450b57cec5SDimitry Andric /// is a lane in the upper half of a 128-bit vector. Recognize and select this 8460b57cec5SDimitry Andric /// so that we don't emit unnecessary lane extracts. 8470b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryMLAV64LaneV128(SDNode *N) { 8480b57cec5SDimitry Andric SDLoc dl(N); 8490b57cec5SDimitry Andric SDValue Op0 = N->getOperand(0); 8500b57cec5SDimitry Andric SDValue Op1 = N->getOperand(1); 8510b57cec5SDimitry Andric SDValue MLAOp1; // Will hold ordinary multiplicand for MLA. 8520b57cec5SDimitry Andric SDValue MLAOp2; // Will hold lane-accessed multiplicand for MLA. 8530b57cec5SDimitry Andric int LaneIdx = -1; // Will hold the lane index. 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric if (Op1.getOpcode() != ISD::MUL || 8560b57cec5SDimitry Andric !checkV64LaneV128(Op1.getOperand(0), Op1.getOperand(1), MLAOp1, MLAOp2, 8570b57cec5SDimitry Andric LaneIdx)) { 8580b57cec5SDimitry Andric std::swap(Op0, Op1); 8590b57cec5SDimitry Andric if (Op1.getOpcode() != ISD::MUL || 8600b57cec5SDimitry Andric !checkV64LaneV128(Op1.getOperand(0), Op1.getOperand(1), MLAOp1, MLAOp2, 8610b57cec5SDimitry Andric LaneIdx)) 8620b57cec5SDimitry Andric return false; 8630b57cec5SDimitry Andric } 8640b57cec5SDimitry Andric 8650b57cec5SDimitry Andric SDValue LaneIdxVal = CurDAG->getTargetConstant(LaneIdx, dl, MVT::i64); 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric SDValue Ops[] = { Op0, MLAOp1, MLAOp2, LaneIdxVal }; 8680b57cec5SDimitry Andric 8690b57cec5SDimitry Andric unsigned MLAOpc = ~0U; 8700b57cec5SDimitry Andric 8710b57cec5SDimitry Andric switch (N->getSimpleValueType(0).SimpleTy) { 8720b57cec5SDimitry Andric default: 8730b57cec5SDimitry Andric llvm_unreachable("Unrecognized MLA."); 8740b57cec5SDimitry Andric case MVT::v4i16: 8750b57cec5SDimitry Andric MLAOpc = AArch64::MLAv4i16_indexed; 8760b57cec5SDimitry Andric break; 8770b57cec5SDimitry Andric case MVT::v8i16: 8780b57cec5SDimitry Andric MLAOpc = AArch64::MLAv8i16_indexed; 8790b57cec5SDimitry Andric break; 8800b57cec5SDimitry Andric case MVT::v2i32: 8810b57cec5SDimitry Andric MLAOpc = AArch64::MLAv2i32_indexed; 8820b57cec5SDimitry Andric break; 8830b57cec5SDimitry Andric case MVT::v4i32: 8840b57cec5SDimitry Andric MLAOpc = AArch64::MLAv4i32_indexed; 8850b57cec5SDimitry Andric break; 8860b57cec5SDimitry Andric } 8870b57cec5SDimitry Andric 8880b57cec5SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(MLAOpc, dl, N->getValueType(0), Ops)); 8890b57cec5SDimitry Andric return true; 8900b57cec5SDimitry Andric } 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryMULLV64LaneV128(unsigned IntNo, SDNode *N) { 8930b57cec5SDimitry Andric SDLoc dl(N); 8940b57cec5SDimitry Andric SDValue SMULLOp0; 8950b57cec5SDimitry Andric SDValue SMULLOp1; 8960b57cec5SDimitry Andric int LaneIdx; 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric if (!checkV64LaneV128(N->getOperand(1), N->getOperand(2), SMULLOp0, SMULLOp1, 8990b57cec5SDimitry Andric LaneIdx)) 9000b57cec5SDimitry Andric return false; 9010b57cec5SDimitry Andric 9020b57cec5SDimitry Andric SDValue LaneIdxVal = CurDAG->getTargetConstant(LaneIdx, dl, MVT::i64); 9030b57cec5SDimitry Andric 9040b57cec5SDimitry Andric SDValue Ops[] = { SMULLOp0, SMULLOp1, LaneIdxVal }; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric unsigned SMULLOpc = ~0U; 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric if (IntNo == Intrinsic::aarch64_neon_smull) { 9090b57cec5SDimitry Andric switch (N->getSimpleValueType(0).SimpleTy) { 9100b57cec5SDimitry Andric default: 9110b57cec5SDimitry Andric llvm_unreachable("Unrecognized SMULL."); 9120b57cec5SDimitry Andric case MVT::v4i32: 9130b57cec5SDimitry Andric SMULLOpc = AArch64::SMULLv4i16_indexed; 9140b57cec5SDimitry Andric break; 9150b57cec5SDimitry Andric case MVT::v2i64: 9160b57cec5SDimitry Andric SMULLOpc = AArch64::SMULLv2i32_indexed; 9170b57cec5SDimitry Andric break; 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric } else if (IntNo == Intrinsic::aarch64_neon_umull) { 9200b57cec5SDimitry Andric switch (N->getSimpleValueType(0).SimpleTy) { 9210b57cec5SDimitry Andric default: 9220b57cec5SDimitry Andric llvm_unreachable("Unrecognized SMULL."); 9230b57cec5SDimitry Andric case MVT::v4i32: 9240b57cec5SDimitry Andric SMULLOpc = AArch64::UMULLv4i16_indexed; 9250b57cec5SDimitry Andric break; 9260b57cec5SDimitry Andric case MVT::v2i64: 9270b57cec5SDimitry Andric SMULLOpc = AArch64::UMULLv2i32_indexed; 9280b57cec5SDimitry Andric break; 9290b57cec5SDimitry Andric } 9300b57cec5SDimitry Andric } else 9310b57cec5SDimitry Andric llvm_unreachable("Unrecognized intrinsic."); 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(SMULLOpc, dl, N->getValueType(0), Ops)); 9340b57cec5SDimitry Andric return true; 9350b57cec5SDimitry Andric } 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric /// Instructions that accept extend modifiers like UXTW expect the register 9380b57cec5SDimitry Andric /// being extended to be a GPR32, but the incoming DAG might be acting on a 9390b57cec5SDimitry Andric /// GPR64 (either via SEXT_INREG or AND). Extract the appropriate low bits if 9400b57cec5SDimitry Andric /// this is the case. 9410b57cec5SDimitry Andric static SDValue narrowIfNeeded(SelectionDAG *CurDAG, SDValue N) { 9420b57cec5SDimitry Andric if (N.getValueType() == MVT::i32) 9430b57cec5SDimitry Andric return N; 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric SDLoc dl(N); 9460b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, dl, MVT::i32); 9470b57cec5SDimitry Andric MachineSDNode *Node = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, 9480b57cec5SDimitry Andric dl, MVT::i32, N, SubReg); 9490b57cec5SDimitry Andric return SDValue(Node, 0); 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric 9525ffd83dbSDimitry Andric // Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N. 9535ffd83dbSDimitry Andric template<signed Low, signed High, signed Scale> 9545ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectRDVLImm(SDValue N, SDValue &Imm) { 9555ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(N)) 9565ffd83dbSDimitry Andric return false; 9575ffd83dbSDimitry Andric 9585ffd83dbSDimitry Andric int64_t MulImm = cast<ConstantSDNode>(N)->getSExtValue(); 9595ffd83dbSDimitry Andric if ((MulImm % std::abs(Scale)) == 0) { 9605ffd83dbSDimitry Andric int64_t RDVLImm = MulImm / Scale; 9615ffd83dbSDimitry Andric if ((RDVLImm >= Low) && (RDVLImm <= High)) { 9625ffd83dbSDimitry Andric Imm = CurDAG->getTargetConstant(RDVLImm, SDLoc(N), MVT::i32); 9635ffd83dbSDimitry Andric return true; 9645ffd83dbSDimitry Andric } 9655ffd83dbSDimitry Andric } 9665ffd83dbSDimitry Andric 9675ffd83dbSDimitry Andric return false; 9685ffd83dbSDimitry Andric } 9690b57cec5SDimitry Andric 9700b57cec5SDimitry Andric /// SelectArithExtendedRegister - Select a "extended register" operand. This 9710b57cec5SDimitry Andric /// operand folds in an extend followed by an optional left shift. 9720b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectArithExtendedRegister(SDValue N, SDValue &Reg, 9730b57cec5SDimitry Andric SDValue &Shift) { 9740b57cec5SDimitry Andric unsigned ShiftVal = 0; 9750b57cec5SDimitry Andric AArch64_AM::ShiftExtendType Ext; 9760b57cec5SDimitry Andric 9770b57cec5SDimitry Andric if (N.getOpcode() == ISD::SHL) { 9780b57cec5SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 9790b57cec5SDimitry Andric if (!CSD) 9800b57cec5SDimitry Andric return false; 9810b57cec5SDimitry Andric ShiftVal = CSD->getZExtValue(); 9820b57cec5SDimitry Andric if (ShiftVal > 4) 9830b57cec5SDimitry Andric return false; 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric Ext = getExtendTypeForNode(N.getOperand(0)); 9860b57cec5SDimitry Andric if (Ext == AArch64_AM::InvalidShiftExtend) 9870b57cec5SDimitry Andric return false; 9880b57cec5SDimitry Andric 9890b57cec5SDimitry Andric Reg = N.getOperand(0).getOperand(0); 9900b57cec5SDimitry Andric } else { 9910b57cec5SDimitry Andric Ext = getExtendTypeForNode(N); 9920b57cec5SDimitry Andric if (Ext == AArch64_AM::InvalidShiftExtend) 9930b57cec5SDimitry Andric return false; 9940b57cec5SDimitry Andric 9950b57cec5SDimitry Andric Reg = N.getOperand(0); 9960b57cec5SDimitry Andric 99781ad6265SDimitry Andric // Don't match if free 32-bit -> 64-bit zext can be used instead. Use the 99881ad6265SDimitry Andric // isDef32 as a heuristic for when the operand is likely to be a 32bit def. 99981ad6265SDimitry Andric auto isDef32 = [](SDValue N) { 100081ad6265SDimitry Andric unsigned Opc = N.getOpcode(); 100181ad6265SDimitry Andric return Opc != ISD::TRUNCATE && Opc != TargetOpcode::EXTRACT_SUBREG && 100281ad6265SDimitry Andric Opc != ISD::CopyFromReg && Opc != ISD::AssertSext && 100381ad6265SDimitry Andric Opc != ISD::AssertZext && Opc != ISD::AssertAlign && 100481ad6265SDimitry Andric Opc != ISD::FREEZE; 100581ad6265SDimitry Andric }; 100681ad6265SDimitry Andric if (Ext == AArch64_AM::UXTW && Reg->getValueType(0).getSizeInBits() == 32 && 100781ad6265SDimitry Andric isDef32(Reg)) 10080b57cec5SDimitry Andric return false; 10090b57cec5SDimitry Andric } 10100b57cec5SDimitry Andric 10110b57cec5SDimitry Andric // AArch64 mandates that the RHS of the operation must use the smallest 10120b57cec5SDimitry Andric // register class that could contain the size being extended from. Thus, 10130b57cec5SDimitry Andric // if we're folding a (sext i8), we need the RHS to be a GPR32, even though 10140b57cec5SDimitry Andric // there might not be an actual 32-bit value in the program. We can 10150b57cec5SDimitry Andric // (harmlessly) synthesize one by injected an EXTRACT_SUBREG here. 10160b57cec5SDimitry Andric assert(Ext != AArch64_AM::UXTX && Ext != AArch64_AM::SXTX); 10170b57cec5SDimitry Andric Reg = narrowIfNeeded(CurDAG, Reg); 10180b57cec5SDimitry Andric Shift = CurDAG->getTargetConstant(getArithExtendImm(Ext, ShiftVal), SDLoc(N), 10190b57cec5SDimitry Andric MVT::i32); 10200b57cec5SDimitry Andric return isWorthFolding(N); 10210b57cec5SDimitry Andric } 10220b57cec5SDimitry Andric 1023fcaf7f86SDimitry Andric /// SelectArithUXTXRegister - Select a "UXTX register" operand. This 1024fcaf7f86SDimitry Andric /// operand is refered by the instructions have SP operand 1025fcaf7f86SDimitry Andric bool AArch64DAGToDAGISel::SelectArithUXTXRegister(SDValue N, SDValue &Reg, 1026fcaf7f86SDimitry Andric SDValue &Shift) { 1027fcaf7f86SDimitry Andric unsigned ShiftVal = 0; 1028fcaf7f86SDimitry Andric AArch64_AM::ShiftExtendType Ext; 1029fcaf7f86SDimitry Andric 1030fcaf7f86SDimitry Andric if (N.getOpcode() != ISD::SHL) 1031fcaf7f86SDimitry Andric return false; 1032fcaf7f86SDimitry Andric 1033fcaf7f86SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 1034fcaf7f86SDimitry Andric if (!CSD) 1035fcaf7f86SDimitry Andric return false; 1036fcaf7f86SDimitry Andric ShiftVal = CSD->getZExtValue(); 1037fcaf7f86SDimitry Andric if (ShiftVal > 4) 1038fcaf7f86SDimitry Andric return false; 1039fcaf7f86SDimitry Andric 1040fcaf7f86SDimitry Andric Ext = AArch64_AM::UXTX; 1041fcaf7f86SDimitry Andric Reg = N.getOperand(0); 1042fcaf7f86SDimitry Andric Shift = CurDAG->getTargetConstant(getArithExtendImm(Ext, ShiftVal), SDLoc(N), 1043fcaf7f86SDimitry Andric MVT::i32); 1044fcaf7f86SDimitry Andric return isWorthFolding(N); 1045fcaf7f86SDimitry Andric } 1046fcaf7f86SDimitry Andric 10470b57cec5SDimitry Andric /// If there's a use of this ADDlow that's not itself a load/store then we'll 10480b57cec5SDimitry Andric /// need to create a real ADD instruction from it anyway and there's no point in 10490b57cec5SDimitry Andric /// folding it into the mem op. Theoretically, it shouldn't matter, but there's 10500b57cec5SDimitry Andric /// a single pseudo-instruction for an ADRP/ADD pair so over-aggressive folding 10510b57cec5SDimitry Andric /// leads to duplicated ADRP instructions. 10520b57cec5SDimitry Andric static bool isWorthFoldingADDlow(SDValue N) { 1053*bdd1243dSDimitry Andric for (auto *Use : N->uses()) { 10540b57cec5SDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 10550b57cec5SDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 10560b57cec5SDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 10570b57cec5SDimitry Andric return false; 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric // ldar and stlr have much more restrictive addressing modes (just a 10600b57cec5SDimitry Andric // register). 1061fe6060f1SDimitry Andric if (isStrongerThanMonotonic(cast<MemSDNode>(Use)->getSuccessOrdering())) 10620b57cec5SDimitry Andric return false; 10630b57cec5SDimitry Andric } 10640b57cec5SDimitry Andric 10650b57cec5SDimitry Andric return true; 10660b57cec5SDimitry Andric } 10670b57cec5SDimitry Andric 10680b57cec5SDimitry Andric /// SelectAddrModeIndexedBitWidth - Select a "register plus scaled (un)signed BW-bit 10690b57cec5SDimitry Andric /// immediate" address. The "Size" argument is the size in bytes of the memory 10700b57cec5SDimitry Andric /// reference, which determines the scale. 10710b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexedBitWidth(SDValue N, bool IsSignedImm, 10720b57cec5SDimitry Andric unsigned BW, unsigned Size, 10730b57cec5SDimitry Andric SDValue &Base, 10740b57cec5SDimitry Andric SDValue &OffImm) { 10750b57cec5SDimitry Andric SDLoc dl(N); 10760b57cec5SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 10770b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 10780b57cec5SDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 10790b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 10800b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 10810b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 10820b57cec5SDimitry Andric return true; 10830b57cec5SDimitry Andric } 10840b57cec5SDimitry Andric 10850b57cec5SDimitry Andric // As opposed to the (12-bit) Indexed addressing mode below, the 7/9-bit signed 10860b57cec5SDimitry Andric // selected here doesn't support labels/immediates, only base+offset. 10870b57cec5SDimitry Andric if (CurDAG->isBaseWithConstantOffset(N)) { 10880b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 10890b57cec5SDimitry Andric if (IsSignedImm) { 10900b57cec5SDimitry Andric int64_t RHSC = RHS->getSExtValue(); 10910b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 10920b57cec5SDimitry Andric int64_t Range = 0x1LL << (BW - 1); 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric if ((RHSC & (Size - 1)) == 0 && RHSC >= -(Range << Scale) && 10950b57cec5SDimitry Andric RHSC < (Range << Scale)) { 10960b57cec5SDimitry Andric Base = N.getOperand(0); 10970b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 10980b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 10990b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 11000b57cec5SDimitry Andric } 11010b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64); 11020b57cec5SDimitry Andric return true; 11030b57cec5SDimitry Andric } 11040b57cec5SDimitry Andric } else { 11050b57cec5SDimitry Andric // unsigned Immediate 11060b57cec5SDimitry Andric uint64_t RHSC = RHS->getZExtValue(); 11070b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 11080b57cec5SDimitry Andric uint64_t Range = 0x1ULL << BW; 11090b57cec5SDimitry Andric 11100b57cec5SDimitry Andric if ((RHSC & (Size - 1)) == 0 && RHSC < (Range << Scale)) { 11110b57cec5SDimitry Andric Base = N.getOperand(0); 11120b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 11130b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 11140b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 11150b57cec5SDimitry Andric } 11160b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64); 11170b57cec5SDimitry Andric return true; 11180b57cec5SDimitry Andric } 11190b57cec5SDimitry Andric } 11200b57cec5SDimitry Andric } 11210b57cec5SDimitry Andric } 11220b57cec5SDimitry Andric // Base only. The address will be materialized into a register before 11230b57cec5SDimitry Andric // the memory is accessed. 11240b57cec5SDimitry Andric // add x0, Xbase, #offset 11250b57cec5SDimitry Andric // stp x1, x2, [x0] 11260b57cec5SDimitry Andric Base = N; 11270b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 11280b57cec5SDimitry Andric return true; 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric /// SelectAddrModeIndexed - Select a "register plus scaled unsigned 12-bit 11320b57cec5SDimitry Andric /// immediate" address. The "Size" argument is the size in bytes of the memory 11330b57cec5SDimitry Andric /// reference, which determines the scale. 11340b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexed(SDValue N, unsigned Size, 11350b57cec5SDimitry Andric SDValue &Base, SDValue &OffImm) { 11360b57cec5SDimitry Andric SDLoc dl(N); 11370b57cec5SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 11380b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 11390b57cec5SDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 11400b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 11410b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 11420b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 11430b57cec5SDimitry Andric return true; 11440b57cec5SDimitry Andric } 11450b57cec5SDimitry Andric 11460b57cec5SDimitry Andric if (N.getOpcode() == AArch64ISD::ADDlow && isWorthFoldingADDlow(N)) { 11470b57cec5SDimitry Andric GlobalAddressSDNode *GAN = 11480b57cec5SDimitry Andric dyn_cast<GlobalAddressSDNode>(N.getOperand(1).getNode()); 11490b57cec5SDimitry Andric Base = N.getOperand(0); 11500b57cec5SDimitry Andric OffImm = N.getOperand(1); 11510b57cec5SDimitry Andric if (!GAN) 11520b57cec5SDimitry Andric return true; 11530b57cec5SDimitry Andric 11545ffd83dbSDimitry Andric if (GAN->getOffset() % Size == 0 && 11555ffd83dbSDimitry Andric GAN->getGlobal()->getPointerAlignment(DL) >= Size) 11560b57cec5SDimitry Andric return true; 11570b57cec5SDimitry Andric } 11580b57cec5SDimitry Andric 11590b57cec5SDimitry Andric if (CurDAG->isBaseWithConstantOffset(N)) { 11600b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 11610b57cec5SDimitry Andric int64_t RHSC = (int64_t)RHS->getZExtValue(); 11620b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 11630b57cec5SDimitry Andric if ((RHSC & (Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) { 11640b57cec5SDimitry Andric Base = N.getOperand(0); 11650b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 11660b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 11670b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 11680b57cec5SDimitry Andric } 11690b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC >> Scale, dl, MVT::i64); 11700b57cec5SDimitry Andric return true; 11710b57cec5SDimitry Andric } 11720b57cec5SDimitry Andric } 11730b57cec5SDimitry Andric } 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric // Before falling back to our general case, check if the unscaled 11760b57cec5SDimitry Andric // instructions can handle this. If so, that's preferable. 11770b57cec5SDimitry Andric if (SelectAddrModeUnscaled(N, Size, Base, OffImm)) 11780b57cec5SDimitry Andric return false; 11790b57cec5SDimitry Andric 11800b57cec5SDimitry Andric // Base only. The address will be materialized into a register before 11810b57cec5SDimitry Andric // the memory is accessed. 11820b57cec5SDimitry Andric // add x0, Xbase, #offset 11830b57cec5SDimitry Andric // ldr x0, [x0] 11840b57cec5SDimitry Andric Base = N; 11850b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 11860b57cec5SDimitry Andric return true; 11870b57cec5SDimitry Andric } 11880b57cec5SDimitry Andric 11890b57cec5SDimitry Andric /// SelectAddrModeUnscaled - Select a "register plus unscaled signed 9-bit 11900b57cec5SDimitry Andric /// immediate" address. This should only match when there is an offset that 11910b57cec5SDimitry Andric /// is not valid for a scaled immediate addressing mode. The "Size" argument 11920b57cec5SDimitry Andric /// is the size in bytes of the memory reference, which is needed here to know 11930b57cec5SDimitry Andric /// what is valid for a scaled immediate. 11940b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeUnscaled(SDValue N, unsigned Size, 11950b57cec5SDimitry Andric SDValue &Base, 11960b57cec5SDimitry Andric SDValue &OffImm) { 11970b57cec5SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(N)) 11980b57cec5SDimitry Andric return false; 11990b57cec5SDimitry Andric if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 12000b57cec5SDimitry Andric int64_t RHSC = RHS->getSExtValue(); 12010b57cec5SDimitry Andric // If the offset is valid as a scaled immediate, don't match here. 12020b57cec5SDimitry Andric if ((RHSC & (Size - 1)) == 0 && RHSC >= 0 && 12030b57cec5SDimitry Andric RHSC < (0x1000 << Log2_32(Size))) 12040b57cec5SDimitry Andric return false; 12050b57cec5SDimitry Andric if (RHSC >= -256 && RHSC < 256) { 12060b57cec5SDimitry Andric Base = N.getOperand(0); 12070b57cec5SDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 12080b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 12090b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 12100b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex( 12110b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 12120b57cec5SDimitry Andric } 12130b57cec5SDimitry Andric OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i64); 12140b57cec5SDimitry Andric return true; 12150b57cec5SDimitry Andric } 12160b57cec5SDimitry Andric } 12170b57cec5SDimitry Andric return false; 12180b57cec5SDimitry Andric } 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric static SDValue Widen(SelectionDAG *CurDAG, SDValue N) { 12210b57cec5SDimitry Andric SDLoc dl(N); 12220b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, dl, MVT::i32); 12230b57cec5SDimitry Andric SDValue ImpDef = SDValue( 12240b57cec5SDimitry Andric CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::i64), 0); 12250b57cec5SDimitry Andric MachineSDNode *Node = CurDAG->getMachineNode( 12260b57cec5SDimitry Andric TargetOpcode::INSERT_SUBREG, dl, MVT::i64, ImpDef, N, SubReg); 12270b57cec5SDimitry Andric return SDValue(Node, 0); 12280b57cec5SDimitry Andric } 12290b57cec5SDimitry Andric 12300b57cec5SDimitry Andric /// Check if the given SHL node (\p N), can be used to form an 12310b57cec5SDimitry Andric /// extended register for an addressing mode. 12320b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectExtendedSHL(SDValue N, unsigned Size, 12330b57cec5SDimitry Andric bool WantExtend, SDValue &Offset, 12340b57cec5SDimitry Andric SDValue &SignExtend) { 12350b57cec5SDimitry Andric assert(N.getOpcode() == ISD::SHL && "Invalid opcode."); 12360b57cec5SDimitry Andric ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N.getOperand(1)); 12370b57cec5SDimitry Andric if (!CSD || (CSD->getZExtValue() & 0x7) != CSD->getZExtValue()) 12380b57cec5SDimitry Andric return false; 12390b57cec5SDimitry Andric 12400b57cec5SDimitry Andric SDLoc dl(N); 12410b57cec5SDimitry Andric if (WantExtend) { 12420b57cec5SDimitry Andric AArch64_AM::ShiftExtendType Ext = 12430b57cec5SDimitry Andric getExtendTypeForNode(N.getOperand(0), true); 12440b57cec5SDimitry Andric if (Ext == AArch64_AM::InvalidShiftExtend) 12450b57cec5SDimitry Andric return false; 12460b57cec5SDimitry Andric 12470b57cec5SDimitry Andric Offset = narrowIfNeeded(CurDAG, N.getOperand(0).getOperand(0)); 12480b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl, 12490b57cec5SDimitry Andric MVT::i32); 12500b57cec5SDimitry Andric } else { 12510b57cec5SDimitry Andric Offset = N.getOperand(0); 12520b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(0, dl, MVT::i32); 12530b57cec5SDimitry Andric } 12540b57cec5SDimitry Andric 12550b57cec5SDimitry Andric unsigned LegalShiftVal = Log2_32(Size); 12560b57cec5SDimitry Andric unsigned ShiftVal = CSD->getZExtValue(); 12570b57cec5SDimitry Andric 12580b57cec5SDimitry Andric if (ShiftVal != 0 && ShiftVal != LegalShiftVal) 12590b57cec5SDimitry Andric return false; 12600b57cec5SDimitry Andric 12610b57cec5SDimitry Andric return isWorthFolding(N); 12620b57cec5SDimitry Andric } 12630b57cec5SDimitry Andric 12640b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeWRO(SDValue N, unsigned Size, 12650b57cec5SDimitry Andric SDValue &Base, SDValue &Offset, 12660b57cec5SDimitry Andric SDValue &SignExtend, 12670b57cec5SDimitry Andric SDValue &DoShift) { 12680b57cec5SDimitry Andric if (N.getOpcode() != ISD::ADD) 12690b57cec5SDimitry Andric return false; 12700b57cec5SDimitry Andric SDValue LHS = N.getOperand(0); 12710b57cec5SDimitry Andric SDValue RHS = N.getOperand(1); 12720b57cec5SDimitry Andric SDLoc dl(N); 12730b57cec5SDimitry Andric 12740b57cec5SDimitry Andric // We don't want to match immediate adds here, because they are better lowered 12750b57cec5SDimitry Andric // to the register-immediate addressing modes. 12760b57cec5SDimitry Andric if (isa<ConstantSDNode>(LHS) || isa<ConstantSDNode>(RHS)) 12770b57cec5SDimitry Andric return false; 12780b57cec5SDimitry Andric 12790b57cec5SDimitry Andric // Check if this particular node is reused in any non-memory related 12800b57cec5SDimitry Andric // operation. If yes, do not try to fold this node into the address 12810b57cec5SDimitry Andric // computation, since the computation will be kept. 12820b57cec5SDimitry Andric const SDNode *Node = N.getNode(); 12830b57cec5SDimitry Andric for (SDNode *UI : Node->uses()) { 12840b57cec5SDimitry Andric if (!isa<MemSDNode>(*UI)) 12850b57cec5SDimitry Andric return false; 12860b57cec5SDimitry Andric } 12870b57cec5SDimitry Andric 12880b57cec5SDimitry Andric // Remember if it is worth folding N when it produces extended register. 12890b57cec5SDimitry Andric bool IsExtendedRegisterWorthFolding = isWorthFolding(N); 12900b57cec5SDimitry Andric 12910b57cec5SDimitry Andric // Try to match a shifted extend on the RHS. 12920b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && RHS.getOpcode() == ISD::SHL && 12930b57cec5SDimitry Andric SelectExtendedSHL(RHS, Size, true, Offset, SignExtend)) { 12940b57cec5SDimitry Andric Base = LHS; 12950b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, dl, MVT::i32); 12960b57cec5SDimitry Andric return true; 12970b57cec5SDimitry Andric } 12980b57cec5SDimitry Andric 12990b57cec5SDimitry Andric // Try to match a shifted extend on the LHS. 13000b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && LHS.getOpcode() == ISD::SHL && 13010b57cec5SDimitry Andric SelectExtendedSHL(LHS, Size, true, Offset, SignExtend)) { 13020b57cec5SDimitry Andric Base = RHS; 13030b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, dl, MVT::i32); 13040b57cec5SDimitry Andric return true; 13050b57cec5SDimitry Andric } 13060b57cec5SDimitry Andric 13070b57cec5SDimitry Andric // There was no shift, whatever else we find. 13080b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(false, dl, MVT::i32); 13090b57cec5SDimitry Andric 13100b57cec5SDimitry Andric AArch64_AM::ShiftExtendType Ext = AArch64_AM::InvalidShiftExtend; 13110b57cec5SDimitry Andric // Try to match an unshifted extend on the LHS. 13120b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && 13130b57cec5SDimitry Andric (Ext = getExtendTypeForNode(LHS, true)) != 13140b57cec5SDimitry Andric AArch64_AM::InvalidShiftExtend) { 13150b57cec5SDimitry Andric Base = RHS; 13160b57cec5SDimitry Andric Offset = narrowIfNeeded(CurDAG, LHS.getOperand(0)); 13170b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl, 13180b57cec5SDimitry Andric MVT::i32); 13190b57cec5SDimitry Andric if (isWorthFolding(LHS)) 13200b57cec5SDimitry Andric return true; 13210b57cec5SDimitry Andric } 13220b57cec5SDimitry Andric 13230b57cec5SDimitry Andric // Try to match an unshifted extend on the RHS. 13240b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && 13250b57cec5SDimitry Andric (Ext = getExtendTypeForNode(RHS, true)) != 13260b57cec5SDimitry Andric AArch64_AM::InvalidShiftExtend) { 13270b57cec5SDimitry Andric Base = LHS; 13280b57cec5SDimitry Andric Offset = narrowIfNeeded(CurDAG, RHS.getOperand(0)); 13290b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(Ext == AArch64_AM::SXTW, dl, 13300b57cec5SDimitry Andric MVT::i32); 13310b57cec5SDimitry Andric if (isWorthFolding(RHS)) 13320b57cec5SDimitry Andric return true; 13330b57cec5SDimitry Andric } 13340b57cec5SDimitry Andric 13350b57cec5SDimitry Andric return false; 13360b57cec5SDimitry Andric } 13370b57cec5SDimitry Andric 13380b57cec5SDimitry Andric // Check if the given immediate is preferred by ADD. If an immediate can be 13390b57cec5SDimitry Andric // encoded in an ADD, or it can be encoded in an "ADD LSL #12" and can not be 13400b57cec5SDimitry Andric // encoded by one MOVZ, return true. 13410b57cec5SDimitry Andric static bool isPreferredADD(int64_t ImmOff) { 13420b57cec5SDimitry Andric // Constant in [0x0, 0xfff] can be encoded in ADD. 13430b57cec5SDimitry Andric if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL) 13440b57cec5SDimitry Andric return true; 13450b57cec5SDimitry Andric // Check if it can be encoded in an "ADD LSL #12". 13460b57cec5SDimitry Andric if ((ImmOff & 0xffffffffff000fffLL) == 0x0LL) 13470b57cec5SDimitry Andric // As a single MOVZ is faster than a "ADD of LSL #12", ignore such constant. 13480b57cec5SDimitry Andric return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL && 13490b57cec5SDimitry Andric (ImmOff & 0xffffffffffff0fffLL) != 0x0LL; 13500b57cec5SDimitry Andric return false; 13510b57cec5SDimitry Andric } 13520b57cec5SDimitry Andric 13530b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeXRO(SDValue N, unsigned Size, 13540b57cec5SDimitry Andric SDValue &Base, SDValue &Offset, 13550b57cec5SDimitry Andric SDValue &SignExtend, 13560b57cec5SDimitry Andric SDValue &DoShift) { 13570b57cec5SDimitry Andric if (N.getOpcode() != ISD::ADD) 13580b57cec5SDimitry Andric return false; 13590b57cec5SDimitry Andric SDValue LHS = N.getOperand(0); 13600b57cec5SDimitry Andric SDValue RHS = N.getOperand(1); 13610b57cec5SDimitry Andric SDLoc DL(N); 13620b57cec5SDimitry Andric 13630b57cec5SDimitry Andric // Check if this particular node is reused in any non-memory related 13640b57cec5SDimitry Andric // operation. If yes, do not try to fold this node into the address 13650b57cec5SDimitry Andric // computation, since the computation will be kept. 13660b57cec5SDimitry Andric const SDNode *Node = N.getNode(); 13670b57cec5SDimitry Andric for (SDNode *UI : Node->uses()) { 13680b57cec5SDimitry Andric if (!isa<MemSDNode>(*UI)) 13690b57cec5SDimitry Andric return false; 13700b57cec5SDimitry Andric } 13710b57cec5SDimitry Andric 13720b57cec5SDimitry Andric // Watch out if RHS is a wide immediate, it can not be selected into 13730b57cec5SDimitry Andric // [BaseReg+Imm] addressing mode. Also it may not be able to be encoded into 13740b57cec5SDimitry Andric // ADD/SUB. Instead it will use [BaseReg + 0] address mode and generate 13750b57cec5SDimitry Andric // instructions like: 13760b57cec5SDimitry Andric // MOV X0, WideImmediate 13770b57cec5SDimitry Andric // ADD X1, BaseReg, X0 13780b57cec5SDimitry Andric // LDR X2, [X1, 0] 13790b57cec5SDimitry Andric // For such situation, using [BaseReg, XReg] addressing mode can save one 13800b57cec5SDimitry Andric // ADD/SUB: 13810b57cec5SDimitry Andric // MOV X0, WideImmediate 13820b57cec5SDimitry Andric // LDR X2, [BaseReg, X0] 13830b57cec5SDimitry Andric if (isa<ConstantSDNode>(RHS)) { 13840b57cec5SDimitry Andric int64_t ImmOff = (int64_t)cast<ConstantSDNode>(RHS)->getZExtValue(); 13850b57cec5SDimitry Andric unsigned Scale = Log2_32(Size); 13860b57cec5SDimitry Andric // Skip the immediate can be selected by load/store addressing mode. 13870b57cec5SDimitry Andric // Also skip the immediate can be encoded by a single ADD (SUB is also 13880b57cec5SDimitry Andric // checked by using -ImmOff). 13890b57cec5SDimitry Andric if ((ImmOff % Size == 0 && ImmOff >= 0 && ImmOff < (0x1000 << Scale)) || 13900b57cec5SDimitry Andric isPreferredADD(ImmOff) || isPreferredADD(-ImmOff)) 13910b57cec5SDimitry Andric return false; 13920b57cec5SDimitry Andric 13930b57cec5SDimitry Andric SDValue Ops[] = { RHS }; 13940b57cec5SDimitry Andric SDNode *MOVI = 13950b57cec5SDimitry Andric CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops); 13960b57cec5SDimitry Andric SDValue MOVIV = SDValue(MOVI, 0); 13970b57cec5SDimitry Andric // This ADD of two X register will be selected into [Reg+Reg] mode. 13980b57cec5SDimitry Andric N = CurDAG->getNode(ISD::ADD, DL, MVT::i64, LHS, MOVIV); 13990b57cec5SDimitry Andric } 14000b57cec5SDimitry Andric 14010b57cec5SDimitry Andric // Remember if it is worth folding N when it produces extended register. 14020b57cec5SDimitry Andric bool IsExtendedRegisterWorthFolding = isWorthFolding(N); 14030b57cec5SDimitry Andric 14040b57cec5SDimitry Andric // Try to match a shifted extend on the RHS. 14050b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && RHS.getOpcode() == ISD::SHL && 14060b57cec5SDimitry Andric SelectExtendedSHL(RHS, Size, false, Offset, SignExtend)) { 14070b57cec5SDimitry Andric Base = LHS; 14080b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, DL, MVT::i32); 14090b57cec5SDimitry Andric return true; 14100b57cec5SDimitry Andric } 14110b57cec5SDimitry Andric 14120b57cec5SDimitry Andric // Try to match a shifted extend on the LHS. 14130b57cec5SDimitry Andric if (IsExtendedRegisterWorthFolding && LHS.getOpcode() == ISD::SHL && 14140b57cec5SDimitry Andric SelectExtendedSHL(LHS, Size, false, Offset, SignExtend)) { 14150b57cec5SDimitry Andric Base = RHS; 14160b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(true, DL, MVT::i32); 14170b57cec5SDimitry Andric return true; 14180b57cec5SDimitry Andric } 14190b57cec5SDimitry Andric 14200b57cec5SDimitry Andric // Match any non-shifted, non-extend, non-immediate add expression. 14210b57cec5SDimitry Andric Base = LHS; 14220b57cec5SDimitry Andric Offset = RHS; 14230b57cec5SDimitry Andric SignExtend = CurDAG->getTargetConstant(false, DL, MVT::i32); 14240b57cec5SDimitry Andric DoShift = CurDAG->getTargetConstant(false, DL, MVT::i32); 14250b57cec5SDimitry Andric // Reg1 + Reg2 is free: no check needed. 14260b57cec5SDimitry Andric return true; 14270b57cec5SDimitry Andric } 14280b57cec5SDimitry Andric 14290b57cec5SDimitry Andric SDValue AArch64DAGToDAGISel::createDTuple(ArrayRef<SDValue> Regs) { 14300b57cec5SDimitry Andric static const unsigned RegClassIDs[] = { 14310b57cec5SDimitry Andric AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID}; 14320b57cec5SDimitry Andric static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1, 14330b57cec5SDimitry Andric AArch64::dsub2, AArch64::dsub3}; 14340b57cec5SDimitry Andric 14350b57cec5SDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 14360b57cec5SDimitry Andric } 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric SDValue AArch64DAGToDAGISel::createQTuple(ArrayRef<SDValue> Regs) { 14390b57cec5SDimitry Andric static const unsigned RegClassIDs[] = { 14400b57cec5SDimitry Andric AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID}; 14410b57cec5SDimitry Andric static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1, 14420b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3}; 14430b57cec5SDimitry Andric 14440b57cec5SDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 14450b57cec5SDimitry Andric } 14460b57cec5SDimitry Andric 14475ffd83dbSDimitry Andric SDValue AArch64DAGToDAGISel::createZTuple(ArrayRef<SDValue> Regs) { 14485ffd83dbSDimitry Andric static const unsigned RegClassIDs[] = {AArch64::ZPR2RegClassID, 14495ffd83dbSDimitry Andric AArch64::ZPR3RegClassID, 14505ffd83dbSDimitry Andric AArch64::ZPR4RegClassID}; 14515ffd83dbSDimitry Andric static const unsigned SubRegs[] = {AArch64::zsub0, AArch64::zsub1, 14525ffd83dbSDimitry Andric AArch64::zsub2, AArch64::zsub3}; 14535ffd83dbSDimitry Andric 14545ffd83dbSDimitry Andric return createTuple(Regs, RegClassIDs, SubRegs); 14555ffd83dbSDimitry Andric } 14565ffd83dbSDimitry Andric 14570b57cec5SDimitry Andric SDValue AArch64DAGToDAGISel::createTuple(ArrayRef<SDValue> Regs, 14580b57cec5SDimitry Andric const unsigned RegClassIDs[], 14590b57cec5SDimitry Andric const unsigned SubRegs[]) { 14600b57cec5SDimitry Andric // There's no special register-class for a vector-list of 1 element: it's just 14610b57cec5SDimitry Andric // a vector. 14620b57cec5SDimitry Andric if (Regs.size() == 1) 14630b57cec5SDimitry Andric return Regs[0]; 14640b57cec5SDimitry Andric 14650b57cec5SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 4); 14660b57cec5SDimitry Andric 14670b57cec5SDimitry Andric SDLoc DL(Regs[0]); 14680b57cec5SDimitry Andric 14690b57cec5SDimitry Andric SmallVector<SDValue, 4> Ops; 14700b57cec5SDimitry Andric 14710b57cec5SDimitry Andric // First operand of REG_SEQUENCE is the desired RegClass. 14720b57cec5SDimitry Andric Ops.push_back( 14730b57cec5SDimitry Andric CurDAG->getTargetConstant(RegClassIDs[Regs.size() - 2], DL, MVT::i32)); 14740b57cec5SDimitry Andric 14750b57cec5SDimitry Andric // Then we get pairs of source & subregister-position for the components. 14760b57cec5SDimitry Andric for (unsigned i = 0; i < Regs.size(); ++i) { 14770b57cec5SDimitry Andric Ops.push_back(Regs[i]); 14780b57cec5SDimitry Andric Ops.push_back(CurDAG->getTargetConstant(SubRegs[i], DL, MVT::i32)); 14790b57cec5SDimitry Andric } 14800b57cec5SDimitry Andric 14810b57cec5SDimitry Andric SDNode *N = 14820b57cec5SDimitry Andric CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 14830b57cec5SDimitry Andric return SDValue(N, 0); 14840b57cec5SDimitry Andric } 14850b57cec5SDimitry Andric 14860b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc, 14870b57cec5SDimitry Andric bool isExt) { 14880b57cec5SDimitry Andric SDLoc dl(N); 14890b57cec5SDimitry Andric EVT VT = N->getValueType(0); 14900b57cec5SDimitry Andric 14910b57cec5SDimitry Andric unsigned ExtOff = isExt; 14920b57cec5SDimitry Andric 14930b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 14940b57cec5SDimitry Andric unsigned Vec0Off = ExtOff + 1; 14950b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + Vec0Off, 14960b57cec5SDimitry Andric N->op_begin() + Vec0Off + NumVecs); 14970b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 14980b57cec5SDimitry Andric 14990b57cec5SDimitry Andric SmallVector<SDValue, 6> Ops; 15000b57cec5SDimitry Andric if (isExt) 15010b57cec5SDimitry Andric Ops.push_back(N->getOperand(1)); 15020b57cec5SDimitry Andric Ops.push_back(RegSeq); 15030b57cec5SDimitry Andric Ops.push_back(N->getOperand(NumVecs + ExtOff + 1)); 15040b57cec5SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops)); 15050b57cec5SDimitry Andric } 15060b57cec5SDimitry Andric 15070b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { 15080b57cec5SDimitry Andric LoadSDNode *LD = cast<LoadSDNode>(N); 15090b57cec5SDimitry Andric if (LD->isUnindexed()) 15100b57cec5SDimitry Andric return false; 15110b57cec5SDimitry Andric EVT VT = LD->getMemoryVT(); 15120b57cec5SDimitry Andric EVT DstVT = N->getValueType(0); 15130b57cec5SDimitry Andric ISD::MemIndexedMode AM = LD->getAddressingMode(); 15140b57cec5SDimitry Andric bool IsPre = AM == ISD::PRE_INC || AM == ISD::PRE_DEC; 15150b57cec5SDimitry Andric 15160b57cec5SDimitry Andric // We're not doing validity checking here. That was done when checking 15170b57cec5SDimitry Andric // if we should mark the load as indexed or not. We're just selecting 15180b57cec5SDimitry Andric // the right instruction. 15190b57cec5SDimitry Andric unsigned Opcode = 0; 15200b57cec5SDimitry Andric 15210b57cec5SDimitry Andric ISD::LoadExtType ExtType = LD->getExtensionType(); 15220b57cec5SDimitry Andric bool InsertTo64 = false; 15230b57cec5SDimitry Andric if (VT == MVT::i64) 15240b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRXpre : AArch64::LDRXpost; 15250b57cec5SDimitry Andric else if (VT == MVT::i32) { 15260b57cec5SDimitry Andric if (ExtType == ISD::NON_EXTLOAD) 15270b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost; 15280b57cec5SDimitry Andric else if (ExtType == ISD::SEXTLOAD) 15290b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost; 15300b57cec5SDimitry Andric else { 15310b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost; 15320b57cec5SDimitry Andric InsertTo64 = true; 15330b57cec5SDimitry Andric // The result of the load is only i32. It's the subreg_to_reg that makes 15340b57cec5SDimitry Andric // it into an i64. 15350b57cec5SDimitry Andric DstVT = MVT::i32; 15360b57cec5SDimitry Andric } 15370b57cec5SDimitry Andric } else if (VT == MVT::i16) { 15380b57cec5SDimitry Andric if (ExtType == ISD::SEXTLOAD) { 15390b57cec5SDimitry Andric if (DstVT == MVT::i64) 15400b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost; 15410b57cec5SDimitry Andric else 15420b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost; 15430b57cec5SDimitry Andric } else { 15440b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost; 15450b57cec5SDimitry Andric InsertTo64 = DstVT == MVT::i64; 15460b57cec5SDimitry Andric // The result of the load is only i32. It's the subreg_to_reg that makes 15470b57cec5SDimitry Andric // it into an i64. 15480b57cec5SDimitry Andric DstVT = MVT::i32; 15490b57cec5SDimitry Andric } 15500b57cec5SDimitry Andric } else if (VT == MVT::i8) { 15510b57cec5SDimitry Andric if (ExtType == ISD::SEXTLOAD) { 15520b57cec5SDimitry Andric if (DstVT == MVT::i64) 15530b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost; 15540b57cec5SDimitry Andric else 15550b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost; 15560b57cec5SDimitry Andric } else { 15570b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost; 15580b57cec5SDimitry Andric InsertTo64 = DstVT == MVT::i64; 15590b57cec5SDimitry Andric // The result of the load is only i32. It's the subreg_to_reg that makes 15600b57cec5SDimitry Andric // it into an i64. 15610b57cec5SDimitry Andric DstVT = MVT::i32; 15620b57cec5SDimitry Andric } 15630b57cec5SDimitry Andric } else if (VT == MVT::f16) { 15640b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost; 15655ffd83dbSDimitry Andric } else if (VT == MVT::bf16) { 15665ffd83dbSDimitry Andric Opcode = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost; 15670b57cec5SDimitry Andric } else if (VT == MVT::f32) { 15680b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost; 15690b57cec5SDimitry Andric } else if (VT == MVT::f64 || VT.is64BitVector()) { 15700b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRDpre : AArch64::LDRDpost; 15710b57cec5SDimitry Andric } else if (VT.is128BitVector()) { 15720b57cec5SDimitry Andric Opcode = IsPre ? AArch64::LDRQpre : AArch64::LDRQpost; 15730b57cec5SDimitry Andric } else 15740b57cec5SDimitry Andric return false; 15750b57cec5SDimitry Andric SDValue Chain = LD->getChain(); 15760b57cec5SDimitry Andric SDValue Base = LD->getBasePtr(); 15770b57cec5SDimitry Andric ConstantSDNode *OffsetOp = cast<ConstantSDNode>(LD->getOffset()); 15780b57cec5SDimitry Andric int OffsetVal = (int)OffsetOp->getZExtValue(); 15790b57cec5SDimitry Andric SDLoc dl(N); 15800b57cec5SDimitry Andric SDValue Offset = CurDAG->getTargetConstant(OffsetVal, dl, MVT::i64); 15810b57cec5SDimitry Andric SDValue Ops[] = { Base, Offset, Chain }; 15820b57cec5SDimitry Andric SDNode *Res = CurDAG->getMachineNode(Opcode, dl, MVT::i64, DstVT, 15830b57cec5SDimitry Andric MVT::Other, Ops); 1584fe6060f1SDimitry Andric 1585fe6060f1SDimitry Andric // Transfer memoperands. 1586fe6060f1SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand(); 1587fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Res), {MemOp}); 1588fe6060f1SDimitry Andric 15890b57cec5SDimitry Andric // Either way, we're replacing the node, so tell the caller that. 15900b57cec5SDimitry Andric SDValue LoadedVal = SDValue(Res, 1); 15910b57cec5SDimitry Andric if (InsertTo64) { 15920b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, dl, MVT::i32); 15930b57cec5SDimitry Andric LoadedVal = 15940b57cec5SDimitry Andric SDValue(CurDAG->getMachineNode( 15950b57cec5SDimitry Andric AArch64::SUBREG_TO_REG, dl, MVT::i64, 15960b57cec5SDimitry Andric CurDAG->getTargetConstant(0, dl, MVT::i64), LoadedVal, 15970b57cec5SDimitry Andric SubReg), 15980b57cec5SDimitry Andric 0); 15990b57cec5SDimitry Andric } 16000b57cec5SDimitry Andric 16010b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), LoadedVal); 16020b57cec5SDimitry Andric ReplaceUses(SDValue(N, 1), SDValue(Res, 0)); 16030b57cec5SDimitry Andric ReplaceUses(SDValue(N, 2), SDValue(Res, 2)); 16040b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 16050b57cec5SDimitry Andric return true; 16060b57cec5SDimitry Andric } 16070b57cec5SDimitry Andric 16080b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc, 16090b57cec5SDimitry Andric unsigned SubRegIdx) { 16100b57cec5SDimitry Andric SDLoc dl(N); 16110b57cec5SDimitry Andric EVT VT = N->getValueType(0); 16120b57cec5SDimitry Andric SDValue Chain = N->getOperand(0); 16130b57cec5SDimitry Andric 16140b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(2), // Mem operand; 16150b57cec5SDimitry Andric Chain}; 16160b57cec5SDimitry Andric 16170b57cec5SDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 16180b57cec5SDimitry Andric 16190b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 16200b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 0); 16210b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 16220b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), 16230b57cec5SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg)); 16240b57cec5SDimitry Andric 16250b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1)); 16260b57cec5SDimitry Andric 1627e8d8bef9SDimitry Andric // Transfer memoperands. In the case of AArch64::LD64B, there won't be one, 1628e8d8bef9SDimitry Andric // because it's too simple to have needed special treatment during lowering. 1629e8d8bef9SDimitry Andric if (auto *MemIntr = dyn_cast<MemIntrinsicSDNode>(N)) { 1630e8d8bef9SDimitry Andric MachineMemOperand *MemOp = MemIntr->getMemOperand(); 16310b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp}); 1632e8d8bef9SDimitry Andric } 16330b57cec5SDimitry Andric 16340b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 16350b57cec5SDimitry Andric } 16360b57cec5SDimitry Andric 16370b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostLoad(SDNode *N, unsigned NumVecs, 16380b57cec5SDimitry Andric unsigned Opc, unsigned SubRegIdx) { 16390b57cec5SDimitry Andric SDLoc dl(N); 16400b57cec5SDimitry Andric EVT VT = N->getValueType(0); 16410b57cec5SDimitry Andric SDValue Chain = N->getOperand(0); 16420b57cec5SDimitry Andric 16430b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(1), // Mem operand 16440b57cec5SDimitry Andric N->getOperand(2), // Incremental 16450b57cec5SDimitry Andric Chain}; 16460b57cec5SDimitry Andric 16470b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 16480b57cec5SDimitry Andric MVT::Untyped, MVT::Other}; 16490b57cec5SDimitry Andric 16500b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 16510b57cec5SDimitry Andric 16520b57cec5SDimitry Andric // Update uses of write back register 16530b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0)); 16540b57cec5SDimitry Andric 16550b57cec5SDimitry Andric // Update uses of vector list 16560b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 1); 16570b57cec5SDimitry Andric if (NumVecs == 1) 16580b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), SuperReg); 16590b57cec5SDimitry Andric else 16600b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 16610b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), 16620b57cec5SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg)); 16630b57cec5SDimitry Andric 16640b57cec5SDimitry Andric // Update the chain 16650b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2)); 16660b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 16670b57cec5SDimitry Andric } 16680b57cec5SDimitry Andric 16695ffd83dbSDimitry Andric /// Optimize \param OldBase and \param OldOffset selecting the best addressing 16705ffd83dbSDimitry Andric /// mode. Returns a tuple consisting of an Opcode, an SDValue representing the 16715ffd83dbSDimitry Andric /// new Base and an SDValue representing the new offset. 16725ffd83dbSDimitry Andric std::tuple<unsigned, SDValue, SDValue> 1673979e22ffSDimitry Andric AArch64DAGToDAGISel::findAddrModeSVELoadStore(SDNode *N, unsigned Opc_rr, 1674979e22ffSDimitry Andric unsigned Opc_ri, 16755ffd83dbSDimitry Andric const SDValue &OldBase, 1676979e22ffSDimitry Andric const SDValue &OldOffset, 1677979e22ffSDimitry Andric unsigned Scale) { 16785ffd83dbSDimitry Andric SDValue NewBase = OldBase; 16795ffd83dbSDimitry Andric SDValue NewOffset = OldOffset; 16805ffd83dbSDimitry Andric // Detect a possible Reg+Imm addressing mode. 16815ffd83dbSDimitry Andric const bool IsRegImm = SelectAddrModeIndexedSVE</*Min=*/-8, /*Max=*/7>( 16825ffd83dbSDimitry Andric N, OldBase, NewBase, NewOffset); 16835ffd83dbSDimitry Andric 16845ffd83dbSDimitry Andric // Detect a possible reg+reg addressing mode, but only if we haven't already 16855ffd83dbSDimitry Andric // detected a Reg+Imm one. 16865ffd83dbSDimitry Andric const bool IsRegReg = 1687979e22ffSDimitry Andric !IsRegImm && SelectSVERegRegAddrMode(OldBase, Scale, NewBase, NewOffset); 16885ffd83dbSDimitry Andric 16895ffd83dbSDimitry Andric // Select the instruction. 16905ffd83dbSDimitry Andric return std::make_tuple(IsRegReg ? Opc_rr : Opc_ri, NewBase, NewOffset); 16915ffd83dbSDimitry Andric } 16925ffd83dbSDimitry Andric 1693*bdd1243dSDimitry Andric enum class SelectTypeKind { 1694*bdd1243dSDimitry Andric Int1 = 0, 1695*bdd1243dSDimitry Andric }; 1696*bdd1243dSDimitry Andric 1697*bdd1243dSDimitry Andric /// This function selects an opcode from a list of opcodes, which is 1698*bdd1243dSDimitry Andric /// expected to be the opcode for { 8-bit, 16-bit, 32-bit, 64-bit } 1699*bdd1243dSDimitry Andric /// element types, in this order. 1700*bdd1243dSDimitry Andric template <SelectTypeKind Kind> 1701*bdd1243dSDimitry Andric static unsigned SelectOpcodeFromVT(EVT VT, ArrayRef<unsigned> Opcodes) { 1702*bdd1243dSDimitry Andric // Only match scalable vector VTs 1703*bdd1243dSDimitry Andric if (!VT.isScalableVector()) 1704*bdd1243dSDimitry Andric return 0; 1705*bdd1243dSDimitry Andric 1706*bdd1243dSDimitry Andric EVT EltVT = VT.getVectorElementType(); 1707*bdd1243dSDimitry Andric switch (Kind) { 1708*bdd1243dSDimitry Andric case SelectTypeKind::Int1: 1709*bdd1243dSDimitry Andric if (EltVT != MVT::i1) 1710*bdd1243dSDimitry Andric return 0; 1711*bdd1243dSDimitry Andric break; 1712*bdd1243dSDimitry Andric } 1713*bdd1243dSDimitry Andric 1714*bdd1243dSDimitry Andric unsigned Offset; 1715*bdd1243dSDimitry Andric switch (VT.getVectorMinNumElements()) { 1716*bdd1243dSDimitry Andric case 16: // 8-bit 1717*bdd1243dSDimitry Andric Offset = 0; 1718*bdd1243dSDimitry Andric break; 1719*bdd1243dSDimitry Andric case 8: // 16-bit 1720*bdd1243dSDimitry Andric Offset = 1; 1721*bdd1243dSDimitry Andric break; 1722*bdd1243dSDimitry Andric case 4: // 32-bit 1723*bdd1243dSDimitry Andric Offset = 2; 1724*bdd1243dSDimitry Andric break; 1725*bdd1243dSDimitry Andric case 2: // 64-bit 1726*bdd1243dSDimitry Andric Offset = 3; 1727*bdd1243dSDimitry Andric break; 1728*bdd1243dSDimitry Andric default: 1729*bdd1243dSDimitry Andric return 0; 1730*bdd1243dSDimitry Andric } 1731*bdd1243dSDimitry Andric 1732*bdd1243dSDimitry Andric return (Opcodes.size() <= Offset) ? 0 : Opcodes[Offset]; 1733*bdd1243dSDimitry Andric } 1734*bdd1243dSDimitry Andric 1735*bdd1243dSDimitry Andric void AArch64DAGToDAGISel::SelectWhilePair(SDNode *N, unsigned Opc) { 1736*bdd1243dSDimitry Andric SDLoc DL(N); 1737*bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 1738*bdd1243dSDimitry Andric 1739*bdd1243dSDimitry Andric SDValue Ops[] = {N->getOperand(1), N->getOperand(2)}; 1740*bdd1243dSDimitry Andric 1741*bdd1243dSDimitry Andric SDNode *WhilePair = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Ops); 1742*bdd1243dSDimitry Andric SDValue SuperReg = SDValue(WhilePair, 0); 1743*bdd1243dSDimitry Andric 1744*bdd1243dSDimitry Andric for (unsigned I = 0; I < 2; ++I) 1745*bdd1243dSDimitry Andric ReplaceUses(SDValue(N, I), CurDAG->getTargetExtractSubreg( 1746*bdd1243dSDimitry Andric AArch64::psub0 + I, DL, VT, SuperReg)); 1747*bdd1243dSDimitry Andric 1748*bdd1243dSDimitry Andric CurDAG->RemoveDeadNode(N); 1749*bdd1243dSDimitry Andric } 1750*bdd1243dSDimitry Andric 1751*bdd1243dSDimitry Andric void AArch64DAGToDAGISel::SelectCVTIntrinsic(SDNode *N, unsigned NumVecs, 1752*bdd1243dSDimitry Andric unsigned Opcode) { 1753*bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 1754*bdd1243dSDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 1755*bdd1243dSDimitry Andric SDValue Ops = createZTuple(Regs); 1756*bdd1243dSDimitry Andric SDLoc DL(N); 1757*bdd1243dSDimitry Andric SDNode *Intrinsic = CurDAG->getMachineNode(Opcode, DL, MVT::Untyped, Ops); 1758*bdd1243dSDimitry Andric SDValue SuperReg = SDValue(Intrinsic, 0); 1759*bdd1243dSDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 1760*bdd1243dSDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 1761*bdd1243dSDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 1762*bdd1243dSDimitry Andric 1763*bdd1243dSDimitry Andric CurDAG->RemoveDeadNode(N); 1764*bdd1243dSDimitry Andric return; 1765*bdd1243dSDimitry Andric } 1766*bdd1243dSDimitry Andric 17675ffd83dbSDimitry Andric void AArch64DAGToDAGISel::SelectPredicatedLoad(SDNode *N, unsigned NumVecs, 1768979e22ffSDimitry Andric unsigned Scale, unsigned Opc_ri, 1769349cc55cSDimitry Andric unsigned Opc_rr, bool IsIntr) { 1770979e22ffSDimitry Andric assert(Scale < 4 && "Invalid scaling value."); 17715ffd83dbSDimitry Andric SDLoc DL(N); 17725ffd83dbSDimitry Andric EVT VT = N->getValueType(0); 17735ffd83dbSDimitry Andric SDValue Chain = N->getOperand(0); 17745ffd83dbSDimitry Andric 1775979e22ffSDimitry Andric // Optimize addressing mode. 1776979e22ffSDimitry Andric SDValue Base, Offset; 1777979e22ffSDimitry Andric unsigned Opc; 1778979e22ffSDimitry Andric std::tie(Opc, Base, Offset) = findAddrModeSVELoadStore( 1779349cc55cSDimitry Andric N, Opc_rr, Opc_ri, N->getOperand(IsIntr ? 3 : 2), 1780979e22ffSDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i64), Scale); 1781979e22ffSDimitry Andric 1782349cc55cSDimitry Andric SDValue Ops[] = {N->getOperand(IsIntr ? 2 : 1), // Predicate 1783979e22ffSDimitry Andric Base, // Memory operand 1784979e22ffSDimitry Andric Offset, Chain}; 17855ffd83dbSDimitry Andric 17865ffd83dbSDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 17875ffd83dbSDimitry Andric 17885ffd83dbSDimitry Andric SDNode *Load = CurDAG->getMachineNode(Opc, DL, ResTys, Ops); 17895ffd83dbSDimitry Andric SDValue SuperReg = SDValue(Load, 0); 17905ffd83dbSDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) 17915ffd83dbSDimitry Andric ReplaceUses(SDValue(N, i), CurDAG->getTargetExtractSubreg( 17925ffd83dbSDimitry Andric AArch64::zsub0 + i, DL, VT, SuperReg)); 17935ffd83dbSDimitry Andric 17945ffd83dbSDimitry Andric // Copy chain 17955ffd83dbSDimitry Andric unsigned ChainIdx = NumVecs; 17965ffd83dbSDimitry Andric ReplaceUses(SDValue(N, ChainIdx), SDValue(Load, 1)); 17975ffd83dbSDimitry Andric CurDAG->RemoveDeadNode(N); 17985ffd83dbSDimitry Andric } 17995ffd83dbSDimitry Andric 18000b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectStore(SDNode *N, unsigned NumVecs, 18010b57cec5SDimitry Andric unsigned Opc) { 18020b57cec5SDimitry Andric SDLoc dl(N); 18030b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 18040b57cec5SDimitry Andric 18050b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 18060b57cec5SDimitry Andric bool Is128Bit = VT.getSizeInBits() == 128; 18070b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 18080b57cec5SDimitry Andric SDValue RegSeq = Is128Bit ? createQTuple(Regs) : createDTuple(Regs); 18090b57cec5SDimitry Andric 18100b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), N->getOperand(0)}; 18110b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops); 18120b57cec5SDimitry Andric 18130b57cec5SDimitry Andric // Transfer memoperands. 18140b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 18150b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 18160b57cec5SDimitry Andric 18170b57cec5SDimitry Andric ReplaceNode(N, St); 18180b57cec5SDimitry Andric } 18190b57cec5SDimitry Andric 18205ffd83dbSDimitry Andric void AArch64DAGToDAGISel::SelectPredicatedStore(SDNode *N, unsigned NumVecs, 1821979e22ffSDimitry Andric unsigned Scale, unsigned Opc_rr, 1822979e22ffSDimitry Andric unsigned Opc_ri) { 18235ffd83dbSDimitry Andric SDLoc dl(N); 18245ffd83dbSDimitry Andric 18255ffd83dbSDimitry Andric // Form a REG_SEQUENCE to force register allocation. 18265ffd83dbSDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 18275ffd83dbSDimitry Andric SDValue RegSeq = createZTuple(Regs); 18285ffd83dbSDimitry Andric 18295ffd83dbSDimitry Andric // Optimize addressing mode. 18305ffd83dbSDimitry Andric unsigned Opc; 18315ffd83dbSDimitry Andric SDValue Offset, Base; 1832979e22ffSDimitry Andric std::tie(Opc, Base, Offset) = findAddrModeSVELoadStore( 18335ffd83dbSDimitry Andric N, Opc_rr, Opc_ri, N->getOperand(NumVecs + 3), 1834979e22ffSDimitry Andric CurDAG->getTargetConstant(0, dl, MVT::i64), Scale); 18355ffd83dbSDimitry Andric 18365ffd83dbSDimitry Andric SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), // predicate 18375ffd83dbSDimitry Andric Base, // address 18385ffd83dbSDimitry Andric Offset, // offset 18395ffd83dbSDimitry Andric N->getOperand(0)}; // chain 18405ffd83dbSDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops); 18415ffd83dbSDimitry Andric 18425ffd83dbSDimitry Andric ReplaceNode(N, St); 18435ffd83dbSDimitry Andric } 18445ffd83dbSDimitry Andric 18455ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeFrameIndexSVE(SDValue N, SDValue &Base, 18465ffd83dbSDimitry Andric SDValue &OffImm) { 18475ffd83dbSDimitry Andric SDLoc dl(N); 18485ffd83dbSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 18495ffd83dbSDimitry Andric const TargetLowering *TLI = getTargetLowering(); 18505ffd83dbSDimitry Andric 18515ffd83dbSDimitry Andric // Try to match it for the frame address 18525ffd83dbSDimitry Andric if (auto FINode = dyn_cast<FrameIndexSDNode>(N)) { 18535ffd83dbSDimitry Andric int FI = FINode->getIndex(); 18545ffd83dbSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 18555ffd83dbSDimitry Andric OffImm = CurDAG->getTargetConstant(0, dl, MVT::i64); 18565ffd83dbSDimitry Andric return true; 18575ffd83dbSDimitry Andric } 18585ffd83dbSDimitry Andric 18595ffd83dbSDimitry Andric return false; 18605ffd83dbSDimitry Andric } 18615ffd83dbSDimitry Andric 18620b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostStore(SDNode *N, unsigned NumVecs, 18630b57cec5SDimitry Andric unsigned Opc) { 18640b57cec5SDimitry Andric SDLoc dl(N); 18650b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 18660b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 18670b57cec5SDimitry Andric MVT::Other}; // Type for the Chain 18680b57cec5SDimitry Andric 18690b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 18700b57cec5SDimitry Andric bool Is128Bit = VT.getSizeInBits() == 128; 18710b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 18720b57cec5SDimitry Andric SDValue RegSeq = Is128Bit ? createQTuple(Regs) : createDTuple(Regs); 18730b57cec5SDimitry Andric 18740b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, 18750b57cec5SDimitry Andric N->getOperand(NumVecs + 1), // base register 18760b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Incremental 18770b57cec5SDimitry Andric N->getOperand(0)}; // Chain 18780b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 18790b57cec5SDimitry Andric 18800b57cec5SDimitry Andric ReplaceNode(N, St); 18810b57cec5SDimitry Andric } 18820b57cec5SDimitry Andric 18830b57cec5SDimitry Andric namespace { 18840b57cec5SDimitry Andric /// WidenVector - Given a value in the V64 register class, produce the 18850b57cec5SDimitry Andric /// equivalent value in the V128 register class. 18860b57cec5SDimitry Andric class WidenVector { 18870b57cec5SDimitry Andric SelectionDAG &DAG; 18880b57cec5SDimitry Andric 18890b57cec5SDimitry Andric public: 18900b57cec5SDimitry Andric WidenVector(SelectionDAG &DAG) : DAG(DAG) {} 18910b57cec5SDimitry Andric 18920b57cec5SDimitry Andric SDValue operator()(SDValue V64Reg) { 18930b57cec5SDimitry Andric EVT VT = V64Reg.getValueType(); 18940b57cec5SDimitry Andric unsigned NarrowSize = VT.getVectorNumElements(); 18950b57cec5SDimitry Andric MVT EltTy = VT.getVectorElementType().getSimpleVT(); 18960b57cec5SDimitry Andric MVT WideTy = MVT::getVectorVT(EltTy, 2 * NarrowSize); 18970b57cec5SDimitry Andric SDLoc DL(V64Reg); 18980b57cec5SDimitry Andric 18990b57cec5SDimitry Andric SDValue Undef = 19000b57cec5SDimitry Andric SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, WideTy), 0); 19010b57cec5SDimitry Andric return DAG.getTargetInsertSubreg(AArch64::dsub, DL, WideTy, Undef, V64Reg); 19020b57cec5SDimitry Andric } 19030b57cec5SDimitry Andric }; 19040b57cec5SDimitry Andric } // namespace 19050b57cec5SDimitry Andric 19060b57cec5SDimitry Andric /// NarrowVector - Given a value in the V128 register class, produce the 19070b57cec5SDimitry Andric /// equivalent value in the V64 register class. 19080b57cec5SDimitry Andric static SDValue NarrowVector(SDValue V128Reg, SelectionDAG &DAG) { 19090b57cec5SDimitry Andric EVT VT = V128Reg.getValueType(); 19100b57cec5SDimitry Andric unsigned WideSize = VT.getVectorNumElements(); 19110b57cec5SDimitry Andric MVT EltTy = VT.getVectorElementType().getSimpleVT(); 19120b57cec5SDimitry Andric MVT NarrowTy = MVT::getVectorVT(EltTy, WideSize / 2); 19130b57cec5SDimitry Andric 19140b57cec5SDimitry Andric return DAG.getTargetExtractSubreg(AArch64::dsub, SDLoc(V128Reg), NarrowTy, 19150b57cec5SDimitry Andric V128Reg); 19160b57cec5SDimitry Andric } 19170b57cec5SDimitry Andric 19180b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectLoadLane(SDNode *N, unsigned NumVecs, 19190b57cec5SDimitry Andric unsigned Opc) { 19200b57cec5SDimitry Andric SDLoc dl(N); 19210b57cec5SDimitry Andric EVT VT = N->getValueType(0); 19220b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 19230b57cec5SDimitry Andric 19240b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 19250b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 19260b57cec5SDimitry Andric 19270b57cec5SDimitry Andric if (Narrow) 19280b57cec5SDimitry Andric transform(Regs, Regs.begin(), 19290b57cec5SDimitry Andric WidenVector(*CurDAG)); 19300b57cec5SDimitry Andric 19310b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 19320b57cec5SDimitry Andric 19330b57cec5SDimitry Andric const EVT ResTys[] = {MVT::Untyped, MVT::Other}; 19340b57cec5SDimitry Andric 19350b57cec5SDimitry Andric unsigned LaneNo = 19360b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 2))->getZExtValue(); 19370b57cec5SDimitry Andric 19380b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 19390b57cec5SDimitry Andric N->getOperand(NumVecs + 3), N->getOperand(0)}; 19400b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 19410b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 0); 19420b57cec5SDimitry Andric 19430b57cec5SDimitry Andric EVT WideVT = RegSeq.getOperand(1)->getValueType(0); 19440b57cec5SDimitry Andric static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1, 19450b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3 }; 19460b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) { 19470b57cec5SDimitry Andric SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, SuperReg); 19480b57cec5SDimitry Andric if (Narrow) 19490b57cec5SDimitry Andric NV = NarrowVector(NV, *CurDAG); 19500b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), NV); 19510b57cec5SDimitry Andric } 19520b57cec5SDimitry Andric 19530b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1)); 19540b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 19550b57cec5SDimitry Andric } 19560b57cec5SDimitry Andric 19570b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostLoadLane(SDNode *N, unsigned NumVecs, 19580b57cec5SDimitry Andric unsigned Opc) { 19590b57cec5SDimitry Andric SDLoc dl(N); 19600b57cec5SDimitry Andric EVT VT = N->getValueType(0); 19610b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 19620b57cec5SDimitry Andric 19630b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 19640b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 19650b57cec5SDimitry Andric 19660b57cec5SDimitry Andric if (Narrow) 19670b57cec5SDimitry Andric transform(Regs, Regs.begin(), 19680b57cec5SDimitry Andric WidenVector(*CurDAG)); 19690b57cec5SDimitry Andric 19700b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 19710b57cec5SDimitry Andric 19720b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 19730b57cec5SDimitry Andric RegSeq->getValueType(0), MVT::Other}; 19740b57cec5SDimitry Andric 19750b57cec5SDimitry Andric unsigned LaneNo = 19760b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 1))->getZExtValue(); 19770b57cec5SDimitry Andric 19780b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, 19790b57cec5SDimitry Andric CurDAG->getTargetConstant(LaneNo, dl, 19800b57cec5SDimitry Andric MVT::i64), // Lane Number 19810b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Base register 19820b57cec5SDimitry Andric N->getOperand(NumVecs + 3), // Incremental 19830b57cec5SDimitry Andric N->getOperand(0)}; 19840b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 19850b57cec5SDimitry Andric 19860b57cec5SDimitry Andric // Update uses of the write back register 19870b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 0)); 19880b57cec5SDimitry Andric 19890b57cec5SDimitry Andric // Update uses of the vector list 19900b57cec5SDimitry Andric SDValue SuperReg = SDValue(Ld, 1); 19910b57cec5SDimitry Andric if (NumVecs == 1) { 19920b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), 19930b57cec5SDimitry Andric Narrow ? NarrowVector(SuperReg, *CurDAG) : SuperReg); 19940b57cec5SDimitry Andric } else { 19950b57cec5SDimitry Andric EVT WideVT = RegSeq.getOperand(1)->getValueType(0); 19960b57cec5SDimitry Andric static const unsigned QSubs[] = { AArch64::qsub0, AArch64::qsub1, 19970b57cec5SDimitry Andric AArch64::qsub2, AArch64::qsub3 }; 19980b57cec5SDimitry Andric for (unsigned i = 0; i < NumVecs; ++i) { 19990b57cec5SDimitry Andric SDValue NV = CurDAG->getTargetExtractSubreg(QSubs[i], dl, WideVT, 20000b57cec5SDimitry Andric SuperReg); 20010b57cec5SDimitry Andric if (Narrow) 20020b57cec5SDimitry Andric NV = NarrowVector(NV, *CurDAG); 20030b57cec5SDimitry Andric ReplaceUses(SDValue(N, i), NV); 20040b57cec5SDimitry Andric } 20050b57cec5SDimitry Andric } 20060b57cec5SDimitry Andric 20070b57cec5SDimitry Andric // Update the Chain 20080b57cec5SDimitry Andric ReplaceUses(SDValue(N, NumVecs + 1), SDValue(Ld, 2)); 20090b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 20100b57cec5SDimitry Andric } 20110b57cec5SDimitry Andric 20120b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectStoreLane(SDNode *N, unsigned NumVecs, 20130b57cec5SDimitry Andric unsigned Opc) { 20140b57cec5SDimitry Andric SDLoc dl(N); 20150b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 20160b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 20170b57cec5SDimitry Andric 20180b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 20190b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs); 20200b57cec5SDimitry Andric 20210b57cec5SDimitry Andric if (Narrow) 20220b57cec5SDimitry Andric transform(Regs, Regs.begin(), 20230b57cec5SDimitry Andric WidenVector(*CurDAG)); 20240b57cec5SDimitry Andric 20250b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 20260b57cec5SDimitry Andric 20270b57cec5SDimitry Andric unsigned LaneNo = 20280b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 2))->getZExtValue(); 20290b57cec5SDimitry Andric 20300b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 20310b57cec5SDimitry Andric N->getOperand(NumVecs + 3), N->getOperand(0)}; 20320b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops); 20330b57cec5SDimitry Andric 20340b57cec5SDimitry Andric // Transfer memoperands. 20350b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 20360b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 20370b57cec5SDimitry Andric 20380b57cec5SDimitry Andric ReplaceNode(N, St); 20390b57cec5SDimitry Andric } 20400b57cec5SDimitry Andric 20410b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectPostStoreLane(SDNode *N, unsigned NumVecs, 20420b57cec5SDimitry Andric unsigned Opc) { 20430b57cec5SDimitry Andric SDLoc dl(N); 20440b57cec5SDimitry Andric EVT VT = N->getOperand(2)->getValueType(0); 20450b57cec5SDimitry Andric bool Narrow = VT.getSizeInBits() == 64; 20460b57cec5SDimitry Andric 20470b57cec5SDimitry Andric // Form a REG_SEQUENCE to force register allocation. 20480b57cec5SDimitry Andric SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs); 20490b57cec5SDimitry Andric 20500b57cec5SDimitry Andric if (Narrow) 20510b57cec5SDimitry Andric transform(Regs, Regs.begin(), 20520b57cec5SDimitry Andric WidenVector(*CurDAG)); 20530b57cec5SDimitry Andric 20540b57cec5SDimitry Andric SDValue RegSeq = createQTuple(Regs); 20550b57cec5SDimitry Andric 20560b57cec5SDimitry Andric const EVT ResTys[] = {MVT::i64, // Type of the write back register 20570b57cec5SDimitry Andric MVT::Other}; 20580b57cec5SDimitry Andric 20590b57cec5SDimitry Andric unsigned LaneNo = 20600b57cec5SDimitry Andric cast<ConstantSDNode>(N->getOperand(NumVecs + 1))->getZExtValue(); 20610b57cec5SDimitry Andric 20620b57cec5SDimitry Andric SDValue Ops[] = {RegSeq, CurDAG->getTargetConstant(LaneNo, dl, MVT::i64), 20630b57cec5SDimitry Andric N->getOperand(NumVecs + 2), // Base Register 20640b57cec5SDimitry Andric N->getOperand(NumVecs + 3), // Incremental 20650b57cec5SDimitry Andric N->getOperand(0)}; 20660b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Opc, dl, ResTys, Ops); 20670b57cec5SDimitry Andric 20680b57cec5SDimitry Andric // Transfer memoperands. 20690b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 20700b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 20710b57cec5SDimitry Andric 20720b57cec5SDimitry Andric ReplaceNode(N, St); 20730b57cec5SDimitry Andric } 20740b57cec5SDimitry Andric 20750b57cec5SDimitry Andric static bool isBitfieldExtractOpFromAnd(SelectionDAG *CurDAG, SDNode *N, 20760b57cec5SDimitry Andric unsigned &Opc, SDValue &Opd0, 20770b57cec5SDimitry Andric unsigned &LSB, unsigned &MSB, 20780b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits, 20790b57cec5SDimitry Andric bool BiggerPattern) { 20800b57cec5SDimitry Andric assert(N->getOpcode() == ISD::AND && 20810b57cec5SDimitry Andric "N must be a AND operation to call this function"); 20820b57cec5SDimitry Andric 20830b57cec5SDimitry Andric EVT VT = N->getValueType(0); 20840b57cec5SDimitry Andric 20850b57cec5SDimitry Andric // Here we can test the type of VT and return false when the type does not 20860b57cec5SDimitry Andric // match, but since it is done prior to that call in the current context 20870b57cec5SDimitry Andric // we turned that into an assert to avoid redundant code. 20880b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 20890b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 20900b57cec5SDimitry Andric 20910b57cec5SDimitry Andric // FIXME: simplify-demanded-bits in DAGCombine will probably have 20920b57cec5SDimitry Andric // changed the AND node to a 32-bit mask operation. We'll have to 20930b57cec5SDimitry Andric // undo that as part of the transform here if we want to catch all 20940b57cec5SDimitry Andric // the opportunities. 20950b57cec5SDimitry Andric // Currently the NumberOfIgnoredLowBits argument helps to recover 2096*bdd1243dSDimitry Andric // from these situations when matching bigger pattern (bitfield insert). 20970b57cec5SDimitry Andric 20980b57cec5SDimitry Andric // For unsigned extracts, check for a shift right and mask 20990b57cec5SDimitry Andric uint64_t AndImm = 0; 21000b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N, ISD::AND, AndImm)) 21010b57cec5SDimitry Andric return false; 21020b57cec5SDimitry Andric 21030b57cec5SDimitry Andric const SDNode *Op0 = N->getOperand(0).getNode(); 21040b57cec5SDimitry Andric 21050b57cec5SDimitry Andric // Because of simplify-demanded-bits in DAGCombine, the mask may have been 21060b57cec5SDimitry Andric // simplified. Try to undo that 21070b57cec5SDimitry Andric AndImm |= maskTrailingOnes<uint64_t>(NumberOfIgnoredLowBits); 21080b57cec5SDimitry Andric 21090b57cec5SDimitry Andric // The immediate is a mask of the low bits iff imm & (imm+1) == 0 21100b57cec5SDimitry Andric if (AndImm & (AndImm + 1)) 21110b57cec5SDimitry Andric return false; 21120b57cec5SDimitry Andric 21130b57cec5SDimitry Andric bool ClampMSB = false; 21140b57cec5SDimitry Andric uint64_t SrlImm = 0; 21150b57cec5SDimitry Andric // Handle the SRL + ANY_EXTEND case. 21160b57cec5SDimitry Andric if (VT == MVT::i64 && Op0->getOpcode() == ISD::ANY_EXTEND && 21170b57cec5SDimitry Andric isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, SrlImm)) { 21180b57cec5SDimitry Andric // Extend the incoming operand of the SRL to 64-bit. 21190b57cec5SDimitry Andric Opd0 = Widen(CurDAG, Op0->getOperand(0).getOperand(0)); 21200b57cec5SDimitry Andric // Make sure to clamp the MSB so that we preserve the semantics of the 21210b57cec5SDimitry Andric // original operations. 21220b57cec5SDimitry Andric ClampMSB = true; 21230b57cec5SDimitry Andric } else if (VT == MVT::i32 && Op0->getOpcode() == ISD::TRUNCATE && 21240b57cec5SDimitry Andric isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL, 21250b57cec5SDimitry Andric SrlImm)) { 21260b57cec5SDimitry Andric // If the shift result was truncated, we can still combine them. 21270b57cec5SDimitry Andric Opd0 = Op0->getOperand(0).getOperand(0); 21280b57cec5SDimitry Andric 21290b57cec5SDimitry Andric // Use the type of SRL node. 21300b57cec5SDimitry Andric VT = Opd0->getValueType(0); 21310b57cec5SDimitry Andric } else if (isOpcWithIntImmediate(Op0, ISD::SRL, SrlImm)) { 21320b57cec5SDimitry Andric Opd0 = Op0->getOperand(0); 213381ad6265SDimitry Andric ClampMSB = (VT == MVT::i32); 21340b57cec5SDimitry Andric } else if (BiggerPattern) { 21350b57cec5SDimitry Andric // Let's pretend a 0 shift right has been performed. 21360b57cec5SDimitry Andric // The resulting code will be at least as good as the original one 21370b57cec5SDimitry Andric // plus it may expose more opportunities for bitfield insert pattern. 21380b57cec5SDimitry Andric // FIXME: Currently we limit this to the bigger pattern, because 21390b57cec5SDimitry Andric // some optimizations expect AND and not UBFM. 21400b57cec5SDimitry Andric Opd0 = N->getOperand(0); 21410b57cec5SDimitry Andric } else 21420b57cec5SDimitry Andric return false; 21430b57cec5SDimitry Andric 21440b57cec5SDimitry Andric // Bail out on large immediates. This happens when no proper 21450b57cec5SDimitry Andric // combining/constant folding was performed. 21460b57cec5SDimitry Andric if (!BiggerPattern && (SrlImm <= 0 || SrlImm >= VT.getSizeInBits())) { 21470b57cec5SDimitry Andric LLVM_DEBUG( 21480b57cec5SDimitry Andric (dbgs() << N 21490b57cec5SDimitry Andric << ": Found large shift immediate, this should not happen\n")); 21500b57cec5SDimitry Andric return false; 21510b57cec5SDimitry Andric } 21520b57cec5SDimitry Andric 21530b57cec5SDimitry Andric LSB = SrlImm; 21540b57cec5SDimitry Andric MSB = SrlImm + (VT == MVT::i32 ? countTrailingOnes<uint32_t>(AndImm) 21550b57cec5SDimitry Andric : countTrailingOnes<uint64_t>(AndImm)) - 21560b57cec5SDimitry Andric 1; 21570b57cec5SDimitry Andric if (ClampMSB) 21580b57cec5SDimitry Andric // Since we're moving the extend before the right shift operation, we need 21590b57cec5SDimitry Andric // to clamp the MSB to make sure we don't shift in undefined bits instead of 21600b57cec5SDimitry Andric // the zeros which would get shifted in with the original right shift 21610b57cec5SDimitry Andric // operation. 21620b57cec5SDimitry Andric MSB = MSB > 31 ? 31 : MSB; 21630b57cec5SDimitry Andric 21640b57cec5SDimitry Andric Opc = VT == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri; 21650b57cec5SDimitry Andric return true; 21660b57cec5SDimitry Andric } 21670b57cec5SDimitry Andric 21680b57cec5SDimitry Andric static bool isBitfieldExtractOpFromSExtInReg(SDNode *N, unsigned &Opc, 21690b57cec5SDimitry Andric SDValue &Opd0, unsigned &Immr, 21700b57cec5SDimitry Andric unsigned &Imms) { 21710b57cec5SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND_INREG); 21720b57cec5SDimitry Andric 21730b57cec5SDimitry Andric EVT VT = N->getValueType(0); 21740b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 21750b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 21760b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 21770b57cec5SDimitry Andric 21780b57cec5SDimitry Andric SDValue Op = N->getOperand(0); 21790b57cec5SDimitry Andric if (Op->getOpcode() == ISD::TRUNCATE) { 21800b57cec5SDimitry Andric Op = Op->getOperand(0); 21810b57cec5SDimitry Andric VT = Op->getValueType(0); 21820b57cec5SDimitry Andric BitWidth = VT.getSizeInBits(); 21830b57cec5SDimitry Andric } 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric uint64_t ShiftImm; 21860b57cec5SDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRL, ShiftImm) && 21870b57cec5SDimitry Andric !isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm)) 21880b57cec5SDimitry Andric return false; 21890b57cec5SDimitry Andric 21900b57cec5SDimitry Andric unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits(); 21910b57cec5SDimitry Andric if (ShiftImm + Width > BitWidth) 21920b57cec5SDimitry Andric return false; 21930b57cec5SDimitry Andric 21940b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::SBFMWri : AArch64::SBFMXri; 21950b57cec5SDimitry Andric Opd0 = Op.getOperand(0); 21960b57cec5SDimitry Andric Immr = ShiftImm; 21970b57cec5SDimitry Andric Imms = ShiftImm + Width - 1; 21980b57cec5SDimitry Andric return true; 21990b57cec5SDimitry Andric } 22000b57cec5SDimitry Andric 22010b57cec5SDimitry Andric static bool isSeveralBitsExtractOpFromShr(SDNode *N, unsigned &Opc, 22020b57cec5SDimitry Andric SDValue &Opd0, unsigned &LSB, 22030b57cec5SDimitry Andric unsigned &MSB) { 22040b57cec5SDimitry Andric // We are looking for the following pattern which basically extracts several 22050b57cec5SDimitry Andric // continuous bits from the source value and places it from the LSB of the 22060b57cec5SDimitry Andric // destination value, all other bits of the destination value or set to zero: 22070b57cec5SDimitry Andric // 22080b57cec5SDimitry Andric // Value2 = AND Value, MaskImm 22090b57cec5SDimitry Andric // SRL Value2, ShiftImm 22100b57cec5SDimitry Andric // 22110b57cec5SDimitry Andric // with MaskImm >> ShiftImm to search for the bit width. 22120b57cec5SDimitry Andric // 22130b57cec5SDimitry Andric // This gets selected into a single UBFM: 22140b57cec5SDimitry Andric // 2215*bdd1243dSDimitry Andric // UBFM Value, ShiftImm, findLastSet(MaskImm) 22160b57cec5SDimitry Andric // 22170b57cec5SDimitry Andric 22180b57cec5SDimitry Andric if (N->getOpcode() != ISD::SRL) 22190b57cec5SDimitry Andric return false; 22200b57cec5SDimitry Andric 22210b57cec5SDimitry Andric uint64_t AndMask = 0; 22220b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, AndMask)) 22230b57cec5SDimitry Andric return false; 22240b57cec5SDimitry Andric 22250b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 22260b57cec5SDimitry Andric 22270b57cec5SDimitry Andric uint64_t SrlImm = 0; 22280b57cec5SDimitry Andric if (!isIntImmediate(N->getOperand(1), SrlImm)) 22290b57cec5SDimitry Andric return false; 22300b57cec5SDimitry Andric 22310b57cec5SDimitry Andric // Check whether we really have several bits extract here. 2232*bdd1243dSDimitry Andric if (!isMask_64(AndMask >> SrlImm)) 22330b57cec5SDimitry Andric return false; 2234*bdd1243dSDimitry Andric 2235*bdd1243dSDimitry Andric Opc = N->getValueType(0) == MVT::i32 ? AArch64::UBFMWri : AArch64::UBFMXri; 2236*bdd1243dSDimitry Andric LSB = SrlImm; 2237*bdd1243dSDimitry Andric MSB = findLastSet(AndMask, ZB_Undefined); 2238*bdd1243dSDimitry Andric return true; 22390b57cec5SDimitry Andric } 22400b57cec5SDimitry Andric 22410b57cec5SDimitry Andric static bool isBitfieldExtractOpFromShr(SDNode *N, unsigned &Opc, SDValue &Opd0, 22420b57cec5SDimitry Andric unsigned &Immr, unsigned &Imms, 22430b57cec5SDimitry Andric bool BiggerPattern) { 22440b57cec5SDimitry Andric assert((N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL) && 22450b57cec5SDimitry Andric "N must be a SHR/SRA operation to call this function"); 22460b57cec5SDimitry Andric 22470b57cec5SDimitry Andric EVT VT = N->getValueType(0); 22480b57cec5SDimitry Andric 22490b57cec5SDimitry Andric // Here we can test the type of VT and return false when the type does not 22500b57cec5SDimitry Andric // match, but since it is done prior to that call in the current context 22510b57cec5SDimitry Andric // we turned that into an assert to avoid redundant code. 22520b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 22530b57cec5SDimitry Andric "Type checking must have been done before calling this function"); 22540b57cec5SDimitry Andric 22550b57cec5SDimitry Andric // Check for AND + SRL doing several bits extract. 22560b57cec5SDimitry Andric if (isSeveralBitsExtractOpFromShr(N, Opc, Opd0, Immr, Imms)) 22570b57cec5SDimitry Andric return true; 22580b57cec5SDimitry Andric 22590b57cec5SDimitry Andric // We're looking for a shift of a shift. 22600b57cec5SDimitry Andric uint64_t ShlImm = 0; 22610b57cec5SDimitry Andric uint64_t TruncBits = 0; 22620b57cec5SDimitry Andric if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, ShlImm)) { 22630b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 22640b57cec5SDimitry Andric } else if (VT == MVT::i32 && N->getOpcode() == ISD::SRL && 22650b57cec5SDimitry Andric N->getOperand(0).getNode()->getOpcode() == ISD::TRUNCATE) { 22660b57cec5SDimitry Andric // We are looking for a shift of truncate. Truncate from i64 to i32 could 22670b57cec5SDimitry Andric // be considered as setting high 32 bits as zero. Our strategy here is to 22680b57cec5SDimitry Andric // always generate 64bit UBFM. This consistency will help the CSE pass 22690b57cec5SDimitry Andric // later find more redundancy. 22700b57cec5SDimitry Andric Opd0 = N->getOperand(0).getOperand(0); 22710b57cec5SDimitry Andric TruncBits = Opd0->getValueType(0).getSizeInBits() - VT.getSizeInBits(); 22720b57cec5SDimitry Andric VT = Opd0.getValueType(); 22730b57cec5SDimitry Andric assert(VT == MVT::i64 && "the promoted type should be i64"); 22740b57cec5SDimitry Andric } else if (BiggerPattern) { 22750b57cec5SDimitry Andric // Let's pretend a 0 shift left has been performed. 22760b57cec5SDimitry Andric // FIXME: Currently we limit this to the bigger pattern case, 22770b57cec5SDimitry Andric // because some optimizations expect AND and not UBFM 22780b57cec5SDimitry Andric Opd0 = N->getOperand(0); 22790b57cec5SDimitry Andric } else 22800b57cec5SDimitry Andric return false; 22810b57cec5SDimitry Andric 22820b57cec5SDimitry Andric // Missing combines/constant folding may have left us with strange 22830b57cec5SDimitry Andric // constants. 22840b57cec5SDimitry Andric if (ShlImm >= VT.getSizeInBits()) { 22850b57cec5SDimitry Andric LLVM_DEBUG( 22860b57cec5SDimitry Andric (dbgs() << N 22870b57cec5SDimitry Andric << ": Found large shift immediate, this should not happen\n")); 22880b57cec5SDimitry Andric return false; 22890b57cec5SDimitry Andric } 22900b57cec5SDimitry Andric 22910b57cec5SDimitry Andric uint64_t SrlImm = 0; 22920b57cec5SDimitry Andric if (!isIntImmediate(N->getOperand(1), SrlImm)) 22930b57cec5SDimitry Andric return false; 22940b57cec5SDimitry Andric 22950b57cec5SDimitry Andric assert(SrlImm > 0 && SrlImm < VT.getSizeInBits() && 22960b57cec5SDimitry Andric "bad amount in shift node!"); 22970b57cec5SDimitry Andric int immr = SrlImm - ShlImm; 22980b57cec5SDimitry Andric Immr = immr < 0 ? immr + VT.getSizeInBits() : immr; 22990b57cec5SDimitry Andric Imms = VT.getSizeInBits() - ShlImm - TruncBits - 1; 23000b57cec5SDimitry Andric // SRA requires a signed extraction 23010b57cec5SDimitry Andric if (VT == MVT::i32) 23020b57cec5SDimitry Andric Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMWri : AArch64::UBFMWri; 23030b57cec5SDimitry Andric else 23040b57cec5SDimitry Andric Opc = N->getOpcode() == ISD::SRA ? AArch64::SBFMXri : AArch64::UBFMXri; 23050b57cec5SDimitry Andric return true; 23060b57cec5SDimitry Andric } 23070b57cec5SDimitry Andric 23080b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldExtractOpFromSExt(SDNode *N) { 23090b57cec5SDimitry Andric assert(N->getOpcode() == ISD::SIGN_EXTEND); 23100b57cec5SDimitry Andric 23110b57cec5SDimitry Andric EVT VT = N->getValueType(0); 23120b57cec5SDimitry Andric EVT NarrowVT = N->getOperand(0)->getValueType(0); 23130b57cec5SDimitry Andric if (VT != MVT::i64 || NarrowVT != MVT::i32) 23140b57cec5SDimitry Andric return false; 23150b57cec5SDimitry Andric 23160b57cec5SDimitry Andric uint64_t ShiftImm; 23170b57cec5SDimitry Andric SDValue Op = N->getOperand(0); 23180b57cec5SDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SRA, ShiftImm)) 23190b57cec5SDimitry Andric return false; 23200b57cec5SDimitry Andric 23210b57cec5SDimitry Andric SDLoc dl(N); 23220b57cec5SDimitry Andric // Extend the incoming operand of the shift to 64-bits. 23230b57cec5SDimitry Andric SDValue Opd0 = Widen(CurDAG, Op.getOperand(0)); 23240b57cec5SDimitry Andric unsigned Immr = ShiftImm; 23250b57cec5SDimitry Andric unsigned Imms = NarrowVT.getSizeInBits() - 1; 23260b57cec5SDimitry Andric SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT), 23270b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, VT)}; 23280b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, AArch64::SBFMXri, VT, Ops); 23290b57cec5SDimitry Andric return true; 23300b57cec5SDimitry Andric } 23310b57cec5SDimitry Andric 2332480093f4SDimitry Andric /// Try to form fcvtl2 instructions from a floating-point extend of a high-half 2333480093f4SDimitry Andric /// extract of a subvector. 2334480093f4SDimitry Andric bool AArch64DAGToDAGISel::tryHighFPExt(SDNode *N) { 2335480093f4SDimitry Andric assert(N->getOpcode() == ISD::FP_EXTEND); 2336480093f4SDimitry Andric 2337480093f4SDimitry Andric // There are 2 forms of fcvtl2 - extend to double or extend to float. 2338480093f4SDimitry Andric SDValue Extract = N->getOperand(0); 2339480093f4SDimitry Andric EVT VT = N->getValueType(0); 2340480093f4SDimitry Andric EVT NarrowVT = Extract.getValueType(); 2341480093f4SDimitry Andric if ((VT != MVT::v2f64 || NarrowVT != MVT::v2f32) && 2342480093f4SDimitry Andric (VT != MVT::v4f32 || NarrowVT != MVT::v4f16)) 2343480093f4SDimitry Andric return false; 2344480093f4SDimitry Andric 2345480093f4SDimitry Andric // Optionally look past a bitcast. 2346480093f4SDimitry Andric Extract = peekThroughBitcasts(Extract); 2347480093f4SDimitry Andric if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR) 2348480093f4SDimitry Andric return false; 2349480093f4SDimitry Andric 2350480093f4SDimitry Andric // Match extract from start of high half index. 2351480093f4SDimitry Andric // Example: v8i16 -> v4i16 means the extract must begin at index 4. 2352480093f4SDimitry Andric unsigned ExtractIndex = Extract.getConstantOperandVal(1); 2353480093f4SDimitry Andric if (ExtractIndex != Extract.getValueType().getVectorNumElements()) 2354480093f4SDimitry Andric return false; 2355480093f4SDimitry Andric 2356480093f4SDimitry Andric auto Opcode = VT == MVT::v2f64 ? AArch64::FCVTLv4i32 : AArch64::FCVTLv8i16; 2357480093f4SDimitry Andric CurDAG->SelectNodeTo(N, Opcode, VT, Extract.getOperand(0)); 2358480093f4SDimitry Andric return true; 2359480093f4SDimitry Andric } 2360480093f4SDimitry Andric 23610b57cec5SDimitry Andric static bool isBitfieldExtractOp(SelectionDAG *CurDAG, SDNode *N, unsigned &Opc, 23620b57cec5SDimitry Andric SDValue &Opd0, unsigned &Immr, unsigned &Imms, 23630b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits = 0, 23640b57cec5SDimitry Andric bool BiggerPattern = false) { 23650b57cec5SDimitry Andric if (N->getValueType(0) != MVT::i32 && N->getValueType(0) != MVT::i64) 23660b57cec5SDimitry Andric return false; 23670b57cec5SDimitry Andric 23680b57cec5SDimitry Andric switch (N->getOpcode()) { 23690b57cec5SDimitry Andric default: 23700b57cec5SDimitry Andric if (!N->isMachineOpcode()) 23710b57cec5SDimitry Andric return false; 23720b57cec5SDimitry Andric break; 23730b57cec5SDimitry Andric case ISD::AND: 23740b57cec5SDimitry Andric return isBitfieldExtractOpFromAnd(CurDAG, N, Opc, Opd0, Immr, Imms, 23750b57cec5SDimitry Andric NumberOfIgnoredLowBits, BiggerPattern); 23760b57cec5SDimitry Andric case ISD::SRL: 23770b57cec5SDimitry Andric case ISD::SRA: 23780b57cec5SDimitry Andric return isBitfieldExtractOpFromShr(N, Opc, Opd0, Immr, Imms, BiggerPattern); 23790b57cec5SDimitry Andric 23800b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 23810b57cec5SDimitry Andric return isBitfieldExtractOpFromSExtInReg(N, Opc, Opd0, Immr, Imms); 23820b57cec5SDimitry Andric } 23830b57cec5SDimitry Andric 23840b57cec5SDimitry Andric unsigned NOpc = N->getMachineOpcode(); 23850b57cec5SDimitry Andric switch (NOpc) { 23860b57cec5SDimitry Andric default: 23870b57cec5SDimitry Andric return false; 23880b57cec5SDimitry Andric case AArch64::SBFMWri: 23890b57cec5SDimitry Andric case AArch64::UBFMWri: 23900b57cec5SDimitry Andric case AArch64::SBFMXri: 23910b57cec5SDimitry Andric case AArch64::UBFMXri: 23920b57cec5SDimitry Andric Opc = NOpc; 23930b57cec5SDimitry Andric Opd0 = N->getOperand(0); 23940b57cec5SDimitry Andric Immr = cast<ConstantSDNode>(N->getOperand(1).getNode())->getZExtValue(); 23950b57cec5SDimitry Andric Imms = cast<ConstantSDNode>(N->getOperand(2).getNode())->getZExtValue(); 23960b57cec5SDimitry Andric return true; 23970b57cec5SDimitry Andric } 23980b57cec5SDimitry Andric // Unreachable 23990b57cec5SDimitry Andric return false; 24000b57cec5SDimitry Andric } 24010b57cec5SDimitry Andric 24020b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldExtractOp(SDNode *N) { 24030b57cec5SDimitry Andric unsigned Opc, Immr, Imms; 24040b57cec5SDimitry Andric SDValue Opd0; 24050b57cec5SDimitry Andric if (!isBitfieldExtractOp(CurDAG, N, Opc, Opd0, Immr, Imms)) 24060b57cec5SDimitry Andric return false; 24070b57cec5SDimitry Andric 24080b57cec5SDimitry Andric EVT VT = N->getValueType(0); 24090b57cec5SDimitry Andric SDLoc dl(N); 24100b57cec5SDimitry Andric 24110b57cec5SDimitry Andric // If the bit extract operation is 64bit but the original type is 32bit, we 24120b57cec5SDimitry Andric // need to add one EXTRACT_SUBREG. 24130b57cec5SDimitry Andric if ((Opc == AArch64::SBFMXri || Opc == AArch64::UBFMXri) && VT == MVT::i32) { 24140b57cec5SDimitry Andric SDValue Ops64[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, MVT::i64), 24150b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, MVT::i64)}; 24160b57cec5SDimitry Andric 24170b57cec5SDimitry Andric SDNode *BFM = CurDAG->getMachineNode(Opc, dl, MVT::i64, Ops64); 24180b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, dl, MVT::i32); 24190b57cec5SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, dl, 24200b57cec5SDimitry Andric MVT::i32, SDValue(BFM, 0), SubReg)); 24210b57cec5SDimitry Andric return true; 24220b57cec5SDimitry Andric } 24230b57cec5SDimitry Andric 24240b57cec5SDimitry Andric SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(Immr, dl, VT), 24250b57cec5SDimitry Andric CurDAG->getTargetConstant(Imms, dl, VT)}; 24260b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 24270b57cec5SDimitry Andric return true; 24280b57cec5SDimitry Andric } 24290b57cec5SDimitry Andric 24300b57cec5SDimitry Andric /// Does DstMask form a complementary pair with the mask provided by 24310b57cec5SDimitry Andric /// BitsToBeInserted, suitable for use in a BFI instruction. Roughly speaking, 24320b57cec5SDimitry Andric /// this asks whether DstMask zeroes precisely those bits that will be set by 24330b57cec5SDimitry Andric /// the other half. 24340b57cec5SDimitry Andric static bool isBitfieldDstMask(uint64_t DstMask, const APInt &BitsToBeInserted, 24350b57cec5SDimitry Andric unsigned NumberOfIgnoredHighBits, EVT VT) { 24360b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 24370b57cec5SDimitry Andric "i32 or i64 mask type expected!"); 24380b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits() - NumberOfIgnoredHighBits; 24390b57cec5SDimitry Andric 24400b57cec5SDimitry Andric APInt SignificantDstMask = APInt(BitWidth, DstMask); 24410b57cec5SDimitry Andric APInt SignificantBitsToBeInserted = BitsToBeInserted.zextOrTrunc(BitWidth); 24420b57cec5SDimitry Andric 24430b57cec5SDimitry Andric return (SignificantDstMask & SignificantBitsToBeInserted) == 0 && 2444349cc55cSDimitry Andric (SignificantDstMask | SignificantBitsToBeInserted).isAllOnes(); 24450b57cec5SDimitry Andric } 24460b57cec5SDimitry Andric 24470b57cec5SDimitry Andric // Look for bits that will be useful for later uses. 24480b57cec5SDimitry Andric // A bit is consider useless as soon as it is dropped and never used 24490b57cec5SDimitry Andric // before it as been dropped. 24500b57cec5SDimitry Andric // E.g., looking for useful bit of x 24510b57cec5SDimitry Andric // 1. y = x & 0x7 24520b57cec5SDimitry Andric // 2. z = y >> 2 24530b57cec5SDimitry Andric // After #1, x useful bits are 0x7, then the useful bits of x, live through 24540b57cec5SDimitry Andric // y. 24550b57cec5SDimitry Andric // After #2, the useful bits of x are 0x4. 24560b57cec5SDimitry Andric // However, if x is used on an unpredicatable instruction, then all its bits 24570b57cec5SDimitry Andric // are useful. 24580b57cec5SDimitry Andric // E.g. 24590b57cec5SDimitry Andric // 1. y = x & 0x7 24600b57cec5SDimitry Andric // 2. z = y >> 2 24610b57cec5SDimitry Andric // 3. str x, [@x] 24620b57cec5SDimitry Andric static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth = 0); 24630b57cec5SDimitry Andric 24640b57cec5SDimitry Andric static void getUsefulBitsFromAndWithImmediate(SDValue Op, APInt &UsefulBits, 24650b57cec5SDimitry Andric unsigned Depth) { 24660b57cec5SDimitry Andric uint64_t Imm = 24670b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue(); 24680b57cec5SDimitry Andric Imm = AArch64_AM::decodeLogicalImmediate(Imm, UsefulBits.getBitWidth()); 24690b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), Imm); 24700b57cec5SDimitry Andric getUsefulBits(Op, UsefulBits, Depth + 1); 24710b57cec5SDimitry Andric } 24720b57cec5SDimitry Andric 24730b57cec5SDimitry Andric static void getUsefulBitsFromBitfieldMoveOpd(SDValue Op, APInt &UsefulBits, 24740b57cec5SDimitry Andric uint64_t Imm, uint64_t MSB, 24750b57cec5SDimitry Andric unsigned Depth) { 24760b57cec5SDimitry Andric // inherit the bitwidth value 24770b57cec5SDimitry Andric APInt OpUsefulBits(UsefulBits); 24780b57cec5SDimitry Andric OpUsefulBits = 1; 24790b57cec5SDimitry Andric 24800b57cec5SDimitry Andric if (MSB >= Imm) { 24810b57cec5SDimitry Andric OpUsefulBits <<= MSB - Imm + 1; 24820b57cec5SDimitry Andric --OpUsefulBits; 24830b57cec5SDimitry Andric // The interesting part will be in the lower part of the result 24840b57cec5SDimitry Andric getUsefulBits(Op, OpUsefulBits, Depth + 1); 24850b57cec5SDimitry Andric // The interesting part was starting at Imm in the argument 24860b57cec5SDimitry Andric OpUsefulBits <<= Imm; 24870b57cec5SDimitry Andric } else { 24880b57cec5SDimitry Andric OpUsefulBits <<= MSB + 1; 24890b57cec5SDimitry Andric --OpUsefulBits; 24900b57cec5SDimitry Andric // The interesting part will be shifted in the result 24910b57cec5SDimitry Andric OpUsefulBits <<= OpUsefulBits.getBitWidth() - Imm; 24920b57cec5SDimitry Andric getUsefulBits(Op, OpUsefulBits, Depth + 1); 24930b57cec5SDimitry Andric // The interesting part was at zero in the argument 24940b57cec5SDimitry Andric OpUsefulBits.lshrInPlace(OpUsefulBits.getBitWidth() - Imm); 24950b57cec5SDimitry Andric } 24960b57cec5SDimitry Andric 24970b57cec5SDimitry Andric UsefulBits &= OpUsefulBits; 24980b57cec5SDimitry Andric } 24990b57cec5SDimitry Andric 25000b57cec5SDimitry Andric static void getUsefulBitsFromUBFM(SDValue Op, APInt &UsefulBits, 25010b57cec5SDimitry Andric unsigned Depth) { 25020b57cec5SDimitry Andric uint64_t Imm = 25030b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(1).getNode())->getZExtValue(); 25040b57cec5SDimitry Andric uint64_t MSB = 25050b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 25060b57cec5SDimitry Andric 25070b57cec5SDimitry Andric getUsefulBitsFromBitfieldMoveOpd(Op, UsefulBits, Imm, MSB, Depth); 25080b57cec5SDimitry Andric } 25090b57cec5SDimitry Andric 25100b57cec5SDimitry Andric static void getUsefulBitsFromOrWithShiftedReg(SDValue Op, APInt &UsefulBits, 25110b57cec5SDimitry Andric unsigned Depth) { 25120b57cec5SDimitry Andric uint64_t ShiftTypeAndValue = 25130b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 25140b57cec5SDimitry Andric APInt Mask(UsefulBits); 25150b57cec5SDimitry Andric Mask.clearAllBits(); 25160b57cec5SDimitry Andric Mask.flipAllBits(); 25170b57cec5SDimitry Andric 25180b57cec5SDimitry Andric if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSL) { 25190b57cec5SDimitry Andric // Shift Left 25200b57cec5SDimitry Andric uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue); 25210b57cec5SDimitry Andric Mask <<= ShiftAmt; 25220b57cec5SDimitry Andric getUsefulBits(Op, Mask, Depth + 1); 25230b57cec5SDimitry Andric Mask.lshrInPlace(ShiftAmt); 25240b57cec5SDimitry Andric } else if (AArch64_AM::getShiftType(ShiftTypeAndValue) == AArch64_AM::LSR) { 25250b57cec5SDimitry Andric // Shift Right 25260b57cec5SDimitry Andric // We do not handle AArch64_AM::ASR, because the sign will change the 25270b57cec5SDimitry Andric // number of useful bits 25280b57cec5SDimitry Andric uint64_t ShiftAmt = AArch64_AM::getShiftValue(ShiftTypeAndValue); 25290b57cec5SDimitry Andric Mask.lshrInPlace(ShiftAmt); 25300b57cec5SDimitry Andric getUsefulBits(Op, Mask, Depth + 1); 25310b57cec5SDimitry Andric Mask <<= ShiftAmt; 25320b57cec5SDimitry Andric } else 25330b57cec5SDimitry Andric return; 25340b57cec5SDimitry Andric 25350b57cec5SDimitry Andric UsefulBits &= Mask; 25360b57cec5SDimitry Andric } 25370b57cec5SDimitry Andric 25380b57cec5SDimitry Andric static void getUsefulBitsFromBFM(SDValue Op, SDValue Orig, APInt &UsefulBits, 25390b57cec5SDimitry Andric unsigned Depth) { 25400b57cec5SDimitry Andric uint64_t Imm = 25410b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue(); 25420b57cec5SDimitry Andric uint64_t MSB = 25430b57cec5SDimitry Andric cast<const ConstantSDNode>(Op.getOperand(3).getNode())->getZExtValue(); 25440b57cec5SDimitry Andric 25450b57cec5SDimitry Andric APInt OpUsefulBits(UsefulBits); 25460b57cec5SDimitry Andric OpUsefulBits = 1; 25470b57cec5SDimitry Andric 25480b57cec5SDimitry Andric APInt ResultUsefulBits(UsefulBits.getBitWidth(), 0); 25490b57cec5SDimitry Andric ResultUsefulBits.flipAllBits(); 25500b57cec5SDimitry Andric APInt Mask(UsefulBits.getBitWidth(), 0); 25510b57cec5SDimitry Andric 25520b57cec5SDimitry Andric getUsefulBits(Op, ResultUsefulBits, Depth + 1); 25530b57cec5SDimitry Andric 25540b57cec5SDimitry Andric if (MSB >= Imm) { 25550b57cec5SDimitry Andric // The instruction is a BFXIL. 25560b57cec5SDimitry Andric uint64_t Width = MSB - Imm + 1; 25570b57cec5SDimitry Andric uint64_t LSB = Imm; 25580b57cec5SDimitry Andric 25590b57cec5SDimitry Andric OpUsefulBits <<= Width; 25600b57cec5SDimitry Andric --OpUsefulBits; 25610b57cec5SDimitry Andric 25620b57cec5SDimitry Andric if (Op.getOperand(1) == Orig) { 25630b57cec5SDimitry Andric // Copy the low bits from the result to bits starting from LSB. 25640b57cec5SDimitry Andric Mask = ResultUsefulBits & OpUsefulBits; 25650b57cec5SDimitry Andric Mask <<= LSB; 25660b57cec5SDimitry Andric } 25670b57cec5SDimitry Andric 25680b57cec5SDimitry Andric if (Op.getOperand(0) == Orig) 25690b57cec5SDimitry Andric // Bits starting from LSB in the input contribute to the result. 25700b57cec5SDimitry Andric Mask |= (ResultUsefulBits & ~OpUsefulBits); 25710b57cec5SDimitry Andric } else { 25720b57cec5SDimitry Andric // The instruction is a BFI. 25730b57cec5SDimitry Andric uint64_t Width = MSB + 1; 25740b57cec5SDimitry Andric uint64_t LSB = UsefulBits.getBitWidth() - Imm; 25750b57cec5SDimitry Andric 25760b57cec5SDimitry Andric OpUsefulBits <<= Width; 25770b57cec5SDimitry Andric --OpUsefulBits; 25780b57cec5SDimitry Andric OpUsefulBits <<= LSB; 25790b57cec5SDimitry Andric 25800b57cec5SDimitry Andric if (Op.getOperand(1) == Orig) { 25810b57cec5SDimitry Andric // Copy the bits from the result to the zero bits. 25820b57cec5SDimitry Andric Mask = ResultUsefulBits & OpUsefulBits; 25830b57cec5SDimitry Andric Mask.lshrInPlace(LSB); 25840b57cec5SDimitry Andric } 25850b57cec5SDimitry Andric 25860b57cec5SDimitry Andric if (Op.getOperand(0) == Orig) 25870b57cec5SDimitry Andric Mask |= (ResultUsefulBits & ~OpUsefulBits); 25880b57cec5SDimitry Andric } 25890b57cec5SDimitry Andric 25900b57cec5SDimitry Andric UsefulBits &= Mask; 25910b57cec5SDimitry Andric } 25920b57cec5SDimitry Andric 25930b57cec5SDimitry Andric static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits, 25940b57cec5SDimitry Andric SDValue Orig, unsigned Depth) { 25950b57cec5SDimitry Andric 25960b57cec5SDimitry Andric // Users of this node should have already been instruction selected 25970b57cec5SDimitry Andric // FIXME: Can we turn that into an assert? 25980b57cec5SDimitry Andric if (!UserNode->isMachineOpcode()) 25990b57cec5SDimitry Andric return; 26000b57cec5SDimitry Andric 26010b57cec5SDimitry Andric switch (UserNode->getMachineOpcode()) { 26020b57cec5SDimitry Andric default: 26030b57cec5SDimitry Andric return; 26040b57cec5SDimitry Andric case AArch64::ANDSWri: 26050b57cec5SDimitry Andric case AArch64::ANDSXri: 26060b57cec5SDimitry Andric case AArch64::ANDWri: 26070b57cec5SDimitry Andric case AArch64::ANDXri: 26080b57cec5SDimitry Andric // We increment Depth only when we call the getUsefulBits 26090b57cec5SDimitry Andric return getUsefulBitsFromAndWithImmediate(SDValue(UserNode, 0), UsefulBits, 26100b57cec5SDimitry Andric Depth); 26110b57cec5SDimitry Andric case AArch64::UBFMWri: 26120b57cec5SDimitry Andric case AArch64::UBFMXri: 26130b57cec5SDimitry Andric return getUsefulBitsFromUBFM(SDValue(UserNode, 0), UsefulBits, Depth); 26140b57cec5SDimitry Andric 26150b57cec5SDimitry Andric case AArch64::ORRWrs: 26160b57cec5SDimitry Andric case AArch64::ORRXrs: 2617fe6060f1SDimitry Andric if (UserNode->getOperand(0) != Orig && UserNode->getOperand(1) == Orig) 2618fe6060f1SDimitry Andric getUsefulBitsFromOrWithShiftedReg(SDValue(UserNode, 0), UsefulBits, 26190b57cec5SDimitry Andric Depth); 2620fe6060f1SDimitry Andric return; 26210b57cec5SDimitry Andric case AArch64::BFMWri: 26220b57cec5SDimitry Andric case AArch64::BFMXri: 26230b57cec5SDimitry Andric return getUsefulBitsFromBFM(SDValue(UserNode, 0), Orig, UsefulBits, Depth); 26240b57cec5SDimitry Andric 26250b57cec5SDimitry Andric case AArch64::STRBBui: 26260b57cec5SDimitry Andric case AArch64::STURBBi: 26270b57cec5SDimitry Andric if (UserNode->getOperand(0) != Orig) 26280b57cec5SDimitry Andric return; 26290b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xff); 26300b57cec5SDimitry Andric return; 26310b57cec5SDimitry Andric 26320b57cec5SDimitry Andric case AArch64::STRHHui: 26330b57cec5SDimitry Andric case AArch64::STURHHi: 26340b57cec5SDimitry Andric if (UserNode->getOperand(0) != Orig) 26350b57cec5SDimitry Andric return; 26360b57cec5SDimitry Andric UsefulBits &= APInt(UsefulBits.getBitWidth(), 0xffff); 26370b57cec5SDimitry Andric return; 26380b57cec5SDimitry Andric } 26390b57cec5SDimitry Andric } 26400b57cec5SDimitry Andric 26410b57cec5SDimitry Andric static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth) { 26428bcb0991SDimitry Andric if (Depth >= SelectionDAG::MaxRecursionDepth) 26430b57cec5SDimitry Andric return; 26440b57cec5SDimitry Andric // Initialize UsefulBits 26450b57cec5SDimitry Andric if (!Depth) { 26460b57cec5SDimitry Andric unsigned Bitwidth = Op.getScalarValueSizeInBits(); 26470b57cec5SDimitry Andric // At the beginning, assume every produced bits is useful 26480b57cec5SDimitry Andric UsefulBits = APInt(Bitwidth, 0); 26490b57cec5SDimitry Andric UsefulBits.flipAllBits(); 26500b57cec5SDimitry Andric } 26510b57cec5SDimitry Andric APInt UsersUsefulBits(UsefulBits.getBitWidth(), 0); 26520b57cec5SDimitry Andric 26530b57cec5SDimitry Andric for (SDNode *Node : Op.getNode()->uses()) { 26540b57cec5SDimitry Andric // A use cannot produce useful bits 26550b57cec5SDimitry Andric APInt UsefulBitsForUse = APInt(UsefulBits); 26560b57cec5SDimitry Andric getUsefulBitsForUse(Node, UsefulBitsForUse, Op, Depth); 26570b57cec5SDimitry Andric UsersUsefulBits |= UsefulBitsForUse; 26580b57cec5SDimitry Andric } 26590b57cec5SDimitry Andric // UsefulBits contains the produced bits that are meaningful for the 26600b57cec5SDimitry Andric // current definition, thus a user cannot make a bit meaningful at 26610b57cec5SDimitry Andric // this point 26620b57cec5SDimitry Andric UsefulBits &= UsersUsefulBits; 26630b57cec5SDimitry Andric } 26640b57cec5SDimitry Andric 26650b57cec5SDimitry Andric /// Create a machine node performing a notional SHL of Op by ShlAmount. If 26660b57cec5SDimitry Andric /// ShlAmount is negative, do a (logical) right-shift instead. If ShlAmount is 26670b57cec5SDimitry Andric /// 0, return Op unchanged. 26680b57cec5SDimitry Andric static SDValue getLeftShift(SelectionDAG *CurDAG, SDValue Op, int ShlAmount) { 26690b57cec5SDimitry Andric if (ShlAmount == 0) 26700b57cec5SDimitry Andric return Op; 26710b57cec5SDimitry Andric 26720b57cec5SDimitry Andric EVT VT = Op.getValueType(); 26730b57cec5SDimitry Andric SDLoc dl(Op); 26740b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 26750b57cec5SDimitry Andric unsigned UBFMOpc = BitWidth == 32 ? AArch64::UBFMWri : AArch64::UBFMXri; 26760b57cec5SDimitry Andric 26770b57cec5SDimitry Andric SDNode *ShiftNode; 26780b57cec5SDimitry Andric if (ShlAmount > 0) { 26790b57cec5SDimitry Andric // LSL wD, wN, #Amt == UBFM wD, wN, #32-Amt, #31-Amt 26800b57cec5SDimitry Andric ShiftNode = CurDAG->getMachineNode( 26810b57cec5SDimitry Andric UBFMOpc, dl, VT, Op, 26820b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - ShlAmount, dl, VT), 26830b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1 - ShlAmount, dl, VT)); 26840b57cec5SDimitry Andric } else { 26850b57cec5SDimitry Andric // LSR wD, wN, #Amt == UBFM wD, wN, #Amt, #32-1 26860b57cec5SDimitry Andric assert(ShlAmount < 0 && "expected right shift"); 26870b57cec5SDimitry Andric int ShrAmount = -ShlAmount; 26880b57cec5SDimitry Andric ShiftNode = CurDAG->getMachineNode( 26890b57cec5SDimitry Andric UBFMOpc, dl, VT, Op, CurDAG->getTargetConstant(ShrAmount, dl, VT), 26900b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1, dl, VT)); 26910b57cec5SDimitry Andric } 26920b57cec5SDimitry Andric 26930b57cec5SDimitry Andric return SDValue(ShiftNode, 0); 26940b57cec5SDimitry Andric } 26950b57cec5SDimitry Andric 2696*bdd1243dSDimitry Andric // For bit-field-positioning pattern "(and (shl VAL, N), ShiftedMask)". 2697*bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, 26980b57cec5SDimitry Andric bool BiggerPattern, 2699*bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2700*bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2701*bdd1243dSDimitry Andric int &Width); 2702*bdd1243dSDimitry Andric 2703*bdd1243dSDimitry Andric // For bit-field-positioning pattern "shl VAL, N)". 2704*bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, 2705*bdd1243dSDimitry Andric bool BiggerPattern, 2706*bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2707*bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2708*bdd1243dSDimitry Andric int &Width); 2709*bdd1243dSDimitry Andric 2710*bdd1243dSDimitry Andric /// Does this tree qualify as an attempt to move a bitfield into position, 2711*bdd1243dSDimitry Andric /// essentially "(and (shl VAL, N), Mask)" or (shl VAL, N). 2712*bdd1243dSDimitry Andric static bool isBitfieldPositioningOp(SelectionDAG *CurDAG, SDValue Op, 2713*bdd1243dSDimitry Andric bool BiggerPattern, SDValue &Src, 2714*bdd1243dSDimitry Andric int &DstLSB, int &Width) { 27150b57cec5SDimitry Andric EVT VT = Op.getValueType(); 27160b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 27170b57cec5SDimitry Andric (void)BitWidth; 27180b57cec5SDimitry Andric assert(BitWidth == 32 || BitWidth == 64); 27190b57cec5SDimitry Andric 27200b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(Op); 27210b57cec5SDimitry Andric 27220b57cec5SDimitry Andric // Non-zero in the sense that they're not provably zero, which is the key 27230b57cec5SDimitry Andric // point if we want to use this value 2724*bdd1243dSDimitry Andric const uint64_t NonZeroBits = (~Known.Zero).getZExtValue(); 27250b57cec5SDimitry Andric if (!isShiftedMask_64(NonZeroBits)) 27260b57cec5SDimitry Andric return false; 27270b57cec5SDimitry Andric 2728*bdd1243dSDimitry Andric switch (Op.getOpcode()) { 2729*bdd1243dSDimitry Andric default: 2730*bdd1243dSDimitry Andric break; 2731*bdd1243dSDimitry Andric case ISD::AND: 2732*bdd1243dSDimitry Andric return isBitfieldPositioningOpFromAnd(CurDAG, Op, BiggerPattern, 2733*bdd1243dSDimitry Andric NonZeroBits, Src, DstLSB, Width); 2734*bdd1243dSDimitry Andric case ISD::SHL: 2735*bdd1243dSDimitry Andric return isBitfieldPositioningOpFromShl(CurDAG, Op, BiggerPattern, 2736*bdd1243dSDimitry Andric NonZeroBits, Src, DstLSB, Width); 2737*bdd1243dSDimitry Andric } 2738*bdd1243dSDimitry Andric 2739*bdd1243dSDimitry Andric return false; 2740*bdd1243dSDimitry Andric } 2741*bdd1243dSDimitry Andric 2742*bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromAnd(SelectionDAG *CurDAG, SDValue Op, 2743*bdd1243dSDimitry Andric bool BiggerPattern, 2744*bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2745*bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2746*bdd1243dSDimitry Andric int &Width) { 2747*bdd1243dSDimitry Andric assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed"); 2748*bdd1243dSDimitry Andric 2749*bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 2750*bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 2751*bdd1243dSDimitry Andric "Caller guarantees VT is one of i32 or i64"); 2752*bdd1243dSDimitry Andric (void)VT; 2753*bdd1243dSDimitry Andric 2754*bdd1243dSDimitry Andric uint64_t AndImm; 2755*bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::AND, AndImm)) 2756*bdd1243dSDimitry Andric return false; 2757*bdd1243dSDimitry Andric 2758*bdd1243dSDimitry Andric // If (~AndImm & NonZeroBits) is not zero at POS, we know that 2759*bdd1243dSDimitry Andric // 1) (AndImm & (1 << POS) == 0) 2760*bdd1243dSDimitry Andric // 2) the result of AND is not zero at POS bit (according to NonZeroBits) 2761*bdd1243dSDimitry Andric // 2762*bdd1243dSDimitry Andric // 1) and 2) don't agree so something must be wrong (e.g., in 2763*bdd1243dSDimitry Andric // 'SelectionDAG::computeKnownBits') 2764*bdd1243dSDimitry Andric assert((~AndImm & NonZeroBits) == 0 && 2765*bdd1243dSDimitry Andric "Something must be wrong (e.g., in SelectionDAG::computeKnownBits)"); 2766*bdd1243dSDimitry Andric 2767*bdd1243dSDimitry Andric SDValue AndOp0 = Op.getOperand(0); 2768*bdd1243dSDimitry Andric 2769*bdd1243dSDimitry Andric uint64_t ShlImm; 2770*bdd1243dSDimitry Andric SDValue ShlOp0; 2771*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(AndOp0.getNode(), ISD::SHL, ShlImm)) { 2772*bdd1243dSDimitry Andric // For pattern "and(shl(val, N), shifted-mask)", 'ShlOp0' is set to 'val'. 2773*bdd1243dSDimitry Andric ShlOp0 = AndOp0.getOperand(0); 2774*bdd1243dSDimitry Andric } else if (VT == MVT::i64 && AndOp0.getOpcode() == ISD::ANY_EXTEND && 2775*bdd1243dSDimitry Andric isOpcWithIntImmediate(AndOp0.getOperand(0).getNode(), ISD::SHL, 2776*bdd1243dSDimitry Andric ShlImm)) { 2777*bdd1243dSDimitry Andric // For pattern "and(any_extend(shl(val, N)), shifted-mask)" 2778*bdd1243dSDimitry Andric 2779*bdd1243dSDimitry Andric // ShlVal == shl(val, N), which is a left shift on a smaller type. 2780*bdd1243dSDimitry Andric SDValue ShlVal = AndOp0.getOperand(0); 2781*bdd1243dSDimitry Andric 2782*bdd1243dSDimitry Andric // Since this is after type legalization and ShlVal is extended to MVT::i64, 2783*bdd1243dSDimitry Andric // expect VT to be MVT::i32. 2784*bdd1243dSDimitry Andric assert((ShlVal.getValueType() == MVT::i32) && "Expect VT to be MVT::i32."); 2785*bdd1243dSDimitry Andric 2786*bdd1243dSDimitry Andric // Widens 'val' to MVT::i64 as the source of bit field positioning. 2787*bdd1243dSDimitry Andric ShlOp0 = Widen(CurDAG, ShlVal.getOperand(0)); 2788*bdd1243dSDimitry Andric } else 2789*bdd1243dSDimitry Andric return false; 2790*bdd1243dSDimitry Andric 2791*bdd1243dSDimitry Andric // For !BiggerPattern, bail out if the AndOp0 has more than one use, since 2792*bdd1243dSDimitry Andric // then we'll end up generating AndOp0+UBFIZ instead of just keeping 2793*bdd1243dSDimitry Andric // AndOp0+AND. 2794*bdd1243dSDimitry Andric if (!BiggerPattern && !AndOp0.hasOneUse()) 2795*bdd1243dSDimitry Andric return false; 2796*bdd1243dSDimitry Andric 2797*bdd1243dSDimitry Andric DstLSB = countTrailingZeros(NonZeroBits); 2798*bdd1243dSDimitry Andric Width = countTrailingOnes(NonZeroBits >> DstLSB); 2799*bdd1243dSDimitry Andric 2800*bdd1243dSDimitry Andric // Bail out on large Width. This happens when no proper combining / constant 2801*bdd1243dSDimitry Andric // folding was performed. 2802*bdd1243dSDimitry Andric if (Width >= (int)VT.getSizeInBits()) { 2803*bdd1243dSDimitry Andric // If VT is i64, Width > 64 is insensible since NonZeroBits is uint64_t, and 2804*bdd1243dSDimitry Andric // Width == 64 indicates a missed dag-combine from "(and val, AllOnes)" to 2805*bdd1243dSDimitry Andric // "val". 2806*bdd1243dSDimitry Andric // If VT is i32, what Width >= 32 means: 2807*bdd1243dSDimitry Andric // - For "(and (any_extend(shl val, N)), shifted-mask)", the`and` Op 2808*bdd1243dSDimitry Andric // demands at least 'Width' bits (after dag-combiner). This together with 2809*bdd1243dSDimitry Andric // `any_extend` Op (undefined higher bits) indicates missed combination 2810*bdd1243dSDimitry Andric // when lowering the 'and' IR instruction to an machine IR instruction. 2811*bdd1243dSDimitry Andric LLVM_DEBUG( 2812*bdd1243dSDimitry Andric dbgs() 2813*bdd1243dSDimitry Andric << "Found large Width in bit-field-positioning -- this indicates no " 2814*bdd1243dSDimitry Andric "proper combining / constant folding was performed\n"); 2815*bdd1243dSDimitry Andric return false; 2816*bdd1243dSDimitry Andric } 28170b57cec5SDimitry Andric 28180b57cec5SDimitry Andric // BFI encompasses sufficiently many nodes that it's worth inserting an extra 28190b57cec5SDimitry Andric // LSL/LSR if the mask in NonZeroBits doesn't quite match up with the ISD::SHL 28200b57cec5SDimitry Andric // amount. BiggerPattern is true when this pattern is being matched for BFI, 28210b57cec5SDimitry Andric // BiggerPattern is false when this pattern is being matched for UBFIZ, in 28220b57cec5SDimitry Andric // which case it is not profitable to insert an extra shift. 2823*bdd1243dSDimitry Andric if (ShlImm != uint64_t(DstLSB) && !BiggerPattern) 28240b57cec5SDimitry Andric return false; 28250b57cec5SDimitry Andric 2826*bdd1243dSDimitry Andric Src = getLeftShift(CurDAG, ShlOp0, ShlImm - DstLSB); 2827*bdd1243dSDimitry Andric return true; 2828*bdd1243dSDimitry Andric } 2829*bdd1243dSDimitry Andric 2830*bdd1243dSDimitry Andric // For node (shl (and val, mask), N)), returns true if the node is equivalent to 2831*bdd1243dSDimitry Andric // UBFIZ. 2832*bdd1243dSDimitry Andric static bool isSeveralBitsPositioningOpFromShl(const uint64_t ShlImm, SDValue Op, 2833*bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2834*bdd1243dSDimitry Andric int &Width) { 2835*bdd1243dSDimitry Andric // Caller should have verified that N is a left shift with constant shift 2836*bdd1243dSDimitry Andric // amount; asserts that. 2837*bdd1243dSDimitry Andric assert(Op.getOpcode() == ISD::SHL && 2838*bdd1243dSDimitry Andric "Op.getNode() should be a SHL node to call this function"); 2839*bdd1243dSDimitry Andric assert(isIntImmediateEq(Op.getOperand(1), ShlImm) && 2840*bdd1243dSDimitry Andric "Op.getNode() should shift ShlImm to call this function"); 2841*bdd1243dSDimitry Andric 2842*bdd1243dSDimitry Andric uint64_t AndImm = 0; 2843*bdd1243dSDimitry Andric SDValue Op0 = Op.getOperand(0); 2844*bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op0.getNode(), ISD::AND, AndImm)) 2845*bdd1243dSDimitry Andric return false; 2846*bdd1243dSDimitry Andric 2847*bdd1243dSDimitry Andric const uint64_t ShiftedAndImm = ((AndImm << ShlImm) >> ShlImm); 2848*bdd1243dSDimitry Andric if (isMask_64(ShiftedAndImm)) { 2849*bdd1243dSDimitry Andric // AndImm is a superset of (AllOnes >> ShlImm); in other words, AndImm 2850*bdd1243dSDimitry Andric // should end with Mask, and could be prefixed with random bits if those 2851*bdd1243dSDimitry Andric // bits are shifted out. 2852*bdd1243dSDimitry Andric // 2853*bdd1243dSDimitry Andric // For example, xyz11111 (with {x,y,z} being 0 or 1) is fine if ShlImm >= 3; 2854*bdd1243dSDimitry Andric // the AND result corresponding to those bits are shifted out, so it's fine 2855*bdd1243dSDimitry Andric // to not extract them. 2856*bdd1243dSDimitry Andric Width = countTrailingOnes(ShiftedAndImm); 2857*bdd1243dSDimitry Andric DstLSB = ShlImm; 2858*bdd1243dSDimitry Andric Src = Op0.getOperand(0); 2859*bdd1243dSDimitry Andric return true; 2860*bdd1243dSDimitry Andric } 2861*bdd1243dSDimitry Andric return false; 2862*bdd1243dSDimitry Andric } 2863*bdd1243dSDimitry Andric 2864*bdd1243dSDimitry Andric static bool isBitfieldPositioningOpFromShl(SelectionDAG *CurDAG, SDValue Op, 2865*bdd1243dSDimitry Andric bool BiggerPattern, 2866*bdd1243dSDimitry Andric const uint64_t NonZeroBits, 2867*bdd1243dSDimitry Andric SDValue &Src, int &DstLSB, 2868*bdd1243dSDimitry Andric int &Width) { 2869*bdd1243dSDimitry Andric assert(isShiftedMask_64(NonZeroBits) && "Caller guaranteed"); 2870*bdd1243dSDimitry Andric 2871*bdd1243dSDimitry Andric EVT VT = Op.getValueType(); 2872*bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 2873*bdd1243dSDimitry Andric "Caller guarantees that type is i32 or i64"); 2874*bdd1243dSDimitry Andric (void)VT; 2875*bdd1243dSDimitry Andric 2876*bdd1243dSDimitry Andric uint64_t ShlImm; 2877*bdd1243dSDimitry Andric if (!isOpcWithIntImmediate(Op.getNode(), ISD::SHL, ShlImm)) 2878*bdd1243dSDimitry Andric return false; 2879*bdd1243dSDimitry Andric 2880*bdd1243dSDimitry Andric if (!BiggerPattern && !Op.hasOneUse()) 2881*bdd1243dSDimitry Andric return false; 2882*bdd1243dSDimitry Andric 2883*bdd1243dSDimitry Andric if (isSeveralBitsPositioningOpFromShl(ShlImm, Op, Src, DstLSB, Width)) 2884*bdd1243dSDimitry Andric return true; 2885*bdd1243dSDimitry Andric 2886*bdd1243dSDimitry Andric DstLSB = countTrailingZeros(NonZeroBits); 2887*bdd1243dSDimitry Andric Width = countTrailingOnes(NonZeroBits >> DstLSB); 2888*bdd1243dSDimitry Andric 2889*bdd1243dSDimitry Andric if (ShlImm != uint64_t(DstLSB) && !BiggerPattern) 2890*bdd1243dSDimitry Andric return false; 2891*bdd1243dSDimitry Andric 2892*bdd1243dSDimitry Andric Src = getLeftShift(CurDAG, Op.getOperand(0), ShlImm - DstLSB); 28930b57cec5SDimitry Andric return true; 28940b57cec5SDimitry Andric } 28950b57cec5SDimitry Andric 28960b57cec5SDimitry Andric static bool isShiftedMask(uint64_t Mask, EVT VT) { 28970b57cec5SDimitry Andric assert(VT == MVT::i32 || VT == MVT::i64); 28980b57cec5SDimitry Andric if (VT == MVT::i32) 28990b57cec5SDimitry Andric return isShiftedMask_32(Mask); 29000b57cec5SDimitry Andric return isShiftedMask_64(Mask); 29010b57cec5SDimitry Andric } 29020b57cec5SDimitry Andric 29030b57cec5SDimitry Andric // Generate a BFI/BFXIL from 'or (and X, MaskImm), OrImm' iff the value being 29040b57cec5SDimitry Andric // inserted only sets known zero bits. 29050b57cec5SDimitry Andric static bool tryBitfieldInsertOpFromOrAndImm(SDNode *N, SelectionDAG *CurDAG) { 29060b57cec5SDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); 29070b57cec5SDimitry Andric 29080b57cec5SDimitry Andric EVT VT = N->getValueType(0); 29090b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 29100b57cec5SDimitry Andric return false; 29110b57cec5SDimitry Andric 29120b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 29130b57cec5SDimitry Andric 29140b57cec5SDimitry Andric uint64_t OrImm; 29150b57cec5SDimitry Andric if (!isOpcWithIntImmediate(N, ISD::OR, OrImm)) 29160b57cec5SDimitry Andric return false; 29170b57cec5SDimitry Andric 29180b57cec5SDimitry Andric // Skip this transformation if the ORR immediate can be encoded in the ORR. 29190b57cec5SDimitry Andric // Otherwise, we'll trade an AND+ORR for ORR+BFI/BFXIL, which is most likely 29200b57cec5SDimitry Andric // performance neutral. 29210b57cec5SDimitry Andric if (AArch64_AM::isLogicalImmediate(OrImm, BitWidth)) 29220b57cec5SDimitry Andric return false; 29230b57cec5SDimitry Andric 29240b57cec5SDimitry Andric uint64_t MaskImm; 29250b57cec5SDimitry Andric SDValue And = N->getOperand(0); 29260b57cec5SDimitry Andric // Must be a single use AND with an immediate operand. 29270b57cec5SDimitry Andric if (!And.hasOneUse() || 29280b57cec5SDimitry Andric !isOpcWithIntImmediate(And.getNode(), ISD::AND, MaskImm)) 29290b57cec5SDimitry Andric return false; 29300b57cec5SDimitry Andric 29310b57cec5SDimitry Andric // Compute the Known Zero for the AND as this allows us to catch more general 29320b57cec5SDimitry Andric // cases than just looking for AND with imm. 29330b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(And); 29340b57cec5SDimitry Andric 29350b57cec5SDimitry Andric // Non-zero in the sense that they're not provably zero, which is the key 29360b57cec5SDimitry Andric // point if we want to use this value. 29370b57cec5SDimitry Andric uint64_t NotKnownZero = (~Known.Zero).getZExtValue(); 29380b57cec5SDimitry Andric 29390b57cec5SDimitry Andric // The KnownZero mask must be a shifted mask (e.g., 1110..011, 11100..00). 29400b57cec5SDimitry Andric if (!isShiftedMask(Known.Zero.getZExtValue(), VT)) 29410b57cec5SDimitry Andric return false; 29420b57cec5SDimitry Andric 29430b57cec5SDimitry Andric // The bits being inserted must only set those bits that are known to be zero. 29440b57cec5SDimitry Andric if ((OrImm & NotKnownZero) != 0) { 29450b57cec5SDimitry Andric // FIXME: It's okay if the OrImm sets NotKnownZero bits to 1, but we don't 29460b57cec5SDimitry Andric // currently handle this case. 29470b57cec5SDimitry Andric return false; 29480b57cec5SDimitry Andric } 29490b57cec5SDimitry Andric 29500b57cec5SDimitry Andric // BFI/BFXIL dst, src, #lsb, #width. 29510b57cec5SDimitry Andric int LSB = countTrailingOnes(NotKnownZero); 29520b57cec5SDimitry Andric int Width = BitWidth - APInt(BitWidth, NotKnownZero).countPopulation(); 29530b57cec5SDimitry Andric 29540b57cec5SDimitry Andric // BFI/BFXIL is an alias of BFM, so translate to BFM operands. 29550b57cec5SDimitry Andric unsigned ImmR = (BitWidth - LSB) % BitWidth; 29560b57cec5SDimitry Andric unsigned ImmS = Width - 1; 29570b57cec5SDimitry Andric 29580b57cec5SDimitry Andric // If we're creating a BFI instruction avoid cases where we need more 29590b57cec5SDimitry Andric // instructions to materialize the BFI constant as compared to the original 29600b57cec5SDimitry Andric // ORR. A BFXIL will use the same constant as the original ORR, so the code 29610b57cec5SDimitry Andric // should be no worse in this case. 29620b57cec5SDimitry Andric bool IsBFI = LSB != 0; 29630b57cec5SDimitry Andric uint64_t BFIImm = OrImm >> LSB; 29640b57cec5SDimitry Andric if (IsBFI && !AArch64_AM::isLogicalImmediate(BFIImm, BitWidth)) { 29650b57cec5SDimitry Andric // We have a BFI instruction and we know the constant can't be materialized 29660b57cec5SDimitry Andric // with a ORR-immediate with the zero register. 29670b57cec5SDimitry Andric unsigned OrChunks = 0, BFIChunks = 0; 29680b57cec5SDimitry Andric for (unsigned Shift = 0; Shift < BitWidth; Shift += 16) { 29690b57cec5SDimitry Andric if (((OrImm >> Shift) & 0xFFFF) != 0) 29700b57cec5SDimitry Andric ++OrChunks; 29710b57cec5SDimitry Andric if (((BFIImm >> Shift) & 0xFFFF) != 0) 29720b57cec5SDimitry Andric ++BFIChunks; 29730b57cec5SDimitry Andric } 29740b57cec5SDimitry Andric if (BFIChunks > OrChunks) 29750b57cec5SDimitry Andric return false; 29760b57cec5SDimitry Andric } 29770b57cec5SDimitry Andric 29780b57cec5SDimitry Andric // Materialize the constant to be inserted. 29790b57cec5SDimitry Andric SDLoc DL(N); 29800b57cec5SDimitry Andric unsigned MOVIOpc = VT == MVT::i32 ? AArch64::MOVi32imm : AArch64::MOVi64imm; 29810b57cec5SDimitry Andric SDNode *MOVI = CurDAG->getMachineNode( 29820b57cec5SDimitry Andric MOVIOpc, DL, VT, CurDAG->getTargetConstant(BFIImm, DL, VT)); 29830b57cec5SDimitry Andric 29840b57cec5SDimitry Andric // Create the BFI/BFXIL instruction. 29850b57cec5SDimitry Andric SDValue Ops[] = {And.getOperand(0), SDValue(MOVI, 0), 29860b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmR, DL, VT), 29870b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 29880b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 29890b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 29900b57cec5SDimitry Andric return true; 29910b57cec5SDimitry Andric } 29920b57cec5SDimitry Andric 2993*bdd1243dSDimitry Andric static bool isWorthFoldingIntoOrrWithShift(SDValue Dst, SelectionDAG *CurDAG, 2994*bdd1243dSDimitry Andric SDValue &ShiftedOperand, 2995*bdd1243dSDimitry Andric uint64_t &EncodedShiftImm) { 2996*bdd1243dSDimitry Andric // Avoid folding Dst into ORR-with-shift if Dst has other uses than ORR. 2997*bdd1243dSDimitry Andric if (!Dst.hasOneUse()) 2998*bdd1243dSDimitry Andric return false; 2999*bdd1243dSDimitry Andric 3000*bdd1243dSDimitry Andric EVT VT = Dst.getValueType(); 3001*bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3002*bdd1243dSDimitry Andric "Caller should guarantee that VT is one of i32 or i64"); 3003*bdd1243dSDimitry Andric const unsigned SizeInBits = VT.getSizeInBits(); 3004*bdd1243dSDimitry Andric 3005*bdd1243dSDimitry Andric SDLoc DL(Dst.getNode()); 3006*bdd1243dSDimitry Andric uint64_t AndImm, ShlImm; 3007*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::AND, AndImm) && 3008*bdd1243dSDimitry Andric isShiftedMask_64(AndImm)) { 3009*bdd1243dSDimitry Andric // Avoid transforming 'DstOp0' if it has other uses than the AND node. 3010*bdd1243dSDimitry Andric SDValue DstOp0 = Dst.getOperand(0); 3011*bdd1243dSDimitry Andric if (!DstOp0.hasOneUse()) 3012*bdd1243dSDimitry Andric return false; 3013*bdd1243dSDimitry Andric 3014*bdd1243dSDimitry Andric // An example to illustrate the transformation 3015*bdd1243dSDimitry Andric // From: 3016*bdd1243dSDimitry Andric // lsr x8, x1, #1 3017*bdd1243dSDimitry Andric // and x8, x8, #0x3f80 3018*bdd1243dSDimitry Andric // bfxil x8, x1, #0, #7 3019*bdd1243dSDimitry Andric // To: 3020*bdd1243dSDimitry Andric // and x8, x23, #0x7f 3021*bdd1243dSDimitry Andric // ubfx x9, x23, #8, #7 3022*bdd1243dSDimitry Andric // orr x23, x8, x9, lsl #7 3023*bdd1243dSDimitry Andric // 3024*bdd1243dSDimitry Andric // The number of instructions remains the same, but ORR is faster than BFXIL 3025*bdd1243dSDimitry Andric // on many AArch64 processors (or as good as BFXIL if not faster). Besides, 3026*bdd1243dSDimitry Andric // the dependency chain is improved after the transformation. 3027*bdd1243dSDimitry Andric uint64_t SrlImm; 3028*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(DstOp0.getNode(), ISD::SRL, SrlImm)) { 3029*bdd1243dSDimitry Andric uint64_t NumTrailingZeroInShiftedMask = countTrailingZeros(AndImm); 3030*bdd1243dSDimitry Andric if ((SrlImm + NumTrailingZeroInShiftedMask) < SizeInBits) { 3031*bdd1243dSDimitry Andric unsigned MaskWidth = 3032*bdd1243dSDimitry Andric countTrailingOnes(AndImm >> NumTrailingZeroInShiftedMask); 3033*bdd1243dSDimitry Andric unsigned UBFMOpc = 3034*bdd1243dSDimitry Andric (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 3035*bdd1243dSDimitry Andric SDNode *UBFMNode = CurDAG->getMachineNode( 3036*bdd1243dSDimitry Andric UBFMOpc, DL, VT, DstOp0.getOperand(0), 3037*bdd1243dSDimitry Andric CurDAG->getTargetConstant(SrlImm + NumTrailingZeroInShiftedMask, DL, 3038*bdd1243dSDimitry Andric VT), 3039*bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3040*bdd1243dSDimitry Andric SrlImm + NumTrailingZeroInShiftedMask + MaskWidth - 1, DL, VT)); 3041*bdd1243dSDimitry Andric ShiftedOperand = SDValue(UBFMNode, 0); 3042*bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm( 3043*bdd1243dSDimitry Andric AArch64_AM::LSL, NumTrailingZeroInShiftedMask); 3044*bdd1243dSDimitry Andric return true; 3045*bdd1243dSDimitry Andric } 3046*bdd1243dSDimitry Andric } 3047*bdd1243dSDimitry Andric return false; 3048*bdd1243dSDimitry Andric } 3049*bdd1243dSDimitry Andric 3050*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::SHL, ShlImm)) { 3051*bdd1243dSDimitry Andric ShiftedOperand = Dst.getOperand(0); 3052*bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm); 3053*bdd1243dSDimitry Andric return true; 3054*bdd1243dSDimitry Andric } 3055*bdd1243dSDimitry Andric 3056*bdd1243dSDimitry Andric uint64_t SrlImm; 3057*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(Dst.getNode(), ISD::SRL, SrlImm)) { 3058*bdd1243dSDimitry Andric ShiftedOperand = Dst.getOperand(0); 3059*bdd1243dSDimitry Andric EncodedShiftImm = AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm); 3060*bdd1243dSDimitry Andric return true; 3061*bdd1243dSDimitry Andric } 3062*bdd1243dSDimitry Andric return false; 3063*bdd1243dSDimitry Andric } 3064*bdd1243dSDimitry Andric 3065*bdd1243dSDimitry Andric // Given an 'ISD::OR' node that is going to be selected as BFM, analyze 3066*bdd1243dSDimitry Andric // the operands and select it to AArch64::ORR with shifted registers if 3067*bdd1243dSDimitry Andric // that's more efficient. Returns true iff selection to AArch64::ORR happens. 3068*bdd1243dSDimitry Andric static bool tryOrrWithShift(SDNode *N, SDValue OrOpd0, SDValue OrOpd1, 3069*bdd1243dSDimitry Andric SDValue Src, SDValue Dst, SelectionDAG *CurDAG, 3070*bdd1243dSDimitry Andric const bool BiggerPattern) { 3071*bdd1243dSDimitry Andric EVT VT = N->getValueType(0); 3072*bdd1243dSDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect N to be an OR node"); 3073*bdd1243dSDimitry Andric assert(((N->getOperand(0) == OrOpd0 && N->getOperand(1) == OrOpd1) || 3074*bdd1243dSDimitry Andric (N->getOperand(1) == OrOpd0 && N->getOperand(0) == OrOpd1)) && 3075*bdd1243dSDimitry Andric "Expect OrOpd0 and OrOpd1 to be operands of ISD::OR"); 3076*bdd1243dSDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && 3077*bdd1243dSDimitry Andric "Expect result type to be i32 or i64 since N is combinable to BFM"); 3078*bdd1243dSDimitry Andric SDLoc DL(N); 3079*bdd1243dSDimitry Andric 3080*bdd1243dSDimitry Andric // Bail out if BFM simplifies away one node in BFM Dst. 3081*bdd1243dSDimitry Andric if (OrOpd1 != Dst) 3082*bdd1243dSDimitry Andric return false; 3083*bdd1243dSDimitry Andric 3084*bdd1243dSDimitry Andric const unsigned OrrOpc = (VT == MVT::i32) ? AArch64::ORRWrs : AArch64::ORRXrs; 3085*bdd1243dSDimitry Andric // For "BFM Rd, Rn, #immr, #imms", it's known that BFM simplifies away fewer 3086*bdd1243dSDimitry Andric // nodes from Rn (or inserts additional shift node) if BiggerPattern is true. 3087*bdd1243dSDimitry Andric if (BiggerPattern) { 3088*bdd1243dSDimitry Andric uint64_t SrcAndImm; 3089*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::AND, SrcAndImm) && 3090*bdd1243dSDimitry Andric isMask_64(SrcAndImm) && OrOpd0.getOperand(0) == Src) { 3091*bdd1243dSDimitry Andric // OrOpd0 = AND Src, #Mask 3092*bdd1243dSDimitry Andric // So BFM simplifies away one AND node from Src and doesn't simplify away 3093*bdd1243dSDimitry Andric // nodes from Dst. If ORR with left-shifted operand also simplifies away 3094*bdd1243dSDimitry Andric // one node (from Rd), ORR is better since it has higher throughput and 3095*bdd1243dSDimitry Andric // smaller latency than BFM on many AArch64 processors (and for the rest 3096*bdd1243dSDimitry Andric // ORR is at least as good as BFM). 3097*bdd1243dSDimitry Andric SDValue ShiftedOperand; 3098*bdd1243dSDimitry Andric uint64_t EncodedShiftImm; 3099*bdd1243dSDimitry Andric if (isWorthFoldingIntoOrrWithShift(Dst, CurDAG, ShiftedOperand, 3100*bdd1243dSDimitry Andric EncodedShiftImm)) { 3101*bdd1243dSDimitry Andric SDValue Ops[] = {OrOpd0, ShiftedOperand, 3102*bdd1243dSDimitry Andric CurDAG->getTargetConstant(EncodedShiftImm, DL, VT)}; 3103*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3104*bdd1243dSDimitry Andric return true; 3105*bdd1243dSDimitry Andric } 3106*bdd1243dSDimitry Andric } 3107*bdd1243dSDimitry Andric return false; 3108*bdd1243dSDimitry Andric } 3109*bdd1243dSDimitry Andric 3110*bdd1243dSDimitry Andric assert((!BiggerPattern) && "BiggerPattern should be handled above"); 3111*bdd1243dSDimitry Andric 3112*bdd1243dSDimitry Andric uint64_t ShlImm; 3113*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SHL, ShlImm)) { 3114*bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == Src && OrOpd0.hasOneUse()) { 3115*bdd1243dSDimitry Andric SDValue Ops[] = { 3116*bdd1243dSDimitry Andric Dst, Src, 3117*bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3118*bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm), DL, VT)}; 3119*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3120*bdd1243dSDimitry Andric return true; 3121*bdd1243dSDimitry Andric } 3122*bdd1243dSDimitry Andric 3123*bdd1243dSDimitry Andric // Select the following pattern to left-shifted operand rather than BFI. 3124*bdd1243dSDimitry Andric // %val1 = op .. 3125*bdd1243dSDimitry Andric // %val2 = shl %val1, #imm 3126*bdd1243dSDimitry Andric // %res = or %val1, %val2 3127*bdd1243dSDimitry Andric // 3128*bdd1243dSDimitry Andric // If N is selected to be BFI, we know that 3129*bdd1243dSDimitry Andric // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into 3130*bdd1243dSDimitry Andric // BFI) 2) OrOpd1 would be the destination operand (i.e., preserved) 3131*bdd1243dSDimitry Andric // 3132*bdd1243dSDimitry Andric // Instead of selecting N to BFI, fold OrOpd0 as a left shift directly. 3133*bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == OrOpd1) { 3134*bdd1243dSDimitry Andric SDValue Ops[] = { 3135*bdd1243dSDimitry Andric OrOpd1, OrOpd1, 3136*bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3137*bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSL, ShlImm), DL, VT)}; 3138*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3139*bdd1243dSDimitry Andric return true; 3140*bdd1243dSDimitry Andric } 3141*bdd1243dSDimitry Andric } 3142*bdd1243dSDimitry Andric 3143*bdd1243dSDimitry Andric uint64_t SrlImm; 3144*bdd1243dSDimitry Andric if (isOpcWithIntImmediate(OrOpd0.getNode(), ISD::SRL, SrlImm)) { 3145*bdd1243dSDimitry Andric // Select the following pattern to right-shifted operand rather than BFXIL. 3146*bdd1243dSDimitry Andric // %val1 = op .. 3147*bdd1243dSDimitry Andric // %val2 = lshr %val1, #imm 3148*bdd1243dSDimitry Andric // %res = or %val1, %val2 3149*bdd1243dSDimitry Andric // 3150*bdd1243dSDimitry Andric // If N is selected to be BFXIL, we know that 3151*bdd1243dSDimitry Andric // 1) OrOpd0 would be the operand from which extract bits (i.e., folded into 3152*bdd1243dSDimitry Andric // BFXIL) 2) OrOpd1 would be the destination operand (i.e., preserved) 3153*bdd1243dSDimitry Andric // 3154*bdd1243dSDimitry Andric // Instead of selecting N to BFXIL, fold OrOpd0 as a right shift directly. 3155*bdd1243dSDimitry Andric if (OrOpd0.getOperand(0) == OrOpd1) { 3156*bdd1243dSDimitry Andric SDValue Ops[] = { 3157*bdd1243dSDimitry Andric OrOpd1, OrOpd1, 3158*bdd1243dSDimitry Andric CurDAG->getTargetConstant( 3159*bdd1243dSDimitry Andric AArch64_AM::getShifterImm(AArch64_AM::LSR, SrlImm), DL, VT)}; 3160*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, OrrOpc, VT, Ops); 3161*bdd1243dSDimitry Andric return true; 3162*bdd1243dSDimitry Andric } 3163*bdd1243dSDimitry Andric } 3164*bdd1243dSDimitry Andric 3165*bdd1243dSDimitry Andric return false; 3166*bdd1243dSDimitry Andric } 3167*bdd1243dSDimitry Andric 31680b57cec5SDimitry Andric static bool tryBitfieldInsertOpFromOr(SDNode *N, const APInt &UsefulBits, 31690b57cec5SDimitry Andric SelectionDAG *CurDAG) { 31700b57cec5SDimitry Andric assert(N->getOpcode() == ISD::OR && "Expect a OR operation"); 31710b57cec5SDimitry Andric 31720b57cec5SDimitry Andric EVT VT = N->getValueType(0); 31730b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 31740b57cec5SDimitry Andric return false; 31750b57cec5SDimitry Andric 31760b57cec5SDimitry Andric unsigned BitWidth = VT.getSizeInBits(); 31770b57cec5SDimitry Andric 31780b57cec5SDimitry Andric // Because of simplify-demanded-bits in DAGCombine, involved masks may not 31790b57cec5SDimitry Andric // have the expected shape. Try to undo that. 31800b57cec5SDimitry Andric 31810b57cec5SDimitry Andric unsigned NumberOfIgnoredLowBits = UsefulBits.countTrailingZeros(); 31820b57cec5SDimitry Andric unsigned NumberOfIgnoredHighBits = UsefulBits.countLeadingZeros(); 31830b57cec5SDimitry Andric 31840b57cec5SDimitry Andric // Given a OR operation, check if we have the following pattern 31850b57cec5SDimitry Andric // ubfm c, b, imm, imm2 (or something that does the same jobs, see 31860b57cec5SDimitry Andric // isBitfieldExtractOp) 31870b57cec5SDimitry Andric // d = e & mask2 ; where mask is a binary sequence of 1..10..0 and 31880b57cec5SDimitry Andric // countTrailingZeros(mask2) == imm2 - imm + 1 31890b57cec5SDimitry Andric // f = d | c 31900b57cec5SDimitry Andric // if yes, replace the OR instruction with: 31910b57cec5SDimitry Andric // f = BFM Opd0, Opd1, LSB, MSB ; where LSB = imm, and MSB = imm2 31920b57cec5SDimitry Andric 31930b57cec5SDimitry Andric // OR is commutative, check all combinations of operand order and values of 31940b57cec5SDimitry Andric // BiggerPattern, i.e. 31950b57cec5SDimitry Andric // Opd0, Opd1, BiggerPattern=false 31960b57cec5SDimitry Andric // Opd1, Opd0, BiggerPattern=false 31970b57cec5SDimitry Andric // Opd0, Opd1, BiggerPattern=true 31980b57cec5SDimitry Andric // Opd1, Opd0, BiggerPattern=true 31990b57cec5SDimitry Andric // Several of these combinations may match, so check with BiggerPattern=false 32000b57cec5SDimitry Andric // first since that will produce better results by matching more instructions 32010b57cec5SDimitry Andric // and/or inserting fewer extra instructions. 32020b57cec5SDimitry Andric for (int I = 0; I < 4; ++I) { 32030b57cec5SDimitry Andric 32040b57cec5SDimitry Andric SDValue Dst, Src; 32050b57cec5SDimitry Andric unsigned ImmR, ImmS; 32060b57cec5SDimitry Andric bool BiggerPattern = I / 2; 32070b57cec5SDimitry Andric SDValue OrOpd0Val = N->getOperand(I % 2); 32080b57cec5SDimitry Andric SDNode *OrOpd0 = OrOpd0Val.getNode(); 32090b57cec5SDimitry Andric SDValue OrOpd1Val = N->getOperand((I + 1) % 2); 32100b57cec5SDimitry Andric SDNode *OrOpd1 = OrOpd1Val.getNode(); 32110b57cec5SDimitry Andric 32120b57cec5SDimitry Andric unsigned BFXOpc; 32130b57cec5SDimitry Andric int DstLSB, Width; 32140b57cec5SDimitry Andric if (isBitfieldExtractOp(CurDAG, OrOpd0, BFXOpc, Src, ImmR, ImmS, 32150b57cec5SDimitry Andric NumberOfIgnoredLowBits, BiggerPattern)) { 32160b57cec5SDimitry Andric // Check that the returned opcode is compatible with the pattern, 32170b57cec5SDimitry Andric // i.e., same type and zero extended (U and not S) 32180b57cec5SDimitry Andric if ((BFXOpc != AArch64::UBFMXri && VT == MVT::i64) || 32190b57cec5SDimitry Andric (BFXOpc != AArch64::UBFMWri && VT == MVT::i32)) 32200b57cec5SDimitry Andric continue; 32210b57cec5SDimitry Andric 32220b57cec5SDimitry Andric // Compute the width of the bitfield insertion 32230b57cec5SDimitry Andric DstLSB = 0; 32240b57cec5SDimitry Andric Width = ImmS - ImmR + 1; 32250b57cec5SDimitry Andric // FIXME: This constraint is to catch bitfield insertion we may 32260b57cec5SDimitry Andric // want to widen the pattern if we want to grab general bitfied 32270b57cec5SDimitry Andric // move case 32280b57cec5SDimitry Andric if (Width <= 0) 32290b57cec5SDimitry Andric continue; 32300b57cec5SDimitry Andric 32310b57cec5SDimitry Andric // If the mask on the insertee is correct, we have a BFXIL operation. We 32320b57cec5SDimitry Andric // can share the ImmR and ImmS values from the already-computed UBFM. 32330b57cec5SDimitry Andric } else if (isBitfieldPositioningOp(CurDAG, OrOpd0Val, 32340b57cec5SDimitry Andric BiggerPattern, 32350b57cec5SDimitry Andric Src, DstLSB, Width)) { 32360b57cec5SDimitry Andric ImmR = (BitWidth - DstLSB) % BitWidth; 32370b57cec5SDimitry Andric ImmS = Width - 1; 32380b57cec5SDimitry Andric } else 32390b57cec5SDimitry Andric continue; 32400b57cec5SDimitry Andric 32410b57cec5SDimitry Andric // Check the second part of the pattern 32420b57cec5SDimitry Andric EVT VT = OrOpd1Val.getValueType(); 32430b57cec5SDimitry Andric assert((VT == MVT::i32 || VT == MVT::i64) && "unexpected OR operand"); 32440b57cec5SDimitry Andric 32450b57cec5SDimitry Andric // Compute the Known Zero for the candidate of the first operand. 32460b57cec5SDimitry Andric // This allows to catch more general case than just looking for 32470b57cec5SDimitry Andric // AND with imm. Indeed, simplify-demanded-bits may have removed 32480b57cec5SDimitry Andric // the AND instruction because it proves it was useless. 32490b57cec5SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(OrOpd1Val); 32500b57cec5SDimitry Andric 32510b57cec5SDimitry Andric // Check if there is enough room for the second operand to appear 32520b57cec5SDimitry Andric // in the first one 32530b57cec5SDimitry Andric APInt BitsToBeInserted = 32540b57cec5SDimitry Andric APInt::getBitsSet(Known.getBitWidth(), DstLSB, DstLSB + Width); 32550b57cec5SDimitry Andric 32560b57cec5SDimitry Andric if ((BitsToBeInserted & ~Known.Zero) != 0) 32570b57cec5SDimitry Andric continue; 32580b57cec5SDimitry Andric 32590b57cec5SDimitry Andric // Set the first operand 32600b57cec5SDimitry Andric uint64_t Imm; 32610b57cec5SDimitry Andric if (isOpcWithIntImmediate(OrOpd1, ISD::AND, Imm) && 32620b57cec5SDimitry Andric isBitfieldDstMask(Imm, BitsToBeInserted, NumberOfIgnoredHighBits, VT)) 32630b57cec5SDimitry Andric // In that case, we can eliminate the AND 32640b57cec5SDimitry Andric Dst = OrOpd1->getOperand(0); 32650b57cec5SDimitry Andric else 32660b57cec5SDimitry Andric // Maybe the AND has been removed by simplify-demanded-bits 32670b57cec5SDimitry Andric // or is useful because it discards more bits 32680b57cec5SDimitry Andric Dst = OrOpd1Val; 32690b57cec5SDimitry Andric 3270*bdd1243dSDimitry Andric // Before selecting ISD::OR node to AArch64::BFM, see if an AArch64::ORR 3271*bdd1243dSDimitry Andric // with shifted operand is more efficient. 3272*bdd1243dSDimitry Andric if (tryOrrWithShift(N, OrOpd0Val, OrOpd1Val, Src, Dst, CurDAG, 3273*bdd1243dSDimitry Andric BiggerPattern)) 3274*bdd1243dSDimitry Andric return true; 3275*bdd1243dSDimitry Andric 32760b57cec5SDimitry Andric // both parts match 32770b57cec5SDimitry Andric SDLoc DL(N); 32780b57cec5SDimitry Andric SDValue Ops[] = {Dst, Src, CurDAG->getTargetConstant(ImmR, DL, VT), 32790b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 32800b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 32810b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 32820b57cec5SDimitry Andric return true; 32830b57cec5SDimitry Andric } 32840b57cec5SDimitry Andric 32850b57cec5SDimitry Andric // Generate a BFXIL from 'or (and X, Mask0Imm), (and Y, Mask1Imm)' iff 32860b57cec5SDimitry Andric // Mask0Imm and ~Mask1Imm are equivalent and one of the MaskImms is a shifted 32870b57cec5SDimitry Andric // mask (e.g., 0x000ffff0). 32880b57cec5SDimitry Andric uint64_t Mask0Imm, Mask1Imm; 32890b57cec5SDimitry Andric SDValue And0 = N->getOperand(0); 32900b57cec5SDimitry Andric SDValue And1 = N->getOperand(1); 32910b57cec5SDimitry Andric if (And0.hasOneUse() && And1.hasOneUse() && 32920b57cec5SDimitry Andric isOpcWithIntImmediate(And0.getNode(), ISD::AND, Mask0Imm) && 32930b57cec5SDimitry Andric isOpcWithIntImmediate(And1.getNode(), ISD::AND, Mask1Imm) && 32940b57cec5SDimitry Andric APInt(BitWidth, Mask0Imm) == ~APInt(BitWidth, Mask1Imm) && 32950b57cec5SDimitry Andric (isShiftedMask(Mask0Imm, VT) || isShiftedMask(Mask1Imm, VT))) { 32960b57cec5SDimitry Andric 32970b57cec5SDimitry Andric // ORR is commutative, so canonicalize to the form 'or (and X, Mask0Imm), 32980b57cec5SDimitry Andric // (and Y, Mask1Imm)' where Mask1Imm is the shifted mask masking off the 32990b57cec5SDimitry Andric // bits to be inserted. 33000b57cec5SDimitry Andric if (isShiftedMask(Mask0Imm, VT)) { 33010b57cec5SDimitry Andric std::swap(And0, And1); 33020b57cec5SDimitry Andric std::swap(Mask0Imm, Mask1Imm); 33030b57cec5SDimitry Andric } 33040b57cec5SDimitry Andric 33050b57cec5SDimitry Andric SDValue Src = And1->getOperand(0); 33060b57cec5SDimitry Andric SDValue Dst = And0->getOperand(0); 33070b57cec5SDimitry Andric unsigned LSB = countTrailingZeros(Mask1Imm); 33080b57cec5SDimitry Andric int Width = BitWidth - APInt(BitWidth, Mask0Imm).countPopulation(); 33090b57cec5SDimitry Andric 33100b57cec5SDimitry Andric // The BFXIL inserts the low-order bits from a source register, so right 33110b57cec5SDimitry Andric // shift the needed bits into place. 33120b57cec5SDimitry Andric SDLoc DL(N); 33130b57cec5SDimitry Andric unsigned ShiftOpc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 331481ad6265SDimitry Andric uint64_t LsrImm = LSB; 331581ad6265SDimitry Andric if (Src->hasOneUse() && 331681ad6265SDimitry Andric isOpcWithIntImmediate(Src.getNode(), ISD::SRL, LsrImm) && 331781ad6265SDimitry Andric (LsrImm + LSB) < BitWidth) { 331881ad6265SDimitry Andric Src = Src->getOperand(0); 331981ad6265SDimitry Andric LsrImm += LSB; 332081ad6265SDimitry Andric } 332181ad6265SDimitry Andric 33220b57cec5SDimitry Andric SDNode *LSR = CurDAG->getMachineNode( 332381ad6265SDimitry Andric ShiftOpc, DL, VT, Src, CurDAG->getTargetConstant(LsrImm, DL, VT), 33240b57cec5SDimitry Andric CurDAG->getTargetConstant(BitWidth - 1, DL, VT)); 33250b57cec5SDimitry Andric 33260b57cec5SDimitry Andric // BFXIL is an alias of BFM, so translate to BFM operands. 33270b57cec5SDimitry Andric unsigned ImmR = (BitWidth - LSB) % BitWidth; 33280b57cec5SDimitry Andric unsigned ImmS = Width - 1; 33290b57cec5SDimitry Andric 33300b57cec5SDimitry Andric // Create the BFXIL instruction. 33310b57cec5SDimitry Andric SDValue Ops[] = {Dst, SDValue(LSR, 0), 33320b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmR, DL, VT), 33330b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 33340b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri; 33350b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 33360b57cec5SDimitry Andric return true; 33370b57cec5SDimitry Andric } 33380b57cec5SDimitry Andric 33390b57cec5SDimitry Andric return false; 33400b57cec5SDimitry Andric } 33410b57cec5SDimitry Andric 33420b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) { 33430b57cec5SDimitry Andric if (N->getOpcode() != ISD::OR) 33440b57cec5SDimitry Andric return false; 33450b57cec5SDimitry Andric 33460b57cec5SDimitry Andric APInt NUsefulBits; 33470b57cec5SDimitry Andric getUsefulBits(SDValue(N, 0), NUsefulBits); 33480b57cec5SDimitry Andric 33490b57cec5SDimitry Andric // If all bits are not useful, just return UNDEF. 33500b57cec5SDimitry Andric if (!NUsefulBits) { 33510b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); 33520b57cec5SDimitry Andric return true; 33530b57cec5SDimitry Andric } 33540b57cec5SDimitry Andric 33550b57cec5SDimitry Andric if (tryBitfieldInsertOpFromOr(N, NUsefulBits, CurDAG)) 33560b57cec5SDimitry Andric return true; 33570b57cec5SDimitry Andric 33580b57cec5SDimitry Andric return tryBitfieldInsertOpFromOrAndImm(N, CurDAG); 33590b57cec5SDimitry Andric } 33600b57cec5SDimitry Andric 33610b57cec5SDimitry Andric /// SelectBitfieldInsertInZeroOp - Match a UBFIZ instruction that is the 33620b57cec5SDimitry Andric /// equivalent of a left shift by a constant amount followed by an and masking 33630b57cec5SDimitry Andric /// out a contiguous set of bits. 33640b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryBitfieldInsertInZeroOp(SDNode *N) { 33650b57cec5SDimitry Andric if (N->getOpcode() != ISD::AND) 33660b57cec5SDimitry Andric return false; 33670b57cec5SDimitry Andric 33680b57cec5SDimitry Andric EVT VT = N->getValueType(0); 33690b57cec5SDimitry Andric if (VT != MVT::i32 && VT != MVT::i64) 33700b57cec5SDimitry Andric return false; 33710b57cec5SDimitry Andric 33720b57cec5SDimitry Andric SDValue Op0; 33730b57cec5SDimitry Andric int DstLSB, Width; 33740b57cec5SDimitry Andric if (!isBitfieldPositioningOp(CurDAG, SDValue(N, 0), /*BiggerPattern=*/false, 33750b57cec5SDimitry Andric Op0, DstLSB, Width)) 33760b57cec5SDimitry Andric return false; 33770b57cec5SDimitry Andric 33780b57cec5SDimitry Andric // ImmR is the rotate right amount. 33790b57cec5SDimitry Andric unsigned ImmR = (VT.getSizeInBits() - DstLSB) % VT.getSizeInBits(); 33800b57cec5SDimitry Andric // ImmS is the most significant bit of the source to be moved. 33810b57cec5SDimitry Andric unsigned ImmS = Width - 1; 33820b57cec5SDimitry Andric 33830b57cec5SDimitry Andric SDLoc DL(N); 33840b57cec5SDimitry Andric SDValue Ops[] = {Op0, CurDAG->getTargetConstant(ImmR, DL, VT), 33850b57cec5SDimitry Andric CurDAG->getTargetConstant(ImmS, DL, VT)}; 33860b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i32) ? AArch64::UBFMWri : AArch64::UBFMXri; 33870b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 33880b57cec5SDimitry Andric return true; 33890b57cec5SDimitry Andric } 33900b57cec5SDimitry Andric 33910b57cec5SDimitry Andric /// tryShiftAmountMod - Take advantage of built-in mod of shift amount in 33920b57cec5SDimitry Andric /// variable shift/rotate instructions. 33930b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryShiftAmountMod(SDNode *N) { 33940b57cec5SDimitry Andric EVT VT = N->getValueType(0); 33950b57cec5SDimitry Andric 33960b57cec5SDimitry Andric unsigned Opc; 33970b57cec5SDimitry Andric switch (N->getOpcode()) { 33980b57cec5SDimitry Andric case ISD::ROTR: 33990b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::RORVWr : AArch64::RORVXr; 34000b57cec5SDimitry Andric break; 34010b57cec5SDimitry Andric case ISD::SHL: 34020b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::LSLVWr : AArch64::LSLVXr; 34030b57cec5SDimitry Andric break; 34040b57cec5SDimitry Andric case ISD::SRL: 34050b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::LSRVWr : AArch64::LSRVXr; 34060b57cec5SDimitry Andric break; 34070b57cec5SDimitry Andric case ISD::SRA: 34080b57cec5SDimitry Andric Opc = (VT == MVT::i32) ? AArch64::ASRVWr : AArch64::ASRVXr; 34090b57cec5SDimitry Andric break; 34100b57cec5SDimitry Andric default: 34110b57cec5SDimitry Andric return false; 34120b57cec5SDimitry Andric } 34130b57cec5SDimitry Andric 34140b57cec5SDimitry Andric uint64_t Size; 34150b57cec5SDimitry Andric uint64_t Bits; 34160b57cec5SDimitry Andric if (VT == MVT::i32) { 34170b57cec5SDimitry Andric Bits = 5; 34180b57cec5SDimitry Andric Size = 32; 34190b57cec5SDimitry Andric } else if (VT == MVT::i64) { 34200b57cec5SDimitry Andric Bits = 6; 34210b57cec5SDimitry Andric Size = 64; 34220b57cec5SDimitry Andric } else 34230b57cec5SDimitry Andric return false; 34240b57cec5SDimitry Andric 34250b57cec5SDimitry Andric SDValue ShiftAmt = N->getOperand(1); 34260b57cec5SDimitry Andric SDLoc DL(N); 34270b57cec5SDimitry Andric SDValue NewShiftAmt; 34280b57cec5SDimitry Andric 34290b57cec5SDimitry Andric // Skip over an extend of the shift amount. 34300b57cec5SDimitry Andric if (ShiftAmt->getOpcode() == ISD::ZERO_EXTEND || 34310b57cec5SDimitry Andric ShiftAmt->getOpcode() == ISD::ANY_EXTEND) 34320b57cec5SDimitry Andric ShiftAmt = ShiftAmt->getOperand(0); 34330b57cec5SDimitry Andric 34340b57cec5SDimitry Andric if (ShiftAmt->getOpcode() == ISD::ADD || ShiftAmt->getOpcode() == ISD::SUB) { 34350b57cec5SDimitry Andric SDValue Add0 = ShiftAmt->getOperand(0); 34360b57cec5SDimitry Andric SDValue Add1 = ShiftAmt->getOperand(1); 34370b57cec5SDimitry Andric uint64_t Add0Imm; 34380b57cec5SDimitry Andric uint64_t Add1Imm; 343981ad6265SDimitry Andric if (isIntImmediate(Add1, Add1Imm) && (Add1Imm % Size == 0)) { 34400b57cec5SDimitry Andric // If we are shifting by X+/-N where N == 0 mod Size, then just shift by X 34410b57cec5SDimitry Andric // to avoid the ADD/SUB. 34420b57cec5SDimitry Andric NewShiftAmt = Add0; 344381ad6265SDimitry Andric } else if (ShiftAmt->getOpcode() == ISD::SUB && 34440b57cec5SDimitry Andric isIntImmediate(Add0, Add0Imm) && Add0Imm != 0 && 34450b57cec5SDimitry Andric (Add0Imm % Size == 0)) { 344681ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X 344781ad6265SDimitry Andric // to generate a NEG instead of a SUB from a constant. 34480b57cec5SDimitry Andric unsigned NegOpc; 34490b57cec5SDimitry Andric unsigned ZeroReg; 34500b57cec5SDimitry Andric EVT SubVT = ShiftAmt->getValueType(0); 34510b57cec5SDimitry Andric if (SubVT == MVT::i32) { 34520b57cec5SDimitry Andric NegOpc = AArch64::SUBWrr; 34530b57cec5SDimitry Andric ZeroReg = AArch64::WZR; 34540b57cec5SDimitry Andric } else { 34550b57cec5SDimitry Andric assert(SubVT == MVT::i64); 34560b57cec5SDimitry Andric NegOpc = AArch64::SUBXrr; 34570b57cec5SDimitry Andric ZeroReg = AArch64::XZR; 34580b57cec5SDimitry Andric } 34590b57cec5SDimitry Andric SDValue Zero = 34600b57cec5SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT); 34610b57cec5SDimitry Andric MachineSDNode *Neg = 34620b57cec5SDimitry Andric CurDAG->getMachineNode(NegOpc, DL, SubVT, Zero, Add1); 34630b57cec5SDimitry Andric NewShiftAmt = SDValue(Neg, 0); 346481ad6265SDimitry Andric } else if (ShiftAmt->getOpcode() == ISD::SUB && 346581ad6265SDimitry Andric isIntImmediate(Add0, Add0Imm) && (Add0Imm % Size == Size - 1)) { 346681ad6265SDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 346781ad6265SDimitry Andric // to generate a NOT instead of a SUB from a constant. 346881ad6265SDimitry Andric unsigned NotOpc; 346981ad6265SDimitry Andric unsigned ZeroReg; 347081ad6265SDimitry Andric EVT SubVT = ShiftAmt->getValueType(0); 347181ad6265SDimitry Andric if (SubVT == MVT::i32) { 347281ad6265SDimitry Andric NotOpc = AArch64::ORNWrr; 347381ad6265SDimitry Andric ZeroReg = AArch64::WZR; 347481ad6265SDimitry Andric } else { 347581ad6265SDimitry Andric assert(SubVT == MVT::i64); 347681ad6265SDimitry Andric NotOpc = AArch64::ORNXrr; 347781ad6265SDimitry Andric ZeroReg = AArch64::XZR; 347881ad6265SDimitry Andric } 347981ad6265SDimitry Andric SDValue Zero = 348081ad6265SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, ZeroReg, SubVT); 348181ad6265SDimitry Andric MachineSDNode *Not = 348281ad6265SDimitry Andric CurDAG->getMachineNode(NotOpc, DL, SubVT, Zero, Add1); 348381ad6265SDimitry Andric NewShiftAmt = SDValue(Not, 0); 34840b57cec5SDimitry Andric } else 34850b57cec5SDimitry Andric return false; 34860b57cec5SDimitry Andric } else { 34870b57cec5SDimitry Andric // If the shift amount is masked with an AND, check that the mask covers the 34880b57cec5SDimitry Andric // bits that are implicitly ANDed off by the above opcodes and if so, skip 34890b57cec5SDimitry Andric // the AND. 34900b57cec5SDimitry Andric uint64_t MaskImm; 34915ffd83dbSDimitry Andric if (!isOpcWithIntImmediate(ShiftAmt.getNode(), ISD::AND, MaskImm) && 34925ffd83dbSDimitry Andric !isOpcWithIntImmediate(ShiftAmt.getNode(), AArch64ISD::ANDS, MaskImm)) 34930b57cec5SDimitry Andric return false; 34940b57cec5SDimitry Andric 34950b57cec5SDimitry Andric if (countTrailingOnes(MaskImm) < Bits) 34960b57cec5SDimitry Andric return false; 34970b57cec5SDimitry Andric 34980b57cec5SDimitry Andric NewShiftAmt = ShiftAmt->getOperand(0); 34990b57cec5SDimitry Andric } 35000b57cec5SDimitry Andric 35010b57cec5SDimitry Andric // Narrow/widen the shift amount to match the size of the shift operation. 35020b57cec5SDimitry Andric if (VT == MVT::i32) 35030b57cec5SDimitry Andric NewShiftAmt = narrowIfNeeded(CurDAG, NewShiftAmt); 35040b57cec5SDimitry Andric else if (VT == MVT::i64 && NewShiftAmt->getValueType(0) == MVT::i32) { 35050b57cec5SDimitry Andric SDValue SubReg = CurDAG->getTargetConstant(AArch64::sub_32, DL, MVT::i32); 35060b57cec5SDimitry Andric MachineSDNode *Ext = CurDAG->getMachineNode( 35070b57cec5SDimitry Andric AArch64::SUBREG_TO_REG, DL, VT, 35080b57cec5SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i64), NewShiftAmt, SubReg); 35090b57cec5SDimitry Andric NewShiftAmt = SDValue(Ext, 0); 35100b57cec5SDimitry Andric } 35110b57cec5SDimitry Andric 35120b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(0), NewShiftAmt}; 35130b57cec5SDimitry Andric CurDAG->SelectNodeTo(N, Opc, VT, Ops); 35140b57cec5SDimitry Andric return true; 35150b57cec5SDimitry Andric } 35160b57cec5SDimitry Andric 35170b57cec5SDimitry Andric bool 35180b57cec5SDimitry Andric AArch64DAGToDAGISel::SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, 35190b57cec5SDimitry Andric unsigned RegWidth) { 35200b57cec5SDimitry Andric APFloat FVal(0.0); 35210b57cec5SDimitry Andric if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N)) 35220b57cec5SDimitry Andric FVal = CN->getValueAPF(); 35230b57cec5SDimitry Andric else if (LoadSDNode *LN = dyn_cast<LoadSDNode>(N)) { 35240b57cec5SDimitry Andric // Some otherwise illegal constants are allowed in this case. 35250b57cec5SDimitry Andric if (LN->getOperand(1).getOpcode() != AArch64ISD::ADDlow || 35260b57cec5SDimitry Andric !isa<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1))) 35270b57cec5SDimitry Andric return false; 35280b57cec5SDimitry Andric 35290b57cec5SDimitry Andric ConstantPoolSDNode *CN = 35300b57cec5SDimitry Andric dyn_cast<ConstantPoolSDNode>(LN->getOperand(1)->getOperand(1)); 35310b57cec5SDimitry Andric FVal = cast<ConstantFP>(CN->getConstVal())->getValueAPF(); 35320b57cec5SDimitry Andric } else 35330b57cec5SDimitry Andric return false; 35340b57cec5SDimitry Andric 35350b57cec5SDimitry Andric // An FCVT[SU] instruction performs: convertToInt(Val * 2^fbits) where fbits 35360b57cec5SDimitry Andric // is between 1 and 32 for a destination w-register, or 1 and 64 for an 35370b57cec5SDimitry Andric // x-register. 35380b57cec5SDimitry Andric // 35390b57cec5SDimitry Andric // By this stage, we've detected (fp_to_[su]int (fmul Val, THIS_NODE)) so we 35400b57cec5SDimitry Andric // want THIS_NODE to be 2^fbits. This is much easier to deal with using 35410b57cec5SDimitry Andric // integers. 35420b57cec5SDimitry Andric bool IsExact; 35430b57cec5SDimitry Andric 35440b57cec5SDimitry Andric // fbits is between 1 and 64 in the worst-case, which means the fmul 35450b57cec5SDimitry Andric // could have 2^64 as an actual operand. Need 65 bits of precision. 35460b57cec5SDimitry Andric APSInt IntVal(65, true); 35470b57cec5SDimitry Andric FVal.convertToInteger(IntVal, APFloat::rmTowardZero, &IsExact); 35480b57cec5SDimitry Andric 35490b57cec5SDimitry Andric // N.b. isPowerOf2 also checks for > 0. 35500b57cec5SDimitry Andric if (!IsExact || !IntVal.isPowerOf2()) return false; 35510b57cec5SDimitry Andric unsigned FBits = IntVal.logBase2(); 35520b57cec5SDimitry Andric 35530b57cec5SDimitry Andric // Checks above should have guaranteed that we haven't lost information in 35540b57cec5SDimitry Andric // finding FBits, but it must still be in range. 35550b57cec5SDimitry Andric if (FBits == 0 || FBits > RegWidth) return false; 35560b57cec5SDimitry Andric 35570b57cec5SDimitry Andric FixedPos = CurDAG->getTargetConstant(FBits, SDLoc(N), MVT::i32); 35580b57cec5SDimitry Andric return true; 35590b57cec5SDimitry Andric } 35600b57cec5SDimitry Andric 35610b57cec5SDimitry Andric // Inspects a register string of the form o0:op1:CRn:CRm:op2 gets the fields 35620b57cec5SDimitry Andric // of the string and obtains the integer values from them and combines these 35630b57cec5SDimitry Andric // into a single value to be used in the MRS/MSR instruction. 35640b57cec5SDimitry Andric static int getIntOperandFromRegisterString(StringRef RegString) { 35650b57cec5SDimitry Andric SmallVector<StringRef, 5> Fields; 35660b57cec5SDimitry Andric RegString.split(Fields, ':'); 35670b57cec5SDimitry Andric 35680b57cec5SDimitry Andric if (Fields.size() == 1) 35690b57cec5SDimitry Andric return -1; 35700b57cec5SDimitry Andric 35710b57cec5SDimitry Andric assert(Fields.size() == 5 35720b57cec5SDimitry Andric && "Invalid number of fields in read register string"); 35730b57cec5SDimitry Andric 35740b57cec5SDimitry Andric SmallVector<int, 5> Ops; 35750b57cec5SDimitry Andric bool AllIntFields = true; 35760b57cec5SDimitry Andric 35770b57cec5SDimitry Andric for (StringRef Field : Fields) { 35780b57cec5SDimitry Andric unsigned IntField; 35790b57cec5SDimitry Andric AllIntFields &= !Field.getAsInteger(10, IntField); 35800b57cec5SDimitry Andric Ops.push_back(IntField); 35810b57cec5SDimitry Andric } 35820b57cec5SDimitry Andric 35830b57cec5SDimitry Andric assert(AllIntFields && 35840b57cec5SDimitry Andric "Unexpected non-integer value in special register string."); 3585fe6060f1SDimitry Andric (void)AllIntFields; 35860b57cec5SDimitry Andric 35870b57cec5SDimitry Andric // Need to combine the integer fields of the string into a single value 35880b57cec5SDimitry Andric // based on the bit encoding of MRS/MSR instruction. 35890b57cec5SDimitry Andric return (Ops[0] << 14) | (Ops[1] << 11) | (Ops[2] << 7) | 35900b57cec5SDimitry Andric (Ops[3] << 3) | (Ops[4]); 35910b57cec5SDimitry Andric } 35920b57cec5SDimitry Andric 35930b57cec5SDimitry Andric // Lower the read_register intrinsic to an MRS instruction node if the special 35940b57cec5SDimitry Andric // register string argument is either of the form detailed in the ALCE (the 35950b57cec5SDimitry Andric // form described in getIntOperandsFromRegsterString) or is a named register 35960b57cec5SDimitry Andric // known by the MRS SysReg mapper. 35970b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryReadRegister(SDNode *N) { 3598349cc55cSDimitry Andric const auto *MD = cast<MDNodeSDNode>(N->getOperand(1)); 3599349cc55cSDimitry Andric const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0)); 36000b57cec5SDimitry Andric SDLoc DL(N); 36010b57cec5SDimitry Andric 3602*bdd1243dSDimitry Andric bool ReadIs128Bit = N->getOpcode() == AArch64ISD::MRRS; 36030b57cec5SDimitry Andric 3604*bdd1243dSDimitry Andric unsigned Opcode64Bit = AArch64::MRS; 3605*bdd1243dSDimitry Andric int Imm = getIntOperandFromRegisterString(RegString->getString()); 3606*bdd1243dSDimitry Andric if (Imm == -1) { 3607*bdd1243dSDimitry Andric // No match, Use the sysreg mapper to map the remaining possible strings to 3608*bdd1243dSDimitry Andric // the value for the register to be used for the instruction operand. 3609*bdd1243dSDimitry Andric const auto *TheReg = 3610*bdd1243dSDimitry Andric AArch64SysReg::lookupSysRegByName(RegString->getString()); 36110b57cec5SDimitry Andric if (TheReg && TheReg->Readable && 36120b57cec5SDimitry Andric TheReg->haveFeatures(Subtarget->getFeatureBits())) 3613*bdd1243dSDimitry Andric Imm = TheReg->Encoding; 36140b57cec5SDimitry Andric else 3615*bdd1243dSDimitry Andric Imm = AArch64SysReg::parseGenericRegister(RegString->getString()); 36160b57cec5SDimitry Andric 3617*bdd1243dSDimitry Andric if (Imm == -1) { 3618*bdd1243dSDimitry Andric // Still no match, see if this is "pc" or give up. 3619*bdd1243dSDimitry Andric if (!ReadIs128Bit && RegString->getString() == "pc") { 3620*bdd1243dSDimitry Andric Opcode64Bit = AArch64::ADR; 3621*bdd1243dSDimitry Andric Imm = 0; 3622*bdd1243dSDimitry Andric } else { 36230b57cec5SDimitry Andric return false; 36240b57cec5SDimitry Andric } 3625*bdd1243dSDimitry Andric } 3626*bdd1243dSDimitry Andric } 3627*bdd1243dSDimitry Andric 3628*bdd1243dSDimitry Andric SDValue InChain = N->getOperand(0); 3629*bdd1243dSDimitry Andric SDValue SysRegImm = CurDAG->getTargetConstant(Imm, DL, MVT::i32); 3630*bdd1243dSDimitry Andric if (!ReadIs128Bit) { 3631*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, Opcode64Bit, MVT::i64, MVT::Other /* Chain */, 3632*bdd1243dSDimitry Andric {SysRegImm, InChain}); 3633*bdd1243dSDimitry Andric } else { 3634*bdd1243dSDimitry Andric SDNode *MRRS = CurDAG->getMachineNode( 3635*bdd1243dSDimitry Andric AArch64::MRRS, DL, 3636*bdd1243dSDimitry Andric {MVT::Untyped /* XSeqPair */, MVT::Other /* Chain */}, 3637*bdd1243dSDimitry Andric {SysRegImm, InChain}); 3638*bdd1243dSDimitry Andric 3639*bdd1243dSDimitry Andric // Sysregs are not endian. The even register always contains the low half 3640*bdd1243dSDimitry Andric // of the register. 3641*bdd1243dSDimitry Andric SDValue Lo = CurDAG->getTargetExtractSubreg(AArch64::sube64, DL, MVT::i64, 3642*bdd1243dSDimitry Andric SDValue(MRRS, 0)); 3643*bdd1243dSDimitry Andric SDValue Hi = CurDAG->getTargetExtractSubreg(AArch64::subo64, DL, MVT::i64, 3644*bdd1243dSDimitry Andric SDValue(MRRS, 0)); 3645*bdd1243dSDimitry Andric SDValue OutChain = SDValue(MRRS, 1); 3646*bdd1243dSDimitry Andric 3647*bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 0), Lo); 3648*bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 1), Hi); 3649*bdd1243dSDimitry Andric ReplaceUses(SDValue(N, 2), OutChain); 3650*bdd1243dSDimitry Andric }; 3651*bdd1243dSDimitry Andric return true; 3652*bdd1243dSDimitry Andric } 36530b57cec5SDimitry Andric 36540b57cec5SDimitry Andric // Lower the write_register intrinsic to an MSR instruction node if the special 36550b57cec5SDimitry Andric // register string argument is either of the form detailed in the ALCE (the 36560b57cec5SDimitry Andric // form described in getIntOperandsFromRegsterString) or is a named register 36570b57cec5SDimitry Andric // known by the MSR SysReg mapper. 36580b57cec5SDimitry Andric bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) { 3659349cc55cSDimitry Andric const auto *MD = cast<MDNodeSDNode>(N->getOperand(1)); 3660349cc55cSDimitry Andric const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0)); 36610b57cec5SDimitry Andric SDLoc DL(N); 36620b57cec5SDimitry Andric 3663*bdd1243dSDimitry Andric bool WriteIs128Bit = N->getOpcode() == AArch64ISD::MSRR; 36640b57cec5SDimitry Andric 3665*bdd1243dSDimitry Andric if (!WriteIs128Bit) { 3666*bdd1243dSDimitry Andric // Check if the register was one of those allowed as the pstatefield value 3667*bdd1243dSDimitry Andric // in the MSR (immediate) instruction. To accept the values allowed in the 36680b57cec5SDimitry Andric // pstatefield for the MSR (immediate) instruction, we also require that an 36690b57cec5SDimitry Andric // immediate value has been provided as an argument, we know that this is 36700b57cec5SDimitry Andric // the case as it has been ensured by semantic checking. 3671*bdd1243dSDimitry Andric auto trySelectPState = [&](auto PMapper, unsigned State) { 36720b57cec5SDimitry Andric if (PMapper) { 3673*bdd1243dSDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(2)) && 3674*bdd1243dSDimitry Andric "Expected a constant integer expression."); 36750b57cec5SDimitry Andric unsigned Reg = PMapper->Encoding; 36760b57cec5SDimitry Andric uint64_t Immed = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); 3677*bdd1243dSDimitry Andric CurDAG->SelectNodeTo( 3678*bdd1243dSDimitry Andric N, State, MVT::Other, CurDAG->getTargetConstant(Reg, DL, MVT::i32), 3679*bdd1243dSDimitry Andric CurDAG->getTargetConstant(Immed, DL, MVT::i16), N->getOperand(0)); 3680*bdd1243dSDimitry Andric return true; 36810b57cec5SDimitry Andric } 3682*bdd1243dSDimitry Andric return false; 3683*bdd1243dSDimitry Andric }; 3684*bdd1243dSDimitry Andric 3685*bdd1243dSDimitry Andric if (trySelectPState( 3686*bdd1243dSDimitry Andric AArch64PState::lookupPStateImm0_15ByName(RegString->getString()), 3687*bdd1243dSDimitry Andric AArch64::MSRpstateImm4)) 3688*bdd1243dSDimitry Andric return true; 3689*bdd1243dSDimitry Andric if (trySelectPState( 3690*bdd1243dSDimitry Andric AArch64PState::lookupPStateImm0_1ByName(RegString->getString()), 3691*bdd1243dSDimitry Andric AArch64::MSRpstateImm1)) 36920b57cec5SDimitry Andric return true; 36930b57cec5SDimitry Andric } 36940b57cec5SDimitry Andric 3695*bdd1243dSDimitry Andric int Imm = getIntOperandFromRegisterString(RegString->getString()); 3696*bdd1243dSDimitry Andric if (Imm == -1) { 36970b57cec5SDimitry Andric // Use the sysreg mapper to attempt to map the remaining possible strings 36980b57cec5SDimitry Andric // to the value for the register to be used for the MSR (register) 36990b57cec5SDimitry Andric // instruction operand. 37000b57cec5SDimitry Andric auto TheReg = AArch64SysReg::lookupSysRegByName(RegString->getString()); 37010b57cec5SDimitry Andric if (TheReg && TheReg->Writeable && 37020b57cec5SDimitry Andric TheReg->haveFeatures(Subtarget->getFeatureBits())) 3703*bdd1243dSDimitry Andric Imm = TheReg->Encoding; 37040b57cec5SDimitry Andric else 3705*bdd1243dSDimitry Andric Imm = AArch64SysReg::parseGenericRegister(RegString->getString()); 3706*bdd1243dSDimitry Andric 3707*bdd1243dSDimitry Andric if (Imm == -1) 3708*bdd1243dSDimitry Andric return false; 37090b57cec5SDimitry Andric } 37100b57cec5SDimitry Andric 3711*bdd1243dSDimitry Andric SDValue InChain = N->getOperand(0); 3712*bdd1243dSDimitry Andric if (!WriteIs128Bit) { 3713*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::MSR, MVT::Other, 3714*bdd1243dSDimitry Andric CurDAG->getTargetConstant(Imm, DL, MVT::i32), 3715*bdd1243dSDimitry Andric N->getOperand(2), InChain); 3716*bdd1243dSDimitry Andric } else { 3717*bdd1243dSDimitry Andric // No endian swap. The lower half always goes into the even subreg, and the 3718*bdd1243dSDimitry Andric // higher half always into the odd supreg. 3719*bdd1243dSDimitry Andric SDNode *Pair = CurDAG->getMachineNode( 3720*bdd1243dSDimitry Andric TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped /* XSeqPair */, 3721*bdd1243dSDimitry Andric {CurDAG->getTargetConstant(AArch64::XSeqPairsClassRegClass.getID(), DL, 3722*bdd1243dSDimitry Andric MVT::i32), 3723*bdd1243dSDimitry Andric N->getOperand(2), 3724*bdd1243dSDimitry Andric CurDAG->getTargetConstant(AArch64::sube64, DL, MVT::i32), 3725*bdd1243dSDimitry Andric N->getOperand(3), 3726*bdd1243dSDimitry Andric CurDAG->getTargetConstant(AArch64::subo64, DL, MVT::i32)}); 3727*bdd1243dSDimitry Andric 3728*bdd1243dSDimitry Andric CurDAG->SelectNodeTo(N, AArch64::MSRR, MVT::Other, 3729*bdd1243dSDimitry Andric CurDAG->getTargetConstant(Imm, DL, MVT::i32), 3730*bdd1243dSDimitry Andric SDValue(Pair, 0), InChain); 3731*bdd1243dSDimitry Andric } 3732*bdd1243dSDimitry Andric 3733*bdd1243dSDimitry Andric return true; 37340b57cec5SDimitry Andric } 37350b57cec5SDimitry Andric 37360b57cec5SDimitry Andric /// We've got special pseudo-instructions for these 37370b57cec5SDimitry Andric bool AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) { 37380b57cec5SDimitry Andric unsigned Opcode; 37390b57cec5SDimitry Andric EVT MemTy = cast<MemSDNode>(N)->getMemoryVT(); 37400b57cec5SDimitry Andric 37410b57cec5SDimitry Andric // Leave IR for LSE if subtarget supports it. 37420b57cec5SDimitry Andric if (Subtarget->hasLSE()) return false; 37430b57cec5SDimitry Andric 37440b57cec5SDimitry Andric if (MemTy == MVT::i8) 37450b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_8; 37460b57cec5SDimitry Andric else if (MemTy == MVT::i16) 37470b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_16; 37480b57cec5SDimitry Andric else if (MemTy == MVT::i32) 37490b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_32; 37500b57cec5SDimitry Andric else if (MemTy == MVT::i64) 37510b57cec5SDimitry Andric Opcode = AArch64::CMP_SWAP_64; 37520b57cec5SDimitry Andric else 37530b57cec5SDimitry Andric llvm_unreachable("Unknown AtomicCmpSwap type"); 37540b57cec5SDimitry Andric 37550b57cec5SDimitry Andric MVT RegTy = MemTy == MVT::i64 ? MVT::i64 : MVT::i32; 37560b57cec5SDimitry Andric SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3), 37570b57cec5SDimitry Andric N->getOperand(0)}; 37580b57cec5SDimitry Andric SDNode *CmpSwap = CurDAG->getMachineNode( 37590b57cec5SDimitry Andric Opcode, SDLoc(N), 37600b57cec5SDimitry Andric CurDAG->getVTList(RegTy, MVT::i32, MVT::Other), Ops); 37610b57cec5SDimitry Andric 37620b57cec5SDimitry Andric MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand(); 37630b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp}); 37640b57cec5SDimitry Andric 37650b57cec5SDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0)); 37660b57cec5SDimitry Andric ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2)); 37670b57cec5SDimitry Andric CurDAG->RemoveDeadNode(N); 37680b57cec5SDimitry Andric 37690b57cec5SDimitry Andric return true; 37700b57cec5SDimitry Andric } 37710b57cec5SDimitry Andric 377281ad6265SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEAddSubImm(SDValue N, MVT VT, SDValue &Imm, 377381ad6265SDimitry Andric SDValue &Shift) { 377481ad6265SDimitry Andric if (!isa<ConstantSDNode>(N)) 37755ffd83dbSDimitry Andric return false; 37765ffd83dbSDimitry Andric 37775ffd83dbSDimitry Andric SDLoc DL(N); 377881ad6265SDimitry Andric uint64_t Val = cast<ConstantSDNode>(N) 377981ad6265SDimitry Andric ->getAPIntValue() 378081ad6265SDimitry Andric .trunc(VT.getFixedSizeInBits()) 378181ad6265SDimitry Andric .getZExtValue(); 3782480093f4SDimitry Andric 3783480093f4SDimitry Andric switch (VT.SimpleTy) { 3784480093f4SDimitry Andric case MVT::i8: 378581ad6265SDimitry Andric // All immediates are supported. 3786fe6060f1SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 378781ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32); 3788fe6060f1SDimitry Andric return true; 3789fe6060f1SDimitry Andric case MVT::i16: 3790480093f4SDimitry Andric case MVT::i32: 3791480093f4SDimitry Andric case MVT::i64: 379281ad6265SDimitry Andric // Support 8bit unsigned immediates. 379381ad6265SDimitry Andric if (Val <= 255) { 3794480093f4SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 379581ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val, DL, MVT::i32); 3796480093f4SDimitry Andric return true; 379781ad6265SDimitry Andric } 379881ad6265SDimitry Andric // Support 16bit unsigned immediates that are a multiple of 256. 379981ad6265SDimitry Andric if (Val <= 65280 && Val % 256 == 0) { 3800480093f4SDimitry Andric Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); 380181ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val >> 8, DL, MVT::i32); 3802480093f4SDimitry Andric return true; 3803480093f4SDimitry Andric } 3804480093f4SDimitry Andric break; 3805480093f4SDimitry Andric default: 3806480093f4SDimitry Andric break; 3807480093f4SDimitry Andric } 380881ad6265SDimitry Andric 380981ad6265SDimitry Andric return false; 381081ad6265SDimitry Andric } 381181ad6265SDimitry Andric 381281ad6265SDimitry Andric bool AArch64DAGToDAGISel::SelectSVECpyDupImm(SDValue N, MVT VT, SDValue &Imm, 381381ad6265SDimitry Andric SDValue &Shift) { 381481ad6265SDimitry Andric if (!isa<ConstantSDNode>(N)) 381581ad6265SDimitry Andric return false; 381681ad6265SDimitry Andric 381781ad6265SDimitry Andric SDLoc DL(N); 381881ad6265SDimitry Andric int64_t Val = cast<ConstantSDNode>(N) 381981ad6265SDimitry Andric ->getAPIntValue() 382081ad6265SDimitry Andric .trunc(VT.getFixedSizeInBits()) 382181ad6265SDimitry Andric .getSExtValue(); 382281ad6265SDimitry Andric 382381ad6265SDimitry Andric switch (VT.SimpleTy) { 382481ad6265SDimitry Andric case MVT::i8: 382581ad6265SDimitry Andric // All immediates are supported. 382681ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 382781ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val & 0xFF, DL, MVT::i32); 382881ad6265SDimitry Andric return true; 382981ad6265SDimitry Andric case MVT::i16: 383081ad6265SDimitry Andric case MVT::i32: 383181ad6265SDimitry Andric case MVT::i64: 383281ad6265SDimitry Andric // Support 8bit signed immediates. 383381ad6265SDimitry Andric if (Val >= -128 && Val <= 127) { 383481ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(0, DL, MVT::i32); 383581ad6265SDimitry Andric Imm = CurDAG->getTargetConstant(Val & 0xFF, DL, MVT::i32); 383681ad6265SDimitry Andric return true; 383781ad6265SDimitry Andric } 383881ad6265SDimitry Andric // Support 16bit signed immediates that are a multiple of 256. 383981ad6265SDimitry Andric if (Val >= -32768 && Val <= 32512 && Val % 256 == 0) { 384081ad6265SDimitry Andric Shift = CurDAG->getTargetConstant(8, DL, MVT::i32); 384181ad6265SDimitry Andric Imm = CurDAG->getTargetConstant((Val >> 8) & 0xFF, DL, MVT::i32); 384281ad6265SDimitry Andric return true; 384381ad6265SDimitry Andric } 384481ad6265SDimitry Andric break; 384581ad6265SDimitry Andric default: 384681ad6265SDimitry Andric break; 3847480093f4SDimitry Andric } 3848480093f4SDimitry Andric 3849480093f4SDimitry Andric return false; 3850480093f4SDimitry Andric } 3851480093f4SDimitry Andric 3852480093f4SDimitry Andric bool AArch64DAGToDAGISel::SelectSVESignedArithImm(SDValue N, SDValue &Imm) { 3853480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 3854480093f4SDimitry Andric int64_t ImmVal = CNode->getSExtValue(); 3855480093f4SDimitry Andric SDLoc DL(N); 38565ffd83dbSDimitry Andric if (ImmVal >= -128 && ImmVal < 128) { 3857480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32); 3858480093f4SDimitry Andric return true; 3859480093f4SDimitry Andric } 3860480093f4SDimitry Andric } 3861480093f4SDimitry Andric return false; 3862480093f4SDimitry Andric } 3863480093f4SDimitry Andric 3864e8d8bef9SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEArithImm(SDValue N, MVT VT, SDValue &Imm) { 3865480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 3866e8d8bef9SDimitry Andric uint64_t ImmVal = CNode->getZExtValue(); 3867e8d8bef9SDimitry Andric 3868e8d8bef9SDimitry Andric switch (VT.SimpleTy) { 3869e8d8bef9SDimitry Andric case MVT::i8: 3870e8d8bef9SDimitry Andric ImmVal &= 0xFF; 3871e8d8bef9SDimitry Andric break; 3872e8d8bef9SDimitry Andric case MVT::i16: 3873e8d8bef9SDimitry Andric ImmVal &= 0xFFFF; 3874e8d8bef9SDimitry Andric break; 3875e8d8bef9SDimitry Andric case MVT::i32: 3876e8d8bef9SDimitry Andric ImmVal &= 0xFFFFFFFF; 3877e8d8bef9SDimitry Andric break; 3878e8d8bef9SDimitry Andric case MVT::i64: 3879e8d8bef9SDimitry Andric break; 3880e8d8bef9SDimitry Andric default: 3881e8d8bef9SDimitry Andric llvm_unreachable("Unexpected type"); 3882e8d8bef9SDimitry Andric } 3883e8d8bef9SDimitry Andric 3884480093f4SDimitry Andric if (ImmVal < 256) { 3885e8d8bef9SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32); 3886480093f4SDimitry Andric return true; 3887480093f4SDimitry Andric } 3888480093f4SDimitry Andric } 3889480093f4SDimitry Andric return false; 3890480093f4SDimitry Andric } 3891480093f4SDimitry Andric 3892fe6060f1SDimitry Andric bool AArch64DAGToDAGISel::SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm, 3893fe6060f1SDimitry Andric bool Invert) { 3894480093f4SDimitry Andric if (auto CNode = dyn_cast<ConstantSDNode>(N)) { 3895480093f4SDimitry Andric uint64_t ImmVal = CNode->getZExtValue(); 3896480093f4SDimitry Andric SDLoc DL(N); 3897480093f4SDimitry Andric 3898fe6060f1SDimitry Andric if (Invert) 3899fe6060f1SDimitry Andric ImmVal = ~ImmVal; 3900fe6060f1SDimitry Andric 3901480093f4SDimitry Andric // Shift mask depending on type size. 3902480093f4SDimitry Andric switch (VT.SimpleTy) { 3903480093f4SDimitry Andric case MVT::i8: 3904480093f4SDimitry Andric ImmVal &= 0xFF; 3905480093f4SDimitry Andric ImmVal |= ImmVal << 8; 3906480093f4SDimitry Andric ImmVal |= ImmVal << 16; 3907480093f4SDimitry Andric ImmVal |= ImmVal << 32; 3908480093f4SDimitry Andric break; 3909480093f4SDimitry Andric case MVT::i16: 3910480093f4SDimitry Andric ImmVal &= 0xFFFF; 3911480093f4SDimitry Andric ImmVal |= ImmVal << 16; 3912480093f4SDimitry Andric ImmVal |= ImmVal << 32; 3913480093f4SDimitry Andric break; 3914480093f4SDimitry Andric case MVT::i32: 3915480093f4SDimitry Andric ImmVal &= 0xFFFFFFFF; 3916480093f4SDimitry Andric ImmVal |= ImmVal << 32; 3917480093f4SDimitry Andric break; 3918480093f4SDimitry Andric case MVT::i64: 3919480093f4SDimitry Andric break; 3920480093f4SDimitry Andric default: 3921480093f4SDimitry Andric llvm_unreachable("Unexpected type"); 3922480093f4SDimitry Andric } 3923480093f4SDimitry Andric 3924480093f4SDimitry Andric uint64_t encoding; 3925480093f4SDimitry Andric if (AArch64_AM::processLogicalImmediate(ImmVal, 64, encoding)) { 3926480093f4SDimitry Andric Imm = CurDAG->getTargetConstant(encoding, DL, MVT::i64); 3927480093f4SDimitry Andric return true; 3928480093f4SDimitry Andric } 3929480093f4SDimitry Andric } 3930480093f4SDimitry Andric return false; 3931480093f4SDimitry Andric } 3932480093f4SDimitry Andric 3933e8d8bef9SDimitry Andric // SVE shift intrinsics allow shift amounts larger than the element's bitwidth. 3934e8d8bef9SDimitry Andric // Rather than attempt to normalise everything we can sometimes saturate the 3935e8d8bef9SDimitry Andric // shift amount during selection. This function also allows for consistent 3936e8d8bef9SDimitry Andric // isel patterns by ensuring the resulting "Imm" node is of the i32 type 3937e8d8bef9SDimitry Andric // required by the instructions. 3938e8d8bef9SDimitry Andric bool AArch64DAGToDAGISel::SelectSVEShiftImm(SDValue N, uint64_t Low, 3939e8d8bef9SDimitry Andric uint64_t High, bool AllowSaturation, 3940e8d8bef9SDimitry Andric SDValue &Imm) { 39415ffd83dbSDimitry Andric if (auto *CN = dyn_cast<ConstantSDNode>(N)) { 39425ffd83dbSDimitry Andric uint64_t ImmVal = CN->getZExtValue(); 39435ffd83dbSDimitry Andric 3944e8d8bef9SDimitry Andric // Reject shift amounts that are too small. 3945e8d8bef9SDimitry Andric if (ImmVal < Low) 3946e8d8bef9SDimitry Andric return false; 3947e8d8bef9SDimitry Andric 3948e8d8bef9SDimitry Andric // Reject or saturate shift amounts that are too big. 3949e8d8bef9SDimitry Andric if (ImmVal > High) { 3950e8d8bef9SDimitry Andric if (!AllowSaturation) 3951e8d8bef9SDimitry Andric return false; 3952e8d8bef9SDimitry Andric ImmVal = High; 39535ffd83dbSDimitry Andric } 3954e8d8bef9SDimitry Andric 3955e8d8bef9SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32); 3956e8d8bef9SDimitry Andric return true; 39575ffd83dbSDimitry Andric } 39585ffd83dbSDimitry Andric 39595ffd83dbSDimitry Andric return false; 39605ffd83dbSDimitry Andric } 39615ffd83dbSDimitry Andric 39620b57cec5SDimitry Andric bool AArch64DAGToDAGISel::trySelectStackSlotTagP(SDNode *N) { 39630b57cec5SDimitry Andric // tagp(FrameIndex, IRGstack, tag_offset): 39640b57cec5SDimitry Andric // since the offset between FrameIndex and IRGstack is a compile-time 39650b57cec5SDimitry Andric // constant, this can be lowered to a single ADDG instruction. 39660b57cec5SDimitry Andric if (!(isa<FrameIndexSDNode>(N->getOperand(1)))) { 39670b57cec5SDimitry Andric return false; 39680b57cec5SDimitry Andric } 39690b57cec5SDimitry Andric 39700b57cec5SDimitry Andric SDValue IRG_SP = N->getOperand(2); 39710b57cec5SDimitry Andric if (IRG_SP->getOpcode() != ISD::INTRINSIC_W_CHAIN || 39720b57cec5SDimitry Andric cast<ConstantSDNode>(IRG_SP->getOperand(1))->getZExtValue() != 39730b57cec5SDimitry Andric Intrinsic::aarch64_irg_sp) { 39740b57cec5SDimitry Andric return false; 39750b57cec5SDimitry Andric } 39760b57cec5SDimitry Andric 39770b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 39780b57cec5SDimitry Andric SDLoc DL(N); 39790b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(N->getOperand(1))->getIndex(); 39800b57cec5SDimitry Andric SDValue FiOp = CurDAG->getTargetFrameIndex( 39810b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 39820b57cec5SDimitry Andric int TagOffset = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(); 39830b57cec5SDimitry Andric 39840b57cec5SDimitry Andric SDNode *Out = CurDAG->getMachineNode( 39850b57cec5SDimitry Andric AArch64::TAGPstack, DL, MVT::i64, 39860b57cec5SDimitry Andric {FiOp, CurDAG->getTargetConstant(0, DL, MVT::i64), N->getOperand(2), 39870b57cec5SDimitry Andric CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)}); 39880b57cec5SDimitry Andric ReplaceNode(N, Out); 39890b57cec5SDimitry Andric return true; 39900b57cec5SDimitry Andric } 39910b57cec5SDimitry Andric 39920b57cec5SDimitry Andric void AArch64DAGToDAGISel::SelectTagP(SDNode *N) { 39930b57cec5SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(3)) && 39940b57cec5SDimitry Andric "llvm.aarch64.tagp third argument must be an immediate"); 39950b57cec5SDimitry Andric if (trySelectStackSlotTagP(N)) 39960b57cec5SDimitry Andric return; 39970b57cec5SDimitry Andric // FIXME: above applies in any case when offset between Op1 and Op2 is a 39980b57cec5SDimitry Andric // compile-time constant, not just for stack allocations. 39990b57cec5SDimitry Andric 40000b57cec5SDimitry Andric // General case for unrelated pointers in Op1 and Op2. 40010b57cec5SDimitry Andric SDLoc DL(N); 40020b57cec5SDimitry Andric int TagOffset = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(); 40030b57cec5SDimitry Andric SDNode *N1 = CurDAG->getMachineNode(AArch64::SUBP, DL, MVT::i64, 40040b57cec5SDimitry Andric {N->getOperand(1), N->getOperand(2)}); 40050b57cec5SDimitry Andric SDNode *N2 = CurDAG->getMachineNode(AArch64::ADDXrr, DL, MVT::i64, 40060b57cec5SDimitry Andric {SDValue(N1, 0), N->getOperand(2)}); 40070b57cec5SDimitry Andric SDNode *N3 = CurDAG->getMachineNode( 40080b57cec5SDimitry Andric AArch64::ADDG, DL, MVT::i64, 40090b57cec5SDimitry Andric {SDValue(N2, 0), CurDAG->getTargetConstant(0, DL, MVT::i64), 40100b57cec5SDimitry Andric CurDAG->getTargetConstant(TagOffset, DL, MVT::i64)}); 40110b57cec5SDimitry Andric ReplaceNode(N, N3); 40120b57cec5SDimitry Andric } 40130b57cec5SDimitry Andric 40145ffd83dbSDimitry Andric // NOTE: We cannot use EXTRACT_SUBREG in all cases because the fixed length 40155ffd83dbSDimitry Andric // vector types larger than NEON don't have a matching SubRegIndex. 40165ffd83dbSDimitry Andric static SDNode *extractSubReg(SelectionDAG *DAG, EVT VT, SDValue V) { 40175ffd83dbSDimitry Andric assert(V.getValueType().isScalableVector() && 4018*bdd1243dSDimitry Andric V.getValueType().getSizeInBits().getKnownMinValue() == 40195ffd83dbSDimitry Andric AArch64::SVEBitsPerBlock && 40205ffd83dbSDimitry Andric "Expected to extract from a packed scalable vector!"); 40215ffd83dbSDimitry Andric assert(VT.isFixedLengthVector() && 40225ffd83dbSDimitry Andric "Expected to extract a fixed length vector!"); 40235ffd83dbSDimitry Andric 40245ffd83dbSDimitry Andric SDLoc DL(V); 40255ffd83dbSDimitry Andric switch (VT.getSizeInBits()) { 40265ffd83dbSDimitry Andric case 64: { 40275ffd83dbSDimitry Andric auto SubReg = DAG->getTargetConstant(AArch64::dsub, DL, MVT::i32); 40285ffd83dbSDimitry Andric return DAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, VT, V, SubReg); 40295ffd83dbSDimitry Andric } 40305ffd83dbSDimitry Andric case 128: { 40315ffd83dbSDimitry Andric auto SubReg = DAG->getTargetConstant(AArch64::zsub, DL, MVT::i32); 40325ffd83dbSDimitry Andric return DAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, VT, V, SubReg); 40335ffd83dbSDimitry Andric } 40345ffd83dbSDimitry Andric default: { 40355ffd83dbSDimitry Andric auto RC = DAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64); 40365ffd83dbSDimitry Andric return DAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 40375ffd83dbSDimitry Andric } 40385ffd83dbSDimitry Andric } 40395ffd83dbSDimitry Andric } 40405ffd83dbSDimitry Andric 40415ffd83dbSDimitry Andric // NOTE: We cannot use INSERT_SUBREG in all cases because the fixed length 40425ffd83dbSDimitry Andric // vector types larger than NEON don't have a matching SubRegIndex. 40435ffd83dbSDimitry Andric static SDNode *insertSubReg(SelectionDAG *DAG, EVT VT, SDValue V) { 40445ffd83dbSDimitry Andric assert(VT.isScalableVector() && 4045*bdd1243dSDimitry Andric VT.getSizeInBits().getKnownMinValue() == AArch64::SVEBitsPerBlock && 40465ffd83dbSDimitry Andric "Expected to insert into a packed scalable vector!"); 40475ffd83dbSDimitry Andric assert(V.getValueType().isFixedLengthVector() && 40485ffd83dbSDimitry Andric "Expected to insert a fixed length vector!"); 40495ffd83dbSDimitry Andric 40505ffd83dbSDimitry Andric SDLoc DL(V); 40515ffd83dbSDimitry Andric switch (V.getValueType().getSizeInBits()) { 40525ffd83dbSDimitry Andric case 64: { 40535ffd83dbSDimitry Andric auto SubReg = DAG->getTargetConstant(AArch64::dsub, DL, MVT::i32); 40545ffd83dbSDimitry Andric auto Container = DAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT); 40555ffd83dbSDimitry Andric return DAG->getMachineNode(TargetOpcode::INSERT_SUBREG, DL, VT, 40565ffd83dbSDimitry Andric SDValue(Container, 0), V, SubReg); 40575ffd83dbSDimitry Andric } 40585ffd83dbSDimitry Andric case 128: { 40595ffd83dbSDimitry Andric auto SubReg = DAG->getTargetConstant(AArch64::zsub, DL, MVT::i32); 40605ffd83dbSDimitry Andric auto Container = DAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT); 40615ffd83dbSDimitry Andric return DAG->getMachineNode(TargetOpcode::INSERT_SUBREG, DL, VT, 40625ffd83dbSDimitry Andric SDValue(Container, 0), V, SubReg); 40635ffd83dbSDimitry Andric } 40645ffd83dbSDimitry Andric default: { 40655ffd83dbSDimitry Andric auto RC = DAG->getTargetConstant(AArch64::ZPRRegClassID, DL, MVT::i64); 40665ffd83dbSDimitry Andric return DAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 40675ffd83dbSDimitry Andric } 40685ffd83dbSDimitry Andric } 40695ffd83dbSDimitry Andric } 40705ffd83dbSDimitry Andric 40710b57cec5SDimitry Andric void AArch64DAGToDAGISel::Select(SDNode *Node) { 40720b57cec5SDimitry Andric // If we have a custom node, we already have selected! 40730b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 40740b57cec5SDimitry Andric LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 40750b57cec5SDimitry Andric Node->setNodeId(-1); 40760b57cec5SDimitry Andric return; 40770b57cec5SDimitry Andric } 40780b57cec5SDimitry Andric 40790b57cec5SDimitry Andric // Few custom selection stuff. 40800b57cec5SDimitry Andric EVT VT = Node->getValueType(0); 40810b57cec5SDimitry Andric 40820b57cec5SDimitry Andric switch (Node->getOpcode()) { 40830b57cec5SDimitry Andric default: 40840b57cec5SDimitry Andric break; 40850b57cec5SDimitry Andric 40860b57cec5SDimitry Andric case ISD::ATOMIC_CMP_SWAP: 40870b57cec5SDimitry Andric if (SelectCMP_SWAP(Node)) 40880b57cec5SDimitry Andric return; 40890b57cec5SDimitry Andric break; 40900b57cec5SDimitry Andric 40910b57cec5SDimitry Andric case ISD::READ_REGISTER: 4092*bdd1243dSDimitry Andric case AArch64ISD::MRRS: 40930b57cec5SDimitry Andric if (tryReadRegister(Node)) 40940b57cec5SDimitry Andric return; 40950b57cec5SDimitry Andric break; 40960b57cec5SDimitry Andric 40970b57cec5SDimitry Andric case ISD::WRITE_REGISTER: 4098*bdd1243dSDimitry Andric case AArch64ISD::MSRR: 40990b57cec5SDimitry Andric if (tryWriteRegister(Node)) 41000b57cec5SDimitry Andric return; 41010b57cec5SDimitry Andric break; 41020b57cec5SDimitry Andric 41030b57cec5SDimitry Andric case ISD::ADD: 41040b57cec5SDimitry Andric if (tryMLAV64LaneV128(Node)) 41050b57cec5SDimitry Andric return; 41060b57cec5SDimitry Andric break; 41070b57cec5SDimitry Andric 41080b57cec5SDimitry Andric case ISD::LOAD: { 41090b57cec5SDimitry Andric // Try to select as an indexed load. Fall through to normal processing 41100b57cec5SDimitry Andric // if we can't. 41110b57cec5SDimitry Andric if (tryIndexedLoad(Node)) 41120b57cec5SDimitry Andric return; 41130b57cec5SDimitry Andric break; 41140b57cec5SDimitry Andric } 41150b57cec5SDimitry Andric 41160b57cec5SDimitry Andric case ISD::SRL: 41170b57cec5SDimitry Andric case ISD::AND: 41180b57cec5SDimitry Andric case ISD::SRA: 41190b57cec5SDimitry Andric case ISD::SIGN_EXTEND_INREG: 41200b57cec5SDimitry Andric if (tryBitfieldExtractOp(Node)) 41210b57cec5SDimitry Andric return; 41220b57cec5SDimitry Andric if (tryBitfieldInsertInZeroOp(Node)) 41230b57cec5SDimitry Andric return; 4124*bdd1243dSDimitry Andric [[fallthrough]]; 41250b57cec5SDimitry Andric case ISD::ROTR: 41260b57cec5SDimitry Andric case ISD::SHL: 41270b57cec5SDimitry Andric if (tryShiftAmountMod(Node)) 41280b57cec5SDimitry Andric return; 41290b57cec5SDimitry Andric break; 41300b57cec5SDimitry Andric 41310b57cec5SDimitry Andric case ISD::SIGN_EXTEND: 41320b57cec5SDimitry Andric if (tryBitfieldExtractOpFromSExt(Node)) 41330b57cec5SDimitry Andric return; 41340b57cec5SDimitry Andric break; 41350b57cec5SDimitry Andric 4136480093f4SDimitry Andric case ISD::FP_EXTEND: 4137480093f4SDimitry Andric if (tryHighFPExt(Node)) 4138480093f4SDimitry Andric return; 4139480093f4SDimitry Andric break; 4140480093f4SDimitry Andric 41410b57cec5SDimitry Andric case ISD::OR: 41420b57cec5SDimitry Andric if (tryBitfieldInsertOp(Node)) 41430b57cec5SDimitry Andric return; 41440b57cec5SDimitry Andric break; 41450b57cec5SDimitry Andric 41465ffd83dbSDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 41475ffd83dbSDimitry Andric // Bail when not a "cast" like extract_subvector. 41485ffd83dbSDimitry Andric if (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue() != 0) 41495ffd83dbSDimitry Andric break; 41505ffd83dbSDimitry Andric 41515ffd83dbSDimitry Andric // Bail when normal isel can do the job. 41525ffd83dbSDimitry Andric EVT InVT = Node->getOperand(0).getValueType(); 41535ffd83dbSDimitry Andric if (VT.isScalableVector() || InVT.isFixedLengthVector()) 41545ffd83dbSDimitry Andric break; 41555ffd83dbSDimitry Andric 41565ffd83dbSDimitry Andric // NOTE: We can only get here when doing fixed length SVE code generation. 41575ffd83dbSDimitry Andric // We do manual selection because the types involved are not linked to real 41585ffd83dbSDimitry Andric // registers (despite being legal) and must be coerced into SVE registers. 41595ffd83dbSDimitry Andric // 41605ffd83dbSDimitry Andric // NOTE: If the above changes, be aware that selection will still not work 41615ffd83dbSDimitry Andric // because the td definition of extract_vector does not support extracting 41625ffd83dbSDimitry Andric // a fixed length vector from a scalable vector. 41635ffd83dbSDimitry Andric 41645ffd83dbSDimitry Andric ReplaceNode(Node, extractSubReg(CurDAG, VT, Node->getOperand(0))); 41655ffd83dbSDimitry Andric return; 41665ffd83dbSDimitry Andric } 41675ffd83dbSDimitry Andric 41685ffd83dbSDimitry Andric case ISD::INSERT_SUBVECTOR: { 41695ffd83dbSDimitry Andric // Bail when not a "cast" like insert_subvector. 41705ffd83dbSDimitry Andric if (cast<ConstantSDNode>(Node->getOperand(2))->getZExtValue() != 0) 41715ffd83dbSDimitry Andric break; 41725ffd83dbSDimitry Andric if (!Node->getOperand(0).isUndef()) 41735ffd83dbSDimitry Andric break; 41745ffd83dbSDimitry Andric 41755ffd83dbSDimitry Andric // Bail when normal isel should do the job. 41765ffd83dbSDimitry Andric EVT InVT = Node->getOperand(1).getValueType(); 41775ffd83dbSDimitry Andric if (VT.isFixedLengthVector() || InVT.isScalableVector()) 41785ffd83dbSDimitry Andric break; 41795ffd83dbSDimitry Andric 41805ffd83dbSDimitry Andric // NOTE: We can only get here when doing fixed length SVE code generation. 41815ffd83dbSDimitry Andric // We do manual selection because the types involved are not linked to real 41825ffd83dbSDimitry Andric // registers (despite being legal) and must be coerced into SVE registers. 41835ffd83dbSDimitry Andric // 41845ffd83dbSDimitry Andric // NOTE: If the above changes, be aware that selection will still not work 41855ffd83dbSDimitry Andric // because the td definition of insert_vector does not support inserting a 41865ffd83dbSDimitry Andric // fixed length vector into a scalable vector. 41875ffd83dbSDimitry Andric 41885ffd83dbSDimitry Andric ReplaceNode(Node, insertSubReg(CurDAG, VT, Node->getOperand(1))); 41895ffd83dbSDimitry Andric return; 41905ffd83dbSDimitry Andric } 41915ffd83dbSDimitry Andric 41920b57cec5SDimitry Andric case ISD::Constant: { 41930b57cec5SDimitry Andric // Materialize zero constants as copies from WZR/XZR. This allows 41940b57cec5SDimitry Andric // the coalescer to propagate these into other instructions. 41950b57cec5SDimitry Andric ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node); 4196349cc55cSDimitry Andric if (ConstNode->isZero()) { 41970b57cec5SDimitry Andric if (VT == MVT::i32) { 41980b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg( 41990b57cec5SDimitry Andric CurDAG->getEntryNode(), SDLoc(Node), AArch64::WZR, MVT::i32); 42000b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 42010b57cec5SDimitry Andric return; 42020b57cec5SDimitry Andric } else if (VT == MVT::i64) { 42030b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg( 42040b57cec5SDimitry Andric CurDAG->getEntryNode(), SDLoc(Node), AArch64::XZR, MVT::i64); 42050b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 42060b57cec5SDimitry Andric return; 42070b57cec5SDimitry Andric } 42080b57cec5SDimitry Andric } 42090b57cec5SDimitry Andric break; 42100b57cec5SDimitry Andric } 42110b57cec5SDimitry Andric 42120b57cec5SDimitry Andric case ISD::FrameIndex: { 42130b57cec5SDimitry Andric // Selects to ADDXri FI, 0 which in turn will become ADDXri SP, imm. 42140b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 42150b57cec5SDimitry Andric unsigned Shifter = AArch64_AM::getShifterImm(AArch64_AM::LSL, 0); 42160b57cec5SDimitry Andric const TargetLowering *TLI = getTargetLowering(); 42170b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex( 42180b57cec5SDimitry Andric FI, TLI->getPointerTy(CurDAG->getDataLayout())); 42190b57cec5SDimitry Andric SDLoc DL(Node); 42200b57cec5SDimitry Andric SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, DL, MVT::i32), 42210b57cec5SDimitry Andric CurDAG->getTargetConstant(Shifter, DL, MVT::i32) }; 42220b57cec5SDimitry Andric CurDAG->SelectNodeTo(Node, AArch64::ADDXri, MVT::i64, Ops); 42230b57cec5SDimitry Andric return; 42240b57cec5SDimitry Andric } 42250b57cec5SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 42260b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 42270b57cec5SDimitry Andric switch (IntNo) { 42280b57cec5SDimitry Andric default: 42290b57cec5SDimitry Andric break; 42300b57cec5SDimitry Andric case Intrinsic::aarch64_ldaxp: 42310b57cec5SDimitry Andric case Intrinsic::aarch64_ldxp: { 42320b57cec5SDimitry Andric unsigned Op = 42330b57cec5SDimitry Andric IntNo == Intrinsic::aarch64_ldaxp ? AArch64::LDAXPX : AArch64::LDXPX; 42340b57cec5SDimitry Andric SDValue MemAddr = Node->getOperand(2); 42350b57cec5SDimitry Andric SDLoc DL(Node); 42360b57cec5SDimitry Andric SDValue Chain = Node->getOperand(0); 42370b57cec5SDimitry Andric 42380b57cec5SDimitry Andric SDNode *Ld = CurDAG->getMachineNode(Op, DL, MVT::i64, MVT::i64, 42390b57cec5SDimitry Andric MVT::Other, MemAddr, Chain); 42400b57cec5SDimitry Andric 42410b57cec5SDimitry Andric // Transfer memoperands. 42420b57cec5SDimitry Andric MachineMemOperand *MemOp = 42430b57cec5SDimitry Andric cast<MemIntrinsicSDNode>(Node)->getMemOperand(); 42440b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp}); 42450b57cec5SDimitry Andric ReplaceNode(Node, Ld); 42460b57cec5SDimitry Andric return; 42470b57cec5SDimitry Andric } 42480b57cec5SDimitry Andric case Intrinsic::aarch64_stlxp: 42490b57cec5SDimitry Andric case Intrinsic::aarch64_stxp: { 42500b57cec5SDimitry Andric unsigned Op = 42510b57cec5SDimitry Andric IntNo == Intrinsic::aarch64_stlxp ? AArch64::STLXPX : AArch64::STXPX; 42520b57cec5SDimitry Andric SDLoc DL(Node); 42530b57cec5SDimitry Andric SDValue Chain = Node->getOperand(0); 42540b57cec5SDimitry Andric SDValue ValLo = Node->getOperand(2); 42550b57cec5SDimitry Andric SDValue ValHi = Node->getOperand(3); 42560b57cec5SDimitry Andric SDValue MemAddr = Node->getOperand(4); 42570b57cec5SDimitry Andric 42580b57cec5SDimitry Andric // Place arguments in the right order. 42590b57cec5SDimitry Andric SDValue Ops[] = {ValLo, ValHi, MemAddr, Chain}; 42600b57cec5SDimitry Andric 42610b57cec5SDimitry Andric SDNode *St = CurDAG->getMachineNode(Op, DL, MVT::i32, MVT::Other, Ops); 42620b57cec5SDimitry Andric // Transfer memoperands. 42630b57cec5SDimitry Andric MachineMemOperand *MemOp = 42640b57cec5SDimitry Andric cast<MemIntrinsicSDNode>(Node)->getMemOperand(); 42650b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp}); 42660b57cec5SDimitry Andric 42670b57cec5SDimitry Andric ReplaceNode(Node, St); 42680b57cec5SDimitry Andric return; 42690b57cec5SDimitry Andric } 42700b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x2: 42710b57cec5SDimitry Andric if (VT == MVT::v8i8) { 42720b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov8b, AArch64::dsub0); 42730b57cec5SDimitry Andric return; 42740b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 42750b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov16b, AArch64::qsub0); 42760b57cec5SDimitry Andric return; 42775ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 42780b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov4h, AArch64::dsub0); 42790b57cec5SDimitry Andric return; 42805ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 42810b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov8h, AArch64::qsub0); 42820b57cec5SDimitry Andric return; 42830b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 42840b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov2s, AArch64::dsub0); 42850b57cec5SDimitry Andric return; 42860b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 42870b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov4s, AArch64::qsub0); 42880b57cec5SDimitry Andric return; 42890b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 42900b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0); 42910b57cec5SDimitry Andric return; 42920b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 42930b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov2d, AArch64::qsub0); 42940b57cec5SDimitry Andric return; 42950b57cec5SDimitry Andric } 42960b57cec5SDimitry Andric break; 42970b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x3: 42980b57cec5SDimitry Andric if (VT == MVT::v8i8) { 42990b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev8b, AArch64::dsub0); 43000b57cec5SDimitry Andric return; 43010b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 43020b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev16b, AArch64::qsub0); 43030b57cec5SDimitry Andric return; 43045ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 43050b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev4h, AArch64::dsub0); 43060b57cec5SDimitry Andric return; 43075ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 43080b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev8h, AArch64::qsub0); 43090b57cec5SDimitry Andric return; 43100b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 43110b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev2s, AArch64::dsub0); 43120b57cec5SDimitry Andric return; 43130b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 43140b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev4s, AArch64::qsub0); 43150b57cec5SDimitry Andric return; 43160b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 43170b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0); 43180b57cec5SDimitry Andric return; 43190b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 43200b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev2d, AArch64::qsub0); 43210b57cec5SDimitry Andric return; 43220b57cec5SDimitry Andric } 43230b57cec5SDimitry Andric break; 43240b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld1x4: 43250b57cec5SDimitry Andric if (VT == MVT::v8i8) { 43260b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv8b, AArch64::dsub0); 43270b57cec5SDimitry Andric return; 43280b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 43290b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv16b, AArch64::qsub0); 43300b57cec5SDimitry Andric return; 43315ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 43320b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv4h, AArch64::dsub0); 43330b57cec5SDimitry Andric return; 43345ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 43350b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv8h, AArch64::qsub0); 43360b57cec5SDimitry Andric return; 43370b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 43380b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv2s, AArch64::dsub0); 43390b57cec5SDimitry Andric return; 43400b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 43410b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv4s, AArch64::qsub0); 43420b57cec5SDimitry Andric return; 43430b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 43440b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0); 43450b57cec5SDimitry Andric return; 43460b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 43470b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv2d, AArch64::qsub0); 43480b57cec5SDimitry Andric return; 43490b57cec5SDimitry Andric } 43500b57cec5SDimitry Andric break; 43510b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2: 43520b57cec5SDimitry Andric if (VT == MVT::v8i8) { 43530b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov8b, AArch64::dsub0); 43540b57cec5SDimitry Andric return; 43550b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 43560b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov16b, AArch64::qsub0); 43570b57cec5SDimitry Andric return; 43585ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 43590b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov4h, AArch64::dsub0); 43600b57cec5SDimitry Andric return; 43615ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 43620b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov8h, AArch64::qsub0); 43630b57cec5SDimitry Andric return; 43640b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 43650b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov2s, AArch64::dsub0); 43660b57cec5SDimitry Andric return; 43670b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 43680b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov4s, AArch64::qsub0); 43690b57cec5SDimitry Andric return; 43700b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 43710b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD1Twov1d, AArch64::dsub0); 43720b57cec5SDimitry Andric return; 43730b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 43740b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Twov2d, AArch64::qsub0); 43750b57cec5SDimitry Andric return; 43760b57cec5SDimitry Andric } 43770b57cec5SDimitry Andric break; 43780b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3: 43790b57cec5SDimitry Andric if (VT == MVT::v8i8) { 43800b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev8b, AArch64::dsub0); 43810b57cec5SDimitry Andric return; 43820b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 43830b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev16b, AArch64::qsub0); 43840b57cec5SDimitry Andric return; 43855ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 43860b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev4h, AArch64::dsub0); 43870b57cec5SDimitry Andric return; 43885ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 43890b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev8h, AArch64::qsub0); 43900b57cec5SDimitry Andric return; 43910b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 43920b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev2s, AArch64::dsub0); 43930b57cec5SDimitry Andric return; 43940b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 43950b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev4s, AArch64::qsub0); 43960b57cec5SDimitry Andric return; 43970b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 43980b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD1Threev1d, AArch64::dsub0); 43990b57cec5SDimitry Andric return; 44000b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 44010b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Threev2d, AArch64::qsub0); 44020b57cec5SDimitry Andric return; 44030b57cec5SDimitry Andric } 44040b57cec5SDimitry Andric break; 44050b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4: 44060b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44070b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv8b, AArch64::dsub0); 44080b57cec5SDimitry Andric return; 44090b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44100b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv16b, AArch64::qsub0); 44110b57cec5SDimitry Andric return; 44125ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44130b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv4h, AArch64::dsub0); 44140b57cec5SDimitry Andric return; 44155ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 44160b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv8h, AArch64::qsub0); 44170b57cec5SDimitry Andric return; 44180b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 44190b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv2s, AArch64::dsub0); 44200b57cec5SDimitry Andric return; 44210b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 44220b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv4s, AArch64::qsub0); 44230b57cec5SDimitry Andric return; 44240b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 44250b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD1Fourv1d, AArch64::dsub0); 44260b57cec5SDimitry Andric return; 44270b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 44280b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Fourv2d, AArch64::qsub0); 44290b57cec5SDimitry Andric return; 44300b57cec5SDimitry Andric } 44310b57cec5SDimitry Andric break; 44320b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2r: 44330b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44340b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv8b, AArch64::dsub0); 44350b57cec5SDimitry Andric return; 44360b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44370b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv16b, AArch64::qsub0); 44380b57cec5SDimitry Andric return; 44395ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44400b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv4h, AArch64::dsub0); 44410b57cec5SDimitry Andric return; 44425ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 44430b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv8h, AArch64::qsub0); 44440b57cec5SDimitry Andric return; 44450b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 44460b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv2s, AArch64::dsub0); 44470b57cec5SDimitry Andric return; 44480b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 44490b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv4s, AArch64::qsub0); 44500b57cec5SDimitry Andric return; 44510b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 44520b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv1d, AArch64::dsub0); 44530b57cec5SDimitry Andric return; 44540b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 44550b57cec5SDimitry Andric SelectLoad(Node, 2, AArch64::LD2Rv2d, AArch64::qsub0); 44560b57cec5SDimitry Andric return; 44570b57cec5SDimitry Andric } 44580b57cec5SDimitry Andric break; 44590b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3r: 44600b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44610b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv8b, AArch64::dsub0); 44620b57cec5SDimitry Andric return; 44630b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44640b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv16b, AArch64::qsub0); 44650b57cec5SDimitry Andric return; 44665ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44670b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv4h, AArch64::dsub0); 44680b57cec5SDimitry Andric return; 44695ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 44700b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv8h, AArch64::qsub0); 44710b57cec5SDimitry Andric return; 44720b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 44730b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv2s, AArch64::dsub0); 44740b57cec5SDimitry Andric return; 44750b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 44760b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv4s, AArch64::qsub0); 44770b57cec5SDimitry Andric return; 44780b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 44790b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv1d, AArch64::dsub0); 44800b57cec5SDimitry Andric return; 44810b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 44820b57cec5SDimitry Andric SelectLoad(Node, 3, AArch64::LD3Rv2d, AArch64::qsub0); 44830b57cec5SDimitry Andric return; 44840b57cec5SDimitry Andric } 44850b57cec5SDimitry Andric break; 44860b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4r: 44870b57cec5SDimitry Andric if (VT == MVT::v8i8) { 44880b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv8b, AArch64::dsub0); 44890b57cec5SDimitry Andric return; 44900b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 44910b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv16b, AArch64::qsub0); 44920b57cec5SDimitry Andric return; 44935ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 44940b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv4h, AArch64::dsub0); 44950b57cec5SDimitry Andric return; 44965ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 44970b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv8h, AArch64::qsub0); 44980b57cec5SDimitry Andric return; 44990b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 45000b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv2s, AArch64::dsub0); 45010b57cec5SDimitry Andric return; 45020b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 45030b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv4s, AArch64::qsub0); 45040b57cec5SDimitry Andric return; 45050b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 45060b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv1d, AArch64::dsub0); 45070b57cec5SDimitry Andric return; 45080b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 45090b57cec5SDimitry Andric SelectLoad(Node, 4, AArch64::LD4Rv2d, AArch64::qsub0); 45100b57cec5SDimitry Andric return; 45110b57cec5SDimitry Andric } 45120b57cec5SDimitry Andric break; 45130b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld2lane: 45140b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 45150b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i8); 45160b57cec5SDimitry Andric return; 45170b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 45185ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 45190b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i16); 45200b57cec5SDimitry Andric return; 45210b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 45220b57cec5SDimitry Andric VT == MVT::v2f32) { 45230b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i32); 45240b57cec5SDimitry Andric return; 45250b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 45260b57cec5SDimitry Andric VT == MVT::v1f64) { 45270b57cec5SDimitry Andric SelectLoadLane(Node, 2, AArch64::LD2i64); 45280b57cec5SDimitry Andric return; 45290b57cec5SDimitry Andric } 45300b57cec5SDimitry Andric break; 45310b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld3lane: 45320b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 45330b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i8); 45340b57cec5SDimitry Andric return; 45350b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 45365ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 45370b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i16); 45380b57cec5SDimitry Andric return; 45390b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 45400b57cec5SDimitry Andric VT == MVT::v2f32) { 45410b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i32); 45420b57cec5SDimitry Andric return; 45430b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 45440b57cec5SDimitry Andric VT == MVT::v1f64) { 45450b57cec5SDimitry Andric SelectLoadLane(Node, 3, AArch64::LD3i64); 45460b57cec5SDimitry Andric return; 45470b57cec5SDimitry Andric } 45480b57cec5SDimitry Andric break; 45490b57cec5SDimitry Andric case Intrinsic::aarch64_neon_ld4lane: 45500b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 45510b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i8); 45520b57cec5SDimitry Andric return; 45530b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 45545ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 45550b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i16); 45560b57cec5SDimitry Andric return; 45570b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 45580b57cec5SDimitry Andric VT == MVT::v2f32) { 45590b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i32); 45600b57cec5SDimitry Andric return; 45610b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 45620b57cec5SDimitry Andric VT == MVT::v1f64) { 45630b57cec5SDimitry Andric SelectLoadLane(Node, 4, AArch64::LD4i64); 45640b57cec5SDimitry Andric return; 45650b57cec5SDimitry Andric } 45660b57cec5SDimitry Andric break; 4567e8d8bef9SDimitry Andric case Intrinsic::aarch64_ld64b: 4568e8d8bef9SDimitry Andric SelectLoad(Node, 8, AArch64::LD64B, AArch64::x8sub_0); 4569e8d8bef9SDimitry Andric return; 4570349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: { 4571349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4572349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B, 4573349cc55cSDimitry Andric true); 4574349cc55cSDimitry Andric return; 4575349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 457681ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4577349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H, 4578349cc55cSDimitry Andric true); 4579349cc55cSDimitry Andric return; 4580349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4581349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W, 4582349cc55cSDimitry Andric true); 4583349cc55cSDimitry Andric return; 4584349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4585349cc55cSDimitry Andric SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D, 4586349cc55cSDimitry Andric true); 4587349cc55cSDimitry Andric return; 4588349cc55cSDimitry Andric } 4589349cc55cSDimitry Andric break; 4590349cc55cSDimitry Andric } 4591349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: { 4592349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4593349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B, 4594349cc55cSDimitry Andric true); 4595349cc55cSDimitry Andric return; 4596349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 459781ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4598349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H, 4599349cc55cSDimitry Andric true); 4600349cc55cSDimitry Andric return; 4601349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4602349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W, 4603349cc55cSDimitry Andric true); 4604349cc55cSDimitry Andric return; 4605349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4606349cc55cSDimitry Andric SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D, 4607349cc55cSDimitry Andric true); 4608349cc55cSDimitry Andric return; 4609349cc55cSDimitry Andric } 4610349cc55cSDimitry Andric break; 4611349cc55cSDimitry Andric } 4612349cc55cSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: { 4613349cc55cSDimitry Andric if (VT == MVT::nxv16i8) { 4614349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B, 4615349cc55cSDimitry Andric true); 4616349cc55cSDimitry Andric return; 4617349cc55cSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 461881ad6265SDimitry Andric VT == MVT::nxv8bf16) { 4619349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H, 4620349cc55cSDimitry Andric true); 4621349cc55cSDimitry Andric return; 4622349cc55cSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 4623349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W, 4624349cc55cSDimitry Andric true); 4625349cc55cSDimitry Andric return; 4626349cc55cSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 4627349cc55cSDimitry Andric SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D, 4628349cc55cSDimitry Andric true); 4629349cc55cSDimitry Andric return; 4630349cc55cSDimitry Andric } 4631349cc55cSDimitry Andric break; 4632349cc55cSDimitry Andric } 4633fcaf7f86SDimitry Andric case Intrinsic::swift_async_context_addr: { 4634fcaf7f86SDimitry Andric SDLoc DL(Node); 4635fcaf7f86SDimitry Andric SDValue Chain = Node->getOperand(0); 4636fcaf7f86SDimitry Andric SDValue CopyFP = CurDAG->getCopyFromReg(Chain, DL, AArch64::FP, MVT::i64); 4637fcaf7f86SDimitry Andric SDValue Res = SDValue( 4638fcaf7f86SDimitry Andric CurDAG->getMachineNode(AArch64::SUBXri, DL, MVT::i64, CopyFP, 4639fcaf7f86SDimitry Andric CurDAG->getTargetConstant(8, DL, MVT::i32), 4640fcaf7f86SDimitry Andric CurDAG->getTargetConstant(0, DL, MVT::i32)), 4641fcaf7f86SDimitry Andric 0); 4642fcaf7f86SDimitry Andric ReplaceUses(SDValue(Node, 0), Res); 4643fcaf7f86SDimitry Andric ReplaceUses(SDValue(Node, 1), CopyFP.getValue(1)); 4644fcaf7f86SDimitry Andric CurDAG->RemoveDeadNode(Node); 4645fcaf7f86SDimitry Andric 4646fcaf7f86SDimitry Andric auto &MF = CurDAG->getMachineFunction(); 4647fcaf7f86SDimitry Andric MF.getFrameInfo().setFrameAddressIsTaken(true); 4648fcaf7f86SDimitry Andric MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); 4649fcaf7f86SDimitry Andric return; 4650fcaf7f86SDimitry Andric } 46510b57cec5SDimitry Andric } 46520b57cec5SDimitry Andric } break; 46530b57cec5SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 46540b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue(); 46550b57cec5SDimitry Andric switch (IntNo) { 46560b57cec5SDimitry Andric default: 46570b57cec5SDimitry Andric break; 46580b57cec5SDimitry Andric case Intrinsic::aarch64_tagp: 46590b57cec5SDimitry Andric SelectTagP(Node); 46600b57cec5SDimitry Andric return; 46610b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl2: 46620b57cec5SDimitry Andric SelectTable(Node, 2, 46630b57cec5SDimitry Andric VT == MVT::v8i8 ? AArch64::TBLv8i8Two : AArch64::TBLv16i8Two, 46640b57cec5SDimitry Andric false); 46650b57cec5SDimitry Andric return; 46660b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl3: 46670b57cec5SDimitry Andric SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBLv8i8Three 46680b57cec5SDimitry Andric : AArch64::TBLv16i8Three, 46690b57cec5SDimitry Andric false); 46700b57cec5SDimitry Andric return; 46710b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbl4: 46720b57cec5SDimitry Andric SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBLv8i8Four 46730b57cec5SDimitry Andric : AArch64::TBLv16i8Four, 46740b57cec5SDimitry Andric false); 46750b57cec5SDimitry Andric return; 46760b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx2: 46770b57cec5SDimitry Andric SelectTable(Node, 2, 46780b57cec5SDimitry Andric VT == MVT::v8i8 ? AArch64::TBXv8i8Two : AArch64::TBXv16i8Two, 46790b57cec5SDimitry Andric true); 46800b57cec5SDimitry Andric return; 46810b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx3: 46820b57cec5SDimitry Andric SelectTable(Node, 3, VT == MVT::v8i8 ? AArch64::TBXv8i8Three 46830b57cec5SDimitry Andric : AArch64::TBXv16i8Three, 46840b57cec5SDimitry Andric true); 46850b57cec5SDimitry Andric return; 46860b57cec5SDimitry Andric case Intrinsic::aarch64_neon_tbx4: 46870b57cec5SDimitry Andric SelectTable(Node, 4, VT == MVT::v8i8 ? AArch64::TBXv8i8Four 46880b57cec5SDimitry Andric : AArch64::TBXv16i8Four, 46890b57cec5SDimitry Andric true); 46900b57cec5SDimitry Andric return; 46910b57cec5SDimitry Andric case Intrinsic::aarch64_neon_smull: 46920b57cec5SDimitry Andric case Intrinsic::aarch64_neon_umull: 46930b57cec5SDimitry Andric if (tryMULLV64LaneV128(IntNo, Node)) 46940b57cec5SDimitry Andric return; 46950b57cec5SDimitry Andric break; 4696*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilege_x2: 4697*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4698*bdd1243dSDimitry Andric Node->getValueType(0), 4699*bdd1243dSDimitry Andric {AArch64::WHILEGE_2PXX_B, AArch64::WHILEGE_2PXX_H, 4700*bdd1243dSDimitry Andric AArch64::WHILEGE_2PXX_S, AArch64::WHILEGE_2PXX_D})) 4701*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4702*bdd1243dSDimitry Andric return; 4703*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilegt_x2: 4704*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4705*bdd1243dSDimitry Andric Node->getValueType(0), 4706*bdd1243dSDimitry Andric {AArch64::WHILEGT_2PXX_B, AArch64::WHILEGT_2PXX_H, 4707*bdd1243dSDimitry Andric AArch64::WHILEGT_2PXX_S, AArch64::WHILEGT_2PXX_D})) 4708*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4709*bdd1243dSDimitry Andric return; 4710*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilehi_x2: 4711*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4712*bdd1243dSDimitry Andric Node->getValueType(0), 4713*bdd1243dSDimitry Andric {AArch64::WHILEHI_2PXX_B, AArch64::WHILEHI_2PXX_H, 4714*bdd1243dSDimitry Andric AArch64::WHILEHI_2PXX_S, AArch64::WHILEHI_2PXX_D})) 4715*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4716*bdd1243dSDimitry Andric return; 4717*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilehs_x2: 4718*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4719*bdd1243dSDimitry Andric Node->getValueType(0), 4720*bdd1243dSDimitry Andric {AArch64::WHILEHS_2PXX_B, AArch64::WHILEHS_2PXX_H, 4721*bdd1243dSDimitry Andric AArch64::WHILEHS_2PXX_S, AArch64::WHILEHS_2PXX_D})) 4722*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4723*bdd1243dSDimitry Andric return; 4724*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilele_x2: 4725*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4726*bdd1243dSDimitry Andric Node->getValueType(0), 4727*bdd1243dSDimitry Andric {AArch64::WHILELE_2PXX_B, AArch64::WHILELE_2PXX_H, 4728*bdd1243dSDimitry Andric AArch64::WHILELE_2PXX_S, AArch64::WHILELE_2PXX_D})) 4729*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4730*bdd1243dSDimitry Andric return; 4731*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilelo_x2: 4732*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4733*bdd1243dSDimitry Andric Node->getValueType(0), 4734*bdd1243dSDimitry Andric {AArch64::WHILELO_2PXX_B, AArch64::WHILELO_2PXX_H, 4735*bdd1243dSDimitry Andric AArch64::WHILELO_2PXX_S, AArch64::WHILELO_2PXX_D})) 4736*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4737*bdd1243dSDimitry Andric return; 4738*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilels_x2: 4739*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4740*bdd1243dSDimitry Andric Node->getValueType(0), 4741*bdd1243dSDimitry Andric {AArch64::WHILELS_2PXX_B, AArch64::WHILELS_2PXX_H, 4742*bdd1243dSDimitry Andric AArch64::WHILELS_2PXX_S, AArch64::WHILELS_2PXX_D})) 4743*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4744*bdd1243dSDimitry Andric return; 4745*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_whilelt_x2: 4746*bdd1243dSDimitry Andric if (auto Op = SelectOpcodeFromVT<SelectTypeKind::Int1>( 4747*bdd1243dSDimitry Andric Node->getValueType(0), 4748*bdd1243dSDimitry Andric {AArch64::WHILELT_2PXX_B, AArch64::WHILELT_2PXX_H, 4749*bdd1243dSDimitry Andric AArch64::WHILELT_2PXX_S, AArch64::WHILELT_2PXX_D})) 4750*bdd1243dSDimitry Andric SelectWhilePair(Node, Op); 4751*bdd1243dSDimitry Andric return; 4752*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvts_x2: 4753*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::FCVTZS_2Z2Z_StoS); 4754*bdd1243dSDimitry Andric return; 4755*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_scvtf_x2: 4756*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::SCVTF_2Z2Z_StoS); 4757*bdd1243dSDimitry Andric return; 4758*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvtu_x2: 4759*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::FCVTZU_2Z2Z_StoS); 4760*bdd1243dSDimitry Andric return; 4761*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ucvtf_x2: 4762*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 2, AArch64::UCVTF_2Z2Z_StoS); 4763*bdd1243dSDimitry Andric return; 4764*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvts_x4: 4765*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::FCVTZS_4Z4Z_StoS); 4766*bdd1243dSDimitry Andric return; 4767*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_scvtf_x4: 4768*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::SCVTF_4Z4Z_StoS); 4769*bdd1243dSDimitry Andric return; 4770*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_fcvtu_x4: 4771*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::FCVTZU_4Z4Z_StoS); 4772*bdd1243dSDimitry Andric return; 4773*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ucvtf_x4: 4774*bdd1243dSDimitry Andric SelectCVTIntrinsic(Node, 4, AArch64::UCVTF_4Z4Z_StoS); 4775*bdd1243dSDimitry Andric return; 47760b57cec5SDimitry Andric } 47770b57cec5SDimitry Andric break; 47780b57cec5SDimitry Andric } 47790b57cec5SDimitry Andric case ISD::INTRINSIC_VOID: { 47800b57cec5SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 47810b57cec5SDimitry Andric if (Node->getNumOperands() >= 3) 47820b57cec5SDimitry Andric VT = Node->getOperand(2)->getValueType(0); 47830b57cec5SDimitry Andric switch (IntNo) { 47840b57cec5SDimitry Andric default: 47850b57cec5SDimitry Andric break; 47860b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x2: { 47870b57cec5SDimitry Andric if (VT == MVT::v8i8) { 47880b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov8b); 47890b57cec5SDimitry Andric return; 47900b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 47910b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov16b); 47920b57cec5SDimitry Andric return; 47935ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 47945ffd83dbSDimitry Andric VT == MVT::v4bf16) { 47950b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov4h); 47960b57cec5SDimitry Andric return; 47975ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 47985ffd83dbSDimitry Andric VT == MVT::v8bf16) { 47990b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov8h); 48000b57cec5SDimitry Andric return; 48010b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 48020b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov2s); 48030b57cec5SDimitry Andric return; 48040b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 48050b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov4s); 48060b57cec5SDimitry Andric return; 48070b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 48080b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov2d); 48090b57cec5SDimitry Andric return; 48100b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 48110b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov1d); 48120b57cec5SDimitry Andric return; 48130b57cec5SDimitry Andric } 48140b57cec5SDimitry Andric break; 48150b57cec5SDimitry Andric } 48160b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x3: { 48170b57cec5SDimitry Andric if (VT == MVT::v8i8) { 48180b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev8b); 48190b57cec5SDimitry Andric return; 48200b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 48210b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev16b); 48220b57cec5SDimitry Andric return; 48235ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 48245ffd83dbSDimitry Andric VT == MVT::v4bf16) { 48250b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev4h); 48260b57cec5SDimitry Andric return; 48275ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 48285ffd83dbSDimitry Andric VT == MVT::v8bf16) { 48290b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev8h); 48300b57cec5SDimitry Andric return; 48310b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 48320b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev2s); 48330b57cec5SDimitry Andric return; 48340b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 48350b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev4s); 48360b57cec5SDimitry Andric return; 48370b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 48380b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev2d); 48390b57cec5SDimitry Andric return; 48400b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 48410b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev1d); 48420b57cec5SDimitry Andric return; 48430b57cec5SDimitry Andric } 48440b57cec5SDimitry Andric break; 48450b57cec5SDimitry Andric } 48460b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st1x4: { 48470b57cec5SDimitry Andric if (VT == MVT::v8i8) { 48480b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv8b); 48490b57cec5SDimitry Andric return; 48500b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 48510b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv16b); 48520b57cec5SDimitry Andric return; 48535ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 48545ffd83dbSDimitry Andric VT == MVT::v4bf16) { 48550b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv4h); 48560b57cec5SDimitry Andric return; 48575ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 48585ffd83dbSDimitry Andric VT == MVT::v8bf16) { 48590b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv8h); 48600b57cec5SDimitry Andric return; 48610b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 48620b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv2s); 48630b57cec5SDimitry Andric return; 48640b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 48650b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv4s); 48660b57cec5SDimitry Andric return; 48670b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 48680b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv2d); 48690b57cec5SDimitry Andric return; 48700b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 48710b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv1d); 48720b57cec5SDimitry Andric return; 48730b57cec5SDimitry Andric } 48740b57cec5SDimitry Andric break; 48750b57cec5SDimitry Andric } 48760b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st2: { 48770b57cec5SDimitry Andric if (VT == MVT::v8i8) { 48780b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov8b); 48790b57cec5SDimitry Andric return; 48800b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 48810b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov16b); 48820b57cec5SDimitry Andric return; 48835ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 48845ffd83dbSDimitry Andric VT == MVT::v4bf16) { 48850b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov4h); 48860b57cec5SDimitry Andric return; 48875ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 48885ffd83dbSDimitry Andric VT == MVT::v8bf16) { 48890b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov8h); 48900b57cec5SDimitry Andric return; 48910b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 48920b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov2s); 48930b57cec5SDimitry Andric return; 48940b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 48950b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov4s); 48960b57cec5SDimitry Andric return; 48970b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 48980b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST2Twov2d); 48990b57cec5SDimitry Andric return; 49000b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 49010b57cec5SDimitry Andric SelectStore(Node, 2, AArch64::ST1Twov1d); 49020b57cec5SDimitry Andric return; 49030b57cec5SDimitry Andric } 49040b57cec5SDimitry Andric break; 49050b57cec5SDimitry Andric } 49060b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st3: { 49070b57cec5SDimitry Andric if (VT == MVT::v8i8) { 49080b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev8b); 49090b57cec5SDimitry Andric return; 49100b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 49110b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev16b); 49120b57cec5SDimitry Andric return; 49135ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 49145ffd83dbSDimitry Andric VT == MVT::v4bf16) { 49150b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev4h); 49160b57cec5SDimitry Andric return; 49175ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 49185ffd83dbSDimitry Andric VT == MVT::v8bf16) { 49190b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev8h); 49200b57cec5SDimitry Andric return; 49210b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 49220b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev2s); 49230b57cec5SDimitry Andric return; 49240b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 49250b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev4s); 49260b57cec5SDimitry Andric return; 49270b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 49280b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST3Threev2d); 49290b57cec5SDimitry Andric return; 49300b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 49310b57cec5SDimitry Andric SelectStore(Node, 3, AArch64::ST1Threev1d); 49320b57cec5SDimitry Andric return; 49330b57cec5SDimitry Andric } 49340b57cec5SDimitry Andric break; 49350b57cec5SDimitry Andric } 49360b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st4: { 49370b57cec5SDimitry Andric if (VT == MVT::v8i8) { 49380b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv8b); 49390b57cec5SDimitry Andric return; 49400b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 49410b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv16b); 49420b57cec5SDimitry Andric return; 49435ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || 49445ffd83dbSDimitry Andric VT == MVT::v4bf16) { 49450b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv4h); 49460b57cec5SDimitry Andric return; 49475ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || 49485ffd83dbSDimitry Andric VT == MVT::v8bf16) { 49490b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv8h); 49500b57cec5SDimitry Andric return; 49510b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 49520b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv2s); 49530b57cec5SDimitry Andric return; 49540b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 49550b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv4s); 49560b57cec5SDimitry Andric return; 49570b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 49580b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST4Fourv2d); 49590b57cec5SDimitry Andric return; 49600b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 49610b57cec5SDimitry Andric SelectStore(Node, 4, AArch64::ST1Fourv1d); 49620b57cec5SDimitry Andric return; 49630b57cec5SDimitry Andric } 49640b57cec5SDimitry Andric break; 49650b57cec5SDimitry Andric } 49660b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st2lane: { 49670b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 49680b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i8); 49690b57cec5SDimitry Andric return; 49700b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 49715ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 49720b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i16); 49730b57cec5SDimitry Andric return; 49740b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 49750b57cec5SDimitry Andric VT == MVT::v2f32) { 49760b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i32); 49770b57cec5SDimitry Andric return; 49780b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 49790b57cec5SDimitry Andric VT == MVT::v1f64) { 49800b57cec5SDimitry Andric SelectStoreLane(Node, 2, AArch64::ST2i64); 49810b57cec5SDimitry Andric return; 49820b57cec5SDimitry Andric } 49830b57cec5SDimitry Andric break; 49840b57cec5SDimitry Andric } 49850b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st3lane: { 49860b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 49870b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i8); 49880b57cec5SDimitry Andric return; 49890b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 49905ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 49910b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i16); 49920b57cec5SDimitry Andric return; 49930b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 49940b57cec5SDimitry Andric VT == MVT::v2f32) { 49950b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i32); 49960b57cec5SDimitry Andric return; 49970b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 49980b57cec5SDimitry Andric VT == MVT::v1f64) { 49990b57cec5SDimitry Andric SelectStoreLane(Node, 3, AArch64::ST3i64); 50000b57cec5SDimitry Andric return; 50010b57cec5SDimitry Andric } 50020b57cec5SDimitry Andric break; 50030b57cec5SDimitry Andric } 50040b57cec5SDimitry Andric case Intrinsic::aarch64_neon_st4lane: { 50050b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 50060b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i8); 50070b57cec5SDimitry Andric return; 50080b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 50095ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 50100b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i16); 50110b57cec5SDimitry Andric return; 50120b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 50130b57cec5SDimitry Andric VT == MVT::v2f32) { 50140b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i32); 50150b57cec5SDimitry Andric return; 50160b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 50170b57cec5SDimitry Andric VT == MVT::v1f64) { 50180b57cec5SDimitry Andric SelectStoreLane(Node, 4, AArch64::ST4i64); 50190b57cec5SDimitry Andric return; 50200b57cec5SDimitry Andric } 50210b57cec5SDimitry Andric break; 50220b57cec5SDimitry Andric } 50235ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st2: { 50245ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 5025979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 0, AArch64::ST2B, AArch64::ST2B_IMM); 50265ffd83dbSDimitry Andric return; 50275ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 502881ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5029979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 1, AArch64::ST2H, AArch64::ST2H_IMM); 50305ffd83dbSDimitry Andric return; 50315ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5032979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 2, AArch64::ST2W, AArch64::ST2W_IMM); 50335ffd83dbSDimitry Andric return; 50345ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5035979e22ffSDimitry Andric SelectPredicatedStore(Node, 2, 3, AArch64::ST2D, AArch64::ST2D_IMM); 50365ffd83dbSDimitry Andric return; 50375ffd83dbSDimitry Andric } 50385ffd83dbSDimitry Andric break; 50395ffd83dbSDimitry Andric } 50405ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st3: { 50415ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 5042979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 0, AArch64::ST3B, AArch64::ST3B_IMM); 50435ffd83dbSDimitry Andric return; 50445ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 504581ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5046979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 1, AArch64::ST3H, AArch64::ST3H_IMM); 50475ffd83dbSDimitry Andric return; 50485ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5049979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 2, AArch64::ST3W, AArch64::ST3W_IMM); 50505ffd83dbSDimitry Andric return; 50515ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5052979e22ffSDimitry Andric SelectPredicatedStore(Node, 3, 3, AArch64::ST3D, AArch64::ST3D_IMM); 50535ffd83dbSDimitry Andric return; 50545ffd83dbSDimitry Andric } 50555ffd83dbSDimitry Andric break; 50565ffd83dbSDimitry Andric } 50575ffd83dbSDimitry Andric case Intrinsic::aarch64_sve_st4: { 50585ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 5059979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 0, AArch64::ST4B, AArch64::ST4B_IMM); 50605ffd83dbSDimitry Andric return; 50615ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 506281ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5063979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 1, AArch64::ST4H, AArch64::ST4H_IMM); 50645ffd83dbSDimitry Andric return; 50655ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5066979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 2, AArch64::ST4W, AArch64::ST4W_IMM); 50675ffd83dbSDimitry Andric return; 50685ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5069979e22ffSDimitry Andric SelectPredicatedStore(Node, 4, 3, AArch64::ST4D, AArch64::ST4D_IMM); 50705ffd83dbSDimitry Andric return; 50715ffd83dbSDimitry Andric } 50725ffd83dbSDimitry Andric break; 50735ffd83dbSDimitry Andric } 50740b57cec5SDimitry Andric } 50750b57cec5SDimitry Andric break; 50760b57cec5SDimitry Andric } 50770b57cec5SDimitry Andric case AArch64ISD::LD2post: { 50780b57cec5SDimitry Andric if (VT == MVT::v8i8) { 50790b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov8b_POST, AArch64::dsub0); 50800b57cec5SDimitry Andric return; 50810b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 50820b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov16b_POST, AArch64::qsub0); 50830b57cec5SDimitry Andric return; 50845ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 50850b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov4h_POST, AArch64::dsub0); 50860b57cec5SDimitry Andric return; 50875ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 50880b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov8h_POST, AArch64::qsub0); 50890b57cec5SDimitry Andric return; 50900b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 50910b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov2s_POST, AArch64::dsub0); 50920b57cec5SDimitry Andric return; 50930b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 50940b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov4s_POST, AArch64::qsub0); 50950b57cec5SDimitry Andric return; 50960b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 50970b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0); 50980b57cec5SDimitry Andric return; 50990b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 51000b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Twov2d_POST, AArch64::qsub0); 51010b57cec5SDimitry Andric return; 51020b57cec5SDimitry Andric } 51030b57cec5SDimitry Andric break; 51040b57cec5SDimitry Andric } 51050b57cec5SDimitry Andric case AArch64ISD::LD3post: { 51060b57cec5SDimitry Andric if (VT == MVT::v8i8) { 51070b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev8b_POST, AArch64::dsub0); 51080b57cec5SDimitry Andric return; 51090b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 51100b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev16b_POST, AArch64::qsub0); 51110b57cec5SDimitry Andric return; 51125ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 51130b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev4h_POST, AArch64::dsub0); 51140b57cec5SDimitry Andric return; 51155ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 51160b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev8h_POST, AArch64::qsub0); 51170b57cec5SDimitry Andric return; 51180b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 51190b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev2s_POST, AArch64::dsub0); 51200b57cec5SDimitry Andric return; 51210b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 51220b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev4s_POST, AArch64::qsub0); 51230b57cec5SDimitry Andric return; 51240b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 51250b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0); 51260b57cec5SDimitry Andric return; 51270b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 51280b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Threev2d_POST, AArch64::qsub0); 51290b57cec5SDimitry Andric return; 51300b57cec5SDimitry Andric } 51310b57cec5SDimitry Andric break; 51320b57cec5SDimitry Andric } 51330b57cec5SDimitry Andric case AArch64ISD::LD4post: { 51340b57cec5SDimitry Andric if (VT == MVT::v8i8) { 51350b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv8b_POST, AArch64::dsub0); 51360b57cec5SDimitry Andric return; 51370b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 51380b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv16b_POST, AArch64::qsub0); 51390b57cec5SDimitry Andric return; 51405ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 51410b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv4h_POST, AArch64::dsub0); 51420b57cec5SDimitry Andric return; 51435ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 51440b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv8h_POST, AArch64::qsub0); 51450b57cec5SDimitry Andric return; 51460b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 51470b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv2s_POST, AArch64::dsub0); 51480b57cec5SDimitry Andric return; 51490b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 51500b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv4s_POST, AArch64::qsub0); 51510b57cec5SDimitry Andric return; 51520b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 51530b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0); 51540b57cec5SDimitry Andric return; 51550b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 51560b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Fourv2d_POST, AArch64::qsub0); 51570b57cec5SDimitry Andric return; 51580b57cec5SDimitry Andric } 51590b57cec5SDimitry Andric break; 51600b57cec5SDimitry Andric } 51610b57cec5SDimitry Andric case AArch64ISD::LD1x2post: { 51620b57cec5SDimitry Andric if (VT == MVT::v8i8) { 51630b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov8b_POST, AArch64::dsub0); 51640b57cec5SDimitry Andric return; 51650b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 51660b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov16b_POST, AArch64::qsub0); 51670b57cec5SDimitry Andric return; 51685ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 51690b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov4h_POST, AArch64::dsub0); 51700b57cec5SDimitry Andric return; 51715ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 51720b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov8h_POST, AArch64::qsub0); 51730b57cec5SDimitry Andric return; 51740b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 51750b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov2s_POST, AArch64::dsub0); 51760b57cec5SDimitry Andric return; 51770b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 51780b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov4s_POST, AArch64::qsub0); 51790b57cec5SDimitry Andric return; 51800b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 51810b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov1d_POST, AArch64::dsub0); 51820b57cec5SDimitry Andric return; 51830b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 51840b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD1Twov2d_POST, AArch64::qsub0); 51850b57cec5SDimitry Andric return; 51860b57cec5SDimitry Andric } 51870b57cec5SDimitry Andric break; 51880b57cec5SDimitry Andric } 51890b57cec5SDimitry Andric case AArch64ISD::LD1x3post: { 51900b57cec5SDimitry Andric if (VT == MVT::v8i8) { 51910b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev8b_POST, AArch64::dsub0); 51920b57cec5SDimitry Andric return; 51930b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 51940b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev16b_POST, AArch64::qsub0); 51950b57cec5SDimitry Andric return; 51965ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 51970b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev4h_POST, AArch64::dsub0); 51980b57cec5SDimitry Andric return; 51995ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 52000b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev8h_POST, AArch64::qsub0); 52010b57cec5SDimitry Andric return; 52020b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 52030b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev2s_POST, AArch64::dsub0); 52040b57cec5SDimitry Andric return; 52050b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 52060b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev4s_POST, AArch64::qsub0); 52070b57cec5SDimitry Andric return; 52080b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 52090b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev1d_POST, AArch64::dsub0); 52100b57cec5SDimitry Andric return; 52110b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 52120b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD1Threev2d_POST, AArch64::qsub0); 52130b57cec5SDimitry Andric return; 52140b57cec5SDimitry Andric } 52150b57cec5SDimitry Andric break; 52160b57cec5SDimitry Andric } 52170b57cec5SDimitry Andric case AArch64ISD::LD1x4post: { 52180b57cec5SDimitry Andric if (VT == MVT::v8i8) { 52190b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv8b_POST, AArch64::dsub0); 52200b57cec5SDimitry Andric return; 52210b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 52220b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv16b_POST, AArch64::qsub0); 52230b57cec5SDimitry Andric return; 52245ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 52250b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv4h_POST, AArch64::dsub0); 52260b57cec5SDimitry Andric return; 52275ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 52280b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv8h_POST, AArch64::qsub0); 52290b57cec5SDimitry Andric return; 52300b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 52310b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv2s_POST, AArch64::dsub0); 52320b57cec5SDimitry Andric return; 52330b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 52340b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv4s_POST, AArch64::qsub0); 52350b57cec5SDimitry Andric return; 52360b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 52370b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv1d_POST, AArch64::dsub0); 52380b57cec5SDimitry Andric return; 52390b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 52400b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD1Fourv2d_POST, AArch64::qsub0); 52410b57cec5SDimitry Andric return; 52420b57cec5SDimitry Andric } 52430b57cec5SDimitry Andric break; 52440b57cec5SDimitry Andric } 52450b57cec5SDimitry Andric case AArch64ISD::LD1DUPpost: { 52460b57cec5SDimitry Andric if (VT == MVT::v8i8) { 52470b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv8b_POST, AArch64::dsub0); 52480b57cec5SDimitry Andric return; 52490b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 52500b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv16b_POST, AArch64::qsub0); 52510b57cec5SDimitry Andric return; 52525ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 52530b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv4h_POST, AArch64::dsub0); 52540b57cec5SDimitry Andric return; 52555ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 52560b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv8h_POST, AArch64::qsub0); 52570b57cec5SDimitry Andric return; 52580b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 52590b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv2s_POST, AArch64::dsub0); 52600b57cec5SDimitry Andric return; 52610b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 52620b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv4s_POST, AArch64::qsub0); 52630b57cec5SDimitry Andric return; 52640b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 52650b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv1d_POST, AArch64::dsub0); 52660b57cec5SDimitry Andric return; 52670b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 52680b57cec5SDimitry Andric SelectPostLoad(Node, 1, AArch64::LD1Rv2d_POST, AArch64::qsub0); 52690b57cec5SDimitry Andric return; 52700b57cec5SDimitry Andric } 52710b57cec5SDimitry Andric break; 52720b57cec5SDimitry Andric } 52730b57cec5SDimitry Andric case AArch64ISD::LD2DUPpost: { 52740b57cec5SDimitry Andric if (VT == MVT::v8i8) { 52750b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv8b_POST, AArch64::dsub0); 52760b57cec5SDimitry Andric return; 52770b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 52780b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv16b_POST, AArch64::qsub0); 52790b57cec5SDimitry Andric return; 52805ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 52810b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv4h_POST, AArch64::dsub0); 52820b57cec5SDimitry Andric return; 52835ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 52840b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv8h_POST, AArch64::qsub0); 52850b57cec5SDimitry Andric return; 52860b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 52870b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv2s_POST, AArch64::dsub0); 52880b57cec5SDimitry Andric return; 52890b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 52900b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv4s_POST, AArch64::qsub0); 52910b57cec5SDimitry Andric return; 52920b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 52930b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv1d_POST, AArch64::dsub0); 52940b57cec5SDimitry Andric return; 52950b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 52960b57cec5SDimitry Andric SelectPostLoad(Node, 2, AArch64::LD2Rv2d_POST, AArch64::qsub0); 52970b57cec5SDimitry Andric return; 52980b57cec5SDimitry Andric } 52990b57cec5SDimitry Andric break; 53000b57cec5SDimitry Andric } 53010b57cec5SDimitry Andric case AArch64ISD::LD3DUPpost: { 53020b57cec5SDimitry Andric if (VT == MVT::v8i8) { 53030b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv8b_POST, AArch64::dsub0); 53040b57cec5SDimitry Andric return; 53050b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 53060b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv16b_POST, AArch64::qsub0); 53070b57cec5SDimitry Andric return; 53085ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 53090b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv4h_POST, AArch64::dsub0); 53100b57cec5SDimitry Andric return; 53115ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 53120b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv8h_POST, AArch64::qsub0); 53130b57cec5SDimitry Andric return; 53140b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 53150b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv2s_POST, AArch64::dsub0); 53160b57cec5SDimitry Andric return; 53170b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 53180b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv4s_POST, AArch64::qsub0); 53190b57cec5SDimitry Andric return; 53200b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 53210b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv1d_POST, AArch64::dsub0); 53220b57cec5SDimitry Andric return; 53230b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 53240b57cec5SDimitry Andric SelectPostLoad(Node, 3, AArch64::LD3Rv2d_POST, AArch64::qsub0); 53250b57cec5SDimitry Andric return; 53260b57cec5SDimitry Andric } 53270b57cec5SDimitry Andric break; 53280b57cec5SDimitry Andric } 53290b57cec5SDimitry Andric case AArch64ISD::LD4DUPpost: { 53300b57cec5SDimitry Andric if (VT == MVT::v8i8) { 53310b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv8b_POST, AArch64::dsub0); 53320b57cec5SDimitry Andric return; 53330b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 53340b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv16b_POST, AArch64::qsub0); 53350b57cec5SDimitry Andric return; 53365ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 53370b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv4h_POST, AArch64::dsub0); 53380b57cec5SDimitry Andric return; 53395ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 53400b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv8h_POST, AArch64::qsub0); 53410b57cec5SDimitry Andric return; 53420b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 53430b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv2s_POST, AArch64::dsub0); 53440b57cec5SDimitry Andric return; 53450b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 53460b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv4s_POST, AArch64::qsub0); 53470b57cec5SDimitry Andric return; 53480b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 53490b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv1d_POST, AArch64::dsub0); 53500b57cec5SDimitry Andric return; 53510b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 53520b57cec5SDimitry Andric SelectPostLoad(Node, 4, AArch64::LD4Rv2d_POST, AArch64::qsub0); 53530b57cec5SDimitry Andric return; 53540b57cec5SDimitry Andric } 53550b57cec5SDimitry Andric break; 53560b57cec5SDimitry Andric } 53570b57cec5SDimitry Andric case AArch64ISD::LD1LANEpost: { 53580b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 53590b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i8_POST); 53600b57cec5SDimitry Andric return; 53610b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 53625ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 53630b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i16_POST); 53640b57cec5SDimitry Andric return; 53650b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 53660b57cec5SDimitry Andric VT == MVT::v2f32) { 53670b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i32_POST); 53680b57cec5SDimitry Andric return; 53690b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 53700b57cec5SDimitry Andric VT == MVT::v1f64) { 53710b57cec5SDimitry Andric SelectPostLoadLane(Node, 1, AArch64::LD1i64_POST); 53720b57cec5SDimitry Andric return; 53730b57cec5SDimitry Andric } 53740b57cec5SDimitry Andric break; 53750b57cec5SDimitry Andric } 53760b57cec5SDimitry Andric case AArch64ISD::LD2LANEpost: { 53770b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 53780b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i8_POST); 53790b57cec5SDimitry Andric return; 53800b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 53815ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 53820b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i16_POST); 53830b57cec5SDimitry Andric return; 53840b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 53850b57cec5SDimitry Andric VT == MVT::v2f32) { 53860b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i32_POST); 53870b57cec5SDimitry Andric return; 53880b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 53890b57cec5SDimitry Andric VT == MVT::v1f64) { 53900b57cec5SDimitry Andric SelectPostLoadLane(Node, 2, AArch64::LD2i64_POST); 53910b57cec5SDimitry Andric return; 53920b57cec5SDimitry Andric } 53930b57cec5SDimitry Andric break; 53940b57cec5SDimitry Andric } 53950b57cec5SDimitry Andric case AArch64ISD::LD3LANEpost: { 53960b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 53970b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i8_POST); 53980b57cec5SDimitry Andric return; 53990b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 54005ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 54010b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i16_POST); 54020b57cec5SDimitry Andric return; 54030b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 54040b57cec5SDimitry Andric VT == MVT::v2f32) { 54050b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i32_POST); 54060b57cec5SDimitry Andric return; 54070b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 54080b57cec5SDimitry Andric VT == MVT::v1f64) { 54090b57cec5SDimitry Andric SelectPostLoadLane(Node, 3, AArch64::LD3i64_POST); 54100b57cec5SDimitry Andric return; 54110b57cec5SDimitry Andric } 54120b57cec5SDimitry Andric break; 54130b57cec5SDimitry Andric } 54140b57cec5SDimitry Andric case AArch64ISD::LD4LANEpost: { 54150b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 54160b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i8_POST); 54170b57cec5SDimitry Andric return; 54180b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 54195ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 54200b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i16_POST); 54210b57cec5SDimitry Andric return; 54220b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 54230b57cec5SDimitry Andric VT == MVT::v2f32) { 54240b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i32_POST); 54250b57cec5SDimitry Andric return; 54260b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 54270b57cec5SDimitry Andric VT == MVT::v1f64) { 54280b57cec5SDimitry Andric SelectPostLoadLane(Node, 4, AArch64::LD4i64_POST); 54290b57cec5SDimitry Andric return; 54300b57cec5SDimitry Andric } 54310b57cec5SDimitry Andric break; 54320b57cec5SDimitry Andric } 54330b57cec5SDimitry Andric case AArch64ISD::ST2post: { 54340b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 54350b57cec5SDimitry Andric if (VT == MVT::v8i8) { 54360b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov8b_POST); 54370b57cec5SDimitry Andric return; 54380b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 54390b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov16b_POST); 54400b57cec5SDimitry Andric return; 54415ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 54420b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov4h_POST); 54430b57cec5SDimitry Andric return; 54445ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 54450b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov8h_POST); 54460b57cec5SDimitry Andric return; 54470b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 54480b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov2s_POST); 54490b57cec5SDimitry Andric return; 54500b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 54510b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov4s_POST); 54520b57cec5SDimitry Andric return; 54530b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 54540b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST2Twov2d_POST); 54550b57cec5SDimitry Andric return; 54560b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 54570b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST); 54580b57cec5SDimitry Andric return; 54590b57cec5SDimitry Andric } 54600b57cec5SDimitry Andric break; 54610b57cec5SDimitry Andric } 54620b57cec5SDimitry Andric case AArch64ISD::ST3post: { 54630b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 54640b57cec5SDimitry Andric if (VT == MVT::v8i8) { 54650b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev8b_POST); 54660b57cec5SDimitry Andric return; 54670b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 54680b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev16b_POST); 54690b57cec5SDimitry Andric return; 54705ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 54710b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev4h_POST); 54720b57cec5SDimitry Andric return; 54735ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 54740b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev8h_POST); 54750b57cec5SDimitry Andric return; 54760b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 54770b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev2s_POST); 54780b57cec5SDimitry Andric return; 54790b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 54800b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev4s_POST); 54810b57cec5SDimitry Andric return; 54820b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 54830b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST3Threev2d_POST); 54840b57cec5SDimitry Andric return; 54850b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 54860b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST); 54870b57cec5SDimitry Andric return; 54880b57cec5SDimitry Andric } 54890b57cec5SDimitry Andric break; 54900b57cec5SDimitry Andric } 54910b57cec5SDimitry Andric case AArch64ISD::ST4post: { 54920b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 54930b57cec5SDimitry Andric if (VT == MVT::v8i8) { 54940b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv8b_POST); 54950b57cec5SDimitry Andric return; 54960b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 54970b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv16b_POST); 54980b57cec5SDimitry Andric return; 54995ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 55000b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv4h_POST); 55010b57cec5SDimitry Andric return; 55025ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 55030b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv8h_POST); 55040b57cec5SDimitry Andric return; 55050b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 55060b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv2s_POST); 55070b57cec5SDimitry Andric return; 55080b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 55090b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv4s_POST); 55100b57cec5SDimitry Andric return; 55110b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 55120b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST4Fourv2d_POST); 55130b57cec5SDimitry Andric return; 55140b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 55150b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST); 55160b57cec5SDimitry Andric return; 55170b57cec5SDimitry Andric } 55180b57cec5SDimitry Andric break; 55190b57cec5SDimitry Andric } 55200b57cec5SDimitry Andric case AArch64ISD::ST1x2post: { 55210b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 55220b57cec5SDimitry Andric if (VT == MVT::v8i8) { 55230b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov8b_POST); 55240b57cec5SDimitry Andric return; 55250b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 55260b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov16b_POST); 55270b57cec5SDimitry Andric return; 55285ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 55290b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov4h_POST); 55300b57cec5SDimitry Andric return; 55315ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 55320b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov8h_POST); 55330b57cec5SDimitry Andric return; 55340b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 55350b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov2s_POST); 55360b57cec5SDimitry Andric return; 55370b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 55380b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov4s_POST); 55390b57cec5SDimitry Andric return; 55400b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 55410b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov1d_POST); 55420b57cec5SDimitry Andric return; 55430b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 55440b57cec5SDimitry Andric SelectPostStore(Node, 2, AArch64::ST1Twov2d_POST); 55450b57cec5SDimitry Andric return; 55460b57cec5SDimitry Andric } 55470b57cec5SDimitry Andric break; 55480b57cec5SDimitry Andric } 55490b57cec5SDimitry Andric case AArch64ISD::ST1x3post: { 55500b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 55510b57cec5SDimitry Andric if (VT == MVT::v8i8) { 55520b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev8b_POST); 55530b57cec5SDimitry Andric return; 55540b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 55550b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev16b_POST); 55560b57cec5SDimitry Andric return; 55575ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 55580b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev4h_POST); 55590b57cec5SDimitry Andric return; 55605ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16 ) { 55610b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev8h_POST); 55620b57cec5SDimitry Andric return; 55630b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 55640b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev2s_POST); 55650b57cec5SDimitry Andric return; 55660b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 55670b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev4s_POST); 55680b57cec5SDimitry Andric return; 55690b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 55700b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev1d_POST); 55710b57cec5SDimitry Andric return; 55720b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 55730b57cec5SDimitry Andric SelectPostStore(Node, 3, AArch64::ST1Threev2d_POST); 55740b57cec5SDimitry Andric return; 55750b57cec5SDimitry Andric } 55760b57cec5SDimitry Andric break; 55770b57cec5SDimitry Andric } 55780b57cec5SDimitry Andric case AArch64ISD::ST1x4post: { 55790b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 55800b57cec5SDimitry Andric if (VT == MVT::v8i8) { 55810b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv8b_POST); 55820b57cec5SDimitry Andric return; 55830b57cec5SDimitry Andric } else if (VT == MVT::v16i8) { 55840b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv16b_POST); 55850b57cec5SDimitry Andric return; 55865ffd83dbSDimitry Andric } else if (VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16) { 55870b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv4h_POST); 55880b57cec5SDimitry Andric return; 55895ffd83dbSDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v8bf16) { 55900b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv8h_POST); 55910b57cec5SDimitry Andric return; 55920b57cec5SDimitry Andric } else if (VT == MVT::v2i32 || VT == MVT::v2f32) { 55930b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv2s_POST); 55940b57cec5SDimitry Andric return; 55950b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v4f32) { 55960b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv4s_POST); 55970b57cec5SDimitry Andric return; 55980b57cec5SDimitry Andric } else if (VT == MVT::v1i64 || VT == MVT::v1f64) { 55990b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv1d_POST); 56000b57cec5SDimitry Andric return; 56010b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v2f64) { 56020b57cec5SDimitry Andric SelectPostStore(Node, 4, AArch64::ST1Fourv2d_POST); 56030b57cec5SDimitry Andric return; 56040b57cec5SDimitry Andric } 56050b57cec5SDimitry Andric break; 56060b57cec5SDimitry Andric } 56070b57cec5SDimitry Andric case AArch64ISD::ST2LANEpost: { 56080b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 56090b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 56100b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i8_POST); 56110b57cec5SDimitry Andric return; 56120b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 56135ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 56140b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i16_POST); 56150b57cec5SDimitry Andric return; 56160b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 56170b57cec5SDimitry Andric VT == MVT::v2f32) { 56180b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i32_POST); 56190b57cec5SDimitry Andric return; 56200b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 56210b57cec5SDimitry Andric VT == MVT::v1f64) { 56220b57cec5SDimitry Andric SelectPostStoreLane(Node, 2, AArch64::ST2i64_POST); 56230b57cec5SDimitry Andric return; 56240b57cec5SDimitry Andric } 56250b57cec5SDimitry Andric break; 56260b57cec5SDimitry Andric } 56270b57cec5SDimitry Andric case AArch64ISD::ST3LANEpost: { 56280b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 56290b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 56300b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i8_POST); 56310b57cec5SDimitry Andric return; 56320b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 56335ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 56340b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i16_POST); 56350b57cec5SDimitry Andric return; 56360b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 56370b57cec5SDimitry Andric VT == MVT::v2f32) { 56380b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i32_POST); 56390b57cec5SDimitry Andric return; 56400b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 56410b57cec5SDimitry Andric VT == MVT::v1f64) { 56420b57cec5SDimitry Andric SelectPostStoreLane(Node, 3, AArch64::ST3i64_POST); 56430b57cec5SDimitry Andric return; 56440b57cec5SDimitry Andric } 56450b57cec5SDimitry Andric break; 56460b57cec5SDimitry Andric } 56470b57cec5SDimitry Andric case AArch64ISD::ST4LANEpost: { 56480b57cec5SDimitry Andric VT = Node->getOperand(1).getValueType(); 56490b57cec5SDimitry Andric if (VT == MVT::v16i8 || VT == MVT::v8i8) { 56500b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i8_POST); 56510b57cec5SDimitry Andric return; 56520b57cec5SDimitry Andric } else if (VT == MVT::v8i16 || VT == MVT::v4i16 || VT == MVT::v4f16 || 56535ffd83dbSDimitry Andric VT == MVT::v8f16 || VT == MVT::v4bf16 || VT == MVT::v8bf16) { 56540b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i16_POST); 56550b57cec5SDimitry Andric return; 56560b57cec5SDimitry Andric } else if (VT == MVT::v4i32 || VT == MVT::v2i32 || VT == MVT::v4f32 || 56570b57cec5SDimitry Andric VT == MVT::v2f32) { 56580b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i32_POST); 56590b57cec5SDimitry Andric return; 56600b57cec5SDimitry Andric } else if (VT == MVT::v2i64 || VT == MVT::v1i64 || VT == MVT::v2f64 || 56610b57cec5SDimitry Andric VT == MVT::v1f64) { 56620b57cec5SDimitry Andric SelectPostStoreLane(Node, 4, AArch64::ST4i64_POST); 56630b57cec5SDimitry Andric return; 56640b57cec5SDimitry Andric } 56650b57cec5SDimitry Andric break; 56660b57cec5SDimitry Andric } 56675ffd83dbSDimitry Andric case AArch64ISD::SVE_LD2_MERGE_ZERO: { 56685ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 5669979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 0, AArch64::LD2B_IMM, AArch64::LD2B); 56705ffd83dbSDimitry Andric return; 56715ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 567281ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5673979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 1, AArch64::LD2H_IMM, AArch64::LD2H); 56745ffd83dbSDimitry Andric return; 56755ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5676979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 2, AArch64::LD2W_IMM, AArch64::LD2W); 56775ffd83dbSDimitry Andric return; 56785ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5679979e22ffSDimitry Andric SelectPredicatedLoad(Node, 2, 3, AArch64::LD2D_IMM, AArch64::LD2D); 56805ffd83dbSDimitry Andric return; 56815ffd83dbSDimitry Andric } 56825ffd83dbSDimitry Andric break; 56835ffd83dbSDimitry Andric } 56845ffd83dbSDimitry Andric case AArch64ISD::SVE_LD3_MERGE_ZERO: { 56855ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 5686979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 0, AArch64::LD3B_IMM, AArch64::LD3B); 56875ffd83dbSDimitry Andric return; 56885ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 568981ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5690979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 1, AArch64::LD3H_IMM, AArch64::LD3H); 56915ffd83dbSDimitry Andric return; 56925ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5693979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 2, AArch64::LD3W_IMM, AArch64::LD3W); 56945ffd83dbSDimitry Andric return; 56955ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5696979e22ffSDimitry Andric SelectPredicatedLoad(Node, 3, 3, AArch64::LD3D_IMM, AArch64::LD3D); 56975ffd83dbSDimitry Andric return; 56985ffd83dbSDimitry Andric } 56995ffd83dbSDimitry Andric break; 57005ffd83dbSDimitry Andric } 57015ffd83dbSDimitry Andric case AArch64ISD::SVE_LD4_MERGE_ZERO: { 57025ffd83dbSDimitry Andric if (VT == MVT::nxv16i8) { 5703979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 0, AArch64::LD4B_IMM, AArch64::LD4B); 57045ffd83dbSDimitry Andric return; 57055ffd83dbSDimitry Andric } else if (VT == MVT::nxv8i16 || VT == MVT::nxv8f16 || 570681ad6265SDimitry Andric VT == MVT::nxv8bf16) { 5707979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 1, AArch64::LD4H_IMM, AArch64::LD4H); 57085ffd83dbSDimitry Andric return; 57095ffd83dbSDimitry Andric } else if (VT == MVT::nxv4i32 || VT == MVT::nxv4f32) { 5710979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 2, AArch64::LD4W_IMM, AArch64::LD4W); 57115ffd83dbSDimitry Andric return; 57125ffd83dbSDimitry Andric } else if (VT == MVT::nxv2i64 || VT == MVT::nxv2f64) { 5713979e22ffSDimitry Andric SelectPredicatedLoad(Node, 4, 3, AArch64::LD4D_IMM, AArch64::LD4D); 57145ffd83dbSDimitry Andric return; 57155ffd83dbSDimitry Andric } 57165ffd83dbSDimitry Andric break; 57175ffd83dbSDimitry Andric } 57180b57cec5SDimitry Andric } 57190b57cec5SDimitry Andric 57200b57cec5SDimitry Andric // Select the default instruction 57210b57cec5SDimitry Andric SelectCode(Node); 57220b57cec5SDimitry Andric } 57230b57cec5SDimitry Andric 57240b57cec5SDimitry Andric /// createAArch64ISelDag - This pass converts a legalized DAG into a 57250b57cec5SDimitry Andric /// AArch64-specific DAG, ready for instruction scheduling. 57260b57cec5SDimitry Andric FunctionPass *llvm::createAArch64ISelDag(AArch64TargetMachine &TM, 57270b57cec5SDimitry Andric CodeGenOpt::Level OptLevel) { 57280b57cec5SDimitry Andric return new AArch64DAGToDAGISel(TM, OptLevel); 57290b57cec5SDimitry Andric } 57305ffd83dbSDimitry Andric 57315ffd83dbSDimitry Andric /// When \p PredVT is a scalable vector predicate in the form 57325ffd83dbSDimitry Andric /// MVT::nx<M>xi1, it builds the correspondent scalable vector of 5733979e22ffSDimitry Andric /// integers MVT::nx<M>xi<bits> s.t. M x bits = 128. When targeting 5734979e22ffSDimitry Andric /// structured vectors (NumVec >1), the output data type is 5735979e22ffSDimitry Andric /// MVT::nx<M*NumVec>xi<bits> s.t. M x bits = 128. If the input 57365ffd83dbSDimitry Andric /// PredVT is not in the form MVT::nx<M>xi1, it returns an invalid 57375ffd83dbSDimitry Andric /// EVT. 5738979e22ffSDimitry Andric static EVT getPackedVectorTypeFromPredicateType(LLVMContext &Ctx, EVT PredVT, 5739979e22ffSDimitry Andric unsigned NumVec) { 5740979e22ffSDimitry Andric assert(NumVec > 0 && NumVec < 5 && "Invalid number of vectors."); 57415ffd83dbSDimitry Andric if (!PredVT.isScalableVector() || PredVT.getVectorElementType() != MVT::i1) 57425ffd83dbSDimitry Andric return EVT(); 57435ffd83dbSDimitry Andric 57445ffd83dbSDimitry Andric if (PredVT != MVT::nxv16i1 && PredVT != MVT::nxv8i1 && 57455ffd83dbSDimitry Andric PredVT != MVT::nxv4i1 && PredVT != MVT::nxv2i1) 57465ffd83dbSDimitry Andric return EVT(); 57475ffd83dbSDimitry Andric 57485ffd83dbSDimitry Andric ElementCount EC = PredVT.getVectorElementCount(); 5749e8d8bef9SDimitry Andric EVT ScalarVT = 5750e8d8bef9SDimitry Andric EVT::getIntegerVT(Ctx, AArch64::SVEBitsPerBlock / EC.getKnownMinValue()); 5751979e22ffSDimitry Andric EVT MemVT = EVT::getVectorVT(Ctx, ScalarVT, EC * NumVec); 5752979e22ffSDimitry Andric 57535ffd83dbSDimitry Andric return MemVT; 57545ffd83dbSDimitry Andric } 57555ffd83dbSDimitry Andric 57565ffd83dbSDimitry Andric /// Return the EVT of the data associated to a memory operation in \p 57575ffd83dbSDimitry Andric /// Root. If such EVT cannot be retrived, it returns an invalid EVT. 57585ffd83dbSDimitry Andric static EVT getMemVTFromNode(LLVMContext &Ctx, SDNode *Root) { 57595ffd83dbSDimitry Andric if (isa<MemSDNode>(Root)) 57605ffd83dbSDimitry Andric return cast<MemSDNode>(Root)->getMemoryVT(); 57615ffd83dbSDimitry Andric 57625ffd83dbSDimitry Andric if (isa<MemIntrinsicSDNode>(Root)) 57635ffd83dbSDimitry Andric return cast<MemIntrinsicSDNode>(Root)->getMemoryVT(); 57645ffd83dbSDimitry Andric 57655ffd83dbSDimitry Andric const unsigned Opcode = Root->getOpcode(); 57665ffd83dbSDimitry Andric // For custom ISD nodes, we have to look at them individually to extract the 57675ffd83dbSDimitry Andric // type of the data moved to/from memory. 57685ffd83dbSDimitry Andric switch (Opcode) { 57695ffd83dbSDimitry Andric case AArch64ISD::LD1_MERGE_ZERO: 57705ffd83dbSDimitry Andric case AArch64ISD::LD1S_MERGE_ZERO: 57715ffd83dbSDimitry Andric case AArch64ISD::LDNF1_MERGE_ZERO: 57725ffd83dbSDimitry Andric case AArch64ISD::LDNF1S_MERGE_ZERO: 57735ffd83dbSDimitry Andric return cast<VTSDNode>(Root->getOperand(3))->getVT(); 57745ffd83dbSDimitry Andric case AArch64ISD::ST1_PRED: 57755ffd83dbSDimitry Andric return cast<VTSDNode>(Root->getOperand(4))->getVT(); 5776979e22ffSDimitry Andric case AArch64ISD::SVE_LD2_MERGE_ZERO: 5777979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 5778979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/2); 5779979e22ffSDimitry Andric case AArch64ISD::SVE_LD3_MERGE_ZERO: 5780979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 5781979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/3); 5782979e22ffSDimitry Andric case AArch64ISD::SVE_LD4_MERGE_ZERO: 5783979e22ffSDimitry Andric return getPackedVectorTypeFromPredicateType( 5784979e22ffSDimitry Andric Ctx, Root->getOperand(1)->getValueType(0), /*NumVec=*/4); 57855ffd83dbSDimitry Andric default: 57865ffd83dbSDimitry Andric break; 57875ffd83dbSDimitry Andric } 57885ffd83dbSDimitry Andric 5789*bdd1243dSDimitry Andric if (Opcode != ISD::INTRINSIC_VOID && Opcode != ISD::INTRINSIC_W_CHAIN) 57905ffd83dbSDimitry Andric return EVT(); 57915ffd83dbSDimitry Andric 5792*bdd1243dSDimitry Andric switch (cast<ConstantSDNode>(Root->getOperand(1))->getZExtValue()) { 5793*bdd1243dSDimitry Andric default: 5794*bdd1243dSDimitry Andric return EVT(); 5795*bdd1243dSDimitry Andric case Intrinsic::aarch64_sme_ldr: 5796*bdd1243dSDimitry Andric case Intrinsic::aarch64_sme_str: 579781ad6265SDimitry Andric return MVT::nxv16i8; 5798*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_prf: 5799*bdd1243dSDimitry Andric // We are using an SVE prefetch intrinsic. Type must be inferred from the 5800*bdd1243dSDimitry Andric // width of the predicate. 58015ffd83dbSDimitry Andric return getPackedVectorTypeFromPredicateType( 5802979e22ffSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/1); 5803*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: 5804*bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 5805*bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/2); 5806*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: 5807*bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 5808*bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/3); 5809*bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: 5810*bdd1243dSDimitry Andric return getPackedVectorTypeFromPredicateType( 5811*bdd1243dSDimitry Andric Ctx, Root->getOperand(2)->getValueType(0), /*NumVec=*/4); 5812*bdd1243dSDimitry Andric } 58135ffd83dbSDimitry Andric } 58145ffd83dbSDimitry Andric 58155ffd83dbSDimitry Andric /// SelectAddrModeIndexedSVE - Attempt selection of the addressing mode: 58165ffd83dbSDimitry Andric /// Base + OffImm * sizeof(MemVT) for Min >= OffImm <= Max 58175ffd83dbSDimitry Andric /// where Root is the memory access using N for its address. 58185ffd83dbSDimitry Andric template <int64_t Min, int64_t Max> 58195ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectAddrModeIndexedSVE(SDNode *Root, SDValue N, 58205ffd83dbSDimitry Andric SDValue &Base, 58215ffd83dbSDimitry Andric SDValue &OffImm) { 58225ffd83dbSDimitry Andric const EVT MemVT = getMemVTFromNode(*(CurDAG->getContext()), Root); 5823349cc55cSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 582481ad6265SDimitry Andric const MachineFrameInfo &MFI = MF->getFrameInfo(); 5825349cc55cSDimitry Andric 5826349cc55cSDimitry Andric if (N.getOpcode() == ISD::FrameIndex) { 5827349cc55cSDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 582881ad6265SDimitry Andric // We can only encode VL scaled offsets, so only fold in frame indexes 582981ad6265SDimitry Andric // referencing SVE objects. 583081ad6265SDimitry Andric if (FI == 0 || MFI.getStackID(FI) == TargetStackID::ScalableVector) { 5831349cc55cSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 5832349cc55cSDimitry Andric OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 5833349cc55cSDimitry Andric return true; 5834349cc55cSDimitry Andric } 58355ffd83dbSDimitry Andric 583681ad6265SDimitry Andric return false; 583781ad6265SDimitry Andric } 583881ad6265SDimitry Andric 58395ffd83dbSDimitry Andric if (MemVT == EVT()) 58405ffd83dbSDimitry Andric return false; 58415ffd83dbSDimitry Andric 58425ffd83dbSDimitry Andric if (N.getOpcode() != ISD::ADD) 58435ffd83dbSDimitry Andric return false; 58445ffd83dbSDimitry Andric 58455ffd83dbSDimitry Andric SDValue VScale = N.getOperand(1); 58465ffd83dbSDimitry Andric if (VScale.getOpcode() != ISD::VSCALE) 58475ffd83dbSDimitry Andric return false; 58485ffd83dbSDimitry Andric 58495ffd83dbSDimitry Andric TypeSize TS = MemVT.getSizeInBits(); 5850*bdd1243dSDimitry Andric int64_t MemWidthBytes = static_cast<int64_t>(TS.getKnownMinValue()) / 8; 58515ffd83dbSDimitry Andric int64_t MulImm = cast<ConstantSDNode>(VScale.getOperand(0))->getSExtValue(); 58525ffd83dbSDimitry Andric 58535ffd83dbSDimitry Andric if ((MulImm % MemWidthBytes) != 0) 58545ffd83dbSDimitry Andric return false; 58555ffd83dbSDimitry Andric 58565ffd83dbSDimitry Andric int64_t Offset = MulImm / MemWidthBytes; 58575ffd83dbSDimitry Andric if (Offset < Min || Offset > Max) 58585ffd83dbSDimitry Andric return false; 58595ffd83dbSDimitry Andric 58605ffd83dbSDimitry Andric Base = N.getOperand(0); 5861349cc55cSDimitry Andric if (Base.getOpcode() == ISD::FrameIndex) { 5862349cc55cSDimitry Andric int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 586381ad6265SDimitry Andric // We can only encode VL scaled offsets, so only fold in frame indexes 586481ad6265SDimitry Andric // referencing SVE objects. 586581ad6265SDimitry Andric if (FI == 0 || MFI.getStackID(FI) == TargetStackID::ScalableVector) 5866349cc55cSDimitry Andric Base = CurDAG->getTargetFrameIndex(FI, TLI->getPointerTy(DL)); 5867349cc55cSDimitry Andric } 5868349cc55cSDimitry Andric 58695ffd83dbSDimitry Andric OffImm = CurDAG->getTargetConstant(Offset, SDLoc(N), MVT::i64); 58705ffd83dbSDimitry Andric return true; 58715ffd83dbSDimitry Andric } 58725ffd83dbSDimitry Andric 58735ffd83dbSDimitry Andric /// Select register plus register addressing mode for SVE, with scaled 58745ffd83dbSDimitry Andric /// offset. 58755ffd83dbSDimitry Andric bool AArch64DAGToDAGISel::SelectSVERegRegAddrMode(SDValue N, unsigned Scale, 58765ffd83dbSDimitry Andric SDValue &Base, 58775ffd83dbSDimitry Andric SDValue &Offset) { 58785ffd83dbSDimitry Andric if (N.getOpcode() != ISD::ADD) 58795ffd83dbSDimitry Andric return false; 58805ffd83dbSDimitry Andric 58815ffd83dbSDimitry Andric // Process an ADD node. 58825ffd83dbSDimitry Andric const SDValue LHS = N.getOperand(0); 58835ffd83dbSDimitry Andric const SDValue RHS = N.getOperand(1); 58845ffd83dbSDimitry Andric 58855ffd83dbSDimitry Andric // 8 bit data does not come with the SHL node, so it is treated 58865ffd83dbSDimitry Andric // separately. 58875ffd83dbSDimitry Andric if (Scale == 0) { 58885ffd83dbSDimitry Andric Base = LHS; 58895ffd83dbSDimitry Andric Offset = RHS; 58905ffd83dbSDimitry Andric return true; 58915ffd83dbSDimitry Andric } 58925ffd83dbSDimitry Andric 5893fe6060f1SDimitry Andric if (auto C = dyn_cast<ConstantSDNode>(RHS)) { 5894fe6060f1SDimitry Andric int64_t ImmOff = C->getSExtValue(); 5895fe6060f1SDimitry Andric unsigned Size = 1 << Scale; 5896fe6060f1SDimitry Andric 5897fe6060f1SDimitry Andric // To use the reg+reg addressing mode, the immediate must be a multiple of 5898fe6060f1SDimitry Andric // the vector element's byte size. 5899fe6060f1SDimitry Andric if (ImmOff % Size) 5900fe6060f1SDimitry Andric return false; 5901fe6060f1SDimitry Andric 5902fe6060f1SDimitry Andric SDLoc DL(N); 5903fe6060f1SDimitry Andric Base = LHS; 5904fe6060f1SDimitry Andric Offset = CurDAG->getTargetConstant(ImmOff >> Scale, DL, MVT::i64); 5905fe6060f1SDimitry Andric SDValue Ops[] = {Offset}; 5906fe6060f1SDimitry Andric SDNode *MI = CurDAG->getMachineNode(AArch64::MOVi64imm, DL, MVT::i64, Ops); 5907fe6060f1SDimitry Andric Offset = SDValue(MI, 0); 5908fe6060f1SDimitry Andric return true; 5909fe6060f1SDimitry Andric } 5910fe6060f1SDimitry Andric 59115ffd83dbSDimitry Andric // Check if the RHS is a shift node with a constant. 59125ffd83dbSDimitry Andric if (RHS.getOpcode() != ISD::SHL) 59135ffd83dbSDimitry Andric return false; 59145ffd83dbSDimitry Andric 59155ffd83dbSDimitry Andric const SDValue ShiftRHS = RHS.getOperand(1); 59165ffd83dbSDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(ShiftRHS)) 59175ffd83dbSDimitry Andric if (C->getZExtValue() == Scale) { 59185ffd83dbSDimitry Andric Base = LHS; 59195ffd83dbSDimitry Andric Offset = RHS.getOperand(0); 59205ffd83dbSDimitry Andric return true; 59215ffd83dbSDimitry Andric } 59225ffd83dbSDimitry Andric 59235ffd83dbSDimitry Andric return false; 59245ffd83dbSDimitry Andric } 5925fe6060f1SDimitry Andric 5926fe6060f1SDimitry Andric bool AArch64DAGToDAGISel::SelectAllActivePredicate(SDValue N) { 5927fe6060f1SDimitry Andric const AArch64TargetLowering *TLI = 5928fe6060f1SDimitry Andric static_cast<const AArch64TargetLowering *>(getTargetLowering()); 5929fe6060f1SDimitry Andric 593004eeddc0SDimitry Andric return TLI->isAllActivePredicate(*CurDAG, N); 5931fe6060f1SDimitry Andric } 593281ad6265SDimitry Andric 5933*bdd1243dSDimitry Andric bool AArch64DAGToDAGISel::SelectSMETileSlice(SDValue N, unsigned MaxSize, 5934*bdd1243dSDimitry Andric SDValue &Base, SDValue &Offset, 5935*bdd1243dSDimitry Andric unsigned Scale) { 593681ad6265SDimitry Andric if (N.getOpcode() != ISD::ADD) { 593781ad6265SDimitry Andric Base = N; 593881ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i64); 593981ad6265SDimitry Andric return true; 594081ad6265SDimitry Andric } 594181ad6265SDimitry Andric 594281ad6265SDimitry Andric // Process an ADD node. 594381ad6265SDimitry Andric const SDValue LHS = N.getOperand(0); 594481ad6265SDimitry Andric const SDValue RHS = N.getOperand(1); 594581ad6265SDimitry Andric 594681ad6265SDimitry Andric if (auto C = dyn_cast<ConstantSDNode>(RHS)) { 594781ad6265SDimitry Andric int64_t ImmOff = C->getSExtValue(); 594881ad6265SDimitry Andric 5949*bdd1243dSDimitry Andric if ((ImmOff < 0 || ImmOff > MaxSize) || (ImmOff % Scale != 0)) 595081ad6265SDimitry Andric return false; 595181ad6265SDimitry Andric 595281ad6265SDimitry Andric Base = LHS; 5953*bdd1243dSDimitry Andric Offset = CurDAG->getTargetConstant(ImmOff / Scale, SDLoc(N), MVT::i64); 595481ad6265SDimitry Andric return true; 595581ad6265SDimitry Andric } 595681ad6265SDimitry Andric 595781ad6265SDimitry Andric return false; 595881ad6265SDimitry Andric } 5959