1234285Sdim//===-- HexagonISelDAGToDAG.cpp - A dag to dag inst selector for Hexagon --===// 2234285Sdim// 3234285Sdim// The LLVM Compiler Infrastructure 4234285Sdim// 5234285Sdim// This file is distributed under the University of Illinois Open Source 6234285Sdim// License. See LICENSE.TXT for details. 7234285Sdim// 8234285Sdim//===----------------------------------------------------------------------===// 9234285Sdim// 10234285Sdim// This file defines an instruction selector for the Hexagon target. 11234285Sdim// 12234285Sdim//===----------------------------------------------------------------------===// 13234285Sdim 14234285Sdim#define DEBUG_TYPE "hexagon-isel" 15252723Sdim#include "Hexagon.h" 16234285Sdim#include "HexagonISelLowering.h" 17234285Sdim#include "HexagonTargetMachine.h" 18252723Sdim#include "llvm/ADT/DenseMap.h" 19252723Sdim#include "llvm/IR/Intrinsics.h" 20234285Sdim#include "llvm/CodeGen/SelectionDAGISel.h" 21252723Sdim#include "llvm/Support/CommandLine.h" 22234285Sdim#include "llvm/Support/Compiler.h" 23234285Sdim#include "llvm/Support/Debug.h" 24234285Sdimusing namespace llvm; 25234285Sdim 26252723Sdimstatic 27252723Sdimcl::opt<unsigned> 28252723SdimMaxNumOfUsesForConstExtenders("ga-max-num-uses-for-constant-extenders", 29252723Sdim cl::Hidden, cl::init(2), 30252723Sdim cl::desc("Maximum number of uses of a global address such that we still us a" 31252723Sdim "constant extended instruction")); 32234285Sdim 33234285Sdim//===----------------------------------------------------------------------===// 34234285Sdim// Instruction Selector Implementation 35234285Sdim//===----------------------------------------------------------------------===// 36234285Sdim 37252723Sdimnamespace llvm { 38252723Sdim void initializeHexagonDAGToDAGISelPass(PassRegistry&); 39252723Sdim} 40252723Sdim 41234285Sdim//===--------------------------------------------------------------------===// 42234285Sdim/// HexagonDAGToDAGISel - Hexagon specific code to select Hexagon machine 43234285Sdim/// instructions for SelectionDAG operations. 44234285Sdim/// 45234285Sdimnamespace { 46234285Sdimclass HexagonDAGToDAGISel : public SelectionDAGISel { 47234285Sdim /// Subtarget - Keep a pointer to the Hexagon Subtarget around so that we can 48234285Sdim /// make the right decision when generating code for different targets. 49234285Sdim const HexagonSubtarget &Subtarget; 50234285Sdim 51234285Sdim // Keep a reference to HexagonTargetMachine. 52252723Sdim const HexagonTargetMachine& TM; 53252723Sdim DenseMap<const GlobalValue *, unsigned> GlobalAddressUseCountMap; 54234285Sdimpublic: 55263509Sdim explicit HexagonDAGToDAGISel(HexagonTargetMachine &targetmachine, 56252723Sdim CodeGenOpt::Level OptLevel) 57252723Sdim : SelectionDAGISel(targetmachine, OptLevel), 58234285Sdim Subtarget(targetmachine.getSubtarget<HexagonSubtarget>()), 59263509Sdim TM(targetmachine) { 60252723Sdim initializeHexagonDAGToDAGISelPass(*PassRegistry::getPassRegistry()); 61234285Sdim } 62252723Sdim bool hasNumUsesBelowThresGA(SDNode *N) const; 63234285Sdim 64234285Sdim SDNode *Select(SDNode *N); 65234285Sdim 66234285Sdim // Complex Pattern Selectors. 67252723Sdim inline bool foldGlobalAddress(SDValue &N, SDValue &R); 68252723Sdim inline bool foldGlobalAddressGP(SDValue &N, SDValue &R); 69252723Sdim bool foldGlobalAddressImpl(SDValue &N, SDValue &R, bool ShouldLookForGP); 70234285Sdim bool SelectADDRri(SDValue& N, SDValue &R1, SDValue &R2); 71234285Sdim bool SelectADDRriS11_0(SDValue& N, SDValue &R1, SDValue &R2); 72234285Sdim bool SelectADDRriS11_1(SDValue& N, SDValue &R1, SDValue &R2); 73234285Sdim bool SelectADDRriS11_2(SDValue& N, SDValue &R1, SDValue &R2); 74234285Sdim bool SelectMEMriS11_2(SDValue& Addr, SDValue &Base, SDValue &Offset); 75234285Sdim bool SelectADDRriS11_3(SDValue& N, SDValue &R1, SDValue &R2); 76234285Sdim bool SelectADDRrr(SDValue &Addr, SDValue &Base, SDValue &Offset); 77234285Sdim bool SelectADDRriU6_0(SDValue& N, SDValue &R1, SDValue &R2); 78234285Sdim bool SelectADDRriU6_1(SDValue& N, SDValue &R1, SDValue &R2); 79234285Sdim bool SelectADDRriU6_2(SDValue& N, SDValue &R1, SDValue &R2); 80234285Sdim 81234285Sdim virtual const char *getPassName() const { 82234285Sdim return "Hexagon DAG->DAG Pattern Instruction Selection"; 83234285Sdim } 84234285Sdim 85234285Sdim /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 86234285Sdim /// inline asm expressions. 87234285Sdim virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, 88234285Sdim char ConstraintCode, 89234285Sdim std::vector<SDValue> &OutOps); 90234285Sdim bool SelectAddr(SDNode *Op, SDValue Addr, SDValue &Base, SDValue &Offset); 91234285Sdim 92234285Sdim SDNode *SelectLoad(SDNode *N); 93263509Sdim SDNode *SelectBaseOffsetLoad(LoadSDNode *LD, SDLoc dl); 94263509Sdim SDNode *SelectIndexedLoad(LoadSDNode *LD, SDLoc dl); 95234285Sdim SDNode *SelectIndexedLoadZeroExtend64(LoadSDNode *LD, unsigned Opcode, 96263509Sdim SDLoc dl); 97234285Sdim SDNode *SelectIndexedLoadSignExtend64(LoadSDNode *LD, unsigned Opcode, 98263509Sdim SDLoc dl); 99263509Sdim SDNode *SelectBaseOffsetStore(StoreSDNode *ST, SDLoc dl); 100263509Sdim SDNode *SelectIndexedStore(StoreSDNode *ST, SDLoc dl); 101234285Sdim SDNode *SelectStore(SDNode *N); 102234285Sdim SDNode *SelectSHL(SDNode *N); 103234285Sdim SDNode *SelectSelect(SDNode *N); 104234285Sdim SDNode *SelectTruncate(SDNode *N); 105234285Sdim SDNode *SelectMul(SDNode *N); 106234285Sdim SDNode *SelectZeroExtend(SDNode *N); 107234285Sdim SDNode *SelectIntrinsicWOChain(SDNode *N); 108245431Sdim SDNode *SelectIntrinsicWChain(SDNode *N); 109234285Sdim SDNode *SelectConstant(SDNode *N); 110245431Sdim SDNode *SelectConstantFP(SDNode *N); 111234285Sdim SDNode *SelectAdd(SDNode *N); 112252723Sdim bool isConstExtProfitable(SDNode *N) const; 113234285Sdim 114252723Sdim// XformMskToBitPosU5Imm - Returns the bit position which 115252723Sdim// the single bit 32 bit mask represents. 116252723Sdim// Used in Clr and Set bit immediate memops. 117252723SdimSDValue XformMskToBitPosU5Imm(uint32_t Imm) { 118252723Sdim int32_t bitPos; 119252723Sdim bitPos = Log2_32(Imm); 120252723Sdim assert(bitPos >= 0 && bitPos < 32 && 121252723Sdim "Constant out of range for 32 BitPos Memops"); 122252723Sdim return CurDAG->getTargetConstant(bitPos, MVT::i32); 123252723Sdim} 124252723Sdim 125252723Sdim// XformMskToBitPosU4Imm - Returns the bit position which the single bit 16 bit 126252723Sdim// mask represents. Used in Clr and Set bit immediate memops. 127252723SdimSDValue XformMskToBitPosU4Imm(uint16_t Imm) { 128252723Sdim return XformMskToBitPosU5Imm(Imm); 129252723Sdim} 130252723Sdim 131252723Sdim// XformMskToBitPosU3Imm - Returns the bit position which the single bit 8 bit 132252723Sdim// mask represents. Used in Clr and Set bit immediate memops. 133252723SdimSDValue XformMskToBitPosU3Imm(uint8_t Imm) { 134252723Sdim return XformMskToBitPosU5Imm(Imm); 135252723Sdim} 136252723Sdim 137252723Sdim// Return true if there is exactly one bit set in V, i.e., if V is one of the 138252723Sdim// following integers: 2^0, 2^1, ..., 2^31. 139252723Sdimbool ImmIsSingleBit(uint32_t v) const { 140252723Sdim uint32_t c = CountPopulation_64(v); 141252723Sdim // Only return true if we counted 1 bit. 142252723Sdim return c == 1; 143252723Sdim} 144252723Sdim 145252723Sdim// XformM5ToU5Imm - Return a target constant with the specified value, of type 146252723Sdim// i32 where the negative literal is transformed into a positive literal for 147252723Sdim// use in -= memops. 148252723Sdiminline SDValue XformM5ToU5Imm(signed Imm) { 149252723Sdim assert( (Imm >= -31 && Imm <= -1) && "Constant out of range for Memops"); 150252723Sdim return CurDAG->getTargetConstant( - Imm, MVT::i32); 151252723Sdim} 152252723Sdim 153252723Sdim 154252723Sdim// XformU7ToU7M1Imm - Return a target constant decremented by 1, in range 155252723Sdim// [1..128], used in cmpb.gtu instructions. 156252723Sdiminline SDValue XformU7ToU7M1Imm(signed Imm) { 157252723Sdim assert((Imm >= 1 && Imm <= 128) && "Constant out of range for cmpb op"); 158252723Sdim return CurDAG->getTargetConstant(Imm - 1, MVT::i8); 159252723Sdim} 160252723Sdim 161252723Sdim// XformS8ToS8M1Imm - Return a target constant decremented by 1. 162252723Sdiminline SDValue XformSToSM1Imm(signed Imm) { 163252723Sdim return CurDAG->getTargetConstant(Imm - 1, MVT::i32); 164252723Sdim} 165252723Sdim 166252723Sdim// XformU8ToU8M1Imm - Return a target constant decremented by 1. 167252723Sdiminline SDValue XformUToUM1Imm(unsigned Imm) { 168252723Sdim assert((Imm >= 1) && "Cannot decrement unsigned int less than 1"); 169252723Sdim return CurDAG->getTargetConstant(Imm - 1, MVT::i32); 170252723Sdim} 171252723Sdim 172252723Sdim// Include the pieces autogenerated from the target description. 173234285Sdim#include "HexagonGenDAGISel.inc" 174234285Sdim}; 175234285Sdim} // end anonymous namespace 176234285Sdim 177234285Sdim 178234285Sdim/// createHexagonISelDag - This pass converts a legalized DAG into a 179234285Sdim/// Hexagon-specific DAG, ready for instruction scheduling. 180234285Sdim/// 181263509SdimFunctionPass *llvm::createHexagonISelDag(HexagonTargetMachine &TM, 182252723Sdim CodeGenOpt::Level OptLevel) { 183252723Sdim return new HexagonDAGToDAGISel(TM, OptLevel); 184234285Sdim} 185234285Sdim 186252723Sdimstatic void initializePassOnce(PassRegistry &Registry) { 187252723Sdim const char *Name = "Hexagon DAG->DAG Pattern Instruction Selection"; 188252723Sdim PassInfo *PI = new PassInfo(Name, "hexagon-isel", 189252723Sdim &SelectionDAGISel::ID, 0, false, false); 190252723Sdim Registry.registerPass(*PI, true); 191252723Sdim} 192252723Sdim 193252723Sdimvoid llvm::initializeHexagonDAGToDAGISelPass(PassRegistry &Registry) { 194252723Sdim CALL_ONCE_INITIALIZATION(initializePassOnce) 195252723Sdim} 196252723Sdim 197252723Sdim 198234285Sdimstatic bool IsS11_0_Offset(SDNode * S) { 199234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 200234285Sdim 201234285Sdim // immS16 predicate - True if the immediate fits in a 16-bit sign extended 202234285Sdim // field. 203234285Sdim int64_t v = (int64_t)N->getSExtValue(); 204234285Sdim return isInt<11>(v); 205234285Sdim} 206234285Sdim 207234285Sdim 208234285Sdimstatic bool IsS11_1_Offset(SDNode * S) { 209234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 210234285Sdim 211234285Sdim // immS16 predicate - True if the immediate fits in a 16-bit sign extended 212234285Sdim // field. 213234285Sdim int64_t v = (int64_t)N->getSExtValue(); 214234285Sdim return isShiftedInt<11,1>(v); 215234285Sdim} 216234285Sdim 217234285Sdim 218234285Sdimstatic bool IsS11_2_Offset(SDNode * S) { 219234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 220234285Sdim 221234285Sdim // immS16 predicate - True if the immediate fits in a 16-bit sign extended 222234285Sdim // field. 223234285Sdim int64_t v = (int64_t)N->getSExtValue(); 224234285Sdim return isShiftedInt<11,2>(v); 225234285Sdim} 226234285Sdim 227234285Sdim 228234285Sdimstatic bool IsS11_3_Offset(SDNode * S) { 229234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 230234285Sdim 231234285Sdim // immS16 predicate - True if the immediate fits in a 16-bit sign extended 232234285Sdim // field. 233234285Sdim int64_t v = (int64_t)N->getSExtValue(); 234234285Sdim return isShiftedInt<11,3>(v); 235234285Sdim} 236234285Sdim 237234285Sdim 238234285Sdimstatic bool IsU6_0_Offset(SDNode * S) { 239234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 240234285Sdim 241234285Sdim // u6 predicate - True if the immediate fits in a 6-bit unsigned extended 242234285Sdim // field. 243234285Sdim int64_t v = (int64_t)N->getSExtValue(); 244234285Sdim return isUInt<6>(v); 245234285Sdim} 246234285Sdim 247234285Sdim 248234285Sdimstatic bool IsU6_1_Offset(SDNode * S) { 249234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 250234285Sdim 251234285Sdim // u6 predicate - True if the immediate fits in a 6-bit unsigned extended 252234285Sdim // field. 253234285Sdim int64_t v = (int64_t)N->getSExtValue(); 254234285Sdim return isShiftedUInt<6,1>(v); 255234285Sdim} 256234285Sdim 257234285Sdim 258234285Sdimstatic bool IsU6_2_Offset(SDNode * S) { 259234285Sdim ConstantSDNode *N = cast<ConstantSDNode>(S); 260234285Sdim 261234285Sdim // u6 predicate - True if the immediate fits in a 6-bit unsigned extended 262234285Sdim // field. 263234285Sdim int64_t v = (int64_t)N->getSExtValue(); 264234285Sdim return isShiftedUInt<6,2>(v); 265234285Sdim} 266234285Sdim 267234285Sdim 268234285Sdim// Intrinsics that return a a predicate. 269234285Sdimstatic unsigned doesIntrinsicReturnPredicate(unsigned ID) 270234285Sdim{ 271234285Sdim switch (ID) { 272234285Sdim default: 273234285Sdim return 0; 274234285Sdim case Intrinsic::hexagon_C2_cmpeq: 275234285Sdim case Intrinsic::hexagon_C2_cmpgt: 276234285Sdim case Intrinsic::hexagon_C2_cmpgtu: 277234285Sdim case Intrinsic::hexagon_C2_cmpgtup: 278234285Sdim case Intrinsic::hexagon_C2_cmpgtp: 279234285Sdim case Intrinsic::hexagon_C2_cmpeqp: 280234285Sdim case Intrinsic::hexagon_C2_bitsset: 281234285Sdim case Intrinsic::hexagon_C2_bitsclr: 282234285Sdim case Intrinsic::hexagon_C2_cmpeqi: 283234285Sdim case Intrinsic::hexagon_C2_cmpgti: 284234285Sdim case Intrinsic::hexagon_C2_cmpgtui: 285234285Sdim case Intrinsic::hexagon_C2_cmpgei: 286234285Sdim case Intrinsic::hexagon_C2_cmpgeui: 287234285Sdim case Intrinsic::hexagon_C2_cmplt: 288234285Sdim case Intrinsic::hexagon_C2_cmpltu: 289234285Sdim case Intrinsic::hexagon_C2_bitsclri: 290234285Sdim case Intrinsic::hexagon_C2_and: 291234285Sdim case Intrinsic::hexagon_C2_or: 292234285Sdim case Intrinsic::hexagon_C2_xor: 293234285Sdim case Intrinsic::hexagon_C2_andn: 294234285Sdim case Intrinsic::hexagon_C2_not: 295234285Sdim case Intrinsic::hexagon_C2_orn: 296234285Sdim case Intrinsic::hexagon_C2_pxfer_map: 297234285Sdim case Intrinsic::hexagon_C2_any8: 298234285Sdim case Intrinsic::hexagon_C2_all8: 299234285Sdim case Intrinsic::hexagon_A2_vcmpbeq: 300234285Sdim case Intrinsic::hexagon_A2_vcmpbgtu: 301234285Sdim case Intrinsic::hexagon_A2_vcmpheq: 302234285Sdim case Intrinsic::hexagon_A2_vcmphgt: 303234285Sdim case Intrinsic::hexagon_A2_vcmphgtu: 304234285Sdim case Intrinsic::hexagon_A2_vcmpweq: 305234285Sdim case Intrinsic::hexagon_A2_vcmpwgt: 306234285Sdim case Intrinsic::hexagon_A2_vcmpwgtu: 307234285Sdim case Intrinsic::hexagon_C2_tfrrp: 308234285Sdim case Intrinsic::hexagon_S2_tstbit_i: 309234285Sdim case Intrinsic::hexagon_S2_tstbit_r: 310234285Sdim return 1; 311234285Sdim } 312234285Sdim} 313234285Sdim 314234285Sdim 315234285Sdim// Intrinsics that have predicate operands. 316234285Sdimstatic unsigned doesIntrinsicContainPredicate(unsigned ID) 317234285Sdim{ 318234285Sdim switch (ID) { 319234285Sdim default: 320234285Sdim return 0; 321234285Sdim case Intrinsic::hexagon_C2_tfrpr: 322234285Sdim return Hexagon::TFR_RsPd; 323234285Sdim case Intrinsic::hexagon_C2_and: 324234285Sdim return Hexagon::AND_pp; 325234285Sdim case Intrinsic::hexagon_C2_xor: 326234285Sdim return Hexagon::XOR_pp; 327234285Sdim case Intrinsic::hexagon_C2_or: 328234285Sdim return Hexagon::OR_pp; 329234285Sdim case Intrinsic::hexagon_C2_not: 330234285Sdim return Hexagon::NOT_p; 331234285Sdim case Intrinsic::hexagon_C2_any8: 332234285Sdim return Hexagon::ANY_pp; 333234285Sdim case Intrinsic::hexagon_C2_all8: 334234285Sdim return Hexagon::ALL_pp; 335234285Sdim case Intrinsic::hexagon_C2_vitpack: 336234285Sdim return Hexagon::VITPACK_pp; 337234285Sdim case Intrinsic::hexagon_C2_mask: 338234285Sdim return Hexagon::MASK_p; 339234285Sdim case Intrinsic::hexagon_C2_mux: 340234285Sdim return Hexagon::MUX_rr; 341234285Sdim 342234285Sdim // Mapping hexagon_C2_muxir to MUX_pri. This is pretty weird - but 343234285Sdim // that's how it's mapped in q6protos.h. 344234285Sdim case Intrinsic::hexagon_C2_muxir: 345234285Sdim return Hexagon::MUX_ri; 346234285Sdim 347234285Sdim // Mapping hexagon_C2_muxri to MUX_pir. This is pretty weird - but 348234285Sdim // that's how it's mapped in q6protos.h. 349234285Sdim case Intrinsic::hexagon_C2_muxri: 350234285Sdim return Hexagon::MUX_ir; 351234285Sdim 352234285Sdim case Intrinsic::hexagon_C2_muxii: 353234285Sdim return Hexagon::MUX_ii; 354234285Sdim case Intrinsic::hexagon_C2_vmux: 355234285Sdim return Hexagon::VMUX_prr64; 356234285Sdim case Intrinsic::hexagon_S2_valignrb: 357234285Sdim return Hexagon::VALIGN_rrp; 358234285Sdim case Intrinsic::hexagon_S2_vsplicerb: 359234285Sdim return Hexagon::VSPLICE_rrp; 360234285Sdim } 361234285Sdim} 362234285Sdim 363234285Sdim 364234285Sdimstatic bool OffsetFitsS11(EVT MemType, int64_t Offset) { 365234285Sdim if (MemType == MVT::i64 && isShiftedInt<11,3>(Offset)) { 366234285Sdim return true; 367234285Sdim } 368234285Sdim if (MemType == MVT::i32 && isShiftedInt<11,2>(Offset)) { 369234285Sdim return true; 370234285Sdim } 371234285Sdim if (MemType == MVT::i16 && isShiftedInt<11,1>(Offset)) { 372234285Sdim return true; 373234285Sdim } 374234285Sdim if (MemType == MVT::i8 && isInt<11>(Offset)) { 375234285Sdim return true; 376234285Sdim } 377234285Sdim return false; 378234285Sdim} 379234285Sdim 380234285Sdim 381234285Sdim// 382234285Sdim// Try to lower loads of GlobalAdresses into base+offset loads. Custom 383234285Sdim// lowering for GlobalAddress nodes has already turned it into a 384234285Sdim// CONST32. 385234285Sdim// 386263509SdimSDNode *HexagonDAGToDAGISel::SelectBaseOffsetLoad(LoadSDNode *LD, SDLoc dl) { 387234285Sdim SDValue Chain = LD->getChain(); 388234285Sdim SDNode* Const32 = LD->getBasePtr().getNode(); 389234285Sdim unsigned Opcode = 0; 390234285Sdim 391234285Sdim if (Const32->getOpcode() == HexagonISD::CONST32 && 392234285Sdim ISD::isNormalLoad(LD)) { 393234285Sdim SDValue Base = Const32->getOperand(0); 394234285Sdim EVT LoadedVT = LD->getMemoryVT(); 395234285Sdim int64_t Offset = cast<GlobalAddressSDNode>(Base)->getOffset(); 396234285Sdim if (Offset != 0 && OffsetFitsS11(LoadedVT, Offset)) { 397263509Sdim MVT PointerTy = getTargetLowering()->getPointerTy(); 398234285Sdim const GlobalValue* GV = 399234285Sdim cast<GlobalAddressSDNode>(Base)->getGlobal(); 400234285Sdim SDValue TargAddr = 401234285Sdim CurDAG->getTargetGlobalAddress(GV, dl, PointerTy, 0); 402234285Sdim SDNode* NewBase = CurDAG->getMachineNode(Hexagon::CONST32_set, 403234285Sdim dl, PointerTy, 404234285Sdim TargAddr); 405234285Sdim // Figure out base + offset opcode 406234285Sdim if (LoadedVT == MVT::i64) Opcode = Hexagon::LDrid_indexed; 407234285Sdim else if (LoadedVT == MVT::i32) Opcode = Hexagon::LDriw_indexed; 408234285Sdim else if (LoadedVT == MVT::i16) Opcode = Hexagon::LDrih_indexed; 409234285Sdim else if (LoadedVT == MVT::i8) Opcode = Hexagon::LDrib_indexed; 410245431Sdim else llvm_unreachable("unknown memory type"); 411234285Sdim 412234285Sdim // Build indexed load. 413234285Sdim SDValue TargetConstOff = CurDAG->getTargetConstant(Offset, PointerTy); 414234285Sdim SDNode* Result = CurDAG->getMachineNode(Opcode, dl, 415234285Sdim LD->getValueType(0), 416234285Sdim MVT::Other, 417234285Sdim SDValue(NewBase,0), 418234285Sdim TargetConstOff, 419234285Sdim Chain); 420234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 421234285Sdim MemOp[0] = LD->getMemOperand(); 422234285Sdim cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1); 423234285Sdim ReplaceUses(LD, Result); 424234285Sdim return Result; 425234285Sdim } 426234285Sdim } 427234285Sdim 428234285Sdim return SelectCode(LD); 429234285Sdim} 430234285Sdim 431234285Sdim 432234285SdimSDNode *HexagonDAGToDAGISel::SelectIndexedLoadSignExtend64(LoadSDNode *LD, 433234285Sdim unsigned Opcode, 434263509Sdim SDLoc dl) 435234285Sdim{ 436234285Sdim SDValue Chain = LD->getChain(); 437234285Sdim EVT LoadedVT = LD->getMemoryVT(); 438234285Sdim SDValue Base = LD->getBasePtr(); 439234285Sdim SDValue Offset = LD->getOffset(); 440234285Sdim SDNode *OffsetNode = Offset.getNode(); 441234285Sdim int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue(); 442234285Sdim SDValue N1 = LD->getOperand(1); 443234285Sdim SDValue CPTmpN1_0; 444234285Sdim SDValue CPTmpN1_1; 445263509Sdim 446234285Sdim if (SelectADDRriS11_2(N1, CPTmpN1_0, CPTmpN1_1) && 447234285Sdim N1.getNode()->getValueType(0) == MVT::i32) { 448263509Sdim const HexagonInstrInfo *TII = 449263509Sdim static_cast<const HexagonInstrInfo*>(TM.getInstrInfo()); 450234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) { 451234285Sdim SDValue TargetConst = CurDAG->getTargetConstant(Val, MVT::i32); 452234285Sdim SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, 453234285Sdim MVT::Other, Base, TargetConst, 454234285Sdim Chain); 455234285Sdim SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::SXTW, dl, MVT::i64, 456234285Sdim SDValue(Result_1, 0)); 457234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 458234285Sdim MemOp[0] = LD->getMemOperand(); 459234285Sdim cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1); 460234285Sdim const SDValue Froms[] = { SDValue(LD, 0), 461234285Sdim SDValue(LD, 1), 462234285Sdim SDValue(LD, 2) 463234285Sdim }; 464234285Sdim const SDValue Tos[] = { SDValue(Result_2, 0), 465234285Sdim SDValue(Result_1, 1), 466234285Sdim SDValue(Result_1, 2) 467234285Sdim }; 468234285Sdim ReplaceUses(Froms, Tos, 3); 469234285Sdim return Result_2; 470245431Sdim } 471234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 472234285Sdim SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32); 473234285Sdim SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, 474234285Sdim MVT::Other, Base, TargetConst0, 475234285Sdim Chain); 476234285Sdim SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::SXTW, dl, 477234285Sdim MVT::i64, SDValue(Result_1, 0)); 478234285Sdim SDNode* Result_3 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, 479234285Sdim MVT::i32, Base, TargetConstVal, 480234285Sdim SDValue(Result_1, 1)); 481234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 482234285Sdim MemOp[0] = LD->getMemOperand(); 483234285Sdim cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1); 484234285Sdim const SDValue Froms[] = { SDValue(LD, 0), 485234285Sdim SDValue(LD, 1), 486234285Sdim SDValue(LD, 2) 487234285Sdim }; 488234285Sdim const SDValue Tos[] = { SDValue(Result_2, 0), 489234285Sdim SDValue(Result_3, 0), 490234285Sdim SDValue(Result_1, 1) 491234285Sdim }; 492234285Sdim ReplaceUses(Froms, Tos, 3); 493234285Sdim return Result_2; 494234285Sdim } 495234285Sdim return SelectCode(LD); 496234285Sdim} 497234285Sdim 498234285Sdim 499234285SdimSDNode *HexagonDAGToDAGISel::SelectIndexedLoadZeroExtend64(LoadSDNode *LD, 500234285Sdim unsigned Opcode, 501263509Sdim SDLoc dl) 502234285Sdim{ 503234285Sdim SDValue Chain = LD->getChain(); 504234285Sdim EVT LoadedVT = LD->getMemoryVT(); 505234285Sdim SDValue Base = LD->getBasePtr(); 506234285Sdim SDValue Offset = LD->getOffset(); 507234285Sdim SDNode *OffsetNode = Offset.getNode(); 508234285Sdim int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue(); 509234285Sdim SDValue N1 = LD->getOperand(1); 510234285Sdim SDValue CPTmpN1_0; 511234285Sdim SDValue CPTmpN1_1; 512263509Sdim 513234285Sdim if (SelectADDRriS11_2(N1, CPTmpN1_0, CPTmpN1_1) && 514234285Sdim N1.getNode()->getValueType(0) == MVT::i32) { 515263509Sdim const HexagonInstrInfo *TII = 516263509Sdim static_cast<const HexagonInstrInfo*>(TM.getInstrInfo()); 517234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) { 518234285Sdim SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32); 519234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 520234285Sdim SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, 521234285Sdim MVT::i32, MVT::Other, Base, 522234285Sdim TargetConstVal, Chain); 523234285Sdim SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::TFRI, dl, MVT::i32, 524234285Sdim TargetConst0); 525234285Sdim SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::COMBINE_rr, dl, 526234285Sdim MVT::i64, MVT::Other, 527234285Sdim SDValue(Result_2,0), 528234285Sdim SDValue(Result_1,0)); 529234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 530234285Sdim MemOp[0] = LD->getMemOperand(); 531234285Sdim cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1); 532234285Sdim const SDValue Froms[] = { SDValue(LD, 0), 533234285Sdim SDValue(LD, 1), 534234285Sdim SDValue(LD, 2) 535234285Sdim }; 536234285Sdim const SDValue Tos[] = { SDValue(Result_3, 0), 537234285Sdim SDValue(Result_1, 1), 538234285Sdim SDValue(Result_1, 2) 539234285Sdim }; 540234285Sdim ReplaceUses(Froms, Tos, 3); 541234285Sdim return Result_3; 542234285Sdim } 543234285Sdim 544234285Sdim // Generate an indirect load. 545234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 546234285Sdim SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32); 547234285Sdim SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, 548234285Sdim MVT::Other, 549234285Sdim Base, TargetConst0, Chain); 550234285Sdim SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::TFRI, dl, MVT::i32, 551234285Sdim TargetConst0); 552234285Sdim SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::COMBINE_rr, dl, 553234285Sdim MVT::i64, MVT::Other, 554234285Sdim SDValue(Result_2,0), 555234285Sdim SDValue(Result_1,0)); 556234285Sdim // Add offset to base. 557234285Sdim SDNode* Result_4 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, MVT::i32, 558234285Sdim Base, TargetConstVal, 559234285Sdim SDValue(Result_1, 1)); 560234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 561234285Sdim MemOp[0] = LD->getMemOperand(); 562234285Sdim cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1); 563234285Sdim const SDValue Froms[] = { SDValue(LD, 0), 564234285Sdim SDValue(LD, 1), 565234285Sdim SDValue(LD, 2) 566234285Sdim }; 567234285Sdim const SDValue Tos[] = { SDValue(Result_3, 0), // Load value. 568234285Sdim SDValue(Result_4, 0), // New address. 569234285Sdim SDValue(Result_1, 1) 570234285Sdim }; 571234285Sdim ReplaceUses(Froms, Tos, 3); 572234285Sdim return Result_3; 573234285Sdim } 574234285Sdim 575234285Sdim return SelectCode(LD); 576234285Sdim} 577234285Sdim 578234285Sdim 579263509SdimSDNode *HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, SDLoc dl) { 580234285Sdim SDValue Chain = LD->getChain(); 581234285Sdim SDValue Base = LD->getBasePtr(); 582234285Sdim SDValue Offset = LD->getOffset(); 583234285Sdim SDNode *OffsetNode = Offset.getNode(); 584234285Sdim // Get the constant value. 585234285Sdim int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue(); 586234285Sdim EVT LoadedVT = LD->getMemoryVT(); 587234285Sdim unsigned Opcode = 0; 588234285Sdim 589234285Sdim // Check for zero ext loads. 590234285Sdim bool zextval = (LD->getExtensionType() == ISD::ZEXTLOAD); 591234285Sdim 592234285Sdim // Figure out the opcode. 593263509Sdim const HexagonInstrInfo *TII = 594263509Sdim static_cast<const HexagonInstrInfo*>(TM.getInstrInfo()); 595234285Sdim if (LoadedVT == MVT::i64) { 596234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) 597234285Sdim Opcode = Hexagon::POST_LDrid; 598234285Sdim else 599234285Sdim Opcode = Hexagon::LDrid; 600234285Sdim } else if (LoadedVT == MVT::i32) { 601234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) 602234285Sdim Opcode = Hexagon::POST_LDriw; 603234285Sdim else 604234285Sdim Opcode = Hexagon::LDriw; 605234285Sdim } else if (LoadedVT == MVT::i16) { 606234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) 607234285Sdim Opcode = zextval ? Hexagon::POST_LDriuh : Hexagon::POST_LDrih; 608234285Sdim else 609234285Sdim Opcode = zextval ? Hexagon::LDriuh : Hexagon::LDrih; 610234285Sdim } else if (LoadedVT == MVT::i8) { 611234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) 612234285Sdim Opcode = zextval ? Hexagon::POST_LDriub : Hexagon::POST_LDrib; 613234285Sdim else 614234285Sdim Opcode = zextval ? Hexagon::LDriub : Hexagon::LDrib; 615234285Sdim } else 616245431Sdim llvm_unreachable("unknown memory type"); 617234285Sdim 618234285Sdim // For zero ext i64 loads, we need to add combine instructions. 619234285Sdim if (LD->getValueType(0) == MVT::i64 && 620234285Sdim LD->getExtensionType() == ISD::ZEXTLOAD) { 621234285Sdim return SelectIndexedLoadZeroExtend64(LD, Opcode, dl); 622234285Sdim } 623234285Sdim if (LD->getValueType(0) == MVT::i64 && 624234285Sdim LD->getExtensionType() == ISD::SEXTLOAD) { 625234285Sdim // Handle sign ext i64 loads. 626234285Sdim return SelectIndexedLoadSignExtend64(LD, Opcode, dl); 627234285Sdim } 628234285Sdim if (TII->isValidAutoIncImm(LoadedVT, Val)) { 629234285Sdim SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32); 630234285Sdim SDNode* Result = CurDAG->getMachineNode(Opcode, dl, 631234285Sdim LD->getValueType(0), 632234285Sdim MVT::i32, MVT::Other, Base, 633234285Sdim TargetConstVal, Chain); 634234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 635234285Sdim MemOp[0] = LD->getMemOperand(); 636234285Sdim cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1); 637234285Sdim const SDValue Froms[] = { SDValue(LD, 0), 638234285Sdim SDValue(LD, 1), 639234285Sdim SDValue(LD, 2) 640234285Sdim }; 641234285Sdim const SDValue Tos[] = { SDValue(Result, 0), 642234285Sdim SDValue(Result, 1), 643234285Sdim SDValue(Result, 2) 644234285Sdim }; 645234285Sdim ReplaceUses(Froms, Tos, 3); 646234285Sdim return Result; 647234285Sdim } else { 648234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 649234285Sdim SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32); 650234285Sdim SDNode* Result_1 = CurDAG->getMachineNode(Opcode, dl, 651234285Sdim LD->getValueType(0), 652234285Sdim MVT::Other, Base, TargetConst0, 653234285Sdim Chain); 654234285Sdim SDNode* Result_2 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, MVT::i32, 655234285Sdim Base, TargetConstVal, 656234285Sdim SDValue(Result_1, 1)); 657234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 658234285Sdim MemOp[0] = LD->getMemOperand(); 659234285Sdim cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1); 660234285Sdim const SDValue Froms[] = { SDValue(LD, 0), 661234285Sdim SDValue(LD, 1), 662234285Sdim SDValue(LD, 2) 663234285Sdim }; 664234285Sdim const SDValue Tos[] = { SDValue(Result_1, 0), 665234285Sdim SDValue(Result_2, 0), 666234285Sdim SDValue(Result_1, 1) 667234285Sdim }; 668234285Sdim ReplaceUses(Froms, Tos, 3); 669234285Sdim return Result_1; 670234285Sdim } 671234285Sdim} 672234285Sdim 673234285Sdim 674234285SdimSDNode *HexagonDAGToDAGISel::SelectLoad(SDNode *N) { 675234285Sdim SDNode *result; 676263509Sdim SDLoc dl(N); 677234285Sdim LoadSDNode *LD = cast<LoadSDNode>(N); 678234285Sdim ISD::MemIndexedMode AM = LD->getAddressingMode(); 679234285Sdim 680234285Sdim // Handle indexed loads. 681234285Sdim if (AM != ISD::UNINDEXED) { 682234285Sdim result = SelectIndexedLoad(LD, dl); 683234285Sdim } else { 684234285Sdim result = SelectBaseOffsetLoad(LD, dl); 685234285Sdim } 686234285Sdim 687234285Sdim return result; 688234285Sdim} 689234285Sdim 690234285Sdim 691263509SdimSDNode *HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, SDLoc dl) { 692234285Sdim SDValue Chain = ST->getChain(); 693234285Sdim SDValue Base = ST->getBasePtr(); 694234285Sdim SDValue Offset = ST->getOffset(); 695234285Sdim SDValue Value = ST->getValue(); 696234285Sdim SDNode *OffsetNode = Offset.getNode(); 697234285Sdim // Get the constant value. 698234285Sdim int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue(); 699234285Sdim EVT StoredVT = ST->getMemoryVT(); 700234285Sdim 701234285Sdim // Offset value must be within representable range 702234285Sdim // and must have correct alignment properties. 703263509Sdim const HexagonInstrInfo *TII = 704263509Sdim static_cast<const HexagonInstrInfo*>(TM.getInstrInfo()); 705234285Sdim if (TII->isValidAutoIncImm(StoredVT, Val)) { 706252723Sdim SDValue Ops[] = {Base, CurDAG->getTargetConstant(Val, MVT::i32), Value, 707252723Sdim Chain}; 708234285Sdim unsigned Opcode = 0; 709234285Sdim 710234285Sdim // Figure out the post inc version of opcode. 711234285Sdim if (StoredVT == MVT::i64) Opcode = Hexagon::POST_STdri; 712234285Sdim else if (StoredVT == MVT::i32) Opcode = Hexagon::POST_STwri; 713234285Sdim else if (StoredVT == MVT::i16) Opcode = Hexagon::POST_SThri; 714234285Sdim else if (StoredVT == MVT::i8) Opcode = Hexagon::POST_STbri; 715245431Sdim else llvm_unreachable("unknown memory type"); 716234285Sdim 717234285Sdim // Build post increment store. 718234285Sdim SDNode* Result = CurDAG->getMachineNode(Opcode, dl, MVT::i32, 719252723Sdim MVT::Other, Ops); 720234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 721234285Sdim MemOp[0] = ST->getMemOperand(); 722234285Sdim cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1); 723234285Sdim 724234285Sdim ReplaceUses(ST, Result); 725234285Sdim ReplaceUses(SDValue(ST,1), SDValue(Result,1)); 726234285Sdim return Result; 727234285Sdim } 728234285Sdim 729234285Sdim // Note: Order of operands matches the def of instruction: 730234285Sdim // def STrid : STInst<(outs), (ins MEMri:$addr, DoubleRegs:$src1), ... 731234285Sdim // and it differs for POST_ST* for instance. 732234285Sdim SDValue Ops[] = { Base, CurDAG->getTargetConstant(0, MVT::i32), Value, 733234285Sdim Chain}; 734234285Sdim unsigned Opcode = 0; 735234285Sdim 736234285Sdim // Figure out the opcode. 737234285Sdim if (StoredVT == MVT::i64) Opcode = Hexagon::STrid; 738245431Sdim else if (StoredVT == MVT::i32) Opcode = Hexagon::STriw_indexed; 739234285Sdim else if (StoredVT == MVT::i16) Opcode = Hexagon::STrih; 740234285Sdim else if (StoredVT == MVT::i8) Opcode = Hexagon::STrib; 741245431Sdim else llvm_unreachable("unknown memory type"); 742234285Sdim 743234285Sdim // Build regular store. 744234285Sdim SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32); 745252723Sdim SDNode* Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::Other, Ops); 746234285Sdim // Build splitted incriment instruction. 747234285Sdim SDNode* Result_2 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, MVT::i32, 748234285Sdim Base, 749234285Sdim TargetConstVal, 750234285Sdim SDValue(Result_1, 0)); 751234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 752234285Sdim MemOp[0] = ST->getMemOperand(); 753234285Sdim cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1); 754234285Sdim 755234285Sdim ReplaceUses(SDValue(ST,0), SDValue(Result_2,0)); 756234285Sdim ReplaceUses(SDValue(ST,1), SDValue(Result_1,0)); 757234285Sdim return Result_2; 758234285Sdim} 759234285Sdim 760234285Sdim 761234285SdimSDNode *HexagonDAGToDAGISel::SelectBaseOffsetStore(StoreSDNode *ST, 762263509Sdim SDLoc dl) { 763234285Sdim SDValue Chain = ST->getChain(); 764234285Sdim SDNode* Const32 = ST->getBasePtr().getNode(); 765234285Sdim SDValue Value = ST->getValue(); 766234285Sdim unsigned Opcode = 0; 767234285Sdim 768234285Sdim // Try to lower stores of GlobalAdresses into indexed stores. Custom 769234285Sdim // lowering for GlobalAddress nodes has already turned it into a 770234285Sdim // CONST32. Avoid truncating stores for the moment. Post-inc stores 771234285Sdim // do the same. Don't think there's a reason for it, so will file a 772234285Sdim // bug to fix. 773234285Sdim if ((Const32->getOpcode() == HexagonISD::CONST32) && 774234285Sdim !(Value.getValueType() == MVT::i64 && ST->isTruncatingStore())) { 775234285Sdim SDValue Base = Const32->getOperand(0); 776234285Sdim if (Base.getOpcode() == ISD::TargetGlobalAddress) { 777234285Sdim EVT StoredVT = ST->getMemoryVT(); 778234285Sdim int64_t Offset = cast<GlobalAddressSDNode>(Base)->getOffset(); 779234285Sdim if (Offset != 0 && OffsetFitsS11(StoredVT, Offset)) { 780263509Sdim MVT PointerTy = getTargetLowering()->getPointerTy(); 781234285Sdim const GlobalValue* GV = 782234285Sdim cast<GlobalAddressSDNode>(Base)->getGlobal(); 783234285Sdim SDValue TargAddr = 784234285Sdim CurDAG->getTargetGlobalAddress(GV, dl, PointerTy, 0); 785234285Sdim SDNode* NewBase = CurDAG->getMachineNode(Hexagon::CONST32_set, 786234285Sdim dl, PointerTy, 787234285Sdim TargAddr); 788234285Sdim 789234285Sdim // Figure out base + offset opcode 790234285Sdim if (StoredVT == MVT::i64) Opcode = Hexagon::STrid_indexed; 791234285Sdim else if (StoredVT == MVT::i32) Opcode = Hexagon::STriw_indexed; 792234285Sdim else if (StoredVT == MVT::i16) Opcode = Hexagon::STrih_indexed; 793234285Sdim else if (StoredVT == MVT::i8) Opcode = Hexagon::STrib_indexed; 794245431Sdim else llvm_unreachable("unknown memory type"); 795234285Sdim 796234285Sdim SDValue Ops[] = {SDValue(NewBase,0), 797234285Sdim CurDAG->getTargetConstant(Offset,PointerTy), 798234285Sdim Value, Chain}; 799234285Sdim // build indexed store 800234285Sdim SDNode* Result = CurDAG->getMachineNode(Opcode, dl, 801252723Sdim MVT::Other, Ops); 802234285Sdim MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 803234285Sdim MemOp[0] = ST->getMemOperand(); 804234285Sdim cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1); 805234285Sdim ReplaceUses(ST, Result); 806234285Sdim return Result; 807234285Sdim } 808234285Sdim } 809234285Sdim } 810234285Sdim 811234285Sdim return SelectCode(ST); 812234285Sdim} 813234285Sdim 814234285Sdim 815234285SdimSDNode *HexagonDAGToDAGISel::SelectStore(SDNode *N) { 816263509Sdim SDLoc dl(N); 817234285Sdim StoreSDNode *ST = cast<StoreSDNode>(N); 818234285Sdim ISD::MemIndexedMode AM = ST->getAddressingMode(); 819234285Sdim 820234285Sdim // Handle indexed stores. 821234285Sdim if (AM != ISD::UNINDEXED) { 822234285Sdim return SelectIndexedStore(ST, dl); 823234285Sdim } 824245431Sdim 825234285Sdim return SelectBaseOffsetStore(ST, dl); 826234285Sdim} 827234285Sdim 828234285SdimSDNode *HexagonDAGToDAGISel::SelectMul(SDNode *N) { 829263509Sdim SDLoc dl(N); 830234285Sdim 831234285Sdim // 832234285Sdim // %conv.i = sext i32 %tmp1 to i64 833234285Sdim // %conv2.i = sext i32 %add to i64 834234285Sdim // %mul.i = mul nsw i64 %conv2.i, %conv.i 835234285Sdim // 836234285Sdim // --- match with the following --- 837234285Sdim // 838234285Sdim // %mul.i = mpy (%tmp1, %add) 839234285Sdim // 840234285Sdim 841234285Sdim if (N->getValueType(0) == MVT::i64) { 842234285Sdim // Shifting a i64 signed multiply. 843234285Sdim SDValue MulOp0 = N->getOperand(0); 844234285Sdim SDValue MulOp1 = N->getOperand(1); 845234285Sdim 846234285Sdim SDValue OP0; 847234285Sdim SDValue OP1; 848234285Sdim 849234285Sdim // Handle sign_extend and sextload. 850234285Sdim if (MulOp0.getOpcode() == ISD::SIGN_EXTEND) { 851234285Sdim SDValue Sext0 = MulOp0.getOperand(0); 852234285Sdim if (Sext0.getNode()->getValueType(0) != MVT::i32) { 853245431Sdim return SelectCode(N); 854234285Sdim } 855234285Sdim 856234285Sdim OP0 = Sext0; 857234285Sdim } else if (MulOp0.getOpcode() == ISD::LOAD) { 858234285Sdim LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode()); 859234285Sdim if (LD->getMemoryVT() != MVT::i32 || 860234285Sdim LD->getExtensionType() != ISD::SEXTLOAD || 861234285Sdim LD->getAddressingMode() != ISD::UNINDEXED) { 862245431Sdim return SelectCode(N); 863234285Sdim } 864234285Sdim 865234285Sdim SDValue Chain = LD->getChain(); 866234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 867234285Sdim OP0 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32, 868234285Sdim MVT::Other, 869234285Sdim LD->getBasePtr(), TargetConst0, 870234285Sdim Chain), 0); 871234285Sdim } else { 872234285Sdim return SelectCode(N); 873234285Sdim } 874234285Sdim 875234285Sdim // Same goes for the second operand. 876234285Sdim if (MulOp1.getOpcode() == ISD::SIGN_EXTEND) { 877234285Sdim SDValue Sext1 = MulOp1.getOperand(0); 878234285Sdim if (Sext1.getNode()->getValueType(0) != MVT::i32) { 879234285Sdim return SelectCode(N); 880234285Sdim } 881234285Sdim 882234285Sdim OP1 = Sext1; 883234285Sdim } else if (MulOp1.getOpcode() == ISD::LOAD) { 884234285Sdim LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode()); 885234285Sdim if (LD->getMemoryVT() != MVT::i32 || 886234285Sdim LD->getExtensionType() != ISD::SEXTLOAD || 887234285Sdim LD->getAddressingMode() != ISD::UNINDEXED) { 888234285Sdim return SelectCode(N); 889234285Sdim } 890234285Sdim 891234285Sdim SDValue Chain = LD->getChain(); 892234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 893234285Sdim OP1 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32, 894234285Sdim MVT::Other, 895234285Sdim LD->getBasePtr(), TargetConst0, 896234285Sdim Chain), 0); 897234285Sdim } else { 898234285Sdim return SelectCode(N); 899234285Sdim } 900234285Sdim 901234285Sdim // Generate a mpy instruction. 902234285Sdim SDNode *Result = CurDAG->getMachineNode(Hexagon::MPY64, dl, MVT::i64, 903234285Sdim OP0, OP1); 904234285Sdim ReplaceUses(N, Result); 905234285Sdim return Result; 906234285Sdim } 907234285Sdim 908234285Sdim return SelectCode(N); 909234285Sdim} 910234285Sdim 911234285Sdim 912234285SdimSDNode *HexagonDAGToDAGISel::SelectSelect(SDNode *N) { 913263509Sdim SDLoc dl(N); 914234285Sdim SDValue N0 = N->getOperand(0); 915234285Sdim if (N0.getOpcode() == ISD::SETCC) { 916234285Sdim SDValue N00 = N0.getOperand(0); 917234285Sdim if (N00.getOpcode() == ISD::SIGN_EXTEND_INREG) { 918234285Sdim SDValue N000 = N00.getOperand(0); 919234285Sdim SDValue N001 = N00.getOperand(1); 920234285Sdim if (cast<VTSDNode>(N001)->getVT() == MVT::i16) { 921234285Sdim SDValue N01 = N0.getOperand(1); 922234285Sdim SDValue N02 = N0.getOperand(2); 923234285Sdim 924234285Sdim // Pattern: (select:i32 (setcc:i1 (sext_inreg:i32 IntRegs:i32:$src2, 925234285Sdim // i16:Other),IntRegs:i32:$src1, SETLT:Other),IntRegs:i32:$src1, 926234285Sdim // IntRegs:i32:$src2) 927234285Sdim // Emits: (MAXh_rr:i32 IntRegs:i32:$src1, IntRegs:i32:$src2) 928234285Sdim // Pattern complexity = 9 cost = 1 size = 0. 929234285Sdim if (cast<CondCodeSDNode>(N02)->get() == ISD::SETLT) { 930234285Sdim SDValue N1 = N->getOperand(1); 931234285Sdim if (N01 == N1) { 932234285Sdim SDValue N2 = N->getOperand(2); 933234285Sdim if (N000 == N2 && 934234285Sdim N0.getNode()->getValueType(N0.getResNo()) == MVT::i1 && 935234285Sdim N00.getNode()->getValueType(N00.getResNo()) == MVT::i32) { 936234285Sdim SDNode *SextNode = CurDAG->getMachineNode(Hexagon::SXTH, dl, 937234285Sdim MVT::i32, N000); 938234285Sdim SDNode *Result = CurDAG->getMachineNode(Hexagon::MAXw_rr, dl, 939234285Sdim MVT::i32, 940234285Sdim SDValue(SextNode, 0), 941234285Sdim N1); 942234285Sdim ReplaceUses(N, Result); 943234285Sdim return Result; 944234285Sdim } 945234285Sdim } 946234285Sdim } 947234285Sdim 948234285Sdim // Pattern: (select:i32 (setcc:i1 (sext_inreg:i32 IntRegs:i32:$src2, 949234285Sdim // i16:Other), IntRegs:i32:$src1, SETGT:Other), IntRegs:i32:$src1, 950234285Sdim // IntRegs:i32:$src2) 951234285Sdim // Emits: (MINh_rr:i32 IntRegs:i32:$src1, IntRegs:i32:$src2) 952234285Sdim // Pattern complexity = 9 cost = 1 size = 0. 953234285Sdim if (cast<CondCodeSDNode>(N02)->get() == ISD::SETGT) { 954234285Sdim SDValue N1 = N->getOperand(1); 955234285Sdim if (N01 == N1) { 956234285Sdim SDValue N2 = N->getOperand(2); 957234285Sdim if (N000 == N2 && 958234285Sdim N0.getNode()->getValueType(N0.getResNo()) == MVT::i1 && 959234285Sdim N00.getNode()->getValueType(N00.getResNo()) == MVT::i32) { 960234285Sdim SDNode *SextNode = CurDAG->getMachineNode(Hexagon::SXTH, dl, 961234285Sdim MVT::i32, N000); 962234285Sdim SDNode *Result = CurDAG->getMachineNode(Hexagon::MINw_rr, dl, 963234285Sdim MVT::i32, 964234285Sdim SDValue(SextNode, 0), 965234285Sdim N1); 966234285Sdim ReplaceUses(N, Result); 967234285Sdim return Result; 968234285Sdim } 969234285Sdim } 970234285Sdim } 971234285Sdim } 972234285Sdim } 973234285Sdim } 974234285Sdim 975234285Sdim return SelectCode(N); 976234285Sdim} 977234285Sdim 978234285Sdim 979234285SdimSDNode *HexagonDAGToDAGISel::SelectTruncate(SDNode *N) { 980263509Sdim SDLoc dl(N); 981234285Sdim SDValue Shift = N->getOperand(0); 982234285Sdim 983234285Sdim // 984234285Sdim // %conv.i = sext i32 %tmp1 to i64 985234285Sdim // %conv2.i = sext i32 %add to i64 986234285Sdim // %mul.i = mul nsw i64 %conv2.i, %conv.i 987234285Sdim // %shr5.i = lshr i64 %mul.i, 32 988234285Sdim // %conv3.i = trunc i64 %shr5.i to i32 989234285Sdim // 990234285Sdim // --- match with the following --- 991234285Sdim // 992234285Sdim // %conv3.i = mpy (%tmp1, %add) 993234285Sdim // 994234285Sdim // Trunc to i32. 995234285Sdim if (N->getValueType(0) == MVT::i32) { 996234285Sdim // Trunc from i64. 997234285Sdim if (Shift.getNode()->getValueType(0) == MVT::i64) { 998234285Sdim // Trunc child is logical shift right. 999234285Sdim if (Shift.getOpcode() != ISD::SRL) { 1000234285Sdim return SelectCode(N); 1001234285Sdim } 1002234285Sdim 1003234285Sdim SDValue ShiftOp0 = Shift.getOperand(0); 1004234285Sdim SDValue ShiftOp1 = Shift.getOperand(1); 1005234285Sdim 1006234285Sdim // Shift by const 32 1007234285Sdim if (ShiftOp1.getOpcode() != ISD::Constant) { 1008234285Sdim return SelectCode(N); 1009234285Sdim } 1010234285Sdim 1011234285Sdim int32_t ShiftConst = 1012234285Sdim cast<ConstantSDNode>(ShiftOp1.getNode())->getSExtValue(); 1013234285Sdim if (ShiftConst != 32) { 1014234285Sdim return SelectCode(N); 1015234285Sdim } 1016234285Sdim 1017234285Sdim // Shifting a i64 signed multiply 1018234285Sdim SDValue Mul = ShiftOp0; 1019234285Sdim if (Mul.getOpcode() != ISD::MUL) { 1020234285Sdim return SelectCode(N); 1021234285Sdim } 1022234285Sdim 1023234285Sdim SDValue MulOp0 = Mul.getOperand(0); 1024234285Sdim SDValue MulOp1 = Mul.getOperand(1); 1025234285Sdim 1026234285Sdim SDValue OP0; 1027234285Sdim SDValue OP1; 1028234285Sdim 1029234285Sdim // Handle sign_extend and sextload 1030234285Sdim if (MulOp0.getOpcode() == ISD::SIGN_EXTEND) { 1031234285Sdim SDValue Sext0 = MulOp0.getOperand(0); 1032234285Sdim if (Sext0.getNode()->getValueType(0) != MVT::i32) { 1033234285Sdim return SelectCode(N); 1034234285Sdim } 1035234285Sdim 1036234285Sdim OP0 = Sext0; 1037234285Sdim } else if (MulOp0.getOpcode() == ISD::LOAD) { 1038234285Sdim LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode()); 1039234285Sdim if (LD->getMemoryVT() != MVT::i32 || 1040234285Sdim LD->getExtensionType() != ISD::SEXTLOAD || 1041234285Sdim LD->getAddressingMode() != ISD::UNINDEXED) { 1042234285Sdim return SelectCode(N); 1043234285Sdim } 1044234285Sdim 1045234285Sdim SDValue Chain = LD->getChain(); 1046234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 1047234285Sdim OP0 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32, 1048234285Sdim MVT::Other, 1049234285Sdim LD->getBasePtr(), 1050234285Sdim TargetConst0, Chain), 0); 1051234285Sdim } else { 1052234285Sdim return SelectCode(N); 1053234285Sdim } 1054234285Sdim 1055234285Sdim // Same goes for the second operand. 1056234285Sdim if (MulOp1.getOpcode() == ISD::SIGN_EXTEND) { 1057234285Sdim SDValue Sext1 = MulOp1.getOperand(0); 1058234285Sdim if (Sext1.getNode()->getValueType(0) != MVT::i32) 1059234285Sdim return SelectCode(N); 1060234285Sdim 1061234285Sdim OP1 = Sext1; 1062234285Sdim } else if (MulOp1.getOpcode() == ISD::LOAD) { 1063234285Sdim LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode()); 1064234285Sdim if (LD->getMemoryVT() != MVT::i32 || 1065234285Sdim LD->getExtensionType() != ISD::SEXTLOAD || 1066234285Sdim LD->getAddressingMode() != ISD::UNINDEXED) { 1067234285Sdim return SelectCode(N); 1068234285Sdim } 1069234285Sdim 1070234285Sdim SDValue Chain = LD->getChain(); 1071234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 1072234285Sdim OP1 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32, 1073234285Sdim MVT::Other, 1074234285Sdim LD->getBasePtr(), 1075234285Sdim TargetConst0, Chain), 0); 1076234285Sdim } else { 1077234285Sdim return SelectCode(N); 1078234285Sdim } 1079234285Sdim 1080234285Sdim // Generate a mpy instruction. 1081234285Sdim SDNode *Result = CurDAG->getMachineNode(Hexagon::MPY, dl, MVT::i32, 1082234285Sdim OP0, OP1); 1083234285Sdim ReplaceUses(N, Result); 1084234285Sdim return Result; 1085234285Sdim } 1086234285Sdim } 1087234285Sdim 1088234285Sdim return SelectCode(N); 1089234285Sdim} 1090234285Sdim 1091234285Sdim 1092234285SdimSDNode *HexagonDAGToDAGISel::SelectSHL(SDNode *N) { 1093263509Sdim SDLoc dl(N); 1094234285Sdim if (N->getValueType(0) == MVT::i32) { 1095234285Sdim SDValue Shl_0 = N->getOperand(0); 1096234285Sdim SDValue Shl_1 = N->getOperand(1); 1097234285Sdim // RHS is const. 1098234285Sdim if (Shl_1.getOpcode() == ISD::Constant) { 1099234285Sdim if (Shl_0.getOpcode() == ISD::MUL) { 1100234285Sdim SDValue Mul_0 = Shl_0.getOperand(0); // Val 1101234285Sdim SDValue Mul_1 = Shl_0.getOperand(1); // Const 1102234285Sdim // RHS of mul is const. 1103234285Sdim if (Mul_1.getOpcode() == ISD::Constant) { 1104234285Sdim int32_t ShlConst = 1105234285Sdim cast<ConstantSDNode>(Shl_1.getNode())->getSExtValue(); 1106234285Sdim int32_t MulConst = 1107234285Sdim cast<ConstantSDNode>(Mul_1.getNode())->getSExtValue(); 1108234285Sdim int32_t ValConst = MulConst << ShlConst; 1109234285Sdim SDValue Val = CurDAG->getTargetConstant(ValConst, 1110234285Sdim MVT::i32); 1111234285Sdim if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val.getNode())) 1112234285Sdim if (isInt<9>(CN->getSExtValue())) { 1113234285Sdim SDNode* Result = 1114234285Sdim CurDAG->getMachineNode(Hexagon::MPYI_ri, dl, 1115234285Sdim MVT::i32, Mul_0, Val); 1116234285Sdim ReplaceUses(N, Result); 1117234285Sdim return Result; 1118234285Sdim } 1119234285Sdim 1120234285Sdim } 1121234285Sdim } else if (Shl_0.getOpcode() == ISD::SUB) { 1122234285Sdim SDValue Sub_0 = Shl_0.getOperand(0); // Const 0 1123234285Sdim SDValue Sub_1 = Shl_0.getOperand(1); // Val 1124234285Sdim if (Sub_0.getOpcode() == ISD::Constant) { 1125234285Sdim int32_t SubConst = 1126234285Sdim cast<ConstantSDNode>(Sub_0.getNode())->getSExtValue(); 1127234285Sdim if (SubConst == 0) { 1128234285Sdim if (Sub_1.getOpcode() == ISD::SHL) { 1129234285Sdim SDValue Shl2_0 = Sub_1.getOperand(0); // Val 1130234285Sdim SDValue Shl2_1 = Sub_1.getOperand(1); // Const 1131234285Sdim if (Shl2_1.getOpcode() == ISD::Constant) { 1132234285Sdim int32_t ShlConst = 1133234285Sdim cast<ConstantSDNode>(Shl_1.getNode())->getSExtValue(); 1134234285Sdim int32_t Shl2Const = 1135234285Sdim cast<ConstantSDNode>(Shl2_1.getNode())->getSExtValue(); 1136234285Sdim int32_t ValConst = 1 << (ShlConst+Shl2Const); 1137234285Sdim SDValue Val = CurDAG->getTargetConstant(-ValConst, MVT::i32); 1138234285Sdim if (ConstantSDNode *CN = 1139234285Sdim dyn_cast<ConstantSDNode>(Val.getNode())) 1140234285Sdim if (isInt<9>(CN->getSExtValue())) { 1141234285Sdim SDNode* Result = 1142234285Sdim CurDAG->getMachineNode(Hexagon::MPYI_ri, dl, MVT::i32, 1143234285Sdim Shl2_0, Val); 1144234285Sdim ReplaceUses(N, Result); 1145234285Sdim return Result; 1146234285Sdim } 1147234285Sdim } 1148234285Sdim } 1149234285Sdim } 1150234285Sdim } 1151234285Sdim } 1152234285Sdim } 1153234285Sdim } 1154234285Sdim return SelectCode(N); 1155234285Sdim} 1156234285Sdim 1157234285Sdim 1158234285Sdim// 1159234285Sdim// If there is an zero_extend followed an intrinsic in DAG (this means - the 1160234285Sdim// result of the intrinsic is predicate); convert the zero_extend to 1161234285Sdim// transfer instruction. 1162234285Sdim// 1163234285Sdim// Zero extend -> transfer is lowered here. Otherwise, zero_extend will be 1164234285Sdim// converted into a MUX as predicate registers defined as 1 bit in the 1165234285Sdim// compiler. Architecture defines them as 8-bit registers. 1166234285Sdim// We want to preserve all the lower 8-bits and, not just 1 LSB bit. 1167234285Sdim// 1168234285SdimSDNode *HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) { 1169263509Sdim SDLoc dl(N); 1170234285Sdim SDNode *IsIntrinsic = N->getOperand(0).getNode(); 1171234285Sdim if ((IsIntrinsic->getOpcode() == ISD::INTRINSIC_WO_CHAIN)) { 1172234285Sdim unsigned ID = 1173234285Sdim cast<ConstantSDNode>(IsIntrinsic->getOperand(0))->getZExtValue(); 1174234285Sdim if (doesIntrinsicReturnPredicate(ID)) { 1175234285Sdim // Now we need to differentiate target data types. 1176234285Sdim if (N->getValueType(0) == MVT::i64) { 1177234285Sdim // Convert the zero_extend to Rs = Pd followed by COMBINE_rr(0,Rs). 1178234285Sdim SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32); 1179234285Sdim SDNode *Result_1 = CurDAG->getMachineNode(Hexagon::TFR_RsPd, dl, 1180234285Sdim MVT::i32, 1181234285Sdim SDValue(IsIntrinsic, 0)); 1182234285Sdim SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::TFRI, dl, 1183234285Sdim MVT::i32, 1184234285Sdim TargetConst0); 1185234285Sdim SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::COMBINE_rr, dl, 1186234285Sdim MVT::i64, MVT::Other, 1187234285Sdim SDValue(Result_2, 0), 1188234285Sdim SDValue(Result_1, 0)); 1189234285Sdim ReplaceUses(N, Result_3); 1190234285Sdim return Result_3; 1191234285Sdim } 1192234285Sdim if (N->getValueType(0) == MVT::i32) { 1193234285Sdim // Convert the zero_extend to Rs = Pd 1194234285Sdim SDNode* RsPd = CurDAG->getMachineNode(Hexagon::TFR_RsPd, dl, 1195234285Sdim MVT::i32, 1196234285Sdim SDValue(IsIntrinsic, 0)); 1197234285Sdim ReplaceUses(N, RsPd); 1198234285Sdim return RsPd; 1199234285Sdim } 1200234285Sdim llvm_unreachable("Unexpected value type"); 1201234285Sdim } 1202234285Sdim } 1203234285Sdim return SelectCode(N); 1204234285Sdim} 1205234285Sdim 1206234285Sdim 1207234285Sdim// 1208234285Sdim// Checking for intrinsics which have predicate registers as operand(s) 1209234285Sdim// and lowering to the actual intrinsic. 1210234285Sdim// 1211234285SdimSDNode *HexagonDAGToDAGISel::SelectIntrinsicWOChain(SDNode *N) { 1212263509Sdim SDLoc dl(N); 1213234285Sdim unsigned ID = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue(); 1214234285Sdim unsigned IntrinsicWithPred = doesIntrinsicContainPredicate(ID); 1215234285Sdim 1216234285Sdim // We are concerned with only those intrinsics that have predicate registers 1217234285Sdim // as at least one of the operands. 1218234285Sdim if (IntrinsicWithPred) { 1219234285Sdim SmallVector<SDValue, 8> Ops; 1220263509Sdim const HexagonInstrInfo *TII = 1221263509Sdim static_cast<const HexagonInstrInfo*>(TM.getInstrInfo()); 1222234285Sdim const MCInstrDesc &MCID = TII->get(IntrinsicWithPred); 1223234285Sdim const TargetRegisterInfo *TRI = TM.getRegisterInfo(); 1224234285Sdim 1225234285Sdim // Iterate over all the operands of the intrinsics. 1226234285Sdim // For PredRegs, do the transfer. 1227234285Sdim // For Double/Int Regs, just preserve the value 1228234285Sdim // For immediates, lower it. 1229234285Sdim for (unsigned i = 1; i < N->getNumOperands(); ++i) { 1230234285Sdim SDNode *Arg = N->getOperand(i).getNode(); 1231245431Sdim const TargetRegisterClass *RC = TII->getRegClass(MCID, i, TRI, *MF); 1232234285Sdim 1233245431Sdim if (RC == &Hexagon::IntRegsRegClass || 1234245431Sdim RC == &Hexagon::DoubleRegsRegClass) { 1235234285Sdim Ops.push_back(SDValue(Arg, 0)); 1236245431Sdim } else if (RC == &Hexagon::PredRegsRegClass) { 1237234285Sdim // Do the transfer. 1238234285Sdim SDNode *PdRs = CurDAG->getMachineNode(Hexagon::TFR_PdRs, dl, MVT::i1, 1239234285Sdim SDValue(Arg, 0)); 1240234285Sdim Ops.push_back(SDValue(PdRs,0)); 1241234285Sdim } else if (RC == NULL && (dyn_cast<ConstantSDNode>(Arg) != NULL)) { 1242234285Sdim // This is immediate operand. Lower it here making sure that we DO have 1243234285Sdim // const SDNode for immediate value. 1244234285Sdim int32_t Val = cast<ConstantSDNode>(Arg)->getSExtValue(); 1245234285Sdim SDValue SDVal = CurDAG->getTargetConstant(Val, MVT::i32); 1246234285Sdim Ops.push_back(SDVal); 1247234285Sdim } else { 1248234285Sdim llvm_unreachable("Unimplemented"); 1249234285Sdim } 1250234285Sdim } 1251234285Sdim EVT ReturnValueVT = N->getValueType(0); 1252234285Sdim SDNode *Result = CurDAG->getMachineNode(IntrinsicWithPred, dl, 1253252723Sdim ReturnValueVT, Ops); 1254234285Sdim ReplaceUses(N, Result); 1255234285Sdim return Result; 1256234285Sdim } 1257234285Sdim return SelectCode(N); 1258234285Sdim} 1259234285Sdim 1260245431Sdim// 1261245431Sdim// Map floating point constant values. 1262245431Sdim// 1263245431SdimSDNode *HexagonDAGToDAGISel::SelectConstantFP(SDNode *N) { 1264263509Sdim SDLoc dl(N); 1265245431Sdim ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); 1266245431Sdim APFloat APF = CN->getValueAPF(); 1267245431Sdim if (N->getValueType(0) == MVT::f32) { 1268245431Sdim return CurDAG->getMachineNode(Hexagon::TFRI_f, dl, MVT::f32, 1269245431Sdim CurDAG->getTargetConstantFP(APF.convertToFloat(), MVT::f32)); 1270245431Sdim } 1271245431Sdim else if (N->getValueType(0) == MVT::f64) { 1272245431Sdim return CurDAG->getMachineNode(Hexagon::CONST64_Float_Real, dl, MVT::f64, 1273245431Sdim CurDAG->getTargetConstantFP(APF.convertToDouble(), MVT::f64)); 1274245431Sdim } 1275234285Sdim 1276245431Sdim return SelectCode(N); 1277245431Sdim} 1278245431Sdim 1279245431Sdim 1280234285Sdim// 1281234285Sdim// Map predicate true (encoded as -1 in LLVM) to a XOR. 1282234285Sdim// 1283234285SdimSDNode *HexagonDAGToDAGISel::SelectConstant(SDNode *N) { 1284263509Sdim SDLoc dl(N); 1285234285Sdim if (N->getValueType(0) == MVT::i1) { 1286234285Sdim SDNode* Result; 1287234285Sdim int32_t Val = cast<ConstantSDNode>(N)->getSExtValue(); 1288234285Sdim if (Val == -1) { 1289234285Sdim // Create the IntReg = 1 node. 1290234285Sdim SDNode* IntRegTFR = 1291234285Sdim CurDAG->getMachineNode(Hexagon::TFRI, dl, MVT::i32, 1292234285Sdim CurDAG->getTargetConstant(0, MVT::i32)); 1293234285Sdim 1294234285Sdim // Pd = IntReg 1295234285Sdim SDNode* Pd = CurDAG->getMachineNode(Hexagon::TFR_PdRs, dl, MVT::i1, 1296234285Sdim SDValue(IntRegTFR, 0)); 1297234285Sdim 1298234285Sdim // not(Pd) 1299234285Sdim SDNode* NotPd = CurDAG->getMachineNode(Hexagon::NOT_p, dl, MVT::i1, 1300234285Sdim SDValue(Pd, 0)); 1301234285Sdim 1302234285Sdim // xor(not(Pd)) 1303234285Sdim Result = CurDAG->getMachineNode(Hexagon::XOR_pp, dl, MVT::i1, 1304234285Sdim SDValue(Pd, 0), SDValue(NotPd, 0)); 1305234285Sdim 1306234285Sdim // We have just built: 1307234285Sdim // Rs = Pd 1308234285Sdim // Pd = xor(not(Pd), Pd) 1309234285Sdim 1310234285Sdim ReplaceUses(N, Result); 1311234285Sdim return Result; 1312234285Sdim } 1313234285Sdim } 1314234285Sdim 1315234285Sdim return SelectCode(N); 1316234285Sdim} 1317234285Sdim 1318234285Sdim 1319234285Sdim// 1320234285Sdim// Map add followed by a asr -> asr +=. 1321234285Sdim// 1322234285SdimSDNode *HexagonDAGToDAGISel::SelectAdd(SDNode *N) { 1323263509Sdim SDLoc dl(N); 1324234285Sdim if (N->getValueType(0) != MVT::i32) { 1325234285Sdim return SelectCode(N); 1326234285Sdim } 1327234285Sdim // Identify nodes of the form: add(asr(...)). 1328234285Sdim SDNode* Src1 = N->getOperand(0).getNode(); 1329234285Sdim if (Src1->getOpcode() != ISD::SRA || !Src1->hasOneUse() 1330234285Sdim || Src1->getValueType(0) != MVT::i32) { 1331234285Sdim return SelectCode(N); 1332234285Sdim } 1333234285Sdim 1334234285Sdim // Build Rd = Rd' + asr(Rs, Rt). The machine constraints will ensure that 1335234285Sdim // Rd and Rd' are assigned to the same register 1336245431Sdim SDNode* Result = CurDAG->getMachineNode(Hexagon::ASR_ADD_rr, dl, MVT::i32, 1337234285Sdim N->getOperand(1), 1338234285Sdim Src1->getOperand(0), 1339234285Sdim Src1->getOperand(1)); 1340234285Sdim ReplaceUses(N, Result); 1341234285Sdim 1342234285Sdim return Result; 1343234285Sdim} 1344234285Sdim 1345234285Sdim 1346234285SdimSDNode *HexagonDAGToDAGISel::Select(SDNode *N) { 1347255946Sdim if (N->isMachineOpcode()) { 1348255946Sdim N->setNodeId(-1); 1349234285Sdim return NULL; // Already selected. 1350255946Sdim } 1351234285Sdim 1352234285Sdim 1353234285Sdim switch (N->getOpcode()) { 1354234285Sdim case ISD::Constant: 1355234285Sdim return SelectConstant(N); 1356234285Sdim 1357245431Sdim case ISD::ConstantFP: 1358245431Sdim return SelectConstantFP(N); 1359245431Sdim 1360234285Sdim case ISD::ADD: 1361234285Sdim return SelectAdd(N); 1362234285Sdim 1363234285Sdim case ISD::SHL: 1364234285Sdim return SelectSHL(N); 1365234285Sdim 1366234285Sdim case ISD::LOAD: 1367234285Sdim return SelectLoad(N); 1368234285Sdim 1369234285Sdim case ISD::STORE: 1370234285Sdim return SelectStore(N); 1371234285Sdim 1372234285Sdim case ISD::SELECT: 1373234285Sdim return SelectSelect(N); 1374234285Sdim 1375234285Sdim case ISD::TRUNCATE: 1376234285Sdim return SelectTruncate(N); 1377234285Sdim 1378234285Sdim case ISD::MUL: 1379234285Sdim return SelectMul(N); 1380234285Sdim 1381234285Sdim case ISD::ZERO_EXTEND: 1382234285Sdim return SelectZeroExtend(N); 1383234285Sdim 1384234285Sdim case ISD::INTRINSIC_WO_CHAIN: 1385234285Sdim return SelectIntrinsicWOChain(N); 1386234285Sdim } 1387234285Sdim 1388234285Sdim return SelectCode(N); 1389234285Sdim} 1390234285Sdim 1391234285Sdim 1392234285Sdim// 1393234285Sdim// Hexagon_TODO: Five functions for ADDRri?! Surely there must be a better way 1394234285Sdim// to define these instructions. 1395234285Sdim// 1396234285Sdimbool HexagonDAGToDAGISel::SelectADDRri(SDValue& Addr, SDValue &Base, 1397234285Sdim SDValue &Offset) { 1398234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1399234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1400234285Sdim return false; // Direct calls. 1401234285Sdim 1402234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1403234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1404234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1405234285Sdim return true; 1406234285Sdim } 1407234285Sdim Base = Addr; 1408234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1409234285Sdim return true; 1410234285Sdim} 1411234285Sdim 1412234285Sdim 1413234285Sdimbool HexagonDAGToDAGISel::SelectADDRriS11_0(SDValue& Addr, SDValue &Base, 1414234285Sdim SDValue &Offset) { 1415234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1416234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1417234285Sdim return false; // Direct calls. 1418234285Sdim 1419234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1420234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1421234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1422234285Sdim return (IsS11_0_Offset(Offset.getNode())); 1423234285Sdim } 1424234285Sdim Base = Addr; 1425234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1426234285Sdim return (IsS11_0_Offset(Offset.getNode())); 1427234285Sdim} 1428234285Sdim 1429234285Sdim 1430234285Sdimbool HexagonDAGToDAGISel::SelectADDRriS11_1(SDValue& Addr, SDValue &Base, 1431234285Sdim SDValue &Offset) { 1432234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1433234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1434234285Sdim return false; // Direct calls. 1435234285Sdim 1436234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1437234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1438234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1439234285Sdim return (IsS11_1_Offset(Offset.getNode())); 1440234285Sdim } 1441234285Sdim Base = Addr; 1442234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1443234285Sdim return (IsS11_1_Offset(Offset.getNode())); 1444234285Sdim} 1445234285Sdim 1446234285Sdim 1447234285Sdimbool HexagonDAGToDAGISel::SelectADDRriS11_2(SDValue& Addr, SDValue &Base, 1448234285Sdim SDValue &Offset) { 1449234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1450234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1451234285Sdim return false; // Direct calls. 1452234285Sdim 1453234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1454234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1455234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1456234285Sdim return (IsS11_2_Offset(Offset.getNode())); 1457234285Sdim } 1458234285Sdim Base = Addr; 1459234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1460234285Sdim return (IsS11_2_Offset(Offset.getNode())); 1461234285Sdim} 1462234285Sdim 1463234285Sdim 1464234285Sdimbool HexagonDAGToDAGISel::SelectADDRriU6_0(SDValue& Addr, SDValue &Base, 1465234285Sdim SDValue &Offset) { 1466234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1467234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1468234285Sdim return false; // Direct calls. 1469234285Sdim 1470234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1471234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1472234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1473234285Sdim return (IsU6_0_Offset(Offset.getNode())); 1474234285Sdim } 1475234285Sdim Base = Addr; 1476234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1477234285Sdim return (IsU6_0_Offset(Offset.getNode())); 1478234285Sdim} 1479234285Sdim 1480234285Sdim 1481234285Sdimbool HexagonDAGToDAGISel::SelectADDRriU6_1(SDValue& Addr, SDValue &Base, 1482234285Sdim SDValue &Offset) { 1483234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1484234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1485234285Sdim return false; // Direct calls. 1486234285Sdim 1487234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1488234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1489234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1490234285Sdim return (IsU6_1_Offset(Offset.getNode())); 1491234285Sdim } 1492234285Sdim Base = Addr; 1493234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1494234285Sdim return (IsU6_1_Offset(Offset.getNode())); 1495234285Sdim} 1496234285Sdim 1497234285Sdim 1498234285Sdimbool HexagonDAGToDAGISel::SelectADDRriU6_2(SDValue& Addr, SDValue &Base, 1499234285Sdim SDValue &Offset) { 1500234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1501234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1502234285Sdim return false; // Direct calls. 1503234285Sdim 1504234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1505234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1506234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1507234285Sdim return (IsU6_2_Offset(Offset.getNode())); 1508234285Sdim } 1509234285Sdim Base = Addr; 1510234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1511234285Sdim return (IsU6_2_Offset(Offset.getNode())); 1512234285Sdim} 1513234285Sdim 1514234285Sdim 1515234285Sdimbool HexagonDAGToDAGISel::SelectMEMriS11_2(SDValue& Addr, SDValue &Base, 1516234285Sdim SDValue &Offset) { 1517234285Sdim 1518234285Sdim if (Addr.getOpcode() != ISD::ADD) { 1519234285Sdim return(SelectADDRriS11_2(Addr, Base, Offset)); 1520234285Sdim } 1521234285Sdim 1522234285Sdim return SelectADDRriS11_2(Addr, Base, Offset); 1523234285Sdim} 1524234285Sdim 1525234285Sdim 1526234285Sdimbool HexagonDAGToDAGISel::SelectADDRriS11_3(SDValue& Addr, SDValue &Base, 1527234285Sdim SDValue &Offset) { 1528234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1529234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1530234285Sdim return false; // Direct calls. 1531234285Sdim 1532234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1533234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1534234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1535234285Sdim return (IsS11_3_Offset(Offset.getNode())); 1536234285Sdim } 1537234285Sdim Base = Addr; 1538234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1539234285Sdim return (IsS11_3_Offset(Offset.getNode())); 1540234285Sdim} 1541234285Sdim 1542234285Sdimbool HexagonDAGToDAGISel::SelectADDRrr(SDValue &Addr, SDValue &R1, 1543234285Sdim SDValue &R2) { 1544234285Sdim if (Addr.getOpcode() == ISD::FrameIndex) return false; 1545234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1546234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1547234285Sdim return false; // Direct calls. 1548234285Sdim 1549234285Sdim if (Addr.getOpcode() == ISD::ADD) { 1550234285Sdim if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) 1551234285Sdim if (isInt<13>(CN->getSExtValue())) 1552234285Sdim return false; // Let the reg+imm pattern catch this! 1553234285Sdim R1 = Addr.getOperand(0); 1554234285Sdim R2 = Addr.getOperand(1); 1555234285Sdim return true; 1556234285Sdim } 1557234285Sdim 1558234285Sdim R1 = Addr; 1559234285Sdim 1560234285Sdim return true; 1561234285Sdim} 1562234285Sdim 1563234285Sdim 1564234285Sdim// Handle generic address case. It is accessed from inlined asm =m constraints, 1565234285Sdim// which could have any kind of pointer. 1566234285Sdimbool HexagonDAGToDAGISel::SelectAddr(SDNode *Op, SDValue Addr, 1567234285Sdim SDValue &Base, SDValue &Offset) { 1568234285Sdim if (Addr.getOpcode() == ISD::TargetExternalSymbol || 1569234285Sdim Addr.getOpcode() == ISD::TargetGlobalAddress) 1570234285Sdim return false; // Direct calls. 1571234285Sdim 1572234285Sdim if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1573234285Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 1574234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1575234285Sdim return true; 1576234285Sdim } 1577234285Sdim 1578234285Sdim if (Addr.getOpcode() == ISD::ADD) { 1579234285Sdim Base = Addr.getOperand(0); 1580234285Sdim Offset = Addr.getOperand(1); 1581234285Sdim return true; 1582234285Sdim } 1583234285Sdim 1584234285Sdim Base = Addr; 1585234285Sdim Offset = CurDAG->getTargetConstant(0, MVT::i32); 1586234285Sdim return true; 1587234285Sdim} 1588234285Sdim 1589234285Sdim 1590234285Sdimbool HexagonDAGToDAGISel:: 1591234285SdimSelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, 1592234285Sdim std::vector<SDValue> &OutOps) { 1593234285Sdim SDValue Op0, Op1; 1594234285Sdim 1595234285Sdim switch (ConstraintCode) { 1596234285Sdim case 'o': // Offsetable. 1597234285Sdim case 'v': // Not offsetable. 1598234285Sdim default: return true; 1599234285Sdim case 'm': // Memory. 1600234285Sdim if (!SelectAddr(Op.getNode(), Op, Op0, Op1)) 1601234285Sdim return true; 1602234285Sdim break; 1603234285Sdim } 1604234285Sdim 1605234285Sdim OutOps.push_back(Op0); 1606234285Sdim OutOps.push_back(Op1); 1607234285Sdim return false; 1608234285Sdim} 1609252723Sdim 1610252723Sdimbool HexagonDAGToDAGISel::isConstExtProfitable(SDNode *N) const { 1611252723Sdim unsigned UseCount = 0; 1612252723Sdim for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) { 1613252723Sdim UseCount++; 1614252723Sdim } 1615252723Sdim 1616252723Sdim return (UseCount <= 1); 1617252723Sdim 1618252723Sdim} 1619252723Sdim 1620252723Sdim//===--------------------------------------------------------------------===// 1621252723Sdim// Return 'true' if use count of the global address is below threshold. 1622252723Sdim//===--------------------------------------------------------------------===// 1623252723Sdimbool HexagonDAGToDAGISel::hasNumUsesBelowThresGA(SDNode *N) const { 1624252723Sdim assert(N->getOpcode() == ISD::TargetGlobalAddress && 1625252723Sdim "Expecting a target global address"); 1626252723Sdim 1627252723Sdim // Always try to fold the address. 1628252723Sdim if (TM.getOptLevel() == CodeGenOpt::Aggressive) 1629252723Sdim return true; 1630252723Sdim 1631252723Sdim GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N); 1632252723Sdim DenseMap<const GlobalValue *, unsigned>::const_iterator GI = 1633252723Sdim GlobalAddressUseCountMap.find(GA->getGlobal()); 1634252723Sdim 1635252723Sdim if (GI == GlobalAddressUseCountMap.end()) 1636252723Sdim return false; 1637252723Sdim 1638252723Sdim return GI->second <= MaxNumOfUsesForConstExtenders; 1639252723Sdim} 1640252723Sdim 1641252723Sdim//===--------------------------------------------------------------------===// 1642252723Sdim// Return true if the non GP-relative global address can be folded. 1643252723Sdim//===--------------------------------------------------------------------===// 1644252723Sdiminline bool HexagonDAGToDAGISel::foldGlobalAddress(SDValue &N, SDValue &R) { 1645252723Sdim return foldGlobalAddressImpl(N, R, false); 1646252723Sdim} 1647252723Sdim 1648252723Sdim//===--------------------------------------------------------------------===// 1649252723Sdim// Return true if the GP-relative global address can be folded. 1650252723Sdim//===--------------------------------------------------------------------===// 1651252723Sdiminline bool HexagonDAGToDAGISel::foldGlobalAddressGP(SDValue &N, SDValue &R) { 1652252723Sdim return foldGlobalAddressImpl(N, R, true); 1653252723Sdim} 1654252723Sdim 1655252723Sdim//===--------------------------------------------------------------------===// 1656252723Sdim// Fold offset of the global address if number of uses are below threshold. 1657252723Sdim//===--------------------------------------------------------------------===// 1658252723Sdimbool HexagonDAGToDAGISel::foldGlobalAddressImpl(SDValue &N, SDValue &R, 1659252723Sdim bool ShouldLookForGP) { 1660252723Sdim if (N.getOpcode() == ISD::ADD) { 1661252723Sdim SDValue N0 = N.getOperand(0); 1662252723Sdim SDValue N1 = N.getOperand(1); 1663252723Sdim if ((ShouldLookForGP && (N0.getOpcode() == HexagonISD::CONST32_GP)) || 1664252723Sdim (!ShouldLookForGP && (N0.getOpcode() == HexagonISD::CONST32))) { 1665252723Sdim ConstantSDNode *Const = dyn_cast<ConstantSDNode>(N1); 1666252723Sdim GlobalAddressSDNode *GA = 1667252723Sdim dyn_cast<GlobalAddressSDNode>(N0.getOperand(0)); 1668252723Sdim 1669252723Sdim if (Const && GA && 1670252723Sdim (GA->getOpcode() == ISD::TargetGlobalAddress)) { 1671252723Sdim if ((N0.getOpcode() == HexagonISD::CONST32) && 1672252723Sdim !hasNumUsesBelowThresGA(GA)) 1673252723Sdim return false; 1674252723Sdim R = CurDAG->getTargetGlobalAddress(GA->getGlobal(), 1675263509Sdim SDLoc(Const), 1676252723Sdim N.getValueType(), 1677252723Sdim GA->getOffset() + 1678252723Sdim (uint64_t)Const->getSExtValue()); 1679252723Sdim return true; 1680252723Sdim } 1681252723Sdim } 1682252723Sdim } 1683252723Sdim return false; 1684252723Sdim} 1685