1249259Sdim//===-- MipsSEISelLowering.cpp - MipsSE DAG Lowering Interface --*- C++ -*-===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// Subclass of MipsTargetLowering specialized for mips32/64.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim#include "MipsSEISelLowering.h"
14249259Sdim#include "MipsRegisterInfo.h"
15249259Sdim#include "MipsTargetMachine.h"
16249259Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
17249259Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
18251662Sdim#include "llvm/IR/Intrinsics.h"
19249259Sdim#include "llvm/Support/CommandLine.h"
20249259Sdim#include "llvm/Target/TargetInstrInfo.h"
21249259Sdim
22249259Sdimusing namespace llvm;
23249259Sdim
24249259Sdimstatic cl::opt<bool>
25249259SdimEnableMipsTailCalls("enable-mips-tail-calls", cl::Hidden,
26249259Sdim                    cl::desc("MIPS: Enable tail calls."), cl::init(false));
27249259Sdim
28249259SdimMipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM)
29249259Sdim  : MipsTargetLowering(TM) {
30249259Sdim  // Set up the register classes
31251662Sdim
32251662Sdim  clearRegisterClasses();
33251662Sdim
34249259Sdim  addRegisterClass(MVT::i32, &Mips::CPURegsRegClass);
35249259Sdim
36249259Sdim  if (HasMips64)
37249259Sdim    addRegisterClass(MVT::i64, &Mips::CPU64RegsRegClass);
38249259Sdim
39249259Sdim  if (Subtarget->hasDSP()) {
40249259Sdim    MVT::SimpleValueType VecTys[2] = {MVT::v2i16, MVT::v4i8};
41249259Sdim
42249259Sdim    for (unsigned i = 0; i < array_lengthof(VecTys); ++i) {
43249259Sdim      addRegisterClass(VecTys[i], &Mips::DSPRegsRegClass);
44249259Sdim
45249259Sdim      // Expand all builtin opcodes.
46249259Sdim      for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
47249259Sdim        setOperationAction(Opc, VecTys[i], Expand);
48249259Sdim
49251662Sdim      setOperationAction(ISD::ADD, VecTys[i], Legal);
50251662Sdim      setOperationAction(ISD::SUB, VecTys[i], Legal);
51249259Sdim      setOperationAction(ISD::LOAD, VecTys[i], Legal);
52249259Sdim      setOperationAction(ISD::STORE, VecTys[i], Legal);
53249259Sdim      setOperationAction(ISD::BITCAST, VecTys[i], Legal);
54249259Sdim    }
55251662Sdim
56251662Sdim    setTargetDAGCombine(ISD::SHL);
57251662Sdim    setTargetDAGCombine(ISD::SRA);
58251662Sdim    setTargetDAGCombine(ISD::SRL);
59251662Sdim    setTargetDAGCombine(ISD::SETCC);
60251662Sdim    setTargetDAGCombine(ISD::VSELECT);
61249259Sdim  }
62249259Sdim
63251662Sdim  if (Subtarget->hasDSPR2())
64251662Sdim    setOperationAction(ISD::MUL, MVT::v2i16, Legal);
65251662Sdim
66249259Sdim  if (!TM.Options.UseSoftFloat) {
67249259Sdim    addRegisterClass(MVT::f32, &Mips::FGR32RegClass);
68249259Sdim
69249259Sdim    // When dealing with single precision only, use libcalls
70249259Sdim    if (!Subtarget->isSingleFloat()) {
71249259Sdim      if (HasMips64)
72249259Sdim        addRegisterClass(MVT::f64, &Mips::FGR64RegClass);
73249259Sdim      else
74249259Sdim        addRegisterClass(MVT::f64, &Mips::AFGR64RegClass);
75249259Sdim    }
76249259Sdim  }
77249259Sdim
78249259Sdim  setOperationAction(ISD::SMUL_LOHI,          MVT::i32, Custom);
79249259Sdim  setOperationAction(ISD::UMUL_LOHI,          MVT::i32, Custom);
80249259Sdim  setOperationAction(ISD::MULHS,              MVT::i32, Custom);
81249259Sdim  setOperationAction(ISD::MULHU,              MVT::i32, Custom);
82249259Sdim
83251662Sdim  if (HasMips64) {
84251662Sdim    setOperationAction(ISD::MULHS,            MVT::i64, Custom);
85251662Sdim    setOperationAction(ISD::MULHU,            MVT::i64, Custom);
86249259Sdim    setOperationAction(ISD::MUL,              MVT::i64, Custom);
87251662Sdim  }
88249259Sdim
89251662Sdim  setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom);
90251662Sdim  setOperationAction(ISD::INTRINSIC_W_CHAIN,  MVT::i64, Custom);
91251662Sdim
92249259Sdim  setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
93249259Sdim  setOperationAction(ISD::UDIVREM, MVT::i32, Custom);
94249259Sdim  setOperationAction(ISD::SDIVREM, MVT::i64, Custom);
95249259Sdim  setOperationAction(ISD::UDIVREM, MVT::i64, Custom);
96249259Sdim  setOperationAction(ISD::ATOMIC_FENCE,       MVT::Other, Custom);
97249259Sdim  setOperationAction(ISD::LOAD,               MVT::i32, Custom);
98249259Sdim  setOperationAction(ISD::STORE,              MVT::i32, Custom);
99249259Sdim
100249259Sdim  setTargetDAGCombine(ISD::ADDE);
101249259Sdim  setTargetDAGCombine(ISD::SUBE);
102249259Sdim
103249259Sdim  computeRegisterProperties();
104249259Sdim}
105249259Sdim
106249259Sdimconst MipsTargetLowering *
107249259Sdimllvm::createMipsSETargetLowering(MipsTargetMachine &TM) {
108249259Sdim  return new MipsSETargetLowering(TM);
109249259Sdim}
110249259Sdim
111249259Sdim
112249259Sdimbool
113249259SdimMipsSETargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const {
114249259Sdim  MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy;
115249259Sdim
116249259Sdim  switch (SVT) {
117249259Sdim  case MVT::i64:
118249259Sdim  case MVT::i32:
119249259Sdim    if (Fast)
120249259Sdim      *Fast = true;
121249259Sdim    return true;
122249259Sdim  default:
123249259Sdim    return false;
124249259Sdim  }
125249259Sdim}
126249259Sdim
127249259SdimSDValue MipsSETargetLowering::LowerOperation(SDValue Op,
128249259Sdim                                             SelectionDAG &DAG) const {
129249259Sdim  switch(Op.getOpcode()) {
130249259Sdim  case ISD::SMUL_LOHI: return lowerMulDiv(Op, MipsISD::Mult, true, true, DAG);
131249259Sdim  case ISD::UMUL_LOHI: return lowerMulDiv(Op, MipsISD::Multu, true, true, DAG);
132249259Sdim  case ISD::MULHS:     return lowerMulDiv(Op, MipsISD::Mult, false, true, DAG);
133249259Sdim  case ISD::MULHU:     return lowerMulDiv(Op, MipsISD::Multu, false, true, DAG);
134249259Sdim  case ISD::MUL:       return lowerMulDiv(Op, MipsISD::Mult, true, false, DAG);
135249259Sdim  case ISD::SDIVREM:   return lowerMulDiv(Op, MipsISD::DivRem, true, true, DAG);
136251662Sdim  case ISD::UDIVREM:   return lowerMulDiv(Op, MipsISD::DivRemU, true, true,
137251662Sdim                                          DAG);
138251662Sdim  case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG);
139251662Sdim  case ISD::INTRINSIC_W_CHAIN:  return lowerINTRINSIC_W_CHAIN(Op, DAG);
140249259Sdim  }
141249259Sdim
142249259Sdim  return MipsTargetLowering::LowerOperation(Op, DAG);
143249259Sdim}
144249259Sdim
145249259Sdim// selectMADD -
146249259Sdim// Transforms a subgraph in CurDAG if the following pattern is found:
147249259Sdim//  (addc multLo, Lo0), (adde multHi, Hi0),
148249259Sdim// where,
149249259Sdim//  multHi/Lo: product of multiplication
150249259Sdim//  Lo0: initial value of Lo register
151249259Sdim//  Hi0: initial value of Hi register
152249259Sdim// Return true if pattern matching was successful.
153249259Sdimstatic bool selectMADD(SDNode *ADDENode, SelectionDAG *CurDAG) {
154249259Sdim  // ADDENode's second operand must be a flag output of an ADDC node in order
155249259Sdim  // for the matching to be successful.
156249259Sdim  SDNode *ADDCNode = ADDENode->getOperand(2).getNode();
157249259Sdim
158249259Sdim  if (ADDCNode->getOpcode() != ISD::ADDC)
159249259Sdim    return false;
160249259Sdim
161249259Sdim  SDValue MultHi = ADDENode->getOperand(0);
162249259Sdim  SDValue MultLo = ADDCNode->getOperand(0);
163249259Sdim  SDNode *MultNode = MultHi.getNode();
164249259Sdim  unsigned MultOpc = MultHi.getOpcode();
165249259Sdim
166249259Sdim  // MultHi and MultLo must be generated by the same node,
167249259Sdim  if (MultLo.getNode() != MultNode)
168249259Sdim    return false;
169249259Sdim
170249259Sdim  // and it must be a multiplication.
171249259Sdim  if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI)
172249259Sdim    return false;
173249259Sdim
174249259Sdim  // MultLo amd MultHi must be the first and second output of MultNode
175249259Sdim  // respectively.
176249259Sdim  if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0)
177249259Sdim    return false;
178249259Sdim
179249259Sdim  // Transform this to a MADD only if ADDENode and ADDCNode are the only users
180249259Sdim  // of the values of MultNode, in which case MultNode will be removed in later
181249259Sdim  // phases.
182249259Sdim  // If there exist users other than ADDENode or ADDCNode, this function returns
183249259Sdim  // here, which will result in MultNode being mapped to a single MULT
184249259Sdim  // instruction node rather than a pair of MULT and MADD instructions being
185249259Sdim  // produced.
186249259Sdim  if (!MultHi.hasOneUse() || !MultLo.hasOneUse())
187249259Sdim    return false;
188249259Sdim
189249259Sdim  DebugLoc DL = ADDENode->getDebugLoc();
190249259Sdim
191249259Sdim  // Initialize accumulator.
192249259Sdim  SDValue ACCIn = CurDAG->getNode(MipsISD::InsertLOHI, DL, MVT::Untyped,
193249259Sdim                                  ADDCNode->getOperand(1),
194249259Sdim                                  ADDENode->getOperand(1));
195249259Sdim
196249259Sdim  // create MipsMAdd(u) node
197249259Sdim  MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MAddu : MipsISD::MAdd;
198249259Sdim
199249259Sdim  SDValue MAdd = CurDAG->getNode(MultOpc, DL, MVT::Untyped,
200249259Sdim                                 MultNode->getOperand(0),// Factor 0
201249259Sdim                                 MultNode->getOperand(1),// Factor 1
202249259Sdim                                 ACCIn);
203249259Sdim
204249259Sdim  // replace uses of adde and addc here
205249259Sdim  if (!SDValue(ADDCNode, 0).use_empty()) {
206249259Sdim    SDValue LoIdx = CurDAG->getConstant(Mips::sub_lo, MVT::i32);
207249259Sdim    SDValue LoOut = CurDAG->getNode(MipsISD::ExtractLOHI, DL, MVT::i32, MAdd,
208249259Sdim                                    LoIdx);
209249259Sdim    CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDCNode, 0), LoOut);
210249259Sdim  }
211249259Sdim  if (!SDValue(ADDENode, 0).use_empty()) {
212249259Sdim    SDValue HiIdx = CurDAG->getConstant(Mips::sub_hi, MVT::i32);
213249259Sdim    SDValue HiOut = CurDAG->getNode(MipsISD::ExtractLOHI, DL, MVT::i32, MAdd,
214249259Sdim                                    HiIdx);
215249259Sdim    CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDENode, 0), HiOut);
216249259Sdim  }
217249259Sdim
218249259Sdim  return true;
219249259Sdim}
220249259Sdim
221249259Sdim// selectMSUB -
222249259Sdim// Transforms a subgraph in CurDAG if the following pattern is found:
223249259Sdim//  (addc Lo0, multLo), (sube Hi0, multHi),
224249259Sdim// where,
225249259Sdim//  multHi/Lo: product of multiplication
226249259Sdim//  Lo0: initial value of Lo register
227249259Sdim//  Hi0: initial value of Hi register
228249259Sdim// Return true if pattern matching was successful.
229249259Sdimstatic bool selectMSUB(SDNode *SUBENode, SelectionDAG *CurDAG) {
230249259Sdim  // SUBENode's second operand must be a flag output of an SUBC node in order
231249259Sdim  // for the matching to be successful.
232249259Sdim  SDNode *SUBCNode = SUBENode->getOperand(2).getNode();
233249259Sdim
234249259Sdim  if (SUBCNode->getOpcode() != ISD::SUBC)
235249259Sdim    return false;
236249259Sdim
237249259Sdim  SDValue MultHi = SUBENode->getOperand(1);
238249259Sdim  SDValue MultLo = SUBCNode->getOperand(1);
239249259Sdim  SDNode *MultNode = MultHi.getNode();
240249259Sdim  unsigned MultOpc = MultHi.getOpcode();
241249259Sdim
242249259Sdim  // MultHi and MultLo must be generated by the same node,
243249259Sdim  if (MultLo.getNode() != MultNode)
244249259Sdim    return false;
245249259Sdim
246249259Sdim  // and it must be a multiplication.
247249259Sdim  if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI)
248249259Sdim    return false;
249249259Sdim
250249259Sdim  // MultLo amd MultHi must be the first and second output of MultNode
251249259Sdim  // respectively.
252249259Sdim  if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0)
253249259Sdim    return false;
254249259Sdim
255249259Sdim  // Transform this to a MSUB only if SUBENode and SUBCNode are the only users
256249259Sdim  // of the values of MultNode, in which case MultNode will be removed in later
257249259Sdim  // phases.
258249259Sdim  // If there exist users other than SUBENode or SUBCNode, this function returns
259249259Sdim  // here, which will result in MultNode being mapped to a single MULT
260249259Sdim  // instruction node rather than a pair of MULT and MSUB instructions being
261249259Sdim  // produced.
262249259Sdim  if (!MultHi.hasOneUse() || !MultLo.hasOneUse())
263249259Sdim    return false;
264249259Sdim
265249259Sdim  DebugLoc DL = SUBENode->getDebugLoc();
266249259Sdim
267249259Sdim  // Initialize accumulator.
268249259Sdim  SDValue ACCIn = CurDAG->getNode(MipsISD::InsertLOHI, DL, MVT::Untyped,
269249259Sdim                                  SUBCNode->getOperand(0),
270249259Sdim                                  SUBENode->getOperand(0));
271249259Sdim
272249259Sdim  // create MipsSub(u) node
273249259Sdim  MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub;
274249259Sdim
275249259Sdim  SDValue MSub = CurDAG->getNode(MultOpc, DL, MVT::Glue,
276249259Sdim                                 MultNode->getOperand(0),// Factor 0
277249259Sdim                                 MultNode->getOperand(1),// Factor 1
278249259Sdim                                 ACCIn);
279249259Sdim
280249259Sdim  // replace uses of sube and subc here
281249259Sdim  if (!SDValue(SUBCNode, 0).use_empty()) {
282249259Sdim    SDValue LoIdx = CurDAG->getConstant(Mips::sub_lo, MVT::i32);
283249259Sdim    SDValue LoOut = CurDAG->getNode(MipsISD::ExtractLOHI, DL, MVT::i32, MSub,
284249259Sdim                                    LoIdx);
285249259Sdim    CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBCNode, 0), LoOut);
286249259Sdim  }
287249259Sdim  if (!SDValue(SUBENode, 0).use_empty()) {
288249259Sdim    SDValue HiIdx = CurDAG->getConstant(Mips::sub_hi, MVT::i32);
289249259Sdim    SDValue HiOut = CurDAG->getNode(MipsISD::ExtractLOHI, DL, MVT::i32, MSub,
290249259Sdim                                    HiIdx);
291249259Sdim    CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBENode, 0), HiOut);
292249259Sdim  }
293249259Sdim
294249259Sdim  return true;
295249259Sdim}
296249259Sdim
297249259Sdimstatic SDValue performADDECombine(SDNode *N, SelectionDAG &DAG,
298249259Sdim                                  TargetLowering::DAGCombinerInfo &DCI,
299249259Sdim                                  const MipsSubtarget *Subtarget) {
300249259Sdim  if (DCI.isBeforeLegalize())
301249259Sdim    return SDValue();
302249259Sdim
303249259Sdim  if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 &&
304249259Sdim      selectMADD(N, &DAG))
305249259Sdim    return SDValue(N, 0);
306249259Sdim
307249259Sdim  return SDValue();
308249259Sdim}
309249259Sdim
310249259Sdimstatic SDValue performSUBECombine(SDNode *N, SelectionDAG &DAG,
311249259Sdim                                  TargetLowering::DAGCombinerInfo &DCI,
312249259Sdim                                  const MipsSubtarget *Subtarget) {
313249259Sdim  if (DCI.isBeforeLegalize())
314249259Sdim    return SDValue();
315249259Sdim
316249259Sdim  if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 &&
317249259Sdim      selectMSUB(N, &DAG))
318249259Sdim    return SDValue(N, 0);
319249259Sdim
320249259Sdim  return SDValue();
321249259Sdim}
322249259Sdim
323251662Sdimstatic SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty,
324251662Sdim                                      SelectionDAG &DAG,
325251662Sdim                                      const MipsSubtarget *Subtarget) {
326251662Sdim  // See if this is a vector splat immediate node.
327251662Sdim  APInt SplatValue, SplatUndef;
328251662Sdim  unsigned SplatBitSize;
329251662Sdim  bool HasAnyUndefs;
330251662Sdim  unsigned EltSize = Ty.getVectorElementType().getSizeInBits();
331251662Sdim  BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N->getOperand(1));
332251662Sdim
333251662Sdim  if (!BV ||
334251662Sdim      !BV->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
335251662Sdim                           EltSize, !Subtarget->isLittle()) ||
336251662Sdim      (SplatBitSize != EltSize) ||
337251662Sdim      (SplatValue.getZExtValue() >= EltSize))
338251662Sdim    return SDValue();
339251662Sdim
340251662Sdim  return DAG.getNode(Opc, N->getDebugLoc(), Ty, N->getOperand(0),
341251662Sdim                     DAG.getConstant(SplatValue.getZExtValue(), MVT::i32));
342251662Sdim}
343251662Sdim
344251662Sdimstatic SDValue performSHLCombine(SDNode *N, SelectionDAG &DAG,
345251662Sdim                                 TargetLowering::DAGCombinerInfo &DCI,
346251662Sdim                                 const MipsSubtarget *Subtarget) {
347251662Sdim  EVT Ty = N->getValueType(0);
348251662Sdim
349251662Sdim  if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8))
350251662Sdim    return SDValue();
351251662Sdim
352251662Sdim  return performDSPShiftCombine(MipsISD::SHLL_DSP, N, Ty, DAG, Subtarget);
353251662Sdim}
354251662Sdim
355251662Sdimstatic SDValue performSRACombine(SDNode *N, SelectionDAG &DAG,
356251662Sdim                                 TargetLowering::DAGCombinerInfo &DCI,
357251662Sdim                                 const MipsSubtarget *Subtarget) {
358251662Sdim  EVT Ty = N->getValueType(0);
359251662Sdim
360251662Sdim  if ((Ty != MVT::v2i16) && ((Ty != MVT::v4i8) || !Subtarget->hasDSPR2()))
361251662Sdim    return SDValue();
362251662Sdim
363251662Sdim  return performDSPShiftCombine(MipsISD::SHRA_DSP, N, Ty, DAG, Subtarget);
364251662Sdim}
365251662Sdim
366251662Sdim
367251662Sdimstatic SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
368251662Sdim                                 TargetLowering::DAGCombinerInfo &DCI,
369251662Sdim                                 const MipsSubtarget *Subtarget) {
370251662Sdim  EVT Ty = N->getValueType(0);
371251662Sdim
372251662Sdim  if (((Ty != MVT::v2i16) || !Subtarget->hasDSPR2()) && (Ty != MVT::v4i8))
373251662Sdim    return SDValue();
374251662Sdim
375251662Sdim  return performDSPShiftCombine(MipsISD::SHRL_DSP, N, Ty, DAG, Subtarget);
376251662Sdim}
377251662Sdim
378251662Sdimstatic bool isLegalDSPCondCode(EVT Ty, ISD::CondCode CC) {
379251662Sdim  bool IsV216 = (Ty == MVT::v2i16);
380251662Sdim
381251662Sdim  switch (CC) {
382251662Sdim  case ISD::SETEQ:
383251662Sdim  case ISD::SETNE:  return true;
384251662Sdim  case ISD::SETLT:
385251662Sdim  case ISD::SETLE:
386251662Sdim  case ISD::SETGT:
387251662Sdim  case ISD::SETGE:  return IsV216;
388251662Sdim  case ISD::SETULT:
389251662Sdim  case ISD::SETULE:
390251662Sdim  case ISD::SETUGT:
391251662Sdim  case ISD::SETUGE: return !IsV216;
392251662Sdim  default:          return false;
393251662Sdim  }
394251662Sdim}
395251662Sdim
396251662Sdimstatic SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG) {
397251662Sdim  EVT Ty = N->getValueType(0);
398251662Sdim
399251662Sdim  if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8))
400251662Sdim    return SDValue();
401251662Sdim
402251662Sdim  if (!isLegalDSPCondCode(Ty, cast<CondCodeSDNode>(N->getOperand(2))->get()))
403251662Sdim    return SDValue();
404251662Sdim
405251662Sdim  return DAG.getNode(MipsISD::SETCC_DSP, N->getDebugLoc(), Ty, N->getOperand(0),
406251662Sdim                     N->getOperand(1), N->getOperand(2));
407251662Sdim}
408251662Sdim
409251662Sdimstatic SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) {
410251662Sdim  EVT Ty = N->getValueType(0);
411251662Sdim
412251662Sdim  if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8))
413251662Sdim    return SDValue();
414251662Sdim
415251662Sdim  SDValue SetCC = N->getOperand(0);
416251662Sdim
417251662Sdim  if (SetCC.getOpcode() != MipsISD::SETCC_DSP)
418251662Sdim    return SDValue();
419251662Sdim
420251662Sdim  return DAG.getNode(MipsISD::SELECT_CC_DSP, N->getDebugLoc(), Ty,
421251662Sdim                     SetCC.getOperand(0), SetCC.getOperand(1), N->getOperand(1),
422251662Sdim                     N->getOperand(2), SetCC.getOperand(2));
423251662Sdim}
424251662Sdim
425249259SdimSDValue
426249259SdimMipsSETargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const {
427249259Sdim  SelectionDAG &DAG = DCI.DAG;
428251662Sdim  SDValue Val;
429249259Sdim
430249259Sdim  switch (N->getOpcode()) {
431249259Sdim  case ISD::ADDE:
432249259Sdim    return performADDECombine(N, DAG, DCI, Subtarget);
433249259Sdim  case ISD::SUBE:
434249259Sdim    return performSUBECombine(N, DAG, DCI, Subtarget);
435251662Sdim  case ISD::SHL:
436251662Sdim    return performSHLCombine(N, DAG, DCI, Subtarget);
437251662Sdim  case ISD::SRA:
438251662Sdim    return performSRACombine(N, DAG, DCI, Subtarget);
439251662Sdim  case ISD::SRL:
440251662Sdim    return performSRLCombine(N, DAG, DCI, Subtarget);
441251662Sdim  case ISD::VSELECT:
442251662Sdim    return performVSELECTCombine(N, DAG);
443251662Sdim  case ISD::SETCC: {
444251662Sdim    Val = performSETCCCombine(N, DAG);
445251662Sdim    break;
446249259Sdim  }
447251662Sdim  }
448251662Sdim
449251662Sdim  if (Val.getNode())
450251662Sdim    return Val;
451251662Sdim
452251662Sdim  return MipsTargetLowering::PerformDAGCombine(N, DCI);
453249259Sdim}
454249259Sdim
455249259SdimMachineBasicBlock *
456249259SdimMipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
457249259Sdim                                                  MachineBasicBlock *BB) const {
458249259Sdim  switch (MI->getOpcode()) {
459249259Sdim  default:
460249259Sdim    return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB);
461249259Sdim  case Mips::BPOSGE32_PSEUDO:
462249259Sdim    return emitBPOSGE32(MI, BB);
463249259Sdim  }
464249259Sdim}
465249259Sdim
466249259Sdimbool MipsSETargetLowering::
467249259SdimisEligibleForTailCallOptimization(const MipsCC &MipsCCInfo,
468249259Sdim                                  unsigned NextStackOffset,
469249259Sdim                                  const MipsFunctionInfo& FI) const {
470249259Sdim  if (!EnableMipsTailCalls)
471249259Sdim    return false;
472249259Sdim
473249259Sdim  // Return false if either the callee or caller has a byval argument.
474249259Sdim  if (MipsCCInfo.hasByValArg() || FI.hasByvalArg())
475249259Sdim    return false;
476249259Sdim
477249259Sdim  // Return true if the callee's argument area is no larger than the
478249259Sdim  // caller's.
479249259Sdim  return NextStackOffset <= FI.getIncomingArgSize();
480249259Sdim}
481249259Sdim
482249259Sdimvoid MipsSETargetLowering::
483249259SdimgetOpndList(SmallVectorImpl<SDValue> &Ops,
484249259Sdim            std::deque< std::pair<unsigned, SDValue> > &RegsToPass,
485249259Sdim            bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage,
486249259Sdim            CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const {
487249259Sdim  // T9 should contain the address of the callee function if
488249259Sdim  // -reloction-model=pic or it is an indirect call.
489249259Sdim  if (IsPICCall || !GlobalOrExternal) {
490249259Sdim    unsigned T9Reg = IsN64 ? Mips::T9_64 : Mips::T9;
491249259Sdim    RegsToPass.push_front(std::make_pair(T9Reg, Callee));
492249259Sdim  } else
493249259Sdim    Ops.push_back(Callee);
494249259Sdim
495249259Sdim  MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal,
496249259Sdim                                  InternalLinkage, CLI, Callee, Chain);
497249259Sdim}
498249259Sdim
499249259SdimSDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc,
500249259Sdim                                          bool HasLo, bool HasHi,
501249259Sdim                                          SelectionDAG &DAG) const {
502249259Sdim  EVT Ty = Op.getOperand(0).getValueType();
503249259Sdim  DebugLoc DL = Op.getDebugLoc();
504249259Sdim  SDValue Mult = DAG.getNode(NewOpc, DL, MVT::Untyped,
505249259Sdim                             Op.getOperand(0), Op.getOperand(1));
506249259Sdim  SDValue Lo, Hi;
507249259Sdim
508249259Sdim  if (HasLo)
509249259Sdim    Lo = DAG.getNode(MipsISD::ExtractLOHI, DL, Ty, Mult,
510249259Sdim                     DAG.getConstant(Mips::sub_lo, MVT::i32));
511249259Sdim  if (HasHi)
512249259Sdim    Hi = DAG.getNode(MipsISD::ExtractLOHI, DL, Ty, Mult,
513249259Sdim                     DAG.getConstant(Mips::sub_hi, MVT::i32));
514249259Sdim
515249259Sdim  if (!HasLo || !HasHi)
516249259Sdim    return HasLo ? Lo : Hi;
517249259Sdim
518249259Sdim  SDValue Vals[] = { Lo, Hi };
519249259Sdim  return DAG.getMergeValues(Vals, 2, DL);
520249259Sdim}
521249259Sdim
522251662Sdim
523251662Sdimstatic SDValue initAccumulator(SDValue In, DebugLoc DL, SelectionDAG &DAG) {
524251662Sdim  SDValue InLo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In,
525251662Sdim                             DAG.getConstant(0, MVT::i32));
526251662Sdim  SDValue InHi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In,
527251662Sdim                             DAG.getConstant(1, MVT::i32));
528251662Sdim  return DAG.getNode(MipsISD::InsertLOHI, DL, MVT::Untyped, InLo, InHi);
529251662Sdim}
530251662Sdim
531251662Sdimstatic SDValue extractLOHI(SDValue Op, DebugLoc DL, SelectionDAG &DAG) {
532251662Sdim  SDValue Lo = DAG.getNode(MipsISD::ExtractLOHI, DL, MVT::i32, Op,
533251662Sdim                           DAG.getConstant(Mips::sub_lo, MVT::i32));
534251662Sdim  SDValue Hi = DAG.getNode(MipsISD::ExtractLOHI, DL, MVT::i32, Op,
535251662Sdim                           DAG.getConstant(Mips::sub_hi, MVT::i32));
536251662Sdim  return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi);
537251662Sdim}
538251662Sdim
539251662Sdim// This function expands mips intrinsic nodes which have 64-bit input operands
540251662Sdim// or output values.
541251662Sdim//
542251662Sdim// out64 = intrinsic-node in64
543251662Sdim// =>
544251662Sdim// lo = copy (extract-element (in64, 0))
545251662Sdim// hi = copy (extract-element (in64, 1))
546251662Sdim// mips-specific-node
547251662Sdim// v0 = copy lo
548251662Sdim// v1 = copy hi
549251662Sdim// out64 = merge-values (v0, v1)
550251662Sdim//
551251662Sdimstatic SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) {
552251662Sdim  DebugLoc DL = Op.getDebugLoc();
553251662Sdim  bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other;
554251662Sdim  SmallVector<SDValue, 3> Ops;
555251662Sdim  unsigned OpNo = 0;
556251662Sdim
557251662Sdim  // See if Op has a chain input.
558251662Sdim  if (HasChainIn)
559251662Sdim    Ops.push_back(Op->getOperand(OpNo++));
560251662Sdim
561251662Sdim  // The next operand is the intrinsic opcode.
562251662Sdim  assert(Op->getOperand(OpNo).getOpcode() == ISD::TargetConstant);
563251662Sdim
564251662Sdim  // See if the next operand has type i64.
565251662Sdim  SDValue Opnd = Op->getOperand(++OpNo), In64;
566251662Sdim
567251662Sdim  if (Opnd.getValueType() == MVT::i64)
568251662Sdim    In64 = initAccumulator(Opnd, DL, DAG);
569251662Sdim  else
570251662Sdim    Ops.push_back(Opnd);
571251662Sdim
572251662Sdim  // Push the remaining operands.
573251662Sdim  for (++OpNo ; OpNo < Op->getNumOperands(); ++OpNo)
574251662Sdim    Ops.push_back(Op->getOperand(OpNo));
575251662Sdim
576251662Sdim  // Add In64 to the end of the list.
577251662Sdim  if (In64.getNode())
578251662Sdim    Ops.push_back(In64);
579251662Sdim
580251662Sdim  // Scan output.
581251662Sdim  SmallVector<EVT, 2> ResTys;
582251662Sdim
583251662Sdim  for (SDNode::value_iterator I = Op->value_begin(), E = Op->value_end();
584251662Sdim       I != E; ++I)
585251662Sdim    ResTys.push_back((*I == MVT::i64) ? MVT::Untyped : *I);
586251662Sdim
587251662Sdim  // Create node.
588251662Sdim  SDValue Val = DAG.getNode(Opc, DL, ResTys, &Ops[0], Ops.size());
589251662Sdim  SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val;
590251662Sdim
591251662Sdim  if (!HasChainIn)
592251662Sdim    return Out;
593251662Sdim
594251662Sdim  assert(Val->getValueType(1) == MVT::Other);
595251662Sdim  SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) };
596251662Sdim  return DAG.getMergeValues(Vals, 2, DL);
597251662Sdim}
598251662Sdim
599251662SdimSDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
600251662Sdim                                                      SelectionDAG &DAG) const {
601251662Sdim  switch (cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue()) {
602251662Sdim  default:
603251662Sdim    return SDValue();
604251662Sdim  case Intrinsic::mips_shilo:
605251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::SHILO);
606251662Sdim  case Intrinsic::mips_dpau_h_qbl:
607251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBL);
608251662Sdim  case Intrinsic::mips_dpau_h_qbr:
609251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBR);
610251662Sdim  case Intrinsic::mips_dpsu_h_qbl:
611251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBL);
612251662Sdim  case Intrinsic::mips_dpsu_h_qbr:
613251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBR);
614251662Sdim  case Intrinsic::mips_dpa_w_ph:
615251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPA_W_PH);
616251662Sdim  case Intrinsic::mips_dps_w_ph:
617251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPS_W_PH);
618251662Sdim  case Intrinsic::mips_dpax_w_ph:
619251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAX_W_PH);
620251662Sdim  case Intrinsic::mips_dpsx_w_ph:
621251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSX_W_PH);
622251662Sdim  case Intrinsic::mips_mulsa_w_ph:
623251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MULSA_W_PH);
624251662Sdim  case Intrinsic::mips_mult:
625251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::Mult);
626251662Sdim  case Intrinsic::mips_multu:
627251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::Multu);
628251662Sdim  case Intrinsic::mips_madd:
629251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MAdd);
630251662Sdim  case Intrinsic::mips_maddu:
631251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MAddu);
632251662Sdim  case Intrinsic::mips_msub:
633251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MSub);
634251662Sdim  case Intrinsic::mips_msubu:
635251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MSubu);
636251662Sdim  }
637251662Sdim}
638251662Sdim
639251662SdimSDValue MipsSETargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
640251662Sdim                                                     SelectionDAG &DAG) const {
641251662Sdim  switch (cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue()) {
642251662Sdim  default:
643251662Sdim    return SDValue();
644251662Sdim  case Intrinsic::mips_extp:
645251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::EXTP);
646251662Sdim  case Intrinsic::mips_extpdp:
647251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::EXTPDP);
648251662Sdim  case Intrinsic::mips_extr_w:
649251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::EXTR_W);
650251662Sdim  case Intrinsic::mips_extr_r_w:
651251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W);
652251662Sdim  case Intrinsic::mips_extr_rs_w:
653251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W);
654251662Sdim  case Intrinsic::mips_extr_s_h:
655251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H);
656251662Sdim  case Intrinsic::mips_mthlip:
657251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MTHLIP);
658251662Sdim  case Intrinsic::mips_mulsaq_s_w_ph:
659251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MULSAQ_S_W_PH);
660251662Sdim  case Intrinsic::mips_maq_s_w_phl:
661251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHL);
662251662Sdim  case Intrinsic::mips_maq_s_w_phr:
663251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHR);
664251662Sdim  case Intrinsic::mips_maq_sa_w_phl:
665251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHL);
666251662Sdim  case Intrinsic::mips_maq_sa_w_phr:
667251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHR);
668251662Sdim  case Intrinsic::mips_dpaq_s_w_ph:
669251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_S_W_PH);
670251662Sdim  case Intrinsic::mips_dpsq_s_w_ph:
671251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_S_W_PH);
672251662Sdim  case Intrinsic::mips_dpaq_sa_l_w:
673251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_SA_L_W);
674251662Sdim  case Intrinsic::mips_dpsq_sa_l_w:
675251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_SA_L_W);
676251662Sdim  case Intrinsic::mips_dpaqx_s_w_ph:
677251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_S_W_PH);
678251662Sdim  case Intrinsic::mips_dpaqx_sa_w_ph:
679251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_SA_W_PH);
680251662Sdim  case Intrinsic::mips_dpsqx_s_w_ph:
681251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_S_W_PH);
682251662Sdim  case Intrinsic::mips_dpsqx_sa_w_ph:
683251662Sdim    return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_SA_W_PH);
684251662Sdim  }
685251662Sdim}
686251662Sdim
687249259SdimMachineBasicBlock * MipsSETargetLowering::
688249259SdimemitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{
689249259Sdim  // $bb:
690249259Sdim  //  bposge32_pseudo $vr0
691249259Sdim  //  =>
692249259Sdim  // $bb:
693249259Sdim  //  bposge32 $tbb
694249259Sdim  // $fbb:
695249259Sdim  //  li $vr2, 0
696249259Sdim  //  b $sink
697249259Sdim  // $tbb:
698249259Sdim  //  li $vr1, 1
699249259Sdim  // $sink:
700249259Sdim  //  $vr0 = phi($vr2, $fbb, $vr1, $tbb)
701249259Sdim
702249259Sdim  MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
703249259Sdim  const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
704249259Sdim  const TargetRegisterClass *RC = &Mips::CPURegsRegClass;
705249259Sdim  DebugLoc DL = MI->getDebugLoc();
706249259Sdim  const BasicBlock *LLVM_BB = BB->getBasicBlock();
707249259Sdim  MachineFunction::iterator It = llvm::next(MachineFunction::iterator(BB));
708249259Sdim  MachineFunction *F = BB->getParent();
709249259Sdim  MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB);
710249259Sdim  MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB);
711249259Sdim  MachineBasicBlock *Sink  = F->CreateMachineBasicBlock(LLVM_BB);
712249259Sdim  F->insert(It, FBB);
713249259Sdim  F->insert(It, TBB);
714249259Sdim  F->insert(It, Sink);
715249259Sdim
716249259Sdim  // Transfer the remainder of BB and its successor edges to Sink.
717249259Sdim  Sink->splice(Sink->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)),
718249259Sdim               BB->end());
719249259Sdim  Sink->transferSuccessorsAndUpdatePHIs(BB);
720249259Sdim
721249259Sdim  // Add successors.
722249259Sdim  BB->addSuccessor(FBB);
723249259Sdim  BB->addSuccessor(TBB);
724249259Sdim  FBB->addSuccessor(Sink);
725249259Sdim  TBB->addSuccessor(Sink);
726249259Sdim
727249259Sdim  // Insert the real bposge32 instruction to $BB.
728249259Sdim  BuildMI(BB, DL, TII->get(Mips::BPOSGE32)).addMBB(TBB);
729249259Sdim
730249259Sdim  // Fill $FBB.
731249259Sdim  unsigned VR2 = RegInfo.createVirtualRegister(RC);
732249259Sdim  BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), VR2)
733249259Sdim    .addReg(Mips::ZERO).addImm(0);
734249259Sdim  BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink);
735249259Sdim
736249259Sdim  // Fill $TBB.
737249259Sdim  unsigned VR1 = RegInfo.createVirtualRegister(RC);
738249259Sdim  BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), VR1)
739249259Sdim    .addReg(Mips::ZERO).addImm(1);
740249259Sdim
741249259Sdim  // Insert phi function to $Sink.
742249259Sdim  BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI),
743249259Sdim          MI->getOperand(0).getReg())
744249259Sdim    .addReg(VR2).addMBB(FBB).addReg(VR1).addMBB(TBB);
745249259Sdim
746249259Sdim  MI->eraseFromParent();   // The pseudo instruction is gone now.
747249259Sdim  return Sink;
748249259Sdim}
749