1207618Srdivacky//===-- ARMSelectionDAGInfo.cpp - ARM SelectionDAG Info -------------------===//
2207618Srdivacky//
3207618Srdivacky//                     The LLVM Compiler Infrastructure
4207618Srdivacky//
5207618Srdivacky// This file is distributed under the University of Illinois Open Source
6207618Srdivacky// License. See LICENSE.TXT for details.
7207618Srdivacky//
8207618Srdivacky//===----------------------------------------------------------------------===//
9207618Srdivacky//
10207618Srdivacky// This file implements the ARMSelectionDAGInfo class.
11207618Srdivacky//
12207618Srdivacky//===----------------------------------------------------------------------===//
13207618Srdivacky
14207618Srdivacky#define DEBUG_TYPE "arm-selectiondag-info"
15208599Srdivacky#include "ARMTargetMachine.h"
16223017Sdim#include "llvm/CodeGen/SelectionDAG.h"
17249423Sdim#include "llvm/IR/DerivedTypes.h"
18207618Srdivackyusing namespace llvm;
19207618Srdivacky
20208599SrdivackyARMSelectionDAGInfo::ARMSelectionDAGInfo(const TargetMachine &TM)
21208599Srdivacky  : TargetSelectionDAGInfo(TM),
22208599Srdivacky    Subtarget(&TM.getSubtarget<ARMSubtarget>()) {
23207618Srdivacky}
24207618Srdivacky
25207618SrdivackyARMSelectionDAGInfo::~ARMSelectionDAGInfo() {
26207618Srdivacky}
27208599Srdivacky
28208599SrdivackySDValue
29263508SdimARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl,
30208599Srdivacky                                             SDValue Chain,
31208599Srdivacky                                             SDValue Dst, SDValue Src,
32208599Srdivacky                                             SDValue Size, unsigned Align,
33208599Srdivacky                                             bool isVolatile, bool AlwaysInline,
34218893Sdim                                             MachinePointerInfo DstPtrInfo,
35218893Sdim                                          MachinePointerInfo SrcPtrInfo) const {
36208599Srdivacky  // Do repeated 4-byte loads and stores. To be improved.
37208599Srdivacky  // This requires 4-byte alignment.
38208599Srdivacky  if ((Align & 3) != 0)
39208599Srdivacky    return SDValue();
40221345Sdim  // This requires the copy size to be a constant, preferably
41208599Srdivacky  // within a subtarget-specific limit.
42208599Srdivacky  ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
43208599Srdivacky  if (!ConstantSize)
44208599Srdivacky    return SDValue();
45208599Srdivacky  uint64_t SizeVal = ConstantSize->getZExtValue();
46208599Srdivacky  if (!AlwaysInline && SizeVal > Subtarget->getMaxInlineSizeThreshold())
47208599Srdivacky    return SDValue();
48208599Srdivacky
49208599Srdivacky  unsigned BytesLeft = SizeVal & 3;
50208599Srdivacky  unsigned NumMemOps = SizeVal >> 2;
51208599Srdivacky  unsigned EmittedNumMemOps = 0;
52208599Srdivacky  EVT VT = MVT::i32;
53208599Srdivacky  unsigned VTSize = 4;
54208599Srdivacky  unsigned i = 0;
55208599Srdivacky  const unsigned MAX_LOADS_IN_LDM = 6;
56208599Srdivacky  SDValue TFOps[MAX_LOADS_IN_LDM];
57208599Srdivacky  SDValue Loads[MAX_LOADS_IN_LDM];
58208599Srdivacky  uint64_t SrcOff = 0, DstOff = 0;
59208599Srdivacky
60208599Srdivacky  // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the
61208599Srdivacky  // same number of stores.  The loads and stores will get combined into
62208599Srdivacky  // ldm/stm later on.
63208599Srdivacky  while (EmittedNumMemOps < NumMemOps) {
64208599Srdivacky    for (i = 0;
65208599Srdivacky         i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
66208599Srdivacky      Loads[i] = DAG.getLoad(VT, dl, Chain,
67208599Srdivacky                             DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
68208599Srdivacky                                         DAG.getConstant(SrcOff, MVT::i32)),
69218893Sdim                             SrcPtrInfo.getWithOffset(SrcOff), isVolatile,
70234353Sdim                             false, false, 0);
71208599Srdivacky      TFOps[i] = Loads[i].getValue(1);
72208599Srdivacky      SrcOff += VTSize;
73208599Srdivacky    }
74208599Srdivacky    Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
75208599Srdivacky
76208599Srdivacky    for (i = 0;
77208599Srdivacky         i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
78208599Srdivacky      TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
79208599Srdivacky                              DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
80208599Srdivacky                                          DAG.getConstant(DstOff, MVT::i32)),
81218893Sdim                              DstPtrInfo.getWithOffset(DstOff),
82218893Sdim                              isVolatile, false, 0);
83208599Srdivacky      DstOff += VTSize;
84208599Srdivacky    }
85208599Srdivacky    Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
86208599Srdivacky
87208599Srdivacky    EmittedNumMemOps += i;
88208599Srdivacky  }
89208599Srdivacky
90208599Srdivacky  if (BytesLeft == 0)
91208599Srdivacky    return Chain;
92208599Srdivacky
93208599Srdivacky  // Issue loads / stores for the trailing (1 - 3) bytes.
94208599Srdivacky  unsigned BytesLeftSave = BytesLeft;
95208599Srdivacky  i = 0;
96208599Srdivacky  while (BytesLeft) {
97208599Srdivacky    if (BytesLeft >= 2) {
98208599Srdivacky      VT = MVT::i16;
99208599Srdivacky      VTSize = 2;
100208599Srdivacky    } else {
101208599Srdivacky      VT = MVT::i8;
102208599Srdivacky      VTSize = 1;
103208599Srdivacky    }
104208599Srdivacky
105208599Srdivacky    Loads[i] = DAG.getLoad(VT, dl, Chain,
106208599Srdivacky                           DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
107208599Srdivacky                                       DAG.getConstant(SrcOff, MVT::i32)),
108234353Sdim                           SrcPtrInfo.getWithOffset(SrcOff),
109234353Sdim                           false, false, false, 0);
110208599Srdivacky    TFOps[i] = Loads[i].getValue(1);
111208599Srdivacky    ++i;
112208599Srdivacky    SrcOff += VTSize;
113208599Srdivacky    BytesLeft -= VTSize;
114208599Srdivacky  }
115208599Srdivacky  Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
116208599Srdivacky
117208599Srdivacky  i = 0;
118208599Srdivacky  BytesLeft = BytesLeftSave;
119208599Srdivacky  while (BytesLeft) {
120208599Srdivacky    if (BytesLeft >= 2) {
121208599Srdivacky      VT = MVT::i16;
122208599Srdivacky      VTSize = 2;
123208599Srdivacky    } else {
124208599Srdivacky      VT = MVT::i8;
125208599Srdivacky      VTSize = 1;
126208599Srdivacky    }
127208599Srdivacky
128208599Srdivacky    TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
129208599Srdivacky                            DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
130208599Srdivacky                                        DAG.getConstant(DstOff, MVT::i32)),
131218893Sdim                            DstPtrInfo.getWithOffset(DstOff), false, false, 0);
132208599Srdivacky    ++i;
133208599Srdivacky    DstOff += VTSize;
134208599Srdivacky    BytesLeft -= VTSize;
135208599Srdivacky  }
136208599Srdivacky  return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
137208599Srdivacky}
138223017Sdim
139223017Sdim// Adjust parameters for memset, EABI uses format (ptr, size, value),
140223017Sdim// GNU library uses (ptr, value, size)
141223017Sdim// See RTABI section 4.3.4
142226633SdimSDValue ARMSelectionDAGInfo::
143263508SdimEmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
144226633Sdim                        SDValue Chain, SDValue Dst,
145226633Sdim                        SDValue Src, SDValue Size,
146226633Sdim                        unsigned Align, bool isVolatile,
147226633Sdim                        MachinePointerInfo DstPtrInfo) const {
148234353Sdim  // Use default for non AAPCS (or Darwin) subtargets
149234353Sdim  if (!Subtarget->isAAPCS_ABI() || Subtarget->isTargetDarwin())
150223017Sdim    return SDValue();
151223017Sdim
152223017Sdim  const ARMTargetLowering &TLI =
153223017Sdim    *static_cast<const ARMTargetLowering*>(DAG.getTarget().getTargetLowering());
154223017Sdim  TargetLowering::ArgListTy Args;
155223017Sdim  TargetLowering::ArgListEntry Entry;
156223017Sdim
157223017Sdim  // First argument: data pointer
158243830Sdim  Type *IntPtrTy = TLI.getDataLayout()->getIntPtrType(*DAG.getContext());
159223017Sdim  Entry.Node = Dst;
160223017Sdim  Entry.Ty = IntPtrTy;
161223017Sdim  Args.push_back(Entry);
162223017Sdim
163223017Sdim  // Second argument: buffer size
164223017Sdim  Entry.Node = Size;
165223017Sdim  Entry.Ty = IntPtrTy;
166223017Sdim  Entry.isSExt = false;
167223017Sdim  Args.push_back(Entry);
168223017Sdim
169223017Sdim  // Extend or truncate the argument to be an i32 value for the call.
170223017Sdim  if (Src.getValueType().bitsGT(MVT::i32))
171223017Sdim    Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
172223017Sdim  else
173223017Sdim    Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
174223017Sdim
175223017Sdim  // Third argument: value to fill
176223017Sdim  Entry.Node = Src;
177223017Sdim  Entry.Ty = Type::getInt32Ty(*DAG.getContext());
178223017Sdim  Entry.isSExt = true;
179223017Sdim  Args.push_back(Entry);
180223017Sdim
181223017Sdim  // Emit __eabi_memset call
182239462Sdim  TargetLowering::CallLoweringInfo CLI(Chain,
183223017Sdim                    Type::getVoidTy(*DAG.getContext()), // return type
184223017Sdim                    false, // return sign ext
185223017Sdim                    false, // return zero ext
186223017Sdim                    false, // is var arg
187223017Sdim                    false, // is in regs
188223017Sdim                    0,     // number of fixed arguments
189223017Sdim                    TLI.getLibcallCallingConv(RTLIB::MEMSET), // call conv
190223017Sdim                    false, // is tail call
191234353Sdim                    false, // does not return
192223017Sdim                    false, // is return val used
193223017Sdim                    DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET),
194223017Sdim                                          TLI.getPointerTy()), // callee
195239462Sdim                    Args, DAG, dl);
196239462Sdim  std::pair<SDValue,SDValue> CallResult =
197239462Sdim    TLI.LowerCallTo(CLI);
198223017Sdim
199223017Sdim  return CallResult.second;
200223017Sdim}
201