xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===//
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 ARM target.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ARM.h"
140b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h"
150b57cec5SDimitry Andric #include "ARMTargetMachine.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/ARMAddressingModes.h"
170b57cec5SDimitry Andric #include "Utils/ARMBaseInfo.h"
18fe6060f1SDimitry Andric #include "llvm/ADT/APSInt.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
270b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h"
280b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
290b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
300b57cec5SDimitry Andric #include "llvm/IR/Function.h"
310b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
32480093f4SDimitry Andric #include "llvm/IR/IntrinsicsARM.h"
330b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
340b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
350b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
360b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
370b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
38bdd1243dSDimitry Andric #include <optional>
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric using namespace llvm;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric #define DEBUG_TYPE "arm-isel"
43bdd1243dSDimitry Andric #define PASS_NAME "ARM Instruction Selection"
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric static cl::opt<bool>
460b57cec5SDimitry Andric DisableShifterOp("disable-shifter-op", cl::Hidden,
470b57cec5SDimitry Andric   cl::desc("Disable isel of shifter-op"),
480b57cec5SDimitry Andric   cl::init(false));
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric //===--------------------------------------------------------------------===//
510b57cec5SDimitry Andric /// ARMDAGToDAGISel - ARM specific code to select ARM machine
520b57cec5SDimitry Andric /// instructions for SelectionDAG operations.
530b57cec5SDimitry Andric ///
540b57cec5SDimitry Andric namespace {
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric class ARMDAGToDAGISel : public SelectionDAGISel {
570b57cec5SDimitry Andric   /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
580b57cec5SDimitry Andric   /// make the right decision when generating code for different targets.
590b57cec5SDimitry Andric   const ARMSubtarget *Subtarget;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric public:
62bdd1243dSDimitry Andric   ARMDAGToDAGISel() = delete;
63bdd1243dSDimitry Andric 
ARMDAGToDAGISel(ARMBaseTargetMachine & tm,CodeGenOptLevel OptLevel)645f757f3fSDimitry Andric   explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm, CodeGenOptLevel OptLevel)
65*0fca6ea1SDimitry Andric       : SelectionDAGISel(tm, OptLevel) {}
660b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)670b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
680b57cec5SDimitry Andric     // Reset the subtarget each time through.
690b57cec5SDimitry Andric     Subtarget = &MF.getSubtarget<ARMSubtarget>();
700b57cec5SDimitry Andric     SelectionDAGISel::runOnMachineFunction(MF);
710b57cec5SDimitry Andric     return true;
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   void PreprocessISelDAG() override;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// getI32Imm - Return a target constant of type i32 with the specified
770b57cec5SDimitry Andric   /// value.
getI32Imm(unsigned Imm,const SDLoc & dl)780b57cec5SDimitry Andric   inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
790b57cec5SDimitry Andric     return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   void Select(SDNode *N) override;
830b57cec5SDimitry Andric 
84ada8b24dSDimitry Andric   /// Return true as some complex patterns, like those that call
85ada8b24dSDimitry Andric   /// canExtractShiftFromMul can modify the DAG inplace.
ComplexPatternFuncMutatesDAG() const86ada8b24dSDimitry Andric   bool ComplexPatternFuncMutatesDAG() const override { return true; }
87ada8b24dSDimitry Andric 
880b57cec5SDimitry Andric   bool hasNoVMLxHazardUse(SDNode *N) const;
890b57cec5SDimitry Andric   bool isShifterOpProfitable(const SDValue &Shift,
900b57cec5SDimitry Andric                              ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt);
910b57cec5SDimitry Andric   bool SelectRegShifterOperand(SDValue N, SDValue &A,
920b57cec5SDimitry Andric                                SDValue &B, SDValue &C,
930b57cec5SDimitry Andric                                bool CheckProfitability = true);
940b57cec5SDimitry Andric   bool SelectImmShifterOperand(SDValue N, SDValue &A,
950b57cec5SDimitry Andric                                SDValue &B, bool CheckProfitability = true);
SelectShiftRegShifterOperand(SDValue N,SDValue & A,SDValue & B,SDValue & C)96fe6060f1SDimitry Andric   bool SelectShiftRegShifterOperand(SDValue N, SDValue &A, SDValue &B,
97fe6060f1SDimitry Andric                                     SDValue &C) {
980b57cec5SDimitry Andric     // Don't apply the profitability check
990b57cec5SDimitry Andric     return SelectRegShifterOperand(N, A, B, C, false);
1000b57cec5SDimitry Andric   }
SelectShiftImmShifterOperand(SDValue N,SDValue & A,SDValue & B)101fe6060f1SDimitry Andric   bool SelectShiftImmShifterOperand(SDValue N, SDValue &A, SDValue &B) {
1020b57cec5SDimitry Andric     // Don't apply the profitability check
1030b57cec5SDimitry Andric     return SelectImmShifterOperand(N, A, B, false);
1040b57cec5SDimitry Andric   }
SelectShiftImmShifterOperandOneUse(SDValue N,SDValue & A,SDValue & B)105fe6060f1SDimitry Andric   bool SelectShiftImmShifterOperandOneUse(SDValue N, SDValue &A, SDValue &B) {
106fe6060f1SDimitry Andric     if (!N.hasOneUse())
107fe6060f1SDimitry Andric       return false;
108fe6060f1SDimitry Andric     return SelectImmShifterOperand(N, A, B, false);
109fe6060f1SDimitry Andric   }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   bool SelectAddLikeOr(SDNode *Parent, SDValue N, SDValue &Out);
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
1140b57cec5SDimitry Andric   bool SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc);
1150b57cec5SDimitry Andric 
SelectCMOVPred(SDValue N,SDValue & Pred,SDValue & Reg)1160b57cec5SDimitry Andric   bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) {
1170b57cec5SDimitry Andric     const ConstantSDNode *CN = cast<ConstantSDNode>(N);
1180b57cec5SDimitry Andric     Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32);
1190b57cec5SDimitry Andric     Reg = CurDAG->getRegister(ARM::CPSR, MVT::i32);
1200b57cec5SDimitry Andric     return true;
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   bool SelectAddrMode2OffsetReg(SDNode *Op, SDValue N,
1240b57cec5SDimitry Andric                              SDValue &Offset, SDValue &Opc);
1250b57cec5SDimitry Andric   bool SelectAddrMode2OffsetImm(SDNode *Op, SDValue N,
1260b57cec5SDimitry Andric                              SDValue &Offset, SDValue &Opc);
1270b57cec5SDimitry Andric   bool SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N,
1280b57cec5SDimitry Andric                              SDValue &Offset, SDValue &Opc);
1290b57cec5SDimitry Andric   bool SelectAddrOffsetNone(SDValue N, SDValue &Base);
1300b57cec5SDimitry Andric   bool SelectAddrMode3(SDValue N, SDValue &Base,
1310b57cec5SDimitry Andric                        SDValue &Offset, SDValue &Opc);
1320b57cec5SDimitry Andric   bool SelectAddrMode3Offset(SDNode *Op, SDValue N,
1330b57cec5SDimitry Andric                              SDValue &Offset, SDValue &Opc);
1340b57cec5SDimitry Andric   bool IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset, bool FP16);
1350b57cec5SDimitry Andric   bool SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset);
1360b57cec5SDimitry Andric   bool SelectAddrMode5FP16(SDValue N, SDValue &Base, SDValue &Offset);
1370b57cec5SDimitry Andric   bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align);
1380b57cec5SDimitry Andric   bool SelectAddrMode6Offset(SDNode *Op, SDValue N, SDValue &Offset);
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   bool SelectAddrModePC(SDValue N, SDValue &Offset, SDValue &Label);
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // Thumb Addressing Modes:
1430b57cec5SDimitry Andric   bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset);
1440b57cec5SDimitry Andric   bool SelectThumbAddrModeRRSext(SDValue N, SDValue &Base, SDValue &Offset);
1450b57cec5SDimitry Andric   bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base,
1460b57cec5SDimitry Andric                                 SDValue &OffImm);
1470b57cec5SDimitry Andric   bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
1480b57cec5SDimitry Andric                                  SDValue &OffImm);
1490b57cec5SDimitry Andric   bool SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base,
1500b57cec5SDimitry Andric                                  SDValue &OffImm);
1510b57cec5SDimitry Andric   bool SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base,
1520b57cec5SDimitry Andric                                  SDValue &OffImm);
1530b57cec5SDimitry Andric   bool SelectThumbAddrModeSP(SDValue N, SDValue &Base, SDValue &OffImm);
1548bcb0991SDimitry Andric   template <unsigned Shift>
1558bcb0991SDimitry Andric   bool SelectTAddrModeImm7(SDValue N, SDValue &Base, SDValue &OffImm);
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   // Thumb 2 Addressing Modes:
1580b57cec5SDimitry Andric   bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
1595ffd83dbSDimitry Andric   template <unsigned Shift>
1605ffd83dbSDimitry Andric   bool SelectT2AddrModeImm8(SDValue N, SDValue &Base, SDValue &OffImm);
1610b57cec5SDimitry Andric   bool SelectT2AddrModeImm8(SDValue N, SDValue &Base,
1620b57cec5SDimitry Andric                             SDValue &OffImm);
1630b57cec5SDimitry Andric   bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
1640b57cec5SDimitry Andric                                  SDValue &OffImm);
1650b57cec5SDimitry Andric   template <unsigned Shift>
1668bcb0991SDimitry Andric   bool SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N, SDValue &OffImm);
1678bcb0991SDimitry Andric   bool SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N, SDValue &OffImm,
1688bcb0991SDimitry Andric                                   unsigned Shift);
1698bcb0991SDimitry Andric   template <unsigned Shift>
1708bcb0991SDimitry Andric   bool SelectT2AddrModeImm7(SDValue N, SDValue &Base, SDValue &OffImm);
1710b57cec5SDimitry Andric   bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base,
1720b57cec5SDimitry Andric                              SDValue &OffReg, SDValue &ShImm);
1730b57cec5SDimitry Andric   bool SelectT2AddrModeExclusive(SDValue N, SDValue &Base, SDValue &OffImm);
1740b57cec5SDimitry Andric 
175480093f4SDimitry Andric   template<int Min, int Max>
176480093f4SDimitry Andric   bool SelectImmediateInRange(SDValue N, SDValue &OffImm);
177480093f4SDimitry Andric 
is_so_imm(unsigned Imm) const1780b57cec5SDimitry Andric   inline bool is_so_imm(unsigned Imm) const {
1790b57cec5SDimitry Andric     return ARM_AM::getSOImmVal(Imm) != -1;
1800b57cec5SDimitry Andric   }
1810b57cec5SDimitry Andric 
is_so_imm_not(unsigned Imm) const1820b57cec5SDimitry Andric   inline bool is_so_imm_not(unsigned Imm) const {
1830b57cec5SDimitry Andric     return ARM_AM::getSOImmVal(~Imm) != -1;
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric 
is_t2_so_imm(unsigned Imm) const1860b57cec5SDimitry Andric   inline bool is_t2_so_imm(unsigned Imm) const {
1870b57cec5SDimitry Andric     return ARM_AM::getT2SOImmVal(Imm) != -1;
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric 
is_t2_so_imm_not(unsigned Imm) const1900b57cec5SDimitry Andric   inline bool is_t2_so_imm_not(unsigned Imm) const {
1910b57cec5SDimitry Andric     return ARM_AM::getT2SOImmVal(~Imm) != -1;
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   // Include the pieces autogenerated from the target description.
1950b57cec5SDimitry Andric #include "ARMGenDAGISel.inc"
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric private:
1980b57cec5SDimitry Andric   void transferMemOperands(SDNode *Src, SDNode *Dst);
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   /// Indexed (pre/post inc/dec) load matching code for ARM.
2010b57cec5SDimitry Andric   bool tryARMIndexedLoad(SDNode *N);
2020b57cec5SDimitry Andric   bool tryT1IndexedLoad(SDNode *N);
2030b57cec5SDimitry Andric   bool tryT2IndexedLoad(SDNode *N);
2048bcb0991SDimitry Andric   bool tryMVEIndexedLoad(SDNode *N);
205fe6060f1SDimitry Andric   bool tryFMULFixed(SDNode *N, SDLoc dl);
206fe6060f1SDimitry Andric   bool tryFP_TO_INT(SDNode *N, SDLoc dl);
207fe6060f1SDimitry Andric   bool transformFixedFloatingPointConversion(SDNode *N, SDNode *FMul,
208fe6060f1SDimitry Andric                                              bool IsUnsigned,
209fe6060f1SDimitry Andric                                              bool FixedToFloat);
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   /// SelectVLD - Select NEON load intrinsics.  NumVecs should be
2120b57cec5SDimitry Andric   /// 1, 2, 3 or 4.  The opcode arrays specify the instructions used for
2130b57cec5SDimitry Andric   /// loads of D registers and even subregs and odd subregs of Q registers.
2140b57cec5SDimitry Andric   /// For NumVecs <= 2, QOpcodes1 is not used.
2150b57cec5SDimitry Andric   void SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
2160b57cec5SDimitry Andric                  const uint16_t *DOpcodes, const uint16_t *QOpcodes0,
2170b57cec5SDimitry Andric                  const uint16_t *QOpcodes1);
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   /// SelectVST - Select NEON store intrinsics.  NumVecs should
2200b57cec5SDimitry Andric   /// be 1, 2, 3 or 4.  The opcode arrays specify the instructions used for
2210b57cec5SDimitry Andric   /// stores of D registers and even subregs and odd subregs of Q registers.
2220b57cec5SDimitry Andric   /// For NumVecs <= 2, QOpcodes1 is not used.
2230b57cec5SDimitry Andric   void SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
2240b57cec5SDimitry Andric                  const uint16_t *DOpcodes, const uint16_t *QOpcodes0,
2250b57cec5SDimitry Andric                  const uint16_t *QOpcodes1);
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   /// SelectVLDSTLane - Select NEON load/store lane intrinsics.  NumVecs should
2280b57cec5SDimitry Andric   /// be 2, 3 or 4.  The opcode arrays specify the instructions used for
2290b57cec5SDimitry Andric   /// load/store of D registers and Q registers.
2300b57cec5SDimitry Andric   void SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
2310b57cec5SDimitry Andric                        unsigned NumVecs, const uint16_t *DOpcodes,
2320b57cec5SDimitry Andric                        const uint16_t *QOpcodes);
2330b57cec5SDimitry Andric 
234480093f4SDimitry Andric   /// Helper functions for setting up clusters of MVE predication operands.
235480093f4SDimitry Andric   template <typename SDValueVector>
236480093f4SDimitry Andric   void AddMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc,
237480093f4SDimitry Andric                             SDValue PredicateMask);
238480093f4SDimitry Andric   template <typename SDValueVector>
239480093f4SDimitry Andric   void AddMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc,
240480093f4SDimitry Andric                             SDValue PredicateMask, SDValue Inactive);
241480093f4SDimitry Andric 
242480093f4SDimitry Andric   template <typename SDValueVector>
243480093f4SDimitry Andric   void AddEmptyMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc);
244480093f4SDimitry Andric   template <typename SDValueVector>
245480093f4SDimitry Andric   void AddEmptyMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc, EVT InactiveTy);
246480093f4SDimitry Andric 
247480093f4SDimitry Andric   /// SelectMVE_WB - Select MVE writeback load/store intrinsics.
248480093f4SDimitry Andric   void SelectMVE_WB(SDNode *N, const uint16_t *Opcodes, bool Predicated);
249480093f4SDimitry Andric 
250480093f4SDimitry Andric   /// SelectMVE_LongShift - Select MVE 64-bit scalar shift intrinsics.
251480093f4SDimitry Andric   void SelectMVE_LongShift(SDNode *N, uint16_t Opcode, bool Immediate,
252480093f4SDimitry Andric                            bool HasSaturationOperand);
253480093f4SDimitry Andric 
254480093f4SDimitry Andric   /// SelectMVE_VADCSBC - Select MVE vector add/sub-with-carry intrinsics.
255480093f4SDimitry Andric   void SelectMVE_VADCSBC(SDNode *N, uint16_t OpcodeWithCarry,
256480093f4SDimitry Andric                          uint16_t OpcodeWithNoCarry, bool Add, bool Predicated);
257480093f4SDimitry Andric 
2585ffd83dbSDimitry Andric   /// SelectMVE_VSHLC - Select MVE intrinsics for a shift that carries between
2595ffd83dbSDimitry Andric   /// vector lanes.
2605ffd83dbSDimitry Andric   void SelectMVE_VSHLC(SDNode *N, bool Predicated);
2615ffd83dbSDimitry Andric 
262480093f4SDimitry Andric   /// Select long MVE vector reductions with two vector operands
263480093f4SDimitry Andric   /// Stride is the number of vector element widths the instruction can operate
264480093f4SDimitry Andric   /// on:
265480093f4SDimitry Andric   /// 2 for long non-rounding variants, vml{a,s}ldav[a][x]: [i16, i32]
266480093f4SDimitry Andric   /// 1 for long rounding variants: vrml{a,s}ldavh[a][x]: [i32]
267480093f4SDimitry Andric   /// Stride is used when addressing the OpcodesS array which contains multiple
268480093f4SDimitry Andric   /// opcodes for each element width.
269480093f4SDimitry Andric   /// TySize is the index into the list of element types listed above
270480093f4SDimitry Andric   void SelectBaseMVE_VMLLDAV(SDNode *N, bool Predicated,
271480093f4SDimitry Andric                              const uint16_t *OpcodesS, const uint16_t *OpcodesU,
272480093f4SDimitry Andric                              size_t Stride, size_t TySize);
273480093f4SDimitry Andric 
274480093f4SDimitry Andric   /// Select a 64-bit MVE vector reduction with two vector operands
275480093f4SDimitry Andric   /// arm_mve_vmlldava_[predicated]
276480093f4SDimitry Andric   void SelectMVE_VMLLDAV(SDNode *N, bool Predicated, const uint16_t *OpcodesS,
277480093f4SDimitry Andric                          const uint16_t *OpcodesU);
278480093f4SDimitry Andric   /// Select a 72-bit MVE vector rounding reduction with two vector operands
279480093f4SDimitry Andric   /// int_arm_mve_vrmlldavha[_predicated]
280480093f4SDimitry Andric   void SelectMVE_VRMLLDAVH(SDNode *N, bool Predicated, const uint16_t *OpcodesS,
281480093f4SDimitry Andric                            const uint16_t *OpcodesU);
282480093f4SDimitry Andric 
283480093f4SDimitry Andric   /// SelectMVE_VLD - Select MVE interleaving load intrinsics. NumVecs
284480093f4SDimitry Andric   /// should be 2 or 4. The opcode array specifies the instructions
285480093f4SDimitry Andric   /// used for 8, 16 and 32-bit lane sizes respectively, and each
286480093f4SDimitry Andric   /// pointer points to a set of NumVecs sub-opcodes used for the
287480093f4SDimitry Andric   /// different stages (e.g. VLD20 versus VLD21) of each load family.
288480093f4SDimitry Andric   void SelectMVE_VLD(SDNode *N, unsigned NumVecs,
2895ffd83dbSDimitry Andric                      const uint16_t *const *Opcodes, bool HasWriteback);
2905ffd83dbSDimitry Andric 
2915ffd83dbSDimitry Andric   /// SelectMVE_VxDUP - Select MVE incrementing-dup instructions. Opcodes is an
2925ffd83dbSDimitry Andric   /// array of 3 elements for the 8, 16 and 32-bit lane sizes.
2935ffd83dbSDimitry Andric   void SelectMVE_VxDUP(SDNode *N, const uint16_t *Opcodes,
2945ffd83dbSDimitry Andric                        bool Wrapping, bool Predicated);
2955ffd83dbSDimitry Andric 
2965ffd83dbSDimitry Andric   /// Select SelectCDE_CXxD - Select CDE dual-GPR instruction (one of CX1D,
2975ffd83dbSDimitry Andric   /// CX1DA, CX2D, CX2DA, CX3, CX3DA).
2985ffd83dbSDimitry Andric   /// \arg \c NumExtraOps number of extra operands besides the coprocossor,
2995ffd83dbSDimitry Andric   ///                     the accumulator and the immediate operand, i.e. 0
3005ffd83dbSDimitry Andric   ///                     for CX1*, 1 for CX2*, 2 for CX3*
3015ffd83dbSDimitry Andric   /// \arg \c HasAccum whether the instruction has an accumulator operand
3025ffd83dbSDimitry Andric   void SelectCDE_CXxD(SDNode *N, uint16_t Opcode, size_t NumExtraOps,
3035ffd83dbSDimitry Andric                       bool HasAccum);
304480093f4SDimitry Andric 
3050b57cec5SDimitry Andric   /// SelectVLDDup - Select NEON load-duplicate intrinsics.  NumVecs
3060b57cec5SDimitry Andric   /// should be 1, 2, 3 or 4.  The opcode array specifies the instructions used
3070b57cec5SDimitry Andric   /// for loading D registers.
3080b57cec5SDimitry Andric   void SelectVLDDup(SDNode *N, bool IsIntrinsic, bool isUpdating,
3090b57cec5SDimitry Andric                     unsigned NumVecs, const uint16_t *DOpcodes,
3100b57cec5SDimitry Andric                     const uint16_t *QOpcodes0 = nullptr,
3110b57cec5SDimitry Andric                     const uint16_t *QOpcodes1 = nullptr);
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   /// Try to select SBFX/UBFX instructions for ARM.
3140b57cec5SDimitry Andric   bool tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned);
3150b57cec5SDimitry Andric 
316fe6060f1SDimitry Andric   bool tryInsertVectorElt(SDNode *N);
317fe6060f1SDimitry Andric 
3180b57cec5SDimitry Andric   // Select special operations if node forms integer ABS pattern
3190b57cec5SDimitry Andric   bool tryABSOp(SDNode *N);
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   bool tryReadRegister(SDNode *N);
3220b57cec5SDimitry Andric   bool tryWriteRegister(SDNode *N);
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   bool tryInlineAsm(SDNode *N);
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   void SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI);
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   void SelectCMP_SWAP(SDNode *N);
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
3310b57cec5SDimitry Andric   /// inline asm expressions.
3325f757f3fSDimitry Andric   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
3335f757f3fSDimitry Andric                                     InlineAsm::ConstraintCode ConstraintID,
3340b57cec5SDimitry Andric                                     std::vector<SDValue> &OutOps) override;
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   // Form pairs of consecutive R, S, D, or Q registers.
3370b57cec5SDimitry Andric   SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
3380b57cec5SDimitry Andric   SDNode *createSRegPairNode(EVT VT, SDValue V0, SDValue V1);
3390b57cec5SDimitry Andric   SDNode *createDRegPairNode(EVT VT, SDValue V0, SDValue V1);
3400b57cec5SDimitry Andric   SDNode *createQRegPairNode(EVT VT, SDValue V0, SDValue V1);
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   // Form sequences of 4 consecutive S, D, or Q registers.
3430b57cec5SDimitry Andric   SDNode *createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
3440b57cec5SDimitry Andric   SDNode *createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
3450b57cec5SDimitry Andric   SDNode *createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   // Get the alignment operand for a NEON VLD or VST instruction.
3480b57cec5SDimitry Andric   SDValue GetVLDSTAlign(SDValue Align, const SDLoc &dl, unsigned NumVecs,
3490b57cec5SDimitry Andric                         bool is64BitVector);
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   /// Checks if N is a multiplication by a constant where we can extract out a
3520b57cec5SDimitry Andric   /// power of two from the constant so that it can be used in a shift, but only
3530b57cec5SDimitry Andric   /// if it simplifies the materialization of the constant. Returns true if it
3540b57cec5SDimitry Andric   /// is, and assigns to PowerOfTwo the power of two that should be extracted
3550b57cec5SDimitry Andric   /// out and to NewMulConst the new constant to be multiplied by.
3560b57cec5SDimitry Andric   bool canExtractShiftFromMul(const SDValue &N, unsigned MaxShift,
3570b57cec5SDimitry Andric                               unsigned &PowerOfTwo, SDValue &NewMulConst) const;
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   /// Replace N with M in CurDAG, in a way that also ensures that M gets
3600b57cec5SDimitry Andric   /// selected when N would have been selected.
3610b57cec5SDimitry Andric   void replaceDAGValue(const SDValue &N, SDValue M);
3620b57cec5SDimitry Andric };
363*0fca6ea1SDimitry Andric 
364*0fca6ea1SDimitry Andric class ARMDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
365*0fca6ea1SDimitry Andric public:
366*0fca6ea1SDimitry Andric   static char ID;
ARMDAGToDAGISelLegacy(ARMBaseTargetMachine & tm,CodeGenOptLevel OptLevel)367*0fca6ea1SDimitry Andric   ARMDAGToDAGISelLegacy(ARMBaseTargetMachine &tm, CodeGenOptLevel OptLevel)
368*0fca6ea1SDimitry Andric       : SelectionDAGISelLegacy(
369*0fca6ea1SDimitry Andric             ID, std::make_unique<ARMDAGToDAGISel>(tm, OptLevel)) {}
370*0fca6ea1SDimitry Andric };
3710b57cec5SDimitry Andric }
3720b57cec5SDimitry Andric 
373*0fca6ea1SDimitry Andric char ARMDAGToDAGISelLegacy::ID = 0;
374bdd1243dSDimitry Andric 
INITIALIZE_PASS(ARMDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)375*0fca6ea1SDimitry Andric INITIALIZE_PASS(ARMDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
376bdd1243dSDimitry Andric 
3770b57cec5SDimitry Andric /// isInt32Immediate - This method tests to see if the node is a 32-bit constant
3780b57cec5SDimitry Andric /// operand. If so Imm will receive the 32-bit value.
3790b57cec5SDimitry Andric static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
3800b57cec5SDimitry Andric   if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
3811db9f3b2SDimitry Andric     Imm = N->getAsZExtVal();
3820b57cec5SDimitry Andric     return true;
3830b57cec5SDimitry Andric   }
3840b57cec5SDimitry Andric   return false;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric // isInt32Immediate - This method tests to see if a constant operand.
3880b57cec5SDimitry Andric // If so Imm will receive the 32 bit value.
isInt32Immediate(SDValue N,unsigned & Imm)3890b57cec5SDimitry Andric static bool isInt32Immediate(SDValue N, unsigned &Imm) {
3900b57cec5SDimitry Andric   return isInt32Immediate(N.getNode(), Imm);
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric // isOpcWithIntImmediate - This method tests to see if the node is a specific
3940b57cec5SDimitry Andric // opcode and that it has a immediate integer right operand.
3950b57cec5SDimitry Andric // If so Imm will receive the 32 bit value.
isOpcWithIntImmediate(SDNode * N,unsigned Opc,unsigned & Imm)3960b57cec5SDimitry Andric static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
3970b57cec5SDimitry Andric   return N->getOpcode() == Opc &&
3980b57cec5SDimitry Andric          isInt32Immediate(N->getOperand(1).getNode(), Imm);
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric /// Check whether a particular node is a constant value representable as
4020b57cec5SDimitry Andric /// (N * Scale) where (N in [\p RangeMin, \p RangeMax).
4030b57cec5SDimitry Andric ///
4040b57cec5SDimitry Andric /// \param ScaledConstant [out] - On success, the pre-scaled constant value.
isScaledConstantInRange(SDValue Node,int Scale,int RangeMin,int RangeMax,int & ScaledConstant)4050b57cec5SDimitry Andric static bool isScaledConstantInRange(SDValue Node, int Scale,
4060b57cec5SDimitry Andric                                     int RangeMin, int RangeMax,
4070b57cec5SDimitry Andric                                     int &ScaledConstant) {
4080b57cec5SDimitry Andric   assert(Scale > 0 && "Invalid scale!");
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   // Check that this is a constant.
4110b57cec5SDimitry Andric   const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Node);
4120b57cec5SDimitry Andric   if (!C)
4130b57cec5SDimitry Andric     return false;
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   ScaledConstant = (int) C->getZExtValue();
4160b57cec5SDimitry Andric   if ((ScaledConstant % Scale) != 0)
4170b57cec5SDimitry Andric     return false;
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   ScaledConstant /= Scale;
4200b57cec5SDimitry Andric   return ScaledConstant >= RangeMin && ScaledConstant < RangeMax;
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric 
PreprocessISelDAG()4230b57cec5SDimitry Andric void ARMDAGToDAGISel::PreprocessISelDAG() {
4240b57cec5SDimitry Andric   if (!Subtarget->hasV6T2Ops())
4250b57cec5SDimitry Andric     return;
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   bool isThumb2 = Subtarget->isThumb();
428349cc55cSDimitry Andric   // We use make_early_inc_range to avoid invalidation issues.
429349cc55cSDimitry Andric   for (SDNode &N : llvm::make_early_inc_range(CurDAG->allnodes())) {
430349cc55cSDimitry Andric     if (N.getOpcode() != ISD::ADD)
4310b57cec5SDimitry Andric       continue;
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric     // Look for (add X1, (and (srl X2, c1), c2)) where c2 is constant with
4340b57cec5SDimitry Andric     // leading zeros, followed by consecutive set bits, followed by 1 or 2
4350b57cec5SDimitry Andric     // trailing zeros, e.g. 1020.
4360b57cec5SDimitry Andric     // Transform the expression to
4370b57cec5SDimitry Andric     // (add X1, (shl (and (srl X2, c1), (c2>>tz)), tz)) where tz is the number
4380b57cec5SDimitry Andric     // of trailing zeros of c2. The left shift would be folded as an shifter
4390b57cec5SDimitry Andric     // operand of 'add' and the 'and' and 'srl' would become a bits extraction
4400b57cec5SDimitry Andric     // node (UBFX).
4410b57cec5SDimitry Andric 
442349cc55cSDimitry Andric     SDValue N0 = N.getOperand(0);
443349cc55cSDimitry Andric     SDValue N1 = N.getOperand(1);
4440b57cec5SDimitry Andric     unsigned And_imm = 0;
4450b57cec5SDimitry Andric     if (!isOpcWithIntImmediate(N1.getNode(), ISD::AND, And_imm)) {
4460b57cec5SDimitry Andric       if (isOpcWithIntImmediate(N0.getNode(), ISD::AND, And_imm))
4470b57cec5SDimitry Andric         std::swap(N0, N1);
4480b57cec5SDimitry Andric     }
4490b57cec5SDimitry Andric     if (!And_imm)
4500b57cec5SDimitry Andric       continue;
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric     // Check if the AND mask is an immediate of the form: 000.....1111111100
45306c3fb27SDimitry Andric     unsigned TZ = llvm::countr_zero(And_imm);
4540b57cec5SDimitry Andric     if (TZ != 1 && TZ != 2)
4550b57cec5SDimitry Andric       // Be conservative here. Shifter operands aren't always free. e.g. On
4560b57cec5SDimitry Andric       // Swift, left shifter operand of 1 / 2 for free but others are not.
4570b57cec5SDimitry Andric       // e.g.
4580b57cec5SDimitry Andric       //  ubfx   r3, r1, #16, #8
4590b57cec5SDimitry Andric       //  ldr.w  r3, [r0, r3, lsl #2]
4600b57cec5SDimitry Andric       // vs.
4610b57cec5SDimitry Andric       //  mov.w  r9, #1020
4620b57cec5SDimitry Andric       //  and.w  r2, r9, r1, lsr #14
4630b57cec5SDimitry Andric       //  ldr    r2, [r0, r2]
4640b57cec5SDimitry Andric       continue;
4650b57cec5SDimitry Andric     And_imm >>= TZ;
4660b57cec5SDimitry Andric     if (And_imm & (And_imm + 1))
4670b57cec5SDimitry Andric       continue;
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric     // Look for (and (srl X, c1), c2).
4700b57cec5SDimitry Andric     SDValue Srl = N1.getOperand(0);
4710b57cec5SDimitry Andric     unsigned Srl_imm = 0;
4720b57cec5SDimitry Andric     if (!isOpcWithIntImmediate(Srl.getNode(), ISD::SRL, Srl_imm) ||
4730b57cec5SDimitry Andric         (Srl_imm <= 2))
4740b57cec5SDimitry Andric       continue;
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric     // Make sure first operand is not a shifter operand which would prevent
4770b57cec5SDimitry Andric     // folding of the left shift.
4780b57cec5SDimitry Andric     SDValue CPTmp0;
4790b57cec5SDimitry Andric     SDValue CPTmp1;
4800b57cec5SDimitry Andric     SDValue CPTmp2;
4810b57cec5SDimitry Andric     if (isThumb2) {
4820b57cec5SDimitry Andric       if (SelectImmShifterOperand(N0, CPTmp0, CPTmp1))
4830b57cec5SDimitry Andric         continue;
4840b57cec5SDimitry Andric     } else {
4850b57cec5SDimitry Andric       if (SelectImmShifterOperand(N0, CPTmp0, CPTmp1) ||
4860b57cec5SDimitry Andric           SelectRegShifterOperand(N0, CPTmp0, CPTmp1, CPTmp2))
4870b57cec5SDimitry Andric         continue;
4880b57cec5SDimitry Andric     }
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric     // Now make the transformation.
4910b57cec5SDimitry Andric     Srl = CurDAG->getNode(ISD::SRL, SDLoc(Srl), MVT::i32,
4920b57cec5SDimitry Andric                           Srl.getOperand(0),
4930b57cec5SDimitry Andric                           CurDAG->getConstant(Srl_imm + TZ, SDLoc(Srl),
4940b57cec5SDimitry Andric                                               MVT::i32));
4950b57cec5SDimitry Andric     N1 = CurDAG->getNode(ISD::AND, SDLoc(N1), MVT::i32,
4960b57cec5SDimitry Andric                          Srl,
4970b57cec5SDimitry Andric                          CurDAG->getConstant(And_imm, SDLoc(Srl), MVT::i32));
4980b57cec5SDimitry Andric     N1 = CurDAG->getNode(ISD::SHL, SDLoc(N1), MVT::i32,
4990b57cec5SDimitry Andric                          N1, CurDAG->getConstant(TZ, SDLoc(Srl), MVT::i32));
500349cc55cSDimitry Andric     CurDAG->UpdateNodeOperands(&N, N0, N1);
5010b57cec5SDimitry Andric   }
5020b57cec5SDimitry Andric }
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric /// hasNoVMLxHazardUse - Return true if it's desirable to select a FP MLA / MLS
5050b57cec5SDimitry Andric /// node. VFP / NEON fp VMLA / VMLS instructions have special RAW hazards (at
5060b57cec5SDimitry Andric /// least on current ARM implementations) which should be avoidded.
hasNoVMLxHazardUse(SDNode * N) const5070b57cec5SDimitry Andric bool ARMDAGToDAGISel::hasNoVMLxHazardUse(SDNode *N) const {
5085f757f3fSDimitry Andric   if (OptLevel == CodeGenOptLevel::None)
5090b57cec5SDimitry Andric     return true;
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric   if (!Subtarget->hasVMLxHazards())
5120b57cec5SDimitry Andric     return true;
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   if (!N->hasOneUse())
5150b57cec5SDimitry Andric     return false;
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric   SDNode *Use = *N->use_begin();
5180b57cec5SDimitry Andric   if (Use->getOpcode() == ISD::CopyToReg)
5190b57cec5SDimitry Andric     return true;
5200b57cec5SDimitry Andric   if (Use->isMachineOpcode()) {
5210b57cec5SDimitry Andric     const ARMBaseInstrInfo *TII = static_cast<const ARMBaseInstrInfo *>(
5220b57cec5SDimitry Andric         CurDAG->getSubtarget().getInstrInfo());
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric     const MCInstrDesc &MCID = TII->get(Use->getMachineOpcode());
5250b57cec5SDimitry Andric     if (MCID.mayStore())
5260b57cec5SDimitry Andric       return true;
5270b57cec5SDimitry Andric     unsigned Opcode = MCID.getOpcode();
5280b57cec5SDimitry Andric     if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)
5290b57cec5SDimitry Andric       return true;
5300b57cec5SDimitry Andric     // vmlx feeding into another vmlx. We actually want to unfold
5310b57cec5SDimitry Andric     // the use later in the MLxExpansion pass. e.g.
5320b57cec5SDimitry Andric     // vmla
5330b57cec5SDimitry Andric     // vmla (stall 8 cycles)
5340b57cec5SDimitry Andric     //
5350b57cec5SDimitry Andric     // vmul (5 cycles)
5360b57cec5SDimitry Andric     // vadd (5 cycles)
5370b57cec5SDimitry Andric     // vmla
5380b57cec5SDimitry Andric     // This adds up to about 18 - 19 cycles.
5390b57cec5SDimitry Andric     //
5400b57cec5SDimitry Andric     // vmla
5410b57cec5SDimitry Andric     // vmul (stall 4 cycles)
5420b57cec5SDimitry Andric     // vadd adds up to about 14 cycles.
5430b57cec5SDimitry Andric     return TII->isFpMLxInstruction(Opcode);
5440b57cec5SDimitry Andric   }
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric   return false;
5470b57cec5SDimitry Andric }
5480b57cec5SDimitry Andric 
isShifterOpProfitable(const SDValue & Shift,ARM_AM::ShiftOpc ShOpcVal,unsigned ShAmt)5490b57cec5SDimitry Andric bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
5500b57cec5SDimitry Andric                                             ARM_AM::ShiftOpc ShOpcVal,
5510b57cec5SDimitry Andric                                             unsigned ShAmt) {
5520b57cec5SDimitry Andric   if (!Subtarget->isLikeA9() && !Subtarget->isSwift())
5530b57cec5SDimitry Andric     return true;
5540b57cec5SDimitry Andric   if (Shift.hasOneUse())
5550b57cec5SDimitry Andric     return true;
5560b57cec5SDimitry Andric   // R << 2 is free.
5570b57cec5SDimitry Andric   return ShOpcVal == ARM_AM::lsl &&
5580b57cec5SDimitry Andric          (ShAmt == 2 || (Subtarget->isSwift() && ShAmt == 1));
5590b57cec5SDimitry Andric }
5600b57cec5SDimitry Andric 
canExtractShiftFromMul(const SDValue & N,unsigned MaxShift,unsigned & PowerOfTwo,SDValue & NewMulConst) const5610b57cec5SDimitry Andric bool ARMDAGToDAGISel::canExtractShiftFromMul(const SDValue &N,
5620b57cec5SDimitry Andric                                              unsigned MaxShift,
5630b57cec5SDimitry Andric                                              unsigned &PowerOfTwo,
5640b57cec5SDimitry Andric                                              SDValue &NewMulConst) const {
5650b57cec5SDimitry Andric   assert(N.getOpcode() == ISD::MUL);
5660b57cec5SDimitry Andric   assert(MaxShift > 0);
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric   // If the multiply is used in more than one place then changing the constant
5690b57cec5SDimitry Andric   // will make other uses incorrect, so don't.
5700b57cec5SDimitry Andric   if (!N.hasOneUse()) return false;
5710b57cec5SDimitry Andric   // Check if the multiply is by a constant
5720b57cec5SDimitry Andric   ConstantSDNode *MulConst = dyn_cast<ConstantSDNode>(N.getOperand(1));
5730b57cec5SDimitry Andric   if (!MulConst) return false;
5740b57cec5SDimitry Andric   // If the constant is used in more than one place then modifying it will mean
5750b57cec5SDimitry Andric   // we need to materialize two constants instead of one, which is a bad idea.
5760b57cec5SDimitry Andric   if (!MulConst->hasOneUse()) return false;
5770b57cec5SDimitry Andric   unsigned MulConstVal = MulConst->getZExtValue();
5780b57cec5SDimitry Andric   if (MulConstVal == 0) return false;
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric   // Find the largest power of 2 that MulConstVal is a multiple of
5810b57cec5SDimitry Andric   PowerOfTwo = MaxShift;
5820b57cec5SDimitry Andric   while ((MulConstVal % (1 << PowerOfTwo)) != 0) {
5830b57cec5SDimitry Andric     --PowerOfTwo;
5840b57cec5SDimitry Andric     if (PowerOfTwo == 0) return false;
5850b57cec5SDimitry Andric   }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   // Only optimise if the new cost is better
5880b57cec5SDimitry Andric   unsigned NewMulConstVal = MulConstVal / (1 << PowerOfTwo);
5890b57cec5SDimitry Andric   NewMulConst = CurDAG->getConstant(NewMulConstVal, SDLoc(N), MVT::i32);
5908bcb0991SDimitry Andric   unsigned OldCost = ConstantMaterializationCost(MulConstVal, Subtarget);
5918bcb0991SDimitry Andric   unsigned NewCost = ConstantMaterializationCost(NewMulConstVal, Subtarget);
5920b57cec5SDimitry Andric   return NewCost < OldCost;
5930b57cec5SDimitry Andric }
5940b57cec5SDimitry Andric 
replaceDAGValue(const SDValue & N,SDValue M)5950b57cec5SDimitry Andric void ARMDAGToDAGISel::replaceDAGValue(const SDValue &N, SDValue M) {
5960b57cec5SDimitry Andric   CurDAG->RepositionNode(N.getNode()->getIterator(), M.getNode());
5970b57cec5SDimitry Andric   ReplaceUses(N, M);
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric 
SelectImmShifterOperand(SDValue N,SDValue & BaseReg,SDValue & Opc,bool CheckProfitability)6000b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N,
6010b57cec5SDimitry Andric                                               SDValue &BaseReg,
6020b57cec5SDimitry Andric                                               SDValue &Opc,
6030b57cec5SDimitry Andric                                               bool CheckProfitability) {
6040b57cec5SDimitry Andric   if (DisableShifterOp)
6050b57cec5SDimitry Andric     return false;
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric   // If N is a multiply-by-constant and it's profitable to extract a shift and
6080b57cec5SDimitry Andric   // use it in a shifted operand do so.
6090b57cec5SDimitry Andric   if (N.getOpcode() == ISD::MUL) {
6100b57cec5SDimitry Andric     unsigned PowerOfTwo = 0;
6110b57cec5SDimitry Andric     SDValue NewMulConst;
6120b57cec5SDimitry Andric     if (canExtractShiftFromMul(N, 31, PowerOfTwo, NewMulConst)) {
6130b57cec5SDimitry Andric       HandleSDNode Handle(N);
6140b57cec5SDimitry Andric       SDLoc Loc(N);
6150b57cec5SDimitry Andric       replaceDAGValue(N.getOperand(1), NewMulConst);
6160b57cec5SDimitry Andric       BaseReg = Handle.getValue();
6170b57cec5SDimitry Andric       Opc = CurDAG->getTargetConstant(
6180b57cec5SDimitry Andric           ARM_AM::getSORegOpc(ARM_AM::lsl, PowerOfTwo), Loc, MVT::i32);
6190b57cec5SDimitry Andric       return true;
6200b57cec5SDimitry Andric     }
6210b57cec5SDimitry Andric   }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric   // Don't match base register only case. That is matched to a separate
6260b57cec5SDimitry Andric   // lower complexity pattern with explicit register operand.
6270b57cec5SDimitry Andric   if (ShOpcVal == ARM_AM::no_shift) return false;
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric   BaseReg = N.getOperand(0);
6300b57cec5SDimitry Andric   unsigned ShImmVal = 0;
6310b57cec5SDimitry Andric   ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
6320b57cec5SDimitry Andric   if (!RHS) return false;
6330b57cec5SDimitry Andric   ShImmVal = RHS->getZExtValue() & 31;
6340b57cec5SDimitry Andric   Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
6350b57cec5SDimitry Andric                                   SDLoc(N), MVT::i32);
6360b57cec5SDimitry Andric   return true;
6370b57cec5SDimitry Andric }
6380b57cec5SDimitry Andric 
SelectRegShifterOperand(SDValue N,SDValue & BaseReg,SDValue & ShReg,SDValue & Opc,bool CheckProfitability)6390b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectRegShifterOperand(SDValue N,
6400b57cec5SDimitry Andric                                               SDValue &BaseReg,
6410b57cec5SDimitry Andric                                               SDValue &ShReg,
6420b57cec5SDimitry Andric                                               SDValue &Opc,
6430b57cec5SDimitry Andric                                               bool CheckProfitability) {
6440b57cec5SDimitry Andric   if (DisableShifterOp)
6450b57cec5SDimitry Andric     return false;
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric   ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric   // Don't match base register only case. That is matched to a separate
6500b57cec5SDimitry Andric   // lower complexity pattern with explicit register operand.
6510b57cec5SDimitry Andric   if (ShOpcVal == ARM_AM::no_shift) return false;
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric   BaseReg = N.getOperand(0);
6540b57cec5SDimitry Andric   unsigned ShImmVal = 0;
6550b57cec5SDimitry Andric   ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
6560b57cec5SDimitry Andric   if (RHS) return false;
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric   ShReg = N.getOperand(1);
6590b57cec5SDimitry Andric   if (CheckProfitability && !isShifterOpProfitable(N, ShOpcVal, ShImmVal))
6600b57cec5SDimitry Andric     return false;
6610b57cec5SDimitry Andric   Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
6620b57cec5SDimitry Andric                                   SDLoc(N), MVT::i32);
6630b57cec5SDimitry Andric   return true;
6640b57cec5SDimitry Andric }
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric // Determine whether an ISD::OR's operands are suitable to turn the operation
6670b57cec5SDimitry Andric // into an addition, which often has more compact encodings.
SelectAddLikeOr(SDNode * Parent,SDValue N,SDValue & Out)6680b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddLikeOr(SDNode *Parent, SDValue N, SDValue &Out) {
6690b57cec5SDimitry Andric   assert(Parent->getOpcode() == ISD::OR && "unexpected parent");
6700b57cec5SDimitry Andric   Out = N;
6710b57cec5SDimitry Andric   return CurDAG->haveNoCommonBitsSet(N, Parent->getOperand(1));
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric 
6740b57cec5SDimitry Andric 
SelectAddrModeImm12(SDValue N,SDValue & Base,SDValue & OffImm)6750b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N,
6760b57cec5SDimitry Andric                                           SDValue &Base,
6770b57cec5SDimitry Andric                                           SDValue &OffImm) {
6780b57cec5SDimitry Andric   // Match simple R + imm12 operands.
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   // Base only.
6810b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
6820b57cec5SDimitry Andric       !CurDAG->isBaseWithConstantOffset(N)) {
6830b57cec5SDimitry Andric     if (N.getOpcode() == ISD::FrameIndex) {
6840b57cec5SDimitry Andric       // Match frame index.
6850b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(N)->getIndex();
6860b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
6870b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
6880b57cec5SDimitry Andric       OffImm  = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
6890b57cec5SDimitry Andric       return true;
6900b57cec5SDimitry Andric     }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric     if (N.getOpcode() == ARMISD::Wrapper &&
6930b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
6940b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
6950b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
6960b57cec5SDimitry Andric       Base = N.getOperand(0);
6970b57cec5SDimitry Andric     } else
6980b57cec5SDimitry Andric       Base = N;
6990b57cec5SDimitry Andric     OffImm  = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
7000b57cec5SDimitry Andric     return true;
7010b57cec5SDimitry Andric   }
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
7040b57cec5SDimitry Andric     int RHSC = (int)RHS->getSExtValue();
7050b57cec5SDimitry Andric     if (N.getOpcode() == ISD::SUB)
7060b57cec5SDimitry Andric       RHSC = -RHSC;
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric     if (RHSC > -0x1000 && RHSC < 0x1000) { // 12 bits
7090b57cec5SDimitry Andric       Base   = N.getOperand(0);
7100b57cec5SDimitry Andric       if (Base.getOpcode() == ISD::FrameIndex) {
7110b57cec5SDimitry Andric         int FI = cast<FrameIndexSDNode>(Base)->getIndex();
7120b57cec5SDimitry Andric         Base = CurDAG->getTargetFrameIndex(
7130b57cec5SDimitry Andric             FI, TLI->getPointerTy(CurDAG->getDataLayout()));
7140b57cec5SDimitry Andric       }
7150b57cec5SDimitry Andric       OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
7160b57cec5SDimitry Andric       return true;
7170b57cec5SDimitry Andric     }
7180b57cec5SDimitry Andric   }
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   // Base only.
7210b57cec5SDimitry Andric   Base = N;
7220b57cec5SDimitry Andric   OffImm  = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
7230b57cec5SDimitry Andric   return true;
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric 
SelectLdStSOReg(SDValue N,SDValue & Base,SDValue & Offset,SDValue & Opc)7280b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset,
7290b57cec5SDimitry Andric                                       SDValue &Opc) {
7300b57cec5SDimitry Andric   if (N.getOpcode() == ISD::MUL &&
7310b57cec5SDimitry Andric       ((!Subtarget->isLikeA9() && !Subtarget->isSwift()) || N.hasOneUse())) {
7320b57cec5SDimitry Andric     if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
7330b57cec5SDimitry Andric       // X * [3,5,9] -> X + X * [2,4,8] etc.
7340b57cec5SDimitry Andric       int RHSC = (int)RHS->getZExtValue();
7350b57cec5SDimitry Andric       if (RHSC & 1) {
7360b57cec5SDimitry Andric         RHSC = RHSC & ~1;
7370b57cec5SDimitry Andric         ARM_AM::AddrOpc AddSub = ARM_AM::add;
7380b57cec5SDimitry Andric         if (RHSC < 0) {
7390b57cec5SDimitry Andric           AddSub = ARM_AM::sub;
7400b57cec5SDimitry Andric           RHSC = - RHSC;
7410b57cec5SDimitry Andric         }
7420b57cec5SDimitry Andric         if (isPowerOf2_32(RHSC)) {
7430b57cec5SDimitry Andric           unsigned ShAmt = Log2_32(RHSC);
7440b57cec5SDimitry Andric           Base = Offset = N.getOperand(0);
7450b57cec5SDimitry Andric           Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt,
7460b57cec5SDimitry Andric                                                             ARM_AM::lsl),
7470b57cec5SDimitry Andric                                           SDLoc(N), MVT::i32);
7480b57cec5SDimitry Andric           return true;
7490b57cec5SDimitry Andric         }
7500b57cec5SDimitry Andric       }
7510b57cec5SDimitry Andric     }
7520b57cec5SDimitry Andric   }
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
7550b57cec5SDimitry Andric       // ISD::OR that is equivalent to an ISD::ADD.
7560b57cec5SDimitry Andric       !CurDAG->isBaseWithConstantOffset(N))
7570b57cec5SDimitry Andric     return false;
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric   // Leave simple R +/- imm12 operands for LDRi12
7600b57cec5SDimitry Andric   if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
7610b57cec5SDimitry Andric     int RHSC;
7620b57cec5SDimitry Andric     if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
7630b57cec5SDimitry Andric                                 -0x1000+1, 0x1000, RHSC)) // 12 bits.
7640b57cec5SDimitry Andric       return false;
7650b57cec5SDimitry Andric   }
7660b57cec5SDimitry Andric 
7670b57cec5SDimitry Andric   // Otherwise this is R +/- [possibly shifted] R.
7680b57cec5SDimitry Andric   ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::SUB ? ARM_AM::sub:ARM_AM::add;
7690b57cec5SDimitry Andric   ARM_AM::ShiftOpc ShOpcVal =
7700b57cec5SDimitry Andric     ARM_AM::getShiftOpcForNode(N.getOperand(1).getOpcode());
7710b57cec5SDimitry Andric   unsigned ShAmt = 0;
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric   Base   = N.getOperand(0);
7740b57cec5SDimitry Andric   Offset = N.getOperand(1);
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   if (ShOpcVal != ARM_AM::no_shift) {
7770b57cec5SDimitry Andric     // Check to see if the RHS of the shift is a constant, if not, we can't fold
7780b57cec5SDimitry Andric     // it.
7790b57cec5SDimitry Andric     if (ConstantSDNode *Sh =
7800b57cec5SDimitry Andric            dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) {
7810b57cec5SDimitry Andric       ShAmt = Sh->getZExtValue();
7820b57cec5SDimitry Andric       if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt))
7830b57cec5SDimitry Andric         Offset = N.getOperand(1).getOperand(0);
7840b57cec5SDimitry Andric       else {
7850b57cec5SDimitry Andric         ShAmt = 0;
7860b57cec5SDimitry Andric         ShOpcVal = ARM_AM::no_shift;
7870b57cec5SDimitry Andric       }
7880b57cec5SDimitry Andric     } else {
7890b57cec5SDimitry Andric       ShOpcVal = ARM_AM::no_shift;
7900b57cec5SDimitry Andric     }
7910b57cec5SDimitry Andric   }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   // Try matching (R shl C) + (R).
7940b57cec5SDimitry Andric   if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift &&
7950b57cec5SDimitry Andric       !(Subtarget->isLikeA9() || Subtarget->isSwift() ||
7960b57cec5SDimitry Andric         N.getOperand(0).hasOneUse())) {
7970b57cec5SDimitry Andric     ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0).getOpcode());
7980b57cec5SDimitry Andric     if (ShOpcVal != ARM_AM::no_shift) {
7990b57cec5SDimitry Andric       // Check to see if the RHS of the shift is a constant, if not, we can't
8000b57cec5SDimitry Andric       // fold it.
8010b57cec5SDimitry Andric       if (ConstantSDNode *Sh =
8020b57cec5SDimitry Andric           dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) {
8030b57cec5SDimitry Andric         ShAmt = Sh->getZExtValue();
8040b57cec5SDimitry Andric         if (isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt)) {
8050b57cec5SDimitry Andric           Offset = N.getOperand(0).getOperand(0);
8060b57cec5SDimitry Andric           Base = N.getOperand(1);
8070b57cec5SDimitry Andric         } else {
8080b57cec5SDimitry Andric           ShAmt = 0;
8090b57cec5SDimitry Andric           ShOpcVal = ARM_AM::no_shift;
8100b57cec5SDimitry Andric         }
8110b57cec5SDimitry Andric       } else {
8120b57cec5SDimitry Andric         ShOpcVal = ARM_AM::no_shift;
8130b57cec5SDimitry Andric       }
8140b57cec5SDimitry Andric     }
8150b57cec5SDimitry Andric   }
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric   // If Offset is a multiply-by-constant and it's profitable to extract a shift
8180b57cec5SDimitry Andric   // and use it in a shifted operand do so.
8190b57cec5SDimitry Andric   if (Offset.getOpcode() == ISD::MUL && N.hasOneUse()) {
8200b57cec5SDimitry Andric     unsigned PowerOfTwo = 0;
8210b57cec5SDimitry Andric     SDValue NewMulConst;
8220b57cec5SDimitry Andric     if (canExtractShiftFromMul(Offset, 31, PowerOfTwo, NewMulConst)) {
8230b57cec5SDimitry Andric       HandleSDNode Handle(Offset);
8240b57cec5SDimitry Andric       replaceDAGValue(Offset.getOperand(1), NewMulConst);
8250b57cec5SDimitry Andric       Offset = Handle.getValue();
8260b57cec5SDimitry Andric       ShAmt = PowerOfTwo;
8270b57cec5SDimitry Andric       ShOpcVal = ARM_AM::lsl;
8280b57cec5SDimitry Andric     }
8290b57cec5SDimitry Andric   }
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric   Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
8320b57cec5SDimitry Andric                                   SDLoc(N), MVT::i32);
8330b57cec5SDimitry Andric   return true;
8340b57cec5SDimitry Andric }
8350b57cec5SDimitry Andric 
SelectAddrMode2OffsetReg(SDNode * Op,SDValue N,SDValue & Offset,SDValue & Opc)8360b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode2OffsetReg(SDNode *Op, SDValue N,
8370b57cec5SDimitry Andric                                             SDValue &Offset, SDValue &Opc) {
8380b57cec5SDimitry Andric   unsigned Opcode = Op->getOpcode();
8390b57cec5SDimitry Andric   ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
8400b57cec5SDimitry Andric     ? cast<LoadSDNode>(Op)->getAddressingMode()
8410b57cec5SDimitry Andric     : cast<StoreSDNode>(Op)->getAddressingMode();
8420b57cec5SDimitry Andric   ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
8430b57cec5SDimitry Andric     ? ARM_AM::add : ARM_AM::sub;
8440b57cec5SDimitry Andric   int Val;
8450b57cec5SDimitry Andric   if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val))
8460b57cec5SDimitry Andric     return false;
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric   Offset = N;
8490b57cec5SDimitry Andric   ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
8500b57cec5SDimitry Andric   unsigned ShAmt = 0;
8510b57cec5SDimitry Andric   if (ShOpcVal != ARM_AM::no_shift) {
8520b57cec5SDimitry Andric     // Check to see if the RHS of the shift is a constant, if not, we can't fold
8530b57cec5SDimitry Andric     // it.
8540b57cec5SDimitry Andric     if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
8550b57cec5SDimitry Andric       ShAmt = Sh->getZExtValue();
8560b57cec5SDimitry Andric       if (isShifterOpProfitable(N, ShOpcVal, ShAmt))
8570b57cec5SDimitry Andric         Offset = N.getOperand(0);
8580b57cec5SDimitry Andric       else {
8590b57cec5SDimitry Andric         ShAmt = 0;
8600b57cec5SDimitry Andric         ShOpcVal = ARM_AM::no_shift;
8610b57cec5SDimitry Andric       }
8620b57cec5SDimitry Andric     } else {
8630b57cec5SDimitry Andric       ShOpcVal = ARM_AM::no_shift;
8640b57cec5SDimitry Andric     }
8650b57cec5SDimitry Andric   }
8660b57cec5SDimitry Andric 
8670b57cec5SDimitry Andric   Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
8680b57cec5SDimitry Andric                                   SDLoc(N), MVT::i32);
8690b57cec5SDimitry Andric   return true;
8700b57cec5SDimitry Andric }
8710b57cec5SDimitry Andric 
SelectAddrMode2OffsetImmPre(SDNode * Op,SDValue N,SDValue & Offset,SDValue & Opc)8720b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N,
8730b57cec5SDimitry Andric                                             SDValue &Offset, SDValue &Opc) {
8740b57cec5SDimitry Andric   unsigned Opcode = Op->getOpcode();
8750b57cec5SDimitry Andric   ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
8760b57cec5SDimitry Andric     ? cast<LoadSDNode>(Op)->getAddressingMode()
8770b57cec5SDimitry Andric     : cast<StoreSDNode>(Op)->getAddressingMode();
8780b57cec5SDimitry Andric   ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
8790b57cec5SDimitry Andric     ? ARM_AM::add : ARM_AM::sub;
8800b57cec5SDimitry Andric   int Val;
8810b57cec5SDimitry Andric   if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits.
8820b57cec5SDimitry Andric     if (AddSub == ARM_AM::sub) Val *= -1;
8830b57cec5SDimitry Andric     Offset = CurDAG->getRegister(0, MVT::i32);
8840b57cec5SDimitry Andric     Opc = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32);
8850b57cec5SDimitry Andric     return true;
8860b57cec5SDimitry Andric   }
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric   return false;
8890b57cec5SDimitry Andric }
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric 
SelectAddrMode2OffsetImm(SDNode * Op,SDValue N,SDValue & Offset,SDValue & Opc)8920b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode2OffsetImm(SDNode *Op, SDValue N,
8930b57cec5SDimitry Andric                                             SDValue &Offset, SDValue &Opc) {
8940b57cec5SDimitry Andric   unsigned Opcode = Op->getOpcode();
8950b57cec5SDimitry Andric   ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
8960b57cec5SDimitry Andric     ? cast<LoadSDNode>(Op)->getAddressingMode()
8970b57cec5SDimitry Andric     : cast<StoreSDNode>(Op)->getAddressingMode();
8980b57cec5SDimitry Andric   ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
8990b57cec5SDimitry Andric     ? ARM_AM::add : ARM_AM::sub;
9000b57cec5SDimitry Andric   int Val;
9010b57cec5SDimitry Andric   if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits.
9020b57cec5SDimitry Andric     Offset = CurDAG->getRegister(0, MVT::i32);
9030b57cec5SDimitry Andric     Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val,
9040b57cec5SDimitry Andric                                                       ARM_AM::no_shift),
9050b57cec5SDimitry Andric                                     SDLoc(Op), MVT::i32);
9060b57cec5SDimitry Andric     return true;
9070b57cec5SDimitry Andric   }
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric   return false;
9100b57cec5SDimitry Andric }
9110b57cec5SDimitry Andric 
SelectAddrOffsetNone(SDValue N,SDValue & Base)9120b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrOffsetNone(SDValue N, SDValue &Base) {
9130b57cec5SDimitry Andric   Base = N;
9140b57cec5SDimitry Andric   return true;
9150b57cec5SDimitry Andric }
9160b57cec5SDimitry Andric 
SelectAddrMode3(SDValue N,SDValue & Base,SDValue & Offset,SDValue & Opc)9170b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode3(SDValue N,
9180b57cec5SDimitry Andric                                       SDValue &Base, SDValue &Offset,
9190b57cec5SDimitry Andric                                       SDValue &Opc) {
9200b57cec5SDimitry Andric   if (N.getOpcode() == ISD::SUB) {
9210b57cec5SDimitry Andric     // X - C  is canonicalize to X + -C, no need to handle it here.
9220b57cec5SDimitry Andric     Base = N.getOperand(0);
9230b57cec5SDimitry Andric     Offset = N.getOperand(1);
9240b57cec5SDimitry Andric     Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0), SDLoc(N),
9250b57cec5SDimitry Andric                                     MVT::i32);
9260b57cec5SDimitry Andric     return true;
9270b57cec5SDimitry Andric   }
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric   if (!CurDAG->isBaseWithConstantOffset(N)) {
9300b57cec5SDimitry Andric     Base = N;
9310b57cec5SDimitry Andric     if (N.getOpcode() == ISD::FrameIndex) {
9320b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(N)->getIndex();
9330b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
9340b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
9350b57cec5SDimitry Andric     }
9360b57cec5SDimitry Andric     Offset = CurDAG->getRegister(0, MVT::i32);
9370b57cec5SDimitry Andric     Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), SDLoc(N),
9380b57cec5SDimitry Andric                                     MVT::i32);
9390b57cec5SDimitry Andric     return true;
9400b57cec5SDimitry Andric   }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   // If the RHS is +/- imm8, fold into addr mode.
9430b57cec5SDimitry Andric   int RHSC;
9440b57cec5SDimitry Andric   if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
9450b57cec5SDimitry Andric                               -256 + 1, 256, RHSC)) { // 8 bits.
9460b57cec5SDimitry Andric     Base = N.getOperand(0);
9470b57cec5SDimitry Andric     if (Base.getOpcode() == ISD::FrameIndex) {
9480b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(Base)->getIndex();
9490b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
9500b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
9510b57cec5SDimitry Andric     }
9520b57cec5SDimitry Andric     Offset = CurDAG->getRegister(0, MVT::i32);
9530b57cec5SDimitry Andric 
9540b57cec5SDimitry Andric     ARM_AM::AddrOpc AddSub = ARM_AM::add;
9550b57cec5SDimitry Andric     if (RHSC < 0) {
9560b57cec5SDimitry Andric       AddSub = ARM_AM::sub;
9570b57cec5SDimitry Andric       RHSC = -RHSC;
9580b57cec5SDimitry Andric     }
9590b57cec5SDimitry Andric     Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC), SDLoc(N),
9600b57cec5SDimitry Andric                                     MVT::i32);
9610b57cec5SDimitry Andric     return true;
9620b57cec5SDimitry Andric   }
9630b57cec5SDimitry Andric 
9640b57cec5SDimitry Andric   Base = N.getOperand(0);
9650b57cec5SDimitry Andric   Offset = N.getOperand(1);
9660b57cec5SDimitry Andric   Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), SDLoc(N),
9670b57cec5SDimitry Andric                                   MVT::i32);
9680b57cec5SDimitry Andric   return true;
9690b57cec5SDimitry Andric }
9700b57cec5SDimitry Andric 
SelectAddrMode3Offset(SDNode * Op,SDValue N,SDValue & Offset,SDValue & Opc)9710b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N,
9720b57cec5SDimitry Andric                                             SDValue &Offset, SDValue &Opc) {
9730b57cec5SDimitry Andric   unsigned Opcode = Op->getOpcode();
9740b57cec5SDimitry Andric   ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
9750b57cec5SDimitry Andric     ? cast<LoadSDNode>(Op)->getAddressingMode()
9760b57cec5SDimitry Andric     : cast<StoreSDNode>(Op)->getAddressingMode();
9770b57cec5SDimitry Andric   ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
9780b57cec5SDimitry Andric     ? ARM_AM::add : ARM_AM::sub;
9790b57cec5SDimitry Andric   int Val;
9800b57cec5SDimitry Andric   if (isScaledConstantInRange(N, /*Scale=*/1, 0, 256, Val)) { // 12 bits.
9810b57cec5SDimitry Andric     Offset = CurDAG->getRegister(0, MVT::i32);
9820b57cec5SDimitry Andric     Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), SDLoc(Op),
9830b57cec5SDimitry Andric                                     MVT::i32);
9840b57cec5SDimitry Andric     return true;
9850b57cec5SDimitry Andric   }
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric   Offset = N;
9880b57cec5SDimitry Andric   Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), SDLoc(Op),
9890b57cec5SDimitry Andric                                   MVT::i32);
9900b57cec5SDimitry Andric   return true;
9910b57cec5SDimitry Andric }
9920b57cec5SDimitry Andric 
IsAddressingMode5(SDValue N,SDValue & Base,SDValue & Offset,bool FP16)9930b57cec5SDimitry Andric bool ARMDAGToDAGISel::IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset,
9940b57cec5SDimitry Andric                                         bool FP16) {
9950b57cec5SDimitry Andric   if (!CurDAG->isBaseWithConstantOffset(N)) {
9960b57cec5SDimitry Andric     Base = N;
9970b57cec5SDimitry Andric     if (N.getOpcode() == ISD::FrameIndex) {
9980b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(N)->getIndex();
9990b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
10000b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
10010b57cec5SDimitry Andric     } else if (N.getOpcode() == ARMISD::Wrapper &&
10020b57cec5SDimitry Andric                N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
10030b57cec5SDimitry Andric                N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
10040b57cec5SDimitry Andric                N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
10050b57cec5SDimitry Andric       Base = N.getOperand(0);
10060b57cec5SDimitry Andric     }
10070b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
10080b57cec5SDimitry Andric                                        SDLoc(N), MVT::i32);
10090b57cec5SDimitry Andric     return true;
10100b57cec5SDimitry Andric   }
10110b57cec5SDimitry Andric 
10120b57cec5SDimitry Andric   // If the RHS is +/- imm8, fold into addr mode.
10130b57cec5SDimitry Andric   int RHSC;
10140b57cec5SDimitry Andric   const int Scale = FP16 ? 2 : 4;
10150b57cec5SDimitry Andric 
10160b57cec5SDimitry Andric   if (isScaledConstantInRange(N.getOperand(1), Scale, -255, 256, RHSC)) {
10170b57cec5SDimitry Andric     Base = N.getOperand(0);
10180b57cec5SDimitry Andric     if (Base.getOpcode() == ISD::FrameIndex) {
10190b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(Base)->getIndex();
10200b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
10210b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
10220b57cec5SDimitry Andric     }
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric     ARM_AM::AddrOpc AddSub = ARM_AM::add;
10250b57cec5SDimitry Andric     if (RHSC < 0) {
10260b57cec5SDimitry Andric       AddSub = ARM_AM::sub;
10270b57cec5SDimitry Andric       RHSC = -RHSC;
10280b57cec5SDimitry Andric     }
10290b57cec5SDimitry Andric 
10300b57cec5SDimitry Andric     if (FP16)
10310b57cec5SDimitry Andric       Offset = CurDAG->getTargetConstant(ARM_AM::getAM5FP16Opc(AddSub, RHSC),
10320b57cec5SDimitry Andric                                          SDLoc(N), MVT::i32);
10330b57cec5SDimitry Andric     else
10340b57cec5SDimitry Andric       Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC),
10350b57cec5SDimitry Andric                                          SDLoc(N), MVT::i32);
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric     return true;
10380b57cec5SDimitry Andric   }
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric   Base = N;
10410b57cec5SDimitry Andric 
10420b57cec5SDimitry Andric   if (FP16)
10430b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(ARM_AM::getAM5FP16Opc(ARM_AM::add, 0),
10440b57cec5SDimitry Andric                                        SDLoc(N), MVT::i32);
10450b57cec5SDimitry Andric   else
10460b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
10470b57cec5SDimitry Andric                                        SDLoc(N), MVT::i32);
10480b57cec5SDimitry Andric 
10490b57cec5SDimitry Andric   return true;
10500b57cec5SDimitry Andric }
10510b57cec5SDimitry Andric 
SelectAddrMode5(SDValue N,SDValue & Base,SDValue & Offset)10520b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
10530b57cec5SDimitry Andric                                       SDValue &Base, SDValue &Offset) {
10540b57cec5SDimitry Andric   return IsAddressingMode5(N, Base, Offset, /*FP16=*/ false);
10550b57cec5SDimitry Andric }
10560b57cec5SDimitry Andric 
SelectAddrMode5FP16(SDValue N,SDValue & Base,SDValue & Offset)10570b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode5FP16(SDValue N,
10580b57cec5SDimitry Andric                                           SDValue &Base, SDValue &Offset) {
10590b57cec5SDimitry Andric   return IsAddressingMode5(N, Base, Offset, /*FP16=*/ true);
10600b57cec5SDimitry Andric }
10610b57cec5SDimitry Andric 
SelectAddrMode6(SDNode * Parent,SDValue N,SDValue & Addr,SDValue & Align)10620b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,
10630b57cec5SDimitry Andric                                       SDValue &Align) {
10640b57cec5SDimitry Andric   Addr = N;
10650b57cec5SDimitry Andric 
10660b57cec5SDimitry Andric   unsigned Alignment = 0;
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric   MemSDNode *MemN = cast<MemSDNode>(Parent);
10690b57cec5SDimitry Andric 
10700b57cec5SDimitry Andric   if (isa<LSBaseSDNode>(MemN) ||
10710b57cec5SDimitry Andric       ((MemN->getOpcode() == ARMISD::VST1_UPD ||
10720b57cec5SDimitry Andric         MemN->getOpcode() == ARMISD::VLD1_UPD) &&
10730b57cec5SDimitry Andric        MemN->getConstantOperandVal(MemN->getNumOperands() - 1) == 1)) {
10740b57cec5SDimitry Andric     // This case occurs only for VLD1-lane/dup and VST1-lane instructions.
10750b57cec5SDimitry Andric     // The maximum alignment is equal to the memory size being referenced.
107681ad6265SDimitry Andric     llvm::Align MMOAlign = MemN->getAlign();
10770b57cec5SDimitry Andric     unsigned MemSize = MemN->getMemoryVT().getSizeInBits() / 8;
107881ad6265SDimitry Andric     if (MMOAlign.value() >= MemSize && MemSize > 1)
10790b57cec5SDimitry Andric       Alignment = MemSize;
10800b57cec5SDimitry Andric   } else {
10810b57cec5SDimitry Andric     // All other uses of addrmode6 are for intrinsics.  For now just record
10820b57cec5SDimitry Andric     // the raw alignment value; it will be refined later based on the legal
10830b57cec5SDimitry Andric     // alignment operands for the intrinsic.
108481ad6265SDimitry Andric     Alignment = MemN->getAlign().value();
10850b57cec5SDimitry Andric   }
10860b57cec5SDimitry Andric 
10870b57cec5SDimitry Andric   Align = CurDAG->getTargetConstant(Alignment, SDLoc(N), MVT::i32);
10880b57cec5SDimitry Andric   return true;
10890b57cec5SDimitry Andric }
10900b57cec5SDimitry Andric 
SelectAddrMode6Offset(SDNode * Op,SDValue N,SDValue & Offset)10910b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrMode6Offset(SDNode *Op, SDValue N,
10920b57cec5SDimitry Andric                                             SDValue &Offset) {
10930b57cec5SDimitry Andric   LSBaseSDNode *LdSt = cast<LSBaseSDNode>(Op);
10940b57cec5SDimitry Andric   ISD::MemIndexedMode AM = LdSt->getAddressingMode();
10950b57cec5SDimitry Andric   if (AM != ISD::POST_INC)
10960b57cec5SDimitry Andric     return false;
10970b57cec5SDimitry Andric   Offset = N;
10980b57cec5SDimitry Andric   if (ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N)) {
10990b57cec5SDimitry Andric     if (NC->getZExtValue() * 8 == LdSt->getMemoryVT().getSizeInBits())
11000b57cec5SDimitry Andric       Offset = CurDAG->getRegister(0, MVT::i32);
11010b57cec5SDimitry Andric   }
11020b57cec5SDimitry Andric   return true;
11030b57cec5SDimitry Andric }
11040b57cec5SDimitry Andric 
SelectAddrModePC(SDValue N,SDValue & Offset,SDValue & Label)11050b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectAddrModePC(SDValue N,
11060b57cec5SDimitry Andric                                        SDValue &Offset, SDValue &Label) {
11070b57cec5SDimitry Andric   if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) {
11080b57cec5SDimitry Andric     Offset = N.getOperand(0);
11090b57cec5SDimitry Andric     SDValue N1 = N.getOperand(1);
11101db9f3b2SDimitry Andric     Label = CurDAG->getTargetConstant(N1->getAsZExtVal(), SDLoc(N), MVT::i32);
11110b57cec5SDimitry Andric     return true;
11120b57cec5SDimitry Andric   }
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric   return false;
11150b57cec5SDimitry Andric }
11160b57cec5SDimitry Andric 
11170b57cec5SDimitry Andric 
11180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11190b57cec5SDimitry Andric //                         Thumb Addressing Modes
11200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11210b57cec5SDimitry Andric 
shouldUseZeroOffsetLdSt(SDValue N)11220b57cec5SDimitry Andric static bool shouldUseZeroOffsetLdSt(SDValue N) {
11230b57cec5SDimitry Andric   // Negative numbers are difficult to materialise in thumb1. If we are
11240b57cec5SDimitry Andric   // selecting the add of a negative, instead try to select ri with a zero
11250b57cec5SDimitry Andric   // offset, so create the add node directly which will become a sub.
11260b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD)
11270b57cec5SDimitry Andric     return false;
11280b57cec5SDimitry Andric 
11290b57cec5SDimitry Andric   // Look for an imm which is not legal for ld/st, but is legal for sub.
11300b57cec5SDimitry Andric   if (auto C = dyn_cast<ConstantSDNode>(N.getOperand(1)))
11310b57cec5SDimitry Andric     return C->getSExtValue() < 0 && C->getSExtValue() >= -255;
11320b57cec5SDimitry Andric 
11330b57cec5SDimitry Andric   return false;
11340b57cec5SDimitry Andric }
11350b57cec5SDimitry Andric 
SelectThumbAddrModeRRSext(SDValue N,SDValue & Base,SDValue & Offset)11360b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectThumbAddrModeRRSext(SDValue N, SDValue &Base,
11370b57cec5SDimitry Andric                                                 SDValue &Offset) {
11380b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) {
11395f757f3fSDimitry Andric     if (!isNullConstant(N))
11400b57cec5SDimitry Andric       return false;
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric     Base = Offset = N;
11430b57cec5SDimitry Andric     return true;
11440b57cec5SDimitry Andric   }
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric   Base = N.getOperand(0);
11470b57cec5SDimitry Andric   Offset = N.getOperand(1);
11480b57cec5SDimitry Andric   return true;
11490b57cec5SDimitry Andric }
11500b57cec5SDimitry Andric 
SelectThumbAddrModeRR(SDValue N,SDValue & Base,SDValue & Offset)11510b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, SDValue &Base,
11520b57cec5SDimitry Andric                                             SDValue &Offset) {
11530b57cec5SDimitry Andric   if (shouldUseZeroOffsetLdSt(N))
11540b57cec5SDimitry Andric     return false; // Select ri instead
11550b57cec5SDimitry Andric   return SelectThumbAddrModeRRSext(N, Base, Offset);
11560b57cec5SDimitry Andric }
11570b57cec5SDimitry Andric 
11580b57cec5SDimitry Andric bool
SelectThumbAddrModeImm5S(SDValue N,unsigned Scale,SDValue & Base,SDValue & OffImm)11590b57cec5SDimitry Andric ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale,
11600b57cec5SDimitry Andric                                           SDValue &Base, SDValue &OffImm) {
11610b57cec5SDimitry Andric   if (shouldUseZeroOffsetLdSt(N)) {
11620b57cec5SDimitry Andric     Base = N;
11630b57cec5SDimitry Andric     OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
11640b57cec5SDimitry Andric     return true;
11650b57cec5SDimitry Andric   }
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric   if (!CurDAG->isBaseWithConstantOffset(N)) {
11680b57cec5SDimitry Andric     if (N.getOpcode() == ISD::ADD) {
11690b57cec5SDimitry Andric       return false; // We want to select register offset instead
11700b57cec5SDimitry Andric     } else if (N.getOpcode() == ARMISD::Wrapper &&
11710b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
11720b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
11730b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetConstantPool &&
11740b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
11750b57cec5SDimitry Andric       Base = N.getOperand(0);
11760b57cec5SDimitry Andric     } else {
11770b57cec5SDimitry Andric       Base = N;
11780b57cec5SDimitry Andric     }
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric     OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
11810b57cec5SDimitry Andric     return true;
11820b57cec5SDimitry Andric   }
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric   // If the RHS is + imm5 * scale, fold into addr mode.
11850b57cec5SDimitry Andric   int RHSC;
11860b57cec5SDimitry Andric   if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) {
11870b57cec5SDimitry Andric     Base = N.getOperand(0);
11880b57cec5SDimitry Andric     OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
11890b57cec5SDimitry Andric     return true;
11900b57cec5SDimitry Andric   }
11910b57cec5SDimitry Andric 
11920b57cec5SDimitry Andric   // Offset is too large, so use register offset instead.
11930b57cec5SDimitry Andric   return false;
11940b57cec5SDimitry Andric }
11950b57cec5SDimitry Andric 
11960b57cec5SDimitry Andric bool
SelectThumbAddrModeImm5S4(SDValue N,SDValue & Base,SDValue & OffImm)11970b57cec5SDimitry Andric ARMDAGToDAGISel::SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base,
11980b57cec5SDimitry Andric                                            SDValue &OffImm) {
11990b57cec5SDimitry Andric   return SelectThumbAddrModeImm5S(N, 4, Base, OffImm);
12000b57cec5SDimitry Andric }
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric bool
SelectThumbAddrModeImm5S2(SDValue N,SDValue & Base,SDValue & OffImm)12030b57cec5SDimitry Andric ARMDAGToDAGISel::SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base,
12040b57cec5SDimitry Andric                                            SDValue &OffImm) {
12050b57cec5SDimitry Andric   return SelectThumbAddrModeImm5S(N, 2, Base, OffImm);
12060b57cec5SDimitry Andric }
12070b57cec5SDimitry Andric 
12080b57cec5SDimitry Andric bool
SelectThumbAddrModeImm5S1(SDValue N,SDValue & Base,SDValue & OffImm)12090b57cec5SDimitry Andric ARMDAGToDAGISel::SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
12100b57cec5SDimitry Andric                                            SDValue &OffImm) {
12110b57cec5SDimitry Andric   return SelectThumbAddrModeImm5S(N, 1, Base, OffImm);
12120b57cec5SDimitry Andric }
12130b57cec5SDimitry Andric 
SelectThumbAddrModeSP(SDValue N,SDValue & Base,SDValue & OffImm)12140b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N,
12150b57cec5SDimitry Andric                                             SDValue &Base, SDValue &OffImm) {
12160b57cec5SDimitry Andric   if (N.getOpcode() == ISD::FrameIndex) {
12170b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(N)->getIndex();
12180b57cec5SDimitry Andric     // Only multiples of 4 are allowed for the offset, so the frame object
12190b57cec5SDimitry Andric     // alignment must be at least 4.
12200b57cec5SDimitry Andric     MachineFrameInfo &MFI = MF->getFrameInfo();
12215ffd83dbSDimitry Andric     if (MFI.getObjectAlign(FI) < Align(4))
12225ffd83dbSDimitry Andric       MFI.setObjectAlignment(FI, Align(4));
12230b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(
12240b57cec5SDimitry Andric         FI, TLI->getPointerTy(CurDAG->getDataLayout()));
12250b57cec5SDimitry Andric     OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
12260b57cec5SDimitry Andric     return true;
12270b57cec5SDimitry Andric   }
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric   if (!CurDAG->isBaseWithConstantOffset(N))
12300b57cec5SDimitry Andric     return false;
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric   if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
12330b57cec5SDimitry Andric     // If the RHS is + imm8 * scale, fold into addr mode.
12340b57cec5SDimitry Andric     int RHSC;
12350b57cec5SDimitry Andric     if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) {
12360b57cec5SDimitry Andric       Base = N.getOperand(0);
12370b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(Base)->getIndex();
12380b57cec5SDimitry Andric       // Make sure the offset is inside the object, or we might fail to
12390b57cec5SDimitry Andric       // allocate an emergency spill slot. (An out-of-range access is UB, but
12400b57cec5SDimitry Andric       // it could show up anyway.)
12410b57cec5SDimitry Andric       MachineFrameInfo &MFI = MF->getFrameInfo();
12420b57cec5SDimitry Andric       if (RHSC * 4 < MFI.getObjectSize(FI)) {
12430b57cec5SDimitry Andric         // For LHS+RHS to result in an offset that's a multiple of 4 the object
12440b57cec5SDimitry Andric         // indexed by the LHS must be 4-byte aligned.
12455ffd83dbSDimitry Andric         if (!MFI.isFixedObjectIndex(FI) && MFI.getObjectAlign(FI) < Align(4))
12465ffd83dbSDimitry Andric           MFI.setObjectAlignment(FI, Align(4));
12475ffd83dbSDimitry Andric         if (MFI.getObjectAlign(FI) >= Align(4)) {
12480b57cec5SDimitry Andric           Base = CurDAG->getTargetFrameIndex(
12490b57cec5SDimitry Andric               FI, TLI->getPointerTy(CurDAG->getDataLayout()));
12500b57cec5SDimitry Andric           OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
12510b57cec5SDimitry Andric           return true;
12520b57cec5SDimitry Andric         }
12530b57cec5SDimitry Andric       }
12540b57cec5SDimitry Andric     }
12550b57cec5SDimitry Andric   }
12560b57cec5SDimitry Andric 
12570b57cec5SDimitry Andric   return false;
12580b57cec5SDimitry Andric }
12590b57cec5SDimitry Andric 
12608bcb0991SDimitry Andric template <unsigned Shift>
SelectTAddrModeImm7(SDValue N,SDValue & Base,SDValue & OffImm)12618bcb0991SDimitry Andric bool ARMDAGToDAGISel::SelectTAddrModeImm7(SDValue N, SDValue &Base,
12628bcb0991SDimitry Andric                                           SDValue &OffImm) {
12638bcb0991SDimitry Andric   if (N.getOpcode() == ISD::SUB || CurDAG->isBaseWithConstantOffset(N)) {
12648bcb0991SDimitry Andric     int RHSC;
12658bcb0991SDimitry Andric     if (isScaledConstantInRange(N.getOperand(1), 1 << Shift, -0x7f, 0x80,
12668bcb0991SDimitry Andric                                 RHSC)) {
12678bcb0991SDimitry Andric       Base = N.getOperand(0);
12688bcb0991SDimitry Andric       if (N.getOpcode() == ISD::SUB)
12698bcb0991SDimitry Andric         RHSC = -RHSC;
12708bcb0991SDimitry Andric       OffImm =
12718bcb0991SDimitry Andric           CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32);
12728bcb0991SDimitry Andric       return true;
12738bcb0991SDimitry Andric     }
12748bcb0991SDimitry Andric   }
12758bcb0991SDimitry Andric 
12768bcb0991SDimitry Andric   // Base only.
12778bcb0991SDimitry Andric   Base = N;
12788bcb0991SDimitry Andric   OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
12798bcb0991SDimitry Andric   return true;
12808bcb0991SDimitry Andric }
12818bcb0991SDimitry Andric 
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12840b57cec5SDimitry Andric //                        Thumb 2 Addressing Modes
12850b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12860b57cec5SDimitry Andric 
12870b57cec5SDimitry Andric 
SelectT2AddrModeImm12(SDValue N,SDValue & Base,SDValue & OffImm)12880b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N,
12890b57cec5SDimitry Andric                                             SDValue &Base, SDValue &OffImm) {
12900b57cec5SDimitry Andric   // Match simple R + imm12 operands.
12910b57cec5SDimitry Andric 
12920b57cec5SDimitry Andric   // Base only.
12930b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
12940b57cec5SDimitry Andric       !CurDAG->isBaseWithConstantOffset(N)) {
12950b57cec5SDimitry Andric     if (N.getOpcode() == ISD::FrameIndex) {
12960b57cec5SDimitry Andric       // Match frame index.
12970b57cec5SDimitry Andric       int FI = cast<FrameIndexSDNode>(N)->getIndex();
12980b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(
12990b57cec5SDimitry Andric           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
13000b57cec5SDimitry Andric       OffImm  = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
13010b57cec5SDimitry Andric       return true;
13020b57cec5SDimitry Andric     }
13030b57cec5SDimitry Andric 
13040b57cec5SDimitry Andric     if (N.getOpcode() == ARMISD::Wrapper &&
13050b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
13060b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
13070b57cec5SDimitry Andric         N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
13080b57cec5SDimitry Andric       Base = N.getOperand(0);
13090b57cec5SDimitry Andric       if (Base.getOpcode() == ISD::TargetConstantPool)
13100b57cec5SDimitry Andric         return false;  // We want to select t2LDRpci instead.
13110b57cec5SDimitry Andric     } else
13120b57cec5SDimitry Andric       Base = N;
13130b57cec5SDimitry Andric     OffImm  = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
13140b57cec5SDimitry Andric     return true;
13150b57cec5SDimitry Andric   }
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
13180b57cec5SDimitry Andric     if (SelectT2AddrModeImm8(N, Base, OffImm))
13190b57cec5SDimitry Andric       // Let t2LDRi8 handle (R - imm8).
13200b57cec5SDimitry Andric       return false;
13210b57cec5SDimitry Andric 
13220b57cec5SDimitry Andric     int RHSC = (int)RHS->getZExtValue();
13230b57cec5SDimitry Andric     if (N.getOpcode() == ISD::SUB)
13240b57cec5SDimitry Andric       RHSC = -RHSC;
13250b57cec5SDimitry Andric 
13260b57cec5SDimitry Andric     if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned)
13270b57cec5SDimitry Andric       Base   = N.getOperand(0);
13280b57cec5SDimitry Andric       if (Base.getOpcode() == ISD::FrameIndex) {
13290b57cec5SDimitry Andric         int FI = cast<FrameIndexSDNode>(Base)->getIndex();
13300b57cec5SDimitry Andric         Base = CurDAG->getTargetFrameIndex(
13310b57cec5SDimitry Andric             FI, TLI->getPointerTy(CurDAG->getDataLayout()));
13320b57cec5SDimitry Andric       }
13330b57cec5SDimitry Andric       OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
13340b57cec5SDimitry Andric       return true;
13350b57cec5SDimitry Andric     }
13360b57cec5SDimitry Andric   }
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric   // Base only.
13390b57cec5SDimitry Andric   Base = N;
13400b57cec5SDimitry Andric   OffImm  = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
13410b57cec5SDimitry Andric   return true;
13420b57cec5SDimitry Andric }
13430b57cec5SDimitry Andric 
13445ffd83dbSDimitry Andric template <unsigned Shift>
SelectT2AddrModeImm8(SDValue N,SDValue & Base,SDValue & OffImm)13455ffd83dbSDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N, SDValue &Base,
13465ffd83dbSDimitry Andric                                            SDValue &OffImm) {
13475ffd83dbSDimitry Andric   if (N.getOpcode() == ISD::SUB || CurDAG->isBaseWithConstantOffset(N)) {
13485ffd83dbSDimitry Andric     int RHSC;
13495ffd83dbSDimitry Andric     if (isScaledConstantInRange(N.getOperand(1), 1 << Shift, -255, 256, RHSC)) {
13505ffd83dbSDimitry Andric       Base = N.getOperand(0);
13515ffd83dbSDimitry Andric       if (Base.getOpcode() == ISD::FrameIndex) {
13525ffd83dbSDimitry Andric         int FI = cast<FrameIndexSDNode>(Base)->getIndex();
13535ffd83dbSDimitry Andric         Base = CurDAG->getTargetFrameIndex(
13545ffd83dbSDimitry Andric             FI, TLI->getPointerTy(CurDAG->getDataLayout()));
13555ffd83dbSDimitry Andric       }
13565ffd83dbSDimitry Andric 
13575ffd83dbSDimitry Andric       if (N.getOpcode() == ISD::SUB)
13585ffd83dbSDimitry Andric         RHSC = -RHSC;
13595ffd83dbSDimitry Andric       OffImm =
13605ffd83dbSDimitry Andric           CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32);
13615ffd83dbSDimitry Andric       return true;
13625ffd83dbSDimitry Andric     }
13635ffd83dbSDimitry Andric   }
13645ffd83dbSDimitry Andric 
13655ffd83dbSDimitry Andric   // Base only.
13665ffd83dbSDimitry Andric   Base = N;
13675ffd83dbSDimitry Andric   OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
13685ffd83dbSDimitry Andric   return true;
13695ffd83dbSDimitry Andric }
13705ffd83dbSDimitry Andric 
SelectT2AddrModeImm8(SDValue N,SDValue & Base,SDValue & OffImm)13710b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N,
13720b57cec5SDimitry Andric                                            SDValue &Base, SDValue &OffImm) {
13730b57cec5SDimitry Andric   // Match simple R - imm8 operands.
13740b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
13750b57cec5SDimitry Andric       !CurDAG->isBaseWithConstantOffset(N))
13760b57cec5SDimitry Andric     return false;
13770b57cec5SDimitry Andric 
13780b57cec5SDimitry Andric   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
13790b57cec5SDimitry Andric     int RHSC = (int)RHS->getSExtValue();
13800b57cec5SDimitry Andric     if (N.getOpcode() == ISD::SUB)
13810b57cec5SDimitry Andric       RHSC = -RHSC;
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric     if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative)
13840b57cec5SDimitry Andric       Base = N.getOperand(0);
13850b57cec5SDimitry Andric       if (Base.getOpcode() == ISD::FrameIndex) {
13860b57cec5SDimitry Andric         int FI = cast<FrameIndexSDNode>(Base)->getIndex();
13870b57cec5SDimitry Andric         Base = CurDAG->getTargetFrameIndex(
13880b57cec5SDimitry Andric             FI, TLI->getPointerTy(CurDAG->getDataLayout()));
13890b57cec5SDimitry Andric       }
13900b57cec5SDimitry Andric       OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
13910b57cec5SDimitry Andric       return true;
13920b57cec5SDimitry Andric     }
13930b57cec5SDimitry Andric   }
13940b57cec5SDimitry Andric 
13950b57cec5SDimitry Andric   return false;
13960b57cec5SDimitry Andric }
13970b57cec5SDimitry Andric 
SelectT2AddrModeImm8Offset(SDNode * Op,SDValue N,SDValue & OffImm)13980b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
13990b57cec5SDimitry Andric                                                  SDValue &OffImm){
14000b57cec5SDimitry Andric   unsigned Opcode = Op->getOpcode();
14010b57cec5SDimitry Andric   ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
14020b57cec5SDimitry Andric     ? cast<LoadSDNode>(Op)->getAddressingMode()
14030b57cec5SDimitry Andric     : cast<StoreSDNode>(Op)->getAddressingMode();
14040b57cec5SDimitry Andric   int RHSC;
14050b57cec5SDimitry Andric   if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x100, RHSC)) { // 8 bits.
14060b57cec5SDimitry Andric     OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC))
14070b57cec5SDimitry Andric       ? CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32)
14080b57cec5SDimitry Andric       : CurDAG->getTargetConstant(-RHSC, SDLoc(N), MVT::i32);
14090b57cec5SDimitry Andric     return true;
14100b57cec5SDimitry Andric   }
14110b57cec5SDimitry Andric 
14120b57cec5SDimitry Andric   return false;
14130b57cec5SDimitry Andric }
14140b57cec5SDimitry Andric 
14150b57cec5SDimitry Andric template <unsigned Shift>
SelectT2AddrModeImm7(SDValue N,SDValue & Base,SDValue & OffImm)14168bcb0991SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm7(SDValue N, SDValue &Base,
14178bcb0991SDimitry Andric                                            SDValue &OffImm) {
14188bcb0991SDimitry Andric   if (N.getOpcode() == ISD::SUB || CurDAG->isBaseWithConstantOffset(N)) {
14198bcb0991SDimitry Andric     int RHSC;
14208bcb0991SDimitry Andric     if (isScaledConstantInRange(N.getOperand(1), 1 << Shift, -0x7f, 0x80,
14218bcb0991SDimitry Andric                                 RHSC)) {
14220b57cec5SDimitry Andric       Base = N.getOperand(0);
14230b57cec5SDimitry Andric       if (Base.getOpcode() == ISD::FrameIndex) {
14240b57cec5SDimitry Andric         int FI = cast<FrameIndexSDNode>(Base)->getIndex();
14250b57cec5SDimitry Andric         Base = CurDAG->getTargetFrameIndex(
14260b57cec5SDimitry Andric             FI, TLI->getPointerTy(CurDAG->getDataLayout()));
14270b57cec5SDimitry Andric       }
14288bcb0991SDimitry Andric 
14298bcb0991SDimitry Andric       if (N.getOpcode() == ISD::SUB)
14308bcb0991SDimitry Andric         RHSC = -RHSC;
14318bcb0991SDimitry Andric       OffImm =
14328bcb0991SDimitry Andric           CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32);
14330b57cec5SDimitry Andric       return true;
14340b57cec5SDimitry Andric     }
14350b57cec5SDimitry Andric   }
14360b57cec5SDimitry Andric 
14370b57cec5SDimitry Andric   // Base only.
14380b57cec5SDimitry Andric   Base = N;
14390b57cec5SDimitry Andric   OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
14400b57cec5SDimitry Andric   return true;
14410b57cec5SDimitry Andric }
14420b57cec5SDimitry Andric 
14438bcb0991SDimitry Andric template <unsigned Shift>
SelectT2AddrModeImm7Offset(SDNode * Op,SDValue N,SDValue & OffImm)14448bcb0991SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N,
14458bcb0991SDimitry Andric                                                  SDValue &OffImm) {
14468bcb0991SDimitry Andric   return SelectT2AddrModeImm7Offset(Op, N, OffImm, Shift);
14478bcb0991SDimitry Andric }
14488bcb0991SDimitry Andric 
SelectT2AddrModeImm7Offset(SDNode * Op,SDValue N,SDValue & OffImm,unsigned Shift)14498bcb0991SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N,
14508bcb0991SDimitry Andric                                                  SDValue &OffImm,
14518bcb0991SDimitry Andric                                                  unsigned Shift) {
14528bcb0991SDimitry Andric   unsigned Opcode = Op->getOpcode();
1453480093f4SDimitry Andric   ISD::MemIndexedMode AM;
1454480093f4SDimitry Andric   switch (Opcode) {
1455480093f4SDimitry Andric   case ISD::LOAD:
1456480093f4SDimitry Andric     AM = cast<LoadSDNode>(Op)->getAddressingMode();
1457480093f4SDimitry Andric     break;
1458480093f4SDimitry Andric   case ISD::STORE:
1459480093f4SDimitry Andric     AM = cast<StoreSDNode>(Op)->getAddressingMode();
1460480093f4SDimitry Andric     break;
1461480093f4SDimitry Andric   case ISD::MLOAD:
1462480093f4SDimitry Andric     AM = cast<MaskedLoadSDNode>(Op)->getAddressingMode();
1463480093f4SDimitry Andric     break;
1464480093f4SDimitry Andric   case ISD::MSTORE:
1465480093f4SDimitry Andric     AM = cast<MaskedStoreSDNode>(Op)->getAddressingMode();
1466480093f4SDimitry Andric     break;
1467480093f4SDimitry Andric   default:
1468480093f4SDimitry Andric     llvm_unreachable("Unexpected Opcode for Imm7Offset");
1469480093f4SDimitry Andric   }
1470480093f4SDimitry Andric 
14718bcb0991SDimitry Andric   int RHSC;
1472480093f4SDimitry Andric   // 7 bit constant, shifted by Shift.
1473480093f4SDimitry Andric   if (isScaledConstantInRange(N, 1 << Shift, 0, 0x80, RHSC)) {
14748bcb0991SDimitry Andric     OffImm =
14758bcb0991SDimitry Andric         ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC))
14768bcb0991SDimitry Andric             ? CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32)
14778bcb0991SDimitry Andric             : CurDAG->getTargetConstant(-RHSC * (1 << Shift), SDLoc(N),
14788bcb0991SDimitry Andric                                         MVT::i32);
14798bcb0991SDimitry Andric     return true;
14808bcb0991SDimitry Andric   }
14818bcb0991SDimitry Andric   return false;
14828bcb0991SDimitry Andric }
14838bcb0991SDimitry Andric 
1484480093f4SDimitry Andric template <int Min, int Max>
SelectImmediateInRange(SDValue N,SDValue & OffImm)1485480093f4SDimitry Andric bool ARMDAGToDAGISel::SelectImmediateInRange(SDValue N, SDValue &OffImm) {
1486480093f4SDimitry Andric   int Val;
1487480093f4SDimitry Andric   if (isScaledConstantInRange(N, 1, Min, Max, Val)) {
1488480093f4SDimitry Andric     OffImm = CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
1489480093f4SDimitry Andric     return true;
1490480093f4SDimitry Andric   }
1491480093f4SDimitry Andric   return false;
1492480093f4SDimitry Andric }
1493480093f4SDimitry Andric 
SelectT2AddrModeSoReg(SDValue N,SDValue & Base,SDValue & OffReg,SDValue & ShImm)14940b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N,
14950b57cec5SDimitry Andric                                             SDValue &Base,
14960b57cec5SDimitry Andric                                             SDValue &OffReg, SDValue &ShImm) {
14970b57cec5SDimitry Andric   // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12.
14980b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N))
14990b57cec5SDimitry Andric     return false;
15000b57cec5SDimitry Andric 
15010b57cec5SDimitry Andric   // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8.
15020b57cec5SDimitry Andric   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
15030b57cec5SDimitry Andric     int RHSC = (int)RHS->getZExtValue();
15040b57cec5SDimitry Andric     if (RHSC >= 0 && RHSC < 0x1000) // 12 bits (unsigned)
15050b57cec5SDimitry Andric       return false;
15060b57cec5SDimitry Andric     else if (RHSC < 0 && RHSC >= -255) // 8 bits
15070b57cec5SDimitry Andric       return false;
15080b57cec5SDimitry Andric   }
15090b57cec5SDimitry Andric 
15100b57cec5SDimitry Andric   // Look for (R + R) or (R + (R << [1,2,3])).
15110b57cec5SDimitry Andric   unsigned ShAmt = 0;
15120b57cec5SDimitry Andric   Base   = N.getOperand(0);
15130b57cec5SDimitry Andric   OffReg = N.getOperand(1);
15140b57cec5SDimitry Andric 
15150b57cec5SDimitry Andric   // Swap if it is ((R << c) + R).
15160b57cec5SDimitry Andric   ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg.getOpcode());
15170b57cec5SDimitry Andric   if (ShOpcVal != ARM_AM::lsl) {
15180b57cec5SDimitry Andric     ShOpcVal = ARM_AM::getShiftOpcForNode(Base.getOpcode());
15190b57cec5SDimitry Andric     if (ShOpcVal == ARM_AM::lsl)
15200b57cec5SDimitry Andric       std::swap(Base, OffReg);
15210b57cec5SDimitry Andric   }
15220b57cec5SDimitry Andric 
15230b57cec5SDimitry Andric   if (ShOpcVal == ARM_AM::lsl) {
15240b57cec5SDimitry Andric     // Check to see if the RHS of the shift is a constant, if not, we can't fold
15250b57cec5SDimitry Andric     // it.
15260b57cec5SDimitry Andric     if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) {
15270b57cec5SDimitry Andric       ShAmt = Sh->getZExtValue();
15280b57cec5SDimitry Andric       if (ShAmt < 4 && isShifterOpProfitable(OffReg, ShOpcVal, ShAmt))
15290b57cec5SDimitry Andric         OffReg = OffReg.getOperand(0);
15300b57cec5SDimitry Andric       else {
15310b57cec5SDimitry Andric         ShAmt = 0;
15320b57cec5SDimitry Andric       }
15330b57cec5SDimitry Andric     }
15340b57cec5SDimitry Andric   }
15350b57cec5SDimitry Andric 
15360b57cec5SDimitry Andric   // If OffReg is a multiply-by-constant and it's profitable to extract a shift
15370b57cec5SDimitry Andric   // and use it in a shifted operand do so.
15380b57cec5SDimitry Andric   if (OffReg.getOpcode() == ISD::MUL && N.hasOneUse()) {
15390b57cec5SDimitry Andric     unsigned PowerOfTwo = 0;
15400b57cec5SDimitry Andric     SDValue NewMulConst;
15410b57cec5SDimitry Andric     if (canExtractShiftFromMul(OffReg, 3, PowerOfTwo, NewMulConst)) {
15420b57cec5SDimitry Andric       HandleSDNode Handle(OffReg);
15430b57cec5SDimitry Andric       replaceDAGValue(OffReg.getOperand(1), NewMulConst);
15440b57cec5SDimitry Andric       OffReg = Handle.getValue();
15450b57cec5SDimitry Andric       ShAmt = PowerOfTwo;
15460b57cec5SDimitry Andric     }
15470b57cec5SDimitry Andric   }
15480b57cec5SDimitry Andric 
15490b57cec5SDimitry Andric   ShImm = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32);
15500b57cec5SDimitry Andric 
15510b57cec5SDimitry Andric   return true;
15520b57cec5SDimitry Andric }
15530b57cec5SDimitry Andric 
SelectT2AddrModeExclusive(SDValue N,SDValue & Base,SDValue & OffImm)15540b57cec5SDimitry Andric bool ARMDAGToDAGISel::SelectT2AddrModeExclusive(SDValue N, SDValue &Base,
15550b57cec5SDimitry Andric                                                 SDValue &OffImm) {
15560b57cec5SDimitry Andric   // This *must* succeed since it's used for the irreplaceable ldrex and strex
15570b57cec5SDimitry Andric   // instructions.
15580b57cec5SDimitry Andric   Base = N;
15590b57cec5SDimitry Andric   OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
15600b57cec5SDimitry Andric 
15610b57cec5SDimitry Andric   if (N.getOpcode() != ISD::ADD || !CurDAG->isBaseWithConstantOffset(N))
15620b57cec5SDimitry Andric     return true;
15630b57cec5SDimitry Andric 
15640b57cec5SDimitry Andric   ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
15650b57cec5SDimitry Andric   if (!RHS)
15660b57cec5SDimitry Andric     return true;
15670b57cec5SDimitry Andric 
15680b57cec5SDimitry Andric   uint32_t RHSC = (int)RHS->getZExtValue();
15690b57cec5SDimitry Andric   if (RHSC > 1020 || RHSC % 4 != 0)
15700b57cec5SDimitry Andric     return true;
15710b57cec5SDimitry Andric 
15720b57cec5SDimitry Andric   Base = N.getOperand(0);
15730b57cec5SDimitry Andric   if (Base.getOpcode() == ISD::FrameIndex) {
15740b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(Base)->getIndex();
15750b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(
15760b57cec5SDimitry Andric         FI, TLI->getPointerTy(CurDAG->getDataLayout()));
15770b57cec5SDimitry Andric   }
15780b57cec5SDimitry Andric 
15790b57cec5SDimitry Andric   OffImm = CurDAG->getTargetConstant(RHSC/4, SDLoc(N), MVT::i32);
15800b57cec5SDimitry Andric   return true;
15810b57cec5SDimitry Andric }
15820b57cec5SDimitry Andric 
15830b57cec5SDimitry Andric //===--------------------------------------------------------------------===//
15840b57cec5SDimitry Andric 
15850b57cec5SDimitry Andric /// getAL - Returns a ARMCC::AL immediate node.
getAL(SelectionDAG * CurDAG,const SDLoc & dl)15860b57cec5SDimitry Andric static inline SDValue getAL(SelectionDAG *CurDAG, const SDLoc &dl) {
15870b57cec5SDimitry Andric   return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, dl, MVT::i32);
15880b57cec5SDimitry Andric }
15890b57cec5SDimitry Andric 
transferMemOperands(SDNode * N,SDNode * Result)15900b57cec5SDimitry Andric void ARMDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) {
15910b57cec5SDimitry Andric   MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
15920b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(Result), {MemOp});
15930b57cec5SDimitry Andric }
15940b57cec5SDimitry Andric 
tryARMIndexedLoad(SDNode * N)15950b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryARMIndexedLoad(SDNode *N) {
15960b57cec5SDimitry Andric   LoadSDNode *LD = cast<LoadSDNode>(N);
15970b57cec5SDimitry Andric   ISD::MemIndexedMode AM = LD->getAddressingMode();
15980b57cec5SDimitry Andric   if (AM == ISD::UNINDEXED)
15990b57cec5SDimitry Andric     return false;
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric   EVT LoadedVT = LD->getMemoryVT();
16020b57cec5SDimitry Andric   SDValue Offset, AMOpc;
16030b57cec5SDimitry Andric   bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
16040b57cec5SDimitry Andric   unsigned Opcode = 0;
16050b57cec5SDimitry Andric   bool Match = false;
16060b57cec5SDimitry Andric   if (LoadedVT == MVT::i32 && isPre &&
16070b57cec5SDimitry Andric       SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) {
16080b57cec5SDimitry Andric     Opcode = ARM::LDR_PRE_IMM;
16090b57cec5SDimitry Andric     Match = true;
16100b57cec5SDimitry Andric   } else if (LoadedVT == MVT::i32 && !isPre &&
16110b57cec5SDimitry Andric       SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) {
16120b57cec5SDimitry Andric     Opcode = ARM::LDR_POST_IMM;
16130b57cec5SDimitry Andric     Match = true;
16140b57cec5SDimitry Andric   } else if (LoadedVT == MVT::i32 &&
16150b57cec5SDimitry Andric       SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) {
16160b57cec5SDimitry Andric     Opcode = isPre ? ARM::LDR_PRE_REG : ARM::LDR_POST_REG;
16170b57cec5SDimitry Andric     Match = true;
16180b57cec5SDimitry Andric 
16190b57cec5SDimitry Andric   } else if (LoadedVT == MVT::i16 &&
16200b57cec5SDimitry Andric              SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
16210b57cec5SDimitry Andric     Match = true;
16220b57cec5SDimitry Andric     Opcode = (LD->getExtensionType() == ISD::SEXTLOAD)
16230b57cec5SDimitry Andric       ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST)
16240b57cec5SDimitry Andric       : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST);
16250b57cec5SDimitry Andric   } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) {
16260b57cec5SDimitry Andric     if (LD->getExtensionType() == ISD::SEXTLOAD) {
16270b57cec5SDimitry Andric       if (SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
16280b57cec5SDimitry Andric         Match = true;
16290b57cec5SDimitry Andric         Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST;
16300b57cec5SDimitry Andric       }
16310b57cec5SDimitry Andric     } else {
16320b57cec5SDimitry Andric       if (isPre &&
16330b57cec5SDimitry Andric           SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) {
16340b57cec5SDimitry Andric         Match = true;
16350b57cec5SDimitry Andric         Opcode = ARM::LDRB_PRE_IMM;
16360b57cec5SDimitry Andric       } else if (!isPre &&
16370b57cec5SDimitry Andric                   SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) {
16380b57cec5SDimitry Andric         Match = true;
16390b57cec5SDimitry Andric         Opcode = ARM::LDRB_POST_IMM;
16400b57cec5SDimitry Andric       } else if (SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) {
16410b57cec5SDimitry Andric         Match = true;
16420b57cec5SDimitry Andric         Opcode = isPre ? ARM::LDRB_PRE_REG : ARM::LDRB_POST_REG;
16430b57cec5SDimitry Andric       }
16440b57cec5SDimitry Andric     }
16450b57cec5SDimitry Andric   }
16460b57cec5SDimitry Andric 
16470b57cec5SDimitry Andric   if (Match) {
16480b57cec5SDimitry Andric     if (Opcode == ARM::LDR_PRE_IMM || Opcode == ARM::LDRB_PRE_IMM) {
16490b57cec5SDimitry Andric       SDValue Chain = LD->getChain();
16500b57cec5SDimitry Andric       SDValue Base = LD->getBasePtr();
16510b57cec5SDimitry Andric       SDValue Ops[]= { Base, AMOpc, getAL(CurDAG, SDLoc(N)),
16520b57cec5SDimitry Andric                        CurDAG->getRegister(0, MVT::i32), Chain };
16530b57cec5SDimitry Andric       SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
16540b57cec5SDimitry Andric                                            MVT::Other, Ops);
16550b57cec5SDimitry Andric       transferMemOperands(N, New);
16560b57cec5SDimitry Andric       ReplaceNode(N, New);
16570b57cec5SDimitry Andric       return true;
16580b57cec5SDimitry Andric     } else {
16590b57cec5SDimitry Andric       SDValue Chain = LD->getChain();
16600b57cec5SDimitry Andric       SDValue Base = LD->getBasePtr();
16610b57cec5SDimitry Andric       SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG, SDLoc(N)),
16620b57cec5SDimitry Andric                        CurDAG->getRegister(0, MVT::i32), Chain };
16630b57cec5SDimitry Andric       SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
16640b57cec5SDimitry Andric                                            MVT::Other, Ops);
16650b57cec5SDimitry Andric       transferMemOperands(N, New);
16660b57cec5SDimitry Andric       ReplaceNode(N, New);
16670b57cec5SDimitry Andric       return true;
16680b57cec5SDimitry Andric     }
16690b57cec5SDimitry Andric   }
16700b57cec5SDimitry Andric 
16710b57cec5SDimitry Andric   return false;
16720b57cec5SDimitry Andric }
16730b57cec5SDimitry Andric 
tryT1IndexedLoad(SDNode * N)16740b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryT1IndexedLoad(SDNode *N) {
16750b57cec5SDimitry Andric   LoadSDNode *LD = cast<LoadSDNode>(N);
16760b57cec5SDimitry Andric   EVT LoadedVT = LD->getMemoryVT();
16770b57cec5SDimitry Andric   ISD::MemIndexedMode AM = LD->getAddressingMode();
16780b57cec5SDimitry Andric   if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD ||
16790b57cec5SDimitry Andric       LoadedVT.getSimpleVT().SimpleTy != MVT::i32)
16800b57cec5SDimitry Andric     return false;
16810b57cec5SDimitry Andric 
16820b57cec5SDimitry Andric   auto *COffs = dyn_cast<ConstantSDNode>(LD->getOffset());
16830b57cec5SDimitry Andric   if (!COffs || COffs->getZExtValue() != 4)
16840b57cec5SDimitry Andric     return false;
16850b57cec5SDimitry Andric 
16860b57cec5SDimitry Andric   // A T1 post-indexed load is just a single register LDM: LDM r0!, {r1}.
16870b57cec5SDimitry Andric   // The encoding of LDM is not how the rest of ISel expects a post-inc load to
16880b57cec5SDimitry Andric   // look however, so we use a pseudo here and switch it for a tLDMIA_UPD after
16890b57cec5SDimitry Andric   // ISel.
16900b57cec5SDimitry Andric   SDValue Chain = LD->getChain();
16910b57cec5SDimitry Andric   SDValue Base = LD->getBasePtr();
16920b57cec5SDimitry Andric   SDValue Ops[]= { Base, getAL(CurDAG, SDLoc(N)),
16930b57cec5SDimitry Andric                    CurDAG->getRegister(0, MVT::i32), Chain };
16940b57cec5SDimitry Andric   SDNode *New = CurDAG->getMachineNode(ARM::tLDR_postidx, SDLoc(N), MVT::i32,
16950b57cec5SDimitry Andric                                        MVT::i32, MVT::Other, Ops);
16960b57cec5SDimitry Andric   transferMemOperands(N, New);
16970b57cec5SDimitry Andric   ReplaceNode(N, New);
16980b57cec5SDimitry Andric   return true;
16990b57cec5SDimitry Andric }
17000b57cec5SDimitry Andric 
tryT2IndexedLoad(SDNode * N)17010b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryT2IndexedLoad(SDNode *N) {
17020b57cec5SDimitry Andric   LoadSDNode *LD = cast<LoadSDNode>(N);
17030b57cec5SDimitry Andric   ISD::MemIndexedMode AM = LD->getAddressingMode();
17040b57cec5SDimitry Andric   if (AM == ISD::UNINDEXED)
17050b57cec5SDimitry Andric     return false;
17060b57cec5SDimitry Andric 
17070b57cec5SDimitry Andric   EVT LoadedVT = LD->getMemoryVT();
17080b57cec5SDimitry Andric   bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
17090b57cec5SDimitry Andric   SDValue Offset;
17100b57cec5SDimitry Andric   bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
17110b57cec5SDimitry Andric   unsigned Opcode = 0;
17120b57cec5SDimitry Andric   bool Match = false;
17130b57cec5SDimitry Andric   if (SelectT2AddrModeImm8Offset(N, LD->getOffset(), Offset)) {
17140b57cec5SDimitry Andric     switch (LoadedVT.getSimpleVT().SimpleTy) {
17150b57cec5SDimitry Andric     case MVT::i32:
17160b57cec5SDimitry Andric       Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST;
17170b57cec5SDimitry Andric       break;
17180b57cec5SDimitry Andric     case MVT::i16:
17190b57cec5SDimitry Andric       if (isSExtLd)
17200b57cec5SDimitry Andric         Opcode = isPre ? ARM::t2LDRSH_PRE : ARM::t2LDRSH_POST;
17210b57cec5SDimitry Andric       else
17220b57cec5SDimitry Andric         Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST;
17230b57cec5SDimitry Andric       break;
17240b57cec5SDimitry Andric     case MVT::i8:
17250b57cec5SDimitry Andric     case MVT::i1:
17260b57cec5SDimitry Andric       if (isSExtLd)
17270b57cec5SDimitry Andric         Opcode = isPre ? ARM::t2LDRSB_PRE : ARM::t2LDRSB_POST;
17280b57cec5SDimitry Andric       else
17290b57cec5SDimitry Andric         Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST;
17300b57cec5SDimitry Andric       break;
17310b57cec5SDimitry Andric     default:
17320b57cec5SDimitry Andric       return false;
17330b57cec5SDimitry Andric     }
17340b57cec5SDimitry Andric     Match = true;
17350b57cec5SDimitry Andric   }
17360b57cec5SDimitry Andric 
17370b57cec5SDimitry Andric   if (Match) {
17380b57cec5SDimitry Andric     SDValue Chain = LD->getChain();
17390b57cec5SDimitry Andric     SDValue Base = LD->getBasePtr();
17400b57cec5SDimitry Andric     SDValue Ops[]= { Base, Offset, getAL(CurDAG, SDLoc(N)),
17410b57cec5SDimitry Andric                      CurDAG->getRegister(0, MVT::i32), Chain };
17420b57cec5SDimitry Andric     SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
17430b57cec5SDimitry Andric                                          MVT::Other, Ops);
17440b57cec5SDimitry Andric     transferMemOperands(N, New);
17450b57cec5SDimitry Andric     ReplaceNode(N, New);
17460b57cec5SDimitry Andric     return true;
17470b57cec5SDimitry Andric   }
17480b57cec5SDimitry Andric 
17490b57cec5SDimitry Andric   return false;
17500b57cec5SDimitry Andric }
17510b57cec5SDimitry Andric 
tryMVEIndexedLoad(SDNode * N)17528bcb0991SDimitry Andric bool ARMDAGToDAGISel::tryMVEIndexedLoad(SDNode *N) {
1753480093f4SDimitry Andric   EVT LoadedVT;
1754480093f4SDimitry Andric   unsigned Opcode = 0;
1755480093f4SDimitry Andric   bool isSExtLd, isPre;
17565ffd83dbSDimitry Andric   Align Alignment;
1757480093f4SDimitry Andric   ARMVCC::VPTCodes Pred;
1758480093f4SDimitry Andric   SDValue PredReg;
1759480093f4SDimitry Andric   SDValue Chain, Base, Offset;
1760480093f4SDimitry Andric 
1761480093f4SDimitry Andric   if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
17628bcb0991SDimitry Andric     ISD::MemIndexedMode AM = LD->getAddressingMode();
17638bcb0991SDimitry Andric     if (AM == ISD::UNINDEXED)
17648bcb0991SDimitry Andric       return false;
1765480093f4SDimitry Andric     LoadedVT = LD->getMemoryVT();
17668bcb0991SDimitry Andric     if (!LoadedVT.isVector())
17678bcb0991SDimitry Andric       return false;
17688bcb0991SDimitry Andric 
1769480093f4SDimitry Andric     Chain = LD->getChain();
1770480093f4SDimitry Andric     Base = LD->getBasePtr();
1771480093f4SDimitry Andric     Offset = LD->getOffset();
17725ffd83dbSDimitry Andric     Alignment = LD->getAlign();
1773480093f4SDimitry Andric     isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
1774480093f4SDimitry Andric     isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1775480093f4SDimitry Andric     Pred = ARMVCC::None;
1776480093f4SDimitry Andric     PredReg = CurDAG->getRegister(0, MVT::i32);
1777480093f4SDimitry Andric   } else if (MaskedLoadSDNode *LD = dyn_cast<MaskedLoadSDNode>(N)) {
1778480093f4SDimitry Andric     ISD::MemIndexedMode AM = LD->getAddressingMode();
1779480093f4SDimitry Andric     if (AM == ISD::UNINDEXED)
1780480093f4SDimitry Andric       return false;
1781480093f4SDimitry Andric     LoadedVT = LD->getMemoryVT();
1782480093f4SDimitry Andric     if (!LoadedVT.isVector())
1783480093f4SDimitry Andric       return false;
1784480093f4SDimitry Andric 
1785480093f4SDimitry Andric     Chain = LD->getChain();
1786480093f4SDimitry Andric     Base = LD->getBasePtr();
1787480093f4SDimitry Andric     Offset = LD->getOffset();
17885ffd83dbSDimitry Andric     Alignment = LD->getAlign();
1789480093f4SDimitry Andric     isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
1790480093f4SDimitry Andric     isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1791480093f4SDimitry Andric     Pred = ARMVCC::Then;
1792480093f4SDimitry Andric     PredReg = LD->getMask();
1793480093f4SDimitry Andric   } else
1794480093f4SDimitry Andric     llvm_unreachable("Expected a Load or a Masked Load!");
1795480093f4SDimitry Andric 
1796480093f4SDimitry Andric   // We allow LE non-masked loads to change the type (for example use a vldrb.8
1797480093f4SDimitry Andric   // as opposed to a vldrw.32). This can allow extra addressing modes or
1798480093f4SDimitry Andric   // alignments for what is otherwise an equivalent instruction.
1799480093f4SDimitry Andric   bool CanChangeType = Subtarget->isLittle() && !isa<MaskedLoadSDNode>(N);
1800480093f4SDimitry Andric 
1801480093f4SDimitry Andric   SDValue NewOffset;
18025ffd83dbSDimitry Andric   if (Alignment >= Align(2) && LoadedVT == MVT::v4i16 &&
1803480093f4SDimitry Andric       SelectT2AddrModeImm7Offset(N, Offset, NewOffset, 1)) {
18048bcb0991SDimitry Andric     if (isSExtLd)
18058bcb0991SDimitry Andric       Opcode = isPre ? ARM::MVE_VLDRHS32_pre : ARM::MVE_VLDRHS32_post;
18068bcb0991SDimitry Andric     else
18078bcb0991SDimitry Andric       Opcode = isPre ? ARM::MVE_VLDRHU32_pre : ARM::MVE_VLDRHU32_post;
18088bcb0991SDimitry Andric   } else if (LoadedVT == MVT::v8i8 &&
1809480093f4SDimitry Andric              SelectT2AddrModeImm7Offset(N, Offset, NewOffset, 0)) {
18108bcb0991SDimitry Andric     if (isSExtLd)
18118bcb0991SDimitry Andric       Opcode = isPre ? ARM::MVE_VLDRBS16_pre : ARM::MVE_VLDRBS16_post;
18128bcb0991SDimitry Andric     else
18138bcb0991SDimitry Andric       Opcode = isPre ? ARM::MVE_VLDRBU16_pre : ARM::MVE_VLDRBU16_post;
18148bcb0991SDimitry Andric   } else if (LoadedVT == MVT::v4i8 &&
1815480093f4SDimitry Andric              SelectT2AddrModeImm7Offset(N, Offset, NewOffset, 0)) {
18168bcb0991SDimitry Andric     if (isSExtLd)
18178bcb0991SDimitry Andric       Opcode = isPre ? ARM::MVE_VLDRBS32_pre : ARM::MVE_VLDRBS32_post;
18188bcb0991SDimitry Andric     else
18198bcb0991SDimitry Andric       Opcode = isPre ? ARM::MVE_VLDRBU32_pre : ARM::MVE_VLDRBU32_post;
18205ffd83dbSDimitry Andric   } else if (Alignment >= Align(4) &&
1821480093f4SDimitry Andric              (CanChangeType || LoadedVT == MVT::v4i32 ||
1822480093f4SDimitry Andric               LoadedVT == MVT::v4f32) &&
1823480093f4SDimitry Andric              SelectT2AddrModeImm7Offset(N, Offset, NewOffset, 2))
18248bcb0991SDimitry Andric     Opcode = isPre ? ARM::MVE_VLDRWU32_pre : ARM::MVE_VLDRWU32_post;
18255ffd83dbSDimitry Andric   else if (Alignment >= Align(2) &&
1826480093f4SDimitry Andric            (CanChangeType || LoadedVT == MVT::v8i16 ||
1827480093f4SDimitry Andric             LoadedVT == MVT::v8f16) &&
1828480093f4SDimitry Andric            SelectT2AddrModeImm7Offset(N, Offset, NewOffset, 1))
18298bcb0991SDimitry Andric     Opcode = isPre ? ARM::MVE_VLDRHU16_pre : ARM::MVE_VLDRHU16_post;
1830480093f4SDimitry Andric   else if ((CanChangeType || LoadedVT == MVT::v16i8) &&
1831480093f4SDimitry Andric            SelectT2AddrModeImm7Offset(N, Offset, NewOffset, 0))
18328bcb0991SDimitry Andric     Opcode = isPre ? ARM::MVE_VLDRBU8_pre : ARM::MVE_VLDRBU8_post;
18338bcb0991SDimitry Andric   else
18348bcb0991SDimitry Andric     return false;
18358bcb0991SDimitry Andric 
1836349cc55cSDimitry Andric   SDValue Ops[] = {Base,
1837349cc55cSDimitry Andric                    NewOffset,
1838349cc55cSDimitry Andric                    CurDAG->getTargetConstant(Pred, SDLoc(N), MVT::i32),
1839349cc55cSDimitry Andric                    PredReg,
1840349cc55cSDimitry Andric                    CurDAG->getRegister(0, MVT::i32), // tp_reg
1841480093f4SDimitry Andric                    Chain};
18425ffd83dbSDimitry Andric   SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32,
18435ffd83dbSDimitry Andric                                        N->getValueType(0), MVT::Other, Ops);
18448bcb0991SDimitry Andric   transferMemOperands(N, New);
18458bcb0991SDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(New, 1));
18468bcb0991SDimitry Andric   ReplaceUses(SDValue(N, 1), SDValue(New, 0));
18478bcb0991SDimitry Andric   ReplaceUses(SDValue(N, 2), SDValue(New, 2));
18488bcb0991SDimitry Andric   CurDAG->RemoveDeadNode(N);
18498bcb0991SDimitry Andric   return true;
18508bcb0991SDimitry Andric }
18518bcb0991SDimitry Andric 
18520b57cec5SDimitry Andric /// Form a GPRPair pseudo register from a pair of GPR regs.
createGPRPairNode(EVT VT,SDValue V0,SDValue V1)18530b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
18540b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
18550b57cec5SDimitry Andric   SDValue RegClass =
18560b57cec5SDimitry Andric     CurDAG->getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32);
18570b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::gsub_0, dl, MVT::i32);
18580b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::gsub_1, dl, MVT::i32);
18590b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
18600b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
18610b57cec5SDimitry Andric }
18620b57cec5SDimitry Andric 
18630b57cec5SDimitry Andric /// Form a D register from a pair of S registers.
createSRegPairNode(EVT VT,SDValue V0,SDValue V1)18640b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createSRegPairNode(EVT VT, SDValue V0, SDValue V1) {
18650b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
18660b57cec5SDimitry Andric   SDValue RegClass =
18670b57cec5SDimitry Andric     CurDAG->getTargetConstant(ARM::DPR_VFP2RegClassID, dl, MVT::i32);
18680b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, dl, MVT::i32);
18690b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, dl, MVT::i32);
18700b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
18710b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
18720b57cec5SDimitry Andric }
18730b57cec5SDimitry Andric 
18740b57cec5SDimitry Andric /// Form a quad register from a pair of D registers.
createDRegPairNode(EVT VT,SDValue V0,SDValue V1)18750b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createDRegPairNode(EVT VT, SDValue V0, SDValue V1) {
18760b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
18770b57cec5SDimitry Andric   SDValue RegClass = CurDAG->getTargetConstant(ARM::QPRRegClassID, dl,
18780b57cec5SDimitry Andric                                                MVT::i32);
18790b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, dl, MVT::i32);
18800b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, dl, MVT::i32);
18810b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
18820b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
18830b57cec5SDimitry Andric }
18840b57cec5SDimitry Andric 
18850b57cec5SDimitry Andric /// Form 4 consecutive D registers from a pair of Q registers.
createQRegPairNode(EVT VT,SDValue V0,SDValue V1)18860b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createQRegPairNode(EVT VT, SDValue V0, SDValue V1) {
18870b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
18880b57cec5SDimitry Andric   SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
18890b57cec5SDimitry Andric                                                MVT::i32);
18900b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, dl, MVT::i32);
18910b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, dl, MVT::i32);
18920b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
18930b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
18940b57cec5SDimitry Andric }
18950b57cec5SDimitry Andric 
18960b57cec5SDimitry Andric /// Form 4 consecutive S registers.
createQuadSRegsNode(EVT VT,SDValue V0,SDValue V1,SDValue V2,SDValue V3)18970b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1,
18980b57cec5SDimitry Andric                                    SDValue V2, SDValue V3) {
18990b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
19000b57cec5SDimitry Andric   SDValue RegClass =
19010b57cec5SDimitry Andric     CurDAG->getTargetConstant(ARM::QPR_VFP2RegClassID, dl, MVT::i32);
19020b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, dl, MVT::i32);
19030b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, dl, MVT::i32);
19040b57cec5SDimitry Andric   SDValue SubReg2 = CurDAG->getTargetConstant(ARM::ssub_2, dl, MVT::i32);
19050b57cec5SDimitry Andric   SDValue SubReg3 = CurDAG->getTargetConstant(ARM::ssub_3, dl, MVT::i32);
19060b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
19070b57cec5SDimitry Andric                                     V2, SubReg2, V3, SubReg3 };
19080b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
19090b57cec5SDimitry Andric }
19100b57cec5SDimitry Andric 
19110b57cec5SDimitry Andric /// Form 4 consecutive D registers.
createQuadDRegsNode(EVT VT,SDValue V0,SDValue V1,SDValue V2,SDValue V3)19120b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1,
19130b57cec5SDimitry Andric                                    SDValue V2, SDValue V3) {
19140b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
19150b57cec5SDimitry Andric   SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
19160b57cec5SDimitry Andric                                                MVT::i32);
19170b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, dl, MVT::i32);
19180b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, dl, MVT::i32);
19190b57cec5SDimitry Andric   SDValue SubReg2 = CurDAG->getTargetConstant(ARM::dsub_2, dl, MVT::i32);
19200b57cec5SDimitry Andric   SDValue SubReg3 = CurDAG->getTargetConstant(ARM::dsub_3, dl, MVT::i32);
19210b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
19220b57cec5SDimitry Andric                                     V2, SubReg2, V3, SubReg3 };
19230b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
19240b57cec5SDimitry Andric }
19250b57cec5SDimitry Andric 
19260b57cec5SDimitry Andric /// Form 4 consecutive Q registers.
createQuadQRegsNode(EVT VT,SDValue V0,SDValue V1,SDValue V2,SDValue V3)19270b57cec5SDimitry Andric SDNode *ARMDAGToDAGISel::createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1,
19280b57cec5SDimitry Andric                                    SDValue V2, SDValue V3) {
19290b57cec5SDimitry Andric   SDLoc dl(V0.getNode());
19300b57cec5SDimitry Andric   SDValue RegClass = CurDAG->getTargetConstant(ARM::QQQQPRRegClassID, dl,
19310b57cec5SDimitry Andric                                                MVT::i32);
19320b57cec5SDimitry Andric   SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, dl, MVT::i32);
19330b57cec5SDimitry Andric   SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, dl, MVT::i32);
19340b57cec5SDimitry Andric   SDValue SubReg2 = CurDAG->getTargetConstant(ARM::qsub_2, dl, MVT::i32);
19350b57cec5SDimitry Andric   SDValue SubReg3 = CurDAG->getTargetConstant(ARM::qsub_3, dl, MVT::i32);
19360b57cec5SDimitry Andric   const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
19370b57cec5SDimitry Andric                                     V2, SubReg2, V3, SubReg3 };
19380b57cec5SDimitry Andric   return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
19390b57cec5SDimitry Andric }
19400b57cec5SDimitry Andric 
19410b57cec5SDimitry Andric /// GetVLDSTAlign - Get the alignment (in bytes) for the alignment operand
19420b57cec5SDimitry Andric /// of a NEON VLD or VST instruction.  The supported values depend on the
19430b57cec5SDimitry Andric /// number of registers being loaded.
GetVLDSTAlign(SDValue Align,const SDLoc & dl,unsigned NumVecs,bool is64BitVector)19440b57cec5SDimitry Andric SDValue ARMDAGToDAGISel::GetVLDSTAlign(SDValue Align, const SDLoc &dl,
19450b57cec5SDimitry Andric                                        unsigned NumVecs, bool is64BitVector) {
19460b57cec5SDimitry Andric   unsigned NumRegs = NumVecs;
19470b57cec5SDimitry Andric   if (!is64BitVector && NumVecs < 3)
19480b57cec5SDimitry Andric     NumRegs *= 2;
19490b57cec5SDimitry Andric 
19501db9f3b2SDimitry Andric   unsigned Alignment = Align->getAsZExtVal();
19510b57cec5SDimitry Andric   if (Alignment >= 32 && NumRegs == 4)
19520b57cec5SDimitry Andric     Alignment = 32;
19530b57cec5SDimitry Andric   else if (Alignment >= 16 && (NumRegs == 2 || NumRegs == 4))
19540b57cec5SDimitry Andric     Alignment = 16;
19550b57cec5SDimitry Andric   else if (Alignment >= 8)
19560b57cec5SDimitry Andric     Alignment = 8;
19570b57cec5SDimitry Andric   else
19580b57cec5SDimitry Andric     Alignment = 0;
19590b57cec5SDimitry Andric 
19600b57cec5SDimitry Andric   return CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
19610b57cec5SDimitry Andric }
19620b57cec5SDimitry Andric 
isVLDfixed(unsigned Opc)19630b57cec5SDimitry Andric static bool isVLDfixed(unsigned Opc)
19640b57cec5SDimitry Andric {
19650b57cec5SDimitry Andric   switch (Opc) {
19660b57cec5SDimitry Andric   default: return false;
19670b57cec5SDimitry Andric   case ARM::VLD1d8wb_fixed : return true;
19680b57cec5SDimitry Andric   case ARM::VLD1d16wb_fixed : return true;
19690b57cec5SDimitry Andric   case ARM::VLD1d64Qwb_fixed : return true;
19700b57cec5SDimitry Andric   case ARM::VLD1d32wb_fixed : return true;
19710b57cec5SDimitry Andric   case ARM::VLD1d64wb_fixed : return true;
1972fe6060f1SDimitry Andric   case ARM::VLD1d8TPseudoWB_fixed : return true;
1973fe6060f1SDimitry Andric   case ARM::VLD1d16TPseudoWB_fixed : return true;
1974fe6060f1SDimitry Andric   case ARM::VLD1d32TPseudoWB_fixed : return true;
19750b57cec5SDimitry Andric   case ARM::VLD1d64TPseudoWB_fixed : return true;
1976fe6060f1SDimitry Andric   case ARM::VLD1d8QPseudoWB_fixed : return true;
1977fe6060f1SDimitry Andric   case ARM::VLD1d16QPseudoWB_fixed : return true;
1978fe6060f1SDimitry Andric   case ARM::VLD1d32QPseudoWB_fixed : return true;
19790b57cec5SDimitry Andric   case ARM::VLD1d64QPseudoWB_fixed : return true;
19800b57cec5SDimitry Andric   case ARM::VLD1q8wb_fixed : return true;
19810b57cec5SDimitry Andric   case ARM::VLD1q16wb_fixed : return true;
19820b57cec5SDimitry Andric   case ARM::VLD1q32wb_fixed : return true;
19830b57cec5SDimitry Andric   case ARM::VLD1q64wb_fixed : return true;
19840b57cec5SDimitry Andric   case ARM::VLD1DUPd8wb_fixed : return true;
19850b57cec5SDimitry Andric   case ARM::VLD1DUPd16wb_fixed : return true;
19860b57cec5SDimitry Andric   case ARM::VLD1DUPd32wb_fixed : return true;
19870b57cec5SDimitry Andric   case ARM::VLD1DUPq8wb_fixed : return true;
19880b57cec5SDimitry Andric   case ARM::VLD1DUPq16wb_fixed : return true;
19890b57cec5SDimitry Andric   case ARM::VLD1DUPq32wb_fixed : return true;
19900b57cec5SDimitry Andric   case ARM::VLD2d8wb_fixed : return true;
19910b57cec5SDimitry Andric   case ARM::VLD2d16wb_fixed : return true;
19920b57cec5SDimitry Andric   case ARM::VLD2d32wb_fixed : return true;
19930b57cec5SDimitry Andric   case ARM::VLD2q8PseudoWB_fixed : return true;
19940b57cec5SDimitry Andric   case ARM::VLD2q16PseudoWB_fixed : return true;
19950b57cec5SDimitry Andric   case ARM::VLD2q32PseudoWB_fixed : return true;
19960b57cec5SDimitry Andric   case ARM::VLD2DUPd8wb_fixed : return true;
19970b57cec5SDimitry Andric   case ARM::VLD2DUPd16wb_fixed : return true;
19980b57cec5SDimitry Andric   case ARM::VLD2DUPd32wb_fixed : return true;
1999fe6060f1SDimitry Andric   case ARM::VLD2DUPq8OddPseudoWB_fixed: return true;
2000fe6060f1SDimitry Andric   case ARM::VLD2DUPq16OddPseudoWB_fixed: return true;
2001fe6060f1SDimitry Andric   case ARM::VLD2DUPq32OddPseudoWB_fixed: return true;
20020b57cec5SDimitry Andric   }
20030b57cec5SDimitry Andric }
20040b57cec5SDimitry Andric 
isVSTfixed(unsigned Opc)20050b57cec5SDimitry Andric static bool isVSTfixed(unsigned Opc)
20060b57cec5SDimitry Andric {
20070b57cec5SDimitry Andric   switch (Opc) {
20080b57cec5SDimitry Andric   default: return false;
20090b57cec5SDimitry Andric   case ARM::VST1d8wb_fixed : return true;
20100b57cec5SDimitry Andric   case ARM::VST1d16wb_fixed : return true;
20110b57cec5SDimitry Andric   case ARM::VST1d32wb_fixed : return true;
20120b57cec5SDimitry Andric   case ARM::VST1d64wb_fixed : return true;
20130b57cec5SDimitry Andric   case ARM::VST1q8wb_fixed : return true;
20140b57cec5SDimitry Andric   case ARM::VST1q16wb_fixed : return true;
20150b57cec5SDimitry Andric   case ARM::VST1q32wb_fixed : return true;
20160b57cec5SDimitry Andric   case ARM::VST1q64wb_fixed : return true;
2017fe6060f1SDimitry Andric   case ARM::VST1d8TPseudoWB_fixed : return true;
2018fe6060f1SDimitry Andric   case ARM::VST1d16TPseudoWB_fixed : return true;
2019fe6060f1SDimitry Andric   case ARM::VST1d32TPseudoWB_fixed : return true;
20200b57cec5SDimitry Andric   case ARM::VST1d64TPseudoWB_fixed : return true;
2021fe6060f1SDimitry Andric   case ARM::VST1d8QPseudoWB_fixed : return true;
2022fe6060f1SDimitry Andric   case ARM::VST1d16QPseudoWB_fixed : return true;
2023fe6060f1SDimitry Andric   case ARM::VST1d32QPseudoWB_fixed : return true;
20240b57cec5SDimitry Andric   case ARM::VST1d64QPseudoWB_fixed : return true;
20250b57cec5SDimitry Andric   case ARM::VST2d8wb_fixed : return true;
20260b57cec5SDimitry Andric   case ARM::VST2d16wb_fixed : return true;
20270b57cec5SDimitry Andric   case ARM::VST2d32wb_fixed : return true;
20280b57cec5SDimitry Andric   case ARM::VST2q8PseudoWB_fixed : return true;
20290b57cec5SDimitry Andric   case ARM::VST2q16PseudoWB_fixed : return true;
20300b57cec5SDimitry Andric   case ARM::VST2q32PseudoWB_fixed : return true;
20310b57cec5SDimitry Andric   }
20320b57cec5SDimitry Andric }
20330b57cec5SDimitry Andric 
20340b57cec5SDimitry Andric // Get the register stride update opcode of a VLD/VST instruction that
20350b57cec5SDimitry Andric // is otherwise equivalent to the given fixed stride updating instruction.
getVLDSTRegisterUpdateOpcode(unsigned Opc)20360b57cec5SDimitry Andric static unsigned getVLDSTRegisterUpdateOpcode(unsigned Opc) {
20370b57cec5SDimitry Andric   assert((isVLDfixed(Opc) || isVSTfixed(Opc))
20380b57cec5SDimitry Andric     && "Incorrect fixed stride updating instruction.");
20390b57cec5SDimitry Andric   switch (Opc) {
20400b57cec5SDimitry Andric   default: break;
20410b57cec5SDimitry Andric   case ARM::VLD1d8wb_fixed: return ARM::VLD1d8wb_register;
20420b57cec5SDimitry Andric   case ARM::VLD1d16wb_fixed: return ARM::VLD1d16wb_register;
20430b57cec5SDimitry Andric   case ARM::VLD1d32wb_fixed: return ARM::VLD1d32wb_register;
20440b57cec5SDimitry Andric   case ARM::VLD1d64wb_fixed: return ARM::VLD1d64wb_register;
20450b57cec5SDimitry Andric   case ARM::VLD1q8wb_fixed: return ARM::VLD1q8wb_register;
20460b57cec5SDimitry Andric   case ARM::VLD1q16wb_fixed: return ARM::VLD1q16wb_register;
20470b57cec5SDimitry Andric   case ARM::VLD1q32wb_fixed: return ARM::VLD1q32wb_register;
20480b57cec5SDimitry Andric   case ARM::VLD1q64wb_fixed: return ARM::VLD1q64wb_register;
20490b57cec5SDimitry Andric   case ARM::VLD1d64Twb_fixed: return ARM::VLD1d64Twb_register;
20500b57cec5SDimitry Andric   case ARM::VLD1d64Qwb_fixed: return ARM::VLD1d64Qwb_register;
2051fe6060f1SDimitry Andric   case ARM::VLD1d8TPseudoWB_fixed: return ARM::VLD1d8TPseudoWB_register;
2052fe6060f1SDimitry Andric   case ARM::VLD1d16TPseudoWB_fixed: return ARM::VLD1d16TPseudoWB_register;
2053fe6060f1SDimitry Andric   case ARM::VLD1d32TPseudoWB_fixed: return ARM::VLD1d32TPseudoWB_register;
20540b57cec5SDimitry Andric   case ARM::VLD1d64TPseudoWB_fixed: return ARM::VLD1d64TPseudoWB_register;
2055fe6060f1SDimitry Andric   case ARM::VLD1d8QPseudoWB_fixed: return ARM::VLD1d8QPseudoWB_register;
2056fe6060f1SDimitry Andric   case ARM::VLD1d16QPseudoWB_fixed: return ARM::VLD1d16QPseudoWB_register;
2057fe6060f1SDimitry Andric   case ARM::VLD1d32QPseudoWB_fixed: return ARM::VLD1d32QPseudoWB_register;
20580b57cec5SDimitry Andric   case ARM::VLD1d64QPseudoWB_fixed: return ARM::VLD1d64QPseudoWB_register;
20590b57cec5SDimitry Andric   case ARM::VLD1DUPd8wb_fixed : return ARM::VLD1DUPd8wb_register;
20600b57cec5SDimitry Andric   case ARM::VLD1DUPd16wb_fixed : return ARM::VLD1DUPd16wb_register;
20610b57cec5SDimitry Andric   case ARM::VLD1DUPd32wb_fixed : return ARM::VLD1DUPd32wb_register;
20620b57cec5SDimitry Andric   case ARM::VLD1DUPq8wb_fixed : return ARM::VLD1DUPq8wb_register;
20630b57cec5SDimitry Andric   case ARM::VLD1DUPq16wb_fixed : return ARM::VLD1DUPq16wb_register;
20640b57cec5SDimitry Andric   case ARM::VLD1DUPq32wb_fixed : return ARM::VLD1DUPq32wb_register;
2065fe6060f1SDimitry Andric   case ARM::VLD2DUPq8OddPseudoWB_fixed: return ARM::VLD2DUPq8OddPseudoWB_register;
2066fe6060f1SDimitry Andric   case ARM::VLD2DUPq16OddPseudoWB_fixed: return ARM::VLD2DUPq16OddPseudoWB_register;
2067fe6060f1SDimitry Andric   case ARM::VLD2DUPq32OddPseudoWB_fixed: return ARM::VLD2DUPq32OddPseudoWB_register;
20680b57cec5SDimitry Andric 
20690b57cec5SDimitry Andric   case ARM::VST1d8wb_fixed: return ARM::VST1d8wb_register;
20700b57cec5SDimitry Andric   case ARM::VST1d16wb_fixed: return ARM::VST1d16wb_register;
20710b57cec5SDimitry Andric   case ARM::VST1d32wb_fixed: return ARM::VST1d32wb_register;
20720b57cec5SDimitry Andric   case ARM::VST1d64wb_fixed: return ARM::VST1d64wb_register;
20730b57cec5SDimitry Andric   case ARM::VST1q8wb_fixed: return ARM::VST1q8wb_register;
20740b57cec5SDimitry Andric   case ARM::VST1q16wb_fixed: return ARM::VST1q16wb_register;
20750b57cec5SDimitry Andric   case ARM::VST1q32wb_fixed: return ARM::VST1q32wb_register;
20760b57cec5SDimitry Andric   case ARM::VST1q64wb_fixed: return ARM::VST1q64wb_register;
2077fe6060f1SDimitry Andric   case ARM::VST1d8TPseudoWB_fixed: return ARM::VST1d8TPseudoWB_register;
2078fe6060f1SDimitry Andric   case ARM::VST1d16TPseudoWB_fixed: return ARM::VST1d16TPseudoWB_register;
2079fe6060f1SDimitry Andric   case ARM::VST1d32TPseudoWB_fixed: return ARM::VST1d32TPseudoWB_register;
20800b57cec5SDimitry Andric   case ARM::VST1d64TPseudoWB_fixed: return ARM::VST1d64TPseudoWB_register;
2081fe6060f1SDimitry Andric   case ARM::VST1d8QPseudoWB_fixed: return ARM::VST1d8QPseudoWB_register;
2082fe6060f1SDimitry Andric   case ARM::VST1d16QPseudoWB_fixed: return ARM::VST1d16QPseudoWB_register;
2083fe6060f1SDimitry Andric   case ARM::VST1d32QPseudoWB_fixed: return ARM::VST1d32QPseudoWB_register;
20840b57cec5SDimitry Andric   case ARM::VST1d64QPseudoWB_fixed: return ARM::VST1d64QPseudoWB_register;
20850b57cec5SDimitry Andric 
20860b57cec5SDimitry Andric   case ARM::VLD2d8wb_fixed: return ARM::VLD2d8wb_register;
20870b57cec5SDimitry Andric   case ARM::VLD2d16wb_fixed: return ARM::VLD2d16wb_register;
20880b57cec5SDimitry Andric   case ARM::VLD2d32wb_fixed: return ARM::VLD2d32wb_register;
20890b57cec5SDimitry Andric   case ARM::VLD2q8PseudoWB_fixed: return ARM::VLD2q8PseudoWB_register;
20900b57cec5SDimitry Andric   case ARM::VLD2q16PseudoWB_fixed: return ARM::VLD2q16PseudoWB_register;
20910b57cec5SDimitry Andric   case ARM::VLD2q32PseudoWB_fixed: return ARM::VLD2q32PseudoWB_register;
20920b57cec5SDimitry Andric 
20930b57cec5SDimitry Andric   case ARM::VST2d8wb_fixed: return ARM::VST2d8wb_register;
20940b57cec5SDimitry Andric   case ARM::VST2d16wb_fixed: return ARM::VST2d16wb_register;
20950b57cec5SDimitry Andric   case ARM::VST2d32wb_fixed: return ARM::VST2d32wb_register;
20960b57cec5SDimitry Andric   case ARM::VST2q8PseudoWB_fixed: return ARM::VST2q8PseudoWB_register;
20970b57cec5SDimitry Andric   case ARM::VST2q16PseudoWB_fixed: return ARM::VST2q16PseudoWB_register;
20980b57cec5SDimitry Andric   case ARM::VST2q32PseudoWB_fixed: return ARM::VST2q32PseudoWB_register;
20990b57cec5SDimitry Andric 
21000b57cec5SDimitry Andric   case ARM::VLD2DUPd8wb_fixed: return ARM::VLD2DUPd8wb_register;
21010b57cec5SDimitry Andric   case ARM::VLD2DUPd16wb_fixed: return ARM::VLD2DUPd16wb_register;
21020b57cec5SDimitry Andric   case ARM::VLD2DUPd32wb_fixed: return ARM::VLD2DUPd32wb_register;
21030b57cec5SDimitry Andric   }
21040b57cec5SDimitry Andric   return Opc; // If not one we handle, return it unchanged.
21050b57cec5SDimitry Andric }
21060b57cec5SDimitry Andric 
21070b57cec5SDimitry Andric /// Returns true if the given increment is a Constant known to be equal to the
21080b57cec5SDimitry Andric /// access size performed by a NEON load/store. This means the "[rN]!" form can
21090b57cec5SDimitry Andric /// be used.
isPerfectIncrement(SDValue Inc,EVT VecTy,unsigned NumVecs)21100b57cec5SDimitry Andric static bool isPerfectIncrement(SDValue Inc, EVT VecTy, unsigned NumVecs) {
21110b57cec5SDimitry Andric   auto C = dyn_cast<ConstantSDNode>(Inc);
21120b57cec5SDimitry Andric   return C && C->getZExtValue() == VecTy.getSizeInBits() / 8 * NumVecs;
21130b57cec5SDimitry Andric }
21140b57cec5SDimitry Andric 
SelectVLD(SDNode * N,bool isUpdating,unsigned NumVecs,const uint16_t * DOpcodes,const uint16_t * QOpcodes0,const uint16_t * QOpcodes1)21150b57cec5SDimitry Andric void ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
21160b57cec5SDimitry Andric                                 const uint16_t *DOpcodes,
21170b57cec5SDimitry Andric                                 const uint16_t *QOpcodes0,
21180b57cec5SDimitry Andric                                 const uint16_t *QOpcodes1) {
21195ffd83dbSDimitry Andric   assert(Subtarget->hasNEON());
21200b57cec5SDimitry Andric   assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range");
21210b57cec5SDimitry Andric   SDLoc dl(N);
21220b57cec5SDimitry Andric 
21230b57cec5SDimitry Andric   SDValue MemAddr, Align;
21240b57cec5SDimitry Andric   bool IsIntrinsic = !isUpdating;  // By coincidence, all supported updating
21250b57cec5SDimitry Andric                                    // nodes are not intrinsics.
21260b57cec5SDimitry Andric   unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
21270b57cec5SDimitry Andric   if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
21280b57cec5SDimitry Andric     return;
21290b57cec5SDimitry Andric 
21300b57cec5SDimitry Andric   SDValue Chain = N->getOperand(0);
21310b57cec5SDimitry Andric   EVT VT = N->getValueType(0);
21320b57cec5SDimitry Andric   bool is64BitVector = VT.is64BitVector();
21330b57cec5SDimitry Andric   Align = GetVLDSTAlign(Align, dl, NumVecs, is64BitVector);
21340b57cec5SDimitry Andric 
21350b57cec5SDimitry Andric   unsigned OpcodeIndex;
21360b57cec5SDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
21370b57cec5SDimitry Andric   default: llvm_unreachable("unhandled vld type");
21380b57cec5SDimitry Andric     // Double-register operations:
21390b57cec5SDimitry Andric   case MVT::v8i8:  OpcodeIndex = 0; break;
21400b57cec5SDimitry Andric   case MVT::v4f16:
21415ffd83dbSDimitry Andric   case MVT::v4bf16:
21420b57cec5SDimitry Andric   case MVT::v4i16: OpcodeIndex = 1; break;
21430b57cec5SDimitry Andric   case MVT::v2f32:
21440b57cec5SDimitry Andric   case MVT::v2i32: OpcodeIndex = 2; break;
21450b57cec5SDimitry Andric   case MVT::v1i64: OpcodeIndex = 3; break;
21460b57cec5SDimitry Andric     // Quad-register operations:
21470b57cec5SDimitry Andric   case MVT::v16i8: OpcodeIndex = 0; break;
21480b57cec5SDimitry Andric   case MVT::v8f16:
21495ffd83dbSDimitry Andric   case MVT::v8bf16:
21500b57cec5SDimitry Andric   case MVT::v8i16: OpcodeIndex = 1; break;
21510b57cec5SDimitry Andric   case MVT::v4f32:
21520b57cec5SDimitry Andric   case MVT::v4i32: OpcodeIndex = 2; break;
21530b57cec5SDimitry Andric   case MVT::v2f64:
21540b57cec5SDimitry Andric   case MVT::v2i64: OpcodeIndex = 3; break;
21550b57cec5SDimitry Andric   }
21560b57cec5SDimitry Andric 
21570b57cec5SDimitry Andric   EVT ResTy;
21580b57cec5SDimitry Andric   if (NumVecs == 1)
21590b57cec5SDimitry Andric     ResTy = VT;
21600b57cec5SDimitry Andric   else {
21610b57cec5SDimitry Andric     unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
21620b57cec5SDimitry Andric     if (!is64BitVector)
21630b57cec5SDimitry Andric       ResTyElts *= 2;
21640b57cec5SDimitry Andric     ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts);
21650b57cec5SDimitry Andric   }
21660b57cec5SDimitry Andric   std::vector<EVT> ResTys;
21670b57cec5SDimitry Andric   ResTys.push_back(ResTy);
21680b57cec5SDimitry Andric   if (isUpdating)
21690b57cec5SDimitry Andric     ResTys.push_back(MVT::i32);
21700b57cec5SDimitry Andric   ResTys.push_back(MVT::Other);
21710b57cec5SDimitry Andric 
21720b57cec5SDimitry Andric   SDValue Pred = getAL(CurDAG, dl);
21730b57cec5SDimitry Andric   SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
21740b57cec5SDimitry Andric   SDNode *VLd;
21750b57cec5SDimitry Andric   SmallVector<SDValue, 7> Ops;
21760b57cec5SDimitry Andric 
21770b57cec5SDimitry Andric   // Double registers and VLD1/VLD2 quad registers are directly supported.
21780b57cec5SDimitry Andric   if (is64BitVector || NumVecs <= 2) {
21790b57cec5SDimitry Andric     unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
21800b57cec5SDimitry Andric                     QOpcodes0[OpcodeIndex]);
21810b57cec5SDimitry Andric     Ops.push_back(MemAddr);
21820b57cec5SDimitry Andric     Ops.push_back(Align);
21830b57cec5SDimitry Andric     if (isUpdating) {
21840b57cec5SDimitry Andric       SDValue Inc = N->getOperand(AddrOpIdx + 1);
21850b57cec5SDimitry Andric       bool IsImmUpdate = isPerfectIncrement(Inc, VT, NumVecs);
21860b57cec5SDimitry Andric       if (!IsImmUpdate) {
21870b57cec5SDimitry Andric         // We use a VLD1 for v1i64 even if the pseudo says vld2/3/4, so
21880b57cec5SDimitry Andric         // check for the opcode rather than the number of vector elements.
21890b57cec5SDimitry Andric         if (isVLDfixed(Opc))
21900b57cec5SDimitry Andric           Opc = getVLDSTRegisterUpdateOpcode(Opc);
21910b57cec5SDimitry Andric         Ops.push_back(Inc);
21920b57cec5SDimitry Andric       // VLD1/VLD2 fixed increment does not need Reg0 so only include it in
21930b57cec5SDimitry Andric       // the operands if not such an opcode.
21940b57cec5SDimitry Andric       } else if (!isVLDfixed(Opc))
21950b57cec5SDimitry Andric         Ops.push_back(Reg0);
21960b57cec5SDimitry Andric     }
21970b57cec5SDimitry Andric     Ops.push_back(Pred);
21980b57cec5SDimitry Andric     Ops.push_back(Reg0);
21990b57cec5SDimitry Andric     Ops.push_back(Chain);
22000b57cec5SDimitry Andric     VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
22010b57cec5SDimitry Andric 
22020b57cec5SDimitry Andric   } else {
22030b57cec5SDimitry Andric     // Otherwise, quad registers are loaded with two separate instructions,
22040b57cec5SDimitry Andric     // where one loads the even registers and the other loads the odd registers.
22050b57cec5SDimitry Andric     EVT AddrTy = MemAddr.getValueType();
22060b57cec5SDimitry Andric 
22070b57cec5SDimitry Andric     // Load the even subregs.  This is always an updating load, so that it
22080b57cec5SDimitry Andric     // provides the address to the second load for the odd subregs.
22090b57cec5SDimitry Andric     SDValue ImplDef =
22100b57cec5SDimitry Andric       SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0);
22110b57cec5SDimitry Andric     const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain };
22120b57cec5SDimitry Andric     SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl,
22130b57cec5SDimitry Andric                                           ResTy, AddrTy, MVT::Other, OpsA);
22140b57cec5SDimitry Andric     Chain = SDValue(VLdA, 2);
22150b57cec5SDimitry Andric 
22160b57cec5SDimitry Andric     // Load the odd subregs.
22170b57cec5SDimitry Andric     Ops.push_back(SDValue(VLdA, 1));
22180b57cec5SDimitry Andric     Ops.push_back(Align);
22190b57cec5SDimitry Andric     if (isUpdating) {
22200b57cec5SDimitry Andric       SDValue Inc = N->getOperand(AddrOpIdx + 1);
22210b57cec5SDimitry Andric       assert(isa<ConstantSDNode>(Inc.getNode()) &&
22220b57cec5SDimitry Andric              "only constant post-increment update allowed for VLD3/4");
22230b57cec5SDimitry Andric       (void)Inc;
22240b57cec5SDimitry Andric       Ops.push_back(Reg0);
22250b57cec5SDimitry Andric     }
22260b57cec5SDimitry Andric     Ops.push_back(SDValue(VLdA, 0));
22270b57cec5SDimitry Andric     Ops.push_back(Pred);
22280b57cec5SDimitry Andric     Ops.push_back(Reg0);
22290b57cec5SDimitry Andric     Ops.push_back(Chain);
22300b57cec5SDimitry Andric     VLd = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, Ops);
22310b57cec5SDimitry Andric   }
22320b57cec5SDimitry Andric 
22330b57cec5SDimitry Andric   // Transfer memoperands.
22340b57cec5SDimitry Andric   MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
22350b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(VLd), {MemOp});
22360b57cec5SDimitry Andric 
22370b57cec5SDimitry Andric   if (NumVecs == 1) {
22380b57cec5SDimitry Andric     ReplaceNode(N, VLd);
22390b57cec5SDimitry Andric     return;
22400b57cec5SDimitry Andric   }
22410b57cec5SDimitry Andric 
22420b57cec5SDimitry Andric   // Extract out the subregisters.
22430b57cec5SDimitry Andric   SDValue SuperReg = SDValue(VLd, 0);
22440b57cec5SDimitry Andric   static_assert(ARM::dsub_7 == ARM::dsub_0 + 7 &&
22450b57cec5SDimitry Andric                     ARM::qsub_3 == ARM::qsub_0 + 3,
22460b57cec5SDimitry Andric                 "Unexpected subreg numbering");
22470b57cec5SDimitry Andric   unsigned Sub0 = (is64BitVector ? ARM::dsub_0 : ARM::qsub_0);
22480b57cec5SDimitry Andric   for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
22490b57cec5SDimitry Andric     ReplaceUses(SDValue(N, Vec),
22500b57cec5SDimitry Andric                 CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg));
22510b57cec5SDimitry Andric   ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1));
22520b57cec5SDimitry Andric   if (isUpdating)
22530b57cec5SDimitry Andric     ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLd, 2));
22540b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
22550b57cec5SDimitry Andric }
22560b57cec5SDimitry Andric 
SelectVST(SDNode * N,bool isUpdating,unsigned NumVecs,const uint16_t * DOpcodes,const uint16_t * QOpcodes0,const uint16_t * QOpcodes1)22570b57cec5SDimitry Andric void ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
22580b57cec5SDimitry Andric                                 const uint16_t *DOpcodes,
22590b57cec5SDimitry Andric                                 const uint16_t *QOpcodes0,
22600b57cec5SDimitry Andric                                 const uint16_t *QOpcodes1) {
22615ffd83dbSDimitry Andric   assert(Subtarget->hasNEON());
22620b57cec5SDimitry Andric   assert(NumVecs >= 1 && NumVecs <= 4 && "VST NumVecs out-of-range");
22630b57cec5SDimitry Andric   SDLoc dl(N);
22640b57cec5SDimitry Andric 
22650b57cec5SDimitry Andric   SDValue MemAddr, Align;
22660b57cec5SDimitry Andric   bool IsIntrinsic = !isUpdating;  // By coincidence, all supported updating
22670b57cec5SDimitry Andric                                    // nodes are not intrinsics.
22680b57cec5SDimitry Andric   unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
22690b57cec5SDimitry Andric   unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
22700b57cec5SDimitry Andric   if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
22710b57cec5SDimitry Andric     return;
22720b57cec5SDimitry Andric 
22730b57cec5SDimitry Andric   MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
22740b57cec5SDimitry Andric 
22750b57cec5SDimitry Andric   SDValue Chain = N->getOperand(0);
22760b57cec5SDimitry Andric   EVT VT = N->getOperand(Vec0Idx).getValueType();
22770b57cec5SDimitry Andric   bool is64BitVector = VT.is64BitVector();
22780b57cec5SDimitry Andric   Align = GetVLDSTAlign(Align, dl, NumVecs, is64BitVector);
22790b57cec5SDimitry Andric 
22800b57cec5SDimitry Andric   unsigned OpcodeIndex;
22810b57cec5SDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
22820b57cec5SDimitry Andric   default: llvm_unreachable("unhandled vst type");
22830b57cec5SDimitry Andric     // Double-register operations:
22840b57cec5SDimitry Andric   case MVT::v8i8:  OpcodeIndex = 0; break;
22850b57cec5SDimitry Andric   case MVT::v4f16:
22865ffd83dbSDimitry Andric   case MVT::v4bf16:
22870b57cec5SDimitry Andric   case MVT::v4i16: OpcodeIndex = 1; break;
22880b57cec5SDimitry Andric   case MVT::v2f32:
22890b57cec5SDimitry Andric   case MVT::v2i32: OpcodeIndex = 2; break;
22900b57cec5SDimitry Andric   case MVT::v1i64: OpcodeIndex = 3; break;
22910b57cec5SDimitry Andric     // Quad-register operations:
22920b57cec5SDimitry Andric   case MVT::v16i8: OpcodeIndex = 0; break;
22930b57cec5SDimitry Andric   case MVT::v8f16:
22945ffd83dbSDimitry Andric   case MVT::v8bf16:
22950b57cec5SDimitry Andric   case MVT::v8i16: OpcodeIndex = 1; break;
22960b57cec5SDimitry Andric   case MVT::v4f32:
22970b57cec5SDimitry Andric   case MVT::v4i32: OpcodeIndex = 2; break;
22980b57cec5SDimitry Andric   case MVT::v2f64:
22990b57cec5SDimitry Andric   case MVT::v2i64: OpcodeIndex = 3; break;
23000b57cec5SDimitry Andric   }
23010b57cec5SDimitry Andric 
23020b57cec5SDimitry Andric   std::vector<EVT> ResTys;
23030b57cec5SDimitry Andric   if (isUpdating)
23040b57cec5SDimitry Andric     ResTys.push_back(MVT::i32);
23050b57cec5SDimitry Andric   ResTys.push_back(MVT::Other);
23060b57cec5SDimitry Andric 
23070b57cec5SDimitry Andric   SDValue Pred = getAL(CurDAG, dl);
23080b57cec5SDimitry Andric   SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
23090b57cec5SDimitry Andric   SmallVector<SDValue, 7> Ops;
23100b57cec5SDimitry Andric 
23110b57cec5SDimitry Andric   // Double registers and VST1/VST2 quad registers are directly supported.
23120b57cec5SDimitry Andric   if (is64BitVector || NumVecs <= 2) {
23130b57cec5SDimitry Andric     SDValue SrcReg;
23140b57cec5SDimitry Andric     if (NumVecs == 1) {
23150b57cec5SDimitry Andric       SrcReg = N->getOperand(Vec0Idx);
23160b57cec5SDimitry Andric     } else if (is64BitVector) {
23170b57cec5SDimitry Andric       // Form a REG_SEQUENCE to force register allocation.
23180b57cec5SDimitry Andric       SDValue V0 = N->getOperand(Vec0Idx + 0);
23190b57cec5SDimitry Andric       SDValue V1 = N->getOperand(Vec0Idx + 1);
23200b57cec5SDimitry Andric       if (NumVecs == 2)
23210b57cec5SDimitry Andric         SrcReg = SDValue(createDRegPairNode(MVT::v2i64, V0, V1), 0);
23220b57cec5SDimitry Andric       else {
23230b57cec5SDimitry Andric         SDValue V2 = N->getOperand(Vec0Idx + 2);
23240b57cec5SDimitry Andric         // If it's a vst3, form a quad D-register and leave the last part as
23250b57cec5SDimitry Andric         // an undef.
23260b57cec5SDimitry Andric         SDValue V3 = (NumVecs == 3)
23270b57cec5SDimitry Andric           ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0)
23280b57cec5SDimitry Andric           : N->getOperand(Vec0Idx + 3);
23290b57cec5SDimitry Andric         SrcReg = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
23300b57cec5SDimitry Andric       }
23310b57cec5SDimitry Andric     } else {
23320b57cec5SDimitry Andric       // Form a QQ register.
23330b57cec5SDimitry Andric       SDValue Q0 = N->getOperand(Vec0Idx);
23340b57cec5SDimitry Andric       SDValue Q1 = N->getOperand(Vec0Idx + 1);
23350b57cec5SDimitry Andric       SrcReg = SDValue(createQRegPairNode(MVT::v4i64, Q0, Q1), 0);
23360b57cec5SDimitry Andric     }
23370b57cec5SDimitry Andric 
23380b57cec5SDimitry Andric     unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
23390b57cec5SDimitry Andric                     QOpcodes0[OpcodeIndex]);
23400b57cec5SDimitry Andric     Ops.push_back(MemAddr);
23410b57cec5SDimitry Andric     Ops.push_back(Align);
23420b57cec5SDimitry Andric     if (isUpdating) {
23430b57cec5SDimitry Andric       SDValue Inc = N->getOperand(AddrOpIdx + 1);
23440b57cec5SDimitry Andric       bool IsImmUpdate = isPerfectIncrement(Inc, VT, NumVecs);
23450b57cec5SDimitry Andric       if (!IsImmUpdate) {
23460b57cec5SDimitry Andric         // We use a VST1 for v1i64 even if the pseudo says VST2/3/4, so
23470b57cec5SDimitry Andric         // check for the opcode rather than the number of vector elements.
23480b57cec5SDimitry Andric         if (isVSTfixed(Opc))
23490b57cec5SDimitry Andric           Opc = getVLDSTRegisterUpdateOpcode(Opc);
23500b57cec5SDimitry Andric         Ops.push_back(Inc);
23510b57cec5SDimitry Andric       }
23520b57cec5SDimitry Andric       // VST1/VST2 fixed increment does not need Reg0 so only include it in
23530b57cec5SDimitry Andric       // the operands if not such an opcode.
23540b57cec5SDimitry Andric       else if (!isVSTfixed(Opc))
23550b57cec5SDimitry Andric         Ops.push_back(Reg0);
23560b57cec5SDimitry Andric     }
23570b57cec5SDimitry Andric     Ops.push_back(SrcReg);
23580b57cec5SDimitry Andric     Ops.push_back(Pred);
23590b57cec5SDimitry Andric     Ops.push_back(Reg0);
23600b57cec5SDimitry Andric     Ops.push_back(Chain);
23610b57cec5SDimitry Andric     SDNode *VSt = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
23620b57cec5SDimitry Andric 
23630b57cec5SDimitry Andric     // Transfer memoperands.
23640b57cec5SDimitry Andric     CurDAG->setNodeMemRefs(cast<MachineSDNode>(VSt), {MemOp});
23650b57cec5SDimitry Andric 
23660b57cec5SDimitry Andric     ReplaceNode(N, VSt);
23670b57cec5SDimitry Andric     return;
23680b57cec5SDimitry Andric   }
23690b57cec5SDimitry Andric 
23700b57cec5SDimitry Andric   // Otherwise, quad registers are stored with two separate instructions,
23710b57cec5SDimitry Andric   // where one stores the even registers and the other stores the odd registers.
23720b57cec5SDimitry Andric 
23730b57cec5SDimitry Andric   // Form the QQQQ REG_SEQUENCE.
23740b57cec5SDimitry Andric   SDValue V0 = N->getOperand(Vec0Idx + 0);
23750b57cec5SDimitry Andric   SDValue V1 = N->getOperand(Vec0Idx + 1);
23760b57cec5SDimitry Andric   SDValue V2 = N->getOperand(Vec0Idx + 2);
23770b57cec5SDimitry Andric   SDValue V3 = (NumVecs == 3)
23780b57cec5SDimitry Andric     ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
23790b57cec5SDimitry Andric     : N->getOperand(Vec0Idx + 3);
23800b57cec5SDimitry Andric   SDValue RegSeq = SDValue(createQuadQRegsNode(MVT::v8i64, V0, V1, V2, V3), 0);
23810b57cec5SDimitry Andric 
23820b57cec5SDimitry Andric   // Store the even D registers.  This is always an updating store, so that it
23830b57cec5SDimitry Andric   // provides the address to the second store for the odd subregs.
23840b57cec5SDimitry Andric   const SDValue OpsA[] = { MemAddr, Align, Reg0, RegSeq, Pred, Reg0, Chain };
23850b57cec5SDimitry Andric   SDNode *VStA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl,
23860b57cec5SDimitry Andric                                         MemAddr.getValueType(),
23870b57cec5SDimitry Andric                                         MVT::Other, OpsA);
23880b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(VStA), {MemOp});
23890b57cec5SDimitry Andric   Chain = SDValue(VStA, 1);
23900b57cec5SDimitry Andric 
23910b57cec5SDimitry Andric   // Store the odd D registers.
23920b57cec5SDimitry Andric   Ops.push_back(SDValue(VStA, 0));
23930b57cec5SDimitry Andric   Ops.push_back(Align);
23940b57cec5SDimitry Andric   if (isUpdating) {
23950b57cec5SDimitry Andric     SDValue Inc = N->getOperand(AddrOpIdx + 1);
23960b57cec5SDimitry Andric     assert(isa<ConstantSDNode>(Inc.getNode()) &&
23970b57cec5SDimitry Andric            "only constant post-increment update allowed for VST3/4");
23980b57cec5SDimitry Andric     (void)Inc;
23990b57cec5SDimitry Andric     Ops.push_back(Reg0);
24000b57cec5SDimitry Andric   }
24010b57cec5SDimitry Andric   Ops.push_back(RegSeq);
24020b57cec5SDimitry Andric   Ops.push_back(Pred);
24030b57cec5SDimitry Andric   Ops.push_back(Reg0);
24040b57cec5SDimitry Andric   Ops.push_back(Chain);
24050b57cec5SDimitry Andric   SDNode *VStB = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys,
24060b57cec5SDimitry Andric                                         Ops);
24070b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(VStB), {MemOp});
24080b57cec5SDimitry Andric   ReplaceNode(N, VStB);
24090b57cec5SDimitry Andric }
24100b57cec5SDimitry Andric 
SelectVLDSTLane(SDNode * N,bool IsLoad,bool isUpdating,unsigned NumVecs,const uint16_t * DOpcodes,const uint16_t * QOpcodes)24110b57cec5SDimitry Andric void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
24120b57cec5SDimitry Andric                                       unsigned NumVecs,
24130b57cec5SDimitry Andric                                       const uint16_t *DOpcodes,
24140b57cec5SDimitry Andric                                       const uint16_t *QOpcodes) {
24155ffd83dbSDimitry Andric   assert(Subtarget->hasNEON());
24160b57cec5SDimitry Andric   assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range");
24170b57cec5SDimitry Andric   SDLoc dl(N);
24180b57cec5SDimitry Andric 
24190b57cec5SDimitry Andric   SDValue MemAddr, Align;
24200b57cec5SDimitry Andric   bool IsIntrinsic = !isUpdating;  // By coincidence, all supported updating
24210b57cec5SDimitry Andric                                    // nodes are not intrinsics.
24220b57cec5SDimitry Andric   unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
24230b57cec5SDimitry Andric   unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
24240b57cec5SDimitry Andric   if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
24250b57cec5SDimitry Andric     return;
24260b57cec5SDimitry Andric 
24270b57cec5SDimitry Andric   MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
24280b57cec5SDimitry Andric 
24290b57cec5SDimitry Andric   SDValue Chain = N->getOperand(0);
2430647cbc5dSDimitry Andric   unsigned Lane = N->getConstantOperandVal(Vec0Idx + NumVecs);
24310b57cec5SDimitry Andric   EVT VT = N->getOperand(Vec0Idx).getValueType();
24320b57cec5SDimitry Andric   bool is64BitVector = VT.is64BitVector();
24330b57cec5SDimitry Andric 
24340b57cec5SDimitry Andric   unsigned Alignment = 0;
24350b57cec5SDimitry Andric   if (NumVecs != 3) {
24361db9f3b2SDimitry Andric     Alignment = Align->getAsZExtVal();
24370b57cec5SDimitry Andric     unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
24380b57cec5SDimitry Andric     if (Alignment > NumBytes)
24390b57cec5SDimitry Andric       Alignment = NumBytes;
24400b57cec5SDimitry Andric     if (Alignment < 8 && Alignment < NumBytes)
24410b57cec5SDimitry Andric       Alignment = 0;
24420b57cec5SDimitry Andric     // Alignment must be a power of two; make sure of that.
24430b57cec5SDimitry Andric     Alignment = (Alignment & -Alignment);
24440b57cec5SDimitry Andric     if (Alignment == 1)
24450b57cec5SDimitry Andric       Alignment = 0;
24460b57cec5SDimitry Andric   }
24470b57cec5SDimitry Andric   Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
24480b57cec5SDimitry Andric 
24490b57cec5SDimitry Andric   unsigned OpcodeIndex;
24500b57cec5SDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
24510b57cec5SDimitry Andric   default: llvm_unreachable("unhandled vld/vst lane type");
24520b57cec5SDimitry Andric     // Double-register operations:
24530b57cec5SDimitry Andric   case MVT::v8i8:  OpcodeIndex = 0; break;
24540b57cec5SDimitry Andric   case MVT::v4f16:
24555ffd83dbSDimitry Andric   case MVT::v4bf16:
24560b57cec5SDimitry Andric   case MVT::v4i16: OpcodeIndex = 1; break;
24570b57cec5SDimitry Andric   case MVT::v2f32:
24580b57cec5SDimitry Andric   case MVT::v2i32: OpcodeIndex = 2; break;
24590b57cec5SDimitry Andric     // Quad-register operations:
24600b57cec5SDimitry Andric   case MVT::v8f16:
24615ffd83dbSDimitry Andric   case MVT::v8bf16:
24620b57cec5SDimitry Andric   case MVT::v8i16: OpcodeIndex = 0; break;
24630b57cec5SDimitry Andric   case MVT::v4f32:
24640b57cec5SDimitry Andric   case MVT::v4i32: OpcodeIndex = 1; break;
24650b57cec5SDimitry Andric   }
24660b57cec5SDimitry Andric 
24670b57cec5SDimitry Andric   std::vector<EVT> ResTys;
24680b57cec5SDimitry Andric   if (IsLoad) {
24690b57cec5SDimitry Andric     unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
24700b57cec5SDimitry Andric     if (!is64BitVector)
24710b57cec5SDimitry Andric       ResTyElts *= 2;
24720b57cec5SDimitry Andric     ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(),
24730b57cec5SDimitry Andric                                       MVT::i64, ResTyElts));
24740b57cec5SDimitry Andric   }
24750b57cec5SDimitry Andric   if (isUpdating)
24760b57cec5SDimitry Andric     ResTys.push_back(MVT::i32);
24770b57cec5SDimitry Andric   ResTys.push_back(MVT::Other);
24780b57cec5SDimitry Andric 
24790b57cec5SDimitry Andric   SDValue Pred = getAL(CurDAG, dl);
24800b57cec5SDimitry Andric   SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
24810b57cec5SDimitry Andric 
24820b57cec5SDimitry Andric   SmallVector<SDValue, 8> Ops;
24830b57cec5SDimitry Andric   Ops.push_back(MemAddr);
24840b57cec5SDimitry Andric   Ops.push_back(Align);
24850b57cec5SDimitry Andric   if (isUpdating) {
24860b57cec5SDimitry Andric     SDValue Inc = N->getOperand(AddrOpIdx + 1);
24870b57cec5SDimitry Andric     bool IsImmUpdate =
24880b57cec5SDimitry Andric         isPerfectIncrement(Inc, VT.getVectorElementType(), NumVecs);
24890b57cec5SDimitry Andric     Ops.push_back(IsImmUpdate ? Reg0 : Inc);
24900b57cec5SDimitry Andric   }
24910b57cec5SDimitry Andric 
24920b57cec5SDimitry Andric   SDValue SuperReg;
24930b57cec5SDimitry Andric   SDValue V0 = N->getOperand(Vec0Idx + 0);
24940b57cec5SDimitry Andric   SDValue V1 = N->getOperand(Vec0Idx + 1);
24950b57cec5SDimitry Andric   if (NumVecs == 2) {
24960b57cec5SDimitry Andric     if (is64BitVector)
24970b57cec5SDimitry Andric       SuperReg = SDValue(createDRegPairNode(MVT::v2i64, V0, V1), 0);
24980b57cec5SDimitry Andric     else
24990b57cec5SDimitry Andric       SuperReg = SDValue(createQRegPairNode(MVT::v4i64, V0, V1), 0);
25000b57cec5SDimitry Andric   } else {
25010b57cec5SDimitry Andric     SDValue V2 = N->getOperand(Vec0Idx + 2);
25020b57cec5SDimitry Andric     SDValue V3 = (NumVecs == 3)
25030b57cec5SDimitry Andric       ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
25040b57cec5SDimitry Andric       : N->getOperand(Vec0Idx + 3);
25050b57cec5SDimitry Andric     if (is64BitVector)
25060b57cec5SDimitry Andric       SuperReg = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
25070b57cec5SDimitry Andric     else
25080b57cec5SDimitry Andric       SuperReg = SDValue(createQuadQRegsNode(MVT::v8i64, V0, V1, V2, V3), 0);
25090b57cec5SDimitry Andric   }
25100b57cec5SDimitry Andric   Ops.push_back(SuperReg);
25110b57cec5SDimitry Andric   Ops.push_back(getI32Imm(Lane, dl));
25120b57cec5SDimitry Andric   Ops.push_back(Pred);
25130b57cec5SDimitry Andric   Ops.push_back(Reg0);
25140b57cec5SDimitry Andric   Ops.push_back(Chain);
25150b57cec5SDimitry Andric 
25160b57cec5SDimitry Andric   unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
25170b57cec5SDimitry Andric                                   QOpcodes[OpcodeIndex]);
25180b57cec5SDimitry Andric   SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
25190b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(VLdLn), {MemOp});
25200b57cec5SDimitry Andric   if (!IsLoad) {
25210b57cec5SDimitry Andric     ReplaceNode(N, VLdLn);
25220b57cec5SDimitry Andric     return;
25230b57cec5SDimitry Andric   }
25240b57cec5SDimitry Andric 
25250b57cec5SDimitry Andric   // Extract the subregisters.
25260b57cec5SDimitry Andric   SuperReg = SDValue(VLdLn, 0);
25270b57cec5SDimitry Andric   static_assert(ARM::dsub_7 == ARM::dsub_0 + 7 &&
25280b57cec5SDimitry Andric                     ARM::qsub_3 == ARM::qsub_0 + 3,
25290b57cec5SDimitry Andric                 "Unexpected subreg numbering");
25300b57cec5SDimitry Andric   unsigned Sub0 = is64BitVector ? ARM::dsub_0 : ARM::qsub_0;
25310b57cec5SDimitry Andric   for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
25320b57cec5SDimitry Andric     ReplaceUses(SDValue(N, Vec),
25330b57cec5SDimitry Andric                 CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg));
25340b57cec5SDimitry Andric   ReplaceUses(SDValue(N, NumVecs), SDValue(VLdLn, 1));
25350b57cec5SDimitry Andric   if (isUpdating)
25360b57cec5SDimitry Andric     ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdLn, 2));
25370b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
25380b57cec5SDimitry Andric }
25390b57cec5SDimitry Andric 
2540480093f4SDimitry Andric template <typename SDValueVector>
AddMVEPredicateToOps(SDValueVector & Ops,SDLoc Loc,SDValue PredicateMask)2541480093f4SDimitry Andric void ARMDAGToDAGISel::AddMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc,
2542480093f4SDimitry Andric                                            SDValue PredicateMask) {
2543480093f4SDimitry Andric   Ops.push_back(CurDAG->getTargetConstant(ARMVCC::Then, Loc, MVT::i32));
2544480093f4SDimitry Andric   Ops.push_back(PredicateMask);
2545349cc55cSDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // tp_reg
2546480093f4SDimitry Andric }
2547480093f4SDimitry Andric 
2548480093f4SDimitry Andric template <typename SDValueVector>
AddMVEPredicateToOps(SDValueVector & Ops,SDLoc Loc,SDValue PredicateMask,SDValue Inactive)2549480093f4SDimitry Andric void ARMDAGToDAGISel::AddMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc,
2550480093f4SDimitry Andric                                            SDValue PredicateMask,
2551480093f4SDimitry Andric                                            SDValue Inactive) {
2552480093f4SDimitry Andric   Ops.push_back(CurDAG->getTargetConstant(ARMVCC::Then, Loc, MVT::i32));
2553480093f4SDimitry Andric   Ops.push_back(PredicateMask);
2554349cc55cSDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // tp_reg
2555480093f4SDimitry Andric   Ops.push_back(Inactive);
2556480093f4SDimitry Andric }
2557480093f4SDimitry Andric 
2558480093f4SDimitry Andric template <typename SDValueVector>
AddEmptyMVEPredicateToOps(SDValueVector & Ops,SDLoc Loc)2559480093f4SDimitry Andric void ARMDAGToDAGISel::AddEmptyMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc) {
2560480093f4SDimitry Andric   Ops.push_back(CurDAG->getTargetConstant(ARMVCC::None, Loc, MVT::i32));
2561480093f4SDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32));
2562349cc55cSDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // tp_reg
2563480093f4SDimitry Andric }
2564480093f4SDimitry Andric 
2565480093f4SDimitry Andric template <typename SDValueVector>
AddEmptyMVEPredicateToOps(SDValueVector & Ops,SDLoc Loc,EVT InactiveTy)2566480093f4SDimitry Andric void ARMDAGToDAGISel::AddEmptyMVEPredicateToOps(SDValueVector &Ops, SDLoc Loc,
2567480093f4SDimitry Andric                                                 EVT InactiveTy) {
2568480093f4SDimitry Andric   Ops.push_back(CurDAG->getTargetConstant(ARMVCC::None, Loc, MVT::i32));
2569480093f4SDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32));
2570349cc55cSDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // tp_reg
2571480093f4SDimitry Andric   Ops.push_back(SDValue(
2572480093f4SDimitry Andric       CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, Loc, InactiveTy), 0));
2573480093f4SDimitry Andric }
2574480093f4SDimitry Andric 
SelectMVE_WB(SDNode * N,const uint16_t * Opcodes,bool Predicated)2575480093f4SDimitry Andric void ARMDAGToDAGISel::SelectMVE_WB(SDNode *N, const uint16_t *Opcodes,
2576480093f4SDimitry Andric                                    bool Predicated) {
2577480093f4SDimitry Andric   SDLoc Loc(N);
2578480093f4SDimitry Andric   SmallVector<SDValue, 8> Ops;
2579480093f4SDimitry Andric 
2580480093f4SDimitry Andric   uint16_t Opcode;
2581480093f4SDimitry Andric   switch (N->getValueType(1).getVectorElementType().getSizeInBits()) {
2582480093f4SDimitry Andric   case 32:
2583480093f4SDimitry Andric     Opcode = Opcodes[0];
2584480093f4SDimitry Andric     break;
2585480093f4SDimitry Andric   case 64:
2586480093f4SDimitry Andric     Opcode = Opcodes[1];
2587480093f4SDimitry Andric     break;
2588480093f4SDimitry Andric   default:
2589480093f4SDimitry Andric     llvm_unreachable("bad vector element size in SelectMVE_WB");
2590480093f4SDimitry Andric   }
2591480093f4SDimitry Andric 
2592480093f4SDimitry Andric   Ops.push_back(N->getOperand(2)); // vector of base addresses
2593480093f4SDimitry Andric 
2594647cbc5dSDimitry Andric   int32_t ImmValue = N->getConstantOperandVal(3);
2595480093f4SDimitry Andric   Ops.push_back(getI32Imm(ImmValue, Loc)); // immediate offset
2596480093f4SDimitry Andric 
2597480093f4SDimitry Andric   if (Predicated)
2598480093f4SDimitry Andric     AddMVEPredicateToOps(Ops, Loc, N->getOperand(4));
2599480093f4SDimitry Andric   else
2600480093f4SDimitry Andric     AddEmptyMVEPredicateToOps(Ops, Loc);
2601480093f4SDimitry Andric 
2602480093f4SDimitry Andric   Ops.push_back(N->getOperand(0)); // chain
2603480093f4SDimitry Andric 
26045ffd83dbSDimitry Andric   SmallVector<EVT, 8> VTs;
26055ffd83dbSDimitry Andric   VTs.push_back(N->getValueType(1));
26065ffd83dbSDimitry Andric   VTs.push_back(N->getValueType(0));
26075ffd83dbSDimitry Andric   VTs.push_back(N->getValueType(2));
26085ffd83dbSDimitry Andric 
26095ffd83dbSDimitry Andric   SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), VTs, Ops);
26105ffd83dbSDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(New, 1));
26115ffd83dbSDimitry Andric   ReplaceUses(SDValue(N, 1), SDValue(New, 0));
26125ffd83dbSDimitry Andric   ReplaceUses(SDValue(N, 2), SDValue(New, 2));
2613fe6060f1SDimitry Andric   transferMemOperands(N, New);
26145ffd83dbSDimitry Andric   CurDAG->RemoveDeadNode(N);
2615480093f4SDimitry Andric }
2616480093f4SDimitry Andric 
SelectMVE_LongShift(SDNode * N,uint16_t Opcode,bool Immediate,bool HasSaturationOperand)2617480093f4SDimitry Andric void ARMDAGToDAGISel::SelectMVE_LongShift(SDNode *N, uint16_t Opcode,
2618480093f4SDimitry Andric                                           bool Immediate,
2619480093f4SDimitry Andric                                           bool HasSaturationOperand) {
2620480093f4SDimitry Andric   SDLoc Loc(N);
2621480093f4SDimitry Andric   SmallVector<SDValue, 8> Ops;
2622480093f4SDimitry Andric 
2623480093f4SDimitry Andric   // Two 32-bit halves of the value to be shifted
2624480093f4SDimitry Andric   Ops.push_back(N->getOperand(1));
2625480093f4SDimitry Andric   Ops.push_back(N->getOperand(2));
2626480093f4SDimitry Andric 
2627480093f4SDimitry Andric   // The shift count
2628480093f4SDimitry Andric   if (Immediate) {
2629647cbc5dSDimitry Andric     int32_t ImmValue = N->getConstantOperandVal(3);
2630480093f4SDimitry Andric     Ops.push_back(getI32Imm(ImmValue, Loc)); // immediate shift count
2631480093f4SDimitry Andric   } else {
2632480093f4SDimitry Andric     Ops.push_back(N->getOperand(3));
2633480093f4SDimitry Andric   }
2634480093f4SDimitry Andric 
2635480093f4SDimitry Andric   // The immediate saturation operand, if any
2636480093f4SDimitry Andric   if (HasSaturationOperand) {
2637647cbc5dSDimitry Andric     int32_t SatOp = N->getConstantOperandVal(4);
2638480093f4SDimitry Andric     int SatBit = (SatOp == 64 ? 0 : 1);
2639480093f4SDimitry Andric     Ops.push_back(getI32Imm(SatBit, Loc));
2640480093f4SDimitry Andric   }
2641480093f4SDimitry Andric 
2642480093f4SDimitry Andric   // MVE scalar shifts are IT-predicable, so include the standard
2643480093f4SDimitry Andric   // predicate arguments.
2644480093f4SDimitry Andric   Ops.push_back(getAL(CurDAG, Loc));
2645480093f4SDimitry Andric   Ops.push_back(CurDAG->getRegister(0, MVT::i32));
2646480093f4SDimitry Andric 
2647bdd1243dSDimitry Andric   CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), ArrayRef(Ops));
2648480093f4SDimitry Andric }
2649480093f4SDimitry Andric 
SelectMVE_VADCSBC(SDNode * N,uint16_t OpcodeWithCarry,uint16_t OpcodeWithNoCarry,bool Add,bool Predicated)2650480093f4SDimitry Andric void ARMDAGToDAGISel::SelectMVE_VADCSBC(SDNode *N, uint16_t OpcodeWithCarry,
2651480093f4SDimitry Andric                                         uint16_t OpcodeWithNoCarry,
2652480093f4SDimitry Andric                                         bool Add, bool Predicated) {
2653480093f4SDimitry Andric   SDLoc Loc(N);
2654480093f4SDimitry Andric   SmallVector<SDValue, 8> Ops;
2655480093f4SDimitry Andric   uint16_t Opcode;
2656480093f4SDimitry Andric 
2657480093f4SDimitry Andric   unsigned FirstInputOp = Predicated ? 2 : 1;
2658480093f4SDimitry Andric 
2659480093f4SDimitry Andric   // Two input vectors and the input carry flag
2660480093f4SDimitry Andric   Ops.push_back(N->getOperand(FirstInputOp));
2661480093f4SDimitry Andric   Ops.push_back(N->getOperand(FirstInputOp + 1));
2662480093f4SDimitry Andric   SDValue CarryIn = N->getOperand(FirstInputOp + 2);
2663480093f4SDimitry Andric   ConstantSDNode *CarryInConstant = dyn_cast<ConstantSDNode>(CarryIn);
2664480093f4SDimitry Andric   uint32_t CarryMask = 1 << 29;
2665480093f4SDimitry Andric   uint32_t CarryExpected = Add ? 0 : CarryMask;
2666480093f4SDimitry Andric   if (CarryInConstant &&
2667480093f4SDimitry Andric       (CarryInConstant->getZExtValue() & CarryMask) == CarryExpected) {
2668480093f4SDimitry Andric     Opcode = OpcodeWithNoCarry;
2669480093f4SDimitry Andric   } else {
2670480093f4SDimitry Andric     Ops.push_back(CarryIn);
2671480093f4SDimitry Andric     Opcode = OpcodeWithCarry;
2672480093f4SDimitry Andric   }
2673480093f4SDimitry Andric 
2674480093f4SDimitry Andric   if (Predicated)
2675480093f4SDimitry Andric     AddMVEPredicateToOps(Ops, Loc,
2676480093f4SDimitry Andric                          N->getOperand(FirstInputOp + 3),  // predicate
2677480093f4SDimitry Andric                          N->getOperand(FirstInputOp - 1)); // inactive
2678480093f4SDimitry Andric   else
2679480093f4SDimitry Andric     AddEmptyMVEPredicateToOps(Ops, Loc, N->getValueType(0));
2680480093f4SDimitry Andric 
2681bdd1243dSDimitry Andric   CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), ArrayRef(Ops));
2682480093f4SDimitry Andric }
2683480093f4SDimitry Andric 
SelectMVE_VSHLC(SDNode * N,bool Predicated)26845ffd83dbSDimitry Andric void ARMDAGToDAGISel::SelectMVE_VSHLC(SDNode *N, bool Predicated) {
26855ffd83dbSDimitry Andric   SDLoc Loc(N);
26865ffd83dbSDimitry Andric   SmallVector<SDValue, 8> Ops;
26875ffd83dbSDimitry Andric 
26885ffd83dbSDimitry Andric   // One vector input, followed by a 32-bit word of bits to shift in
26895ffd83dbSDimitry Andric   // and then an immediate shift count
26905ffd83dbSDimitry Andric   Ops.push_back(N->getOperand(1));
26915ffd83dbSDimitry Andric   Ops.push_back(N->getOperand(2));
2692647cbc5dSDimitry Andric   int32_t ImmValue = N->getConstantOperandVal(3);
26935ffd83dbSDimitry Andric   Ops.push_back(getI32Imm(ImmValue, Loc)); // immediate shift count
26945ffd83dbSDimitry Andric 
26955ffd83dbSDimitry Andric   if (Predicated)
26965ffd83dbSDimitry Andric     AddMVEPredicateToOps(Ops, Loc, N->getOperand(4));
26975ffd83dbSDimitry Andric   else
26985ffd83dbSDimitry Andric     AddEmptyMVEPredicateToOps(Ops, Loc);
26995ffd83dbSDimitry Andric 
2700bdd1243dSDimitry Andric   CurDAG->SelectNodeTo(N, ARM::MVE_VSHLC, N->getVTList(), ArrayRef(Ops));
27015ffd83dbSDimitry Andric }
27025ffd83dbSDimitry Andric 
SDValueToConstBool(SDValue SDVal)2703480093f4SDimitry Andric static bool SDValueToConstBool(SDValue SDVal) {
2704480093f4SDimitry Andric   assert(isa<ConstantSDNode>(SDVal) && "expected a compile-time constant");
2705480093f4SDimitry Andric   ConstantSDNode *SDValConstant = dyn_cast<ConstantSDNode>(SDVal);
2706480093f4SDimitry Andric   uint64_t Value = SDValConstant->getZExtValue();
2707480093f4SDimitry Andric   assert((Value == 0 || Value == 1) && "expected value 0 or 1");
2708480093f4SDimitry Andric   return Value;
2709480093f4SDimitry Andric }
2710480093f4SDimitry Andric 
SelectBaseMVE_VMLLDAV(SDNode * N,bool Predicated,const uint16_t * OpcodesS,const uint16_t * OpcodesU,size_t Stride,size_t TySize)2711480093f4SDimitry Andric void ARMDAGToDAGISel::SelectBaseMVE_VMLLDAV(SDNode *N, bool Predicated,
2712480093f4SDimitry Andric                                             const uint16_t *OpcodesS,
2713480093f4SDimitry Andric                                             const uint16_t *OpcodesU,
2714480093f4SDimitry Andric                                             size_t Stride, size_t TySize) {
2715480093f4SDimitry Andric   assert(TySize < Stride && "Invalid TySize");
2716480093f4SDimitry Andric   bool IsUnsigned = SDValueToConstBool(N->getOperand(1));
2717480093f4SDimitry Andric   bool IsSub = SDValueToConstBool(N->getOperand(2));
2718480093f4SDimitry Andric   bool IsExchange = SDValueToConstBool(N->getOperand(3));
2719480093f4SDimitry Andric   if (IsUnsigned) {
2720480093f4SDimitry Andric     assert(!IsSub &&
2721480093f4SDimitry Andric            "Unsigned versions of vmlsldav[a]/vrmlsldavh[a] do not exist");
2722480093f4SDimitry Andric     assert(!IsExchange &&
2723480093f4SDimitry Andric            "Unsigned versions of vmlaldav[a]x/vrmlaldavh[a]x do not exist");
2724480093f4SDimitry Andric   }
2725480093f4SDimitry Andric 
2726480093f4SDimitry Andric   auto OpIsZero = [N](size_t OpNo) {
272706c3fb27SDimitry Andric     return isNullConstant(N->getOperand(OpNo));
2728480093f4SDimitry Andric   };
2729480093f4SDimitry Andric 
2730480093f4SDimitry Andric   // If the input accumulator value is not zero, select an instruction with
2731480093f4SDimitry Andric   // accumulator, otherwise select an instruction without accumulator
2732480093f4SDimitry Andric   bool IsAccum = !(OpIsZero(4) && OpIsZero(5));
2733480093f4SDimitry Andric 
2734480093f4SDimitry Andric   const uint16_t *Opcodes = IsUnsigned ? OpcodesU : OpcodesS;
2735480093f4SDimitry Andric   if (IsSub)
2736480093f4SDimitry Andric     Opcodes += 4 * Stride;
2737480093f4SDimitry Andric   if (IsExchange)
2738480093f4SDimitry Andric     Opcodes += 2 * Stride;
2739480093f4SDimitry Andric   if (IsAccum)
2740480093f4SDimitry Andric     Opcodes += Stride;
2741480093f4SDimitry Andric   uint16_t Opcode = Opcodes[TySize];
2742480093f4SDimitry Andric 
2743480093f4SDimitry Andric   SDLoc Loc(N);
2744480093f4SDimitry Andric   SmallVector<SDValue, 8> Ops;
2745480093f4SDimitry Andric   // Push the accumulator operands, if they are used
2746480093f4SDimitry Andric   if (IsAccum) {
2747480093f4SDimitry Andric     Ops.push_back(N->getOperand(4));
2748480093f4SDimitry Andric     Ops.push_back(N->getOperand(5));
2749480093f4SDimitry Andric   }
2750480093f4SDimitry Andric   // Push the two vector operands
2751480093f4SDimitry Andric   Ops.push_back(N->getOperand(6));
2752480093f4SDimitry Andric   Ops.push_back(N->getOperand(7));
2753480093f4SDimitry Andric 
2754480093f4SDimitry Andric   if (Predicated)
2755480093f4SDimitry Andric     AddMVEPredicateToOps(Ops, Loc, N->getOperand(8));
2756480093f4SDimitry Andric   else
2757480093f4SDimitry Andric     AddEmptyMVEPredicateToOps(Ops, Loc);
2758480093f4SDimitry Andric 
2759bdd1243dSDimitry Andric   CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), ArrayRef(Ops));
2760480093f4SDimitry Andric }
2761480093f4SDimitry Andric 
SelectMVE_VMLLDAV(SDNode * N,bool Predicated,const uint16_t * OpcodesS,const uint16_t * OpcodesU)2762480093f4SDimitry Andric void ARMDAGToDAGISel::SelectMVE_VMLLDAV(SDNode *N, bool Predicated,
2763480093f4SDimitry Andric                                         const uint16_t *OpcodesS,
2764480093f4SDimitry Andric                                         const uint16_t *OpcodesU) {
2765480093f4SDimitry Andric   EVT VecTy = N->getOperand(6).getValueType();
2766480093f4SDimitry Andric   size_t SizeIndex;
2767480093f4SDimitry Andric   switch (VecTy.getVectorElementType().getSizeInBits()) {
2768480093f4SDimitry Andric   case 16:
2769480093f4SDimitry Andric     SizeIndex = 0;
2770480093f4SDimitry Andric     break;
2771480093f4SDimitry Andric   case 32:
2772480093f4SDimitry Andric     SizeIndex = 1;
2773480093f4SDimitry Andric     break;
2774480093f4SDimitry Andric   default:
2775480093f4SDimitry Andric     llvm_unreachable("bad vector element size");
2776480093f4SDimitry Andric   }
2777480093f4SDimitry Andric 
2778480093f4SDimitry Andric   SelectBaseMVE_VMLLDAV(N, Predicated, OpcodesS, OpcodesU, 2, SizeIndex);
2779480093f4SDimitry Andric }
2780480093f4SDimitry Andric 
SelectMVE_VRMLLDAVH(SDNode * N,bool Predicated,const uint16_t * OpcodesS,const uint16_t * OpcodesU)2781480093f4SDimitry Andric void ARMDAGToDAGISel::SelectMVE_VRMLLDAVH(SDNode *N, bool Predicated,
2782480093f4SDimitry Andric                                           const uint16_t *OpcodesS,
2783480093f4SDimitry Andric                                           const uint16_t *OpcodesU) {
2784480093f4SDimitry Andric   assert(
2785480093f4SDimitry Andric       N->getOperand(6).getValueType().getVectorElementType().getSizeInBits() ==
2786480093f4SDimitry Andric           32 &&
2787480093f4SDimitry Andric       "bad vector element size");
2788480093f4SDimitry Andric   SelectBaseMVE_VMLLDAV(N, Predicated, OpcodesS, OpcodesU, 1, 0);
2789480093f4SDimitry Andric }
2790480093f4SDimitry Andric 
SelectMVE_VLD(SDNode * N,unsigned NumVecs,const uint16_t * const * Opcodes,bool HasWriteback)2791480093f4SDimitry Andric void ARMDAGToDAGISel::SelectMVE_VLD(SDNode *N, unsigned NumVecs,
27925ffd83dbSDimitry Andric                                     const uint16_t *const *Opcodes,
27935ffd83dbSDimitry Andric                                     bool HasWriteback) {
2794480093f4SDimitry Andric   EVT VT = N->getValueType(0);
2795480093f4SDimitry Andric   SDLoc Loc(N);
2796480093f4SDimitry Andric 
2797480093f4SDimitry Andric   const uint16_t *OurOpcodes;
2798480093f4SDimitry Andric   switch (VT.getVectorElementType().getSizeInBits()) {
2799480093f4SDimitry Andric   case 8:
2800480093f4SDimitry Andric     OurOpcodes = Opcodes[0];
2801480093f4SDimitry Andric     break;
2802480093f4SDimitry Andric   case 16:
2803480093f4SDimitry Andric     OurOpcodes = Opcodes[1];
2804480093f4SDimitry Andric     break;
2805480093f4SDimitry Andric   case 32:
2806480093f4SDimitry Andric     OurOpcodes = Opcodes[2];
2807480093f4SDimitry Andric     break;
2808480093f4SDimitry Andric   default:
2809480093f4SDimitry Andric     llvm_unreachable("bad vector element size in SelectMVE_VLD");
2810480093f4SDimitry Andric   }
2811480093f4SDimitry Andric 
2812480093f4SDimitry Andric   EVT DataTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, NumVecs * 2);
28135ffd83dbSDimitry Andric   SmallVector<EVT, 4> ResultTys = {DataTy, MVT::Other};
28145ffd83dbSDimitry Andric   unsigned PtrOperand = HasWriteback ? 1 : 2;
2815480093f4SDimitry Andric 
2816480093f4SDimitry Andric   auto Data = SDValue(
2817480093f4SDimitry Andric       CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, Loc, DataTy), 0);
2818480093f4SDimitry Andric   SDValue Chain = N->getOperand(0);
28195ffd83dbSDimitry Andric   // Add a MVE_VLDn instruction for each Vec, except the last
28205ffd83dbSDimitry Andric   for (unsigned Stage = 0; Stage < NumVecs - 1; ++Stage) {
28215ffd83dbSDimitry Andric     SDValue Ops[] = {Data, N->getOperand(PtrOperand), Chain};
2822480093f4SDimitry Andric     auto LoadInst =
2823480093f4SDimitry Andric         CurDAG->getMachineNode(OurOpcodes[Stage], Loc, ResultTys, Ops);
2824480093f4SDimitry Andric     Data = SDValue(LoadInst, 0);
2825480093f4SDimitry Andric     Chain = SDValue(LoadInst, 1);
2826fe6060f1SDimitry Andric     transferMemOperands(N, LoadInst);
2827480093f4SDimitry Andric   }
28285ffd83dbSDimitry Andric   // The last may need a writeback on it
28295ffd83dbSDimitry Andric   if (HasWriteback)
28305ffd83dbSDimitry Andric     ResultTys = {DataTy, MVT::i32, MVT::Other};
28315ffd83dbSDimitry Andric   SDValue Ops[] = {Data, N->getOperand(PtrOperand), Chain};
28325ffd83dbSDimitry Andric   auto LoadInst =
28335ffd83dbSDimitry Andric       CurDAG->getMachineNode(OurOpcodes[NumVecs - 1], Loc, ResultTys, Ops);
2834fe6060f1SDimitry Andric   transferMemOperands(N, LoadInst);
2835480093f4SDimitry Andric 
28365ffd83dbSDimitry Andric   unsigned i;
28375ffd83dbSDimitry Andric   for (i = 0; i < NumVecs; i++)
2838480093f4SDimitry Andric     ReplaceUses(SDValue(N, i),
28395ffd83dbSDimitry Andric                 CurDAG->getTargetExtractSubreg(ARM::qsub_0 + i, Loc, VT,
28405ffd83dbSDimitry Andric                                                SDValue(LoadInst, 0)));
28415ffd83dbSDimitry Andric   if (HasWriteback)
28425ffd83dbSDimitry Andric     ReplaceUses(SDValue(N, i++), SDValue(LoadInst, 1));
28435ffd83dbSDimitry Andric   ReplaceUses(SDValue(N, i), SDValue(LoadInst, HasWriteback ? 2 : 1));
28445ffd83dbSDimitry Andric   CurDAG->RemoveDeadNode(N);
28455ffd83dbSDimitry Andric }
28465ffd83dbSDimitry Andric 
SelectMVE_VxDUP(SDNode * N,const uint16_t * Opcodes,bool Wrapping,bool Predicated)28475ffd83dbSDimitry Andric void ARMDAGToDAGISel::SelectMVE_VxDUP(SDNode *N, const uint16_t *Opcodes,
28485ffd83dbSDimitry Andric                                       bool Wrapping, bool Predicated) {
28495ffd83dbSDimitry Andric   EVT VT = N->getValueType(0);
28505ffd83dbSDimitry Andric   SDLoc Loc(N);
28515ffd83dbSDimitry Andric 
28525ffd83dbSDimitry Andric   uint16_t Opcode;
28535ffd83dbSDimitry Andric   switch (VT.getScalarSizeInBits()) {
28545ffd83dbSDimitry Andric   case 8:
28555ffd83dbSDimitry Andric     Opcode = Opcodes[0];
28565ffd83dbSDimitry Andric     break;
28575ffd83dbSDimitry Andric   case 16:
28585ffd83dbSDimitry Andric     Opcode = Opcodes[1];
28595ffd83dbSDimitry Andric     break;
28605ffd83dbSDimitry Andric   case 32:
28615ffd83dbSDimitry Andric     Opcode = Opcodes[2];
28625ffd83dbSDimitry Andric     break;
28635ffd83dbSDimitry Andric   default:
28645ffd83dbSDimitry Andric     llvm_unreachable("bad vector element size in SelectMVE_VxDUP");
28655ffd83dbSDimitry Andric   }
28665ffd83dbSDimitry Andric 
28675ffd83dbSDimitry Andric   SmallVector<SDValue, 8> Ops;
28685ffd83dbSDimitry Andric   unsigned OpIdx = 1;
28695ffd83dbSDimitry Andric 
28705ffd83dbSDimitry Andric   SDValue Inactive;
28715ffd83dbSDimitry Andric   if (Predicated)
28725ffd83dbSDimitry Andric     Inactive = N->getOperand(OpIdx++);
28735ffd83dbSDimitry Andric 
28745ffd83dbSDimitry Andric   Ops.push_back(N->getOperand(OpIdx++));     // base
28755ffd83dbSDimitry Andric   if (Wrapping)
28765ffd83dbSDimitry Andric     Ops.push_back(N->getOperand(OpIdx++));   // limit
28775ffd83dbSDimitry Andric 
28785ffd83dbSDimitry Andric   SDValue ImmOp = N->getOperand(OpIdx++);    // step
28791db9f3b2SDimitry Andric   int ImmValue = ImmOp->getAsZExtVal();
28805ffd83dbSDimitry Andric   Ops.push_back(getI32Imm(ImmValue, Loc));
28815ffd83dbSDimitry Andric 
28825ffd83dbSDimitry Andric   if (Predicated)
28835ffd83dbSDimitry Andric     AddMVEPredicateToOps(Ops, Loc, N->getOperand(OpIdx), Inactive);
28845ffd83dbSDimitry Andric   else
28855ffd83dbSDimitry Andric     AddEmptyMVEPredicateToOps(Ops, Loc, N->getValueType(0));
28865ffd83dbSDimitry Andric 
2887bdd1243dSDimitry Andric   CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), ArrayRef(Ops));
28885ffd83dbSDimitry Andric }
28895ffd83dbSDimitry Andric 
SelectCDE_CXxD(SDNode * N,uint16_t Opcode,size_t NumExtraOps,bool HasAccum)28905ffd83dbSDimitry Andric void ARMDAGToDAGISel::SelectCDE_CXxD(SDNode *N, uint16_t Opcode,
28915ffd83dbSDimitry Andric                                      size_t NumExtraOps, bool HasAccum) {
28925ffd83dbSDimitry Andric   bool IsBigEndian = CurDAG->getDataLayout().isBigEndian();
28935ffd83dbSDimitry Andric   SDLoc Loc(N);
28945ffd83dbSDimitry Andric   SmallVector<SDValue, 8> Ops;
28955ffd83dbSDimitry Andric 
28965ffd83dbSDimitry Andric   unsigned OpIdx = 1;
28975ffd83dbSDimitry Andric 
28985ffd83dbSDimitry Andric   // Convert and append the immediate operand designating the coprocessor.
28995ffd83dbSDimitry Andric   SDValue ImmCorpoc = N->getOperand(OpIdx++);
29001db9f3b2SDimitry Andric   uint32_t ImmCoprocVal = ImmCorpoc->getAsZExtVal();
29015ffd83dbSDimitry Andric   Ops.push_back(getI32Imm(ImmCoprocVal, Loc));
29025ffd83dbSDimitry Andric 
29035ffd83dbSDimitry Andric   // For accumulating variants copy the low and high order parts of the
29045ffd83dbSDimitry Andric   // accumulator into a register pair and add it to the operand vector.
29055ffd83dbSDimitry Andric   if (HasAccum) {
29065ffd83dbSDimitry Andric     SDValue AccLo = N->getOperand(OpIdx++);
29075ffd83dbSDimitry Andric     SDValue AccHi = N->getOperand(OpIdx++);
29085ffd83dbSDimitry Andric     if (IsBigEndian)
29095ffd83dbSDimitry Andric       std::swap(AccLo, AccHi);
29105ffd83dbSDimitry Andric     Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, AccLo, AccHi), 0));
29115ffd83dbSDimitry Andric   }
29125ffd83dbSDimitry Andric 
29135ffd83dbSDimitry Andric   // Copy extra operands as-is.
29145ffd83dbSDimitry Andric   for (size_t I = 0; I < NumExtraOps; I++)
29155ffd83dbSDimitry Andric     Ops.push_back(N->getOperand(OpIdx++));
29165ffd83dbSDimitry Andric 
29175ffd83dbSDimitry Andric   // Convert and append the immediate operand
29185ffd83dbSDimitry Andric   SDValue Imm = N->getOperand(OpIdx);
29191db9f3b2SDimitry Andric   uint32_t ImmVal = Imm->getAsZExtVal();
29205ffd83dbSDimitry Andric   Ops.push_back(getI32Imm(ImmVal, Loc));
29215ffd83dbSDimitry Andric 
29225ffd83dbSDimitry Andric   // Accumulating variants are IT-predicable, add predicate operands.
29235ffd83dbSDimitry Andric   if (HasAccum) {
29245ffd83dbSDimitry Andric     SDValue Pred = getAL(CurDAG, Loc);
29255ffd83dbSDimitry Andric     SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
29265ffd83dbSDimitry Andric     Ops.push_back(Pred);
29275ffd83dbSDimitry Andric     Ops.push_back(PredReg);
29285ffd83dbSDimitry Andric   }
29295ffd83dbSDimitry Andric 
29305ffd83dbSDimitry Andric   // Create the CDE intruction
29315ffd83dbSDimitry Andric   SDNode *InstrNode = CurDAG->getMachineNode(Opcode, Loc, MVT::Untyped, Ops);
29325ffd83dbSDimitry Andric   SDValue ResultPair = SDValue(InstrNode, 0);
29335ffd83dbSDimitry Andric 
29345ffd83dbSDimitry Andric   // The original intrinsic had two outputs, and the output of the dual-register
29355ffd83dbSDimitry Andric   // CDE instruction is a register pair. We need to extract the two subregisters
29365ffd83dbSDimitry Andric   // and replace all uses of the original outputs with the extracted
29375ffd83dbSDimitry Andric   // subregisters.
29385ffd83dbSDimitry Andric   uint16_t SubRegs[2] = {ARM::gsub_0, ARM::gsub_1};
29395ffd83dbSDimitry Andric   if (IsBigEndian)
29405ffd83dbSDimitry Andric     std::swap(SubRegs[0], SubRegs[1]);
29415ffd83dbSDimitry Andric 
29425ffd83dbSDimitry Andric   for (size_t ResIdx = 0; ResIdx < 2; ResIdx++) {
29435ffd83dbSDimitry Andric     if (SDValue(N, ResIdx).use_empty())
29445ffd83dbSDimitry Andric       continue;
29455ffd83dbSDimitry Andric     SDValue SubReg = CurDAG->getTargetExtractSubreg(SubRegs[ResIdx], Loc,
29465ffd83dbSDimitry Andric                                                     MVT::i32, ResultPair);
29475ffd83dbSDimitry Andric     ReplaceUses(SDValue(N, ResIdx), SubReg);
29485ffd83dbSDimitry Andric   }
29495ffd83dbSDimitry Andric 
2950480093f4SDimitry Andric   CurDAG->RemoveDeadNode(N);
2951480093f4SDimitry Andric }
2952480093f4SDimitry Andric 
SelectVLDDup(SDNode * N,bool IsIntrinsic,bool isUpdating,unsigned NumVecs,const uint16_t * DOpcodes,const uint16_t * QOpcodes0,const uint16_t * QOpcodes1)29530b57cec5SDimitry Andric void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool IsIntrinsic,
29540b57cec5SDimitry Andric                                    bool isUpdating, unsigned NumVecs,
29550b57cec5SDimitry Andric                                    const uint16_t *DOpcodes,
29560b57cec5SDimitry Andric                                    const uint16_t *QOpcodes0,
29570b57cec5SDimitry Andric                                    const uint16_t *QOpcodes1) {
29585ffd83dbSDimitry Andric   assert(Subtarget->hasNEON());
29590b57cec5SDimitry Andric   assert(NumVecs >= 1 && NumVecs <= 4 && "VLDDup NumVecs out-of-range");
29600b57cec5SDimitry Andric   SDLoc dl(N);
29610b57cec5SDimitry Andric 
29620b57cec5SDimitry Andric   SDValue MemAddr, Align;
29630b57cec5SDimitry Andric   unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
29640b57cec5SDimitry Andric   if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
29650b57cec5SDimitry Andric     return;
29660b57cec5SDimitry Andric 
29670b57cec5SDimitry Andric   SDValue Chain = N->getOperand(0);
29680b57cec5SDimitry Andric   EVT VT = N->getValueType(0);
29690b57cec5SDimitry Andric   bool is64BitVector = VT.is64BitVector();
29700b57cec5SDimitry Andric 
29710b57cec5SDimitry Andric   unsigned Alignment = 0;
29720b57cec5SDimitry Andric   if (NumVecs != 3) {
29731db9f3b2SDimitry Andric     Alignment = Align->getAsZExtVal();
29740b57cec5SDimitry Andric     unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
29750b57cec5SDimitry Andric     if (Alignment > NumBytes)
29760b57cec5SDimitry Andric       Alignment = NumBytes;
29770b57cec5SDimitry Andric     if (Alignment < 8 && Alignment < NumBytes)
29780b57cec5SDimitry Andric       Alignment = 0;
29790b57cec5SDimitry Andric     // Alignment must be a power of two; make sure of that.
29800b57cec5SDimitry Andric     Alignment = (Alignment & -Alignment);
29810b57cec5SDimitry Andric     if (Alignment == 1)
29820b57cec5SDimitry Andric       Alignment = 0;
29830b57cec5SDimitry Andric   }
29840b57cec5SDimitry Andric   Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
29850b57cec5SDimitry Andric 
29860b57cec5SDimitry Andric   unsigned OpcodeIndex;
29870b57cec5SDimitry Andric   switch (VT.getSimpleVT().SimpleTy) {
29880b57cec5SDimitry Andric   default: llvm_unreachable("unhandled vld-dup type");
29890b57cec5SDimitry Andric   case MVT::v8i8:
29900b57cec5SDimitry Andric   case MVT::v16i8: OpcodeIndex = 0; break;
29910b57cec5SDimitry Andric   case MVT::v4i16:
29920b57cec5SDimitry Andric   case MVT::v8i16:
29930b57cec5SDimitry Andric   case MVT::v4f16:
29940b57cec5SDimitry Andric   case MVT::v8f16:
29955ffd83dbSDimitry Andric   case MVT::v4bf16:
29965ffd83dbSDimitry Andric   case MVT::v8bf16:
29970b57cec5SDimitry Andric                   OpcodeIndex = 1; break;
29980b57cec5SDimitry Andric   case MVT::v2f32:
29990b57cec5SDimitry Andric   case MVT::v2i32:
30000b57cec5SDimitry Andric   case MVT::v4f32:
30010b57cec5SDimitry Andric   case MVT::v4i32: OpcodeIndex = 2; break;
30020b57cec5SDimitry Andric   case MVT::v1f64:
30030b57cec5SDimitry Andric   case MVT::v1i64: OpcodeIndex = 3; break;
30040b57cec5SDimitry Andric   }
30050b57cec5SDimitry Andric 
30060b57cec5SDimitry Andric   unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
30070b57cec5SDimitry Andric   if (!is64BitVector)
30080b57cec5SDimitry Andric     ResTyElts *= 2;
30090b57cec5SDimitry Andric   EVT ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts);
30100b57cec5SDimitry Andric 
30110b57cec5SDimitry Andric   std::vector<EVT> ResTys;
30120b57cec5SDimitry Andric   ResTys.push_back(ResTy);
30130b57cec5SDimitry Andric   if (isUpdating)
30140b57cec5SDimitry Andric     ResTys.push_back(MVT::i32);
30150b57cec5SDimitry Andric   ResTys.push_back(MVT::Other);
30160b57cec5SDimitry Andric 
30170b57cec5SDimitry Andric   SDValue Pred = getAL(CurDAG, dl);
30180b57cec5SDimitry Andric   SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
30190b57cec5SDimitry Andric 
30200b57cec5SDimitry Andric   SmallVector<SDValue, 6> Ops;
30210b57cec5SDimitry Andric   Ops.push_back(MemAddr);
30220b57cec5SDimitry Andric   Ops.push_back(Align);
3023fe6060f1SDimitry Andric   unsigned Opc = is64BitVector    ? DOpcodes[OpcodeIndex]
3024fe6060f1SDimitry Andric                  : (NumVecs == 1) ? QOpcodes0[OpcodeIndex]
3025fe6060f1SDimitry Andric                                   : QOpcodes1[OpcodeIndex];
30260b57cec5SDimitry Andric   if (isUpdating) {
30270b57cec5SDimitry Andric     SDValue Inc = N->getOperand(2);
30280b57cec5SDimitry Andric     bool IsImmUpdate =
30290b57cec5SDimitry Andric         isPerfectIncrement(Inc, VT.getVectorElementType(), NumVecs);
3030fe6060f1SDimitry Andric     if (IsImmUpdate) {
3031fe6060f1SDimitry Andric       if (!isVLDfixed(Opc))
30320b57cec5SDimitry Andric         Ops.push_back(Reg0);
3033fe6060f1SDimitry Andric     } else {
3034fe6060f1SDimitry Andric       if (isVLDfixed(Opc))
3035fe6060f1SDimitry Andric         Opc = getVLDSTRegisterUpdateOpcode(Opc);
3036fe6060f1SDimitry Andric       Ops.push_back(Inc);
30370b57cec5SDimitry Andric     }
3038fe6060f1SDimitry Andric   }
3039fe6060f1SDimitry Andric   if (is64BitVector || NumVecs == 1) {
3040fe6060f1SDimitry Andric     // Double registers and VLD1 quad registers are directly supported.
3041fe6060f1SDimitry Andric   } else {
3042fe6060f1SDimitry Andric     SDValue ImplDef = SDValue(
3043fe6060f1SDimitry Andric         CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0);
3044fe6060f1SDimitry Andric     const SDValue OpsA[] = {MemAddr, Align, ImplDef, Pred, Reg0, Chain};
3045fe6060f1SDimitry Andric     SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl, ResTy,
3046fe6060f1SDimitry Andric                                           MVT::Other, OpsA);
3047fe6060f1SDimitry Andric     Ops.push_back(SDValue(VLdA, 0));
3048fe6060f1SDimitry Andric     Chain = SDValue(VLdA, 1);
3049fe6060f1SDimitry Andric   }
3050fe6060f1SDimitry Andric 
30510b57cec5SDimitry Andric   Ops.push_back(Pred);
30520b57cec5SDimitry Andric   Ops.push_back(Reg0);
30530b57cec5SDimitry Andric   Ops.push_back(Chain);
30540b57cec5SDimitry Andric 
3055fe6060f1SDimitry Andric   SDNode *VLdDup = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
30560b57cec5SDimitry Andric 
30570b57cec5SDimitry Andric   // Transfer memoperands.
30580b57cec5SDimitry Andric   MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
30590b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(VLdDup), {MemOp});
30600b57cec5SDimitry Andric 
30610b57cec5SDimitry Andric   // Extract the subregisters.
30620b57cec5SDimitry Andric   if (NumVecs == 1) {
30630b57cec5SDimitry Andric     ReplaceUses(SDValue(N, 0), SDValue(VLdDup, 0));
30640b57cec5SDimitry Andric   } else {
30650b57cec5SDimitry Andric     SDValue SuperReg = SDValue(VLdDup, 0);
30660b57cec5SDimitry Andric     static_assert(ARM::dsub_7 == ARM::dsub_0 + 7, "Unexpected subreg numbering");
30670b57cec5SDimitry Andric     unsigned SubIdx = is64BitVector ? ARM::dsub_0 : ARM::qsub_0;
30680b57cec5SDimitry Andric     for (unsigned Vec = 0; Vec != NumVecs; ++Vec) {
30690b57cec5SDimitry Andric       ReplaceUses(SDValue(N, Vec),
30700b57cec5SDimitry Andric                   CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg));
30710b57cec5SDimitry Andric     }
30720b57cec5SDimitry Andric   }
30730b57cec5SDimitry Andric   ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1));
30740b57cec5SDimitry Andric   if (isUpdating)
30750b57cec5SDimitry Andric     ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdDup, 2));
30760b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
30770b57cec5SDimitry Andric }
30780b57cec5SDimitry Andric 
tryInsertVectorElt(SDNode * N)3079fe6060f1SDimitry Andric bool ARMDAGToDAGISel::tryInsertVectorElt(SDNode *N) {
3080fe6060f1SDimitry Andric   if (!Subtarget->hasMVEIntegerOps())
3081fe6060f1SDimitry Andric     return false;
3082fe6060f1SDimitry Andric 
3083fe6060f1SDimitry Andric   SDLoc dl(N);
3084fe6060f1SDimitry Andric 
3085fe6060f1SDimitry Andric   // We are trying to use VMOV/VMOVX/VINS to more efficiently lower insert and
3086fe6060f1SDimitry Andric   // extracts of v8f16 and v8i16 vectors. Check that we have two adjacent
3087fe6060f1SDimitry Andric   // inserts of the correct type:
3088fe6060f1SDimitry Andric   SDValue Ins1 = SDValue(N, 0);
3089fe6060f1SDimitry Andric   SDValue Ins2 = N->getOperand(0);
3090fe6060f1SDimitry Andric   EVT VT = Ins1.getValueType();
3091fe6060f1SDimitry Andric   if (Ins2.getOpcode() != ISD::INSERT_VECTOR_ELT || !Ins2.hasOneUse() ||
3092fe6060f1SDimitry Andric       !isa<ConstantSDNode>(Ins1.getOperand(2)) ||
3093fe6060f1SDimitry Andric       !isa<ConstantSDNode>(Ins2.getOperand(2)) ||
3094fe6060f1SDimitry Andric       (VT != MVT::v8f16 && VT != MVT::v8i16) || (Ins2.getValueType() != VT))
3095fe6060f1SDimitry Andric     return false;
3096fe6060f1SDimitry Andric 
3097fe6060f1SDimitry Andric   unsigned Lane1 = Ins1.getConstantOperandVal(2);
3098fe6060f1SDimitry Andric   unsigned Lane2 = Ins2.getConstantOperandVal(2);
3099fe6060f1SDimitry Andric   if (Lane2 % 2 != 0 || Lane1 != Lane2 + 1)
3100fe6060f1SDimitry Andric     return false;
3101fe6060f1SDimitry Andric 
3102fe6060f1SDimitry Andric   // If the inserted values will be able to use T/B already, leave it to the
3103fe6060f1SDimitry Andric   // existing tablegen patterns. For example VCVTT/VCVTB.
3104fe6060f1SDimitry Andric   SDValue Val1 = Ins1.getOperand(1);
3105fe6060f1SDimitry Andric   SDValue Val2 = Ins2.getOperand(1);
3106fe6060f1SDimitry Andric   if (Val1.getOpcode() == ISD::FP_ROUND || Val2.getOpcode() == ISD::FP_ROUND)
3107fe6060f1SDimitry Andric     return false;
3108fe6060f1SDimitry Andric 
3109fe6060f1SDimitry Andric   // Check if the inserted values are both extracts.
3110fe6060f1SDimitry Andric   if ((Val1.getOpcode() == ISD::EXTRACT_VECTOR_ELT ||
3111fe6060f1SDimitry Andric        Val1.getOpcode() == ARMISD::VGETLANEu) &&
3112fe6060f1SDimitry Andric       (Val2.getOpcode() == ISD::EXTRACT_VECTOR_ELT ||
3113fe6060f1SDimitry Andric        Val2.getOpcode() == ARMISD::VGETLANEu) &&
3114fe6060f1SDimitry Andric       isa<ConstantSDNode>(Val1.getOperand(1)) &&
3115fe6060f1SDimitry Andric       isa<ConstantSDNode>(Val2.getOperand(1)) &&
3116fe6060f1SDimitry Andric       (Val1.getOperand(0).getValueType() == MVT::v8f16 ||
3117fe6060f1SDimitry Andric        Val1.getOperand(0).getValueType() == MVT::v8i16) &&
3118fe6060f1SDimitry Andric       (Val2.getOperand(0).getValueType() == MVT::v8f16 ||
3119fe6060f1SDimitry Andric        Val2.getOperand(0).getValueType() == MVT::v8i16)) {
3120fe6060f1SDimitry Andric     unsigned ExtractLane1 = Val1.getConstantOperandVal(1);
3121fe6060f1SDimitry Andric     unsigned ExtractLane2 = Val2.getConstantOperandVal(1);
3122fe6060f1SDimitry Andric 
3123fe6060f1SDimitry Andric     // If the two extracted lanes are from the same place and adjacent, this
3124fe6060f1SDimitry Andric     // simplifies into a f32 lane move.
3125fe6060f1SDimitry Andric     if (Val1.getOperand(0) == Val2.getOperand(0) && ExtractLane2 % 2 == 0 &&
3126fe6060f1SDimitry Andric         ExtractLane1 == ExtractLane2 + 1) {
3127fe6060f1SDimitry Andric       SDValue NewExt = CurDAG->getTargetExtractSubreg(
3128fe6060f1SDimitry Andric           ARM::ssub_0 + ExtractLane2 / 2, dl, MVT::f32, Val1.getOperand(0));
3129fe6060f1SDimitry Andric       SDValue NewIns = CurDAG->getTargetInsertSubreg(
3130fe6060f1SDimitry Andric           ARM::ssub_0 + Lane2 / 2, dl, VT, Ins2.getOperand(0),
3131fe6060f1SDimitry Andric           NewExt);
3132fe6060f1SDimitry Andric       ReplaceUses(Ins1, NewIns);
3133fe6060f1SDimitry Andric       return true;
3134fe6060f1SDimitry Andric     }
3135fe6060f1SDimitry Andric 
3136fe6060f1SDimitry Andric     // Else v8i16 pattern of an extract and an insert, with a optional vmovx for
3137fe6060f1SDimitry Andric     // extracting odd lanes.
3138fcaf7f86SDimitry Andric     if (VT == MVT::v8i16 && Subtarget->hasFullFP16()) {
3139fe6060f1SDimitry Andric       SDValue Inp1 = CurDAG->getTargetExtractSubreg(
3140fe6060f1SDimitry Andric           ARM::ssub_0 + ExtractLane1 / 2, dl, MVT::f32, Val1.getOperand(0));
3141fe6060f1SDimitry Andric       SDValue Inp2 = CurDAG->getTargetExtractSubreg(
3142fe6060f1SDimitry Andric           ARM::ssub_0 + ExtractLane2 / 2, dl, MVT::f32, Val2.getOperand(0));
3143fe6060f1SDimitry Andric       if (ExtractLane1 % 2 != 0)
3144fe6060f1SDimitry Andric         Inp1 = SDValue(CurDAG->getMachineNode(ARM::VMOVH, dl, MVT::f32, Inp1), 0);
3145fe6060f1SDimitry Andric       if (ExtractLane2 % 2 != 0)
3146fe6060f1SDimitry Andric         Inp2 = SDValue(CurDAG->getMachineNode(ARM::VMOVH, dl, MVT::f32, Inp2), 0);
3147fe6060f1SDimitry Andric       SDNode *VINS = CurDAG->getMachineNode(ARM::VINSH, dl, MVT::f32, Inp2, Inp1);
3148fe6060f1SDimitry Andric       SDValue NewIns =
3149fe6060f1SDimitry Andric           CurDAG->getTargetInsertSubreg(ARM::ssub_0 + Lane2 / 2, dl, MVT::v4f32,
3150fe6060f1SDimitry Andric                                         Ins2.getOperand(0), SDValue(VINS, 0));
3151fe6060f1SDimitry Andric       ReplaceUses(Ins1, NewIns);
3152fe6060f1SDimitry Andric       return true;
3153fe6060f1SDimitry Andric     }
3154fe6060f1SDimitry Andric   }
3155fe6060f1SDimitry Andric 
3156fe6060f1SDimitry Andric   // The inserted values are not extracted - if they are f16 then insert them
3157fe6060f1SDimitry Andric   // directly using a VINS.
3158fcaf7f86SDimitry Andric   if (VT == MVT::v8f16 && Subtarget->hasFullFP16()) {
3159fe6060f1SDimitry Andric     SDNode *VINS = CurDAG->getMachineNode(ARM::VINSH, dl, MVT::f32, Val2, Val1);
3160fe6060f1SDimitry Andric     SDValue NewIns =
3161fe6060f1SDimitry Andric         CurDAG->getTargetInsertSubreg(ARM::ssub_0 + Lane2 / 2, dl, MVT::v4f32,
3162fe6060f1SDimitry Andric                                       Ins2.getOperand(0), SDValue(VINS, 0));
3163fe6060f1SDimitry Andric     ReplaceUses(Ins1, NewIns);
3164fe6060f1SDimitry Andric     return true;
3165fe6060f1SDimitry Andric   }
3166fe6060f1SDimitry Andric 
3167fe6060f1SDimitry Andric   return false;
3168fe6060f1SDimitry Andric }
3169fe6060f1SDimitry Andric 
transformFixedFloatingPointConversion(SDNode * N,SDNode * FMul,bool IsUnsigned,bool FixedToFloat)3170fe6060f1SDimitry Andric bool ARMDAGToDAGISel::transformFixedFloatingPointConversion(SDNode *N,
3171fe6060f1SDimitry Andric                                                             SDNode *FMul,
3172fe6060f1SDimitry Andric                                                             bool IsUnsigned,
3173fe6060f1SDimitry Andric                                                             bool FixedToFloat) {
3174fe6060f1SDimitry Andric   auto Type = N->getValueType(0);
3175fe6060f1SDimitry Andric   unsigned ScalarBits = Type.getScalarSizeInBits();
3176fe6060f1SDimitry Andric   if (ScalarBits > 32)
3177fe6060f1SDimitry Andric     return false;
3178fe6060f1SDimitry Andric 
3179fe6060f1SDimitry Andric   SDNodeFlags FMulFlags = FMul->getFlags();
3180fe6060f1SDimitry Andric   // The fixed-point vcvt and vcvt+vmul are not always equivalent if inf is
3181fe6060f1SDimitry Andric   // allowed in 16 bit unsigned floats
3182fe6060f1SDimitry Andric   if (ScalarBits == 16 && !FMulFlags.hasNoInfs() && IsUnsigned)
3183fe6060f1SDimitry Andric     return false;
3184fe6060f1SDimitry Andric 
3185fe6060f1SDimitry Andric   SDValue ImmNode = FMul->getOperand(1);
3186fe6060f1SDimitry Andric   SDValue VecVal = FMul->getOperand(0);
3187fe6060f1SDimitry Andric   if (VecVal->getOpcode() == ISD::UINT_TO_FP ||
3188fe6060f1SDimitry Andric       VecVal->getOpcode() == ISD::SINT_TO_FP)
3189fe6060f1SDimitry Andric     VecVal = VecVal->getOperand(0);
3190fe6060f1SDimitry Andric 
3191fe6060f1SDimitry Andric   if (VecVal.getValueType().getScalarSizeInBits() != ScalarBits)
3192fe6060f1SDimitry Andric     return false;
3193fe6060f1SDimitry Andric 
3194fe6060f1SDimitry Andric   if (ImmNode.getOpcode() == ISD::BITCAST) {
3195fe6060f1SDimitry Andric     if (ImmNode.getValueType().getScalarSizeInBits() != ScalarBits)
3196fe6060f1SDimitry Andric       return false;
3197fe6060f1SDimitry Andric     ImmNode = ImmNode.getOperand(0);
3198fe6060f1SDimitry Andric   }
3199fe6060f1SDimitry Andric 
3200fe6060f1SDimitry Andric   if (ImmNode.getValueType().getScalarSizeInBits() != ScalarBits)
3201fe6060f1SDimitry Andric     return false;
3202fe6060f1SDimitry Andric 
3203fe6060f1SDimitry Andric   APFloat ImmAPF(0.0f);
3204fe6060f1SDimitry Andric   switch (ImmNode.getOpcode()) {
3205fe6060f1SDimitry Andric   case ARMISD::VMOVIMM:
3206fe6060f1SDimitry Andric   case ARMISD::VDUP: {
3207fe6060f1SDimitry Andric     if (!isa<ConstantSDNode>(ImmNode.getOperand(0)))
3208fe6060f1SDimitry Andric       return false;
3209fe6060f1SDimitry Andric     unsigned Imm = ImmNode.getConstantOperandVal(0);
3210fe6060f1SDimitry Andric     if (ImmNode.getOpcode() == ARMISD::VMOVIMM)
3211fe6060f1SDimitry Andric       Imm = ARM_AM::decodeVMOVModImm(Imm, ScalarBits);
3212fe6060f1SDimitry Andric     ImmAPF =
3213fe6060f1SDimitry Andric         APFloat(ScalarBits == 32 ? APFloat::IEEEsingle() : APFloat::IEEEhalf(),
3214fe6060f1SDimitry Andric                 APInt(ScalarBits, Imm));
3215fe6060f1SDimitry Andric     break;
3216fe6060f1SDimitry Andric   }
3217fe6060f1SDimitry Andric   case ARMISD::VMOVFPIMM: {
3218fe6060f1SDimitry Andric     ImmAPF = APFloat(ARM_AM::getFPImmFloat(ImmNode.getConstantOperandVal(0)));
3219fe6060f1SDimitry Andric     break;
3220fe6060f1SDimitry Andric   }
3221fe6060f1SDimitry Andric   default:
3222fe6060f1SDimitry Andric     return false;
3223fe6060f1SDimitry Andric   }
3224fe6060f1SDimitry Andric 
3225fe6060f1SDimitry Andric   // Where n is the number of fractional bits, multiplying by 2^n will convert
3226fe6060f1SDimitry Andric   // from float to fixed and multiplying by 2^-n will convert from fixed to
3227fe6060f1SDimitry Andric   // float. Taking log2 of the factor (after taking the inverse in the case of
3228fe6060f1SDimitry Andric   // float to fixed) will give n.
3229fe6060f1SDimitry Andric   APFloat ToConvert = ImmAPF;
3230fe6060f1SDimitry Andric   if (FixedToFloat) {
3231fe6060f1SDimitry Andric     if (!ImmAPF.getExactInverse(&ToConvert))
3232fe6060f1SDimitry Andric       return false;
3233fe6060f1SDimitry Andric   }
323404eeddc0SDimitry Andric   APSInt Converted(64, false);
3235fe6060f1SDimitry Andric   bool IsExact;
3236fe6060f1SDimitry Andric   ToConvert.convertToInteger(Converted, llvm::RoundingMode::NearestTiesToEven,
3237fe6060f1SDimitry Andric                              &IsExact);
3238fe6060f1SDimitry Andric   if (!IsExact || !Converted.isPowerOf2())
3239fe6060f1SDimitry Andric     return false;
3240fe6060f1SDimitry Andric 
3241fe6060f1SDimitry Andric   unsigned FracBits = Converted.logBase2();
3242fe6060f1SDimitry Andric   if (FracBits > ScalarBits)
3243fe6060f1SDimitry Andric     return false;
3244fe6060f1SDimitry Andric 
3245fe6060f1SDimitry Andric   SmallVector<SDValue, 3> Ops{
3246fe6060f1SDimitry Andric       VecVal, CurDAG->getConstant(FracBits, SDLoc(N), MVT::i32)};
3247fe6060f1SDimitry Andric   AddEmptyMVEPredicateToOps(Ops, SDLoc(N), Type);
3248fe6060f1SDimitry Andric 
3249fe6060f1SDimitry Andric   unsigned int Opcode;
3250fe6060f1SDimitry Andric   switch (ScalarBits) {
3251fe6060f1SDimitry Andric   case 16:
3252fe6060f1SDimitry Andric     if (FixedToFloat)
3253fe6060f1SDimitry Andric       Opcode = IsUnsigned ? ARM::MVE_VCVTf16u16_fix : ARM::MVE_VCVTf16s16_fix;
3254fe6060f1SDimitry Andric     else
3255fe6060f1SDimitry Andric       Opcode = IsUnsigned ? ARM::MVE_VCVTu16f16_fix : ARM::MVE_VCVTs16f16_fix;
3256fe6060f1SDimitry Andric     break;
3257fe6060f1SDimitry Andric   case 32:
3258fe6060f1SDimitry Andric     if (FixedToFloat)
3259fe6060f1SDimitry Andric       Opcode = IsUnsigned ? ARM::MVE_VCVTf32u32_fix : ARM::MVE_VCVTf32s32_fix;
3260fe6060f1SDimitry Andric     else
3261fe6060f1SDimitry Andric       Opcode = IsUnsigned ? ARM::MVE_VCVTu32f32_fix : ARM::MVE_VCVTs32f32_fix;
3262fe6060f1SDimitry Andric     break;
3263fe6060f1SDimitry Andric   default:
3264fe6060f1SDimitry Andric     llvm_unreachable("unexpected number of scalar bits");
3265fe6060f1SDimitry Andric     break;
3266fe6060f1SDimitry Andric   }
3267fe6060f1SDimitry Andric 
3268fe6060f1SDimitry Andric   ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), Type, Ops));
3269fe6060f1SDimitry Andric   return true;
3270fe6060f1SDimitry Andric }
3271fe6060f1SDimitry Andric 
tryFP_TO_INT(SDNode * N,SDLoc dl)3272fe6060f1SDimitry Andric bool ARMDAGToDAGISel::tryFP_TO_INT(SDNode *N, SDLoc dl) {
3273fe6060f1SDimitry Andric   // Transform a floating-point to fixed-point conversion to a VCVT
3274fe6060f1SDimitry Andric   if (!Subtarget->hasMVEFloatOps())
3275fe6060f1SDimitry Andric     return false;
3276fe6060f1SDimitry Andric   EVT Type = N->getValueType(0);
3277fe6060f1SDimitry Andric   if (!Type.isVector())
3278fe6060f1SDimitry Andric     return false;
3279fe6060f1SDimitry Andric   unsigned int ScalarBits = Type.getScalarSizeInBits();
3280fe6060f1SDimitry Andric 
32814824e7fdSDimitry Andric   bool IsUnsigned = N->getOpcode() == ISD::FP_TO_UINT ||
32824824e7fdSDimitry Andric                     N->getOpcode() == ISD::FP_TO_UINT_SAT;
3283fe6060f1SDimitry Andric   SDNode *Node = N->getOperand(0).getNode();
3284fe6060f1SDimitry Andric 
3285fe6060f1SDimitry Andric   // floating-point to fixed-point with one fractional bit gets turned into an
3286fe6060f1SDimitry Andric   // FP_TO_[U|S]INT(FADD (x, x)) rather than an FP_TO_[U|S]INT(FMUL (x, y))
3287fe6060f1SDimitry Andric   if (Node->getOpcode() == ISD::FADD) {
3288fe6060f1SDimitry Andric     if (Node->getOperand(0) != Node->getOperand(1))
3289fe6060f1SDimitry Andric       return false;
3290fe6060f1SDimitry Andric     SDNodeFlags Flags = Node->getFlags();
3291fe6060f1SDimitry Andric     // The fixed-point vcvt and vcvt+vmul are not always equivalent if inf is
3292fe6060f1SDimitry Andric     // allowed in 16 bit unsigned floats
3293fe6060f1SDimitry Andric     if (ScalarBits == 16 && !Flags.hasNoInfs() && IsUnsigned)
3294fe6060f1SDimitry Andric       return false;
3295fe6060f1SDimitry Andric 
3296fe6060f1SDimitry Andric     unsigned Opcode;
3297fe6060f1SDimitry Andric     switch (ScalarBits) {
3298fe6060f1SDimitry Andric     case 16:
3299fe6060f1SDimitry Andric       Opcode = IsUnsigned ? ARM::MVE_VCVTu16f16_fix : ARM::MVE_VCVTs16f16_fix;
3300fe6060f1SDimitry Andric       break;
3301fe6060f1SDimitry Andric     case 32:
3302fe6060f1SDimitry Andric       Opcode = IsUnsigned ? ARM::MVE_VCVTu32f32_fix : ARM::MVE_VCVTs32f32_fix;
3303fe6060f1SDimitry Andric       break;
3304fe6060f1SDimitry Andric     }
3305fe6060f1SDimitry Andric     SmallVector<SDValue, 3> Ops{Node->getOperand(0),
3306fe6060f1SDimitry Andric                                 CurDAG->getConstant(1, dl, MVT::i32)};
3307fe6060f1SDimitry Andric     AddEmptyMVEPredicateToOps(Ops, dl, Type);
3308fe6060f1SDimitry Andric 
3309fe6060f1SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opcode, dl, Type, Ops));
3310fe6060f1SDimitry Andric     return true;
3311fe6060f1SDimitry Andric   }
3312fe6060f1SDimitry Andric 
3313fe6060f1SDimitry Andric   if (Node->getOpcode() != ISD::FMUL)
3314fe6060f1SDimitry Andric     return false;
3315fe6060f1SDimitry Andric 
3316fe6060f1SDimitry Andric   return transformFixedFloatingPointConversion(N, Node, IsUnsigned, false);
3317fe6060f1SDimitry Andric }
3318fe6060f1SDimitry Andric 
tryFMULFixed(SDNode * N,SDLoc dl)3319fe6060f1SDimitry Andric bool ARMDAGToDAGISel::tryFMULFixed(SDNode *N, SDLoc dl) {
3320fe6060f1SDimitry Andric   // Transform a fixed-point to floating-point conversion to a VCVT
3321fe6060f1SDimitry Andric   if (!Subtarget->hasMVEFloatOps())
3322fe6060f1SDimitry Andric     return false;
3323fe6060f1SDimitry Andric   auto Type = N->getValueType(0);
3324fe6060f1SDimitry Andric   if (!Type.isVector())
3325fe6060f1SDimitry Andric     return false;
3326fe6060f1SDimitry Andric 
3327fe6060f1SDimitry Andric   auto LHS = N->getOperand(0);
3328fe6060f1SDimitry Andric   if (LHS.getOpcode() != ISD::SINT_TO_FP && LHS.getOpcode() != ISD::UINT_TO_FP)
3329fe6060f1SDimitry Andric     return false;
3330fe6060f1SDimitry Andric 
3331fe6060f1SDimitry Andric   return transformFixedFloatingPointConversion(
3332fe6060f1SDimitry Andric       N, N, LHS.getOpcode() == ISD::UINT_TO_FP, true);
3333fe6060f1SDimitry Andric }
3334fe6060f1SDimitry Andric 
tryV6T2BitfieldExtractOp(SDNode * N,bool isSigned)33350b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
33360b57cec5SDimitry Andric   if (!Subtarget->hasV6T2Ops())
33370b57cec5SDimitry Andric     return false;
33380b57cec5SDimitry Andric 
33390b57cec5SDimitry Andric   unsigned Opc = isSigned
33400b57cec5SDimitry Andric     ? (Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX)
33410b57cec5SDimitry Andric     : (Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX);
33420b57cec5SDimitry Andric   SDLoc dl(N);
33430b57cec5SDimitry Andric 
33440b57cec5SDimitry Andric   // For unsigned extracts, check for a shift right and mask
33450b57cec5SDimitry Andric   unsigned And_imm = 0;
33460b57cec5SDimitry Andric   if (N->getOpcode() == ISD::AND) {
33470b57cec5SDimitry Andric     if (isOpcWithIntImmediate(N, ISD::AND, And_imm)) {
33480b57cec5SDimitry Andric 
33490b57cec5SDimitry Andric       // The immediate is a mask of the low bits iff imm & (imm+1) == 0
33500b57cec5SDimitry Andric       if (And_imm & (And_imm + 1))
33510b57cec5SDimitry Andric         return false;
33520b57cec5SDimitry Andric 
33530b57cec5SDimitry Andric       unsigned Srl_imm = 0;
33540b57cec5SDimitry Andric       if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL,
33550b57cec5SDimitry Andric                                 Srl_imm)) {
33560b57cec5SDimitry Andric         assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
33570b57cec5SDimitry Andric 
33580b57cec5SDimitry Andric         // Mask off the unnecessary bits of the AND immediate; normally
33590b57cec5SDimitry Andric         // DAGCombine will do this, but that might not happen if
33600b57cec5SDimitry Andric         // targetShrinkDemandedConstant chooses a different immediate.
33610b57cec5SDimitry Andric         And_imm &= -1U >> Srl_imm;
33620b57cec5SDimitry Andric 
33630b57cec5SDimitry Andric         // Note: The width operand is encoded as width-1.
336406c3fb27SDimitry Andric         unsigned Width = llvm::countr_one(And_imm) - 1;
33650b57cec5SDimitry Andric         unsigned LSB = Srl_imm;
33660b57cec5SDimitry Andric 
33670b57cec5SDimitry Andric         SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
33680b57cec5SDimitry Andric 
33690b57cec5SDimitry Andric         if ((LSB + Width + 1) == N->getValueType(0).getSizeInBits()) {
33700b57cec5SDimitry Andric           // It's cheaper to use a right shift to extract the top bits.
33710b57cec5SDimitry Andric           if (Subtarget->isThumb()) {
33720b57cec5SDimitry Andric             Opc = isSigned ? ARM::t2ASRri : ARM::t2LSRri;
33730b57cec5SDimitry Andric             SDValue Ops[] = { N->getOperand(0).getOperand(0),
33740b57cec5SDimitry Andric                               CurDAG->getTargetConstant(LSB, dl, MVT::i32),
33750b57cec5SDimitry Andric                               getAL(CurDAG, dl), Reg0, Reg0 };
33760b57cec5SDimitry Andric             CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
33770b57cec5SDimitry Andric             return true;
33780b57cec5SDimitry Andric           }
33790b57cec5SDimitry Andric 
33800b57cec5SDimitry Andric           // ARM models shift instructions as MOVsi with shifter operand.
33810b57cec5SDimitry Andric           ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(ISD::SRL);
33820b57cec5SDimitry Andric           SDValue ShOpc =
33830b57cec5SDimitry Andric             CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, LSB), dl,
33840b57cec5SDimitry Andric                                       MVT::i32);
33850b57cec5SDimitry Andric           SDValue Ops[] = { N->getOperand(0).getOperand(0), ShOpc,
33860b57cec5SDimitry Andric                             getAL(CurDAG, dl), Reg0, Reg0 };
33870b57cec5SDimitry Andric           CurDAG->SelectNodeTo(N, ARM::MOVsi, MVT::i32, Ops);
33880b57cec5SDimitry Andric           return true;
33890b57cec5SDimitry Andric         }
33900b57cec5SDimitry Andric 
33910b57cec5SDimitry Andric         assert(LSB + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
33920b57cec5SDimitry Andric         SDValue Ops[] = { N->getOperand(0).getOperand(0),
33930b57cec5SDimitry Andric                           CurDAG->getTargetConstant(LSB, dl, MVT::i32),
33940b57cec5SDimitry Andric                           CurDAG->getTargetConstant(Width, dl, MVT::i32),
33950b57cec5SDimitry Andric                           getAL(CurDAG, dl), Reg0 };
33960b57cec5SDimitry Andric         CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
33970b57cec5SDimitry Andric         return true;
33980b57cec5SDimitry Andric       }
33990b57cec5SDimitry Andric     }
34000b57cec5SDimitry Andric     return false;
34010b57cec5SDimitry Andric   }
34020b57cec5SDimitry Andric 
34030b57cec5SDimitry Andric   // Otherwise, we're looking for a shift of a shift
34040b57cec5SDimitry Andric   unsigned Shl_imm = 0;
34050b57cec5SDimitry Andric   if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) {
34060b57cec5SDimitry Andric     assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!");
34070b57cec5SDimitry Andric     unsigned Srl_imm = 0;
34080b57cec5SDimitry Andric     if (isInt32Immediate(N->getOperand(1), Srl_imm)) {
34090b57cec5SDimitry Andric       assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
34100b57cec5SDimitry Andric       // Note: The width operand is encoded as width-1.
34110b57cec5SDimitry Andric       unsigned Width = 32 - Srl_imm - 1;
34120b57cec5SDimitry Andric       int LSB = Srl_imm - Shl_imm;
34130b57cec5SDimitry Andric       if (LSB < 0)
34140b57cec5SDimitry Andric         return false;
34150b57cec5SDimitry Andric       SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
34160b57cec5SDimitry Andric       assert(LSB + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
34170b57cec5SDimitry Andric       SDValue Ops[] = { N->getOperand(0).getOperand(0),
34180b57cec5SDimitry Andric                         CurDAG->getTargetConstant(LSB, dl, MVT::i32),
34190b57cec5SDimitry Andric                         CurDAG->getTargetConstant(Width, dl, MVT::i32),
34200b57cec5SDimitry Andric                         getAL(CurDAG, dl), Reg0 };
34210b57cec5SDimitry Andric       CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
34220b57cec5SDimitry Andric       return true;
34230b57cec5SDimitry Andric     }
34240b57cec5SDimitry Andric   }
34250b57cec5SDimitry Andric 
34260b57cec5SDimitry Andric   // Or we are looking for a shift of an and, with a mask operand
34270b57cec5SDimitry Andric   if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, And_imm) &&
34280b57cec5SDimitry Andric       isShiftedMask_32(And_imm)) {
34290b57cec5SDimitry Andric     unsigned Srl_imm = 0;
343006c3fb27SDimitry Andric     unsigned LSB = llvm::countr_zero(And_imm);
34310b57cec5SDimitry Andric     // Shift must be the same as the ands lsb
34320b57cec5SDimitry Andric     if (isInt32Immediate(N->getOperand(1), Srl_imm) && Srl_imm == LSB) {
34330b57cec5SDimitry Andric       assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
343406c3fb27SDimitry Andric       unsigned MSB = llvm::Log2_32(And_imm);
34350b57cec5SDimitry Andric       // Note: The width operand is encoded as width-1.
34360b57cec5SDimitry Andric       unsigned Width = MSB - LSB;
34370b57cec5SDimitry Andric       SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
34380b57cec5SDimitry Andric       assert(Srl_imm + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
34390b57cec5SDimitry Andric       SDValue Ops[] = { N->getOperand(0).getOperand(0),
34400b57cec5SDimitry Andric                         CurDAG->getTargetConstant(Srl_imm, dl, MVT::i32),
34410b57cec5SDimitry Andric                         CurDAG->getTargetConstant(Width, dl, MVT::i32),
34420b57cec5SDimitry Andric                         getAL(CurDAG, dl), Reg0 };
34430b57cec5SDimitry Andric       CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
34440b57cec5SDimitry Andric       return true;
34450b57cec5SDimitry Andric     }
34460b57cec5SDimitry Andric   }
34470b57cec5SDimitry Andric 
34480b57cec5SDimitry Andric   if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) {
34490b57cec5SDimitry Andric     unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits();
34500b57cec5SDimitry Andric     unsigned LSB = 0;
34510b57cec5SDimitry Andric     if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL, LSB) &&
34520b57cec5SDimitry Andric         !isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRA, LSB))
34530b57cec5SDimitry Andric       return false;
34540b57cec5SDimitry Andric 
34550b57cec5SDimitry Andric     if (LSB + Width > 32)
34560b57cec5SDimitry Andric       return false;
34570b57cec5SDimitry Andric 
34580b57cec5SDimitry Andric     SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
34590b57cec5SDimitry Andric     assert(LSB + Width <= 32 && "Shouldn't create an invalid ubfx");
34600b57cec5SDimitry Andric     SDValue Ops[] = { N->getOperand(0).getOperand(0),
34610b57cec5SDimitry Andric                       CurDAG->getTargetConstant(LSB, dl, MVT::i32),
34620b57cec5SDimitry Andric                       CurDAG->getTargetConstant(Width - 1, dl, MVT::i32),
34630b57cec5SDimitry Andric                       getAL(CurDAG, dl), Reg0 };
34640b57cec5SDimitry Andric     CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
34650b57cec5SDimitry Andric     return true;
34660b57cec5SDimitry Andric   }
34670b57cec5SDimitry Andric 
34680b57cec5SDimitry Andric   return false;
34690b57cec5SDimitry Andric }
34700b57cec5SDimitry Andric 
347181ad6265SDimitry Andric /// Target-specific DAG combining for ISD::SUB.
34720b57cec5SDimitry Andric /// Target-independent combining lowers SELECT_CC nodes of the form
34730b57cec5SDimitry Andric /// select_cc setg[ge] X,  0,  X, -X
34740b57cec5SDimitry Andric /// select_cc setgt    X, -1,  X, -X
34750b57cec5SDimitry Andric /// select_cc setl[te] X,  0, -X,  X
34760b57cec5SDimitry Andric /// select_cc setlt    X,  1, -X,  X
34770b57cec5SDimitry Andric /// which represent Integer ABS into:
347881ad6265SDimitry Andric /// Y = sra (X, size(X)-1); sub (xor (X, Y), Y)
34790b57cec5SDimitry Andric /// ARM instruction selection detects the latter and matches it to
34800b57cec5SDimitry Andric /// ARM::ABS or ARM::t2ABS machine node.
tryABSOp(SDNode * N)34810b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryABSOp(SDNode *N){
348281ad6265SDimitry Andric   SDValue SUBSrc0 = N->getOperand(0);
348381ad6265SDimitry Andric   SDValue SUBSrc1 = N->getOperand(1);
34840b57cec5SDimitry Andric   EVT VT = N->getValueType(0);
34850b57cec5SDimitry Andric 
34860b57cec5SDimitry Andric   if (Subtarget->isThumb1Only())
34870b57cec5SDimitry Andric     return false;
34880b57cec5SDimitry Andric 
348981ad6265SDimitry Andric   if (SUBSrc0.getOpcode() != ISD::XOR || SUBSrc1.getOpcode() != ISD::SRA)
34900b57cec5SDimitry Andric     return false;
34910b57cec5SDimitry Andric 
349281ad6265SDimitry Andric   SDValue XORSrc0 = SUBSrc0.getOperand(0);
349381ad6265SDimitry Andric   SDValue XORSrc1 = SUBSrc0.getOperand(1);
349481ad6265SDimitry Andric   SDValue SRASrc0 = SUBSrc1.getOperand(0);
349581ad6265SDimitry Andric   SDValue SRASrc1 = SUBSrc1.getOperand(1);
34960b57cec5SDimitry Andric   ConstantSDNode *SRAConstant =  dyn_cast<ConstantSDNode>(SRASrc1);
34970b57cec5SDimitry Andric   EVT XType = SRASrc0.getValueType();
34980b57cec5SDimitry Andric   unsigned Size = XType.getSizeInBits() - 1;
34990b57cec5SDimitry Andric 
350081ad6265SDimitry Andric   if (XORSrc1 == SUBSrc1 && XORSrc0 == SRASrc0 && XType.isInteger() &&
350181ad6265SDimitry Andric       SRAConstant != nullptr && Size == SRAConstant->getZExtValue()) {
35020b57cec5SDimitry Andric     unsigned Opcode = Subtarget->isThumb2() ? ARM::t2ABS : ARM::ABS;
350381ad6265SDimitry Andric     CurDAG->SelectNodeTo(N, Opcode, VT, XORSrc0);
35040b57cec5SDimitry Andric     return true;
35050b57cec5SDimitry Andric   }
35060b57cec5SDimitry Andric 
35070b57cec5SDimitry Andric   return false;
35080b57cec5SDimitry Andric }
35090b57cec5SDimitry Andric 
35100b57cec5SDimitry Andric /// We've got special pseudo-instructions for these
SelectCMP_SWAP(SDNode * N)35110b57cec5SDimitry Andric void ARMDAGToDAGISel::SelectCMP_SWAP(SDNode *N) {
35120b57cec5SDimitry Andric   unsigned Opcode;
35130b57cec5SDimitry Andric   EVT MemTy = cast<MemSDNode>(N)->getMemoryVT();
35140b57cec5SDimitry Andric   if (MemTy == MVT::i8)
3515fe6060f1SDimitry Andric     Opcode = Subtarget->isThumb() ? ARM::tCMP_SWAP_8 : ARM::CMP_SWAP_8;
35160b57cec5SDimitry Andric   else if (MemTy == MVT::i16)
3517fe6060f1SDimitry Andric     Opcode = Subtarget->isThumb() ? ARM::tCMP_SWAP_16 : ARM::CMP_SWAP_16;
35180b57cec5SDimitry Andric   else if (MemTy == MVT::i32)
3519fcaf7f86SDimitry Andric     Opcode = Subtarget->isThumb() ? ARM::tCMP_SWAP_32 : ARM::CMP_SWAP_32;
35200b57cec5SDimitry Andric   else
35210b57cec5SDimitry Andric     llvm_unreachable("Unknown AtomicCmpSwap type");
35220b57cec5SDimitry Andric 
35230b57cec5SDimitry Andric   SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3),
35240b57cec5SDimitry Andric                    N->getOperand(0)};
35250b57cec5SDimitry Andric   SDNode *CmpSwap = CurDAG->getMachineNode(
35260b57cec5SDimitry Andric       Opcode, SDLoc(N),
35270b57cec5SDimitry Andric       CurDAG->getVTList(MVT::i32, MVT::i32, MVT::Other), Ops);
35280b57cec5SDimitry Andric 
35290b57cec5SDimitry Andric   MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
35300b57cec5SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
35310b57cec5SDimitry Andric 
35320b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0));
35330b57cec5SDimitry Andric   ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2));
35340b57cec5SDimitry Andric   CurDAG->RemoveDeadNode(N);
35350b57cec5SDimitry Andric }
35360b57cec5SDimitry Andric 
3537bdd1243dSDimitry Andric static std::optional<std::pair<unsigned, unsigned>>
getContiguousRangeOfSetBits(const APInt & A)35380b57cec5SDimitry Andric getContiguousRangeOfSetBits(const APInt &A) {
353906c3fb27SDimitry Andric   unsigned FirstOne = A.getBitWidth() - A.countl_zero() - 1;
354006c3fb27SDimitry Andric   unsigned LastOne = A.countr_zero();
354106c3fb27SDimitry Andric   if (A.popcount() != (FirstOne - LastOne + 1))
3542bdd1243dSDimitry Andric     return std::nullopt;
35430b57cec5SDimitry Andric   return std::make_pair(FirstOne, LastOne);
35440b57cec5SDimitry Andric }
35450b57cec5SDimitry Andric 
SelectCMPZ(SDNode * N,bool & SwitchEQNEToPLMI)35460b57cec5SDimitry Andric void ARMDAGToDAGISel::SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI) {
35470b57cec5SDimitry Andric   assert(N->getOpcode() == ARMISD::CMPZ);
35480b57cec5SDimitry Andric   SwitchEQNEToPLMI = false;
35490b57cec5SDimitry Andric 
35500b57cec5SDimitry Andric   if (!Subtarget->isThumb())
35510b57cec5SDimitry Andric     // FIXME: Work out whether it is profitable to do this in A32 mode - LSL and
35520b57cec5SDimitry Andric     // LSR don't exist as standalone instructions - they need the barrel shifter.
35530b57cec5SDimitry Andric     return;
35540b57cec5SDimitry Andric 
35550b57cec5SDimitry Andric   // select (cmpz (and X, C), #0) -> (LSLS X) or (LSRS X) or (LSRS (LSLS X))
35560b57cec5SDimitry Andric   SDValue And = N->getOperand(0);
35570b57cec5SDimitry Andric   if (!And->hasOneUse())
35580b57cec5SDimitry Andric     return;
35590b57cec5SDimitry Andric 
35600b57cec5SDimitry Andric   SDValue Zero = N->getOperand(1);
35615f757f3fSDimitry Andric   if (!isNullConstant(Zero) || And->getOpcode() != ISD::AND)
35620b57cec5SDimitry Andric     return;
35630b57cec5SDimitry Andric   SDValue X = And.getOperand(0);
35640b57cec5SDimitry Andric   auto C = dyn_cast<ConstantSDNode>(And.getOperand(1));
35650b57cec5SDimitry Andric 
35660b57cec5SDimitry Andric   if (!C)
35670b57cec5SDimitry Andric     return;
35680b57cec5SDimitry Andric   auto Range = getContiguousRangeOfSetBits(C->getAPIntValue());
35690b57cec5SDimitry Andric   if (!Range)
35700b57cec5SDimitry Andric     return;
35710b57cec5SDimitry Andric 
35720b57cec5SDimitry Andric   // There are several ways to lower this:
35730b57cec5SDimitry Andric   SDNode *NewN;
35740b57cec5SDimitry Andric   SDLoc dl(N);
35750b57cec5SDimitry Andric 
35760b57cec5SDimitry Andric   auto EmitShift = [&](unsigned Opc, SDValue Src, unsigned Imm) -> SDNode* {
35770b57cec5SDimitry Andric     if (Subtarget->isThumb2()) {
35780b57cec5SDimitry Andric       Opc = (Opc == ARM::tLSLri) ? ARM::t2LSLri : ARM::t2LSRri;
35790b57cec5SDimitry Andric       SDValue Ops[] = { Src, CurDAG->getTargetConstant(Imm, dl, MVT::i32),
35800b57cec5SDimitry Andric                         getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
35810b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32) };
35820b57cec5SDimitry Andric       return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
35830b57cec5SDimitry Andric     } else {
35840b57cec5SDimitry Andric       SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), Src,
35850b57cec5SDimitry Andric                        CurDAG->getTargetConstant(Imm, dl, MVT::i32),
35860b57cec5SDimitry Andric                        getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
35870b57cec5SDimitry Andric       return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
35880b57cec5SDimitry Andric     }
35890b57cec5SDimitry Andric   };
35900b57cec5SDimitry Andric 
35910b57cec5SDimitry Andric   if (Range->second == 0) {
35920b57cec5SDimitry Andric     //  1. Mask includes the LSB -> Simply shift the top N bits off
35930b57cec5SDimitry Andric     NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
35940b57cec5SDimitry Andric     ReplaceNode(And.getNode(), NewN);
35950b57cec5SDimitry Andric   } else if (Range->first == 31) {
35960b57cec5SDimitry Andric     //  2. Mask includes the MSB -> Simply shift the bottom N bits off
35970b57cec5SDimitry Andric     NewN = EmitShift(ARM::tLSRri, X, Range->second);
35980b57cec5SDimitry Andric     ReplaceNode(And.getNode(), NewN);
35990b57cec5SDimitry Andric   } else if (Range->first == Range->second) {
36000b57cec5SDimitry Andric     //  3. Only one bit is set. We can shift this into the sign bit and use a
36010b57cec5SDimitry Andric     //     PL/MI comparison.
36020b57cec5SDimitry Andric     NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
36030b57cec5SDimitry Andric     ReplaceNode(And.getNode(), NewN);
36040b57cec5SDimitry Andric 
36050b57cec5SDimitry Andric     SwitchEQNEToPLMI = true;
36060b57cec5SDimitry Andric   } else if (!Subtarget->hasV6T2Ops()) {
36070b57cec5SDimitry Andric     //  4. Do a double shift to clear bottom and top bits, but only in
36080b57cec5SDimitry Andric     //     thumb-1 mode as in thumb-2 we can use UBFX.
36090b57cec5SDimitry Andric     NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
36100b57cec5SDimitry Andric     NewN = EmitShift(ARM::tLSRri, SDValue(NewN, 0),
36110b57cec5SDimitry Andric                      Range->second + (31 - Range->first));
36120b57cec5SDimitry Andric     ReplaceNode(And.getNode(), NewN);
36130b57cec5SDimitry Andric   }
3614bdd1243dSDimitry Andric }
36150b57cec5SDimitry Andric 
getVectorShuffleOpcode(EVT VT,unsigned Opc64[3],unsigned Opc128[3])3616bdd1243dSDimitry Andric static unsigned getVectorShuffleOpcode(EVT VT, unsigned Opc64[3],
3617bdd1243dSDimitry Andric                                        unsigned Opc128[3]) {
3618bdd1243dSDimitry Andric   assert((VT.is64BitVector() || VT.is128BitVector()) &&
3619bdd1243dSDimitry Andric          "Unexpected vector shuffle length");
3620bdd1243dSDimitry Andric   switch (VT.getScalarSizeInBits()) {
3621bdd1243dSDimitry Andric   default:
3622bdd1243dSDimitry Andric     llvm_unreachable("Unexpected vector shuffle element size");
3623bdd1243dSDimitry Andric   case 8:
3624bdd1243dSDimitry Andric     return VT.is64BitVector() ? Opc64[0] : Opc128[0];
3625bdd1243dSDimitry Andric   case 16:
3626bdd1243dSDimitry Andric     return VT.is64BitVector() ? Opc64[1] : Opc128[1];
3627bdd1243dSDimitry Andric   case 32:
3628bdd1243dSDimitry Andric     return VT.is64BitVector() ? Opc64[2] : Opc128[2];
3629bdd1243dSDimitry Andric   }
36300b57cec5SDimitry Andric }
36310b57cec5SDimitry Andric 
Select(SDNode * N)36320b57cec5SDimitry Andric void ARMDAGToDAGISel::Select(SDNode *N) {
36330b57cec5SDimitry Andric   SDLoc dl(N);
36340b57cec5SDimitry Andric 
36350b57cec5SDimitry Andric   if (N->isMachineOpcode()) {
36360b57cec5SDimitry Andric     N->setNodeId(-1);
36370b57cec5SDimitry Andric     return;   // Already selected.
36380b57cec5SDimitry Andric   }
36390b57cec5SDimitry Andric 
36400b57cec5SDimitry Andric   switch (N->getOpcode()) {
36410b57cec5SDimitry Andric   default: break;
36420b57cec5SDimitry Andric   case ISD::STORE: {
36430b57cec5SDimitry Andric     // For Thumb1, match an sp-relative store in C++. This is a little
36440b57cec5SDimitry Andric     // unfortunate, but I don't think I can make the chain check work
36450b57cec5SDimitry Andric     // otherwise.  (The chain of the store has to be the same as the chain
36460b57cec5SDimitry Andric     // of the CopyFromReg, or else we can't replace the CopyFromReg with
36470b57cec5SDimitry Andric     // a direct reference to "SP".)
36480b57cec5SDimitry Andric     //
36490b57cec5SDimitry Andric     // This is only necessary on Thumb1 because Thumb1 sp-relative stores use
36500b57cec5SDimitry Andric     // a different addressing mode from other four-byte stores.
36510b57cec5SDimitry Andric     //
36520b57cec5SDimitry Andric     // This pattern usually comes up with call arguments.
36530b57cec5SDimitry Andric     StoreSDNode *ST = cast<StoreSDNode>(N);
36540b57cec5SDimitry Andric     SDValue Ptr = ST->getBasePtr();
36550b57cec5SDimitry Andric     if (Subtarget->isThumb1Only() && ST->isUnindexed()) {
36560b57cec5SDimitry Andric       int RHSC = 0;
36570b57cec5SDimitry Andric       if (Ptr.getOpcode() == ISD::ADD &&
36580b57cec5SDimitry Andric           isScaledConstantInRange(Ptr.getOperand(1), /*Scale=*/4, 0, 256, RHSC))
36590b57cec5SDimitry Andric         Ptr = Ptr.getOperand(0);
36600b57cec5SDimitry Andric 
36610b57cec5SDimitry Andric       if (Ptr.getOpcode() == ISD::CopyFromReg &&
36620b57cec5SDimitry Andric           cast<RegisterSDNode>(Ptr.getOperand(1))->getReg() == ARM::SP &&
36630b57cec5SDimitry Andric           Ptr.getOperand(0) == ST->getChain()) {
36640b57cec5SDimitry Andric         SDValue Ops[] = {ST->getValue(),
36650b57cec5SDimitry Andric                          CurDAG->getRegister(ARM::SP, MVT::i32),
36660b57cec5SDimitry Andric                          CurDAG->getTargetConstant(RHSC, dl, MVT::i32),
36670b57cec5SDimitry Andric                          getAL(CurDAG, dl),
36680b57cec5SDimitry Andric                          CurDAG->getRegister(0, MVT::i32),
36690b57cec5SDimitry Andric                          ST->getChain()};
36700b57cec5SDimitry Andric         MachineSDNode *ResNode =
36710b57cec5SDimitry Andric             CurDAG->getMachineNode(ARM::tSTRspi, dl, MVT::Other, Ops);
36720b57cec5SDimitry Andric         MachineMemOperand *MemOp = ST->getMemOperand();
36730b57cec5SDimitry Andric         CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemOp});
36740b57cec5SDimitry Andric         ReplaceNode(N, ResNode);
36750b57cec5SDimitry Andric         return;
36760b57cec5SDimitry Andric       }
36770b57cec5SDimitry Andric     }
36780b57cec5SDimitry Andric     break;
36790b57cec5SDimitry Andric   }
36800b57cec5SDimitry Andric   case ISD::WRITE_REGISTER:
36810b57cec5SDimitry Andric     if (tryWriteRegister(N))
36820b57cec5SDimitry Andric       return;
36830b57cec5SDimitry Andric     break;
36840b57cec5SDimitry Andric   case ISD::READ_REGISTER:
36850b57cec5SDimitry Andric     if (tryReadRegister(N))
36860b57cec5SDimitry Andric       return;
36870b57cec5SDimitry Andric     break;
36880b57cec5SDimitry Andric   case ISD::INLINEASM:
36890b57cec5SDimitry Andric   case ISD::INLINEASM_BR:
36900b57cec5SDimitry Andric     if (tryInlineAsm(N))
36910b57cec5SDimitry Andric       return;
36920b57cec5SDimitry Andric     break;
369381ad6265SDimitry Andric   case ISD::SUB:
369481ad6265SDimitry Andric     // Select special operations if SUB node forms integer ABS pattern
36950b57cec5SDimitry Andric     if (tryABSOp(N))
36960b57cec5SDimitry Andric       return;
36970b57cec5SDimitry Andric     // Other cases are autogenerated.
36980b57cec5SDimitry Andric     break;
36990b57cec5SDimitry Andric   case ISD::Constant: {
37001db9f3b2SDimitry Andric     unsigned Val = N->getAsZExtVal();
37010b57cec5SDimitry Andric     // If we can't materialize the constant we need to use a literal pool
370206c3fb27SDimitry Andric     if (ConstantMaterializationCost(Val, Subtarget) > 2 &&
370306c3fb27SDimitry Andric         !Subtarget->genExecuteOnly()) {
37040b57cec5SDimitry Andric       SDValue CPIdx = CurDAG->getTargetConstantPool(
37050b57cec5SDimitry Andric           ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
37060b57cec5SDimitry Andric           TLI->getPointerTy(CurDAG->getDataLayout()));
37070b57cec5SDimitry Andric 
37080b57cec5SDimitry Andric       SDNode *ResNode;
37090b57cec5SDimitry Andric       if (Subtarget->isThumb()) {
37100b57cec5SDimitry Andric         SDValue Ops[] = {
37110b57cec5SDimitry Andric           CPIdx,
37120b57cec5SDimitry Andric           getAL(CurDAG, dl),
37130b57cec5SDimitry Andric           CurDAG->getRegister(0, MVT::i32),
37140b57cec5SDimitry Andric           CurDAG->getEntryNode()
37150b57cec5SDimitry Andric         };
37160b57cec5SDimitry Andric         ResNode = CurDAG->getMachineNode(ARM::tLDRpci, dl, MVT::i32, MVT::Other,
37170b57cec5SDimitry Andric                                          Ops);
37180b57cec5SDimitry Andric       } else {
37190b57cec5SDimitry Andric         SDValue Ops[] = {
37200b57cec5SDimitry Andric           CPIdx,
37210b57cec5SDimitry Andric           CurDAG->getTargetConstant(0, dl, MVT::i32),
37220b57cec5SDimitry Andric           getAL(CurDAG, dl),
37230b57cec5SDimitry Andric           CurDAG->getRegister(0, MVT::i32),
37240b57cec5SDimitry Andric           CurDAG->getEntryNode()
37250b57cec5SDimitry Andric         };
37260b57cec5SDimitry Andric         ResNode = CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other,
37270b57cec5SDimitry Andric                                          Ops);
37280b57cec5SDimitry Andric       }
37290b57cec5SDimitry Andric       // Annotate the Node with memory operand information so that MachineInstr
37300b57cec5SDimitry Andric       // queries work properly. This e.g. gives the register allocation the
37310b57cec5SDimitry Andric       // required information for rematerialization.
37320b57cec5SDimitry Andric       MachineFunction& MF = CurDAG->getMachineFunction();
37330b57cec5SDimitry Andric       MachineMemOperand *MemOp =
37340b57cec5SDimitry Andric           MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
37355ffd83dbSDimitry Andric                                   MachineMemOperand::MOLoad, 4, Align(4));
37360b57cec5SDimitry Andric 
37370b57cec5SDimitry Andric       CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemOp});
37380b57cec5SDimitry Andric 
37390b57cec5SDimitry Andric       ReplaceNode(N, ResNode);
37400b57cec5SDimitry Andric       return;
37410b57cec5SDimitry Andric     }
37420b57cec5SDimitry Andric 
37430b57cec5SDimitry Andric     // Other cases are autogenerated.
37440b57cec5SDimitry Andric     break;
37450b57cec5SDimitry Andric   }
37460b57cec5SDimitry Andric   case ISD::FrameIndex: {
37470b57cec5SDimitry Andric     // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm.
37480b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(N)->getIndex();
37490b57cec5SDimitry Andric     SDValue TFI = CurDAG->getTargetFrameIndex(
37500b57cec5SDimitry Andric         FI, TLI->getPointerTy(CurDAG->getDataLayout()));
37510b57cec5SDimitry Andric     if (Subtarget->isThumb1Only()) {
37520b57cec5SDimitry Andric       // Set the alignment of the frame object to 4, to avoid having to generate
37530b57cec5SDimitry Andric       // more than one ADD
37540b57cec5SDimitry Andric       MachineFrameInfo &MFI = MF->getFrameInfo();
37555ffd83dbSDimitry Andric       if (MFI.getObjectAlign(FI) < Align(4))
37565ffd83dbSDimitry Andric         MFI.setObjectAlignment(FI, Align(4));
37570b57cec5SDimitry Andric       CurDAG->SelectNodeTo(N, ARM::tADDframe, MVT::i32, TFI,
37580b57cec5SDimitry Andric                            CurDAG->getTargetConstant(0, dl, MVT::i32));
37590b57cec5SDimitry Andric       return;
37600b57cec5SDimitry Andric     } else {
37610b57cec5SDimitry Andric       unsigned Opc = ((Subtarget->isThumb() && Subtarget->hasThumb2()) ?
37620b57cec5SDimitry Andric                       ARM::t2ADDri : ARM::ADDri);
37630b57cec5SDimitry Andric       SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, dl, MVT::i32),
37640b57cec5SDimitry Andric                         getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
37650b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32) };
37660b57cec5SDimitry Andric       CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
37670b57cec5SDimitry Andric       return;
37680b57cec5SDimitry Andric     }
37690b57cec5SDimitry Andric   }
3770fe6060f1SDimitry Andric   case ISD::INSERT_VECTOR_ELT: {
3771fe6060f1SDimitry Andric     if (tryInsertVectorElt(N))
3772fe6060f1SDimitry Andric       return;
3773fe6060f1SDimitry Andric     break;
3774fe6060f1SDimitry Andric   }
37750b57cec5SDimitry Andric   case ISD::SRL:
37760b57cec5SDimitry Andric     if (tryV6T2BitfieldExtractOp(N, false))
37770b57cec5SDimitry Andric       return;
37780b57cec5SDimitry Andric     break;
37790b57cec5SDimitry Andric   case ISD::SIGN_EXTEND_INREG:
37800b57cec5SDimitry Andric   case ISD::SRA:
37810b57cec5SDimitry Andric     if (tryV6T2BitfieldExtractOp(N, true))
37820b57cec5SDimitry Andric       return;
37830b57cec5SDimitry Andric     break;
3784fe6060f1SDimitry Andric   case ISD::FP_TO_UINT:
3785fe6060f1SDimitry Andric   case ISD::FP_TO_SINT:
37864824e7fdSDimitry Andric   case ISD::FP_TO_UINT_SAT:
37874824e7fdSDimitry Andric   case ISD::FP_TO_SINT_SAT:
3788fe6060f1SDimitry Andric     if (tryFP_TO_INT(N, dl))
3789fe6060f1SDimitry Andric       return;
3790fe6060f1SDimitry Andric     break;
3791fe6060f1SDimitry Andric   case ISD::FMUL:
3792fe6060f1SDimitry Andric     if (tryFMULFixed(N, dl))
3793fe6060f1SDimitry Andric       return;
3794fe6060f1SDimitry Andric     break;
37950b57cec5SDimitry Andric   case ISD::MUL:
37960b57cec5SDimitry Andric     if (Subtarget->isThumb1Only())
37970b57cec5SDimitry Andric       break;
37980b57cec5SDimitry Andric     if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
37990b57cec5SDimitry Andric       unsigned RHSV = C->getZExtValue();
38000b57cec5SDimitry Andric       if (!RHSV) break;
38010b57cec5SDimitry Andric       if (isPowerOf2_32(RHSV-1)) {  // 2^n+1?
38020b57cec5SDimitry Andric         unsigned ShImm = Log2_32(RHSV-1);
38030b57cec5SDimitry Andric         if (ShImm >= 32)
38040b57cec5SDimitry Andric           break;
38050b57cec5SDimitry Andric         SDValue V = N->getOperand(0);
38060b57cec5SDimitry Andric         ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
38070b57cec5SDimitry Andric         SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
38080b57cec5SDimitry Andric         SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
38090b57cec5SDimitry Andric         if (Subtarget->isThumb()) {
38100b57cec5SDimitry Andric           SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
38110b57cec5SDimitry Andric           CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops);
38120b57cec5SDimitry Andric           return;
38130b57cec5SDimitry Andric         } else {
38140b57cec5SDimitry Andric           SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
38150b57cec5SDimitry Andric                             Reg0 };
38160b57cec5SDimitry Andric           CurDAG->SelectNodeTo(N, ARM::ADDrsi, MVT::i32, Ops);
38170b57cec5SDimitry Andric           return;
38180b57cec5SDimitry Andric         }
38190b57cec5SDimitry Andric       }
38200b57cec5SDimitry Andric       if (isPowerOf2_32(RHSV+1)) {  // 2^n-1?
38210b57cec5SDimitry Andric         unsigned ShImm = Log2_32(RHSV+1);
38220b57cec5SDimitry Andric         if (ShImm >= 32)
38230b57cec5SDimitry Andric           break;
38240b57cec5SDimitry Andric         SDValue V = N->getOperand(0);
38250b57cec5SDimitry Andric         ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
38260b57cec5SDimitry Andric         SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
38270b57cec5SDimitry Andric         SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
38280b57cec5SDimitry Andric         if (Subtarget->isThumb()) {
38290b57cec5SDimitry Andric           SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
38300b57cec5SDimitry Andric           CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops);
38310b57cec5SDimitry Andric           return;
38320b57cec5SDimitry Andric         } else {
38330b57cec5SDimitry Andric           SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
38340b57cec5SDimitry Andric                             Reg0 };
38350b57cec5SDimitry Andric           CurDAG->SelectNodeTo(N, ARM::RSBrsi, MVT::i32, Ops);
38360b57cec5SDimitry Andric           return;
38370b57cec5SDimitry Andric         }
38380b57cec5SDimitry Andric       }
38390b57cec5SDimitry Andric     }
38400b57cec5SDimitry Andric     break;
38410b57cec5SDimitry Andric   case ISD::AND: {
38420b57cec5SDimitry Andric     // Check for unsigned bitfield extract
38430b57cec5SDimitry Andric     if (tryV6T2BitfieldExtractOp(N, false))
38440b57cec5SDimitry Andric       return;
38450b57cec5SDimitry Andric 
38460b57cec5SDimitry Andric     // If an immediate is used in an AND node, it is possible that the immediate
38470b57cec5SDimitry Andric     // can be more optimally materialized when negated. If this is the case we
38480b57cec5SDimitry Andric     // can negate the immediate and use a BIC instead.
38490b57cec5SDimitry Andric     auto *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1));
38500b57cec5SDimitry Andric     if (N1C && N1C->hasOneUse() && Subtarget->isThumb()) {
38510b57cec5SDimitry Andric       uint32_t Imm = (uint32_t) N1C->getZExtValue();
38520b57cec5SDimitry Andric 
38530b57cec5SDimitry Andric       // In Thumb2 mode, an AND can take a 12-bit immediate. If this
38540b57cec5SDimitry Andric       // immediate can be negated and fit in the immediate operand of
38550b57cec5SDimitry Andric       // a t2BIC, don't do any manual transform here as this can be
38560b57cec5SDimitry Andric       // handled by the generic ISel machinery.
38570b57cec5SDimitry Andric       bool PreferImmediateEncoding =
38580b57cec5SDimitry Andric         Subtarget->hasThumb2() && (is_t2_so_imm(Imm) || is_t2_so_imm_not(Imm));
38590b57cec5SDimitry Andric       if (!PreferImmediateEncoding &&
38608bcb0991SDimitry Andric           ConstantMaterializationCost(Imm, Subtarget) >
38618bcb0991SDimitry Andric               ConstantMaterializationCost(~Imm, Subtarget)) {
38620b57cec5SDimitry Andric         // The current immediate costs more to materialize than a negated
38630b57cec5SDimitry Andric         // immediate, so negate the immediate and use a BIC.
38640b57cec5SDimitry Andric         SDValue NewImm =
38650b57cec5SDimitry Andric           CurDAG->getConstant(~N1C->getZExtValue(), dl, MVT::i32);
38660b57cec5SDimitry Andric         // If the new constant didn't exist before, reposition it in the topological
38670b57cec5SDimitry Andric         // ordering so it is just before N. Otherwise, don't touch its location.
38680b57cec5SDimitry Andric         if (NewImm->getNodeId() == -1)
38690b57cec5SDimitry Andric           CurDAG->RepositionNode(N->getIterator(), NewImm.getNode());
38700b57cec5SDimitry Andric 
38710b57cec5SDimitry Andric         if (!Subtarget->hasThumb2()) {
38720b57cec5SDimitry Andric           SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32),
38730b57cec5SDimitry Andric                            N->getOperand(0), NewImm, getAL(CurDAG, dl),
38740b57cec5SDimitry Andric                            CurDAG->getRegister(0, MVT::i32)};
38750b57cec5SDimitry Andric           ReplaceNode(N, CurDAG->getMachineNode(ARM::tBIC, dl, MVT::i32, Ops));
38760b57cec5SDimitry Andric           return;
38770b57cec5SDimitry Andric         } else {
38780b57cec5SDimitry Andric           SDValue Ops[] = {N->getOperand(0), NewImm, getAL(CurDAG, dl),
38790b57cec5SDimitry Andric                            CurDAG->getRegister(0, MVT::i32),
38800b57cec5SDimitry Andric                            CurDAG->getRegister(0, MVT::i32)};
38810b57cec5SDimitry Andric           ReplaceNode(N,
38820b57cec5SDimitry Andric                       CurDAG->getMachineNode(ARM::t2BICrr, dl, MVT::i32, Ops));
38830b57cec5SDimitry Andric           return;
38840b57cec5SDimitry Andric         }
38850b57cec5SDimitry Andric       }
38860b57cec5SDimitry Andric     }
38870b57cec5SDimitry Andric 
38880b57cec5SDimitry Andric     // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits
38890b57cec5SDimitry Andric     // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits
38900b57cec5SDimitry Andric     // are entirely contributed by c2 and lower 16-bits are entirely contributed
38910b57cec5SDimitry Andric     // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)).
38920b57cec5SDimitry Andric     // Select it to: "movt x, ((c1 & 0xffff) >> 16)
38930b57cec5SDimitry Andric     EVT VT = N->getValueType(0);
38940b57cec5SDimitry Andric     if (VT != MVT::i32)
38950b57cec5SDimitry Andric       break;
38960b57cec5SDimitry Andric     unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2())
38970b57cec5SDimitry Andric       ? ARM::t2MOVTi16
38980b57cec5SDimitry Andric       : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0);
38990b57cec5SDimitry Andric     if (!Opc)
39000b57cec5SDimitry Andric       break;
39010b57cec5SDimitry Andric     SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
39020b57cec5SDimitry Andric     N1C = dyn_cast<ConstantSDNode>(N1);
39030b57cec5SDimitry Andric     if (!N1C)
39040b57cec5SDimitry Andric       break;
39050b57cec5SDimitry Andric     if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) {
39060b57cec5SDimitry Andric       SDValue N2 = N0.getOperand(1);
39070b57cec5SDimitry Andric       ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2);
39080b57cec5SDimitry Andric       if (!N2C)
39090b57cec5SDimitry Andric         break;
39100b57cec5SDimitry Andric       unsigned N1CVal = N1C->getZExtValue();
39110b57cec5SDimitry Andric       unsigned N2CVal = N2C->getZExtValue();
39120b57cec5SDimitry Andric       if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) &&
39130b57cec5SDimitry Andric           (N1CVal & 0xffffU) == 0xffffU &&
39140b57cec5SDimitry Andric           (N2CVal & 0xffffU) == 0x0U) {
39150b57cec5SDimitry Andric         SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16,
39160b57cec5SDimitry Andric                                                   dl, MVT::i32);
39170b57cec5SDimitry Andric         SDValue Ops[] = { N0.getOperand(0), Imm16,
39180b57cec5SDimitry Andric                           getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32) };
39190b57cec5SDimitry Andric         ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops));
39200b57cec5SDimitry Andric         return;
39210b57cec5SDimitry Andric       }
39220b57cec5SDimitry Andric     }
39230b57cec5SDimitry Andric 
39240b57cec5SDimitry Andric     break;
39250b57cec5SDimitry Andric   }
39260b57cec5SDimitry Andric   case ARMISD::UMAAL: {
39270b57cec5SDimitry Andric     unsigned Opc = Subtarget->isThumb() ? ARM::t2UMAAL : ARM::UMAAL;
39280b57cec5SDimitry Andric     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
39290b57cec5SDimitry Andric                       N->getOperand(2), N->getOperand(3),
39300b57cec5SDimitry Andric                       getAL(CurDAG, dl),
39310b57cec5SDimitry Andric                       CurDAG->getRegister(0, MVT::i32) };
39320b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, MVT::i32, Ops));
39330b57cec5SDimitry Andric     return;
39340b57cec5SDimitry Andric   }
39350b57cec5SDimitry Andric   case ARMISD::UMLAL:{
39360b57cec5SDimitry Andric     if (Subtarget->isThumb()) {
39370b57cec5SDimitry Andric       SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
39380b57cec5SDimitry Andric                         N->getOperand(3), getAL(CurDAG, dl),
39390b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32)};
39400b57cec5SDimitry Andric       ReplaceNode(
39410b57cec5SDimitry Andric           N, CurDAG->getMachineNode(ARM::t2UMLAL, dl, MVT::i32, MVT::i32, Ops));
39420b57cec5SDimitry Andric       return;
39430b57cec5SDimitry Andric     }else{
39440b57cec5SDimitry Andric       SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
39450b57cec5SDimitry Andric                         N->getOperand(3), getAL(CurDAG, dl),
39460b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32),
39470b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32) };
39480b57cec5SDimitry Andric       ReplaceNode(N, CurDAG->getMachineNode(
39490b57cec5SDimitry Andric                          Subtarget->hasV6Ops() ? ARM::UMLAL : ARM::UMLALv5, dl,
39500b57cec5SDimitry Andric                          MVT::i32, MVT::i32, Ops));
39510b57cec5SDimitry Andric       return;
39520b57cec5SDimitry Andric     }
39530b57cec5SDimitry Andric   }
39540b57cec5SDimitry Andric   case ARMISD::SMLAL:{
39550b57cec5SDimitry Andric     if (Subtarget->isThumb()) {
39560b57cec5SDimitry Andric       SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
39570b57cec5SDimitry Andric                         N->getOperand(3), getAL(CurDAG, dl),
39580b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32)};
39590b57cec5SDimitry Andric       ReplaceNode(
39600b57cec5SDimitry Andric           N, CurDAG->getMachineNode(ARM::t2SMLAL, dl, MVT::i32, MVT::i32, Ops));
39610b57cec5SDimitry Andric       return;
39620b57cec5SDimitry Andric     }else{
39630b57cec5SDimitry Andric       SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
39640b57cec5SDimitry Andric                         N->getOperand(3), getAL(CurDAG, dl),
39650b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32),
39660b57cec5SDimitry Andric                         CurDAG->getRegister(0, MVT::i32) };
39670b57cec5SDimitry Andric       ReplaceNode(N, CurDAG->getMachineNode(
39680b57cec5SDimitry Andric                          Subtarget->hasV6Ops() ? ARM::SMLAL : ARM::SMLALv5, dl,
39690b57cec5SDimitry Andric                          MVT::i32, MVT::i32, Ops));
39700b57cec5SDimitry Andric       return;
39710b57cec5SDimitry Andric     }
39720b57cec5SDimitry Andric   }
39730b57cec5SDimitry Andric   case ARMISD::SUBE: {
39740b57cec5SDimitry Andric     if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP())
39750b57cec5SDimitry Andric       break;
39760b57cec5SDimitry Andric     // Look for a pattern to match SMMLS
39770b57cec5SDimitry Andric     // (sube a, (smul_loHi a, b), (subc 0, (smul_LOhi(a, b))))
39780b57cec5SDimitry Andric     if (N->getOperand(1).getOpcode() != ISD::SMUL_LOHI ||
39790b57cec5SDimitry Andric         N->getOperand(2).getOpcode() != ARMISD::SUBC ||
39800b57cec5SDimitry Andric         !SDValue(N, 1).use_empty())
39810b57cec5SDimitry Andric       break;
39820b57cec5SDimitry Andric 
39830b57cec5SDimitry Andric     if (Subtarget->isThumb())
39840b57cec5SDimitry Andric       assert(Subtarget->hasThumb2() &&
39850b57cec5SDimitry Andric              "This pattern should not be generated for Thumb");
39860b57cec5SDimitry Andric 
39870b57cec5SDimitry Andric     SDValue SmulLoHi = N->getOperand(1);
39880b57cec5SDimitry Andric     SDValue Subc = N->getOperand(2);
398906c3fb27SDimitry Andric     SDValue Zero = Subc.getOperand(0);
39900b57cec5SDimitry Andric 
399106c3fb27SDimitry Andric     if (!isNullConstant(Zero) || Subc.getOperand(1) != SmulLoHi.getValue(0) ||
39920b57cec5SDimitry Andric         N->getOperand(1) != SmulLoHi.getValue(1) ||
39930b57cec5SDimitry Andric         N->getOperand(2) != Subc.getValue(1))
39940b57cec5SDimitry Andric       break;
39950b57cec5SDimitry Andric 
39960b57cec5SDimitry Andric     unsigned Opc = Subtarget->isThumb2() ? ARM::t2SMMLS : ARM::SMMLS;
39970b57cec5SDimitry Andric     SDValue Ops[] = { SmulLoHi.getOperand(0), SmulLoHi.getOperand(1),
39980b57cec5SDimitry Andric                       N->getOperand(0), getAL(CurDAG, dl),
39990b57cec5SDimitry Andric                       CurDAG->getRegister(0, MVT::i32) };
40000b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops));
40010b57cec5SDimitry Andric     return;
40020b57cec5SDimitry Andric   }
40030b57cec5SDimitry Andric   case ISD::LOAD: {
40048bcb0991SDimitry Andric     if (Subtarget->hasMVEIntegerOps() && tryMVEIndexedLoad(N))
40058bcb0991SDimitry Andric       return;
40060b57cec5SDimitry Andric     if (Subtarget->isThumb() && Subtarget->hasThumb2()) {
40070b57cec5SDimitry Andric       if (tryT2IndexedLoad(N))
40080b57cec5SDimitry Andric         return;
40090b57cec5SDimitry Andric     } else if (Subtarget->isThumb()) {
40100b57cec5SDimitry Andric       if (tryT1IndexedLoad(N))
40110b57cec5SDimitry Andric         return;
40120b57cec5SDimitry Andric     } else if (tryARMIndexedLoad(N))
40130b57cec5SDimitry Andric       return;
40140b57cec5SDimitry Andric     // Other cases are autogenerated.
40150b57cec5SDimitry Andric     break;
40160b57cec5SDimitry Andric   }
4017480093f4SDimitry Andric   case ISD::MLOAD:
4018480093f4SDimitry Andric     if (Subtarget->hasMVEIntegerOps() && tryMVEIndexedLoad(N))
4019480093f4SDimitry Andric       return;
4020480093f4SDimitry Andric     // Other cases are autogenerated.
4021480093f4SDimitry Andric     break;
4022fe6060f1SDimitry Andric   case ARMISD::WLSSETUP: {
4023fe6060f1SDimitry Andric     SDNode *New = CurDAG->getMachineNode(ARM::t2WhileLoopSetup, dl, MVT::i32,
4024fe6060f1SDimitry Andric                                          N->getOperand(0));
4025fe6060f1SDimitry Andric     ReplaceUses(N, New);
4026fe6060f1SDimitry Andric     CurDAG->RemoveDeadNode(N);
4027fe6060f1SDimitry Andric     return;
4028fe6060f1SDimitry Andric   }
4029fe6060f1SDimitry Andric   case ARMISD::WLS: {
4030fe6060f1SDimitry Andric     SDNode *New = CurDAG->getMachineNode(ARM::t2WhileLoopStart, dl, MVT::Other,
4031fe6060f1SDimitry Andric                                          N->getOperand(1), N->getOperand(2),
4032fe6060f1SDimitry Andric                                          N->getOperand(0));
4033fe6060f1SDimitry Andric     ReplaceUses(N, New);
4034fe6060f1SDimitry Andric     CurDAG->RemoveDeadNode(N);
4035fe6060f1SDimitry Andric     return;
4036fe6060f1SDimitry Andric   }
40378bcb0991SDimitry Andric   case ARMISD::LE: {
40388bcb0991SDimitry Andric     SDValue Ops[] = { N->getOperand(1),
40398bcb0991SDimitry Andric                       N->getOperand(2),
40400b57cec5SDimitry Andric                       N->getOperand(0) };
4041fe6060f1SDimitry Andric     unsigned Opc = ARM::t2LoopEnd;
40428bcb0991SDimitry Andric     SDNode *New = CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops);
40438bcb0991SDimitry Andric     ReplaceUses(N, New);
40448bcb0991SDimitry Andric     CurDAG->RemoveDeadNode(N);
40458bcb0991SDimitry Andric     return;
40468bcb0991SDimitry Andric   }
40475ffd83dbSDimitry Andric   case ARMISD::LDRD: {
40485ffd83dbSDimitry Andric     if (Subtarget->isThumb2())
40495ffd83dbSDimitry Andric       break; // TableGen handles isel in this case.
40505ffd83dbSDimitry Andric     SDValue Base, RegOffset, ImmOffset;
40515ffd83dbSDimitry Andric     const SDValue &Chain = N->getOperand(0);
40525ffd83dbSDimitry Andric     const SDValue &Addr = N->getOperand(1);
40535ffd83dbSDimitry Andric     SelectAddrMode3(Addr, Base, RegOffset, ImmOffset);
40545ffd83dbSDimitry Andric     if (RegOffset != CurDAG->getRegister(0, MVT::i32)) {
40555ffd83dbSDimitry Andric       // The register-offset variant of LDRD mandates that the register
40565ffd83dbSDimitry Andric       // allocated to RegOffset is not reused in any of the remaining operands.
40575ffd83dbSDimitry Andric       // This restriction is currently not enforced. Therefore emitting this
40585ffd83dbSDimitry Andric       // variant is explicitly avoided.
40595ffd83dbSDimitry Andric       Base = Addr;
40605ffd83dbSDimitry Andric       RegOffset = CurDAG->getRegister(0, MVT::i32);
40615ffd83dbSDimitry Andric     }
40625ffd83dbSDimitry Andric     SDValue Ops[] = {Base, RegOffset, ImmOffset, Chain};
40635ffd83dbSDimitry Andric     SDNode *New = CurDAG->getMachineNode(ARM::LOADDUAL, dl,
40645ffd83dbSDimitry Andric                                          {MVT::Untyped, MVT::Other}, Ops);
40655ffd83dbSDimitry Andric     SDValue Lo = CurDAG->getTargetExtractSubreg(ARM::gsub_0, dl, MVT::i32,
40665ffd83dbSDimitry Andric                                                 SDValue(New, 0));
40675ffd83dbSDimitry Andric     SDValue Hi = CurDAG->getTargetExtractSubreg(ARM::gsub_1, dl, MVT::i32,
40685ffd83dbSDimitry Andric                                                 SDValue(New, 0));
40695ffd83dbSDimitry Andric     transferMemOperands(N, New);
40705ffd83dbSDimitry Andric     ReplaceUses(SDValue(N, 0), Lo);
40715ffd83dbSDimitry Andric     ReplaceUses(SDValue(N, 1), Hi);
40725ffd83dbSDimitry Andric     ReplaceUses(SDValue(N, 2), SDValue(New, 1));
40735ffd83dbSDimitry Andric     CurDAG->RemoveDeadNode(N);
40745ffd83dbSDimitry Andric     return;
40755ffd83dbSDimitry Andric   }
40765ffd83dbSDimitry Andric   case ARMISD::STRD: {
40775ffd83dbSDimitry Andric     if (Subtarget->isThumb2())
40785ffd83dbSDimitry Andric       break; // TableGen handles isel in this case.
40795ffd83dbSDimitry Andric     SDValue Base, RegOffset, ImmOffset;
40805ffd83dbSDimitry Andric     const SDValue &Chain = N->getOperand(0);
40815ffd83dbSDimitry Andric     const SDValue &Addr = N->getOperand(3);
40825ffd83dbSDimitry Andric     SelectAddrMode3(Addr, Base, RegOffset, ImmOffset);
40835ffd83dbSDimitry Andric     if (RegOffset != CurDAG->getRegister(0, MVT::i32)) {
40845ffd83dbSDimitry Andric       // The register-offset variant of STRD mandates that the register
40855ffd83dbSDimitry Andric       // allocated to RegOffset is not reused in any of the remaining operands.
40865ffd83dbSDimitry Andric       // This restriction is currently not enforced. Therefore emitting this
40875ffd83dbSDimitry Andric       // variant is explicitly avoided.
40885ffd83dbSDimitry Andric       Base = Addr;
40895ffd83dbSDimitry Andric       RegOffset = CurDAG->getRegister(0, MVT::i32);
40905ffd83dbSDimitry Andric     }
40915ffd83dbSDimitry Andric     SDNode *RegPair =
40925ffd83dbSDimitry Andric         createGPRPairNode(MVT::Untyped, N->getOperand(1), N->getOperand(2));
40935ffd83dbSDimitry Andric     SDValue Ops[] = {SDValue(RegPair, 0), Base, RegOffset, ImmOffset, Chain};
40945ffd83dbSDimitry Andric     SDNode *New = CurDAG->getMachineNode(ARM::STOREDUAL, dl, MVT::Other, Ops);
40955ffd83dbSDimitry Andric     transferMemOperands(N, New);
40965ffd83dbSDimitry Andric     ReplaceUses(SDValue(N, 0), SDValue(New, 0));
40975ffd83dbSDimitry Andric     CurDAG->RemoveDeadNode(N);
40985ffd83dbSDimitry Andric     return;
40995ffd83dbSDimitry Andric   }
41008bcb0991SDimitry Andric   case ARMISD::LOOP_DEC: {
41018bcb0991SDimitry Andric     SDValue Ops[] = { N->getOperand(1),
41028bcb0991SDimitry Andric                       N->getOperand(2),
41038bcb0991SDimitry Andric                       N->getOperand(0) };
41048bcb0991SDimitry Andric     SDNode *Dec =
41058bcb0991SDimitry Andric       CurDAG->getMachineNode(ARM::t2LoopDec, dl,
41068bcb0991SDimitry Andric                              CurDAG->getVTList(MVT::i32, MVT::Other), Ops);
41078bcb0991SDimitry Andric     ReplaceUses(N, Dec);
41080b57cec5SDimitry Andric     CurDAG->RemoveDeadNode(N);
41090b57cec5SDimitry Andric     return;
41100b57cec5SDimitry Andric   }
41110b57cec5SDimitry Andric   case ARMISD::BRCOND: {
41120b57cec5SDimitry Andric     // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
41130b57cec5SDimitry Andric     // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc)
41140b57cec5SDimitry Andric     // Pattern complexity = 6  cost = 1  size = 0
41150b57cec5SDimitry Andric 
41160b57cec5SDimitry Andric     // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
41170b57cec5SDimitry Andric     // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc)
41180b57cec5SDimitry Andric     // Pattern complexity = 6  cost = 1  size = 0
41190b57cec5SDimitry Andric 
41200b57cec5SDimitry Andric     // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
41210b57cec5SDimitry Andric     // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc)
41220b57cec5SDimitry Andric     // Pattern complexity = 6  cost = 1  size = 0
41230b57cec5SDimitry Andric 
41240b57cec5SDimitry Andric     unsigned Opc = Subtarget->isThumb() ?
41250b57cec5SDimitry Andric       ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
41260b57cec5SDimitry Andric     SDValue Chain = N->getOperand(0);
41270b57cec5SDimitry Andric     SDValue N1 = N->getOperand(1);
41280b57cec5SDimitry Andric     SDValue N2 = N->getOperand(2);
41290b57cec5SDimitry Andric     SDValue N3 = N->getOperand(3);
413006c3fb27SDimitry Andric     SDValue InGlue = N->getOperand(4);
41310b57cec5SDimitry Andric     assert(N1.getOpcode() == ISD::BasicBlock);
41320b57cec5SDimitry Andric     assert(N2.getOpcode() == ISD::Constant);
41330b57cec5SDimitry Andric     assert(N3.getOpcode() == ISD::Register);
41340b57cec5SDimitry Andric 
41351db9f3b2SDimitry Andric     unsigned CC = (unsigned)N2->getAsZExtVal();
41360b57cec5SDimitry Andric 
413706c3fb27SDimitry Andric     if (InGlue.getOpcode() == ARMISD::CMPZ) {
413806c3fb27SDimitry Andric       if (InGlue.getOperand(0).getOpcode() == ISD::INTRINSIC_W_CHAIN) {
413906c3fb27SDimitry Andric         SDValue Int = InGlue.getOperand(0);
4140647cbc5dSDimitry Andric         uint64_t ID = Int->getConstantOperandVal(1);
41410b57cec5SDimitry Andric 
41420b57cec5SDimitry Andric         // Handle low-overhead loops.
41430b57cec5SDimitry Andric         if (ID == Intrinsic::loop_decrement_reg) {
41440b57cec5SDimitry Andric           SDValue Elements = Int.getOperand(2);
4145647cbc5dSDimitry Andric           SDValue Size = CurDAG->getTargetConstant(Int.getConstantOperandVal(3),
4146647cbc5dSDimitry Andric                                                    dl, MVT::i32);
41470b57cec5SDimitry Andric 
41480b57cec5SDimitry Andric           SDValue Args[] = { Elements, Size, Int.getOperand(0) };
41490b57cec5SDimitry Andric           SDNode *LoopDec =
41500b57cec5SDimitry Andric             CurDAG->getMachineNode(ARM::t2LoopDec, dl,
41510b57cec5SDimitry Andric                                    CurDAG->getVTList(MVT::i32, MVT::Other),
41520b57cec5SDimitry Andric                                    Args);
41530b57cec5SDimitry Andric           ReplaceUses(Int.getNode(), LoopDec);
41540b57cec5SDimitry Andric 
41550b57cec5SDimitry Andric           SDValue EndArgs[] = { SDValue(LoopDec, 0), N1, Chain };
41560b57cec5SDimitry Andric           SDNode *LoopEnd =
41570b57cec5SDimitry Andric             CurDAG->getMachineNode(ARM::t2LoopEnd, dl, MVT::Other, EndArgs);
41580b57cec5SDimitry Andric 
41590b57cec5SDimitry Andric           ReplaceUses(N, LoopEnd);
41600b57cec5SDimitry Andric           CurDAG->RemoveDeadNode(N);
416106c3fb27SDimitry Andric           CurDAG->RemoveDeadNode(InGlue.getNode());
41620b57cec5SDimitry Andric           CurDAG->RemoveDeadNode(Int.getNode());
41630b57cec5SDimitry Andric           return;
41640b57cec5SDimitry Andric         }
41650b57cec5SDimitry Andric       }
41660b57cec5SDimitry Andric 
41670b57cec5SDimitry Andric       bool SwitchEQNEToPLMI;
416806c3fb27SDimitry Andric       SelectCMPZ(InGlue.getNode(), SwitchEQNEToPLMI);
416906c3fb27SDimitry Andric       InGlue = N->getOperand(4);
41700b57cec5SDimitry Andric 
41710b57cec5SDimitry Andric       if (SwitchEQNEToPLMI) {
41720b57cec5SDimitry Andric         switch ((ARMCC::CondCodes)CC) {
41730b57cec5SDimitry Andric         default: llvm_unreachable("CMPZ must be either NE or EQ!");
41740b57cec5SDimitry Andric         case ARMCC::NE:
41750b57cec5SDimitry Andric           CC = (unsigned)ARMCC::MI;
41760b57cec5SDimitry Andric           break;
41770b57cec5SDimitry Andric         case ARMCC::EQ:
41780b57cec5SDimitry Andric           CC = (unsigned)ARMCC::PL;
41790b57cec5SDimitry Andric           break;
41800b57cec5SDimitry Andric         }
41810b57cec5SDimitry Andric       }
41820b57cec5SDimitry Andric     }
41830b57cec5SDimitry Andric 
41840b57cec5SDimitry Andric     SDValue Tmp2 = CurDAG->getTargetConstant(CC, dl, MVT::i32);
418506c3fb27SDimitry Andric     SDValue Ops[] = { N1, Tmp2, N3, Chain, InGlue };
41860b57cec5SDimitry Andric     SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other,
41870b57cec5SDimitry Andric                                              MVT::Glue, Ops);
41880b57cec5SDimitry Andric     Chain = SDValue(ResNode, 0);
41890b57cec5SDimitry Andric     if (N->getNumValues() == 2) {
419006c3fb27SDimitry Andric       InGlue = SDValue(ResNode, 1);
419106c3fb27SDimitry Andric       ReplaceUses(SDValue(N, 1), InGlue);
41920b57cec5SDimitry Andric     }
41930b57cec5SDimitry Andric     ReplaceUses(SDValue(N, 0),
41940b57cec5SDimitry Andric                 SDValue(Chain.getNode(), Chain.getResNo()));
41950b57cec5SDimitry Andric     CurDAG->RemoveDeadNode(N);
41960b57cec5SDimitry Andric     return;
41970b57cec5SDimitry Andric   }
41980b57cec5SDimitry Andric 
41990b57cec5SDimitry Andric   case ARMISD::CMPZ: {
42000b57cec5SDimitry Andric     // select (CMPZ X, #-C) -> (CMPZ (ADDS X, #C), #0)
42010b57cec5SDimitry Andric     //   This allows us to avoid materializing the expensive negative constant.
42020b57cec5SDimitry Andric     //   The CMPZ #0 is useless and will be peepholed away but we need to keep it
42030b57cec5SDimitry Andric     //   for its glue output.
42040b57cec5SDimitry Andric     SDValue X = N->getOperand(0);
42050b57cec5SDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
42060b57cec5SDimitry Andric     if (C && C->getSExtValue() < 0 && Subtarget->isThumb()) {
42070b57cec5SDimitry Andric       int64_t Addend = -C->getSExtValue();
42080b57cec5SDimitry Andric 
42090b57cec5SDimitry Andric       SDNode *Add = nullptr;
42100b57cec5SDimitry Andric       // ADDS can be better than CMN if the immediate fits in a
42110b57cec5SDimitry Andric       // 16-bit ADDS, which means either [0,256) for tADDi8 or [0,8) for tADDi3.
42120b57cec5SDimitry Andric       // Outside that range we can just use a CMN which is 32-bit but has a
42130b57cec5SDimitry Andric       // 12-bit immediate range.
42140b57cec5SDimitry Andric       if (Addend < 1<<8) {
42150b57cec5SDimitry Andric         if (Subtarget->isThumb2()) {
42160b57cec5SDimitry Andric           SDValue Ops[] = { X, CurDAG->getTargetConstant(Addend, dl, MVT::i32),
42170b57cec5SDimitry Andric                             getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
42180b57cec5SDimitry Andric                             CurDAG->getRegister(0, MVT::i32) };
42190b57cec5SDimitry Andric           Add = CurDAG->getMachineNode(ARM::t2ADDri, dl, MVT::i32, Ops);
42200b57cec5SDimitry Andric         } else {
42210b57cec5SDimitry Andric           unsigned Opc = (Addend < 1<<3) ? ARM::tADDi3 : ARM::tADDi8;
42220b57cec5SDimitry Andric           SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
42230b57cec5SDimitry Andric                            CurDAG->getTargetConstant(Addend, dl, MVT::i32),
42240b57cec5SDimitry Andric                            getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
42250b57cec5SDimitry Andric           Add = CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
42260b57cec5SDimitry Andric         }
42270b57cec5SDimitry Andric       }
42280b57cec5SDimitry Andric       if (Add) {
42290b57cec5SDimitry Andric         SDValue Ops2[] = {SDValue(Add, 0), CurDAG->getConstant(0, dl, MVT::i32)};
42300b57cec5SDimitry Andric         CurDAG->MorphNodeTo(N, ARMISD::CMPZ, CurDAG->getVTList(MVT::Glue), Ops2);
42310b57cec5SDimitry Andric       }
42320b57cec5SDimitry Andric     }
42330b57cec5SDimitry Andric     // Other cases are autogenerated.
42340b57cec5SDimitry Andric     break;
42350b57cec5SDimitry Andric   }
42360b57cec5SDimitry Andric 
42370b57cec5SDimitry Andric   case ARMISD::CMOV: {
423806c3fb27SDimitry Andric     SDValue InGlue = N->getOperand(4);
42390b57cec5SDimitry Andric 
424006c3fb27SDimitry Andric     if (InGlue.getOpcode() == ARMISD::CMPZ) {
42410b57cec5SDimitry Andric       bool SwitchEQNEToPLMI;
424206c3fb27SDimitry Andric       SelectCMPZ(InGlue.getNode(), SwitchEQNEToPLMI);
42430b57cec5SDimitry Andric 
42440b57cec5SDimitry Andric       if (SwitchEQNEToPLMI) {
42450b57cec5SDimitry Andric         SDValue ARMcc = N->getOperand(2);
42461db9f3b2SDimitry Andric         ARMCC::CondCodes CC = (ARMCC::CondCodes)ARMcc->getAsZExtVal();
42470b57cec5SDimitry Andric 
42480b57cec5SDimitry Andric         switch (CC) {
42490b57cec5SDimitry Andric         default: llvm_unreachable("CMPZ must be either NE or EQ!");
42500b57cec5SDimitry Andric         case ARMCC::NE:
42510b57cec5SDimitry Andric           CC = ARMCC::MI;
42520b57cec5SDimitry Andric           break;
42530b57cec5SDimitry Andric         case ARMCC::EQ:
42540b57cec5SDimitry Andric           CC = ARMCC::PL;
42550b57cec5SDimitry Andric           break;
42560b57cec5SDimitry Andric         }
42570b57cec5SDimitry Andric         SDValue NewARMcc = CurDAG->getConstant((unsigned)CC, dl, MVT::i32);
42580b57cec5SDimitry Andric         SDValue Ops[] = {N->getOperand(0), N->getOperand(1), NewARMcc,
42590b57cec5SDimitry Andric                          N->getOperand(3), N->getOperand(4)};
42600b57cec5SDimitry Andric         CurDAG->MorphNodeTo(N, ARMISD::CMOV, N->getVTList(), Ops);
42610b57cec5SDimitry Andric       }
42620b57cec5SDimitry Andric 
42630b57cec5SDimitry Andric     }
42640b57cec5SDimitry Andric     // Other cases are autogenerated.
42650b57cec5SDimitry Andric     break;
42660b57cec5SDimitry Andric   }
42670b57cec5SDimitry Andric   case ARMISD::VZIP: {
42680b57cec5SDimitry Andric     EVT VT = N->getValueType(0);
42690b57cec5SDimitry Andric     // vzip.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm.
4270bdd1243dSDimitry Andric     unsigned Opc64[] = {ARM::VZIPd8, ARM::VZIPd16, ARM::VTRNd32};
4271bdd1243dSDimitry Andric     unsigned Opc128[] = {ARM::VZIPq8, ARM::VZIPq16, ARM::VZIPq32};
4272bdd1243dSDimitry Andric     unsigned Opc = getVectorShuffleOpcode(VT, Opc64, Opc128);
42730b57cec5SDimitry Andric     SDValue Pred = getAL(CurDAG, dl);
42740b57cec5SDimitry Andric     SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
42750b57cec5SDimitry Andric     SDValue Ops[] = {N->getOperand(0), N->getOperand(1), Pred, PredReg};
42760b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
42770b57cec5SDimitry Andric     return;
42780b57cec5SDimitry Andric   }
42790b57cec5SDimitry Andric   case ARMISD::VUZP: {
42800b57cec5SDimitry Andric     EVT VT = N->getValueType(0);
42810b57cec5SDimitry Andric     // vuzp.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm.
4282bdd1243dSDimitry Andric     unsigned Opc64[] = {ARM::VUZPd8, ARM::VUZPd16, ARM::VTRNd32};
4283bdd1243dSDimitry Andric     unsigned Opc128[] = {ARM::VUZPq8, ARM::VUZPq16, ARM::VUZPq32};
4284bdd1243dSDimitry Andric     unsigned Opc = getVectorShuffleOpcode(VT, Opc64, Opc128);
42850b57cec5SDimitry Andric     SDValue Pred = getAL(CurDAG, dl);
42860b57cec5SDimitry Andric     SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
42870b57cec5SDimitry Andric     SDValue Ops[] = {N->getOperand(0), N->getOperand(1), Pred, PredReg};
42880b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
42890b57cec5SDimitry Andric     return;
42900b57cec5SDimitry Andric   }
42910b57cec5SDimitry Andric   case ARMISD::VTRN: {
42920b57cec5SDimitry Andric     EVT VT = N->getValueType(0);
4293bdd1243dSDimitry Andric     unsigned Opc64[] = {ARM::VTRNd8, ARM::VTRNd16, ARM::VTRNd32};
4294bdd1243dSDimitry Andric     unsigned Opc128[] = {ARM::VTRNq8, ARM::VTRNq16, ARM::VTRNq32};
4295bdd1243dSDimitry Andric     unsigned Opc = getVectorShuffleOpcode(VT, Opc64, Opc128);
42960b57cec5SDimitry Andric     SDValue Pred = getAL(CurDAG, dl);
42970b57cec5SDimitry Andric     SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
42980b57cec5SDimitry Andric     SDValue Ops[] = {N->getOperand(0), N->getOperand(1), Pred, PredReg};
42990b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
43000b57cec5SDimitry Andric     return;
43010b57cec5SDimitry Andric   }
43020b57cec5SDimitry Andric   case ARMISD::BUILD_VECTOR: {
43030b57cec5SDimitry Andric     EVT VecVT = N->getValueType(0);
43040b57cec5SDimitry Andric     EVT EltVT = VecVT.getVectorElementType();
43050b57cec5SDimitry Andric     unsigned NumElts = VecVT.getVectorNumElements();
43060b57cec5SDimitry Andric     if (EltVT == MVT::f64) {
43070b57cec5SDimitry Andric       assert(NumElts == 2 && "unexpected type for BUILD_VECTOR");
43080b57cec5SDimitry Andric       ReplaceNode(
43090b57cec5SDimitry Andric           N, createDRegPairNode(VecVT, N->getOperand(0), N->getOperand(1)));
43100b57cec5SDimitry Andric       return;
43110b57cec5SDimitry Andric     }
43120b57cec5SDimitry Andric     assert(EltVT == MVT::f32 && "unexpected type for BUILD_VECTOR");
43130b57cec5SDimitry Andric     if (NumElts == 2) {
43140b57cec5SDimitry Andric       ReplaceNode(
43150b57cec5SDimitry Andric           N, createSRegPairNode(VecVT, N->getOperand(0), N->getOperand(1)));
43160b57cec5SDimitry Andric       return;
43170b57cec5SDimitry Andric     }
43180b57cec5SDimitry Andric     assert(NumElts == 4 && "unexpected type for BUILD_VECTOR");
43190b57cec5SDimitry Andric     ReplaceNode(N,
43200b57cec5SDimitry Andric                 createQuadSRegsNode(VecVT, N->getOperand(0), N->getOperand(1),
43210b57cec5SDimitry Andric                                     N->getOperand(2), N->getOperand(3)));
43220b57cec5SDimitry Andric     return;
43230b57cec5SDimitry Andric   }
43240b57cec5SDimitry Andric 
43250b57cec5SDimitry Andric   case ARMISD::VLD1DUP: {
43260b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD1DUPd8, ARM::VLD1DUPd16,
43270b57cec5SDimitry Andric                                          ARM::VLD1DUPd32 };
43280b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8, ARM::VLD1DUPq16,
43290b57cec5SDimitry Andric                                          ARM::VLD1DUPq32 };
43300b57cec5SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, false, 1, DOpcodes, QOpcodes);
43310b57cec5SDimitry Andric     return;
43320b57cec5SDimitry Andric   }
43330b57cec5SDimitry Andric 
43340b57cec5SDimitry Andric   case ARMISD::VLD2DUP: {
43350b57cec5SDimitry Andric     static const uint16_t Opcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
43360b57cec5SDimitry Andric                                         ARM::VLD2DUPd32 };
43370b57cec5SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, false, 2, Opcodes);
43380b57cec5SDimitry Andric     return;
43390b57cec5SDimitry Andric   }
43400b57cec5SDimitry Andric 
43410b57cec5SDimitry Andric   case ARMISD::VLD3DUP: {
43420b57cec5SDimitry Andric     static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo,
43430b57cec5SDimitry Andric                                         ARM::VLD3DUPd16Pseudo,
43440b57cec5SDimitry Andric                                         ARM::VLD3DUPd32Pseudo };
43450b57cec5SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, false, 3, Opcodes);
43460b57cec5SDimitry Andric     return;
43470b57cec5SDimitry Andric   }
43480b57cec5SDimitry Andric 
43490b57cec5SDimitry Andric   case ARMISD::VLD4DUP: {
43500b57cec5SDimitry Andric     static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo,
43510b57cec5SDimitry Andric                                         ARM::VLD4DUPd16Pseudo,
43520b57cec5SDimitry Andric                                         ARM::VLD4DUPd32Pseudo };
43530b57cec5SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, false, 4, Opcodes);
43540b57cec5SDimitry Andric     return;
43550b57cec5SDimitry Andric   }
43560b57cec5SDimitry Andric 
43570b57cec5SDimitry Andric   case ARMISD::VLD1DUP_UPD: {
43580b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD1DUPd8wb_fixed,
43590b57cec5SDimitry Andric                                          ARM::VLD1DUPd16wb_fixed,
43600b57cec5SDimitry Andric                                          ARM::VLD1DUPd32wb_fixed };
43610b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8wb_fixed,
43620b57cec5SDimitry Andric                                          ARM::VLD1DUPq16wb_fixed,
43630b57cec5SDimitry Andric                                          ARM::VLD1DUPq32wb_fixed };
43640b57cec5SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, true, 1, DOpcodes, QOpcodes);
43650b57cec5SDimitry Andric     return;
43660b57cec5SDimitry Andric   }
43670b57cec5SDimitry Andric 
43680b57cec5SDimitry Andric   case ARMISD::VLD2DUP_UPD: {
4369fe6060f1SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD2DUPd8wb_fixed,
43700b57cec5SDimitry Andric                                          ARM::VLD2DUPd16wb_fixed,
4371fe6060f1SDimitry Andric                                          ARM::VLD2DUPd32wb_fixed,
4372fe6060f1SDimitry Andric                                          ARM::VLD1q64wb_fixed };
4373fe6060f1SDimitry Andric     static const uint16_t QOpcodes0[] = { ARM::VLD2DUPq8EvenPseudo,
4374fe6060f1SDimitry Andric                                           ARM::VLD2DUPq16EvenPseudo,
4375fe6060f1SDimitry Andric                                           ARM::VLD2DUPq32EvenPseudo };
4376fe6060f1SDimitry Andric     static const uint16_t QOpcodes1[] = { ARM::VLD2DUPq8OddPseudoWB_fixed,
4377fe6060f1SDimitry Andric                                           ARM::VLD2DUPq16OddPseudoWB_fixed,
4378fe6060f1SDimitry Andric                                           ARM::VLD2DUPq32OddPseudoWB_fixed };
4379fe6060f1SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, true, 2, DOpcodes, QOpcodes0, QOpcodes1);
43800b57cec5SDimitry Andric     return;
43810b57cec5SDimitry Andric   }
43820b57cec5SDimitry Andric 
43830b57cec5SDimitry Andric   case ARMISD::VLD3DUP_UPD: {
4384fe6060f1SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD3DUPd8Pseudo_UPD,
43850b57cec5SDimitry Andric                                          ARM::VLD3DUPd16Pseudo_UPD,
4386fe6060f1SDimitry Andric                                          ARM::VLD3DUPd32Pseudo_UPD,
4387fe6060f1SDimitry Andric                                          ARM::VLD1d64TPseudoWB_fixed };
4388fe6060f1SDimitry Andric     static const uint16_t QOpcodes0[] = { ARM::VLD3DUPq8EvenPseudo,
4389fe6060f1SDimitry Andric                                           ARM::VLD3DUPq16EvenPseudo,
4390fe6060f1SDimitry Andric                                           ARM::VLD3DUPq32EvenPseudo };
4391fe6060f1SDimitry Andric     static const uint16_t QOpcodes1[] = { ARM::VLD3DUPq8OddPseudo_UPD,
4392fe6060f1SDimitry Andric                                           ARM::VLD3DUPq16OddPseudo_UPD,
4393fe6060f1SDimitry Andric                                           ARM::VLD3DUPq32OddPseudo_UPD };
4394fe6060f1SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
43950b57cec5SDimitry Andric     return;
43960b57cec5SDimitry Andric   }
43970b57cec5SDimitry Andric 
43980b57cec5SDimitry Andric   case ARMISD::VLD4DUP_UPD: {
4399fe6060f1SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD4DUPd8Pseudo_UPD,
44000b57cec5SDimitry Andric                                          ARM::VLD4DUPd16Pseudo_UPD,
4401fe6060f1SDimitry Andric                                          ARM::VLD4DUPd32Pseudo_UPD,
4402fe6060f1SDimitry Andric                                          ARM::VLD1d64QPseudoWB_fixed };
4403fe6060f1SDimitry Andric     static const uint16_t QOpcodes0[] = { ARM::VLD4DUPq8EvenPseudo,
4404fe6060f1SDimitry Andric                                           ARM::VLD4DUPq16EvenPseudo,
4405fe6060f1SDimitry Andric                                           ARM::VLD4DUPq32EvenPseudo };
4406fe6060f1SDimitry Andric     static const uint16_t QOpcodes1[] = { ARM::VLD4DUPq8OddPseudo_UPD,
4407fe6060f1SDimitry Andric                                           ARM::VLD4DUPq16OddPseudo_UPD,
4408fe6060f1SDimitry Andric                                           ARM::VLD4DUPq32OddPseudo_UPD };
4409fe6060f1SDimitry Andric     SelectVLDDup(N, /* IsIntrinsic= */ false, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
44100b57cec5SDimitry Andric     return;
44110b57cec5SDimitry Andric   }
44120b57cec5SDimitry Andric 
44130b57cec5SDimitry Andric   case ARMISD::VLD1_UPD: {
44140b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD1d8wb_fixed,
44150b57cec5SDimitry Andric                                          ARM::VLD1d16wb_fixed,
44160b57cec5SDimitry Andric                                          ARM::VLD1d32wb_fixed,
44170b57cec5SDimitry Andric                                          ARM::VLD1d64wb_fixed };
44180b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VLD1q8wb_fixed,
44190b57cec5SDimitry Andric                                          ARM::VLD1q16wb_fixed,
44200b57cec5SDimitry Andric                                          ARM::VLD1q32wb_fixed,
44210b57cec5SDimitry Andric                                          ARM::VLD1q64wb_fixed };
44220b57cec5SDimitry Andric     SelectVLD(N, true, 1, DOpcodes, QOpcodes, nullptr);
44230b57cec5SDimitry Andric     return;
44240b57cec5SDimitry Andric   }
44250b57cec5SDimitry Andric 
44260b57cec5SDimitry Andric   case ARMISD::VLD2_UPD: {
44275ffd83dbSDimitry Andric     if (Subtarget->hasNEON()) {
44285ffd83dbSDimitry Andric       static const uint16_t DOpcodes[] = {
44295ffd83dbSDimitry Andric           ARM::VLD2d8wb_fixed, ARM::VLD2d16wb_fixed, ARM::VLD2d32wb_fixed,
44300b57cec5SDimitry Andric           ARM::VLD1q64wb_fixed};
44310b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = {ARM::VLD2q8PseudoWB_fixed,
44320b57cec5SDimitry Andric                                           ARM::VLD2q16PseudoWB_fixed,
44330b57cec5SDimitry Andric                                           ARM::VLD2q32PseudoWB_fixed};
44340b57cec5SDimitry Andric       SelectVLD(N, true, 2, DOpcodes, QOpcodes, nullptr);
44355ffd83dbSDimitry Andric     } else {
44365ffd83dbSDimitry Andric       static const uint16_t Opcodes8[] = {ARM::MVE_VLD20_8,
44375ffd83dbSDimitry Andric                                           ARM::MVE_VLD21_8_wb};
44385ffd83dbSDimitry Andric       static const uint16_t Opcodes16[] = {ARM::MVE_VLD20_16,
44395ffd83dbSDimitry Andric                                            ARM::MVE_VLD21_16_wb};
44405ffd83dbSDimitry Andric       static const uint16_t Opcodes32[] = {ARM::MVE_VLD20_32,
44415ffd83dbSDimitry Andric                                            ARM::MVE_VLD21_32_wb};
44425ffd83dbSDimitry Andric       static const uint16_t *const Opcodes[] = {Opcodes8, Opcodes16, Opcodes32};
44435ffd83dbSDimitry Andric       SelectMVE_VLD(N, 2, Opcodes, true);
44445ffd83dbSDimitry Andric     }
44450b57cec5SDimitry Andric     return;
44460b57cec5SDimitry Andric   }
44470b57cec5SDimitry Andric 
44480b57cec5SDimitry Andric   case ARMISD::VLD3_UPD: {
44490b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo_UPD,
44500b57cec5SDimitry Andric                                          ARM::VLD3d16Pseudo_UPD,
44510b57cec5SDimitry Andric                                          ARM::VLD3d32Pseudo_UPD,
44520b57cec5SDimitry Andric                                          ARM::VLD1d64TPseudoWB_fixed};
44530b57cec5SDimitry Andric     static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD,
44540b57cec5SDimitry Andric                                           ARM::VLD3q16Pseudo_UPD,
44550b57cec5SDimitry Andric                                           ARM::VLD3q32Pseudo_UPD };
44560b57cec5SDimitry Andric     static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD,
44570b57cec5SDimitry Andric                                           ARM::VLD3q16oddPseudo_UPD,
44580b57cec5SDimitry Andric                                           ARM::VLD3q32oddPseudo_UPD };
44590b57cec5SDimitry Andric     SelectVLD(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
44600b57cec5SDimitry Andric     return;
44610b57cec5SDimitry Andric   }
44620b57cec5SDimitry Andric 
44630b57cec5SDimitry Andric   case ARMISD::VLD4_UPD: {
44645ffd83dbSDimitry Andric     if (Subtarget->hasNEON()) {
44655ffd83dbSDimitry Andric       static const uint16_t DOpcodes[] = {
44665ffd83dbSDimitry Andric           ARM::VLD4d8Pseudo_UPD, ARM::VLD4d16Pseudo_UPD, ARM::VLD4d32Pseudo_UPD,
44670b57cec5SDimitry Andric           ARM::VLD1d64QPseudoWB_fixed};
44680b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = {ARM::VLD4q8Pseudo_UPD,
44690b57cec5SDimitry Andric                                            ARM::VLD4q16Pseudo_UPD,
44700b57cec5SDimitry Andric                                            ARM::VLD4q32Pseudo_UPD};
44710b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = {ARM::VLD4q8oddPseudo_UPD,
44720b57cec5SDimitry Andric                                            ARM::VLD4q16oddPseudo_UPD,
44730b57cec5SDimitry Andric                                            ARM::VLD4q32oddPseudo_UPD};
44740b57cec5SDimitry Andric       SelectVLD(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
44755ffd83dbSDimitry Andric     } else {
44765ffd83dbSDimitry Andric       static const uint16_t Opcodes8[] = {ARM::MVE_VLD40_8, ARM::MVE_VLD41_8,
44775ffd83dbSDimitry Andric                                           ARM::MVE_VLD42_8,
44785ffd83dbSDimitry Andric                                           ARM::MVE_VLD43_8_wb};
44795ffd83dbSDimitry Andric       static const uint16_t Opcodes16[] = {ARM::MVE_VLD40_16, ARM::MVE_VLD41_16,
44805ffd83dbSDimitry Andric                                            ARM::MVE_VLD42_16,
44815ffd83dbSDimitry Andric                                            ARM::MVE_VLD43_16_wb};
44825ffd83dbSDimitry Andric       static const uint16_t Opcodes32[] = {ARM::MVE_VLD40_32, ARM::MVE_VLD41_32,
44835ffd83dbSDimitry Andric                                            ARM::MVE_VLD42_32,
44845ffd83dbSDimitry Andric                                            ARM::MVE_VLD43_32_wb};
44855ffd83dbSDimitry Andric       static const uint16_t *const Opcodes[] = {Opcodes8, Opcodes16, Opcodes32};
44865ffd83dbSDimitry Andric       SelectMVE_VLD(N, 4, Opcodes, true);
44875ffd83dbSDimitry Andric     }
44880b57cec5SDimitry Andric     return;
44890b57cec5SDimitry Andric   }
44900b57cec5SDimitry Andric 
4491fe6060f1SDimitry Andric   case ARMISD::VLD1x2_UPD: {
4492fe6060f1SDimitry Andric     if (Subtarget->hasNEON()) {
4493fe6060f1SDimitry Andric       static const uint16_t DOpcodes[] = {
4494fe6060f1SDimitry Andric           ARM::VLD1q8wb_fixed, ARM::VLD1q16wb_fixed, ARM::VLD1q32wb_fixed,
4495fe6060f1SDimitry Andric           ARM::VLD1q64wb_fixed};
4496fe6060f1SDimitry Andric       static const uint16_t QOpcodes[] = {
4497fe6060f1SDimitry Andric           ARM::VLD1d8QPseudoWB_fixed, ARM::VLD1d16QPseudoWB_fixed,
4498fe6060f1SDimitry Andric           ARM::VLD1d32QPseudoWB_fixed, ARM::VLD1d64QPseudoWB_fixed};
4499fe6060f1SDimitry Andric       SelectVLD(N, true, 2, DOpcodes, QOpcodes, nullptr);
4500fe6060f1SDimitry Andric       return;
4501fe6060f1SDimitry Andric     }
4502fe6060f1SDimitry Andric     break;
4503fe6060f1SDimitry Andric   }
4504fe6060f1SDimitry Andric 
4505fe6060f1SDimitry Andric   case ARMISD::VLD1x3_UPD: {
4506fe6060f1SDimitry Andric     if (Subtarget->hasNEON()) {
4507fe6060f1SDimitry Andric       static const uint16_t DOpcodes[] = {
4508fe6060f1SDimitry Andric           ARM::VLD1d8TPseudoWB_fixed, ARM::VLD1d16TPseudoWB_fixed,
4509fe6060f1SDimitry Andric           ARM::VLD1d32TPseudoWB_fixed, ARM::VLD1d64TPseudoWB_fixed};
4510fe6060f1SDimitry Andric       static const uint16_t QOpcodes0[] = {
4511fe6060f1SDimitry Andric           ARM::VLD1q8LowTPseudo_UPD, ARM::VLD1q16LowTPseudo_UPD,
4512fe6060f1SDimitry Andric           ARM::VLD1q32LowTPseudo_UPD, ARM::VLD1q64LowTPseudo_UPD};
4513fe6060f1SDimitry Andric       static const uint16_t QOpcodes1[] = {
4514fe6060f1SDimitry Andric           ARM::VLD1q8HighTPseudo_UPD, ARM::VLD1q16HighTPseudo_UPD,
4515fe6060f1SDimitry Andric           ARM::VLD1q32HighTPseudo_UPD, ARM::VLD1q64HighTPseudo_UPD};
4516fe6060f1SDimitry Andric       SelectVLD(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
4517fe6060f1SDimitry Andric       return;
4518fe6060f1SDimitry Andric     }
4519fe6060f1SDimitry Andric     break;
4520fe6060f1SDimitry Andric   }
4521fe6060f1SDimitry Andric 
4522fe6060f1SDimitry Andric   case ARMISD::VLD1x4_UPD: {
4523fe6060f1SDimitry Andric     if (Subtarget->hasNEON()) {
4524fe6060f1SDimitry Andric       static const uint16_t DOpcodes[] = {
4525fe6060f1SDimitry Andric           ARM::VLD1d8QPseudoWB_fixed, ARM::VLD1d16QPseudoWB_fixed,
4526fe6060f1SDimitry Andric           ARM::VLD1d32QPseudoWB_fixed, ARM::VLD1d64QPseudoWB_fixed};
4527fe6060f1SDimitry Andric       static const uint16_t QOpcodes0[] = {
4528fe6060f1SDimitry Andric           ARM::VLD1q8LowQPseudo_UPD, ARM::VLD1q16LowQPseudo_UPD,
4529fe6060f1SDimitry Andric           ARM::VLD1q32LowQPseudo_UPD, ARM::VLD1q64LowQPseudo_UPD};
4530fe6060f1SDimitry Andric       static const uint16_t QOpcodes1[] = {
4531fe6060f1SDimitry Andric           ARM::VLD1q8HighQPseudo_UPD, ARM::VLD1q16HighQPseudo_UPD,
4532fe6060f1SDimitry Andric           ARM::VLD1q32HighQPseudo_UPD, ARM::VLD1q64HighQPseudo_UPD};
4533fe6060f1SDimitry Andric       SelectVLD(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
4534fe6060f1SDimitry Andric       return;
4535fe6060f1SDimitry Andric     }
4536fe6060f1SDimitry Andric     break;
4537fe6060f1SDimitry Andric   }
4538fe6060f1SDimitry Andric 
45390b57cec5SDimitry Andric   case ARMISD::VLD2LN_UPD: {
45400b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo_UPD,
45410b57cec5SDimitry Andric                                          ARM::VLD2LNd16Pseudo_UPD,
45420b57cec5SDimitry Andric                                          ARM::VLD2LNd32Pseudo_UPD };
45430b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo_UPD,
45440b57cec5SDimitry Andric                                          ARM::VLD2LNq32Pseudo_UPD };
45450b57cec5SDimitry Andric     SelectVLDSTLane(N, true, true, 2, DOpcodes, QOpcodes);
45460b57cec5SDimitry Andric     return;
45470b57cec5SDimitry Andric   }
45480b57cec5SDimitry Andric 
45490b57cec5SDimitry Andric   case ARMISD::VLD3LN_UPD: {
45500b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo_UPD,
45510b57cec5SDimitry Andric                                          ARM::VLD3LNd16Pseudo_UPD,
45520b57cec5SDimitry Andric                                          ARM::VLD3LNd32Pseudo_UPD };
45530b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo_UPD,
45540b57cec5SDimitry Andric                                          ARM::VLD3LNq32Pseudo_UPD };
45550b57cec5SDimitry Andric     SelectVLDSTLane(N, true, true, 3, DOpcodes, QOpcodes);
45560b57cec5SDimitry Andric     return;
45570b57cec5SDimitry Andric   }
45580b57cec5SDimitry Andric 
45590b57cec5SDimitry Andric   case ARMISD::VLD4LN_UPD: {
45600b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo_UPD,
45610b57cec5SDimitry Andric                                          ARM::VLD4LNd16Pseudo_UPD,
45620b57cec5SDimitry Andric                                          ARM::VLD4LNd32Pseudo_UPD };
45630b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo_UPD,
45640b57cec5SDimitry Andric                                          ARM::VLD4LNq32Pseudo_UPD };
45650b57cec5SDimitry Andric     SelectVLDSTLane(N, true, true, 4, DOpcodes, QOpcodes);
45660b57cec5SDimitry Andric     return;
45670b57cec5SDimitry Andric   }
45680b57cec5SDimitry Andric 
45690b57cec5SDimitry Andric   case ARMISD::VST1_UPD: {
45700b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VST1d8wb_fixed,
45710b57cec5SDimitry Andric                                          ARM::VST1d16wb_fixed,
45720b57cec5SDimitry Andric                                          ARM::VST1d32wb_fixed,
45730b57cec5SDimitry Andric                                          ARM::VST1d64wb_fixed };
45740b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VST1q8wb_fixed,
45750b57cec5SDimitry Andric                                          ARM::VST1q16wb_fixed,
45760b57cec5SDimitry Andric                                          ARM::VST1q32wb_fixed,
45770b57cec5SDimitry Andric                                          ARM::VST1q64wb_fixed };
45780b57cec5SDimitry Andric     SelectVST(N, true, 1, DOpcodes, QOpcodes, nullptr);
45790b57cec5SDimitry Andric     return;
45800b57cec5SDimitry Andric   }
45810b57cec5SDimitry Andric 
45820b57cec5SDimitry Andric   case ARMISD::VST2_UPD: {
45835ffd83dbSDimitry Andric     if (Subtarget->hasNEON()) {
45845ffd83dbSDimitry Andric       static const uint16_t DOpcodes[] = {
45855ffd83dbSDimitry Andric           ARM::VST2d8wb_fixed, ARM::VST2d16wb_fixed, ARM::VST2d32wb_fixed,
45860b57cec5SDimitry Andric           ARM::VST1q64wb_fixed};
45870b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = {ARM::VST2q8PseudoWB_fixed,
45880b57cec5SDimitry Andric                                           ARM::VST2q16PseudoWB_fixed,
45890b57cec5SDimitry Andric                                           ARM::VST2q32PseudoWB_fixed};
45900b57cec5SDimitry Andric       SelectVST(N, true, 2, DOpcodes, QOpcodes, nullptr);
45910b57cec5SDimitry Andric       return;
45920b57cec5SDimitry Andric     }
45935ffd83dbSDimitry Andric     break;
45945ffd83dbSDimitry Andric   }
45950b57cec5SDimitry Andric 
45960b57cec5SDimitry Andric   case ARMISD::VST3_UPD: {
45970b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo_UPD,
45980b57cec5SDimitry Andric                                          ARM::VST3d16Pseudo_UPD,
45990b57cec5SDimitry Andric                                          ARM::VST3d32Pseudo_UPD,
46000b57cec5SDimitry Andric                                          ARM::VST1d64TPseudoWB_fixed};
46010b57cec5SDimitry Andric     static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD,
46020b57cec5SDimitry Andric                                           ARM::VST3q16Pseudo_UPD,
46030b57cec5SDimitry Andric                                           ARM::VST3q32Pseudo_UPD };
46040b57cec5SDimitry Andric     static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD,
46050b57cec5SDimitry Andric                                           ARM::VST3q16oddPseudo_UPD,
46060b57cec5SDimitry Andric                                           ARM::VST3q32oddPseudo_UPD };
46070b57cec5SDimitry Andric     SelectVST(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
46080b57cec5SDimitry Andric     return;
46090b57cec5SDimitry Andric   }
46100b57cec5SDimitry Andric 
46110b57cec5SDimitry Andric   case ARMISD::VST4_UPD: {
46125ffd83dbSDimitry Andric     if (Subtarget->hasNEON()) {
46135ffd83dbSDimitry Andric       static const uint16_t DOpcodes[] = {
46145ffd83dbSDimitry Andric           ARM::VST4d8Pseudo_UPD, ARM::VST4d16Pseudo_UPD, ARM::VST4d32Pseudo_UPD,
46150b57cec5SDimitry Andric           ARM::VST1d64QPseudoWB_fixed};
46160b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = {ARM::VST4q8Pseudo_UPD,
46170b57cec5SDimitry Andric                                            ARM::VST4q16Pseudo_UPD,
46180b57cec5SDimitry Andric                                            ARM::VST4q32Pseudo_UPD};
46190b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = {ARM::VST4q8oddPseudo_UPD,
46200b57cec5SDimitry Andric                                            ARM::VST4q16oddPseudo_UPD,
46210b57cec5SDimitry Andric                                            ARM::VST4q32oddPseudo_UPD};
46220b57cec5SDimitry Andric       SelectVST(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
46230b57cec5SDimitry Andric       return;
46240b57cec5SDimitry Andric     }
46255ffd83dbSDimitry Andric     break;
46265ffd83dbSDimitry Andric   }
46270b57cec5SDimitry Andric 
4628fe6060f1SDimitry Andric   case ARMISD::VST1x2_UPD: {
4629fe6060f1SDimitry Andric     if (Subtarget->hasNEON()) {
4630fe6060f1SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1q8wb_fixed,
4631fe6060f1SDimitry Andric                                            ARM::VST1q16wb_fixed,
4632fe6060f1SDimitry Andric                                            ARM::VST1q32wb_fixed,
4633fe6060f1SDimitry Andric                                            ARM::VST1q64wb_fixed};
4634fe6060f1SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST1d8QPseudoWB_fixed,
4635fe6060f1SDimitry Andric                                            ARM::VST1d16QPseudoWB_fixed,
4636fe6060f1SDimitry Andric                                            ARM::VST1d32QPseudoWB_fixed,
4637fe6060f1SDimitry Andric                                            ARM::VST1d64QPseudoWB_fixed };
4638fe6060f1SDimitry Andric       SelectVST(N, true, 2, DOpcodes, QOpcodes, nullptr);
4639fe6060f1SDimitry Andric       return;
4640fe6060f1SDimitry Andric     }
4641fe6060f1SDimitry Andric     break;
4642fe6060f1SDimitry Andric   }
4643fe6060f1SDimitry Andric 
4644fe6060f1SDimitry Andric   case ARMISD::VST1x3_UPD: {
4645fe6060f1SDimitry Andric     if (Subtarget->hasNEON()) {
4646fe6060f1SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1d8TPseudoWB_fixed,
4647fe6060f1SDimitry Andric                                            ARM::VST1d16TPseudoWB_fixed,
4648fe6060f1SDimitry Andric                                            ARM::VST1d32TPseudoWB_fixed,
4649fe6060f1SDimitry Andric                                            ARM::VST1d64TPseudoWB_fixed };
4650fe6060f1SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VST1q8LowTPseudo_UPD,
4651fe6060f1SDimitry Andric                                             ARM::VST1q16LowTPseudo_UPD,
4652fe6060f1SDimitry Andric                                             ARM::VST1q32LowTPseudo_UPD,
4653fe6060f1SDimitry Andric                                             ARM::VST1q64LowTPseudo_UPD };
4654fe6060f1SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VST1q8HighTPseudo_UPD,
4655fe6060f1SDimitry Andric                                             ARM::VST1q16HighTPseudo_UPD,
4656fe6060f1SDimitry Andric                                             ARM::VST1q32HighTPseudo_UPD,
4657fe6060f1SDimitry Andric                                             ARM::VST1q64HighTPseudo_UPD };
4658fe6060f1SDimitry Andric       SelectVST(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
4659fe6060f1SDimitry Andric       return;
4660fe6060f1SDimitry Andric     }
4661fe6060f1SDimitry Andric     break;
4662fe6060f1SDimitry Andric   }
4663fe6060f1SDimitry Andric 
4664fe6060f1SDimitry Andric   case ARMISD::VST1x4_UPD: {
4665fe6060f1SDimitry Andric     if (Subtarget->hasNEON()) {
4666fe6060f1SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1d8QPseudoWB_fixed,
4667fe6060f1SDimitry Andric                                            ARM::VST1d16QPseudoWB_fixed,
4668fe6060f1SDimitry Andric                                            ARM::VST1d32QPseudoWB_fixed,
4669fe6060f1SDimitry Andric                                            ARM::VST1d64QPseudoWB_fixed };
4670fe6060f1SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VST1q8LowQPseudo_UPD,
4671fe6060f1SDimitry Andric                                             ARM::VST1q16LowQPseudo_UPD,
4672fe6060f1SDimitry Andric                                             ARM::VST1q32LowQPseudo_UPD,
4673fe6060f1SDimitry Andric                                             ARM::VST1q64LowQPseudo_UPD };
4674fe6060f1SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VST1q8HighQPseudo_UPD,
4675fe6060f1SDimitry Andric                                             ARM::VST1q16HighQPseudo_UPD,
4676fe6060f1SDimitry Andric                                             ARM::VST1q32HighQPseudo_UPD,
4677fe6060f1SDimitry Andric                                             ARM::VST1q64HighQPseudo_UPD };
4678fe6060f1SDimitry Andric       SelectVST(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
4679fe6060f1SDimitry Andric       return;
4680fe6060f1SDimitry Andric     }
4681fe6060f1SDimitry Andric     break;
4682fe6060f1SDimitry Andric   }
46830b57cec5SDimitry Andric   case ARMISD::VST2LN_UPD: {
46840b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo_UPD,
46850b57cec5SDimitry Andric                                          ARM::VST2LNd16Pseudo_UPD,
46860b57cec5SDimitry Andric                                          ARM::VST2LNd32Pseudo_UPD };
46870b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo_UPD,
46880b57cec5SDimitry Andric                                          ARM::VST2LNq32Pseudo_UPD };
46890b57cec5SDimitry Andric     SelectVLDSTLane(N, false, true, 2, DOpcodes, QOpcodes);
46900b57cec5SDimitry Andric     return;
46910b57cec5SDimitry Andric   }
46920b57cec5SDimitry Andric 
46930b57cec5SDimitry Andric   case ARMISD::VST3LN_UPD: {
46940b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo_UPD,
46950b57cec5SDimitry Andric                                          ARM::VST3LNd16Pseudo_UPD,
46960b57cec5SDimitry Andric                                          ARM::VST3LNd32Pseudo_UPD };
46970b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo_UPD,
46980b57cec5SDimitry Andric                                          ARM::VST3LNq32Pseudo_UPD };
46990b57cec5SDimitry Andric     SelectVLDSTLane(N, false, true, 3, DOpcodes, QOpcodes);
47000b57cec5SDimitry Andric     return;
47010b57cec5SDimitry Andric   }
47020b57cec5SDimitry Andric 
47030b57cec5SDimitry Andric   case ARMISD::VST4LN_UPD: {
47040b57cec5SDimitry Andric     static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo_UPD,
47050b57cec5SDimitry Andric                                          ARM::VST4LNd16Pseudo_UPD,
47060b57cec5SDimitry Andric                                          ARM::VST4LNd32Pseudo_UPD };
47070b57cec5SDimitry Andric     static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo_UPD,
47080b57cec5SDimitry Andric                                          ARM::VST4LNq32Pseudo_UPD };
47090b57cec5SDimitry Andric     SelectVLDSTLane(N, false, true, 4, DOpcodes, QOpcodes);
47100b57cec5SDimitry Andric     return;
47110b57cec5SDimitry Andric   }
47120b57cec5SDimitry Andric 
47130b57cec5SDimitry Andric   case ISD::INTRINSIC_VOID:
47140b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
4715647cbc5dSDimitry Andric     unsigned IntNo = N->getConstantOperandVal(1);
47160b57cec5SDimitry Andric     switch (IntNo) {
47170b57cec5SDimitry Andric     default:
47180b57cec5SDimitry Andric       break;
47190b57cec5SDimitry Andric 
47200b57cec5SDimitry Andric     case Intrinsic::arm_mrrc:
47210b57cec5SDimitry Andric     case Intrinsic::arm_mrrc2: {
47220b57cec5SDimitry Andric       SDLoc dl(N);
47230b57cec5SDimitry Andric       SDValue Chain = N->getOperand(0);
47240b57cec5SDimitry Andric       unsigned Opc;
47250b57cec5SDimitry Andric 
47260b57cec5SDimitry Andric       if (Subtarget->isThumb())
47270b57cec5SDimitry Andric         Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::t2MRRC : ARM::t2MRRC2);
47280b57cec5SDimitry Andric       else
47290b57cec5SDimitry Andric         Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::MRRC : ARM::MRRC2);
47300b57cec5SDimitry Andric 
47310b57cec5SDimitry Andric       SmallVector<SDValue, 5> Ops;
4732647cbc5dSDimitry Andric       Ops.push_back(getI32Imm(N->getConstantOperandVal(2), dl)); /* coproc */
4733647cbc5dSDimitry Andric       Ops.push_back(getI32Imm(N->getConstantOperandVal(3), dl)); /* opc */
4734647cbc5dSDimitry Andric       Ops.push_back(getI32Imm(N->getConstantOperandVal(4), dl)); /* CRm */
47350b57cec5SDimitry Andric 
47360b57cec5SDimitry Andric       // The mrrc2 instruction in ARM doesn't allow predicates, the top 4 bits of the encoded
47370b57cec5SDimitry Andric       // instruction will always be '1111' but it is possible in assembly language to specify
47380b57cec5SDimitry Andric       // AL as a predicate to mrrc2 but it doesn't make any difference to the encoded instruction.
47390b57cec5SDimitry Andric       if (Opc != ARM::MRRC2) {
47400b57cec5SDimitry Andric         Ops.push_back(getAL(CurDAG, dl));
47410b57cec5SDimitry Andric         Ops.push_back(CurDAG->getRegister(0, MVT::i32));
47420b57cec5SDimitry Andric       }
47430b57cec5SDimitry Andric 
47440b57cec5SDimitry Andric       Ops.push_back(Chain);
47450b57cec5SDimitry Andric 
47460b57cec5SDimitry Andric       // Writes to two registers.
47470b57cec5SDimitry Andric       const EVT RetType[] = {MVT::i32, MVT::i32, MVT::Other};
47480b57cec5SDimitry Andric 
47490b57cec5SDimitry Andric       ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, RetType, Ops));
47500b57cec5SDimitry Andric       return;
47510b57cec5SDimitry Andric     }
47520b57cec5SDimitry Andric     case Intrinsic::arm_ldaexd:
47530b57cec5SDimitry Andric     case Intrinsic::arm_ldrexd: {
47540b57cec5SDimitry Andric       SDLoc dl(N);
47550b57cec5SDimitry Andric       SDValue Chain = N->getOperand(0);
47560b57cec5SDimitry Andric       SDValue MemAddr = N->getOperand(2);
47570b57cec5SDimitry Andric       bool isThumb = Subtarget->isThumb() && Subtarget->hasV8MBaselineOps();
47580b57cec5SDimitry Andric 
47590b57cec5SDimitry Andric       bool IsAcquire = IntNo == Intrinsic::arm_ldaexd;
47600b57cec5SDimitry Andric       unsigned NewOpc = isThumb ? (IsAcquire ? ARM::t2LDAEXD : ARM::t2LDREXD)
47610b57cec5SDimitry Andric                                 : (IsAcquire ? ARM::LDAEXD : ARM::LDREXD);
47620b57cec5SDimitry Andric 
47630b57cec5SDimitry Andric       // arm_ldrexd returns a i64 value in {i32, i32}
47640b57cec5SDimitry Andric       std::vector<EVT> ResTys;
47650b57cec5SDimitry Andric       if (isThumb) {
47660b57cec5SDimitry Andric         ResTys.push_back(MVT::i32);
47670b57cec5SDimitry Andric         ResTys.push_back(MVT::i32);
47680b57cec5SDimitry Andric       } else
47690b57cec5SDimitry Andric         ResTys.push_back(MVT::Untyped);
47700b57cec5SDimitry Andric       ResTys.push_back(MVT::Other);
47710b57cec5SDimitry Andric 
47720b57cec5SDimitry Andric       // Place arguments in the right order.
47730b57cec5SDimitry Andric       SDValue Ops[] = {MemAddr, getAL(CurDAG, dl),
47740b57cec5SDimitry Andric                        CurDAG->getRegister(0, MVT::i32), Chain};
47750b57cec5SDimitry Andric       SDNode *Ld = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
47760b57cec5SDimitry Andric       // Transfer memoperands.
47770b57cec5SDimitry Andric       MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
47780b57cec5SDimitry Andric       CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp});
47790b57cec5SDimitry Andric 
47800b57cec5SDimitry Andric       // Remap uses.
47810b57cec5SDimitry Andric       SDValue OutChain = isThumb ? SDValue(Ld, 2) : SDValue(Ld, 1);
47820b57cec5SDimitry Andric       if (!SDValue(N, 0).use_empty()) {
47830b57cec5SDimitry Andric         SDValue Result;
47840b57cec5SDimitry Andric         if (isThumb)
47850b57cec5SDimitry Andric           Result = SDValue(Ld, 0);
47860b57cec5SDimitry Andric         else {
47870b57cec5SDimitry Andric           SDValue SubRegIdx =
47880b57cec5SDimitry Andric             CurDAG->getTargetConstant(ARM::gsub_0, dl, MVT::i32);
47890b57cec5SDimitry Andric           SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
47900b57cec5SDimitry Andric               dl, MVT::i32, SDValue(Ld, 0), SubRegIdx);
47910b57cec5SDimitry Andric           Result = SDValue(ResNode,0);
47920b57cec5SDimitry Andric         }
47930b57cec5SDimitry Andric         ReplaceUses(SDValue(N, 0), Result);
47940b57cec5SDimitry Andric       }
47950b57cec5SDimitry Andric       if (!SDValue(N, 1).use_empty()) {
47960b57cec5SDimitry Andric         SDValue Result;
47970b57cec5SDimitry Andric         if (isThumb)
47980b57cec5SDimitry Andric           Result = SDValue(Ld, 1);
47990b57cec5SDimitry Andric         else {
48000b57cec5SDimitry Andric           SDValue SubRegIdx =
48010b57cec5SDimitry Andric             CurDAG->getTargetConstant(ARM::gsub_1, dl, MVT::i32);
48020b57cec5SDimitry Andric           SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
48030b57cec5SDimitry Andric               dl, MVT::i32, SDValue(Ld, 0), SubRegIdx);
48040b57cec5SDimitry Andric           Result = SDValue(ResNode,0);
48050b57cec5SDimitry Andric         }
48060b57cec5SDimitry Andric         ReplaceUses(SDValue(N, 1), Result);
48070b57cec5SDimitry Andric       }
48080b57cec5SDimitry Andric       ReplaceUses(SDValue(N, 2), OutChain);
48090b57cec5SDimitry Andric       CurDAG->RemoveDeadNode(N);
48100b57cec5SDimitry Andric       return;
48110b57cec5SDimitry Andric     }
48120b57cec5SDimitry Andric     case Intrinsic::arm_stlexd:
48130b57cec5SDimitry Andric     case Intrinsic::arm_strexd: {
48140b57cec5SDimitry Andric       SDLoc dl(N);
48150b57cec5SDimitry Andric       SDValue Chain = N->getOperand(0);
48160b57cec5SDimitry Andric       SDValue Val0 = N->getOperand(2);
48170b57cec5SDimitry Andric       SDValue Val1 = N->getOperand(3);
48180b57cec5SDimitry Andric       SDValue MemAddr = N->getOperand(4);
48190b57cec5SDimitry Andric 
48200b57cec5SDimitry Andric       // Store exclusive double return a i32 value which is the return status
48210b57cec5SDimitry Andric       // of the issued store.
48220b57cec5SDimitry Andric       const EVT ResTys[] = {MVT::i32, MVT::Other};
48230b57cec5SDimitry Andric 
48240b57cec5SDimitry Andric       bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
48250b57cec5SDimitry Andric       // Place arguments in the right order.
48260b57cec5SDimitry Andric       SmallVector<SDValue, 7> Ops;
48270b57cec5SDimitry Andric       if (isThumb) {
48280b57cec5SDimitry Andric         Ops.push_back(Val0);
48290b57cec5SDimitry Andric         Ops.push_back(Val1);
48300b57cec5SDimitry Andric       } else
48310b57cec5SDimitry Andric         // arm_strexd uses GPRPair.
48320b57cec5SDimitry Andric         Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, Val0, Val1), 0));
48330b57cec5SDimitry Andric       Ops.push_back(MemAddr);
48340b57cec5SDimitry Andric       Ops.push_back(getAL(CurDAG, dl));
48350b57cec5SDimitry Andric       Ops.push_back(CurDAG->getRegister(0, MVT::i32));
48360b57cec5SDimitry Andric       Ops.push_back(Chain);
48370b57cec5SDimitry Andric 
48380b57cec5SDimitry Andric       bool IsRelease = IntNo == Intrinsic::arm_stlexd;
48390b57cec5SDimitry Andric       unsigned NewOpc = isThumb ? (IsRelease ? ARM::t2STLEXD : ARM::t2STREXD)
48400b57cec5SDimitry Andric                                 : (IsRelease ? ARM::STLEXD : ARM::STREXD);
48410b57cec5SDimitry Andric 
48420b57cec5SDimitry Andric       SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
48430b57cec5SDimitry Andric       // Transfer memoperands.
48440b57cec5SDimitry Andric       MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
48450b57cec5SDimitry Andric       CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
48460b57cec5SDimitry Andric 
48470b57cec5SDimitry Andric       ReplaceNode(N, St);
48480b57cec5SDimitry Andric       return;
48490b57cec5SDimitry Andric     }
48500b57cec5SDimitry Andric 
48510b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld1: {
48520b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16,
48530b57cec5SDimitry Andric                                            ARM::VLD1d32, ARM::VLD1d64 };
48540b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
48550b57cec5SDimitry Andric                                            ARM::VLD1q32, ARM::VLD1q64};
48560b57cec5SDimitry Andric       SelectVLD(N, false, 1, DOpcodes, QOpcodes, nullptr);
48570b57cec5SDimitry Andric       return;
48580b57cec5SDimitry Andric     }
48590b57cec5SDimitry Andric 
48600b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld1x2: {
48610b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
48620b57cec5SDimitry Andric                                            ARM::VLD1q32, ARM::VLD1q64 };
48630b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VLD1d8QPseudo,
48640b57cec5SDimitry Andric                                            ARM::VLD1d16QPseudo,
48650b57cec5SDimitry Andric                                            ARM::VLD1d32QPseudo,
48660b57cec5SDimitry Andric                                            ARM::VLD1d64QPseudo };
48670b57cec5SDimitry Andric       SelectVLD(N, false, 2, DOpcodes, QOpcodes, nullptr);
48680b57cec5SDimitry Andric       return;
48690b57cec5SDimitry Andric     }
48700b57cec5SDimitry Andric 
48710b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld1x3: {
48720b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD1d8TPseudo,
48730b57cec5SDimitry Andric                                            ARM::VLD1d16TPseudo,
48740b57cec5SDimitry Andric                                            ARM::VLD1d32TPseudo,
48750b57cec5SDimitry Andric                                            ARM::VLD1d64TPseudo };
48760b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD1q8LowTPseudo_UPD,
48770b57cec5SDimitry Andric                                             ARM::VLD1q16LowTPseudo_UPD,
48780b57cec5SDimitry Andric                                             ARM::VLD1q32LowTPseudo_UPD,
48790b57cec5SDimitry Andric                                             ARM::VLD1q64LowTPseudo_UPD };
48800b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD1q8HighTPseudo,
48810b57cec5SDimitry Andric                                             ARM::VLD1q16HighTPseudo,
48820b57cec5SDimitry Andric                                             ARM::VLD1q32HighTPseudo,
48830b57cec5SDimitry Andric                                             ARM::VLD1q64HighTPseudo };
48840b57cec5SDimitry Andric       SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
48850b57cec5SDimitry Andric       return;
48860b57cec5SDimitry Andric     }
48870b57cec5SDimitry Andric 
48880b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld1x4: {
48890b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD1d8QPseudo,
48900b57cec5SDimitry Andric                                            ARM::VLD1d16QPseudo,
48910b57cec5SDimitry Andric                                            ARM::VLD1d32QPseudo,
48920b57cec5SDimitry Andric                                            ARM::VLD1d64QPseudo };
48930b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD1q8LowQPseudo_UPD,
48940b57cec5SDimitry Andric                                             ARM::VLD1q16LowQPseudo_UPD,
48950b57cec5SDimitry Andric                                             ARM::VLD1q32LowQPseudo_UPD,
48960b57cec5SDimitry Andric                                             ARM::VLD1q64LowQPseudo_UPD };
48970b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD1q8HighQPseudo,
48980b57cec5SDimitry Andric                                             ARM::VLD1q16HighQPseudo,
48990b57cec5SDimitry Andric                                             ARM::VLD1q32HighQPseudo,
49000b57cec5SDimitry Andric                                             ARM::VLD1q64HighQPseudo };
49010b57cec5SDimitry Andric       SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
49020b57cec5SDimitry Andric       return;
49030b57cec5SDimitry Andric     }
49040b57cec5SDimitry Andric 
49050b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld2: {
49060b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16,
49070b57cec5SDimitry Andric                                            ARM::VLD2d32, ARM::VLD1q64 };
49080b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo,
49090b57cec5SDimitry Andric                                            ARM::VLD2q32Pseudo };
49100b57cec5SDimitry Andric       SelectVLD(N, false, 2, DOpcodes, QOpcodes, nullptr);
49110b57cec5SDimitry Andric       return;
49120b57cec5SDimitry Andric     }
49130b57cec5SDimitry Andric 
49140b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld3: {
49150b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo,
49160b57cec5SDimitry Andric                                            ARM::VLD3d16Pseudo,
49170b57cec5SDimitry Andric                                            ARM::VLD3d32Pseudo,
49180b57cec5SDimitry Andric                                            ARM::VLD1d64TPseudo };
49190b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD,
49200b57cec5SDimitry Andric                                             ARM::VLD3q16Pseudo_UPD,
49210b57cec5SDimitry Andric                                             ARM::VLD3q32Pseudo_UPD };
49220b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo,
49230b57cec5SDimitry Andric                                             ARM::VLD3q16oddPseudo,
49240b57cec5SDimitry Andric                                             ARM::VLD3q32oddPseudo };
49250b57cec5SDimitry Andric       SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
49260b57cec5SDimitry Andric       return;
49270b57cec5SDimitry Andric     }
49280b57cec5SDimitry Andric 
49290b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld4: {
49300b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo,
49310b57cec5SDimitry Andric                                            ARM::VLD4d16Pseudo,
49320b57cec5SDimitry Andric                                            ARM::VLD4d32Pseudo,
49330b57cec5SDimitry Andric                                            ARM::VLD1d64QPseudo };
49340b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD,
49350b57cec5SDimitry Andric                                             ARM::VLD4q16Pseudo_UPD,
49360b57cec5SDimitry Andric                                             ARM::VLD4q32Pseudo_UPD };
49370b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo,
49380b57cec5SDimitry Andric                                             ARM::VLD4q16oddPseudo,
49390b57cec5SDimitry Andric                                             ARM::VLD4q32oddPseudo };
49400b57cec5SDimitry Andric       SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
49410b57cec5SDimitry Andric       return;
49420b57cec5SDimitry Andric     }
49430b57cec5SDimitry Andric 
49440b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld2dup: {
49450b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
49460b57cec5SDimitry Andric                                            ARM::VLD2DUPd32, ARM::VLD1q64 };
49470b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD2DUPq8EvenPseudo,
49480b57cec5SDimitry Andric                                             ARM::VLD2DUPq16EvenPseudo,
49490b57cec5SDimitry Andric                                             ARM::VLD2DUPq32EvenPseudo };
49500b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD2DUPq8OddPseudo,
49510b57cec5SDimitry Andric                                             ARM::VLD2DUPq16OddPseudo,
49520b57cec5SDimitry Andric                                             ARM::VLD2DUPq32OddPseudo };
49530b57cec5SDimitry Andric       SelectVLDDup(N, /* IsIntrinsic= */ true, false, 2,
49540b57cec5SDimitry Andric                    DOpcodes, QOpcodes0, QOpcodes1);
49550b57cec5SDimitry Andric       return;
49560b57cec5SDimitry Andric     }
49570b57cec5SDimitry Andric 
49580b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld3dup: {
49590b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD3DUPd8Pseudo,
49600b57cec5SDimitry Andric                                            ARM::VLD3DUPd16Pseudo,
49610b57cec5SDimitry Andric                                            ARM::VLD3DUPd32Pseudo,
49620b57cec5SDimitry Andric                                            ARM::VLD1d64TPseudo };
49630b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD3DUPq8EvenPseudo,
49640b57cec5SDimitry Andric                                             ARM::VLD3DUPq16EvenPseudo,
49650b57cec5SDimitry Andric                                             ARM::VLD3DUPq32EvenPseudo };
49660b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD3DUPq8OddPseudo,
49670b57cec5SDimitry Andric                                             ARM::VLD3DUPq16OddPseudo,
49680b57cec5SDimitry Andric                                             ARM::VLD3DUPq32OddPseudo };
49690b57cec5SDimitry Andric       SelectVLDDup(N, /* IsIntrinsic= */ true, false, 3,
49700b57cec5SDimitry Andric                    DOpcodes, QOpcodes0, QOpcodes1);
49710b57cec5SDimitry Andric       return;
49720b57cec5SDimitry Andric     }
49730b57cec5SDimitry Andric 
49740b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld4dup: {
49750b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD4DUPd8Pseudo,
49760b57cec5SDimitry Andric                                            ARM::VLD4DUPd16Pseudo,
49770b57cec5SDimitry Andric                                            ARM::VLD4DUPd32Pseudo,
49780b57cec5SDimitry Andric                                            ARM::VLD1d64QPseudo };
49790b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VLD4DUPq8EvenPseudo,
49800b57cec5SDimitry Andric                                             ARM::VLD4DUPq16EvenPseudo,
49810b57cec5SDimitry Andric                                             ARM::VLD4DUPq32EvenPseudo };
49820b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VLD4DUPq8OddPseudo,
49830b57cec5SDimitry Andric                                             ARM::VLD4DUPq16OddPseudo,
49840b57cec5SDimitry Andric                                             ARM::VLD4DUPq32OddPseudo };
49850b57cec5SDimitry Andric       SelectVLDDup(N, /* IsIntrinsic= */ true, false, 4,
49860b57cec5SDimitry Andric                    DOpcodes, QOpcodes0, QOpcodes1);
49870b57cec5SDimitry Andric       return;
49880b57cec5SDimitry Andric     }
49890b57cec5SDimitry Andric 
49900b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld2lane: {
49910b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo,
49920b57cec5SDimitry Andric                                            ARM::VLD2LNd16Pseudo,
49930b57cec5SDimitry Andric                                            ARM::VLD2LNd32Pseudo };
49940b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo,
49950b57cec5SDimitry Andric                                            ARM::VLD2LNq32Pseudo };
49960b57cec5SDimitry Andric       SelectVLDSTLane(N, true, false, 2, DOpcodes, QOpcodes);
49970b57cec5SDimitry Andric       return;
49980b57cec5SDimitry Andric     }
49990b57cec5SDimitry Andric 
50000b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld3lane: {
50010b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo,
50020b57cec5SDimitry Andric                                            ARM::VLD3LNd16Pseudo,
50030b57cec5SDimitry Andric                                            ARM::VLD3LNd32Pseudo };
50040b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo,
50050b57cec5SDimitry Andric                                            ARM::VLD3LNq32Pseudo };
50060b57cec5SDimitry Andric       SelectVLDSTLane(N, true, false, 3, DOpcodes, QOpcodes);
50070b57cec5SDimitry Andric       return;
50080b57cec5SDimitry Andric     }
50090b57cec5SDimitry Andric 
50100b57cec5SDimitry Andric     case Intrinsic::arm_neon_vld4lane: {
50110b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo,
50120b57cec5SDimitry Andric                                            ARM::VLD4LNd16Pseudo,
50130b57cec5SDimitry Andric                                            ARM::VLD4LNd32Pseudo };
50140b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo,
50150b57cec5SDimitry Andric                                            ARM::VLD4LNq32Pseudo };
50160b57cec5SDimitry Andric       SelectVLDSTLane(N, true, false, 4, DOpcodes, QOpcodes);
50170b57cec5SDimitry Andric       return;
50180b57cec5SDimitry Andric     }
50190b57cec5SDimitry Andric 
50200b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst1: {
50210b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1d8, ARM::VST1d16,
50220b57cec5SDimitry Andric                                            ARM::VST1d32, ARM::VST1d64 };
50230b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
50240b57cec5SDimitry Andric                                            ARM::VST1q32, ARM::VST1q64 };
50250b57cec5SDimitry Andric       SelectVST(N, false, 1, DOpcodes, QOpcodes, nullptr);
50260b57cec5SDimitry Andric       return;
50270b57cec5SDimitry Andric     }
50280b57cec5SDimitry Andric 
50290b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst1x2: {
50300b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
50310b57cec5SDimitry Andric                                            ARM::VST1q32, ARM::VST1q64 };
50320b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST1d8QPseudo,
50330b57cec5SDimitry Andric                                            ARM::VST1d16QPseudo,
50340b57cec5SDimitry Andric                                            ARM::VST1d32QPseudo,
50350b57cec5SDimitry Andric                                            ARM::VST1d64QPseudo };
50360b57cec5SDimitry Andric       SelectVST(N, false, 2, DOpcodes, QOpcodes, nullptr);
50370b57cec5SDimitry Andric       return;
50380b57cec5SDimitry Andric     }
50390b57cec5SDimitry Andric 
50400b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst1x3: {
50410b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1d8TPseudo,
50420b57cec5SDimitry Andric                                            ARM::VST1d16TPseudo,
50430b57cec5SDimitry Andric                                            ARM::VST1d32TPseudo,
50440b57cec5SDimitry Andric                                            ARM::VST1d64TPseudo };
50450b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VST1q8LowTPseudo_UPD,
50460b57cec5SDimitry Andric                                             ARM::VST1q16LowTPseudo_UPD,
50470b57cec5SDimitry Andric                                             ARM::VST1q32LowTPseudo_UPD,
50480b57cec5SDimitry Andric                                             ARM::VST1q64LowTPseudo_UPD };
50490b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VST1q8HighTPseudo,
50500b57cec5SDimitry Andric                                             ARM::VST1q16HighTPseudo,
50510b57cec5SDimitry Andric                                             ARM::VST1q32HighTPseudo,
50520b57cec5SDimitry Andric                                             ARM::VST1q64HighTPseudo };
50530b57cec5SDimitry Andric       SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
50540b57cec5SDimitry Andric       return;
50550b57cec5SDimitry Andric     }
50560b57cec5SDimitry Andric 
50570b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst1x4: {
50580b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST1d8QPseudo,
50590b57cec5SDimitry Andric                                            ARM::VST1d16QPseudo,
50600b57cec5SDimitry Andric                                            ARM::VST1d32QPseudo,
50610b57cec5SDimitry Andric                                            ARM::VST1d64QPseudo };
50620b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VST1q8LowQPseudo_UPD,
50630b57cec5SDimitry Andric                                             ARM::VST1q16LowQPseudo_UPD,
50640b57cec5SDimitry Andric                                             ARM::VST1q32LowQPseudo_UPD,
50650b57cec5SDimitry Andric                                             ARM::VST1q64LowQPseudo_UPD };
50660b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VST1q8HighQPseudo,
50670b57cec5SDimitry Andric                                             ARM::VST1q16HighQPseudo,
50680b57cec5SDimitry Andric                                             ARM::VST1q32HighQPseudo,
50690b57cec5SDimitry Andric                                             ARM::VST1q64HighQPseudo };
50700b57cec5SDimitry Andric       SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
50710b57cec5SDimitry Andric       return;
50720b57cec5SDimitry Andric     }
50730b57cec5SDimitry Andric 
50740b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst2: {
50750b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST2d8, ARM::VST2d16,
50760b57cec5SDimitry Andric                                            ARM::VST2d32, ARM::VST1q64 };
50770b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo,
50780b57cec5SDimitry Andric                                            ARM::VST2q32Pseudo };
50790b57cec5SDimitry Andric       SelectVST(N, false, 2, DOpcodes, QOpcodes, nullptr);
50800b57cec5SDimitry Andric       return;
50810b57cec5SDimitry Andric     }
50820b57cec5SDimitry Andric 
50830b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst3: {
50840b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo,
50850b57cec5SDimitry Andric                                            ARM::VST3d16Pseudo,
50860b57cec5SDimitry Andric                                            ARM::VST3d32Pseudo,
50870b57cec5SDimitry Andric                                            ARM::VST1d64TPseudo };
50880b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD,
50890b57cec5SDimitry Andric                                             ARM::VST3q16Pseudo_UPD,
50900b57cec5SDimitry Andric                                             ARM::VST3q32Pseudo_UPD };
50910b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo,
50920b57cec5SDimitry Andric                                             ARM::VST3q16oddPseudo,
50930b57cec5SDimitry Andric                                             ARM::VST3q32oddPseudo };
50940b57cec5SDimitry Andric       SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
50950b57cec5SDimitry Andric       return;
50960b57cec5SDimitry Andric     }
50970b57cec5SDimitry Andric 
50980b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst4: {
50990b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo,
51000b57cec5SDimitry Andric                                            ARM::VST4d16Pseudo,
51010b57cec5SDimitry Andric                                            ARM::VST4d32Pseudo,
51020b57cec5SDimitry Andric                                            ARM::VST1d64QPseudo };
51030b57cec5SDimitry Andric       static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD,
51040b57cec5SDimitry Andric                                             ARM::VST4q16Pseudo_UPD,
51050b57cec5SDimitry Andric                                             ARM::VST4q32Pseudo_UPD };
51060b57cec5SDimitry Andric       static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo,
51070b57cec5SDimitry Andric                                             ARM::VST4q16oddPseudo,
51080b57cec5SDimitry Andric                                             ARM::VST4q32oddPseudo };
51090b57cec5SDimitry Andric       SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
51100b57cec5SDimitry Andric       return;
51110b57cec5SDimitry Andric     }
51120b57cec5SDimitry Andric 
51130b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst2lane: {
51140b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo,
51150b57cec5SDimitry Andric                                            ARM::VST2LNd16Pseudo,
51160b57cec5SDimitry Andric                                            ARM::VST2LNd32Pseudo };
51170b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo,
51180b57cec5SDimitry Andric                                            ARM::VST2LNq32Pseudo };
51190b57cec5SDimitry Andric       SelectVLDSTLane(N, false, false, 2, DOpcodes, QOpcodes);
51200b57cec5SDimitry Andric       return;
51210b57cec5SDimitry Andric     }
51220b57cec5SDimitry Andric 
51230b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst3lane: {
51240b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo,
51250b57cec5SDimitry Andric                                            ARM::VST3LNd16Pseudo,
51260b57cec5SDimitry Andric                                            ARM::VST3LNd32Pseudo };
51270b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo,
51280b57cec5SDimitry Andric                                            ARM::VST3LNq32Pseudo };
51290b57cec5SDimitry Andric       SelectVLDSTLane(N, false, false, 3, DOpcodes, QOpcodes);
51300b57cec5SDimitry Andric       return;
51310b57cec5SDimitry Andric     }
51320b57cec5SDimitry Andric 
51330b57cec5SDimitry Andric     case Intrinsic::arm_neon_vst4lane: {
51340b57cec5SDimitry Andric       static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo,
51350b57cec5SDimitry Andric                                            ARM::VST4LNd16Pseudo,
51360b57cec5SDimitry Andric                                            ARM::VST4LNd32Pseudo };
51370b57cec5SDimitry Andric       static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo,
51380b57cec5SDimitry Andric                                            ARM::VST4LNq32Pseudo };
51390b57cec5SDimitry Andric       SelectVLDSTLane(N, false, false, 4, DOpcodes, QOpcodes);
51400b57cec5SDimitry Andric       return;
51410b57cec5SDimitry Andric     }
5142480093f4SDimitry Andric 
5143480093f4SDimitry Andric     case Intrinsic::arm_mve_vldr_gather_base_wb:
5144480093f4SDimitry Andric     case Intrinsic::arm_mve_vldr_gather_base_wb_predicated: {
5145480093f4SDimitry Andric       static const uint16_t Opcodes[] = {ARM::MVE_VLDRWU32_qi_pre,
5146480093f4SDimitry Andric                                          ARM::MVE_VLDRDU64_qi_pre};
5147480093f4SDimitry Andric       SelectMVE_WB(N, Opcodes,
5148480093f4SDimitry Andric                    IntNo == Intrinsic::arm_mve_vldr_gather_base_wb_predicated);
5149480093f4SDimitry Andric       return;
5150480093f4SDimitry Andric     }
5151480093f4SDimitry Andric 
5152480093f4SDimitry Andric     case Intrinsic::arm_mve_vld2q: {
5153480093f4SDimitry Andric       static const uint16_t Opcodes8[] = {ARM::MVE_VLD20_8, ARM::MVE_VLD21_8};
5154480093f4SDimitry Andric       static const uint16_t Opcodes16[] = {ARM::MVE_VLD20_16,
5155480093f4SDimitry Andric                                            ARM::MVE_VLD21_16};
5156480093f4SDimitry Andric       static const uint16_t Opcodes32[] = {ARM::MVE_VLD20_32,
5157480093f4SDimitry Andric                                            ARM::MVE_VLD21_32};
5158480093f4SDimitry Andric       static const uint16_t *const Opcodes[] = {Opcodes8, Opcodes16, Opcodes32};
51595ffd83dbSDimitry Andric       SelectMVE_VLD(N, 2, Opcodes, false);
5160480093f4SDimitry Andric       return;
5161480093f4SDimitry Andric     }
5162480093f4SDimitry Andric 
5163480093f4SDimitry Andric     case Intrinsic::arm_mve_vld4q: {
5164480093f4SDimitry Andric       static const uint16_t Opcodes8[] = {ARM::MVE_VLD40_8, ARM::MVE_VLD41_8,
5165480093f4SDimitry Andric                                           ARM::MVE_VLD42_8, ARM::MVE_VLD43_8};
5166480093f4SDimitry Andric       static const uint16_t Opcodes16[] = {ARM::MVE_VLD40_16, ARM::MVE_VLD41_16,
5167480093f4SDimitry Andric                                            ARM::MVE_VLD42_16,
5168480093f4SDimitry Andric                                            ARM::MVE_VLD43_16};
5169480093f4SDimitry Andric       static const uint16_t Opcodes32[] = {ARM::MVE_VLD40_32, ARM::MVE_VLD41_32,
5170480093f4SDimitry Andric                                            ARM::MVE_VLD42_32,
5171480093f4SDimitry Andric                                            ARM::MVE_VLD43_32};
5172480093f4SDimitry Andric       static const uint16_t *const Opcodes[] = {Opcodes8, Opcodes16, Opcodes32};
51735ffd83dbSDimitry Andric       SelectMVE_VLD(N, 4, Opcodes, false);
5174480093f4SDimitry Andric       return;
5175480093f4SDimitry Andric     }
5176480093f4SDimitry Andric     }
5177480093f4SDimitry Andric     break;
5178480093f4SDimitry Andric   }
5179480093f4SDimitry Andric 
5180480093f4SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN: {
5181647cbc5dSDimitry Andric     unsigned IntNo = N->getConstantOperandVal(0);
5182480093f4SDimitry Andric     switch (IntNo) {
5183480093f4SDimitry Andric     default:
5184480093f4SDimitry Andric       break;
5185480093f4SDimitry Andric 
51865ffd83dbSDimitry Andric     // Scalar f32 -> bf16
51875ffd83dbSDimitry Andric     case Intrinsic::arm_neon_vcvtbfp2bf: {
51885ffd83dbSDimitry Andric       SDLoc dl(N);
51895ffd83dbSDimitry Andric       const SDValue &Src = N->getOperand(1);
51905ffd83dbSDimitry Andric       llvm::EVT DestTy = N->getValueType(0);
51915ffd83dbSDimitry Andric       SDValue Pred = getAL(CurDAG, dl);
51925ffd83dbSDimitry Andric       SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
51935ffd83dbSDimitry Andric       SDValue Ops[] = { Src, Src, Pred, Reg0 };
51945ffd83dbSDimitry Andric       CurDAG->SelectNodeTo(N, ARM::BF16_VCVTB, DestTy, Ops);
51955ffd83dbSDimitry Andric       return;
51965ffd83dbSDimitry Andric     }
51975ffd83dbSDimitry Andric 
51985ffd83dbSDimitry Andric     // Vector v4f32 -> v4bf16
51995ffd83dbSDimitry Andric     case Intrinsic::arm_neon_vcvtfp2bf: {
52005ffd83dbSDimitry Andric       SDLoc dl(N);
52015ffd83dbSDimitry Andric       const SDValue &Src = N->getOperand(1);
52025ffd83dbSDimitry Andric       SDValue Pred = getAL(CurDAG, dl);
52035ffd83dbSDimitry Andric       SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
52045ffd83dbSDimitry Andric       SDValue Ops[] = { Src, Pred, Reg0 };
52055ffd83dbSDimitry Andric       CurDAG->SelectNodeTo(N, ARM::BF16_VCVT, MVT::v4bf16, Ops);
52065ffd83dbSDimitry Andric       return;
52075ffd83dbSDimitry Andric     }
52085ffd83dbSDimitry Andric 
5209480093f4SDimitry Andric     case Intrinsic::arm_mve_urshrl:
5210480093f4SDimitry Andric       SelectMVE_LongShift(N, ARM::MVE_URSHRL, true, false);
5211480093f4SDimitry Andric       return;
5212480093f4SDimitry Andric     case Intrinsic::arm_mve_uqshll:
5213480093f4SDimitry Andric       SelectMVE_LongShift(N, ARM::MVE_UQSHLL, true, false);
5214480093f4SDimitry Andric       return;
5215480093f4SDimitry Andric     case Intrinsic::arm_mve_srshrl:
5216480093f4SDimitry Andric       SelectMVE_LongShift(N, ARM::MVE_SRSHRL, true, false);
5217480093f4SDimitry Andric       return;
5218480093f4SDimitry Andric     case Intrinsic::arm_mve_sqshll:
5219480093f4SDimitry Andric       SelectMVE_LongShift(N, ARM::MVE_SQSHLL, true, false);
5220480093f4SDimitry Andric       return;
5221480093f4SDimitry Andric     case Intrinsic::arm_mve_uqrshll:
5222480093f4SDimitry Andric       SelectMVE_LongShift(N, ARM::MVE_UQRSHLL, false, true);
5223480093f4SDimitry Andric       return;
5224480093f4SDimitry Andric     case Intrinsic::arm_mve_sqrshrl:
5225480093f4SDimitry Andric       SelectMVE_LongShift(N, ARM::MVE_SQRSHRL, false, true);
5226480093f4SDimitry Andric       return;
5227480093f4SDimitry Andric 
5228480093f4SDimitry Andric     case Intrinsic::arm_mve_vadc:
5229480093f4SDimitry Andric     case Intrinsic::arm_mve_vadc_predicated:
5230480093f4SDimitry Andric       SelectMVE_VADCSBC(N, ARM::MVE_VADC, ARM::MVE_VADCI, true,
5231480093f4SDimitry Andric                         IntNo == Intrinsic::arm_mve_vadc_predicated);
5232480093f4SDimitry Andric       return;
52335ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vsbc:
52345ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vsbc_predicated:
52355ffd83dbSDimitry Andric       SelectMVE_VADCSBC(N, ARM::MVE_VSBC, ARM::MVE_VSBCI, true,
52365ffd83dbSDimitry Andric                         IntNo == Intrinsic::arm_mve_vsbc_predicated);
52375ffd83dbSDimitry Andric       return;
52385ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vshlc:
52395ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vshlc_predicated:
52405ffd83dbSDimitry Andric       SelectMVE_VSHLC(N, IntNo == Intrinsic::arm_mve_vshlc_predicated);
52415ffd83dbSDimitry Andric       return;
5242480093f4SDimitry Andric 
5243480093f4SDimitry Andric     case Intrinsic::arm_mve_vmlldava:
5244480093f4SDimitry Andric     case Intrinsic::arm_mve_vmlldava_predicated: {
5245480093f4SDimitry Andric       static const uint16_t OpcodesU[] = {
5246480093f4SDimitry Andric           ARM::MVE_VMLALDAVu16,   ARM::MVE_VMLALDAVu32,
5247480093f4SDimitry Andric           ARM::MVE_VMLALDAVau16,  ARM::MVE_VMLALDAVau32,
5248480093f4SDimitry Andric       };
5249480093f4SDimitry Andric       static const uint16_t OpcodesS[] = {
5250480093f4SDimitry Andric           ARM::MVE_VMLALDAVs16,   ARM::MVE_VMLALDAVs32,
5251480093f4SDimitry Andric           ARM::MVE_VMLALDAVas16,  ARM::MVE_VMLALDAVas32,
5252480093f4SDimitry Andric           ARM::MVE_VMLALDAVxs16,  ARM::MVE_VMLALDAVxs32,
5253480093f4SDimitry Andric           ARM::MVE_VMLALDAVaxs16, ARM::MVE_VMLALDAVaxs32,
5254480093f4SDimitry Andric           ARM::MVE_VMLSLDAVs16,   ARM::MVE_VMLSLDAVs32,
5255480093f4SDimitry Andric           ARM::MVE_VMLSLDAVas16,  ARM::MVE_VMLSLDAVas32,
5256480093f4SDimitry Andric           ARM::MVE_VMLSLDAVxs16,  ARM::MVE_VMLSLDAVxs32,
5257480093f4SDimitry Andric           ARM::MVE_VMLSLDAVaxs16, ARM::MVE_VMLSLDAVaxs32,
5258480093f4SDimitry Andric       };
5259480093f4SDimitry Andric       SelectMVE_VMLLDAV(N, IntNo == Intrinsic::arm_mve_vmlldava_predicated,
5260480093f4SDimitry Andric                         OpcodesS, OpcodesU);
5261480093f4SDimitry Andric       return;
5262480093f4SDimitry Andric     }
5263480093f4SDimitry Andric 
5264480093f4SDimitry Andric     case Intrinsic::arm_mve_vrmlldavha:
5265480093f4SDimitry Andric     case Intrinsic::arm_mve_vrmlldavha_predicated: {
5266480093f4SDimitry Andric       static const uint16_t OpcodesU[] = {
5267480093f4SDimitry Andric           ARM::MVE_VRMLALDAVHu32,  ARM::MVE_VRMLALDAVHau32,
5268480093f4SDimitry Andric       };
5269480093f4SDimitry Andric       static const uint16_t OpcodesS[] = {
5270480093f4SDimitry Andric           ARM::MVE_VRMLALDAVHs32,  ARM::MVE_VRMLALDAVHas32,
5271480093f4SDimitry Andric           ARM::MVE_VRMLALDAVHxs32, ARM::MVE_VRMLALDAVHaxs32,
5272480093f4SDimitry Andric           ARM::MVE_VRMLSLDAVHs32,  ARM::MVE_VRMLSLDAVHas32,
5273480093f4SDimitry Andric           ARM::MVE_VRMLSLDAVHxs32, ARM::MVE_VRMLSLDAVHaxs32,
5274480093f4SDimitry Andric       };
5275480093f4SDimitry Andric       SelectMVE_VRMLLDAVH(N, IntNo == Intrinsic::arm_mve_vrmlldavha_predicated,
5276480093f4SDimitry Andric                           OpcodesS, OpcodesU);
5277480093f4SDimitry Andric       return;
5278480093f4SDimitry Andric     }
52795ffd83dbSDimitry Andric 
52805ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vidup:
52815ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vidup_predicated: {
52825ffd83dbSDimitry Andric       static const uint16_t Opcodes[] = {
52835ffd83dbSDimitry Andric           ARM::MVE_VIDUPu8, ARM::MVE_VIDUPu16, ARM::MVE_VIDUPu32,
52845ffd83dbSDimitry Andric       };
52855ffd83dbSDimitry Andric       SelectMVE_VxDUP(N, Opcodes, false,
52865ffd83dbSDimitry Andric                       IntNo == Intrinsic::arm_mve_vidup_predicated);
52875ffd83dbSDimitry Andric       return;
52885ffd83dbSDimitry Andric     }
52895ffd83dbSDimitry Andric 
52905ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vddup:
52915ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vddup_predicated: {
52925ffd83dbSDimitry Andric       static const uint16_t Opcodes[] = {
52935ffd83dbSDimitry Andric           ARM::MVE_VDDUPu8, ARM::MVE_VDDUPu16, ARM::MVE_VDDUPu32,
52945ffd83dbSDimitry Andric       };
52955ffd83dbSDimitry Andric       SelectMVE_VxDUP(N, Opcodes, false,
52965ffd83dbSDimitry Andric                       IntNo == Intrinsic::arm_mve_vddup_predicated);
52975ffd83dbSDimitry Andric       return;
52985ffd83dbSDimitry Andric     }
52995ffd83dbSDimitry Andric 
53005ffd83dbSDimitry Andric     case Intrinsic::arm_mve_viwdup:
53015ffd83dbSDimitry Andric     case Intrinsic::arm_mve_viwdup_predicated: {
53025ffd83dbSDimitry Andric       static const uint16_t Opcodes[] = {
53035ffd83dbSDimitry Andric           ARM::MVE_VIWDUPu8, ARM::MVE_VIWDUPu16, ARM::MVE_VIWDUPu32,
53045ffd83dbSDimitry Andric       };
53055ffd83dbSDimitry Andric       SelectMVE_VxDUP(N, Opcodes, true,
53065ffd83dbSDimitry Andric                       IntNo == Intrinsic::arm_mve_viwdup_predicated);
53075ffd83dbSDimitry Andric       return;
53085ffd83dbSDimitry Andric     }
53095ffd83dbSDimitry Andric 
53105ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vdwdup:
53115ffd83dbSDimitry Andric     case Intrinsic::arm_mve_vdwdup_predicated: {
53125ffd83dbSDimitry Andric       static const uint16_t Opcodes[] = {
53135ffd83dbSDimitry Andric           ARM::MVE_VDWDUPu8, ARM::MVE_VDWDUPu16, ARM::MVE_VDWDUPu32,
53145ffd83dbSDimitry Andric       };
53155ffd83dbSDimitry Andric       SelectMVE_VxDUP(N, Opcodes, true,
53165ffd83dbSDimitry Andric                       IntNo == Intrinsic::arm_mve_vdwdup_predicated);
53175ffd83dbSDimitry Andric       return;
53185ffd83dbSDimitry Andric     }
53195ffd83dbSDimitry Andric 
53205ffd83dbSDimitry Andric     case Intrinsic::arm_cde_cx1d:
53215ffd83dbSDimitry Andric     case Intrinsic::arm_cde_cx1da:
53225ffd83dbSDimitry Andric     case Intrinsic::arm_cde_cx2d:
53235ffd83dbSDimitry Andric     case Intrinsic::arm_cde_cx2da:
53245ffd83dbSDimitry Andric     case Intrinsic::arm_cde_cx3d:
53255ffd83dbSDimitry Andric     case Intrinsic::arm_cde_cx3da: {
53265ffd83dbSDimitry Andric       bool HasAccum = IntNo == Intrinsic::arm_cde_cx1da ||
53275ffd83dbSDimitry Andric                       IntNo == Intrinsic::arm_cde_cx2da ||
53285ffd83dbSDimitry Andric                       IntNo == Intrinsic::arm_cde_cx3da;
53295ffd83dbSDimitry Andric       size_t NumExtraOps;
53305ffd83dbSDimitry Andric       uint16_t Opcode;
53315ffd83dbSDimitry Andric       switch (IntNo) {
53325ffd83dbSDimitry Andric       case Intrinsic::arm_cde_cx1d:
53335ffd83dbSDimitry Andric       case Intrinsic::arm_cde_cx1da:
53345ffd83dbSDimitry Andric         NumExtraOps = 0;
53355ffd83dbSDimitry Andric         Opcode = HasAccum ? ARM::CDE_CX1DA : ARM::CDE_CX1D;
53365ffd83dbSDimitry Andric         break;
53375ffd83dbSDimitry Andric       case Intrinsic::arm_cde_cx2d:
53385ffd83dbSDimitry Andric       case Intrinsic::arm_cde_cx2da:
53395ffd83dbSDimitry Andric         NumExtraOps = 1;
53405ffd83dbSDimitry Andric         Opcode = HasAccum ? ARM::CDE_CX2DA : ARM::CDE_CX2D;
53415ffd83dbSDimitry Andric         break;
53425ffd83dbSDimitry Andric       case Intrinsic::arm_cde_cx3d:
53435ffd83dbSDimitry Andric       case Intrinsic::arm_cde_cx3da:
53445ffd83dbSDimitry Andric         NumExtraOps = 2;
53455ffd83dbSDimitry Andric         Opcode = HasAccum ? ARM::CDE_CX3DA : ARM::CDE_CX3D;
53465ffd83dbSDimitry Andric         break;
53475ffd83dbSDimitry Andric       default:
53485ffd83dbSDimitry Andric         llvm_unreachable("Unexpected opcode");
53495ffd83dbSDimitry Andric       }
53505ffd83dbSDimitry Andric       SelectCDE_CXxD(N, Opcode, NumExtraOps, HasAccum);
53515ffd83dbSDimitry Andric       return;
53525ffd83dbSDimitry Andric     }
53530b57cec5SDimitry Andric     }
53540b57cec5SDimitry Andric     break;
53550b57cec5SDimitry Andric   }
53560b57cec5SDimitry Andric 
53570b57cec5SDimitry Andric   case ISD::ATOMIC_CMP_SWAP:
53580b57cec5SDimitry Andric     SelectCMP_SWAP(N);
53590b57cec5SDimitry Andric     return;
53600b57cec5SDimitry Andric   }
53610b57cec5SDimitry Andric 
53620b57cec5SDimitry Andric   SelectCode(N);
53630b57cec5SDimitry Andric }
53640b57cec5SDimitry Andric 
53650b57cec5SDimitry Andric // Inspect a register string of the form
53660b57cec5SDimitry Andric // cp<coprocessor>:<opc1>:c<CRn>:c<CRm>:<opc2> (32bit) or
53670b57cec5SDimitry Andric // cp<coprocessor>:<opc1>:c<CRm> (64bit) inspect the fields of the string
53680b57cec5SDimitry Andric // and obtain the integer operands from them, adding these operands to the
53690b57cec5SDimitry Andric // provided vector.
getIntOperandsFromRegisterString(StringRef RegString,SelectionDAG * CurDAG,const SDLoc & DL,std::vector<SDValue> & Ops)53700b57cec5SDimitry Andric static void getIntOperandsFromRegisterString(StringRef RegString,
53710b57cec5SDimitry Andric                                              SelectionDAG *CurDAG,
53720b57cec5SDimitry Andric                                              const SDLoc &DL,
53730b57cec5SDimitry Andric                                              std::vector<SDValue> &Ops) {
53740b57cec5SDimitry Andric   SmallVector<StringRef, 5> Fields;
53750b57cec5SDimitry Andric   RegString.split(Fields, ':');
53760b57cec5SDimitry Andric 
53770b57cec5SDimitry Andric   if (Fields.size() > 1) {
53780b57cec5SDimitry Andric     bool AllIntFields = true;
53790b57cec5SDimitry Andric 
53800b57cec5SDimitry Andric     for (StringRef Field : Fields) {
53810b57cec5SDimitry Andric       // Need to trim out leading 'cp' characters and get the integer field.
53820b57cec5SDimitry Andric       unsigned IntField;
53830b57cec5SDimitry Andric       AllIntFields &= !Field.trim("CPcp").getAsInteger(10, IntField);
53840b57cec5SDimitry Andric       Ops.push_back(CurDAG->getTargetConstant(IntField, DL, MVT::i32));
53850b57cec5SDimitry Andric     }
53860b57cec5SDimitry Andric 
53870b57cec5SDimitry Andric     assert(AllIntFields &&
53880b57cec5SDimitry Andric             "Unexpected non-integer value in special register string.");
5389fe6060f1SDimitry Andric     (void)AllIntFields;
53900b57cec5SDimitry Andric   }
53910b57cec5SDimitry Andric }
53920b57cec5SDimitry Andric 
53930b57cec5SDimitry Andric // Maps a Banked Register string to its mask value. The mask value returned is
53940b57cec5SDimitry Andric // for use in the MRSbanked / MSRbanked instruction nodes as the Banked Register
53950b57cec5SDimitry Andric // mask operand, which expresses which register is to be used, e.g. r8, and in
53960b57cec5SDimitry Andric // which mode it is to be used, e.g. usr. Returns -1 to signify that the string
53970b57cec5SDimitry Andric // was invalid.
getBankedRegisterMask(StringRef RegString)53980b57cec5SDimitry Andric static inline int getBankedRegisterMask(StringRef RegString) {
53990b57cec5SDimitry Andric   auto TheReg = ARMBankedReg::lookupBankedRegByName(RegString.lower());
54000b57cec5SDimitry Andric   if (!TheReg)
54010b57cec5SDimitry Andric      return -1;
54020b57cec5SDimitry Andric   return TheReg->Encoding;
54030b57cec5SDimitry Andric }
54040b57cec5SDimitry Andric 
54050b57cec5SDimitry Andric // The flags here are common to those allowed for apsr in the A class cores and
54060b57cec5SDimitry Andric // those allowed for the special registers in the M class cores. Returns a
54070b57cec5SDimitry Andric // value representing which flags were present, -1 if invalid.
getMClassFlagsMask(StringRef Flags)54080b57cec5SDimitry Andric static inline int getMClassFlagsMask(StringRef Flags) {
54090b57cec5SDimitry Andric   return StringSwitch<int>(Flags)
54100b57cec5SDimitry Andric           .Case("", 0x2) // no flags means nzcvq for psr registers, and 0x2 is
54110b57cec5SDimitry Andric                          // correct when flags are not permitted
54120b57cec5SDimitry Andric           .Case("g", 0x1)
54130b57cec5SDimitry Andric           .Case("nzcvq", 0x2)
54140b57cec5SDimitry Andric           .Case("nzcvqg", 0x3)
54150b57cec5SDimitry Andric           .Default(-1);
54160b57cec5SDimitry Andric }
54170b57cec5SDimitry Andric 
54180b57cec5SDimitry Andric // Maps MClass special registers string to its value for use in the
54190b57cec5SDimitry Andric // t2MRS_M/t2MSR_M instruction nodes as the SYSm value operand.
54200b57cec5SDimitry Andric // Returns -1 to signify that the string was invalid.
getMClassRegisterMask(StringRef Reg,const ARMSubtarget * Subtarget)54210b57cec5SDimitry Andric static int getMClassRegisterMask(StringRef Reg, const ARMSubtarget *Subtarget) {
54220b57cec5SDimitry Andric   auto TheReg = ARMSysReg::lookupMClassSysRegByName(Reg);
54230b57cec5SDimitry Andric   const FeatureBitset &FeatureBits = Subtarget->getFeatureBits();
54240b57cec5SDimitry Andric   if (!TheReg || !TheReg->hasRequiredFeatures(FeatureBits))
54250b57cec5SDimitry Andric     return -1;
54260b57cec5SDimitry Andric   return (int)(TheReg->Encoding & 0xFFF); // SYSm value
54270b57cec5SDimitry Andric }
54280b57cec5SDimitry Andric 
getARClassRegisterMask(StringRef Reg,StringRef Flags)54290b57cec5SDimitry Andric static int getARClassRegisterMask(StringRef Reg, StringRef Flags) {
54300b57cec5SDimitry Andric   // The mask operand contains the special register (R Bit) in bit 4, whether
54310b57cec5SDimitry Andric   // the register is spsr (R bit is 1) or one of cpsr/apsr (R bit is 0), and
54320b57cec5SDimitry Andric   // bits 3-0 contains the fields to be accessed in the special register, set by
54330b57cec5SDimitry Andric   // the flags provided with the register.
54340b57cec5SDimitry Andric   int Mask = 0;
54350b57cec5SDimitry Andric   if (Reg == "apsr") {
54360b57cec5SDimitry Andric     // The flags permitted for apsr are the same flags that are allowed in
54370b57cec5SDimitry Andric     // M class registers. We get the flag value and then shift the flags into
54380b57cec5SDimitry Andric     // the correct place to combine with the mask.
54390b57cec5SDimitry Andric     Mask = getMClassFlagsMask(Flags);
54400b57cec5SDimitry Andric     if (Mask == -1)
54410b57cec5SDimitry Andric       return -1;
54420b57cec5SDimitry Andric     return Mask << 2;
54430b57cec5SDimitry Andric   }
54440b57cec5SDimitry Andric 
54450b57cec5SDimitry Andric   if (Reg != "cpsr" && Reg != "spsr") {
54460b57cec5SDimitry Andric     return -1;
54470b57cec5SDimitry Andric   }
54480b57cec5SDimitry Andric 
54490b57cec5SDimitry Andric   // This is the same as if the flags were "fc"
54500b57cec5SDimitry Andric   if (Flags.empty() || Flags == "all")
54510b57cec5SDimitry Andric     return Mask | 0x9;
54520b57cec5SDimitry Andric 
54530b57cec5SDimitry Andric   // Inspect the supplied flags string and set the bits in the mask for
54540b57cec5SDimitry Andric   // the relevant and valid flags allowed for cpsr and spsr.
54550b57cec5SDimitry Andric   for (char Flag : Flags) {
54560b57cec5SDimitry Andric     int FlagVal;
54570b57cec5SDimitry Andric     switch (Flag) {
54580b57cec5SDimitry Andric       case 'c':
54590b57cec5SDimitry Andric         FlagVal = 0x1;
54600b57cec5SDimitry Andric         break;
54610b57cec5SDimitry Andric       case 'x':
54620b57cec5SDimitry Andric         FlagVal = 0x2;
54630b57cec5SDimitry Andric         break;
54640b57cec5SDimitry Andric       case 's':
54650b57cec5SDimitry Andric         FlagVal = 0x4;
54660b57cec5SDimitry Andric         break;
54670b57cec5SDimitry Andric       case 'f':
54680b57cec5SDimitry Andric         FlagVal = 0x8;
54690b57cec5SDimitry Andric         break;
54700b57cec5SDimitry Andric       default:
54710b57cec5SDimitry Andric         FlagVal = 0;
54720b57cec5SDimitry Andric     }
54730b57cec5SDimitry Andric 
54740b57cec5SDimitry Andric     // This avoids allowing strings where the same flag bit appears twice.
54750b57cec5SDimitry Andric     if (!FlagVal || (Mask & FlagVal))
54760b57cec5SDimitry Andric       return -1;
54770b57cec5SDimitry Andric     Mask |= FlagVal;
54780b57cec5SDimitry Andric   }
54790b57cec5SDimitry Andric 
54800b57cec5SDimitry Andric   // If the register is spsr then we need to set the R bit.
54810b57cec5SDimitry Andric   if (Reg == "spsr")
54820b57cec5SDimitry Andric     Mask |= 0x10;
54830b57cec5SDimitry Andric 
54840b57cec5SDimitry Andric   return Mask;
54850b57cec5SDimitry Andric }
54860b57cec5SDimitry Andric 
54870b57cec5SDimitry Andric // Lower the read_register intrinsic to ARM specific DAG nodes
54880b57cec5SDimitry Andric // using the supplied metadata string to select the instruction node to use
54890b57cec5SDimitry Andric // and the registers/masks to construct as operands for the node.
tryReadRegister(SDNode * N)54900b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryReadRegister(SDNode *N){
5491349cc55cSDimitry Andric   const auto *MD = cast<MDNodeSDNode>(N->getOperand(1));
5492349cc55cSDimitry Andric   const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0));
54930b57cec5SDimitry Andric   bool IsThumb2 = Subtarget->isThumb2();
54940b57cec5SDimitry Andric   SDLoc DL(N);
54950b57cec5SDimitry Andric 
54960b57cec5SDimitry Andric   std::vector<SDValue> Ops;
54970b57cec5SDimitry Andric   getIntOperandsFromRegisterString(RegString->getString(), CurDAG, DL, Ops);
54980b57cec5SDimitry Andric 
54990b57cec5SDimitry Andric   if (!Ops.empty()) {
55000b57cec5SDimitry Andric     // If the special register string was constructed of fields (as defined
55010b57cec5SDimitry Andric     // in the ACLE) then need to lower to MRC node (32 bit) or
55020b57cec5SDimitry Andric     // MRRC node(64 bit), we can make the distinction based on the number of
55030b57cec5SDimitry Andric     // operands we have.
55040b57cec5SDimitry Andric     unsigned Opcode;
55050b57cec5SDimitry Andric     SmallVector<EVT, 3> ResTypes;
55060b57cec5SDimitry Andric     if (Ops.size() == 5){
55070b57cec5SDimitry Andric       Opcode = IsThumb2 ? ARM::t2MRC : ARM::MRC;
55080b57cec5SDimitry Andric       ResTypes.append({ MVT::i32, MVT::Other });
55090b57cec5SDimitry Andric     } else {
55100b57cec5SDimitry Andric       assert(Ops.size() == 3 &&
55110b57cec5SDimitry Andric               "Invalid number of fields in special register string.");
55120b57cec5SDimitry Andric       Opcode = IsThumb2 ? ARM::t2MRRC : ARM::MRRC;
55130b57cec5SDimitry Andric       ResTypes.append({ MVT::i32, MVT::i32, MVT::Other });
55140b57cec5SDimitry Andric     }
55150b57cec5SDimitry Andric 
55160b57cec5SDimitry Andric     Ops.push_back(getAL(CurDAG, DL));
55170b57cec5SDimitry Andric     Ops.push_back(CurDAG->getRegister(0, MVT::i32));
55180b57cec5SDimitry Andric     Ops.push_back(N->getOperand(0));
55190b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, ResTypes, Ops));
55200b57cec5SDimitry Andric     return true;
55210b57cec5SDimitry Andric   }
55220b57cec5SDimitry Andric 
55230b57cec5SDimitry Andric   std::string SpecialReg = RegString->getString().lower();
55240b57cec5SDimitry Andric 
55250b57cec5SDimitry Andric   int BankedReg = getBankedRegisterMask(SpecialReg);
55260b57cec5SDimitry Andric   if (BankedReg != -1) {
55270b57cec5SDimitry Andric     Ops = { CurDAG->getTargetConstant(BankedReg, DL, MVT::i32),
55280b57cec5SDimitry Andric             getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
55290b57cec5SDimitry Andric             N->getOperand(0) };
55300b57cec5SDimitry Andric     ReplaceNode(
55310b57cec5SDimitry Andric         N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRSbanked : ARM::MRSbanked,
55320b57cec5SDimitry Andric                                   DL, MVT::i32, MVT::Other, Ops));
55330b57cec5SDimitry Andric     return true;
55340b57cec5SDimitry Andric   }
55350b57cec5SDimitry Andric 
55360b57cec5SDimitry Andric   // The VFP registers are read by creating SelectionDAG nodes with opcodes
55370b57cec5SDimitry Andric   // corresponding to the register that is being read from. So we switch on the
55380b57cec5SDimitry Andric   // string to find which opcode we need to use.
55390b57cec5SDimitry Andric   unsigned Opcode = StringSwitch<unsigned>(SpecialReg)
55400b57cec5SDimitry Andric                     .Case("fpscr", ARM::VMRS)
55410b57cec5SDimitry Andric                     .Case("fpexc", ARM::VMRS_FPEXC)
55420b57cec5SDimitry Andric                     .Case("fpsid", ARM::VMRS_FPSID)
55430b57cec5SDimitry Andric                     .Case("mvfr0", ARM::VMRS_MVFR0)
55440b57cec5SDimitry Andric                     .Case("mvfr1", ARM::VMRS_MVFR1)
55450b57cec5SDimitry Andric                     .Case("mvfr2", ARM::VMRS_MVFR2)
55460b57cec5SDimitry Andric                     .Case("fpinst", ARM::VMRS_FPINST)
55470b57cec5SDimitry Andric                     .Case("fpinst2", ARM::VMRS_FPINST2)
55480b57cec5SDimitry Andric                     .Default(0);
55490b57cec5SDimitry Andric 
55500b57cec5SDimitry Andric   // If an opcode was found then we can lower the read to a VFP instruction.
55510b57cec5SDimitry Andric   if (Opcode) {
55520b57cec5SDimitry Andric     if (!Subtarget->hasVFP2Base())
55530b57cec5SDimitry Andric       return false;
55540b57cec5SDimitry Andric     if (Opcode == ARM::VMRS_MVFR2 && !Subtarget->hasFPARMv8Base())
55550b57cec5SDimitry Andric       return false;
55560b57cec5SDimitry Andric 
55570b57cec5SDimitry Andric     Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
55580b57cec5SDimitry Andric             N->getOperand(0) };
55590b57cec5SDimitry Andric     ReplaceNode(N,
55600b57cec5SDimitry Andric                 CurDAG->getMachineNode(Opcode, DL, MVT::i32, MVT::Other, Ops));
55610b57cec5SDimitry Andric     return true;
55620b57cec5SDimitry Andric   }
55630b57cec5SDimitry Andric 
55640b57cec5SDimitry Andric   // If the target is M Class then need to validate that the register string
55650b57cec5SDimitry Andric   // is an acceptable value, so check that a mask can be constructed from the
55660b57cec5SDimitry Andric   // string.
55670b57cec5SDimitry Andric   if (Subtarget->isMClass()) {
55680b57cec5SDimitry Andric     int SYSmValue = getMClassRegisterMask(SpecialReg, Subtarget);
55690b57cec5SDimitry Andric     if (SYSmValue == -1)
55700b57cec5SDimitry Andric       return false;
55710b57cec5SDimitry Andric 
55720b57cec5SDimitry Andric     SDValue Ops[] = { CurDAG->getTargetConstant(SYSmValue, DL, MVT::i32),
55730b57cec5SDimitry Andric                       getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
55740b57cec5SDimitry Andric                       N->getOperand(0) };
55750b57cec5SDimitry Andric     ReplaceNode(
55760b57cec5SDimitry Andric         N, CurDAG->getMachineNode(ARM::t2MRS_M, DL, MVT::i32, MVT::Other, Ops));
55770b57cec5SDimitry Andric     return true;
55780b57cec5SDimitry Andric   }
55790b57cec5SDimitry Andric 
55800b57cec5SDimitry Andric   // Here we know the target is not M Class so we need to check if it is one
55810b57cec5SDimitry Andric   // of the remaining possible values which are apsr, cpsr or spsr.
55820b57cec5SDimitry Andric   if (SpecialReg == "apsr" || SpecialReg == "cpsr") {
55830b57cec5SDimitry Andric     Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
55840b57cec5SDimitry Andric             N->getOperand(0) };
55850b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRS_AR : ARM::MRS,
55860b57cec5SDimitry Andric                                           DL, MVT::i32, MVT::Other, Ops));
55870b57cec5SDimitry Andric     return true;
55880b57cec5SDimitry Andric   }
55890b57cec5SDimitry Andric 
55900b57cec5SDimitry Andric   if (SpecialReg == "spsr") {
55910b57cec5SDimitry Andric     Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
55920b57cec5SDimitry Andric             N->getOperand(0) };
55930b57cec5SDimitry Andric     ReplaceNode(
55940b57cec5SDimitry Andric         N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRSsys_AR : ARM::MRSsys, DL,
55950b57cec5SDimitry Andric                                   MVT::i32, MVT::Other, Ops));
55960b57cec5SDimitry Andric     return true;
55970b57cec5SDimitry Andric   }
55980b57cec5SDimitry Andric 
55990b57cec5SDimitry Andric   return false;
56000b57cec5SDimitry Andric }
56010b57cec5SDimitry Andric 
56020b57cec5SDimitry Andric // Lower the write_register intrinsic to ARM specific DAG nodes
56030b57cec5SDimitry Andric // using the supplied metadata string to select the instruction node to use
56040b57cec5SDimitry Andric // and the registers/masks to use in the nodes
tryWriteRegister(SDNode * N)56050b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryWriteRegister(SDNode *N){
5606349cc55cSDimitry Andric   const auto *MD = cast<MDNodeSDNode>(N->getOperand(1));
5607349cc55cSDimitry Andric   const auto *RegString = cast<MDString>(MD->getMD()->getOperand(0));
56080b57cec5SDimitry Andric   bool IsThumb2 = Subtarget->isThumb2();
56090b57cec5SDimitry Andric   SDLoc DL(N);
56100b57cec5SDimitry Andric 
56110b57cec5SDimitry Andric   std::vector<SDValue> Ops;
56120b57cec5SDimitry Andric   getIntOperandsFromRegisterString(RegString->getString(), CurDAG, DL, Ops);
56130b57cec5SDimitry Andric 
56140b57cec5SDimitry Andric   if (!Ops.empty()) {
56150b57cec5SDimitry Andric     // If the special register string was constructed of fields (as defined
56160b57cec5SDimitry Andric     // in the ACLE) then need to lower to MCR node (32 bit) or
56170b57cec5SDimitry Andric     // MCRR node(64 bit), we can make the distinction based on the number of
56180b57cec5SDimitry Andric     // operands we have.
56190b57cec5SDimitry Andric     unsigned Opcode;
56200b57cec5SDimitry Andric     if (Ops.size() == 5) {
56210b57cec5SDimitry Andric       Opcode = IsThumb2 ? ARM::t2MCR : ARM::MCR;
56220b57cec5SDimitry Andric       Ops.insert(Ops.begin()+2, N->getOperand(2));
56230b57cec5SDimitry Andric     } else {
56240b57cec5SDimitry Andric       assert(Ops.size() == 3 &&
56250b57cec5SDimitry Andric               "Invalid number of fields in special register string.");
56260b57cec5SDimitry Andric       Opcode = IsThumb2 ? ARM::t2MCRR : ARM::MCRR;
56270b57cec5SDimitry Andric       SDValue WriteValue[] = { N->getOperand(2), N->getOperand(3) };
56280b57cec5SDimitry Andric       Ops.insert(Ops.begin()+2, WriteValue, WriteValue+2);
56290b57cec5SDimitry Andric     }
56300b57cec5SDimitry Andric 
56310b57cec5SDimitry Andric     Ops.push_back(getAL(CurDAG, DL));
56320b57cec5SDimitry Andric     Ops.push_back(CurDAG->getRegister(0, MVT::i32));
56330b57cec5SDimitry Andric     Ops.push_back(N->getOperand(0));
56340b57cec5SDimitry Andric 
56350b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops));
56360b57cec5SDimitry Andric     return true;
56370b57cec5SDimitry Andric   }
56380b57cec5SDimitry Andric 
56390b57cec5SDimitry Andric   std::string SpecialReg = RegString->getString().lower();
56400b57cec5SDimitry Andric   int BankedReg = getBankedRegisterMask(SpecialReg);
56410b57cec5SDimitry Andric   if (BankedReg != -1) {
56420b57cec5SDimitry Andric     Ops = { CurDAG->getTargetConstant(BankedReg, DL, MVT::i32), N->getOperand(2),
56430b57cec5SDimitry Andric             getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
56440b57cec5SDimitry Andric             N->getOperand(0) };
56450b57cec5SDimitry Andric     ReplaceNode(
56460b57cec5SDimitry Andric         N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MSRbanked : ARM::MSRbanked,
56470b57cec5SDimitry Andric                                   DL, MVT::Other, Ops));
56480b57cec5SDimitry Andric     return true;
56490b57cec5SDimitry Andric   }
56500b57cec5SDimitry Andric 
56510b57cec5SDimitry Andric   // The VFP registers are written to by creating SelectionDAG nodes with
56520b57cec5SDimitry Andric   // opcodes corresponding to the register that is being written. So we switch
56530b57cec5SDimitry Andric   // on the string to find which opcode we need to use.
56540b57cec5SDimitry Andric   unsigned Opcode = StringSwitch<unsigned>(SpecialReg)
56550b57cec5SDimitry Andric                     .Case("fpscr", ARM::VMSR)
56560b57cec5SDimitry Andric                     .Case("fpexc", ARM::VMSR_FPEXC)
56570b57cec5SDimitry Andric                     .Case("fpsid", ARM::VMSR_FPSID)
56580b57cec5SDimitry Andric                     .Case("fpinst", ARM::VMSR_FPINST)
56590b57cec5SDimitry Andric                     .Case("fpinst2", ARM::VMSR_FPINST2)
56600b57cec5SDimitry Andric                     .Default(0);
56610b57cec5SDimitry Andric 
56620b57cec5SDimitry Andric   if (Opcode) {
56630b57cec5SDimitry Andric     if (!Subtarget->hasVFP2Base())
56640b57cec5SDimitry Andric       return false;
56650b57cec5SDimitry Andric     Ops = { N->getOperand(2), getAL(CurDAG, DL),
56660b57cec5SDimitry Andric             CurDAG->getRegister(0, MVT::i32), N->getOperand(0) };
56670b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops));
56680b57cec5SDimitry Andric     return true;
56690b57cec5SDimitry Andric   }
56700b57cec5SDimitry Andric 
56710b57cec5SDimitry Andric   std::pair<StringRef, StringRef> Fields;
56720b57cec5SDimitry Andric   Fields = StringRef(SpecialReg).rsplit('_');
56730b57cec5SDimitry Andric   std::string Reg = Fields.first.str();
56740b57cec5SDimitry Andric   StringRef Flags = Fields.second;
56750b57cec5SDimitry Andric 
56760b57cec5SDimitry Andric   // If the target was M Class then need to validate the special register value
56770b57cec5SDimitry Andric   // and retrieve the mask for use in the instruction node.
56780b57cec5SDimitry Andric   if (Subtarget->isMClass()) {
56790b57cec5SDimitry Andric     int SYSmValue = getMClassRegisterMask(SpecialReg, Subtarget);
56800b57cec5SDimitry Andric     if (SYSmValue == -1)
56810b57cec5SDimitry Andric       return false;
56820b57cec5SDimitry Andric 
56830b57cec5SDimitry Andric     SDValue Ops[] = { CurDAG->getTargetConstant(SYSmValue, DL, MVT::i32),
56840b57cec5SDimitry Andric                       N->getOperand(2), getAL(CurDAG, DL),
56850b57cec5SDimitry Andric                       CurDAG->getRegister(0, MVT::i32), N->getOperand(0) };
56860b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(ARM::t2MSR_M, DL, MVT::Other, Ops));
56870b57cec5SDimitry Andric     return true;
56880b57cec5SDimitry Andric   }
56890b57cec5SDimitry Andric 
56900b57cec5SDimitry Andric   // We then check to see if a valid mask can be constructed for one of the
56910b57cec5SDimitry Andric   // register string values permitted for the A and R class cores. These values
56920b57cec5SDimitry Andric   // are apsr, spsr and cpsr; these are also valid on older cores.
56930b57cec5SDimitry Andric   int Mask = getARClassRegisterMask(Reg, Flags);
56940b57cec5SDimitry Andric   if (Mask != -1) {
56950b57cec5SDimitry Andric     Ops = { CurDAG->getTargetConstant(Mask, DL, MVT::i32), N->getOperand(2),
56960b57cec5SDimitry Andric             getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
56970b57cec5SDimitry Andric             N->getOperand(0) };
56980b57cec5SDimitry Andric     ReplaceNode(N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MSR_AR : ARM::MSR,
56990b57cec5SDimitry Andric                                           DL, MVT::Other, Ops));
57000b57cec5SDimitry Andric     return true;
57010b57cec5SDimitry Andric   }
57020b57cec5SDimitry Andric 
57030b57cec5SDimitry Andric   return false;
57040b57cec5SDimitry Andric }
57050b57cec5SDimitry Andric 
tryInlineAsm(SDNode * N)57060b57cec5SDimitry Andric bool ARMDAGToDAGISel::tryInlineAsm(SDNode *N){
57070b57cec5SDimitry Andric   std::vector<SDValue> AsmNodeOperands;
57085f757f3fSDimitry Andric   InlineAsm::Flag Flag;
57090b57cec5SDimitry Andric   bool Changed = false;
57100b57cec5SDimitry Andric   unsigned NumOps = N->getNumOperands();
57110b57cec5SDimitry Andric 
57120b57cec5SDimitry Andric   // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
57130b57cec5SDimitry Andric   // However, some instrstions (e.g. ldrexd/strexd in ARM mode) require
57140b57cec5SDimitry Andric   // (even/even+1) GPRs and use %n and %Hn to refer to the individual regs
57150b57cec5SDimitry Andric   // respectively. Since there is no constraint to explicitly specify a
57160b57cec5SDimitry Andric   // reg pair, we use GPRPair reg class for "%r" for 64-bit data. For Thumb,
57170b57cec5SDimitry Andric   // the 64-bit data may be referred by H, Q, R modifiers, so we still pack
57180b57cec5SDimitry Andric   // them into a GPRPair.
57190b57cec5SDimitry Andric 
57200b57cec5SDimitry Andric   SDLoc dl(N);
572104eeddc0SDimitry Andric   SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue();
57220b57cec5SDimitry Andric 
57230b57cec5SDimitry Andric   SmallVector<bool, 8> OpChanged;
57240b57cec5SDimitry Andric   // Glue node will be appended late.
57250b57cec5SDimitry Andric   for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
57260b57cec5SDimitry Andric     SDValue op = N->getOperand(i);
57270b57cec5SDimitry Andric     AsmNodeOperands.push_back(op);
57280b57cec5SDimitry Andric 
57290b57cec5SDimitry Andric     if (i < InlineAsm::Op_FirstOperand)
57300b57cec5SDimitry Andric       continue;
57310b57cec5SDimitry Andric 
57325f757f3fSDimitry Andric     if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))
57335f757f3fSDimitry Andric       Flag = InlineAsm::Flag(C->getZExtValue());
57340b57cec5SDimitry Andric     else
57350b57cec5SDimitry Andric       continue;
57360b57cec5SDimitry Andric 
57370b57cec5SDimitry Andric     // Immediate operands to inline asm in the SelectionDAG are modeled with
57385f757f3fSDimitry Andric     // two operands. The first is a constant of value InlineAsm::Kind::Imm, and
57390b57cec5SDimitry Andric     // the second is a constant with the value of the immediate. If we get here
57405f757f3fSDimitry Andric     // and we have a Kind::Imm, skip the next operand, and continue.
57415f757f3fSDimitry Andric     if (Flag.isImmKind()) {
57420b57cec5SDimitry Andric       SDValue op = N->getOperand(++i);
57430b57cec5SDimitry Andric       AsmNodeOperands.push_back(op);
57440b57cec5SDimitry Andric       continue;
57450b57cec5SDimitry Andric     }
57460b57cec5SDimitry Andric 
57475f757f3fSDimitry Andric     const unsigned NumRegs = Flag.getNumOperandRegisters();
57480b57cec5SDimitry Andric     if (NumRegs)
57490b57cec5SDimitry Andric       OpChanged.push_back(false);
57500b57cec5SDimitry Andric 
57510b57cec5SDimitry Andric     unsigned DefIdx = 0;
57520b57cec5SDimitry Andric     bool IsTiedToChangedOp = false;
57530b57cec5SDimitry Andric     // If it's a use that is tied with a previous def, it has no
57540b57cec5SDimitry Andric     // reg class constraint.
57555f757f3fSDimitry Andric     if (Changed && Flag.isUseOperandTiedToDef(DefIdx))
57560b57cec5SDimitry Andric       IsTiedToChangedOp = OpChanged[DefIdx];
57570b57cec5SDimitry Andric 
57580b57cec5SDimitry Andric     // Memory operands to inline asm in the SelectionDAG are modeled with two
57595f757f3fSDimitry Andric     // operands: a constant of value InlineAsm::Kind::Mem followed by the input
57605f757f3fSDimitry Andric     // operand. If we get here and we have a Kind::Mem, skip the next operand
57615f757f3fSDimitry Andric     // (so it doesn't get misinterpreted), and continue. We do this here because
57620b57cec5SDimitry Andric     // it's important to update the OpChanged array correctly before moving on.
57635f757f3fSDimitry Andric     if (Flag.isMemKind()) {
57640b57cec5SDimitry Andric       SDValue op = N->getOperand(++i);
57650b57cec5SDimitry Andric       AsmNodeOperands.push_back(op);
57660b57cec5SDimitry Andric       continue;
57670b57cec5SDimitry Andric     }
57680b57cec5SDimitry Andric 
57695f757f3fSDimitry Andric     if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&
57705f757f3fSDimitry Andric         !Flag.isRegDefEarlyClobberKind())
57710b57cec5SDimitry Andric       continue;
57720b57cec5SDimitry Andric 
57730b57cec5SDimitry Andric     unsigned RC;
57745f757f3fSDimitry Andric     const bool HasRC = Flag.hasRegClassConstraint(RC);
57750b57cec5SDimitry Andric     if ((!IsTiedToChangedOp && (!HasRC || RC != ARM::GPRRegClassID))
57760b57cec5SDimitry Andric         || NumRegs != 2)
57770b57cec5SDimitry Andric       continue;
57780b57cec5SDimitry Andric 
57790b57cec5SDimitry Andric     assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
57800b57cec5SDimitry Andric     SDValue V0 = N->getOperand(i+1);
57810b57cec5SDimitry Andric     SDValue V1 = N->getOperand(i+2);
578204eeddc0SDimitry Andric     Register Reg0 = cast<RegisterSDNode>(V0)->getReg();
578304eeddc0SDimitry Andric     Register Reg1 = cast<RegisterSDNode>(V1)->getReg();
57840b57cec5SDimitry Andric     SDValue PairedReg;
57850b57cec5SDimitry Andric     MachineRegisterInfo &MRI = MF->getRegInfo();
57860b57cec5SDimitry Andric 
57875f757f3fSDimitry Andric     if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {
57880b57cec5SDimitry Andric       // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
57890b57cec5SDimitry Andric       // the original GPRs.
57900b57cec5SDimitry Andric 
57918bcb0991SDimitry Andric       Register GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
57920b57cec5SDimitry Andric       PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
57930b57cec5SDimitry Andric       SDValue Chain = SDValue(N,0);
57940b57cec5SDimitry Andric 
57950b57cec5SDimitry Andric       SDNode *GU = N->getGluedUser();
57960b57cec5SDimitry Andric       SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::Untyped,
57970b57cec5SDimitry Andric                                                Chain.getValue(1));
57980b57cec5SDimitry Andric 
57990b57cec5SDimitry Andric       // Extract values from a GPRPair reg and copy to the original GPR reg.
58000b57cec5SDimitry Andric       SDValue Sub0 = CurDAG->getTargetExtractSubreg(ARM::gsub_0, dl, MVT::i32,
58010b57cec5SDimitry Andric                                                     RegCopy);
58020b57cec5SDimitry Andric       SDValue Sub1 = CurDAG->getTargetExtractSubreg(ARM::gsub_1, dl, MVT::i32,
58030b57cec5SDimitry Andric                                                     RegCopy);
58040b57cec5SDimitry Andric       SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
58050b57cec5SDimitry Andric                                         RegCopy.getValue(1));
58060b57cec5SDimitry Andric       SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
58070b57cec5SDimitry Andric 
58080b57cec5SDimitry Andric       // Update the original glue user.
58090b57cec5SDimitry Andric       std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
58100b57cec5SDimitry Andric       Ops.push_back(T1.getValue(1));
58110b57cec5SDimitry Andric       CurDAG->UpdateNodeOperands(GU, Ops);
58125f757f3fSDimitry Andric     } else {
58135f757f3fSDimitry Andric       // For Kind  == InlineAsm::Kind::RegUse, we first copy two GPRs into a
58140b57cec5SDimitry Andric       // GPRPair and then pass the GPRPair to the inline asm.
58150b57cec5SDimitry Andric       SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
58160b57cec5SDimitry Andric 
58170b57cec5SDimitry Andric       // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
58180b57cec5SDimitry Andric       SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
58190b57cec5SDimitry Andric                                           Chain.getValue(1));
58200b57cec5SDimitry Andric       SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
58210b57cec5SDimitry Andric                                           T0.getValue(1));
58220b57cec5SDimitry Andric       SDValue Pair = SDValue(createGPRPairNode(MVT::Untyped, T0, T1), 0);
58230b57cec5SDimitry Andric 
58240b57cec5SDimitry Andric       // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
58250b57cec5SDimitry Andric       // i32 VRs of inline asm with it.
58268bcb0991SDimitry Andric       Register GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
58270b57cec5SDimitry Andric       PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
58280b57cec5SDimitry Andric       Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
58290b57cec5SDimitry Andric 
58300b57cec5SDimitry Andric       AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
58310b57cec5SDimitry Andric       Glue = Chain.getValue(1);
58320b57cec5SDimitry Andric     }
58330b57cec5SDimitry Andric 
58340b57cec5SDimitry Andric     Changed = true;
58350b57cec5SDimitry Andric 
58360b57cec5SDimitry Andric     if(PairedReg.getNode()) {
58370b57cec5SDimitry Andric       OpChanged[OpChanged.size() -1 ] = true;
58385f757f3fSDimitry Andric       Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);
58390b57cec5SDimitry Andric       if (IsTiedToChangedOp)
58405f757f3fSDimitry Andric         Flag.setMatchingOp(DefIdx);
58410b57cec5SDimitry Andric       else
58425f757f3fSDimitry Andric         Flag.setRegClass(ARM::GPRPairRegClassID);
58430b57cec5SDimitry Andric       // Replace the current flag.
58440b57cec5SDimitry Andric       AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
58450b57cec5SDimitry Andric           Flag, dl, MVT::i32);
58460b57cec5SDimitry Andric       // Add the new register node and skip the original two GPRs.
58470b57cec5SDimitry Andric       AsmNodeOperands.push_back(PairedReg);
58480b57cec5SDimitry Andric       // Skip the next two GPRs.
58490b57cec5SDimitry Andric       i += 2;
58500b57cec5SDimitry Andric     }
58510b57cec5SDimitry Andric   }
58520b57cec5SDimitry Andric 
58530b57cec5SDimitry Andric   if (Glue.getNode())
58540b57cec5SDimitry Andric     AsmNodeOperands.push_back(Glue);
58550b57cec5SDimitry Andric   if (!Changed)
58560b57cec5SDimitry Andric     return false;
58570b57cec5SDimitry Andric 
58580b57cec5SDimitry Andric   SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
58590b57cec5SDimitry Andric       CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
58600b57cec5SDimitry Andric   New->setNodeId(-1);
58610b57cec5SDimitry Andric   ReplaceNode(N, New.getNode());
58620b57cec5SDimitry Andric   return true;
58630b57cec5SDimitry Andric }
58640b57cec5SDimitry Andric 
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintID,std::vector<SDValue> & OutOps)58655f757f3fSDimitry Andric bool ARMDAGToDAGISel::SelectInlineAsmMemoryOperand(
58665f757f3fSDimitry Andric     const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
58670b57cec5SDimitry Andric     std::vector<SDValue> &OutOps) {
58680b57cec5SDimitry Andric   switch(ConstraintID) {
58690b57cec5SDimitry Andric   default:
58700b57cec5SDimitry Andric     llvm_unreachable("Unexpected asm memory constraint");
58715f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::m:
58725f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::o:
58735f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Q:
58745f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Um:
58755f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Un:
58765f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Uq:
58775f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Us:
58785f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Ut:
58795f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Uv:
58805f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::Uy:
58810b57cec5SDimitry Andric     // Require the address to be in a register.  That is safe for all ARM
58820b57cec5SDimitry Andric     // variants and it is hard to do anything much smarter without knowing
58830b57cec5SDimitry Andric     // how the operand is used.
58840b57cec5SDimitry Andric     OutOps.push_back(Op);
58850b57cec5SDimitry Andric     return false;
58860b57cec5SDimitry Andric   }
58870b57cec5SDimitry Andric   return true;
58880b57cec5SDimitry Andric }
58890b57cec5SDimitry Andric 
58900b57cec5SDimitry Andric /// createARMISelDag - This pass converts a legalized DAG into a
58910b57cec5SDimitry Andric /// ARM-specific DAG, ready for instruction scheduling.
58920b57cec5SDimitry Andric ///
createARMISelDag(ARMBaseTargetMachine & TM,CodeGenOptLevel OptLevel)58930b57cec5SDimitry Andric FunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM,
58945f757f3fSDimitry Andric                                      CodeGenOptLevel OptLevel) {
5895*0fca6ea1SDimitry Andric   return new ARMDAGToDAGISelLegacy(TM, OptLevel);
58960b57cec5SDimitry Andric }
5897