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