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