ARMISelDAGToDAG.cpp revision 243830
1193323Sed//===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===// 2193323Sed// 3193323Sed// The LLVM Compiler Infrastructure 4193323Sed// 5193323Sed// This file is distributed under the University of Illinois Open Source 6193323Sed// License. See LICENSE.TXT for details. 7193323Sed// 8193323Sed//===----------------------------------------------------------------------===// 9193323Sed// 10193323Sed// This file defines an instruction selector for the ARM target. 11193323Sed// 12193323Sed//===----------------------------------------------------------------------===// 13193323Sed 14210299Sed#define DEBUG_TYPE "arm-isel" 15193323Sed#include "ARM.h" 16218893Sdim#include "ARMBaseInstrInfo.h" 17193323Sed#include "ARMTargetMachine.h" 18226633Sdim#include "MCTargetDesc/ARMAddressingModes.h" 19193323Sed#include "llvm/CallingConv.h" 20193323Sed#include "llvm/Constants.h" 21193323Sed#include "llvm/DerivedTypes.h" 22193323Sed#include "llvm/Function.h" 23193323Sed#include "llvm/Intrinsics.h" 24198090Srdivacky#include "llvm/LLVMContext.h" 25193323Sed#include "llvm/CodeGen/MachineFrameInfo.h" 26193323Sed#include "llvm/CodeGen/MachineFunction.h" 27193323Sed#include "llvm/CodeGen/MachineInstrBuilder.h" 28193323Sed#include "llvm/CodeGen/SelectionDAG.h" 29193323Sed#include "llvm/CodeGen/SelectionDAGISel.h" 30193323Sed#include "llvm/Target/TargetLowering.h" 31193323Sed#include "llvm/Target/TargetOptions.h" 32207631Srdivacky#include "llvm/Support/CommandLine.h" 33193323Sed#include "llvm/Support/Compiler.h" 34193323Sed#include "llvm/Support/Debug.h" 35198090Srdivacky#include "llvm/Support/ErrorHandling.h" 36198090Srdivacky#include "llvm/Support/raw_ostream.h" 37198090Srdivacky 38193323Sedusing namespace llvm; 39193323Sed 40212904Sdimstatic cl::opt<bool> 41212904SdimDisableShifterOp("disable-shifter-op", cl::Hidden, 42212904Sdim cl::desc("Disable isel of shifter-op"), 43212904Sdim cl::init(false)); 44212904Sdim 45218893Sdimstatic cl::opt<bool> 46218893SdimCheckVMLxHazard("check-vmlx-hazard", cl::Hidden, 47218893Sdim cl::desc("Check fp vmla / vmls hazard at isel time"), 48221345Sdim cl::init(true)); 49218893Sdim 50193323Sed//===--------------------------------------------------------------------===// 51193323Sed/// ARMDAGToDAGISel - ARM specific code to select ARM machine 52193323Sed/// instructions for SelectionDAG operations. 53193323Sed/// 54193323Sednamespace { 55218893Sdim 56218893Sdimenum AddrMode2Type { 57218893Sdim AM2_BASE, // Simple AM2 (+-imm12) 58218893Sdim AM2_SHOP // Shifter-op AM2 59218893Sdim}; 60218893Sdim 61193323Sedclass ARMDAGToDAGISel : public SelectionDAGISel { 62195098Sed ARMBaseTargetMachine &TM; 63218893Sdim const ARMBaseInstrInfo *TII; 64193323Sed 65193323Sed /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can 66193323Sed /// make the right decision when generating code for different targets. 67193323Sed const ARMSubtarget *Subtarget; 68193323Sed 69193323Sedpublic: 70198090Srdivacky explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm, 71198090Srdivacky CodeGenOpt::Level OptLevel) 72198090Srdivacky : SelectionDAGISel(tm, OptLevel), TM(tm), 73218893Sdim TII(static_cast<const ARMBaseInstrInfo*>(TM.getInstrInfo())), 74218893Sdim Subtarget(&TM.getSubtarget<ARMSubtarget>()) { 75193323Sed } 76193323Sed 77193323Sed virtual const char *getPassName() const { 78193323Sed return "ARM Instruction Selection"; 79194612Sed } 80194612Sed 81198090Srdivacky /// getI32Imm - Return a target constant of type i32 with the specified 82198090Srdivacky /// value. 83194612Sed inline SDValue getI32Imm(unsigned Imm) { 84194612Sed return CurDAG->getTargetConstant(Imm, MVT::i32); 85194612Sed } 86194612Sed 87202375Srdivacky SDNode *Select(SDNode *N); 88203954Srdivacky 89218893Sdim 90218893Sdim bool hasNoVMLxHazardUse(SDNode *N) const; 91218893Sdim bool isShifterOpProfitable(const SDValue &Shift, 92218893Sdim ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt); 93226633Sdim bool SelectRegShifterOperand(SDValue N, SDValue &A, 94221345Sdim SDValue &B, SDValue &C, 95221345Sdim bool CheckProfitability = true); 96226633Sdim bool SelectImmShifterOperand(SDValue N, SDValue &A, 97226633Sdim SDValue &B, bool CheckProfitability = true); 98226633Sdim bool SelectShiftRegShifterOperand(SDValue N, SDValue &A, 99221345Sdim SDValue &B, SDValue &C) { 100221345Sdim // Don't apply the profitability check 101226633Sdim return SelectRegShifterOperand(N, A, B, C, false); 102221345Sdim } 103226633Sdim bool SelectShiftImmShifterOperand(SDValue N, SDValue &A, 104226633Sdim SDValue &B) { 105226633Sdim // Don't apply the profitability check 106226633Sdim return SelectImmShifterOperand(N, A, B, false); 107226633Sdim } 108221345Sdim 109218893Sdim bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm); 110218893Sdim bool SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc); 111218893Sdim 112218893Sdim AddrMode2Type SelectAddrMode2Worker(SDValue N, SDValue &Base, 113218893Sdim SDValue &Offset, SDValue &Opc); 114218893Sdim bool SelectAddrMode2Base(SDValue N, SDValue &Base, SDValue &Offset, 115218893Sdim SDValue &Opc) { 116218893Sdim return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_BASE; 117218893Sdim } 118218893Sdim 119218893Sdim bool SelectAddrMode2ShOp(SDValue N, SDValue &Base, SDValue &Offset, 120218893Sdim SDValue &Opc) { 121218893Sdim return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_SHOP; 122218893Sdim } 123218893Sdim 124218893Sdim bool SelectAddrMode2(SDValue N, SDValue &Base, SDValue &Offset, 125218893Sdim SDValue &Opc) { 126218893Sdim SelectAddrMode2Worker(N, Base, Offset, Opc); 127218893Sdim// return SelectAddrMode2ShOp(N, Base, Offset, Opc); 128218893Sdim // This always matches one way or another. 129218893Sdim return true; 130218893Sdim } 131218893Sdim 132226633Sdim bool SelectAddrMode2OffsetReg(SDNode *Op, SDValue N, 133193323Sed SDValue &Offset, SDValue &Opc); 134226633Sdim bool SelectAddrMode2OffsetImm(SDNode *Op, SDValue N, 135226633Sdim SDValue &Offset, SDValue &Opc); 136226633Sdim bool SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N, 137226633Sdim SDValue &Offset, SDValue &Opc); 138226633Sdim bool SelectAddrOffsetNone(SDValue N, SDValue &Base); 139218893Sdim bool SelectAddrMode3(SDValue N, SDValue &Base, 140193323Sed SDValue &Offset, SDValue &Opc); 141202375Srdivacky bool SelectAddrMode3Offset(SDNode *Op, SDValue N, 142193323Sed SDValue &Offset, SDValue &Opc); 143218893Sdim bool SelectAddrMode5(SDValue N, SDValue &Base, 144193323Sed SDValue &Offset); 145218893Sdim bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align); 146219077Sdim bool SelectAddrMode6Offset(SDNode *Op, SDValue N, SDValue &Offset); 147193323Sed 148218893Sdim bool SelectAddrModePC(SDValue N, SDValue &Offset, SDValue &Label); 149193323Sed 150218893Sdim // Thumb Addressing Modes: 151218893Sdim bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset); 152218893Sdim bool SelectThumbAddrModeRI(SDValue N, SDValue &Base, SDValue &Offset, 153218893Sdim unsigned Scale); 154218893Sdim bool SelectThumbAddrModeRI5S1(SDValue N, SDValue &Base, SDValue &Offset); 155218893Sdim bool SelectThumbAddrModeRI5S2(SDValue N, SDValue &Base, SDValue &Offset); 156218893Sdim bool SelectThumbAddrModeRI5S4(SDValue N, SDValue &Base, SDValue &Offset); 157218893Sdim bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base, 158218893Sdim SDValue &OffImm); 159218893Sdim bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base, 160218893Sdim SDValue &OffImm); 161218893Sdim bool SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base, 162218893Sdim SDValue &OffImm); 163218893Sdim bool SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base, 164218893Sdim SDValue &OffImm); 165218893Sdim bool SelectThumbAddrModeSP(SDValue N, SDValue &Base, SDValue &OffImm); 166193323Sed 167218893Sdim // Thumb 2 Addressing Modes: 168218893Sdim bool SelectT2ShifterOperandReg(SDValue N, 169195098Sed SDValue &BaseReg, SDValue &Opc); 170218893Sdim bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm); 171218893Sdim bool SelectT2AddrModeImm8(SDValue N, SDValue &Base, 172195340Sed SDValue &OffImm); 173202375Srdivacky bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, 174195340Sed SDValue &OffImm); 175218893Sdim bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base, 176195340Sed SDValue &OffReg, SDValue &ShImm); 177195340Sed 178218893Sdim inline bool is_so_imm(unsigned Imm) const { 179218893Sdim return ARM_AM::getSOImmVal(Imm) != -1; 180218893Sdim } 181218893Sdim 182218893Sdim inline bool is_so_imm_not(unsigned Imm) const { 183218893Sdim return ARM_AM::getSOImmVal(~Imm) != -1; 184218893Sdim } 185218893Sdim 186218893Sdim inline bool is_t2_so_imm(unsigned Imm) const { 187218893Sdim return ARM_AM::getT2SOImmVal(Imm) != -1; 188218893Sdim } 189218893Sdim 190218893Sdim inline bool is_t2_so_imm_not(unsigned Imm) const { 191218893Sdim return ARM_AM::getT2SOImmVal(~Imm) != -1; 192218893Sdim } 193218893Sdim 194193323Sed // Include the pieces autogenerated from the target description. 195193323Sed#include "ARMGenDAGISel.inc" 196193323Sed 197193323Sedprivate: 198195340Sed /// SelectARMIndexedLoad - Indexed (pre/post inc/dec) load matching code for 199195340Sed /// ARM. 200202375Srdivacky SDNode *SelectARMIndexedLoad(SDNode *N); 201202375Srdivacky SDNode *SelectT2IndexedLoad(SDNode *N); 202195340Sed 203206083Srdivacky /// SelectVLD - Select NEON load intrinsics. NumVecs should be 204206083Srdivacky /// 1, 2, 3 or 4. The opcode arrays specify the instructions used for 205198090Srdivacky /// loads of D registers and even subregs and odd subregs of Q registers. 206206083Srdivacky /// For NumVecs <= 2, QOpcodes1 is not used. 207218893Sdim SDNode *SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs, 208239462Sdim const uint16_t *DOpcodes, 209239462Sdim const uint16_t *QOpcodes0, const uint16_t *QOpcodes1); 210198090Srdivacky 211198113Srdivacky /// SelectVST - Select NEON store intrinsics. NumVecs should 212206083Srdivacky /// be 1, 2, 3 or 4. The opcode arrays specify the instructions used for 213198113Srdivacky /// stores of D registers and even subregs and odd subregs of Q registers. 214206083Srdivacky /// For NumVecs <= 2, QOpcodes1 is not used. 215218893Sdim SDNode *SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs, 216239462Sdim const uint16_t *DOpcodes, 217239462Sdim const uint16_t *QOpcodes0, const uint16_t *QOpcodes1); 218198113Srdivacky 219198090Srdivacky /// SelectVLDSTLane - Select NEON load/store lane intrinsics. NumVecs should 220198090Srdivacky /// be 2, 3 or 4. The opcode arrays specify the instructions used for 221218893Sdim /// load/store of D registers and Q registers. 222218893Sdim SDNode *SelectVLDSTLane(SDNode *N, bool IsLoad, 223218893Sdim bool isUpdating, unsigned NumVecs, 224239462Sdim const uint16_t *DOpcodes, const uint16_t *QOpcodes); 225198090Srdivacky 226218893Sdim /// SelectVLDDup - Select NEON load-duplicate intrinsics. NumVecs 227218893Sdim /// should be 2, 3 or 4. The opcode array specifies the instructions used 228218893Sdim /// for loading D registers. (Q registers are not supported.) 229218893Sdim SDNode *SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs, 230239462Sdim const uint16_t *Opcodes); 231218893Sdim 232210299Sed /// SelectVTBL - Select NEON VTBL and VTBX intrinsics. NumVecs should be 2, 233210299Sed /// 3 or 4. These are custom-selected so that a REG_SEQUENCE can be 234210299Sed /// generated to force the table registers to be consecutive. 235210299Sed SDNode *SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, unsigned Opc); 236210299Sed 237198090Srdivacky /// SelectV6T2BitfieldExtractOp - Select SBFX/UBFX instructions for ARM. 238207618Srdivacky SDNode *SelectV6T2BitfieldExtractOp(SDNode *N, bool isSigned); 239198090Srdivacky 240199989Srdivacky /// SelectCMOVOp - Select CMOV instructions for ARM. 241202375Srdivacky SDNode *SelectCMOVOp(SDNode *N); 242202375Srdivacky SDNode *SelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 243199989Srdivacky ARMCC::CondCodes CCVal, SDValue CCR, 244199989Srdivacky SDValue InFlag); 245202375Srdivacky SDNode *SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 246199989Srdivacky ARMCC::CondCodes CCVal, SDValue CCR, 247199989Srdivacky SDValue InFlag); 248218893Sdim SDNode *SelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 249199989Srdivacky ARMCC::CondCodes CCVal, SDValue CCR, 250199989Srdivacky SDValue InFlag); 251218893Sdim SDNode *SelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 252199989Srdivacky ARMCC::CondCodes CCVal, SDValue CCR, 253199989Srdivacky SDValue InFlag); 254199989Srdivacky 255226633Sdim // Select special operations if node forms integer ABS pattern 256226633Sdim SDNode *SelectABSOp(SDNode *N); 257226633Sdim 258208599Srdivacky SDNode *SelectConcatVector(SDNode *N); 259208599Srdivacky 260226633Sdim SDNode *SelectAtomic64(SDNode *Node, unsigned Opc); 261226633Sdim 262195340Sed /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 263195340Sed /// inline asm expressions. 264195340Sed virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, 265195340Sed char ConstraintCode, 266195340Sed std::vector<SDValue> &OutOps); 267198090Srdivacky 268210299Sed // Form pairs of consecutive S, D, or Q registers. 269210299Sed SDNode *PairSRegs(EVT VT, SDValue V0, SDValue V1); 270198090Srdivacky SDNode *PairDRegs(EVT VT, SDValue V0, SDValue V1); 271208599Srdivacky SDNode *PairQRegs(EVT VT, SDValue V0, SDValue V1); 272208599Srdivacky 273210299Sed // Form sequences of 4 consecutive S, D, or Q registers. 274210299Sed SDNode *QuadSRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); 275208599Srdivacky SDNode *QuadDRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); 276208599Srdivacky SDNode *QuadQRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); 277208599Srdivacky 278218893Sdim // Get the alignment operand for a NEON VLD or VST instruction. 279218893Sdim SDValue GetVLDSTAlign(SDValue Align, unsigned NumVecs, bool is64BitVector); 280193323Sed}; 281193323Sed} 282193323Sed 283198090Srdivacky/// isInt32Immediate - This method tests to see if the node is a 32-bit constant 284198090Srdivacky/// operand. If so Imm will receive the 32-bit value. 285198090Srdivackystatic bool isInt32Immediate(SDNode *N, unsigned &Imm) { 286198090Srdivacky if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) { 287198090Srdivacky Imm = cast<ConstantSDNode>(N)->getZExtValue(); 288198090Srdivacky return true; 289198090Srdivacky } 290198090Srdivacky return false; 291198090Srdivacky} 292198090Srdivacky 293198090Srdivacky// isInt32Immediate - This method tests to see if a constant operand. 294198090Srdivacky// If so Imm will receive the 32 bit value. 295198090Srdivackystatic bool isInt32Immediate(SDValue N, unsigned &Imm) { 296198090Srdivacky return isInt32Immediate(N.getNode(), Imm); 297198090Srdivacky} 298198090Srdivacky 299198090Srdivacky// isOpcWithIntImmediate - This method tests to see if the node is a specific 300198090Srdivacky// opcode and that it has a immediate integer right operand. 301198090Srdivacky// If so Imm will receive the 32 bit value. 302198090Srdivackystatic bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) { 303198090Srdivacky return N->getOpcode() == Opc && 304198090Srdivacky isInt32Immediate(N->getOperand(1).getNode(), Imm); 305198090Srdivacky} 306198090Srdivacky 307218893Sdim/// \brief Check whether a particular node is a constant value representable as 308243830Sdim/// (N * Scale) where (N in [\p RangeMin, \p RangeMax). 309218893Sdim/// 310218893Sdim/// \param ScaledConstant [out] - On success, the pre-scaled constant value. 311226633Sdimstatic bool isScaledConstantInRange(SDValue Node, int Scale, 312218893Sdim int RangeMin, int RangeMax, 313218893Sdim int &ScaledConstant) { 314226633Sdim assert(Scale > 0 && "Invalid scale!"); 315198090Srdivacky 316218893Sdim // Check that this is a constant. 317218893Sdim const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Node); 318218893Sdim if (!C) 319218893Sdim return false; 320218893Sdim 321218893Sdim ScaledConstant = (int) C->getZExtValue(); 322218893Sdim if ((ScaledConstant % Scale) != 0) 323218893Sdim return false; 324218893Sdim 325218893Sdim ScaledConstant /= Scale; 326218893Sdim return ScaledConstant >= RangeMin && ScaledConstant < RangeMax; 327218893Sdim} 328218893Sdim 329218893Sdim/// hasNoVMLxHazardUse - Return true if it's desirable to select a FP MLA / MLS 330218893Sdim/// node. VFP / NEON fp VMLA / VMLS instructions have special RAW hazards (at 331218893Sdim/// least on current ARM implementations) which should be avoidded. 332218893Sdimbool ARMDAGToDAGISel::hasNoVMLxHazardUse(SDNode *N) const { 333218893Sdim if (OptLevel == CodeGenOpt::None) 334218893Sdim return true; 335218893Sdim 336218893Sdim if (!CheckVMLxHazard) 337218893Sdim return true; 338218893Sdim 339243830Sdim if (!Subtarget->isCortexA8() && !Subtarget->isLikeA9() && 340243830Sdim !Subtarget->isSwift()) 341218893Sdim return true; 342218893Sdim 343218893Sdim if (!N->hasOneUse()) 344218893Sdim return false; 345218893Sdim 346218893Sdim SDNode *Use = *N->use_begin(); 347218893Sdim if (Use->getOpcode() == ISD::CopyToReg) 348218893Sdim return true; 349218893Sdim if (Use->isMachineOpcode()) { 350224145Sdim const MCInstrDesc &MCID = TII->get(Use->getMachineOpcode()); 351224145Sdim if (MCID.mayStore()) 352218893Sdim return true; 353224145Sdim unsigned Opcode = MCID.getOpcode(); 354218893Sdim if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) 355218893Sdim return true; 356218893Sdim // vmlx feeding into another vmlx. We actually want to unfold 357218893Sdim // the use later in the MLxExpansion pass. e.g. 358218893Sdim // vmla 359218893Sdim // vmla (stall 8 cycles) 360218893Sdim // 361218893Sdim // vmul (5 cycles) 362218893Sdim // vadd (5 cycles) 363218893Sdim // vmla 364218893Sdim // This adds up to about 18 - 19 cycles. 365218893Sdim // 366218893Sdim // vmla 367218893Sdim // vmul (stall 4 cycles) 368218893Sdim // vadd adds up to about 14 cycles. 369218893Sdim return TII->isFpMLxInstruction(Opcode); 370218893Sdim } 371218893Sdim 372218893Sdim return false; 373218893Sdim} 374218893Sdim 375218893Sdimbool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift, 376218893Sdim ARM_AM::ShiftOpc ShOpcVal, 377218893Sdim unsigned ShAmt) { 378243830Sdim if (!Subtarget->isLikeA9() && !Subtarget->isSwift()) 379218893Sdim return true; 380218893Sdim if (Shift.hasOneUse()) 381218893Sdim return true; 382218893Sdim // R << 2 is free. 383243830Sdim return ShOpcVal == ARM_AM::lsl && 384243830Sdim (ShAmt == 2 || (Subtarget->isSwift() && ShAmt == 1)); 385218893Sdim} 386218893Sdim 387226633Sdimbool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N, 388195340Sed SDValue &BaseReg, 389226633Sdim SDValue &Opc, 390226633Sdim bool CheckProfitability) { 391226633Sdim if (DisableShifterOp) 392226633Sdim return false; 393226633Sdim 394226633Sdim ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode()); 395226633Sdim 396226633Sdim // Don't match base register only case. That is matched to a separate 397226633Sdim // lower complexity pattern with explicit register operand. 398226633Sdim if (ShOpcVal == ARM_AM::no_shift) return false; 399226633Sdim 400226633Sdim BaseReg = N.getOperand(0); 401226633Sdim unsigned ShImmVal = 0; 402226633Sdim ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1)); 403226633Sdim if (!RHS) return false; 404226633Sdim ShImmVal = RHS->getZExtValue() & 31; 405226633Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), 406226633Sdim MVT::i32); 407226633Sdim return true; 408226633Sdim} 409226633Sdim 410226633Sdimbool ARMDAGToDAGISel::SelectRegShifterOperand(SDValue N, 411226633Sdim SDValue &BaseReg, 412195340Sed SDValue &ShReg, 413221345Sdim SDValue &Opc, 414221345Sdim bool CheckProfitability) { 415212904Sdim if (DisableShifterOp) 416212904Sdim return false; 417212904Sdim 418226633Sdim ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode()); 419195340Sed 420195340Sed // Don't match base register only case. That is matched to a separate 421195340Sed // lower complexity pattern with explicit register operand. 422195340Sed if (ShOpcVal == ARM_AM::no_shift) return false; 423198090Srdivacky 424195340Sed BaseReg = N.getOperand(0); 425195340Sed unsigned ShImmVal = 0; 426226633Sdim ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1)); 427226633Sdim if (RHS) return false; 428226633Sdim 429226633Sdim ShReg = N.getOperand(1); 430226633Sdim if (CheckProfitability && !isShifterOpProfitable(N, ShOpcVal, ShImmVal)) 431226633Sdim return false; 432195340Sed Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), 433195340Sed MVT::i32); 434195340Sed return true; 435195340Sed} 436195340Sed 437226633Sdim 438218893Sdimbool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N, 439218893Sdim SDValue &Base, 440218893Sdim SDValue &OffImm) { 441218893Sdim // Match simple R + imm12 operands. 442218893Sdim 443218893Sdim // Base only. 444218893Sdim if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && 445218893Sdim !CurDAG->isBaseWithConstantOffset(N)) { 446218893Sdim if (N.getOpcode() == ISD::FrameIndex) { 447218893Sdim // Match frame index. 448218893Sdim int FI = cast<FrameIndexSDNode>(N)->getIndex(); 449218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 450218893Sdim OffImm = CurDAG->getTargetConstant(0, MVT::i32); 451218893Sdim return true; 452218893Sdim } 453221345Sdim 454218893Sdim if (N.getOpcode() == ARMISD::Wrapper && 455218893Sdim !(Subtarget->useMovt() && 456218893Sdim N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { 457218893Sdim Base = N.getOperand(0); 458218893Sdim } else 459218893Sdim Base = N; 460218893Sdim OffImm = CurDAG->getTargetConstant(0, MVT::i32); 461218893Sdim return true; 462218893Sdim } 463218893Sdim 464218893Sdim if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 465218893Sdim int RHSC = (int)RHS->getZExtValue(); 466218893Sdim if (N.getOpcode() == ISD::SUB) 467218893Sdim RHSC = -RHSC; 468218893Sdim 469218893Sdim if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned) 470218893Sdim Base = N.getOperand(0); 471218893Sdim if (Base.getOpcode() == ISD::FrameIndex) { 472218893Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 473218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 474218893Sdim } 475218893Sdim OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); 476218893Sdim return true; 477218893Sdim } 478218893Sdim } 479218893Sdim 480218893Sdim // Base only. 481218893Sdim Base = N; 482218893Sdim OffImm = CurDAG->getTargetConstant(0, MVT::i32); 483218893Sdim return true; 484218893Sdim} 485218893Sdim 486218893Sdim 487218893Sdim 488218893Sdimbool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, 489193323Sed SDValue &Opc) { 490218893Sdim if (N.getOpcode() == ISD::MUL && 491243830Sdim ((!Subtarget->isLikeA9() && !Subtarget->isSwift()) || N.hasOneUse())) { 492193323Sed if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 493193323Sed // X * [3,5,9] -> X + X * [2,4,8] etc. 494193323Sed int RHSC = (int)RHS->getZExtValue(); 495193323Sed if (RHSC & 1) { 496193323Sed RHSC = RHSC & ~1; 497193323Sed ARM_AM::AddrOpc AddSub = ARM_AM::add; 498193323Sed if (RHSC < 0) { 499193323Sed AddSub = ARM_AM::sub; 500193323Sed RHSC = - RHSC; 501193323Sed } 502193323Sed if (isPowerOf2_32(RHSC)) { 503193323Sed unsigned ShAmt = Log2_32(RHSC); 504193323Sed Base = Offset = N.getOperand(0); 505193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, 506193323Sed ARM_AM::lsl), 507193323Sed MVT::i32); 508193323Sed return true; 509193323Sed } 510193323Sed } 511193323Sed } 512193323Sed } 513193323Sed 514218893Sdim if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && 515218893Sdim // ISD::OR that is equivalent to an ISD::ADD. 516218893Sdim !CurDAG->isBaseWithConstantOffset(N)) 517218893Sdim return false; 518218893Sdim 519218893Sdim // Leave simple R +/- imm12 operands for LDRi12 520218893Sdim if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { 521218893Sdim int RHSC; 522218893Sdim if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1, 523218893Sdim -0x1000+1, 0x1000, RHSC)) // 12 bits. 524218893Sdim return false; 525218893Sdim } 526218893Sdim 527218893Sdim // Otherwise this is R +/- [possibly shifted] R. 528218893Sdim ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::SUB ? ARM_AM::sub:ARM_AM::add; 529226633Sdim ARM_AM::ShiftOpc ShOpcVal = 530226633Sdim ARM_AM::getShiftOpcForNode(N.getOperand(1).getOpcode()); 531218893Sdim unsigned ShAmt = 0; 532218893Sdim 533218893Sdim Base = N.getOperand(0); 534218893Sdim Offset = N.getOperand(1); 535218893Sdim 536218893Sdim if (ShOpcVal != ARM_AM::no_shift) { 537218893Sdim // Check to see if the RHS of the shift is a constant, if not, we can't fold 538218893Sdim // it. 539218893Sdim if (ConstantSDNode *Sh = 540218893Sdim dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) { 541218893Sdim ShAmt = Sh->getZExtValue(); 542218893Sdim if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt)) 543218893Sdim Offset = N.getOperand(1).getOperand(0); 544218893Sdim else { 545218893Sdim ShAmt = 0; 546218893Sdim ShOpcVal = ARM_AM::no_shift; 547218893Sdim } 548218893Sdim } else { 549218893Sdim ShOpcVal = ARM_AM::no_shift; 550218893Sdim } 551218893Sdim } 552218893Sdim 553218893Sdim // Try matching (R shl C) + (R). 554218893Sdim if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift && 555243830Sdim !(Subtarget->isLikeA9() || Subtarget->isSwift() || 556243830Sdim N.getOperand(0).hasOneUse())) { 557226633Sdim ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0).getOpcode()); 558218893Sdim if (ShOpcVal != ARM_AM::no_shift) { 559218893Sdim // Check to see if the RHS of the shift is a constant, if not, we can't 560218893Sdim // fold it. 561218893Sdim if (ConstantSDNode *Sh = 562218893Sdim dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) { 563218893Sdim ShAmt = Sh->getZExtValue(); 564226633Sdim if (isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt)) { 565218893Sdim Offset = N.getOperand(0).getOperand(0); 566218893Sdim Base = N.getOperand(1); 567218893Sdim } else { 568218893Sdim ShAmt = 0; 569218893Sdim ShOpcVal = ARM_AM::no_shift; 570218893Sdim } 571218893Sdim } else { 572218893Sdim ShOpcVal = ARM_AM::no_shift; 573218893Sdim } 574218893Sdim } 575218893Sdim } 576218893Sdim 577218893Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), 578218893Sdim MVT::i32); 579218893Sdim return true; 580218893Sdim} 581218893Sdim 582218893Sdim 583218893Sdim//----- 584218893Sdim 585218893SdimAddrMode2Type ARMDAGToDAGISel::SelectAddrMode2Worker(SDValue N, 586218893Sdim SDValue &Base, 587218893Sdim SDValue &Offset, 588218893Sdim SDValue &Opc) { 589218893Sdim if (N.getOpcode() == ISD::MUL && 590243830Sdim (!(Subtarget->isLikeA9() || Subtarget->isSwift()) || N.hasOneUse())) { 591218893Sdim if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 592218893Sdim // X * [3,5,9] -> X + X * [2,4,8] etc. 593218893Sdim int RHSC = (int)RHS->getZExtValue(); 594218893Sdim if (RHSC & 1) { 595218893Sdim RHSC = RHSC & ~1; 596218893Sdim ARM_AM::AddrOpc AddSub = ARM_AM::add; 597218893Sdim if (RHSC < 0) { 598218893Sdim AddSub = ARM_AM::sub; 599218893Sdim RHSC = - RHSC; 600218893Sdim } 601218893Sdim if (isPowerOf2_32(RHSC)) { 602218893Sdim unsigned ShAmt = Log2_32(RHSC); 603218893Sdim Base = Offset = N.getOperand(0); 604218893Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, 605218893Sdim ARM_AM::lsl), 606218893Sdim MVT::i32); 607218893Sdim return AM2_SHOP; 608218893Sdim } 609218893Sdim } 610218893Sdim } 611218893Sdim } 612218893Sdim 613218893Sdim if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && 614218893Sdim // ISD::OR that is equivalent to an ADD. 615218893Sdim !CurDAG->isBaseWithConstantOffset(N)) { 616193323Sed Base = N; 617193323Sed if (N.getOpcode() == ISD::FrameIndex) { 618193323Sed int FI = cast<FrameIndexSDNode>(N)->getIndex(); 619193323Sed Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 620199989Srdivacky } else if (N.getOpcode() == ARMISD::Wrapper && 621199989Srdivacky !(Subtarget->useMovt() && 622199989Srdivacky N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { 623193323Sed Base = N.getOperand(0); 624193323Sed } 625193323Sed Offset = CurDAG->getRegister(0, MVT::i32); 626193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0, 627193323Sed ARM_AM::no_shift), 628193323Sed MVT::i32); 629218893Sdim return AM2_BASE; 630193323Sed } 631198090Srdivacky 632193323Sed // Match simple R +/- imm12 operands. 633218893Sdim if (N.getOpcode() != ISD::SUB) { 634218893Sdim int RHSC; 635218893Sdim if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1, 636218893Sdim -0x1000+1, 0x1000, RHSC)) { // 12 bits. 637218893Sdim Base = N.getOperand(0); 638218893Sdim if (Base.getOpcode() == ISD::FrameIndex) { 639218893Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 640218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 641218893Sdim } 642218893Sdim Offset = CurDAG->getRegister(0, MVT::i32); 643193323Sed 644218893Sdim ARM_AM::AddrOpc AddSub = ARM_AM::add; 645218893Sdim if (RHSC < 0) { 646218893Sdim AddSub = ARM_AM::sub; 647218893Sdim RHSC = - RHSC; 648193323Sed } 649218893Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC, 650218893Sdim ARM_AM::no_shift), 651218893Sdim MVT::i32); 652218893Sdim return AM2_BASE; 653193323Sed } 654218893Sdim } 655198090Srdivacky 656243830Sdim if ((Subtarget->isLikeA9() || Subtarget->isSwift()) && !N.hasOneUse()) { 657218893Sdim // Compute R +/- (R << N) and reuse it. 658218893Sdim Base = N; 659218893Sdim Offset = CurDAG->getRegister(0, MVT::i32); 660218893Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0, 661218893Sdim ARM_AM::no_shift), 662218893Sdim MVT::i32); 663218893Sdim return AM2_BASE; 664218893Sdim } 665218893Sdim 666198892Srdivacky // Otherwise this is R +/- [possibly shifted] R. 667218893Sdim ARM_AM::AddrOpc AddSub = N.getOpcode() != ISD::SUB ? ARM_AM::add:ARM_AM::sub; 668226633Sdim ARM_AM::ShiftOpc ShOpcVal = 669226633Sdim ARM_AM::getShiftOpcForNode(N.getOperand(1).getOpcode()); 670193323Sed unsigned ShAmt = 0; 671198090Srdivacky 672193323Sed Base = N.getOperand(0); 673193323Sed Offset = N.getOperand(1); 674198090Srdivacky 675193323Sed if (ShOpcVal != ARM_AM::no_shift) { 676193323Sed // Check to see if the RHS of the shift is a constant, if not, we can't fold 677193323Sed // it. 678193323Sed if (ConstantSDNode *Sh = 679193323Sed dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) { 680193323Sed ShAmt = Sh->getZExtValue(); 681218893Sdim if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt)) 682218893Sdim Offset = N.getOperand(1).getOperand(0); 683218893Sdim else { 684218893Sdim ShAmt = 0; 685218893Sdim ShOpcVal = ARM_AM::no_shift; 686218893Sdim } 687193323Sed } else { 688193323Sed ShOpcVal = ARM_AM::no_shift; 689193323Sed } 690193323Sed } 691198090Srdivacky 692193323Sed // Try matching (R shl C) + (R). 693218893Sdim if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift && 694243830Sdim !(Subtarget->isLikeA9() || Subtarget->isSwift() || 695243830Sdim N.getOperand(0).hasOneUse())) { 696226633Sdim ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0).getOpcode()); 697193323Sed if (ShOpcVal != ARM_AM::no_shift) { 698193323Sed // Check to see if the RHS of the shift is a constant, if not, we can't 699193323Sed // fold it. 700193323Sed if (ConstantSDNode *Sh = 701193323Sed dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) { 702193323Sed ShAmt = Sh->getZExtValue(); 703226633Sdim if (isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt)) { 704218893Sdim Offset = N.getOperand(0).getOperand(0); 705218893Sdim Base = N.getOperand(1); 706218893Sdim } else { 707218893Sdim ShAmt = 0; 708218893Sdim ShOpcVal = ARM_AM::no_shift; 709218893Sdim } 710193323Sed } else { 711193323Sed ShOpcVal = ARM_AM::no_shift; 712193323Sed } 713193323Sed } 714193323Sed } 715198090Srdivacky 716193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), 717193323Sed MVT::i32); 718218893Sdim return AM2_SHOP; 719193323Sed} 720193323Sed 721226633Sdimbool ARMDAGToDAGISel::SelectAddrMode2OffsetReg(SDNode *Op, SDValue N, 722193323Sed SDValue &Offset, SDValue &Opc) { 723202375Srdivacky unsigned Opcode = Op->getOpcode(); 724193323Sed ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) 725193323Sed ? cast<LoadSDNode>(Op)->getAddressingMode() 726193323Sed : cast<StoreSDNode>(Op)->getAddressingMode(); 727193323Sed ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) 728193323Sed ? ARM_AM::add : ARM_AM::sub; 729218893Sdim int Val; 730226633Sdim if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) 731226633Sdim return false; 732193323Sed 733193323Sed Offset = N; 734226633Sdim ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode()); 735193323Sed unsigned ShAmt = 0; 736193323Sed if (ShOpcVal != ARM_AM::no_shift) { 737193323Sed // Check to see if the RHS of the shift is a constant, if not, we can't fold 738193323Sed // it. 739193323Sed if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 740193323Sed ShAmt = Sh->getZExtValue(); 741218893Sdim if (isShifterOpProfitable(N, ShOpcVal, ShAmt)) 742218893Sdim Offset = N.getOperand(0); 743218893Sdim else { 744218893Sdim ShAmt = 0; 745218893Sdim ShOpcVal = ARM_AM::no_shift; 746218893Sdim } 747193323Sed } else { 748193323Sed ShOpcVal = ARM_AM::no_shift; 749193323Sed } 750193323Sed } 751193323Sed 752193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), 753193323Sed MVT::i32); 754193323Sed return true; 755193323Sed} 756193323Sed 757226633Sdimbool ARMDAGToDAGISel::SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N, 758226633Sdim SDValue &Offset, SDValue &Opc) { 759226633Sdim unsigned Opcode = Op->getOpcode(); 760226633Sdim ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) 761226633Sdim ? cast<LoadSDNode>(Op)->getAddressingMode() 762226633Sdim : cast<StoreSDNode>(Op)->getAddressingMode(); 763226633Sdim ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) 764226633Sdim ? ARM_AM::add : ARM_AM::sub; 765226633Sdim int Val; 766226633Sdim if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits. 767226633Sdim if (AddSub == ARM_AM::sub) Val *= -1; 768226633Sdim Offset = CurDAG->getRegister(0, MVT::i32); 769226633Sdim Opc = CurDAG->getTargetConstant(Val, MVT::i32); 770226633Sdim return true; 771226633Sdim } 772193323Sed 773226633Sdim return false; 774226633Sdim} 775226633Sdim 776226633Sdim 777226633Sdimbool ARMDAGToDAGISel::SelectAddrMode2OffsetImm(SDNode *Op, SDValue N, 778226633Sdim SDValue &Offset, SDValue &Opc) { 779226633Sdim unsigned Opcode = Op->getOpcode(); 780226633Sdim ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) 781226633Sdim ? cast<LoadSDNode>(Op)->getAddressingMode() 782226633Sdim : cast<StoreSDNode>(Op)->getAddressingMode(); 783226633Sdim ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) 784226633Sdim ? ARM_AM::add : ARM_AM::sub; 785226633Sdim int Val; 786226633Sdim if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits. 787226633Sdim Offset = CurDAG->getRegister(0, MVT::i32); 788226633Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val, 789226633Sdim ARM_AM::no_shift), 790226633Sdim MVT::i32); 791226633Sdim return true; 792226633Sdim } 793226633Sdim 794226633Sdim return false; 795226633Sdim} 796226633Sdim 797226633Sdimbool ARMDAGToDAGISel::SelectAddrOffsetNone(SDValue N, SDValue &Base) { 798226633Sdim Base = N; 799226633Sdim return true; 800226633Sdim} 801226633Sdim 802218893Sdimbool ARMDAGToDAGISel::SelectAddrMode3(SDValue N, 803193323Sed SDValue &Base, SDValue &Offset, 804193323Sed SDValue &Opc) { 805193323Sed if (N.getOpcode() == ISD::SUB) { 806193323Sed // X - C is canonicalize to X + -C, no need to handle it here. 807193323Sed Base = N.getOperand(0); 808193323Sed Offset = N.getOperand(1); 809193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0),MVT::i32); 810193323Sed return true; 811193323Sed } 812198090Srdivacky 813218893Sdim if (!CurDAG->isBaseWithConstantOffset(N)) { 814193323Sed Base = N; 815193323Sed if (N.getOpcode() == ISD::FrameIndex) { 816193323Sed int FI = cast<FrameIndexSDNode>(N)->getIndex(); 817193323Sed Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 818193323Sed } 819193323Sed Offset = CurDAG->getRegister(0, MVT::i32); 820193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0),MVT::i32); 821193323Sed return true; 822193323Sed } 823198090Srdivacky 824193323Sed // If the RHS is +/- imm8, fold into addr mode. 825218893Sdim int RHSC; 826218893Sdim if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1, 827218893Sdim -256 + 1, 256, RHSC)) { // 8 bits. 828218893Sdim Base = N.getOperand(0); 829218893Sdim if (Base.getOpcode() == ISD::FrameIndex) { 830218893Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 831218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 832218893Sdim } 833218893Sdim Offset = CurDAG->getRegister(0, MVT::i32); 834193323Sed 835218893Sdim ARM_AM::AddrOpc AddSub = ARM_AM::add; 836218893Sdim if (RHSC < 0) { 837218893Sdim AddSub = ARM_AM::sub; 838218893Sdim RHSC = -RHSC; 839193323Sed } 840218893Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC),MVT::i32); 841218893Sdim return true; 842193323Sed } 843198090Srdivacky 844193323Sed Base = N.getOperand(0); 845193323Sed Offset = N.getOperand(1); 846193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), MVT::i32); 847193323Sed return true; 848193323Sed} 849193323Sed 850202375Srdivackybool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N, 851193323Sed SDValue &Offset, SDValue &Opc) { 852202375Srdivacky unsigned Opcode = Op->getOpcode(); 853193323Sed ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) 854193323Sed ? cast<LoadSDNode>(Op)->getAddressingMode() 855193323Sed : cast<StoreSDNode>(Op)->getAddressingMode(); 856193323Sed ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) 857193323Sed ? ARM_AM::add : ARM_AM::sub; 858218893Sdim int Val; 859218893Sdim if (isScaledConstantInRange(N, /*Scale=*/1, 0, 256, Val)) { // 12 bits. 860218893Sdim Offset = CurDAG->getRegister(0, MVT::i32); 861218893Sdim Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32); 862218893Sdim return true; 863193323Sed } 864193323Sed 865193323Sed Offset = N; 866193323Sed Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), MVT::i32); 867193323Sed return true; 868193323Sed} 869193323Sed 870218893Sdimbool ARMDAGToDAGISel::SelectAddrMode5(SDValue N, 871193323Sed SDValue &Base, SDValue &Offset) { 872218893Sdim if (!CurDAG->isBaseWithConstantOffset(N)) { 873193323Sed Base = N; 874193323Sed if (N.getOpcode() == ISD::FrameIndex) { 875193323Sed int FI = cast<FrameIndexSDNode>(N)->getIndex(); 876193323Sed Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 877199989Srdivacky } else if (N.getOpcode() == ARMISD::Wrapper && 878199989Srdivacky !(Subtarget->useMovt() && 879199989Srdivacky N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { 880193323Sed Base = N.getOperand(0); 881193323Sed } 882193323Sed Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), 883193323Sed MVT::i32); 884193323Sed return true; 885193323Sed } 886198090Srdivacky 887193323Sed // If the RHS is +/- imm8, fold into addr mode. 888218893Sdim int RHSC; 889218893Sdim if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 890218893Sdim -256 + 1, 256, RHSC)) { 891218893Sdim Base = N.getOperand(0); 892218893Sdim if (Base.getOpcode() == ISD::FrameIndex) { 893218893Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 894218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 895218893Sdim } 896193323Sed 897218893Sdim ARM_AM::AddrOpc AddSub = ARM_AM::add; 898218893Sdim if (RHSC < 0) { 899218893Sdim AddSub = ARM_AM::sub; 900218893Sdim RHSC = -RHSC; 901193323Sed } 902218893Sdim Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC), 903218893Sdim MVT::i32); 904218893Sdim return true; 905193323Sed } 906198090Srdivacky 907193323Sed Base = N; 908193323Sed Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), 909193323Sed MVT::i32); 910193323Sed return true; 911193323Sed} 912193323Sed 913218893Sdimbool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr, 914218893Sdim SDValue &Align) { 915195340Sed Addr = N; 916218893Sdim 917218893Sdim unsigned Alignment = 0; 918218893Sdim if (LSBaseSDNode *LSN = dyn_cast<LSBaseSDNode>(Parent)) { 919218893Sdim // This case occurs only for VLD1-lane/dup and VST1-lane instructions. 920218893Sdim // The maximum alignment is equal to the memory size being referenced. 921218893Sdim unsigned LSNAlign = LSN->getAlignment(); 922218893Sdim unsigned MemSize = LSN->getMemoryVT().getSizeInBits() / 8; 923234353Sdim if (LSNAlign >= MemSize && MemSize > 1) 924218893Sdim Alignment = MemSize; 925218893Sdim } else { 926218893Sdim // All other uses of addrmode6 are for intrinsics. For now just record 927218893Sdim // the raw alignment value; it will be refined later based on the legal 928218893Sdim // alignment operands for the intrinsic. 929218893Sdim Alignment = cast<MemIntrinsicSDNode>(Parent)->getAlignment(); 930218893Sdim } 931218893Sdim 932218893Sdim Align = CurDAG->getTargetConstant(Alignment, MVT::i32); 933195340Sed return true; 934195340Sed} 935195340Sed 936219077Sdimbool ARMDAGToDAGISel::SelectAddrMode6Offset(SDNode *Op, SDValue N, 937219077Sdim SDValue &Offset) { 938219077Sdim LSBaseSDNode *LdSt = cast<LSBaseSDNode>(Op); 939219077Sdim ISD::MemIndexedMode AM = LdSt->getAddressingMode(); 940219077Sdim if (AM != ISD::POST_INC) 941219077Sdim return false; 942219077Sdim Offset = N; 943219077Sdim if (ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N)) { 944219077Sdim if (NC->getZExtValue() * 8 == LdSt->getMemoryVT().getSizeInBits()) 945219077Sdim Offset = CurDAG->getRegister(0, MVT::i32); 946219077Sdim } 947219077Sdim return true; 948219077Sdim} 949219077Sdim 950218893Sdimbool ARMDAGToDAGISel::SelectAddrModePC(SDValue N, 951198090Srdivacky SDValue &Offset, SDValue &Label) { 952193323Sed if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) { 953193323Sed Offset = N.getOperand(0); 954193323Sed SDValue N1 = N.getOperand(1); 955218893Sdim Label = CurDAG->getTargetConstant(cast<ConstantSDNode>(N1)->getZExtValue(), 956218893Sdim MVT::i32); 957193323Sed return true; 958193323Sed } 959218893Sdim 960193323Sed return false; 961193323Sed} 962193323Sed 963218893Sdim 964218893Sdim//===----------------------------------------------------------------------===// 965218893Sdim// Thumb Addressing Modes 966218893Sdim//===----------------------------------------------------------------------===// 967218893Sdim 968218893Sdimbool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, 969193323Sed SDValue &Base, SDValue &Offset){ 970218893Sdim if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) { 971198090Srdivacky ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N); 972210299Sed if (!NC || !NC->isNullValue()) 973198090Srdivacky return false; 974198090Srdivacky 975198090Srdivacky Base = Offset = N; 976193323Sed return true; 977193323Sed } 978193323Sed 979193323Sed Base = N.getOperand(0); 980193323Sed Offset = N.getOperand(1); 981193323Sed return true; 982193323Sed} 983193323Sed 984193323Sedbool 985218893SdimARMDAGToDAGISel::SelectThumbAddrModeRI(SDValue N, SDValue &Base, 986218893Sdim SDValue &Offset, unsigned Scale) { 987193323Sed if (Scale == 4) { 988193323Sed SDValue TmpBase, TmpOffImm; 989218893Sdim if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm)) 990193323Sed return false; // We want to select tLDRspi / tSTRspi instead. 991218893Sdim 992193323Sed if (N.getOpcode() == ARMISD::Wrapper && 993193323Sed N.getOperand(0).getOpcode() == ISD::TargetConstantPool) 994193323Sed return false; // We want to select tLDRpci instead. 995193323Sed } 996193323Sed 997218893Sdim if (!CurDAG->isBaseWithConstantOffset(N)) 998218893Sdim return false; 999218893Sdim 1000218893Sdim // Thumb does not have [sp, r] address mode. 1001218893Sdim RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0)); 1002218893Sdim RegisterSDNode *RHSR = dyn_cast<RegisterSDNode>(N.getOperand(1)); 1003218893Sdim if ((LHSR && LHSR->getReg() == ARM::SP) || 1004218893Sdim (RHSR && RHSR->getReg() == ARM::SP)) 1005218893Sdim return false; 1006218893Sdim 1007218893Sdim // FIXME: Why do we explicitly check for a match here and then return false? 1008218893Sdim // Presumably to allow something else to match, but shouldn't this be 1009218893Sdim // documented? 1010218893Sdim int RHSC; 1011218893Sdim if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) 1012218893Sdim return false; 1013218893Sdim 1014218893Sdim Base = N.getOperand(0); 1015218893Sdim Offset = N.getOperand(1); 1016218893Sdim return true; 1017218893Sdim} 1018218893Sdim 1019218893Sdimbool 1020218893SdimARMDAGToDAGISel::SelectThumbAddrModeRI5S1(SDValue N, 1021218893Sdim SDValue &Base, 1022218893Sdim SDValue &Offset) { 1023218893Sdim return SelectThumbAddrModeRI(N, Base, Offset, 1); 1024218893Sdim} 1025218893Sdim 1026218893Sdimbool 1027218893SdimARMDAGToDAGISel::SelectThumbAddrModeRI5S2(SDValue N, 1028218893Sdim SDValue &Base, 1029218893Sdim SDValue &Offset) { 1030218893Sdim return SelectThumbAddrModeRI(N, Base, Offset, 2); 1031218893Sdim} 1032218893Sdim 1033218893Sdimbool 1034218893SdimARMDAGToDAGISel::SelectThumbAddrModeRI5S4(SDValue N, 1035218893Sdim SDValue &Base, 1036218893Sdim SDValue &Offset) { 1037218893Sdim return SelectThumbAddrModeRI(N, Base, Offset, 4); 1038218893Sdim} 1039218893Sdim 1040218893Sdimbool 1041218893SdimARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, 1042218893Sdim SDValue &Base, SDValue &OffImm) { 1043218893Sdim if (Scale == 4) { 1044218893Sdim SDValue TmpBase, TmpOffImm; 1045218893Sdim if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm)) 1046218893Sdim return false; // We want to select tLDRspi / tSTRspi instead. 1047218893Sdim 1048199989Srdivacky if (N.getOpcode() == ARMISD::Wrapper && 1049218893Sdim N.getOperand(0).getOpcode() == ISD::TargetConstantPool) 1050218893Sdim return false; // We want to select tLDRpci instead. 1051218893Sdim } 1052218893Sdim 1053218893Sdim if (!CurDAG->isBaseWithConstantOffset(N)) { 1054218893Sdim if (N.getOpcode() == ARMISD::Wrapper && 1055199989Srdivacky !(Subtarget->useMovt() && 1056199989Srdivacky N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { 1057199989Srdivacky Base = N.getOperand(0); 1058218893Sdim } else { 1059199989Srdivacky Base = N; 1060218893Sdim } 1061199989Srdivacky 1062193323Sed OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1063193323Sed return true; 1064193323Sed } 1065193323Sed 1066193323Sed RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0)); 1067193323Sed RegisterSDNode *RHSR = dyn_cast<RegisterSDNode>(N.getOperand(1)); 1068193323Sed if ((LHSR && LHSR->getReg() == ARM::SP) || 1069193323Sed (RHSR && RHSR->getReg() == ARM::SP)) { 1070218893Sdim ConstantSDNode *LHS = dyn_cast<ConstantSDNode>(N.getOperand(0)); 1071218893Sdim ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1)); 1072218893Sdim unsigned LHSC = LHS ? LHS->getZExtValue() : 0; 1073218893Sdim unsigned RHSC = RHS ? RHS->getZExtValue() : 0; 1074218893Sdim 1075218893Sdim // Thumb does not have [sp, #imm5] address mode for non-zero imm5. 1076218893Sdim if (LHSC != 0 || RHSC != 0) return false; 1077218893Sdim 1078193323Sed Base = N; 1079193323Sed OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1080193323Sed return true; 1081193323Sed } 1082193323Sed 1083193323Sed // If the RHS is + imm5 * scale, fold into addr mode. 1084218893Sdim int RHSC; 1085218893Sdim if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) { 1086218893Sdim Base = N.getOperand(0); 1087218893Sdim OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); 1088218893Sdim return true; 1089193323Sed } 1090193323Sed 1091193323Sed Base = N.getOperand(0); 1092193323Sed OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1093193323Sed return true; 1094193323Sed} 1095193323Sed 1096218893Sdimbool 1097218893SdimARMDAGToDAGISel::SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base, 1098218893Sdim SDValue &OffImm) { 1099218893Sdim return SelectThumbAddrModeImm5S(N, 4, Base, OffImm); 1100193323Sed} 1101193323Sed 1102218893Sdimbool 1103218893SdimARMDAGToDAGISel::SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base, 1104218893Sdim SDValue &OffImm) { 1105218893Sdim return SelectThumbAddrModeImm5S(N, 2, Base, OffImm); 1106193323Sed} 1107193323Sed 1108218893Sdimbool 1109218893SdimARMDAGToDAGISel::SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base, 1110218893Sdim SDValue &OffImm) { 1111218893Sdim return SelectThumbAddrModeImm5S(N, 1, Base, OffImm); 1112193323Sed} 1113193323Sed 1114218893Sdimbool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N, 1115218893Sdim SDValue &Base, SDValue &OffImm) { 1116193323Sed if (N.getOpcode() == ISD::FrameIndex) { 1117193323Sed int FI = cast<FrameIndexSDNode>(N)->getIndex(); 1118193323Sed Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 1119193323Sed OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1120193323Sed return true; 1121193323Sed } 1122193323Sed 1123218893Sdim if (!CurDAG->isBaseWithConstantOffset(N)) 1124193323Sed return false; 1125193323Sed 1126193323Sed RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0)); 1127193323Sed if (N.getOperand(0).getOpcode() == ISD::FrameIndex || 1128193323Sed (LHSR && LHSR->getReg() == ARM::SP)) { 1129193323Sed // If the RHS is + imm8 * scale, fold into addr mode. 1130218893Sdim int RHSC; 1131218893Sdim if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) { 1132218893Sdim Base = N.getOperand(0); 1133218893Sdim if (Base.getOpcode() == ISD::FrameIndex) { 1134218893Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 1135218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 1136193323Sed } 1137218893Sdim OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); 1138218893Sdim return true; 1139193323Sed } 1140193323Sed } 1141198090Srdivacky 1142193323Sed return false; 1143193323Sed} 1144193323Sed 1145218893Sdim 1146218893Sdim//===----------------------------------------------------------------------===// 1147218893Sdim// Thumb 2 Addressing Modes 1148218893Sdim//===----------------------------------------------------------------------===// 1149218893Sdim 1150218893Sdim 1151218893Sdimbool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDValue N, SDValue &BaseReg, 1152195098Sed SDValue &Opc) { 1153212904Sdim if (DisableShifterOp) 1154212904Sdim return false; 1155212904Sdim 1156226633Sdim ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode()); 1157195098Sed 1158195098Sed // Don't match base register only case. That is matched to a separate 1159195098Sed // lower complexity pattern with explicit register operand. 1160195098Sed if (ShOpcVal == ARM_AM::no_shift) return false; 1161195098Sed 1162195098Sed BaseReg = N.getOperand(0); 1163195098Sed unsigned ShImmVal = 0; 1164195098Sed if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 1165195098Sed ShImmVal = RHS->getZExtValue() & 31; 1166195098Sed Opc = getI32Imm(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal)); 1167195098Sed return true; 1168195098Sed } 1169195098Sed 1170195098Sed return false; 1171195098Sed} 1172195098Sed 1173218893Sdimbool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N, 1174195340Sed SDValue &Base, SDValue &OffImm) { 1175195340Sed // Match simple R + imm12 operands. 1176195340Sed 1177198090Srdivacky // Base only. 1178218893Sdim if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && 1179218893Sdim !CurDAG->isBaseWithConstantOffset(N)) { 1180198090Srdivacky if (N.getOpcode() == ISD::FrameIndex) { 1181218893Sdim // Match frame index. 1182198090Srdivacky int FI = cast<FrameIndexSDNode>(N)->getIndex(); 1183198090Srdivacky Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 1184198090Srdivacky OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1185198090Srdivacky return true; 1186218893Sdim } 1187221345Sdim 1188218893Sdim if (N.getOpcode() == ARMISD::Wrapper && 1189199989Srdivacky !(Subtarget->useMovt() && 1190199989Srdivacky N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { 1191198090Srdivacky Base = N.getOperand(0); 1192198090Srdivacky if (Base.getOpcode() == ISD::TargetConstantPool) 1193198090Srdivacky return false; // We want to select t2LDRpci instead. 1194198090Srdivacky } else 1195198090Srdivacky Base = N; 1196198090Srdivacky OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1197198090Srdivacky return true; 1198198090Srdivacky } 1199198090Srdivacky 1200195340Sed if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 1201218893Sdim if (SelectT2AddrModeImm8(N, Base, OffImm)) 1202198090Srdivacky // Let t2LDRi8 handle (R - imm8). 1203198090Srdivacky return false; 1204198090Srdivacky 1205195340Sed int RHSC = (int)RHS->getZExtValue(); 1206198090Srdivacky if (N.getOpcode() == ISD::SUB) 1207198090Srdivacky RHSC = -RHSC; 1208198090Srdivacky 1209198090Srdivacky if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned) 1210195340Sed Base = N.getOperand(0); 1211198090Srdivacky if (Base.getOpcode() == ISD::FrameIndex) { 1212198090Srdivacky int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 1213198090Srdivacky Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 1214198090Srdivacky } 1215195340Sed OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); 1216195340Sed return true; 1217195340Sed } 1218195340Sed } 1219195340Sed 1220198090Srdivacky // Base only. 1221198090Srdivacky Base = N; 1222198090Srdivacky OffImm = CurDAG->getTargetConstant(0, MVT::i32); 1223198090Srdivacky return true; 1224195340Sed} 1225195340Sed 1226218893Sdimbool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N, 1227195340Sed SDValue &Base, SDValue &OffImm) { 1228198090Srdivacky // Match simple R - imm8 operands. 1229218893Sdim if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && 1230218893Sdim !CurDAG->isBaseWithConstantOffset(N)) 1231218893Sdim return false; 1232221345Sdim 1233218893Sdim if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 1234218893Sdim int RHSC = (int)RHS->getSExtValue(); 1235218893Sdim if (N.getOpcode() == ISD::SUB) 1236218893Sdim RHSC = -RHSC; 1237198090Srdivacky 1238218893Sdim if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative) 1239218893Sdim Base = N.getOperand(0); 1240218893Sdim if (Base.getOpcode() == ISD::FrameIndex) { 1241218893Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 1242218893Sdim Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 1243195340Sed } 1244218893Sdim OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); 1245218893Sdim return true; 1246195340Sed } 1247195340Sed } 1248195340Sed 1249195340Sed return false; 1250195340Sed} 1251195340Sed 1252202375Srdivackybool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, 1253195340Sed SDValue &OffImm){ 1254202375Srdivacky unsigned Opcode = Op->getOpcode(); 1255195340Sed ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) 1256195340Sed ? cast<LoadSDNode>(Op)->getAddressingMode() 1257195340Sed : cast<StoreSDNode>(Op)->getAddressingMode(); 1258218893Sdim int RHSC; 1259218893Sdim if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x100, RHSC)) { // 8 bits. 1260218893Sdim OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC)) 1261218893Sdim ? CurDAG->getTargetConstant(RHSC, MVT::i32) 1262218893Sdim : CurDAG->getTargetConstant(-RHSC, MVT::i32); 1263218893Sdim return true; 1264195340Sed } 1265195340Sed 1266195340Sed return false; 1267195340Sed} 1268195340Sed 1269218893Sdimbool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N, 1270195340Sed SDValue &Base, 1271195340Sed SDValue &OffReg, SDValue &ShImm) { 1272198090Srdivacky // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12. 1273218893Sdim if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) 1274198090Srdivacky return false; 1275198090Srdivacky 1276198090Srdivacky // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8. 1277198090Srdivacky if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 1278198090Srdivacky int RHSC = (int)RHS->getZExtValue(); 1279198090Srdivacky if (RHSC >= 0 && RHSC < 0x1000) // 12 bits (unsigned) 1280198090Srdivacky return false; 1281198090Srdivacky else if (RHSC < 0 && RHSC >= -255) // 8 bits 1282198090Srdivacky return false; 1283195340Sed } 1284195340Sed 1285195340Sed // Look for (R + R) or (R + (R << [1,2,3])). 1286195340Sed unsigned ShAmt = 0; 1287195340Sed Base = N.getOperand(0); 1288195340Sed OffReg = N.getOperand(1); 1289195340Sed 1290195340Sed // Swap if it is ((R << c) + R). 1291226633Sdim ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg.getOpcode()); 1292195340Sed if (ShOpcVal != ARM_AM::lsl) { 1293226633Sdim ShOpcVal = ARM_AM::getShiftOpcForNode(Base.getOpcode()); 1294195340Sed if (ShOpcVal == ARM_AM::lsl) 1295195340Sed std::swap(Base, OffReg); 1296198090Srdivacky } 1297198090Srdivacky 1298195340Sed if (ShOpcVal == ARM_AM::lsl) { 1299195340Sed // Check to see if the RHS of the shift is a constant, if not, we can't fold 1300195340Sed // it. 1301195340Sed if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) { 1302195340Sed ShAmt = Sh->getZExtValue(); 1303218893Sdim if (ShAmt < 4 && isShifterOpProfitable(OffReg, ShOpcVal, ShAmt)) 1304218893Sdim OffReg = OffReg.getOperand(0); 1305218893Sdim else { 1306195340Sed ShAmt = 0; 1307195340Sed ShOpcVal = ARM_AM::no_shift; 1308218893Sdim } 1309195340Sed } else { 1310195340Sed ShOpcVal = ARM_AM::no_shift; 1311195340Sed } 1312198090Srdivacky } 1313198090Srdivacky 1314195340Sed ShImm = CurDAG->getTargetConstant(ShAmt, MVT::i32); 1315195340Sed 1316195340Sed return true; 1317195340Sed} 1318195340Sed 1319195340Sed//===--------------------------------------------------------------------===// 1320195340Sed 1321193323Sed/// getAL - Returns a ARMCC::AL immediate node. 1322193323Sedstatic inline SDValue getAL(SelectionDAG *CurDAG) { 1323193323Sed return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, MVT::i32); 1324193323Sed} 1325193323Sed 1326202375SrdivackySDNode *ARMDAGToDAGISel::SelectARMIndexedLoad(SDNode *N) { 1327202375Srdivacky LoadSDNode *LD = cast<LoadSDNode>(N); 1328195340Sed ISD::MemIndexedMode AM = LD->getAddressingMode(); 1329195340Sed if (AM == ISD::UNINDEXED) 1330195340Sed return NULL; 1331193323Sed 1332198090Srdivacky EVT LoadedVT = LD->getMemoryVT(); 1333195340Sed SDValue Offset, AMOpc; 1334195340Sed bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC); 1335195340Sed unsigned Opcode = 0; 1336195340Sed bool Match = false; 1337226633Sdim if (LoadedVT == MVT::i32 && isPre && 1338226633Sdim SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) { 1339226633Sdim Opcode = ARM::LDR_PRE_IMM; 1340195340Sed Match = true; 1341226633Sdim } else if (LoadedVT == MVT::i32 && !isPre && 1342226633Sdim SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) { 1343226633Sdim Opcode = ARM::LDR_POST_IMM; 1344226633Sdim Match = true; 1345226633Sdim } else if (LoadedVT == MVT::i32 && 1346226633Sdim SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) { 1347226633Sdim Opcode = isPre ? ARM::LDR_PRE_REG : ARM::LDR_POST_REG; 1348226633Sdim Match = true; 1349226633Sdim 1350195340Sed } else if (LoadedVT == MVT::i16 && 1351202375Srdivacky SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) { 1352195340Sed Match = true; 1353195340Sed Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) 1354195340Sed ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST) 1355195340Sed : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST); 1356195340Sed } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) { 1357195340Sed if (LD->getExtensionType() == ISD::SEXTLOAD) { 1358202375Srdivacky if (SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) { 1359195340Sed Match = true; 1360195340Sed Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST; 1361195340Sed } 1362195340Sed } else { 1363226633Sdim if (isPre && 1364226633Sdim SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) { 1365195340Sed Match = true; 1366226633Sdim Opcode = ARM::LDRB_PRE_IMM; 1367226633Sdim } else if (!isPre && 1368226633Sdim SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) { 1369226633Sdim Match = true; 1370226633Sdim Opcode = ARM::LDRB_POST_IMM; 1371226633Sdim } else if (SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) { 1372226633Sdim Match = true; 1373226633Sdim Opcode = isPre ? ARM::LDRB_PRE_REG : ARM::LDRB_POST_REG; 1374195340Sed } 1375195340Sed } 1376195340Sed } 1377195340Sed 1378195340Sed if (Match) { 1379226633Sdim if (Opcode == ARM::LDR_PRE_IMM || Opcode == ARM::LDRB_PRE_IMM) { 1380226633Sdim SDValue Chain = LD->getChain(); 1381226633Sdim SDValue Base = LD->getBasePtr(); 1382226633Sdim SDValue Ops[]= { Base, AMOpc, getAL(CurDAG), 1383226633Sdim CurDAG->getRegister(0, MVT::i32), Chain }; 1384226633Sdim return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, 1385226633Sdim MVT::i32, MVT::Other, Ops, 5); 1386226633Sdim } else { 1387226633Sdim SDValue Chain = LD->getChain(); 1388226633Sdim SDValue Base = LD->getBasePtr(); 1389226633Sdim SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG), 1390226633Sdim CurDAG->getRegister(0, MVT::i32), Chain }; 1391226633Sdim return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, 1392226633Sdim MVT::i32, MVT::Other, Ops, 6); 1393226633Sdim } 1394195340Sed } 1395195340Sed 1396195340Sed return NULL; 1397195340Sed} 1398195340Sed 1399202375SrdivackySDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDNode *N) { 1400202375Srdivacky LoadSDNode *LD = cast<LoadSDNode>(N); 1401195340Sed ISD::MemIndexedMode AM = LD->getAddressingMode(); 1402195340Sed if (AM == ISD::UNINDEXED) 1403195340Sed return NULL; 1404195340Sed 1405198090Srdivacky EVT LoadedVT = LD->getMemoryVT(); 1406195340Sed bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD; 1407195340Sed SDValue Offset; 1408195340Sed bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC); 1409195340Sed unsigned Opcode = 0; 1410195340Sed bool Match = false; 1411202375Srdivacky if (SelectT2AddrModeImm8Offset(N, LD->getOffset(), Offset)) { 1412198090Srdivacky switch (LoadedVT.getSimpleVT().SimpleTy) { 1413195340Sed case MVT::i32: 1414195340Sed Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST; 1415195340Sed break; 1416195340Sed case MVT::i16: 1417195340Sed if (isSExtLd) 1418195340Sed Opcode = isPre ? ARM::t2LDRSH_PRE : ARM::t2LDRSH_POST; 1419195340Sed else 1420195340Sed Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST; 1421195340Sed break; 1422195340Sed case MVT::i8: 1423195340Sed case MVT::i1: 1424195340Sed if (isSExtLd) 1425195340Sed Opcode = isPre ? ARM::t2LDRSB_PRE : ARM::t2LDRSB_POST; 1426195340Sed else 1427195340Sed Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST; 1428195340Sed break; 1429195340Sed default: 1430195340Sed return NULL; 1431195340Sed } 1432195340Sed Match = true; 1433195340Sed } 1434195340Sed 1435195340Sed if (Match) { 1436195340Sed SDValue Chain = LD->getChain(); 1437195340Sed SDValue Base = LD->getBasePtr(); 1438195340Sed SDValue Ops[]= { Base, Offset, getAL(CurDAG), 1439195340Sed CurDAG->getRegister(0, MVT::i32), Chain }; 1440202375Srdivacky return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, MVT::i32, 1441198090Srdivacky MVT::Other, Ops, 5); 1442195340Sed } 1443195340Sed 1444195340Sed return NULL; 1445195340Sed} 1446195340Sed 1447210299Sed/// PairSRegs - Form a D register from a pair of S registers. 1448210299Sed/// 1449210299SedSDNode *ARMDAGToDAGISel::PairSRegs(EVT VT, SDValue V0, SDValue V1) { 1450210299Sed DebugLoc dl = V0.getNode()->getDebugLoc(); 1451224145Sdim SDValue RegClass = 1452224145Sdim CurDAG->getTargetConstant(ARM::DPR_VFP2RegClassID, MVT::i32); 1453210299Sed SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, MVT::i32); 1454210299Sed SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, MVT::i32); 1455224145Sdim const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 }; 1456224145Sdim return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 5); 1457210299Sed} 1458210299Sed 1459208599Srdivacky/// PairDRegs - Form a quad register from a pair of D registers. 1460208599Srdivacky/// 1461198090SrdivackySDNode *ARMDAGToDAGISel::PairDRegs(EVT VT, SDValue V0, SDValue V1) { 1462198090Srdivacky DebugLoc dl = V0.getNode()->getDebugLoc(); 1463224145Sdim SDValue RegClass = CurDAG->getTargetConstant(ARM::QPRRegClassID, MVT::i32); 1464208599Srdivacky SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); 1465208599Srdivacky SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); 1466224145Sdim const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 }; 1467224145Sdim return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 5); 1468198090Srdivacky} 1469198090Srdivacky 1470208599Srdivacky/// PairQRegs - Form 4 consecutive D registers from a pair of Q registers. 1471208599Srdivacky/// 1472208599SrdivackySDNode *ARMDAGToDAGISel::PairQRegs(EVT VT, SDValue V0, SDValue V1) { 1473208599Srdivacky DebugLoc dl = V0.getNode()->getDebugLoc(); 1474224145Sdim SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, MVT::i32); 1475208599Srdivacky SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, MVT::i32); 1476208599Srdivacky SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, MVT::i32); 1477224145Sdim const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 }; 1478224145Sdim return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 5); 1479208599Srdivacky} 1480208599Srdivacky 1481210299Sed/// QuadSRegs - Form 4 consecutive S registers. 1482210299Sed/// 1483210299SedSDNode *ARMDAGToDAGISel::QuadSRegs(EVT VT, SDValue V0, SDValue V1, 1484210299Sed SDValue V2, SDValue V3) { 1485210299Sed DebugLoc dl = V0.getNode()->getDebugLoc(); 1486224145Sdim SDValue RegClass = 1487224145Sdim CurDAG->getTargetConstant(ARM::QPR_VFP2RegClassID, MVT::i32); 1488210299Sed SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, MVT::i32); 1489210299Sed SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, MVT::i32); 1490210299Sed SDValue SubReg2 = CurDAG->getTargetConstant(ARM::ssub_2, MVT::i32); 1491210299Sed SDValue SubReg3 = CurDAG->getTargetConstant(ARM::ssub_3, MVT::i32); 1492224145Sdim const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1, 1493224145Sdim V2, SubReg2, V3, SubReg3 }; 1494224145Sdim return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 9); 1495210299Sed} 1496210299Sed 1497208599Srdivacky/// QuadDRegs - Form 4 consecutive D registers. 1498208599Srdivacky/// 1499208599SrdivackySDNode *ARMDAGToDAGISel::QuadDRegs(EVT VT, SDValue V0, SDValue V1, 1500208599Srdivacky SDValue V2, SDValue V3) { 1501208599Srdivacky DebugLoc dl = V0.getNode()->getDebugLoc(); 1502224145Sdim SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, MVT::i32); 1503208599Srdivacky SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); 1504208599Srdivacky SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); 1505208599Srdivacky SDValue SubReg2 = CurDAG->getTargetConstant(ARM::dsub_2, MVT::i32); 1506208599Srdivacky SDValue SubReg3 = CurDAG->getTargetConstant(ARM::dsub_3, MVT::i32); 1507224145Sdim const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1, 1508224145Sdim V2, SubReg2, V3, SubReg3 }; 1509224145Sdim return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 9); 1510208599Srdivacky} 1511208599Srdivacky 1512208599Srdivacky/// QuadQRegs - Form 4 consecutive Q registers. 1513208599Srdivacky/// 1514208599SrdivackySDNode *ARMDAGToDAGISel::QuadQRegs(EVT VT, SDValue V0, SDValue V1, 1515208599Srdivacky SDValue V2, SDValue V3) { 1516208599Srdivacky DebugLoc dl = V0.getNode()->getDebugLoc(); 1517224145Sdim SDValue RegClass = CurDAG->getTargetConstant(ARM::QQQQPRRegClassID, MVT::i32); 1518208599Srdivacky SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, MVT::i32); 1519208599Srdivacky SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, MVT::i32); 1520208599Srdivacky SDValue SubReg2 = CurDAG->getTargetConstant(ARM::qsub_2, MVT::i32); 1521208599Srdivacky SDValue SubReg3 = CurDAG->getTargetConstant(ARM::qsub_3, MVT::i32); 1522224145Sdim const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1, 1523224145Sdim V2, SubReg2, V3, SubReg3 }; 1524224145Sdim return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 9); 1525208599Srdivacky} 1526208599Srdivacky 1527218893Sdim/// GetVLDSTAlign - Get the alignment (in bytes) for the alignment operand 1528218893Sdim/// of a NEON VLD or VST instruction. The supported values depend on the 1529218893Sdim/// number of registers being loaded. 1530218893SdimSDValue ARMDAGToDAGISel::GetVLDSTAlign(SDValue Align, unsigned NumVecs, 1531218893Sdim bool is64BitVector) { 1532218893Sdim unsigned NumRegs = NumVecs; 1533218893Sdim if (!is64BitVector && NumVecs < 3) 1534218893Sdim NumRegs *= 2; 1535208599Srdivacky 1536218893Sdim unsigned Alignment = cast<ConstantSDNode>(Align)->getZExtValue(); 1537218893Sdim if (Alignment >= 32 && NumRegs == 4) 1538218893Sdim Alignment = 32; 1539218893Sdim else if (Alignment >= 16 && (NumRegs == 2 || NumRegs == 4)) 1540218893Sdim Alignment = 16; 1541218893Sdim else if (Alignment >= 8) 1542218893Sdim Alignment = 8; 1543218893Sdim else 1544218893Sdim Alignment = 0; 1545218893Sdim 1546218893Sdim return CurDAG->getTargetConstant(Alignment, MVT::i32); 1547198090Srdivacky} 1548198090Srdivacky 1549234353Sdim// Get the register stride update opcode of a VLD/VST instruction that 1550234353Sdim// is otherwise equivalent to the given fixed stride updating instruction. 1551234353Sdimstatic unsigned getVLDSTRegisterUpdateOpcode(unsigned Opc) { 1552234353Sdim switch (Opc) { 1553234353Sdim default: break; 1554234353Sdim case ARM::VLD1d8wb_fixed: return ARM::VLD1d8wb_register; 1555234353Sdim case ARM::VLD1d16wb_fixed: return ARM::VLD1d16wb_register; 1556234353Sdim case ARM::VLD1d32wb_fixed: return ARM::VLD1d32wb_register; 1557234353Sdim case ARM::VLD1d64wb_fixed: return ARM::VLD1d64wb_register; 1558234353Sdim case ARM::VLD1q8wb_fixed: return ARM::VLD1q8wb_register; 1559234353Sdim case ARM::VLD1q16wb_fixed: return ARM::VLD1q16wb_register; 1560234353Sdim case ARM::VLD1q32wb_fixed: return ARM::VLD1q32wb_register; 1561234353Sdim case ARM::VLD1q64wb_fixed: return ARM::VLD1q64wb_register; 1562234353Sdim 1563234353Sdim case ARM::VST1d8wb_fixed: return ARM::VST1d8wb_register; 1564234353Sdim case ARM::VST1d16wb_fixed: return ARM::VST1d16wb_register; 1565234353Sdim case ARM::VST1d32wb_fixed: return ARM::VST1d32wb_register; 1566234353Sdim case ARM::VST1d64wb_fixed: return ARM::VST1d64wb_register; 1567234353Sdim case ARM::VST1q8wb_fixed: return ARM::VST1q8wb_register; 1568234353Sdim case ARM::VST1q16wb_fixed: return ARM::VST1q16wb_register; 1569234353Sdim case ARM::VST1q32wb_fixed: return ARM::VST1q32wb_register; 1570234353Sdim case ARM::VST1q64wb_fixed: return ARM::VST1q64wb_register; 1571234353Sdim case ARM::VST1d64TPseudoWB_fixed: return ARM::VST1d64TPseudoWB_register; 1572234353Sdim case ARM::VST1d64QPseudoWB_fixed: return ARM::VST1d64QPseudoWB_register; 1573234353Sdim 1574234353Sdim case ARM::VLD2d8wb_fixed: return ARM::VLD2d8wb_register; 1575234353Sdim case ARM::VLD2d16wb_fixed: return ARM::VLD2d16wb_register; 1576234353Sdim case ARM::VLD2d32wb_fixed: return ARM::VLD2d32wb_register; 1577234353Sdim case ARM::VLD2q8PseudoWB_fixed: return ARM::VLD2q8PseudoWB_register; 1578234353Sdim case ARM::VLD2q16PseudoWB_fixed: return ARM::VLD2q16PseudoWB_register; 1579234353Sdim case ARM::VLD2q32PseudoWB_fixed: return ARM::VLD2q32PseudoWB_register; 1580234353Sdim 1581234353Sdim case ARM::VST2d8wb_fixed: return ARM::VST2d8wb_register; 1582234353Sdim case ARM::VST2d16wb_fixed: return ARM::VST2d16wb_register; 1583234353Sdim case ARM::VST2d32wb_fixed: return ARM::VST2d32wb_register; 1584234353Sdim case ARM::VST2q8PseudoWB_fixed: return ARM::VST2q8PseudoWB_register; 1585234353Sdim case ARM::VST2q16PseudoWB_fixed: return ARM::VST2q16PseudoWB_register; 1586234353Sdim case ARM::VST2q32PseudoWB_fixed: return ARM::VST2q32PseudoWB_register; 1587234353Sdim 1588234353Sdim case ARM::VLD2DUPd8wb_fixed: return ARM::VLD2DUPd8wb_register; 1589234353Sdim case ARM::VLD2DUPd16wb_fixed: return ARM::VLD2DUPd16wb_register; 1590234353Sdim case ARM::VLD2DUPd32wb_fixed: return ARM::VLD2DUPd32wb_register; 1591234353Sdim } 1592234353Sdim return Opc; // If not one we handle, return it unchanged. 1593234353Sdim} 1594234353Sdim 1595218893SdimSDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs, 1596239462Sdim const uint16_t *DOpcodes, 1597239462Sdim const uint16_t *QOpcodes0, 1598239462Sdim const uint16_t *QOpcodes1) { 1599206083Srdivacky assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range"); 1600198090Srdivacky DebugLoc dl = N->getDebugLoc(); 1601198090Srdivacky 1602205407Srdivacky SDValue MemAddr, Align; 1603218893Sdim unsigned AddrOpIdx = isUpdating ? 1 : 2; 1604218893Sdim if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align)) 1605198090Srdivacky return NULL; 1606198090Srdivacky 1607198090Srdivacky SDValue Chain = N->getOperand(0); 1608198090Srdivacky EVT VT = N->getValueType(0); 1609198090Srdivacky bool is64BitVector = VT.is64BitVector(); 1610218893Sdim Align = GetVLDSTAlign(Align, NumVecs, is64BitVector); 1611198090Srdivacky 1612198090Srdivacky unsigned OpcodeIndex; 1613198090Srdivacky switch (VT.getSimpleVT().SimpleTy) { 1614198090Srdivacky default: llvm_unreachable("unhandled vld type"); 1615198090Srdivacky // Double-register operations: 1616198090Srdivacky case MVT::v8i8: OpcodeIndex = 0; break; 1617198090Srdivacky case MVT::v4i16: OpcodeIndex = 1; break; 1618198090Srdivacky case MVT::v2f32: 1619198090Srdivacky case MVT::v2i32: OpcodeIndex = 2; break; 1620198090Srdivacky case MVT::v1i64: OpcodeIndex = 3; break; 1621198090Srdivacky // Quad-register operations: 1622198090Srdivacky case MVT::v16i8: OpcodeIndex = 0; break; 1623198090Srdivacky case MVT::v8i16: OpcodeIndex = 1; break; 1624198090Srdivacky case MVT::v4f32: 1625198090Srdivacky case MVT::v4i32: OpcodeIndex = 2; break; 1626206083Srdivacky case MVT::v2i64: OpcodeIndex = 3; 1627206083Srdivacky assert(NumVecs == 1 && "v2i64 type only supported for VLD1"); 1628206083Srdivacky break; 1629198090Srdivacky } 1630198090Srdivacky 1631212904Sdim EVT ResTy; 1632212904Sdim if (NumVecs == 1) 1633212904Sdim ResTy = VT; 1634212904Sdim else { 1635212904Sdim unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; 1636212904Sdim if (!is64BitVector) 1637212904Sdim ResTyElts *= 2; 1638212904Sdim ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts); 1639212904Sdim } 1640218893Sdim std::vector<EVT> ResTys; 1641218893Sdim ResTys.push_back(ResTy); 1642218893Sdim if (isUpdating) 1643218893Sdim ResTys.push_back(MVT::i32); 1644218893Sdim ResTys.push_back(MVT::Other); 1645212904Sdim 1646207618Srdivacky SDValue Pred = getAL(CurDAG); 1647205407Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 1648218893Sdim SDNode *VLd; 1649218893Sdim SmallVector<SDValue, 7> Ops; 1650208599Srdivacky 1651218893Sdim // Double registers and VLD1/VLD2 quad registers are directly supported. 1652218893Sdim if (is64BitVector || NumVecs <= 2) { 1653218893Sdim unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : 1654218893Sdim QOpcodes0[OpcodeIndex]); 1655218893Sdim Ops.push_back(MemAddr); 1656218893Sdim Ops.push_back(Align); 1657218893Sdim if (isUpdating) { 1658218893Sdim SDValue Inc = N->getOperand(AddrOpIdx + 1); 1659234353Sdim // FIXME: VLD1/VLD2 fixed increment doesn't need Reg0. Remove the reg0 1660234353Sdim // case entirely when the rest are updated to that form, too. 1661234353Sdim if ((NumVecs == 1 || NumVecs == 2) && !isa<ConstantSDNode>(Inc.getNode())) 1662234353Sdim Opc = getVLDSTRegisterUpdateOpcode(Opc); 1663234353Sdim // We use a VLD1 for v1i64 even if the pseudo says vld2/3/4, so 1664234353Sdim // check for that explicitly too. Horribly hacky, but temporary. 1665234353Sdim if ((NumVecs != 1 && NumVecs != 2 && Opc != ARM::VLD1q64wb_fixed) || 1666234353Sdim !isa<ConstantSDNode>(Inc.getNode())) 1667234353Sdim Ops.push_back(isa<ConstantSDNode>(Inc.getNode()) ? Reg0 : Inc); 1668208599Srdivacky } 1669218893Sdim Ops.push_back(Pred); 1670218893Sdim Ops.push_back(Reg0); 1671218893Sdim Ops.push_back(Chain); 1672218893Sdim VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), Ops.size()); 1673198090Srdivacky 1674198090Srdivacky } else { 1675198090Srdivacky // Otherwise, quad registers are loaded with two separate instructions, 1676198090Srdivacky // where one loads the even registers and the other loads the odd registers. 1677212904Sdim EVT AddrTy = MemAddr.getValueType(); 1678198090Srdivacky 1679218893Sdim // Load the even subregs. This is always an updating load, so that it 1680218893Sdim // provides the address to the second load for the odd subregs. 1681212904Sdim SDValue ImplDef = 1682212904Sdim SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0); 1683212904Sdim const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain }; 1684218893Sdim SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl, 1685218893Sdim ResTy, AddrTy, MVT::Other, OpsA, 7); 1686212904Sdim Chain = SDValue(VLdA, 2); 1687198090Srdivacky 1688198113Srdivacky // Load the odd subregs. 1689218893Sdim Ops.push_back(SDValue(VLdA, 1)); 1690218893Sdim Ops.push_back(Align); 1691218893Sdim if (isUpdating) { 1692218893Sdim SDValue Inc = N->getOperand(AddrOpIdx + 1); 1693218893Sdim assert(isa<ConstantSDNode>(Inc.getNode()) && 1694218893Sdim "only constant post-increment update allowed for VLD3/4"); 1695218893Sdim (void)Inc; 1696218893Sdim Ops.push_back(Reg0); 1697218893Sdim } 1698218893Sdim Ops.push_back(SDValue(VLdA, 0)); 1699218893Sdim Ops.push_back(Pred); 1700218893Sdim Ops.push_back(Reg0); 1701218893Sdim Ops.push_back(Chain); 1702218893Sdim VLd = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, 1703218893Sdim Ops.data(), Ops.size()); 1704212904Sdim } 1705198090Srdivacky 1706221345Sdim // Transfer memoperands. 1707221345Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 1708221345Sdim MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 1709221345Sdim cast<MachineSDNode>(VLd)->setMemRefs(MemOp, MemOp + 1); 1710221345Sdim 1711218893Sdim if (NumVecs == 1) 1712218893Sdim return VLd; 1713218893Sdim 1714218893Sdim // Extract out the subregisters. 1715218893Sdim SDValue SuperReg = SDValue(VLd, 0); 1716218893Sdim assert(ARM::dsub_7 == ARM::dsub_0+7 && 1717218893Sdim ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); 1718218893Sdim unsigned Sub0 = (is64BitVector ? ARM::dsub_0 : ARM::qsub_0); 1719218893Sdim for (unsigned Vec = 0; Vec < NumVecs; ++Vec) 1720218893Sdim ReplaceUses(SDValue(N, Vec), 1721218893Sdim CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg)); 1722218893Sdim ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1)); 1723218893Sdim if (isUpdating) 1724218893Sdim ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLd, 2)); 1725198090Srdivacky return NULL; 1726198090Srdivacky} 1727198090Srdivacky 1728218893SdimSDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs, 1729239462Sdim const uint16_t *DOpcodes, 1730239462Sdim const uint16_t *QOpcodes0, 1731239462Sdim const uint16_t *QOpcodes1) { 1732210299Sed assert(NumVecs >= 1 && NumVecs <= 4 && "VST NumVecs out-of-range"); 1733198113Srdivacky DebugLoc dl = N->getDebugLoc(); 1734198113Srdivacky 1735205407Srdivacky SDValue MemAddr, Align; 1736218893Sdim unsigned AddrOpIdx = isUpdating ? 1 : 2; 1737218893Sdim unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1) 1738218893Sdim if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align)) 1739198113Srdivacky return NULL; 1740198113Srdivacky 1741221345Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 1742221345Sdim MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 1743221345Sdim 1744198113Srdivacky SDValue Chain = N->getOperand(0); 1745218893Sdim EVT VT = N->getOperand(Vec0Idx).getValueType(); 1746198113Srdivacky bool is64BitVector = VT.is64BitVector(); 1747218893Sdim Align = GetVLDSTAlign(Align, NumVecs, is64BitVector); 1748198113Srdivacky 1749198113Srdivacky unsigned OpcodeIndex; 1750198113Srdivacky switch (VT.getSimpleVT().SimpleTy) { 1751198113Srdivacky default: llvm_unreachable("unhandled vst type"); 1752198113Srdivacky // Double-register operations: 1753198113Srdivacky case MVT::v8i8: OpcodeIndex = 0; break; 1754198113Srdivacky case MVT::v4i16: OpcodeIndex = 1; break; 1755198113Srdivacky case MVT::v2f32: 1756198113Srdivacky case MVT::v2i32: OpcodeIndex = 2; break; 1757198113Srdivacky case MVT::v1i64: OpcodeIndex = 3; break; 1758198113Srdivacky // Quad-register operations: 1759198113Srdivacky case MVT::v16i8: OpcodeIndex = 0; break; 1760198113Srdivacky case MVT::v8i16: OpcodeIndex = 1; break; 1761198113Srdivacky case MVT::v4f32: 1762198113Srdivacky case MVT::v4i32: OpcodeIndex = 2; break; 1763206083Srdivacky case MVT::v2i64: OpcodeIndex = 3; 1764206083Srdivacky assert(NumVecs == 1 && "v2i64 type only supported for VST1"); 1765206083Srdivacky break; 1766198113Srdivacky } 1767198113Srdivacky 1768218893Sdim std::vector<EVT> ResTys; 1769218893Sdim if (isUpdating) 1770218893Sdim ResTys.push_back(MVT::i32); 1771218893Sdim ResTys.push_back(MVT::Other); 1772218893Sdim 1773207618Srdivacky SDValue Pred = getAL(CurDAG); 1774205407Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 1775212904Sdim SmallVector<SDValue, 7> Ops; 1776198113Srdivacky 1777218893Sdim // Double registers and VST1/VST2 quad registers are directly supported. 1778218893Sdim if (is64BitVector || NumVecs <= 2) { 1779218893Sdim SDValue SrcReg; 1780212904Sdim if (NumVecs == 1) { 1781218893Sdim SrcReg = N->getOperand(Vec0Idx); 1782218893Sdim } else if (is64BitVector) { 1783208599Srdivacky // Form a REG_SEQUENCE to force register allocation. 1784218893Sdim SDValue V0 = N->getOperand(Vec0Idx + 0); 1785218893Sdim SDValue V1 = N->getOperand(Vec0Idx + 1); 1786208599Srdivacky if (NumVecs == 2) 1787218893Sdim SrcReg = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); 1788208599Srdivacky else { 1789218893Sdim SDValue V2 = N->getOperand(Vec0Idx + 2); 1790218893Sdim // If it's a vst3, form a quad D-register and leave the last part as 1791208599Srdivacky // an undef. 1792208599Srdivacky SDValue V3 = (NumVecs == 3) 1793208599Srdivacky ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) 1794218893Sdim : N->getOperand(Vec0Idx + 3); 1795218893Sdim SrcReg = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); 1796208599Srdivacky } 1797212904Sdim } else { 1798212904Sdim // Form a QQ register. 1799218893Sdim SDValue Q0 = N->getOperand(Vec0Idx); 1800218893Sdim SDValue Q1 = N->getOperand(Vec0Idx + 1); 1801218893Sdim SrcReg = SDValue(PairQRegs(MVT::v4i64, Q0, Q1), 0); 1802198113Srdivacky } 1803218893Sdim 1804218893Sdim unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : 1805218893Sdim QOpcodes0[OpcodeIndex]); 1806218893Sdim Ops.push_back(MemAddr); 1807218893Sdim Ops.push_back(Align); 1808218893Sdim if (isUpdating) { 1809218893Sdim SDValue Inc = N->getOperand(AddrOpIdx + 1); 1810234353Sdim // FIXME: VST1/VST2 fixed increment doesn't need Reg0. Remove the reg0 1811234353Sdim // case entirely when the rest are updated to that form, too. 1812234353Sdim if (NumVecs <= 2 && !isa<ConstantSDNode>(Inc.getNode())) 1813234353Sdim Opc = getVLDSTRegisterUpdateOpcode(Opc); 1814234353Sdim // We use a VST1 for v1i64 even if the pseudo says vld2/3/4, so 1815234353Sdim // check for that explicitly too. Horribly hacky, but temporary. 1816234353Sdim if ((NumVecs > 2 && Opc != ARM::VST1q64wb_fixed) || 1817234353Sdim !isa<ConstantSDNode>(Inc.getNode())) 1818234353Sdim Ops.push_back(isa<ConstantSDNode>(Inc.getNode()) ? Reg0 : Inc); 1819218893Sdim } 1820218893Sdim Ops.push_back(SrcReg); 1821212904Sdim Ops.push_back(Pred); 1822218893Sdim Ops.push_back(Reg0); 1823212904Sdim Ops.push_back(Chain); 1824221345Sdim SDNode *VSt = 1825221345Sdim CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), Ops.size()); 1826221345Sdim 1827221345Sdim // Transfer memoperands. 1828221345Sdim cast<MachineSDNode>(VSt)->setMemRefs(MemOp, MemOp + 1); 1829221345Sdim 1830221345Sdim return VSt; 1831198113Srdivacky } 1832198113Srdivacky 1833198113Srdivacky // Otherwise, quad registers are stored with two separate instructions, 1834198113Srdivacky // where one stores the even registers and the other stores the odd registers. 1835198113Srdivacky 1836210299Sed // Form the QQQQ REG_SEQUENCE. 1837218893Sdim SDValue V0 = N->getOperand(Vec0Idx + 0); 1838218893Sdim SDValue V1 = N->getOperand(Vec0Idx + 1); 1839218893Sdim SDValue V2 = N->getOperand(Vec0Idx + 2); 1840212904Sdim SDValue V3 = (NumVecs == 3) 1841212904Sdim ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) 1842218893Sdim : N->getOperand(Vec0Idx + 3); 1843212904Sdim SDValue RegSeq = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); 1844198113Srdivacky 1845218893Sdim // Store the even D registers. This is always an updating store, so that it 1846218893Sdim // provides the address to the second store for the odd subregs. 1847218893Sdim const SDValue OpsA[] = { MemAddr, Align, Reg0, RegSeq, Pred, Reg0, Chain }; 1848218893Sdim SDNode *VStA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl, 1849218893Sdim MemAddr.getValueType(), 1850218893Sdim MVT::Other, OpsA, 7); 1851221345Sdim cast<MachineSDNode>(VStA)->setMemRefs(MemOp, MemOp + 1); 1852218893Sdim Chain = SDValue(VStA, 1); 1853218893Sdim 1854218893Sdim // Store the odd D registers. 1855218893Sdim Ops.push_back(SDValue(VStA, 0)); 1856218893Sdim Ops.push_back(Align); 1857218893Sdim if (isUpdating) { 1858218893Sdim SDValue Inc = N->getOperand(AddrOpIdx + 1); 1859218893Sdim assert(isa<ConstantSDNode>(Inc.getNode()) && 1860218893Sdim "only constant post-increment update allowed for VST3/4"); 1861218893Sdim (void)Inc; 1862218893Sdim Ops.push_back(Reg0); 1863218893Sdim } 1864212904Sdim Ops.push_back(RegSeq); 1865210299Sed Ops.push_back(Pred); 1866218893Sdim Ops.push_back(Reg0); 1867210299Sed Ops.push_back(Chain); 1868221345Sdim SDNode *VStB = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, 1869221345Sdim Ops.data(), Ops.size()); 1870221345Sdim cast<MachineSDNode>(VStB)->setMemRefs(MemOp, MemOp + 1); 1871221345Sdim return VStB; 1872198113Srdivacky} 1873198113Srdivacky 1874202375SrdivackySDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, 1875218893Sdim bool isUpdating, unsigned NumVecs, 1876239462Sdim const uint16_t *DOpcodes, 1877239462Sdim const uint16_t *QOpcodes) { 1878198090Srdivacky assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range"); 1879198090Srdivacky DebugLoc dl = N->getDebugLoc(); 1880198090Srdivacky 1881205407Srdivacky SDValue MemAddr, Align; 1882218893Sdim unsigned AddrOpIdx = isUpdating ? 1 : 2; 1883218893Sdim unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1) 1884218893Sdim if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align)) 1885198090Srdivacky return NULL; 1886198090Srdivacky 1887221345Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 1888221345Sdim MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 1889221345Sdim 1890198090Srdivacky SDValue Chain = N->getOperand(0); 1891198090Srdivacky unsigned Lane = 1892218893Sdim cast<ConstantSDNode>(N->getOperand(Vec0Idx + NumVecs))->getZExtValue(); 1893218893Sdim EVT VT = N->getOperand(Vec0Idx).getValueType(); 1894198090Srdivacky bool is64BitVector = VT.is64BitVector(); 1895198090Srdivacky 1896218893Sdim unsigned Alignment = 0; 1897218893Sdim if (NumVecs != 3) { 1898218893Sdim Alignment = cast<ConstantSDNode>(Align)->getZExtValue(); 1899218893Sdim unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8; 1900218893Sdim if (Alignment > NumBytes) 1901218893Sdim Alignment = NumBytes; 1902218893Sdim if (Alignment < 8 && Alignment < NumBytes) 1903218893Sdim Alignment = 0; 1904218893Sdim // Alignment must be a power of two; make sure of that. 1905218893Sdim Alignment = (Alignment & -Alignment); 1906218893Sdim if (Alignment == 1) 1907218893Sdim Alignment = 0; 1908198090Srdivacky } 1909218893Sdim Align = CurDAG->getTargetConstant(Alignment, MVT::i32); 1910198090Srdivacky 1911198090Srdivacky unsigned OpcodeIndex; 1912198090Srdivacky switch (VT.getSimpleVT().SimpleTy) { 1913198090Srdivacky default: llvm_unreachable("unhandled vld/vst lane type"); 1914198090Srdivacky // Double-register operations: 1915198090Srdivacky case MVT::v8i8: OpcodeIndex = 0; break; 1916198090Srdivacky case MVT::v4i16: OpcodeIndex = 1; break; 1917198090Srdivacky case MVT::v2f32: 1918198090Srdivacky case MVT::v2i32: OpcodeIndex = 2; break; 1919198090Srdivacky // Quad-register operations: 1920198090Srdivacky case MVT::v8i16: OpcodeIndex = 0; break; 1921198090Srdivacky case MVT::v4f32: 1922198090Srdivacky case MVT::v4i32: OpcodeIndex = 1; break; 1923198090Srdivacky } 1924198090Srdivacky 1925218893Sdim std::vector<EVT> ResTys; 1926218893Sdim if (IsLoad) { 1927218893Sdim unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; 1928218893Sdim if (!is64BitVector) 1929218893Sdim ResTyElts *= 2; 1930218893Sdim ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(), 1931218893Sdim MVT::i64, ResTyElts)); 1932218893Sdim } 1933218893Sdim if (isUpdating) 1934218893Sdim ResTys.push_back(MVT::i32); 1935218893Sdim ResTys.push_back(MVT::Other); 1936218893Sdim 1937207618Srdivacky SDValue Pred = getAL(CurDAG); 1938205407Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 1939199989Srdivacky 1940218893Sdim SmallVector<SDValue, 8> Ops; 1941198090Srdivacky Ops.push_back(MemAddr); 1942199481Srdivacky Ops.push_back(Align); 1943218893Sdim if (isUpdating) { 1944218893Sdim SDValue Inc = N->getOperand(AddrOpIdx + 1); 1945218893Sdim Ops.push_back(isa<ConstantSDNode>(Inc.getNode()) ? Reg0 : Inc); 1946218893Sdim } 1947198090Srdivacky 1948218893Sdim SDValue SuperReg; 1949218893Sdim SDValue V0 = N->getOperand(Vec0Idx + 0); 1950218893Sdim SDValue V1 = N->getOperand(Vec0Idx + 1); 1951218893Sdim if (NumVecs == 2) { 1952218893Sdim if (is64BitVector) 1953218893Sdim SuperReg = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); 1954218893Sdim else 1955218893Sdim SuperReg = SDValue(PairQRegs(MVT::v4i64, V0, V1), 0); 1956198090Srdivacky } else { 1957218893Sdim SDValue V2 = N->getOperand(Vec0Idx + 2); 1958218893Sdim SDValue V3 = (NumVecs == 3) 1959218893Sdim ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) 1960218893Sdim : N->getOperand(Vec0Idx + 3); 1961218893Sdim if (is64BitVector) 1962218893Sdim SuperReg = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); 1963218893Sdim else 1964218893Sdim SuperReg = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); 1965198090Srdivacky } 1966218893Sdim Ops.push_back(SuperReg); 1967198090Srdivacky Ops.push_back(getI32Imm(Lane)); 1968199989Srdivacky Ops.push_back(Pred); 1969205407Srdivacky Ops.push_back(Reg0); 1970198090Srdivacky Ops.push_back(Chain); 1971198090Srdivacky 1972218893Sdim unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : 1973218893Sdim QOpcodes[OpcodeIndex]); 1974218893Sdim SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTys, 1975218893Sdim Ops.data(), Ops.size()); 1976221345Sdim cast<MachineSDNode>(VLdLn)->setMemRefs(MemOp, MemOp + 1); 1977198090Srdivacky if (!IsLoad) 1978218893Sdim return VLdLn; 1979198090Srdivacky 1980218893Sdim // Extract the subregisters. 1981218893Sdim SuperReg = SDValue(VLdLn, 0); 1982218893Sdim assert(ARM::dsub_7 == ARM::dsub_0+7 && 1983218893Sdim ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); 1984218893Sdim unsigned Sub0 = is64BitVector ? ARM::dsub_0 : ARM::qsub_0; 1985218893Sdim for (unsigned Vec = 0; Vec < NumVecs; ++Vec) 1986218893Sdim ReplaceUses(SDValue(N, Vec), 1987218893Sdim CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg)); 1988218893Sdim ReplaceUses(SDValue(N, NumVecs), SDValue(VLdLn, 1)); 1989218893Sdim if (isUpdating) 1990218893Sdim ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdLn, 2)); 1991218893Sdim return NULL; 1992218893Sdim} 1993208599Srdivacky 1994218893SdimSDNode *ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, 1995239462Sdim unsigned NumVecs, 1996239462Sdim const uint16_t *Opcodes) { 1997218893Sdim assert(NumVecs >=2 && NumVecs <= 4 && "VLDDup NumVecs out-of-range"); 1998218893Sdim DebugLoc dl = N->getDebugLoc(); 1999208599Srdivacky 2000218893Sdim SDValue MemAddr, Align; 2001218893Sdim if (!SelectAddrMode6(N, N->getOperand(1), MemAddr, Align)) 2002218893Sdim return NULL; 2003218893Sdim 2004221345Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 2005221345Sdim MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 2006221345Sdim 2007218893Sdim SDValue Chain = N->getOperand(0); 2008218893Sdim EVT VT = N->getValueType(0); 2009218893Sdim 2010218893Sdim unsigned Alignment = 0; 2011218893Sdim if (NumVecs != 3) { 2012218893Sdim Alignment = cast<ConstantSDNode>(Align)->getZExtValue(); 2013218893Sdim unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8; 2014218893Sdim if (Alignment > NumBytes) 2015218893Sdim Alignment = NumBytes; 2016218893Sdim if (Alignment < 8 && Alignment < NumBytes) 2017218893Sdim Alignment = 0; 2018218893Sdim // Alignment must be a power of two; make sure of that. 2019218893Sdim Alignment = (Alignment & -Alignment); 2020218893Sdim if (Alignment == 1) 2021218893Sdim Alignment = 0; 2022208599Srdivacky } 2023218893Sdim Align = CurDAG->getTargetConstant(Alignment, MVT::i32); 2024208599Srdivacky 2025218893Sdim unsigned OpcodeIndex; 2026218893Sdim switch (VT.getSimpleVT().SimpleTy) { 2027218893Sdim default: llvm_unreachable("unhandled vld-dup type"); 2028218893Sdim case MVT::v8i8: OpcodeIndex = 0; break; 2029218893Sdim case MVT::v4i16: OpcodeIndex = 1; break; 2030218893Sdim case MVT::v2f32: 2031218893Sdim case MVT::v2i32: OpcodeIndex = 2; break; 2032218893Sdim } 2033218893Sdim 2034218893Sdim SDValue Pred = getAL(CurDAG); 2035218893Sdim SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 2036218893Sdim SDValue SuperReg; 2037218893Sdim unsigned Opc = Opcodes[OpcodeIndex]; 2038218893Sdim SmallVector<SDValue, 6> Ops; 2039218893Sdim Ops.push_back(MemAddr); 2040218893Sdim Ops.push_back(Align); 2041218893Sdim if (isUpdating) { 2042234353Sdim // fixed-stride update instructions don't have an explicit writeback 2043234353Sdim // operand. It's implicit in the opcode itself. 2044218893Sdim SDValue Inc = N->getOperand(2); 2045234353Sdim if (!isa<ConstantSDNode>(Inc.getNode())) 2046234353Sdim Ops.push_back(Inc); 2047234353Sdim // FIXME: VLD3 and VLD4 haven't been updated to that form yet. 2048234353Sdim else if (NumVecs > 2) 2049234353Sdim Ops.push_back(Reg0); 2050218893Sdim } 2051218893Sdim Ops.push_back(Pred); 2052218893Sdim Ops.push_back(Reg0); 2053218893Sdim Ops.push_back(Chain); 2054218893Sdim 2055218893Sdim unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; 2056218893Sdim std::vector<EVT> ResTys; 2057221345Sdim ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(), MVT::i64,ResTyElts)); 2058218893Sdim if (isUpdating) 2059218893Sdim ResTys.push_back(MVT::i32); 2060218893Sdim ResTys.push_back(MVT::Other); 2061218893Sdim SDNode *VLdDup = 2062218893Sdim CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), Ops.size()); 2063221345Sdim cast<MachineSDNode>(VLdDup)->setMemRefs(MemOp, MemOp + 1); 2064218893Sdim SuperReg = SDValue(VLdDup, 0); 2065218893Sdim 2066218893Sdim // Extract the subregisters. 2067210299Sed assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); 2068218893Sdim unsigned SubIdx = ARM::dsub_0; 2069210299Sed for (unsigned Vec = 0; Vec < NumVecs; ++Vec) 2070210299Sed ReplaceUses(SDValue(N, Vec), 2071218893Sdim CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg)); 2072218893Sdim ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1)); 2073218893Sdim if (isUpdating) 2074218893Sdim ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdDup, 2)); 2075210299Sed return NULL; 2076210299Sed} 2077198090Srdivacky 2078210299SedSDNode *ARMDAGToDAGISel::SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, 2079210299Sed unsigned Opc) { 2080210299Sed assert(NumVecs >= 2 && NumVecs <= 4 && "VTBL NumVecs out-of-range"); 2081210299Sed DebugLoc dl = N->getDebugLoc(); 2082210299Sed EVT VT = N->getValueType(0); 2083210299Sed unsigned FirstTblReg = IsExt ? 2 : 1; 2084210299Sed 2085210299Sed // Form a REG_SEQUENCE to force register allocation. 2086210299Sed SDValue RegSeq; 2087210299Sed SDValue V0 = N->getOperand(FirstTblReg + 0); 2088210299Sed SDValue V1 = N->getOperand(FirstTblReg + 1); 2089210299Sed if (NumVecs == 2) 2090210299Sed RegSeq = SDValue(PairDRegs(MVT::v16i8, V0, V1), 0); 2091210299Sed else { 2092210299Sed SDValue V2 = N->getOperand(FirstTblReg + 2); 2093218893Sdim // If it's a vtbl3, form a quad D-register and leave the last part as 2094210299Sed // an undef. 2095210299Sed SDValue V3 = (NumVecs == 3) 2096210299Sed ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) 2097210299Sed : N->getOperand(FirstTblReg + 3); 2098210299Sed RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); 2099198090Srdivacky } 2100198090Srdivacky 2101210299Sed SmallVector<SDValue, 6> Ops; 2102210299Sed if (IsExt) 2103210299Sed Ops.push_back(N->getOperand(1)); 2104218893Sdim Ops.push_back(RegSeq); 2105210299Sed Ops.push_back(N->getOperand(FirstTblReg + NumVecs)); 2106210299Sed Ops.push_back(getAL(CurDAG)); // predicate 2107210299Sed Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // predicate register 2108210299Sed return CurDAG->getMachineNode(Opc, dl, VT, Ops.data(), Ops.size()); 2109198090Srdivacky} 2110198090Srdivacky 2111202375SrdivackySDNode *ARMDAGToDAGISel::SelectV6T2BitfieldExtractOp(SDNode *N, 2112207618Srdivacky bool isSigned) { 2113198090Srdivacky if (!Subtarget->hasV6T2Ops()) 2114198090Srdivacky return NULL; 2115198090Srdivacky 2116207618Srdivacky unsigned Opc = isSigned ? (Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX) 2117207618Srdivacky : (Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX); 2118207618Srdivacky 2119207618Srdivacky 2120207618Srdivacky // For unsigned extracts, check for a shift right and mask 2121207618Srdivacky unsigned And_imm = 0; 2122207618Srdivacky if (N->getOpcode() == ISD::AND) { 2123207618Srdivacky if (isOpcWithIntImmediate(N, ISD::AND, And_imm)) { 2124207618Srdivacky 2125207618Srdivacky // The immediate is a mask of the low bits iff imm & (imm+1) == 0 2126207618Srdivacky if (And_imm & (And_imm + 1)) 2127207618Srdivacky return NULL; 2128207618Srdivacky 2129207618Srdivacky unsigned Srl_imm = 0; 2130207618Srdivacky if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL, 2131207618Srdivacky Srl_imm)) { 2132207618Srdivacky assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); 2133207618Srdivacky 2134226633Sdim // Note: The width operand is encoded as width-1. 2135226633Sdim unsigned Width = CountTrailingOnes_32(And_imm) - 1; 2136207618Srdivacky unsigned LSB = Srl_imm; 2137207618Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 2138207618Srdivacky SDValue Ops[] = { N->getOperand(0).getOperand(0), 2139207618Srdivacky CurDAG->getTargetConstant(LSB, MVT::i32), 2140207618Srdivacky CurDAG->getTargetConstant(Width, MVT::i32), 2141207618Srdivacky getAL(CurDAG), Reg0 }; 2142207618Srdivacky return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); 2143207618Srdivacky } 2144207618Srdivacky } 2145207618Srdivacky return NULL; 2146207618Srdivacky } 2147207618Srdivacky 2148207618Srdivacky // Otherwise, we're looking for a shift of a shift 2149198090Srdivacky unsigned Shl_imm = 0; 2150202375Srdivacky if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) { 2151198090Srdivacky assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!"); 2152198090Srdivacky unsigned Srl_imm = 0; 2153202375Srdivacky if (isInt32Immediate(N->getOperand(1), Srl_imm)) { 2154198090Srdivacky assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); 2155226633Sdim // Note: The width operand is encoded as width-1. 2156226633Sdim unsigned Width = 32 - Srl_imm - 1; 2157198090Srdivacky int LSB = Srl_imm - Shl_imm; 2158198396Srdivacky if (LSB < 0) 2159198090Srdivacky return NULL; 2160198090Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 2161202375Srdivacky SDValue Ops[] = { N->getOperand(0).getOperand(0), 2162198090Srdivacky CurDAG->getTargetConstant(LSB, MVT::i32), 2163198090Srdivacky CurDAG->getTargetConstant(Width, MVT::i32), 2164198090Srdivacky getAL(CurDAG), Reg0 }; 2165202375Srdivacky return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); 2166198090Srdivacky } 2167198090Srdivacky } 2168198090Srdivacky return NULL; 2169198090Srdivacky} 2170198090Srdivacky 2171199989SrdivackySDNode *ARMDAGToDAGISel:: 2172202375SrdivackySelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 2173199989Srdivacky ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { 2174199989Srdivacky SDValue CPTmp0; 2175199989Srdivacky SDValue CPTmp1; 2176218893Sdim if (SelectT2ShifterOperandReg(TrueVal, CPTmp0, CPTmp1)) { 2177199989Srdivacky unsigned SOVal = cast<ConstantSDNode>(CPTmp1)->getZExtValue(); 2178199989Srdivacky unsigned SOShOp = ARM_AM::getSORegShOp(SOVal); 2179199989Srdivacky unsigned Opc = 0; 2180199989Srdivacky switch (SOShOp) { 2181199989Srdivacky case ARM_AM::lsl: Opc = ARM::t2MOVCClsl; break; 2182199989Srdivacky case ARM_AM::lsr: Opc = ARM::t2MOVCClsr; break; 2183199989Srdivacky case ARM_AM::asr: Opc = ARM::t2MOVCCasr; break; 2184199989Srdivacky case ARM_AM::ror: Opc = ARM::t2MOVCCror; break; 2185199989Srdivacky default: 2186199989Srdivacky llvm_unreachable("Unknown so_reg opcode!"); 2187199989Srdivacky } 2188199989Srdivacky SDValue SOShImm = 2189199989Srdivacky CurDAG->getTargetConstant(ARM_AM::getSORegOffset(SOVal), MVT::i32); 2190199989Srdivacky SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); 2191199989Srdivacky SDValue Ops[] = { FalseVal, CPTmp0, SOShImm, CC, CCR, InFlag }; 2192202375Srdivacky return CurDAG->SelectNodeTo(N, Opc, MVT::i32,Ops, 6); 2193199989Srdivacky } 2194199989Srdivacky return 0; 2195199989Srdivacky} 2196199989Srdivacky 2197199989SrdivackySDNode *ARMDAGToDAGISel:: 2198202375SrdivackySelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 2199199989Srdivacky ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { 2200199989Srdivacky SDValue CPTmp0; 2201199989Srdivacky SDValue CPTmp1; 2202199989Srdivacky SDValue CPTmp2; 2203226633Sdim if (SelectImmShifterOperand(TrueVal, CPTmp0, CPTmp2)) { 2204199989Srdivacky SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); 2205226633Sdim SDValue Ops[] = { FalseVal, CPTmp0, CPTmp2, CC, CCR, InFlag }; 2206226633Sdim return CurDAG->SelectNodeTo(N, ARM::MOVCCsi, MVT::i32, Ops, 6); 2207226633Sdim } 2208226633Sdim 2209226633Sdim if (SelectRegShifterOperand(TrueVal, CPTmp0, CPTmp1, CPTmp2)) { 2210226633Sdim SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); 2211199989Srdivacky SDValue Ops[] = { FalseVal, CPTmp0, CPTmp1, CPTmp2, CC, CCR, InFlag }; 2212226633Sdim return CurDAG->SelectNodeTo(N, ARM::MOVCCsr, MVT::i32, Ops, 7); 2213199989Srdivacky } 2214199989Srdivacky return 0; 2215199989Srdivacky} 2216199989Srdivacky 2217199989SrdivackySDNode *ARMDAGToDAGISel:: 2218218893SdimSelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 2219218893Sdim ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { 2220199989Srdivacky ConstantSDNode *T = dyn_cast<ConstantSDNode>(TrueVal); 2221199989Srdivacky if (!T) 2222199989Srdivacky return 0; 2223199989Srdivacky 2224218893Sdim unsigned Opc = 0; 2225218893Sdim unsigned TrueImm = T->getZExtValue(); 2226218893Sdim if (is_t2_so_imm(TrueImm)) { 2227218893Sdim Opc = ARM::t2MOVCCi; 2228218893Sdim } else if (TrueImm <= 0xffff) { 2229218893Sdim Opc = ARM::t2MOVCCi16; 2230218893Sdim } else if (is_t2_so_imm_not(TrueImm)) { 2231218893Sdim TrueImm = ~TrueImm; 2232218893Sdim Opc = ARM::t2MVNCCi; 2233218893Sdim } else if (TrueVal.getNode()->hasOneUse() && Subtarget->hasV6T2Ops()) { 2234218893Sdim // Large immediate. 2235218893Sdim Opc = ARM::t2MOVCCi32imm; 2236218893Sdim } 2237218893Sdim 2238218893Sdim if (Opc) { 2239218893Sdim SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); 2240199989Srdivacky SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); 2241199989Srdivacky SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; 2242218893Sdim return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); 2243199989Srdivacky } 2244218893Sdim 2245199989Srdivacky return 0; 2246199989Srdivacky} 2247199989Srdivacky 2248199989SrdivackySDNode *ARMDAGToDAGISel:: 2249218893SdimSelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, 2250218893Sdim ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { 2251199989Srdivacky ConstantSDNode *T = dyn_cast<ConstantSDNode>(TrueVal); 2252199989Srdivacky if (!T) 2253199989Srdivacky return 0; 2254199989Srdivacky 2255218893Sdim unsigned Opc = 0; 2256218893Sdim unsigned TrueImm = T->getZExtValue(); 2257218893Sdim bool isSoImm = is_so_imm(TrueImm); 2258218893Sdim if (isSoImm) { 2259218893Sdim Opc = ARM::MOVCCi; 2260218893Sdim } else if (Subtarget->hasV6T2Ops() && TrueImm <= 0xffff) { 2261218893Sdim Opc = ARM::MOVCCi16; 2262218893Sdim } else if (is_so_imm_not(TrueImm)) { 2263218893Sdim TrueImm = ~TrueImm; 2264218893Sdim Opc = ARM::MVNCCi; 2265218893Sdim } else if (TrueVal.getNode()->hasOneUse() && 2266218893Sdim (Subtarget->hasV6T2Ops() || ARM_AM::isSOImmTwoPartVal(TrueImm))) { 2267218893Sdim // Large immediate. 2268218893Sdim Opc = ARM::MOVCCi32imm; 2269218893Sdim } 2270218893Sdim 2271218893Sdim if (Opc) { 2272218893Sdim SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); 2273199989Srdivacky SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); 2274199989Srdivacky SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; 2275218893Sdim return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); 2276199989Srdivacky } 2277218893Sdim 2278199989Srdivacky return 0; 2279199989Srdivacky} 2280199989Srdivacky 2281202375SrdivackySDNode *ARMDAGToDAGISel::SelectCMOVOp(SDNode *N) { 2282202375Srdivacky EVT VT = N->getValueType(0); 2283202375Srdivacky SDValue FalseVal = N->getOperand(0); 2284202375Srdivacky SDValue TrueVal = N->getOperand(1); 2285202375Srdivacky SDValue CC = N->getOperand(2); 2286202375Srdivacky SDValue CCR = N->getOperand(3); 2287202375Srdivacky SDValue InFlag = N->getOperand(4); 2288199989Srdivacky assert(CC.getOpcode() == ISD::Constant); 2289199989Srdivacky assert(CCR.getOpcode() == ISD::Register); 2290199989Srdivacky ARMCC::CondCodes CCVal = 2291199989Srdivacky (ARMCC::CondCodes)cast<ConstantSDNode>(CC)->getZExtValue(); 2292199989Srdivacky 2293199989Srdivacky if (!Subtarget->isThumb1Only() && VT == MVT::i32) { 2294199989Srdivacky // Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) 2295199989Srdivacky // Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) 2296199989Srdivacky // Pattern complexity = 18 cost = 1 size = 0 2297199989Srdivacky if (Subtarget->isThumb()) { 2298202375Srdivacky SDNode *Res = SelectT2CMOVShiftOp(N, FalseVal, TrueVal, 2299199989Srdivacky CCVal, CCR, InFlag); 2300199989Srdivacky if (!Res) 2301202375Srdivacky Res = SelectT2CMOVShiftOp(N, TrueVal, FalseVal, 2302199989Srdivacky ARMCC::getOppositeCondition(CCVal), CCR, InFlag); 2303199989Srdivacky if (Res) 2304199989Srdivacky return Res; 2305199989Srdivacky } else { 2306202375Srdivacky SDNode *Res = SelectARMCMOVShiftOp(N, FalseVal, TrueVal, 2307199989Srdivacky CCVal, CCR, InFlag); 2308199989Srdivacky if (!Res) 2309202375Srdivacky Res = SelectARMCMOVShiftOp(N, TrueVal, FalseVal, 2310199989Srdivacky ARMCC::getOppositeCondition(CCVal), CCR, InFlag); 2311199989Srdivacky if (Res) 2312199989Srdivacky return Res; 2313199989Srdivacky } 2314199989Srdivacky 2315199989Srdivacky // Pattern: (ARMcmov:i32 GPR:i32:$false, 2316212904Sdim // (imm:i32)<<P:Pred_so_imm>>:$true, 2317199989Srdivacky // (imm:i32):$cc) 2318199989Srdivacky // Emits: (MOVCCi:i32 GPR:i32:$false, 2319199989Srdivacky // (so_imm:i32 (imm:i32):$true), (imm:i32):$cc) 2320199989Srdivacky // Pattern complexity = 10 cost = 1 size = 0 2321199989Srdivacky if (Subtarget->isThumb()) { 2322218893Sdim SDNode *Res = SelectT2CMOVImmOp(N, FalseVal, TrueVal, 2323199989Srdivacky CCVal, CCR, InFlag); 2324199989Srdivacky if (!Res) 2325218893Sdim Res = SelectT2CMOVImmOp(N, TrueVal, FalseVal, 2326199989Srdivacky ARMCC::getOppositeCondition(CCVal), CCR, InFlag); 2327199989Srdivacky if (Res) 2328199989Srdivacky return Res; 2329199989Srdivacky } else { 2330218893Sdim SDNode *Res = SelectARMCMOVImmOp(N, FalseVal, TrueVal, 2331199989Srdivacky CCVal, CCR, InFlag); 2332199989Srdivacky if (!Res) 2333218893Sdim Res = SelectARMCMOVImmOp(N, TrueVal, FalseVal, 2334199989Srdivacky ARMCC::getOppositeCondition(CCVal), CCR, InFlag); 2335199989Srdivacky if (Res) 2336199989Srdivacky return Res; 2337199989Srdivacky } 2338199989Srdivacky } 2339199989Srdivacky 2340199989Srdivacky // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) 2341199989Srdivacky // Emits: (MOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) 2342199989Srdivacky // Pattern complexity = 6 cost = 1 size = 0 2343199989Srdivacky // 2344199989Srdivacky // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) 2345199989Srdivacky // Emits: (tMOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) 2346199989Srdivacky // Pattern complexity = 6 cost = 11 size = 0 2347199989Srdivacky // 2348221345Sdim // Also VMOVScc and VMOVDcc. 2349199989Srdivacky SDValue Tmp2 = CurDAG->getTargetConstant(CCVal, MVT::i32); 2350199989Srdivacky SDValue Ops[] = { FalseVal, TrueVal, Tmp2, CCR, InFlag }; 2351199989Srdivacky unsigned Opc = 0; 2352199989Srdivacky switch (VT.getSimpleVT().SimpleTy) { 2353234353Sdim default: llvm_unreachable("Illegal conditional move type!"); 2354199989Srdivacky case MVT::i32: 2355199989Srdivacky Opc = Subtarget->isThumb() 2356199989Srdivacky ? (Subtarget->hasThumb2() ? ARM::t2MOVCCr : ARM::tMOVCCr_pseudo) 2357199989Srdivacky : ARM::MOVCCr; 2358199989Srdivacky break; 2359199989Srdivacky case MVT::f32: 2360199989Srdivacky Opc = ARM::VMOVScc; 2361199989Srdivacky break; 2362199989Srdivacky case MVT::f64: 2363199989Srdivacky Opc = ARM::VMOVDcc; 2364199989Srdivacky break; 2365199989Srdivacky } 2366202375Srdivacky return CurDAG->SelectNodeTo(N, Opc, VT, Ops, 5); 2367199989Srdivacky} 2368199989Srdivacky 2369226633Sdim/// Target-specific DAG combining for ISD::XOR. 2370226633Sdim/// Target-independent combining lowers SELECT_CC nodes of the form 2371226633Sdim/// select_cc setg[ge] X, 0, X, -X 2372226633Sdim/// select_cc setgt X, -1, X, -X 2373226633Sdim/// select_cc setl[te] X, 0, -X, X 2374226633Sdim/// select_cc setlt X, 1, -X, X 2375226633Sdim/// which represent Integer ABS into: 2376226633Sdim/// Y = sra (X, size(X)-1); xor (add (X, Y), Y) 2377226633Sdim/// ARM instruction selection detects the latter and matches it to 2378226633Sdim/// ARM::ABS or ARM::t2ABS machine node. 2379226633SdimSDNode *ARMDAGToDAGISel::SelectABSOp(SDNode *N){ 2380226633Sdim SDValue XORSrc0 = N->getOperand(0); 2381226633Sdim SDValue XORSrc1 = N->getOperand(1); 2382226633Sdim EVT VT = N->getValueType(0); 2383226633Sdim 2384226633Sdim if (Subtarget->isThumb1Only()) 2385226633Sdim return NULL; 2386226633Sdim 2387239462Sdim if (XORSrc0.getOpcode() != ISD::ADD || XORSrc1.getOpcode() != ISD::SRA) 2388226633Sdim return NULL; 2389226633Sdim 2390226633Sdim SDValue ADDSrc0 = XORSrc0.getOperand(0); 2391226633Sdim SDValue ADDSrc1 = XORSrc0.getOperand(1); 2392226633Sdim SDValue SRASrc0 = XORSrc1.getOperand(0); 2393226633Sdim SDValue SRASrc1 = XORSrc1.getOperand(1); 2394226633Sdim ConstantSDNode *SRAConstant = dyn_cast<ConstantSDNode>(SRASrc1); 2395226633Sdim EVT XType = SRASrc0.getValueType(); 2396226633Sdim unsigned Size = XType.getSizeInBits() - 1; 2397226633Sdim 2398239462Sdim if (ADDSrc1 == XORSrc1 && ADDSrc0 == SRASrc0 && 2399239462Sdim XType.isInteger() && SRAConstant != NULL && 2400226633Sdim Size == SRAConstant->getZExtValue()) { 2401239462Sdim unsigned Opcode = Subtarget->isThumb2() ? ARM::t2ABS : ARM::ABS; 2402226633Sdim return CurDAG->SelectNodeTo(N, Opcode, VT, ADDSrc0); 2403226633Sdim } 2404226633Sdim 2405226633Sdim return NULL; 2406226633Sdim} 2407226633Sdim 2408208599SrdivackySDNode *ARMDAGToDAGISel::SelectConcatVector(SDNode *N) { 2409208599Srdivacky // The only time a CONCAT_VECTORS operation can have legal types is when 2410208599Srdivacky // two 64-bit vectors are concatenated to a 128-bit vector. 2411208599Srdivacky EVT VT = N->getValueType(0); 2412208599Srdivacky if (!VT.is128BitVector() || N->getNumOperands() != 2) 2413208599Srdivacky llvm_unreachable("unexpected CONCAT_VECTORS"); 2414218893Sdim return PairDRegs(VT, N->getOperand(0), N->getOperand(1)); 2415208599Srdivacky} 2416208599Srdivacky 2417226633SdimSDNode *ARMDAGToDAGISel::SelectAtomic64(SDNode *Node, unsigned Opc) { 2418226633Sdim SmallVector<SDValue, 6> Ops; 2419226633Sdim Ops.push_back(Node->getOperand(1)); // Ptr 2420226633Sdim Ops.push_back(Node->getOperand(2)); // Low part of Val1 2421226633Sdim Ops.push_back(Node->getOperand(3)); // High part of Val1 2422226633Sdim if (Opc == ARM::ATOMCMPXCHG6432) { 2423226633Sdim Ops.push_back(Node->getOperand(4)); // Low part of Val2 2424226633Sdim Ops.push_back(Node->getOperand(5)); // High part of Val2 2425226633Sdim } 2426226633Sdim Ops.push_back(Node->getOperand(0)); // Chain 2427226633Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 2428226633Sdim MemOp[0] = cast<MemSDNode>(Node)->getMemOperand(); 2429226633Sdim SDNode *ResNode = CurDAG->getMachineNode(Opc, Node->getDebugLoc(), 2430226633Sdim MVT::i32, MVT::i32, MVT::Other, 2431226633Sdim Ops.data() ,Ops.size()); 2432226633Sdim cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1); 2433226633Sdim return ResNode; 2434226633Sdim} 2435226633Sdim 2436202375SrdivackySDNode *ARMDAGToDAGISel::Select(SDNode *N) { 2437193323Sed DebugLoc dl = N->getDebugLoc(); 2438193323Sed 2439193323Sed if (N->isMachineOpcode()) 2440193323Sed return NULL; // Already selected. 2441193323Sed 2442193323Sed switch (N->getOpcode()) { 2443193323Sed default: break; 2444226633Sdim case ISD::XOR: { 2445226633Sdim // Select special operations if XOR node forms integer ABS pattern 2446226633Sdim SDNode *ResNode = SelectABSOp(N); 2447226633Sdim if (ResNode) 2448226633Sdim return ResNode; 2449226633Sdim // Other cases are autogenerated. 2450226633Sdim break; 2451226633Sdim } 2452193323Sed case ISD::Constant: { 2453193323Sed unsigned Val = cast<ConstantSDNode>(N)->getZExtValue(); 2454193323Sed bool UseCP = true; 2455198090Srdivacky if (Subtarget->hasThumb2()) 2456198090Srdivacky // Thumb2-aware targets have the MOVT instruction, so all immediates can 2457198090Srdivacky // be done with MOV + MOVT, at worst. 2458198090Srdivacky UseCP = 0; 2459198090Srdivacky else { 2460198090Srdivacky if (Subtarget->isThumb()) { 2461194710Sed UseCP = (Val > 255 && // MOV 2462194710Sed ~Val > 255 && // MOV + MVN 2463194710Sed !ARM_AM::isThumbImmShiftedVal(Val)); // MOV + LSL 2464198090Srdivacky } else 2465198090Srdivacky UseCP = (ARM_AM::getSOImmVal(Val) == -1 && // MOV 2466198090Srdivacky ARM_AM::getSOImmVal(~Val) == -1 && // MVN 2467198090Srdivacky !ARM_AM::isSOImmTwoPartVal(Val)); // two instrs. 2468198090Srdivacky } 2469198090Srdivacky 2470193323Sed if (UseCP) { 2471193323Sed SDValue CPIdx = 2472198090Srdivacky CurDAG->getTargetConstantPool(ConstantInt::get( 2473198090Srdivacky Type::getInt32Ty(*CurDAG->getContext()), Val), 2474193323Sed TLI.getPointerTy()); 2475193323Sed 2476193323Sed SDNode *ResNode; 2477198090Srdivacky if (Subtarget->isThumb1Only()) { 2478207618Srdivacky SDValue Pred = getAL(CurDAG); 2479198090Srdivacky SDValue PredReg = CurDAG->getRegister(0, MVT::i32); 2480198090Srdivacky SDValue Ops[] = { CPIdx, Pred, PredReg, CurDAG->getEntryNode() }; 2481218893Sdim ResNode = CurDAG->getMachineNode(ARM::tLDRpci, dl, MVT::i32, MVT::Other, 2482198090Srdivacky Ops, 4); 2483198090Srdivacky } else { 2484193323Sed SDValue Ops[] = { 2485198090Srdivacky CPIdx, 2486193323Sed CurDAG->getTargetConstant(0, MVT::i32), 2487193323Sed getAL(CurDAG), 2488193323Sed CurDAG->getRegister(0, MVT::i32), 2489193323Sed CurDAG->getEntryNode() 2490193323Sed }; 2491198090Srdivacky ResNode=CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other, 2492218893Sdim Ops, 5); 2493193323Sed } 2494202375Srdivacky ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 2495193323Sed return NULL; 2496193323Sed } 2497198090Srdivacky 2498193323Sed // Other cases are autogenerated. 2499193323Sed break; 2500193323Sed } 2501193323Sed case ISD::FrameIndex: { 2502193323Sed // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm. 2503193323Sed int FI = cast<FrameIndexSDNode>(N)->getIndex(); 2504193323Sed SDValue TFI = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); 2505198090Srdivacky if (Subtarget->isThumb1Only()) { 2506226633Sdim SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, MVT::i32), 2507226633Sdim getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; 2508226633Sdim return CurDAG->SelectNodeTo(N, ARM::tADDrSPi, MVT::i32, Ops, 4); 2509193323Sed } else { 2510198090Srdivacky unsigned Opc = ((Subtarget->isThumb() && Subtarget->hasThumb2()) ? 2511198090Srdivacky ARM::t2ADDri : ARM::ADDri); 2512193323Sed SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, MVT::i32), 2513198090Srdivacky getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), 2514198090Srdivacky CurDAG->getRegister(0, MVT::i32) }; 2515198090Srdivacky return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); 2516193323Sed } 2517193323Sed } 2518198090Srdivacky case ISD::SRL: 2519207618Srdivacky if (SDNode *I = SelectV6T2BitfieldExtractOp(N, false)) 2520198090Srdivacky return I; 2521193323Sed break; 2522198090Srdivacky case ISD::SRA: 2523207618Srdivacky if (SDNode *I = SelectV6T2BitfieldExtractOp(N, true)) 2524198090Srdivacky return I; 2525198090Srdivacky break; 2526193323Sed case ISD::MUL: 2527198090Srdivacky if (Subtarget->isThumb1Only()) 2528193323Sed break; 2529202375Srdivacky if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) { 2530193323Sed unsigned RHSV = C->getZExtValue(); 2531193323Sed if (!RHSV) break; 2532193323Sed if (isPowerOf2_32(RHSV-1)) { // 2^n+1? 2533198090Srdivacky unsigned ShImm = Log2_32(RHSV-1); 2534198090Srdivacky if (ShImm >= 32) 2535198090Srdivacky break; 2536202375Srdivacky SDValue V = N->getOperand(0); 2537198090Srdivacky ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm); 2538198090Srdivacky SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, MVT::i32); 2539198090Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 2540198090Srdivacky if (Subtarget->isThumb()) { 2541198090Srdivacky SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; 2542198090Srdivacky return CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops, 6); 2543198090Srdivacky } else { 2544198090Srdivacky SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; 2545226633Sdim return CurDAG->SelectNodeTo(N, ARM::ADDrsi, MVT::i32, Ops, 7); 2546198090Srdivacky } 2547193323Sed } 2548193323Sed if (isPowerOf2_32(RHSV+1)) { // 2^n-1? 2549198090Srdivacky unsigned ShImm = Log2_32(RHSV+1); 2550198090Srdivacky if (ShImm >= 32) 2551198090Srdivacky break; 2552202375Srdivacky SDValue V = N->getOperand(0); 2553198090Srdivacky ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm); 2554198090Srdivacky SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, MVT::i32); 2555198090Srdivacky SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); 2556198090Srdivacky if (Subtarget->isThumb()) { 2557210299Sed SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; 2558210299Sed return CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops, 6); 2559198090Srdivacky } else { 2560198090Srdivacky SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; 2561226633Sdim return CurDAG->SelectNodeTo(N, ARM::RSBrsi, MVT::i32, Ops, 7); 2562198090Srdivacky } 2563193323Sed } 2564193323Sed } 2565193323Sed break; 2566198396Srdivacky case ISD::AND: { 2567207618Srdivacky // Check for unsigned bitfield extract 2568207618Srdivacky if (SDNode *I = SelectV6T2BitfieldExtractOp(N, false)) 2569207618Srdivacky return I; 2570207618Srdivacky 2571198396Srdivacky // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits 2572198396Srdivacky // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits 2573198396Srdivacky // are entirely contributed by c2 and lower 16-bits are entirely contributed 2574198396Srdivacky // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)). 2575198396Srdivacky // Select it to: "movt x, ((c1 & 0xffff) >> 16) 2576202375Srdivacky EVT VT = N->getValueType(0); 2577198396Srdivacky if (VT != MVT::i32) 2578198396Srdivacky break; 2579198396Srdivacky unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2()) 2580198396Srdivacky ? ARM::t2MOVTi16 2581198396Srdivacky : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0); 2582198396Srdivacky if (!Opc) 2583198396Srdivacky break; 2584202375Srdivacky SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); 2585198396Srdivacky ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1); 2586198396Srdivacky if (!N1C) 2587198396Srdivacky break; 2588198396Srdivacky if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) { 2589198396Srdivacky SDValue N2 = N0.getOperand(1); 2590198396Srdivacky ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2); 2591198396Srdivacky if (!N2C) 2592198396Srdivacky break; 2593198396Srdivacky unsigned N1CVal = N1C->getZExtValue(); 2594198396Srdivacky unsigned N2CVal = N2C->getZExtValue(); 2595198396Srdivacky if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) && 2596198396Srdivacky (N1CVal & 0xffffU) == 0xffffU && 2597198396Srdivacky (N2CVal & 0xffffU) == 0x0U) { 2598198396Srdivacky SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16, 2599198396Srdivacky MVT::i32); 2600198396Srdivacky SDValue Ops[] = { N0.getOperand(0), Imm16, 2601198396Srdivacky getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; 2602198396Srdivacky return CurDAG->getMachineNode(Opc, dl, VT, Ops, 4); 2603198396Srdivacky } 2604198396Srdivacky } 2605198396Srdivacky break; 2606198396Srdivacky } 2607199481Srdivacky case ARMISD::VMOVRRD: 2608199481Srdivacky return CurDAG->getMachineNode(ARM::VMOVRRD, dl, MVT::i32, MVT::i32, 2609202375Srdivacky N->getOperand(0), getAL(CurDAG), 2610198090Srdivacky CurDAG->getRegister(0, MVT::i32)); 2611193323Sed case ISD::UMUL_LOHI: { 2612198090Srdivacky if (Subtarget->isThumb1Only()) 2613198090Srdivacky break; 2614198090Srdivacky if (Subtarget->isThumb()) { 2615202375Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 2616193323Sed getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), 2617193323Sed CurDAG->getRegister(0, MVT::i32) }; 2618210299Sed return CurDAG->getMachineNode(ARM::t2UMULL, dl, MVT::i32, MVT::i32,Ops,4); 2619198090Srdivacky } else { 2620202375Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 2621198090Srdivacky getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), 2622198090Srdivacky CurDAG->getRegister(0, MVT::i32) }; 2623218893Sdim return CurDAG->getMachineNode(Subtarget->hasV6Ops() ? 2624218893Sdim ARM::UMULL : ARM::UMULLv5, 2625218893Sdim dl, MVT::i32, MVT::i32, Ops, 5); 2626198090Srdivacky } 2627193323Sed } 2628193323Sed case ISD::SMUL_LOHI: { 2629198090Srdivacky if (Subtarget->isThumb1Only()) 2630198090Srdivacky break; 2631198090Srdivacky if (Subtarget->isThumb()) { 2632202375Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 2633198090Srdivacky getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; 2634210299Sed return CurDAG->getMachineNode(ARM::t2SMULL, dl, MVT::i32, MVT::i32,Ops,4); 2635198090Srdivacky } else { 2636202375Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 2637193323Sed getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), 2638193323Sed CurDAG->getRegister(0, MVT::i32) }; 2639218893Sdim return CurDAG->getMachineNode(Subtarget->hasV6Ops() ? 2640218893Sdim ARM::SMULL : ARM::SMULLv5, 2641218893Sdim dl, MVT::i32, MVT::i32, Ops, 5); 2642198090Srdivacky } 2643193323Sed } 2644243830Sdim case ARMISD::UMLAL:{ 2645243830Sdim if (Subtarget->isThumb()) { 2646243830Sdim SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2), 2647243830Sdim N->getOperand(3), getAL(CurDAG), 2648243830Sdim CurDAG->getRegister(0, MVT::i32)}; 2649243830Sdim return CurDAG->getMachineNode(ARM::t2UMLAL, dl, MVT::i32, MVT::i32, Ops, 6); 2650243830Sdim }else{ 2651243830Sdim SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2), 2652243830Sdim N->getOperand(3), getAL(CurDAG), 2653243830Sdim CurDAG->getRegister(0, MVT::i32), 2654243830Sdim CurDAG->getRegister(0, MVT::i32) }; 2655243830Sdim return CurDAG->getMachineNode(Subtarget->hasV6Ops() ? 2656243830Sdim ARM::UMLAL : ARM::UMLALv5, 2657243830Sdim dl, MVT::i32, MVT::i32, Ops, 7); 2658243830Sdim } 2659243830Sdim } 2660243830Sdim case ARMISD::SMLAL:{ 2661243830Sdim if (Subtarget->isThumb()) { 2662243830Sdim SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2), 2663243830Sdim N->getOperand(3), getAL(CurDAG), 2664243830Sdim CurDAG->getRegister(0, MVT::i32)}; 2665243830Sdim return CurDAG->getMachineNode(ARM::t2SMLAL, dl, MVT::i32, MVT::i32, Ops, 6); 2666243830Sdim }else{ 2667243830Sdim SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2), 2668243830Sdim N->getOperand(3), getAL(CurDAG), 2669243830Sdim CurDAG->getRegister(0, MVT::i32), 2670243830Sdim CurDAG->getRegister(0, MVT::i32) }; 2671243830Sdim return CurDAG->getMachineNode(Subtarget->hasV6Ops() ? 2672243830Sdim ARM::SMLAL : ARM::SMLALv5, 2673243830Sdim dl, MVT::i32, MVT::i32, Ops, 7); 2674243830Sdim } 2675243830Sdim } 2676193323Sed case ISD::LOAD: { 2677195340Sed SDNode *ResNode = 0; 2678198090Srdivacky if (Subtarget->isThumb() && Subtarget->hasThumb2()) 2679202375Srdivacky ResNode = SelectT2IndexedLoad(N); 2680195340Sed else 2681202375Srdivacky ResNode = SelectARMIndexedLoad(N); 2682195340Sed if (ResNode) 2683195340Sed return ResNode; 2684193323Sed // Other cases are autogenerated. 2685193323Sed break; 2686193323Sed } 2687193323Sed case ARMISD::BRCOND: { 2688193323Sed // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) 2689193323Sed // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc) 2690193323Sed // Pattern complexity = 6 cost = 1 size = 0 2691193323Sed 2692193323Sed // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) 2693193323Sed // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc) 2694193323Sed // Pattern complexity = 6 cost = 1 size = 0 2695193323Sed 2696195340Sed // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) 2697195340Sed // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc) 2698195340Sed // Pattern complexity = 6 cost = 1 size = 0 2699195340Sed 2700198090Srdivacky unsigned Opc = Subtarget->isThumb() ? 2701195340Sed ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc; 2702202375Srdivacky SDValue Chain = N->getOperand(0); 2703202375Srdivacky SDValue N1 = N->getOperand(1); 2704202375Srdivacky SDValue N2 = N->getOperand(2); 2705202375Srdivacky SDValue N3 = N->getOperand(3); 2706202375Srdivacky SDValue InFlag = N->getOperand(4); 2707193323Sed assert(N1.getOpcode() == ISD::BasicBlock); 2708193323Sed assert(N2.getOpcode() == ISD::Constant); 2709193323Sed assert(N3.getOpcode() == ISD::Register); 2710193323Sed 2711193323Sed SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) 2712193323Sed cast<ConstantSDNode>(N2)->getZExtValue()), 2713193323Sed MVT::i32); 2714193323Sed SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag }; 2715198090Srdivacky SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other, 2716218893Sdim MVT::Glue, Ops, 5); 2717193323Sed Chain = SDValue(ResNode, 0); 2718202375Srdivacky if (N->getNumValues() == 2) { 2719193323Sed InFlag = SDValue(ResNode, 1); 2720202375Srdivacky ReplaceUses(SDValue(N, 1), InFlag); 2721193323Sed } 2722202375Srdivacky ReplaceUses(SDValue(N, 0), 2723199511Srdivacky SDValue(Chain.getNode(), Chain.getResNo())); 2724193323Sed return NULL; 2725193323Sed } 2726199989Srdivacky case ARMISD::CMOV: 2727202375Srdivacky return SelectCMOVOp(N); 2728198090Srdivacky case ARMISD::VZIP: { 2729198090Srdivacky unsigned Opc = 0; 2730198090Srdivacky EVT VT = N->getValueType(0); 2731198090Srdivacky switch (VT.getSimpleVT().SimpleTy) { 2732198090Srdivacky default: return NULL; 2733198090Srdivacky case MVT::v8i8: Opc = ARM::VZIPd8; break; 2734198090Srdivacky case MVT::v4i16: Opc = ARM::VZIPd16; break; 2735198090Srdivacky case MVT::v2f32: 2736234353Sdim // vzip.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm. 2737234353Sdim case MVT::v2i32: Opc = ARM::VTRNd32; break; 2738198090Srdivacky case MVT::v16i8: Opc = ARM::VZIPq8; break; 2739198090Srdivacky case MVT::v8i16: Opc = ARM::VZIPq16; break; 2740198090Srdivacky case MVT::v4f32: 2741198090Srdivacky case MVT::v4i32: Opc = ARM::VZIPq32; break; 2742193323Sed } 2743207618Srdivacky SDValue Pred = getAL(CurDAG); 2744199989Srdivacky SDValue PredReg = CurDAG->getRegister(0, MVT::i32); 2745199989Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg }; 2746199989Srdivacky return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4); 2747198090Srdivacky } 2748198090Srdivacky case ARMISD::VUZP: { 2749198090Srdivacky unsigned Opc = 0; 2750198090Srdivacky EVT VT = N->getValueType(0); 2751198090Srdivacky switch (VT.getSimpleVT().SimpleTy) { 2752198090Srdivacky default: return NULL; 2753198090Srdivacky case MVT::v8i8: Opc = ARM::VUZPd8; break; 2754198090Srdivacky case MVT::v4i16: Opc = ARM::VUZPd16; break; 2755198090Srdivacky case MVT::v2f32: 2756234353Sdim // vuzp.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm. 2757234353Sdim case MVT::v2i32: Opc = ARM::VTRNd32; break; 2758198090Srdivacky case MVT::v16i8: Opc = ARM::VUZPq8; break; 2759198090Srdivacky case MVT::v8i16: Opc = ARM::VUZPq16; break; 2760198090Srdivacky case MVT::v4f32: 2761198090Srdivacky case MVT::v4i32: Opc = ARM::VUZPq32; break; 2762193323Sed } 2763207618Srdivacky SDValue Pred = getAL(CurDAG); 2764199989Srdivacky SDValue PredReg = CurDAG->getRegister(0, MVT::i32); 2765199989Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg }; 2766199989Srdivacky return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4); 2767198090Srdivacky } 2768198090Srdivacky case ARMISD::VTRN: { 2769198090Srdivacky unsigned Opc = 0; 2770198090Srdivacky EVT VT = N->getValueType(0); 2771198090Srdivacky switch (VT.getSimpleVT().SimpleTy) { 2772198090Srdivacky default: return NULL; 2773198090Srdivacky case MVT::v8i8: Opc = ARM::VTRNd8; break; 2774198090Srdivacky case MVT::v4i16: Opc = ARM::VTRNd16; break; 2775198090Srdivacky case MVT::v2f32: 2776198090Srdivacky case MVT::v2i32: Opc = ARM::VTRNd32; break; 2777198090Srdivacky case MVT::v16i8: Opc = ARM::VTRNq8; break; 2778198090Srdivacky case MVT::v8i16: Opc = ARM::VTRNq16; break; 2779198090Srdivacky case MVT::v4f32: 2780198090Srdivacky case MVT::v4i32: Opc = ARM::VTRNq32; break; 2781193323Sed } 2782207618Srdivacky SDValue Pred = getAL(CurDAG); 2783199989Srdivacky SDValue PredReg = CurDAG->getRegister(0, MVT::i32); 2784199989Srdivacky SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg }; 2785199989Srdivacky return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4); 2786193323Sed } 2787210299Sed case ARMISD::BUILD_VECTOR: { 2788210299Sed EVT VecVT = N->getValueType(0); 2789210299Sed EVT EltVT = VecVT.getVectorElementType(); 2790210299Sed unsigned NumElts = VecVT.getVectorNumElements(); 2791218893Sdim if (EltVT == MVT::f64) { 2792210299Sed assert(NumElts == 2 && "unexpected type for BUILD_VECTOR"); 2793210299Sed return PairDRegs(VecVT, N->getOperand(0), N->getOperand(1)); 2794210299Sed } 2795218893Sdim assert(EltVT == MVT::f32 && "unexpected type for BUILD_VECTOR"); 2796210299Sed if (NumElts == 2) 2797210299Sed return PairSRegs(VecVT, N->getOperand(0), N->getOperand(1)); 2798210299Sed assert(NumElts == 4 && "unexpected type for BUILD_VECTOR"); 2799210299Sed return QuadSRegs(VecVT, N->getOperand(0), N->getOperand(1), 2800210299Sed N->getOperand(2), N->getOperand(3)); 2801210299Sed } 2802194710Sed 2803218893Sdim case ARMISD::VLD2DUP: { 2804239462Sdim static const uint16_t Opcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16, 2805239462Sdim ARM::VLD2DUPd32 }; 2806218893Sdim return SelectVLDDup(N, false, 2, Opcodes); 2807218893Sdim } 2808218893Sdim 2809218893Sdim case ARMISD::VLD3DUP: { 2810239462Sdim static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo, 2811239462Sdim ARM::VLD3DUPd16Pseudo, 2812239462Sdim ARM::VLD3DUPd32Pseudo }; 2813218893Sdim return SelectVLDDup(N, false, 3, Opcodes); 2814218893Sdim } 2815218893Sdim 2816218893Sdim case ARMISD::VLD4DUP: { 2817239462Sdim static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo, 2818239462Sdim ARM::VLD4DUPd16Pseudo, 2819239462Sdim ARM::VLD4DUPd32Pseudo }; 2820218893Sdim return SelectVLDDup(N, false, 4, Opcodes); 2821218893Sdim } 2822218893Sdim 2823218893Sdim case ARMISD::VLD2DUP_UPD: { 2824239462Sdim static const uint16_t Opcodes[] = { ARM::VLD2DUPd8wb_fixed, 2825239462Sdim ARM::VLD2DUPd16wb_fixed, 2826239462Sdim ARM::VLD2DUPd32wb_fixed }; 2827218893Sdim return SelectVLDDup(N, true, 2, Opcodes); 2828218893Sdim } 2829218893Sdim 2830218893Sdim case ARMISD::VLD3DUP_UPD: { 2831239462Sdim static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo_UPD, 2832239462Sdim ARM::VLD3DUPd16Pseudo_UPD, 2833239462Sdim ARM::VLD3DUPd32Pseudo_UPD }; 2834218893Sdim return SelectVLDDup(N, true, 3, Opcodes); 2835218893Sdim } 2836218893Sdim 2837218893Sdim case ARMISD::VLD4DUP_UPD: { 2838239462Sdim static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo_UPD, 2839239462Sdim ARM::VLD4DUPd16Pseudo_UPD, 2840239462Sdim ARM::VLD4DUPd32Pseudo_UPD }; 2841218893Sdim return SelectVLDDup(N, true, 4, Opcodes); 2842218893Sdim } 2843218893Sdim 2844218893Sdim case ARMISD::VLD1_UPD: { 2845239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD1d8wb_fixed, 2846239462Sdim ARM::VLD1d16wb_fixed, 2847239462Sdim ARM::VLD1d32wb_fixed, 2848239462Sdim ARM::VLD1d64wb_fixed }; 2849239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD1q8wb_fixed, 2850239462Sdim ARM::VLD1q16wb_fixed, 2851239462Sdim ARM::VLD1q32wb_fixed, 2852239462Sdim ARM::VLD1q64wb_fixed }; 2853218893Sdim return SelectVLD(N, true, 1, DOpcodes, QOpcodes, 0); 2854218893Sdim } 2855218893Sdim 2856218893Sdim case ARMISD::VLD2_UPD: { 2857239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD2d8wb_fixed, 2858239462Sdim ARM::VLD2d16wb_fixed, 2859239462Sdim ARM::VLD2d32wb_fixed, 2860239462Sdim ARM::VLD1q64wb_fixed}; 2861239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD2q8PseudoWB_fixed, 2862239462Sdim ARM::VLD2q16PseudoWB_fixed, 2863239462Sdim ARM::VLD2q32PseudoWB_fixed }; 2864218893Sdim return SelectVLD(N, true, 2, DOpcodes, QOpcodes, 0); 2865218893Sdim } 2866218893Sdim 2867218893Sdim case ARMISD::VLD3_UPD: { 2868239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo_UPD, 2869239462Sdim ARM::VLD3d16Pseudo_UPD, 2870239462Sdim ARM::VLD3d32Pseudo_UPD, 2871239462Sdim ARM::VLD1q64wb_fixed}; 2872239462Sdim static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD, 2873239462Sdim ARM::VLD3q16Pseudo_UPD, 2874239462Sdim ARM::VLD3q32Pseudo_UPD }; 2875239462Sdim static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD, 2876239462Sdim ARM::VLD3q16oddPseudo_UPD, 2877239462Sdim ARM::VLD3q32oddPseudo_UPD }; 2878218893Sdim return SelectVLD(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1); 2879218893Sdim } 2880218893Sdim 2881218893Sdim case ARMISD::VLD4_UPD: { 2882239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo_UPD, 2883239462Sdim ARM::VLD4d16Pseudo_UPD, 2884239462Sdim ARM::VLD4d32Pseudo_UPD, 2885239462Sdim ARM::VLD1q64wb_fixed}; 2886239462Sdim static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD, 2887239462Sdim ARM::VLD4q16Pseudo_UPD, 2888239462Sdim ARM::VLD4q32Pseudo_UPD }; 2889239462Sdim static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD, 2890239462Sdim ARM::VLD4q16oddPseudo_UPD, 2891239462Sdim ARM::VLD4q32oddPseudo_UPD }; 2892218893Sdim return SelectVLD(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1); 2893218893Sdim } 2894218893Sdim 2895218893Sdim case ARMISD::VLD2LN_UPD: { 2896239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo_UPD, 2897239462Sdim ARM::VLD2LNd16Pseudo_UPD, 2898239462Sdim ARM::VLD2LNd32Pseudo_UPD }; 2899239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo_UPD, 2900239462Sdim ARM::VLD2LNq32Pseudo_UPD }; 2901218893Sdim return SelectVLDSTLane(N, true, true, 2, DOpcodes, QOpcodes); 2902218893Sdim } 2903218893Sdim 2904218893Sdim case ARMISD::VLD3LN_UPD: { 2905239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo_UPD, 2906239462Sdim ARM::VLD3LNd16Pseudo_UPD, 2907239462Sdim ARM::VLD3LNd32Pseudo_UPD }; 2908239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo_UPD, 2909239462Sdim ARM::VLD3LNq32Pseudo_UPD }; 2910218893Sdim return SelectVLDSTLane(N, true, true, 3, DOpcodes, QOpcodes); 2911218893Sdim } 2912218893Sdim 2913218893Sdim case ARMISD::VLD4LN_UPD: { 2914239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo_UPD, 2915239462Sdim ARM::VLD4LNd16Pseudo_UPD, 2916239462Sdim ARM::VLD4LNd32Pseudo_UPD }; 2917239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo_UPD, 2918239462Sdim ARM::VLD4LNq32Pseudo_UPD }; 2919218893Sdim return SelectVLDSTLane(N, true, true, 4, DOpcodes, QOpcodes); 2920218893Sdim } 2921218893Sdim 2922218893Sdim case ARMISD::VST1_UPD: { 2923239462Sdim static const uint16_t DOpcodes[] = { ARM::VST1d8wb_fixed, 2924239462Sdim ARM::VST1d16wb_fixed, 2925239462Sdim ARM::VST1d32wb_fixed, 2926239462Sdim ARM::VST1d64wb_fixed }; 2927239462Sdim static const uint16_t QOpcodes[] = { ARM::VST1q8wb_fixed, 2928239462Sdim ARM::VST1q16wb_fixed, 2929239462Sdim ARM::VST1q32wb_fixed, 2930239462Sdim ARM::VST1q64wb_fixed }; 2931218893Sdim return SelectVST(N, true, 1, DOpcodes, QOpcodes, 0); 2932218893Sdim } 2933218893Sdim 2934218893Sdim case ARMISD::VST2_UPD: { 2935239462Sdim static const uint16_t DOpcodes[] = { ARM::VST2d8wb_fixed, 2936239462Sdim ARM::VST2d16wb_fixed, 2937239462Sdim ARM::VST2d32wb_fixed, 2938239462Sdim ARM::VST1q64wb_fixed}; 2939239462Sdim static const uint16_t QOpcodes[] = { ARM::VST2q8PseudoWB_fixed, 2940239462Sdim ARM::VST2q16PseudoWB_fixed, 2941239462Sdim ARM::VST2q32PseudoWB_fixed }; 2942218893Sdim return SelectVST(N, true, 2, DOpcodes, QOpcodes, 0); 2943218893Sdim } 2944218893Sdim 2945218893Sdim case ARMISD::VST3_UPD: { 2946239462Sdim static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo_UPD, 2947239462Sdim ARM::VST3d16Pseudo_UPD, 2948239462Sdim ARM::VST3d32Pseudo_UPD, 2949239462Sdim ARM::VST1d64TPseudoWB_fixed}; 2950239462Sdim static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD, 2951239462Sdim ARM::VST3q16Pseudo_UPD, 2952239462Sdim ARM::VST3q32Pseudo_UPD }; 2953239462Sdim static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD, 2954239462Sdim ARM::VST3q16oddPseudo_UPD, 2955239462Sdim ARM::VST3q32oddPseudo_UPD }; 2956218893Sdim return SelectVST(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1); 2957218893Sdim } 2958218893Sdim 2959218893Sdim case ARMISD::VST4_UPD: { 2960239462Sdim static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo_UPD, 2961239462Sdim ARM::VST4d16Pseudo_UPD, 2962239462Sdim ARM::VST4d32Pseudo_UPD, 2963239462Sdim ARM::VST1d64QPseudoWB_fixed}; 2964239462Sdim static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD, 2965239462Sdim ARM::VST4q16Pseudo_UPD, 2966239462Sdim ARM::VST4q32Pseudo_UPD }; 2967239462Sdim static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD, 2968239462Sdim ARM::VST4q16oddPseudo_UPD, 2969239462Sdim ARM::VST4q32oddPseudo_UPD }; 2970218893Sdim return SelectVST(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1); 2971218893Sdim } 2972218893Sdim 2973218893Sdim case ARMISD::VST2LN_UPD: { 2974239462Sdim static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo_UPD, 2975239462Sdim ARM::VST2LNd16Pseudo_UPD, 2976239462Sdim ARM::VST2LNd32Pseudo_UPD }; 2977239462Sdim static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo_UPD, 2978239462Sdim ARM::VST2LNq32Pseudo_UPD }; 2979218893Sdim return SelectVLDSTLane(N, false, true, 2, DOpcodes, QOpcodes); 2980218893Sdim } 2981218893Sdim 2982218893Sdim case ARMISD::VST3LN_UPD: { 2983239462Sdim static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo_UPD, 2984239462Sdim ARM::VST3LNd16Pseudo_UPD, 2985239462Sdim ARM::VST3LNd32Pseudo_UPD }; 2986239462Sdim static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo_UPD, 2987239462Sdim ARM::VST3LNq32Pseudo_UPD }; 2988218893Sdim return SelectVLDSTLane(N, false, true, 3, DOpcodes, QOpcodes); 2989218893Sdim } 2990218893Sdim 2991218893Sdim case ARMISD::VST4LN_UPD: { 2992239462Sdim static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo_UPD, 2993239462Sdim ARM::VST4LNd16Pseudo_UPD, 2994239462Sdim ARM::VST4LNd32Pseudo_UPD }; 2995239462Sdim static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo_UPD, 2996239462Sdim ARM::VST4LNq32Pseudo_UPD }; 2997218893Sdim return SelectVLDSTLane(N, false, true, 4, DOpcodes, QOpcodes); 2998218893Sdim } 2999218893Sdim 3000198090Srdivacky case ISD::INTRINSIC_VOID: 3001198090Srdivacky case ISD::INTRINSIC_W_CHAIN: { 3002198090Srdivacky unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); 3003198090Srdivacky switch (IntNo) { 3004198090Srdivacky default: 3005198090Srdivacky break; 3006194710Sed 3007223017Sdim case Intrinsic::arm_ldrexd: { 3008223017Sdim SDValue MemAddr = N->getOperand(2); 3009223017Sdim DebugLoc dl = N->getDebugLoc(); 3010223017Sdim SDValue Chain = N->getOperand(0); 3011223017Sdim 3012223017Sdim unsigned NewOpc = ARM::LDREXD; 3013223017Sdim if (Subtarget->isThumb() && Subtarget->hasThumb2()) 3014223017Sdim NewOpc = ARM::t2LDREXD; 3015223017Sdim 3016223017Sdim // arm_ldrexd returns a i64 value in {i32, i32} 3017223017Sdim std::vector<EVT> ResTys; 3018223017Sdim ResTys.push_back(MVT::i32); 3019223017Sdim ResTys.push_back(MVT::i32); 3020223017Sdim ResTys.push_back(MVT::Other); 3021223017Sdim 3022223017Sdim // place arguments in the right order 3023223017Sdim SmallVector<SDValue, 7> Ops; 3024223017Sdim Ops.push_back(MemAddr); 3025223017Sdim Ops.push_back(getAL(CurDAG)); 3026223017Sdim Ops.push_back(CurDAG->getRegister(0, MVT::i32)); 3027223017Sdim Ops.push_back(Chain); 3028223017Sdim SDNode *Ld = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops.data(), 3029223017Sdim Ops.size()); 3030223017Sdim // Transfer memoperands. 3031223017Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 3032223017Sdim MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 3033223017Sdim cast<MachineSDNode>(Ld)->setMemRefs(MemOp, MemOp + 1); 3034223017Sdim 3035223017Sdim // Until there's support for specifing explicit register constraints 3036223017Sdim // like the use of even/odd register pair, hardcode ldrexd to always 3037223017Sdim // use the pair [R0, R1] to hold the load result. 3038223017Sdim Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R0, 3039223017Sdim SDValue(Ld, 0), SDValue(0,0)); 3040223017Sdim Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R1, 3041223017Sdim SDValue(Ld, 1), Chain.getValue(1)); 3042223017Sdim 3043223017Sdim // Remap uses. 3044223017Sdim SDValue Glue = Chain.getValue(1); 3045223017Sdim if (!SDValue(N, 0).use_empty()) { 3046223017Sdim SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, 3047223017Sdim ARM::R0, MVT::i32, Glue); 3048223017Sdim Glue = Result.getValue(2); 3049223017Sdim ReplaceUses(SDValue(N, 0), Result); 3050223017Sdim } 3051223017Sdim if (!SDValue(N, 1).use_empty()) { 3052223017Sdim SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, 3053223017Sdim ARM::R1, MVT::i32, Glue); 3054223017Sdim Glue = Result.getValue(2); 3055223017Sdim ReplaceUses(SDValue(N, 1), Result); 3056223017Sdim } 3057223017Sdim 3058223017Sdim ReplaceUses(SDValue(N, 2), SDValue(Ld, 2)); 3059223017Sdim return NULL; 3060223017Sdim } 3061223017Sdim 3062223017Sdim case Intrinsic::arm_strexd: { 3063223017Sdim DebugLoc dl = N->getDebugLoc(); 3064223017Sdim SDValue Chain = N->getOperand(0); 3065223017Sdim SDValue Val0 = N->getOperand(2); 3066223017Sdim SDValue Val1 = N->getOperand(3); 3067223017Sdim SDValue MemAddr = N->getOperand(4); 3068223017Sdim 3069223017Sdim // Until there's support for specifing explicit register constraints 3070223017Sdim // like the use of even/odd register pair, hardcode strexd to always 3071223017Sdim // use the pair [R2, R3] to hold the i64 (i32, i32) value to be stored. 3072223017Sdim Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R2, Val0, 3073223017Sdim SDValue(0, 0)); 3074223017Sdim Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R3, Val1, Chain.getValue(1)); 3075223017Sdim 3076223017Sdim SDValue Glue = Chain.getValue(1); 3077223017Sdim Val0 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, 3078223017Sdim ARM::R2, MVT::i32, Glue); 3079223017Sdim Glue = Val0.getValue(1); 3080223017Sdim Val1 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, 3081223017Sdim ARM::R3, MVT::i32, Glue); 3082223017Sdim 3083223017Sdim // Store exclusive double return a i32 value which is the return status 3084223017Sdim // of the issued store. 3085223017Sdim std::vector<EVT> ResTys; 3086223017Sdim ResTys.push_back(MVT::i32); 3087223017Sdim ResTys.push_back(MVT::Other); 3088223017Sdim 3089223017Sdim // place arguments in the right order 3090223017Sdim SmallVector<SDValue, 7> Ops; 3091223017Sdim Ops.push_back(Val0); 3092223017Sdim Ops.push_back(Val1); 3093223017Sdim Ops.push_back(MemAddr); 3094223017Sdim Ops.push_back(getAL(CurDAG)); 3095223017Sdim Ops.push_back(CurDAG->getRegister(0, MVT::i32)); 3096223017Sdim Ops.push_back(Chain); 3097223017Sdim 3098223017Sdim unsigned NewOpc = ARM::STREXD; 3099223017Sdim if (Subtarget->isThumb() && Subtarget->hasThumb2()) 3100223017Sdim NewOpc = ARM::t2STREXD; 3101223017Sdim 3102223017Sdim SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops.data(), 3103223017Sdim Ops.size()); 3104223017Sdim // Transfer memoperands. 3105223017Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 3106223017Sdim MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand(); 3107223017Sdim cast<MachineSDNode>(St)->setMemRefs(MemOp, MemOp + 1); 3108223017Sdim 3109223017Sdim return St; 3110223017Sdim } 3111223017Sdim 3112206083Srdivacky case Intrinsic::arm_neon_vld1: { 3113239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16, 3114239462Sdim ARM::VLD1d32, ARM::VLD1d64 }; 3115239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16, 3116239462Sdim ARM::VLD1q32, ARM::VLD1q64}; 3117218893Sdim return SelectVLD(N, false, 1, DOpcodes, QOpcodes, 0); 3118206083Srdivacky } 3119206083Srdivacky 3120198090Srdivacky case Intrinsic::arm_neon_vld2: { 3121239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16, 3122239462Sdim ARM::VLD2d32, ARM::VLD1q64 }; 3123239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo, 3124239462Sdim ARM::VLD2q32Pseudo }; 3125218893Sdim return SelectVLD(N, false, 2, DOpcodes, QOpcodes, 0); 3126198090Srdivacky } 3127194710Sed 3128198090Srdivacky case Intrinsic::arm_neon_vld3: { 3129239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo, 3130239462Sdim ARM::VLD3d16Pseudo, 3131239462Sdim ARM::VLD3d32Pseudo, 3132239462Sdim ARM::VLD1d64TPseudo }; 3133239462Sdim static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD, 3134239462Sdim ARM::VLD3q16Pseudo_UPD, 3135239462Sdim ARM::VLD3q32Pseudo_UPD }; 3136239462Sdim static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo, 3137239462Sdim ARM::VLD3q16oddPseudo, 3138239462Sdim ARM::VLD3q32oddPseudo }; 3139218893Sdim return SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1); 3140198090Srdivacky } 3141198090Srdivacky 3142198090Srdivacky case Intrinsic::arm_neon_vld4: { 3143239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo, 3144239462Sdim ARM::VLD4d16Pseudo, 3145239462Sdim ARM::VLD4d32Pseudo, 3146239462Sdim ARM::VLD1d64QPseudo }; 3147239462Sdim static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD, 3148239462Sdim ARM::VLD4q16Pseudo_UPD, 3149239462Sdim ARM::VLD4q32Pseudo_UPD }; 3150239462Sdim static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo, 3151239462Sdim ARM::VLD4q16oddPseudo, 3152239462Sdim ARM::VLD4q32oddPseudo }; 3153218893Sdim return SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1); 3154198090Srdivacky } 3155198090Srdivacky 3156198090Srdivacky case Intrinsic::arm_neon_vld2lane: { 3157239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo, 3158239462Sdim ARM::VLD2LNd16Pseudo, 3159239462Sdim ARM::VLD2LNd32Pseudo }; 3160239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo, 3161239462Sdim ARM::VLD2LNq32Pseudo }; 3162218893Sdim return SelectVLDSTLane(N, true, false, 2, DOpcodes, QOpcodes); 3163198090Srdivacky } 3164198090Srdivacky 3165198090Srdivacky case Intrinsic::arm_neon_vld3lane: { 3166239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo, 3167239462Sdim ARM::VLD3LNd16Pseudo, 3168239462Sdim ARM::VLD3LNd32Pseudo }; 3169239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo, 3170239462Sdim ARM::VLD3LNq32Pseudo }; 3171218893Sdim return SelectVLDSTLane(N, true, false, 3, DOpcodes, QOpcodes); 3172198090Srdivacky } 3173198090Srdivacky 3174198090Srdivacky case Intrinsic::arm_neon_vld4lane: { 3175239462Sdim static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo, 3176239462Sdim ARM::VLD4LNd16Pseudo, 3177239462Sdim ARM::VLD4LNd32Pseudo }; 3178239462Sdim static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo, 3179239462Sdim ARM::VLD4LNq32Pseudo }; 3180218893Sdim return SelectVLDSTLane(N, true, false, 4, DOpcodes, QOpcodes); 3181198090Srdivacky } 3182198090Srdivacky 3183206083Srdivacky case Intrinsic::arm_neon_vst1: { 3184239462Sdim static const uint16_t DOpcodes[] = { ARM::VST1d8, ARM::VST1d16, 3185239462Sdim ARM::VST1d32, ARM::VST1d64 }; 3186239462Sdim static const uint16_t QOpcodes[] = { ARM::VST1q8, ARM::VST1q16, 3187239462Sdim ARM::VST1q32, ARM::VST1q64 }; 3188218893Sdim return SelectVST(N, false, 1, DOpcodes, QOpcodes, 0); 3189206083Srdivacky } 3190206083Srdivacky 3191198090Srdivacky case Intrinsic::arm_neon_vst2: { 3192239462Sdim static const uint16_t DOpcodes[] = { ARM::VST2d8, ARM::VST2d16, 3193239462Sdim ARM::VST2d32, ARM::VST1q64 }; 3194239462Sdim static uint16_t QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo, 3195239462Sdim ARM::VST2q32Pseudo }; 3196218893Sdim return SelectVST(N, false, 2, DOpcodes, QOpcodes, 0); 3197198090Srdivacky } 3198194710Sed 3199198090Srdivacky case Intrinsic::arm_neon_vst3: { 3200239462Sdim static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo, 3201239462Sdim ARM::VST3d16Pseudo, 3202239462Sdim ARM::VST3d32Pseudo, 3203239462Sdim ARM::VST1d64TPseudo }; 3204239462Sdim static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD, 3205239462Sdim ARM::VST3q16Pseudo_UPD, 3206239462Sdim ARM::VST3q32Pseudo_UPD }; 3207239462Sdim static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo, 3208239462Sdim ARM::VST3q16oddPseudo, 3209239462Sdim ARM::VST3q32oddPseudo }; 3210218893Sdim return SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1); 3211194710Sed } 3212194710Sed 3213198090Srdivacky case Intrinsic::arm_neon_vst4: { 3214239462Sdim static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo, 3215239462Sdim ARM::VST4d16Pseudo, 3216239462Sdim ARM::VST4d32Pseudo, 3217239462Sdim ARM::VST1d64QPseudo }; 3218239462Sdim static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD, 3219239462Sdim ARM::VST4q16Pseudo_UPD, 3220239462Sdim ARM::VST4q32Pseudo_UPD }; 3221239462Sdim static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo, 3222239462Sdim ARM::VST4q16oddPseudo, 3223239462Sdim ARM::VST4q32oddPseudo }; 3224218893Sdim return SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1); 3225198090Srdivacky } 3226198090Srdivacky 3227198090Srdivacky case Intrinsic::arm_neon_vst2lane: { 3228239462Sdim static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo, 3229239462Sdim ARM::VST2LNd16Pseudo, 3230239462Sdim ARM::VST2LNd32Pseudo }; 3231239462Sdim static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo, 3232239462Sdim ARM::VST2LNq32Pseudo }; 3233218893Sdim return SelectVLDSTLane(N, false, false, 2, DOpcodes, QOpcodes); 3234198090Srdivacky } 3235198090Srdivacky 3236198090Srdivacky case Intrinsic::arm_neon_vst3lane: { 3237239462Sdim static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo, 3238239462Sdim ARM::VST3LNd16Pseudo, 3239239462Sdim ARM::VST3LNd32Pseudo }; 3240239462Sdim static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo, 3241239462Sdim ARM::VST3LNq32Pseudo }; 3242218893Sdim return SelectVLDSTLane(N, false, false, 3, DOpcodes, QOpcodes); 3243198090Srdivacky } 3244198090Srdivacky 3245198090Srdivacky case Intrinsic::arm_neon_vst4lane: { 3246239462Sdim static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo, 3247239462Sdim ARM::VST4LNd16Pseudo, 3248239462Sdim ARM::VST4LNd32Pseudo }; 3249239462Sdim static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo, 3250239462Sdim ARM::VST4LNq32Pseudo }; 3251218893Sdim return SelectVLDSTLane(N, false, false, 4, DOpcodes, QOpcodes); 3252198090Srdivacky } 3253198090Srdivacky } 3254208599Srdivacky break; 3255194710Sed } 3256208599Srdivacky 3257210299Sed case ISD::INTRINSIC_WO_CHAIN: { 3258210299Sed unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue(); 3259210299Sed switch (IntNo) { 3260210299Sed default: 3261210299Sed break; 3262210299Sed 3263210299Sed case Intrinsic::arm_neon_vtbl2: 3264234353Sdim return SelectVTBL(N, false, 2, ARM::VTBL2); 3265210299Sed case Intrinsic::arm_neon_vtbl3: 3266218893Sdim return SelectVTBL(N, false, 3, ARM::VTBL3Pseudo); 3267210299Sed case Intrinsic::arm_neon_vtbl4: 3268218893Sdim return SelectVTBL(N, false, 4, ARM::VTBL4Pseudo); 3269210299Sed 3270210299Sed case Intrinsic::arm_neon_vtbx2: 3271234353Sdim return SelectVTBL(N, true, 2, ARM::VTBX2); 3272210299Sed case Intrinsic::arm_neon_vtbx3: 3273218893Sdim return SelectVTBL(N, true, 3, ARM::VTBX3Pseudo); 3274210299Sed case Intrinsic::arm_neon_vtbx4: 3275218893Sdim return SelectVTBL(N, true, 4, ARM::VTBX4Pseudo); 3276210299Sed } 3277210299Sed break; 3278210299Sed } 3279210299Sed 3280221345Sdim case ARMISD::VTBL1: { 3281221345Sdim DebugLoc dl = N->getDebugLoc(); 3282221345Sdim EVT VT = N->getValueType(0); 3283221345Sdim SmallVector<SDValue, 6> Ops; 3284221345Sdim 3285221345Sdim Ops.push_back(N->getOperand(0)); 3286221345Sdim Ops.push_back(N->getOperand(1)); 3287221345Sdim Ops.push_back(getAL(CurDAG)); // Predicate 3288221345Sdim Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // Predicate Register 3289221345Sdim return CurDAG->getMachineNode(ARM::VTBL1, dl, VT, Ops.data(), Ops.size()); 3290221345Sdim } 3291221345Sdim case ARMISD::VTBL2: { 3292221345Sdim DebugLoc dl = N->getDebugLoc(); 3293221345Sdim EVT VT = N->getValueType(0); 3294221345Sdim 3295221345Sdim // Form a REG_SEQUENCE to force register allocation. 3296221345Sdim SDValue V0 = N->getOperand(0); 3297221345Sdim SDValue V1 = N->getOperand(1); 3298221345Sdim SDValue RegSeq = SDValue(PairDRegs(MVT::v16i8, V0, V1), 0); 3299221345Sdim 3300221345Sdim SmallVector<SDValue, 6> Ops; 3301221345Sdim Ops.push_back(RegSeq); 3302221345Sdim Ops.push_back(N->getOperand(2)); 3303221345Sdim Ops.push_back(getAL(CurDAG)); // Predicate 3304221345Sdim Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // Predicate Register 3305234353Sdim return CurDAG->getMachineNode(ARM::VTBL2, dl, VT, 3306221345Sdim Ops.data(), Ops.size()); 3307221345Sdim } 3308221345Sdim 3309208599Srdivacky case ISD::CONCAT_VECTORS: 3310208599Srdivacky return SelectConcatVector(N); 3311226633Sdim 3312226633Sdim case ARMISD::ATOMOR64_DAG: 3313226633Sdim return SelectAtomic64(N, ARM::ATOMOR6432); 3314226633Sdim case ARMISD::ATOMXOR64_DAG: 3315226633Sdim return SelectAtomic64(N, ARM::ATOMXOR6432); 3316226633Sdim case ARMISD::ATOMADD64_DAG: 3317226633Sdim return SelectAtomic64(N, ARM::ATOMADD6432); 3318226633Sdim case ARMISD::ATOMSUB64_DAG: 3319226633Sdim return SelectAtomic64(N, ARM::ATOMSUB6432); 3320226633Sdim case ARMISD::ATOMNAND64_DAG: 3321226633Sdim return SelectAtomic64(N, ARM::ATOMNAND6432); 3322226633Sdim case ARMISD::ATOMAND64_DAG: 3323226633Sdim return SelectAtomic64(N, ARM::ATOMAND6432); 3324226633Sdim case ARMISD::ATOMSWAP64_DAG: 3325226633Sdim return SelectAtomic64(N, ARM::ATOMSWAP6432); 3326226633Sdim case ARMISD::ATOMCMPXCHG64_DAG: 3327226633Sdim return SelectAtomic64(N, ARM::ATOMCMPXCHG6432); 3328194710Sed } 3329194710Sed 3330202375Srdivacky return SelectCode(N); 3331193323Sed} 3332193323Sed 3333193323Sedbool ARMDAGToDAGISel:: 3334193323SedSelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, 3335193323Sed std::vector<SDValue> &OutOps) { 3336193323Sed assert(ConstraintCode == 'm' && "unexpected asm memory constraint"); 3337198090Srdivacky // Require the address to be in a register. That is safe for all ARM 3338198090Srdivacky // variants and it is hard to do anything much smarter without knowing 3339198090Srdivacky // how the operand is used. 3340198090Srdivacky OutOps.push_back(Op); 3341193323Sed return false; 3342193323Sed} 3343193323Sed 3344193323Sed/// createARMISelDag - This pass converts a legalized DAG into a 3345193323Sed/// ARM-specific DAG, ready for instruction scheduling. 3346193323Sed/// 3347198090SrdivackyFunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM, 3348198090Srdivacky CodeGenOpt::Level OptLevel) { 3349198090Srdivacky return new ARMDAGToDAGISel(TM, OptLevel); 3350193323Sed} 3351