1//===-- ARMSelectionDAGInfo.cpp - ARM SelectionDAG Info -------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the ARMSelectionDAGInfo class.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "arm-selectiondag-info"
15#include "ARMTargetMachine.h"
16#include "llvm/CodeGen/SelectionDAG.h"
17#include "llvm/IR/DerivedTypes.h"
18using namespace llvm;
19
20ARMSelectionDAGInfo::ARMSelectionDAGInfo(const TargetMachine &TM)
21  : TargetSelectionDAGInfo(TM),
22    Subtarget(&TM.getSubtarget<ARMSubtarget>()) {
23}
24
25ARMSelectionDAGInfo::~ARMSelectionDAGInfo() {
26}
27
28SDValue
29ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl,
30                                             SDValue Chain,
31                                             SDValue Dst, SDValue Src,
32                                             SDValue Size, unsigned Align,
33                                             bool isVolatile, bool AlwaysInline,
34                                             MachinePointerInfo DstPtrInfo,
35                                          MachinePointerInfo SrcPtrInfo) const {
36  // Do repeated 4-byte loads and stores. To be improved.
37  // This requires 4-byte alignment.
38  if ((Align & 3) != 0)
39    return SDValue();
40  // This requires the copy size to be a constant, preferably
41  // within a subtarget-specific limit.
42  ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
43  if (!ConstantSize)
44    return SDValue();
45  uint64_t SizeVal = ConstantSize->getZExtValue();
46  if (!AlwaysInline && SizeVal > Subtarget->getMaxInlineSizeThreshold())
47    return SDValue();
48
49  unsigned BytesLeft = SizeVal & 3;
50  unsigned NumMemOps = SizeVal >> 2;
51  unsigned EmittedNumMemOps = 0;
52  EVT VT = MVT::i32;
53  unsigned VTSize = 4;
54  unsigned i = 0;
55  const unsigned MAX_LOADS_IN_LDM = 6;
56  SDValue TFOps[MAX_LOADS_IN_LDM];
57  SDValue Loads[MAX_LOADS_IN_LDM];
58  uint64_t SrcOff = 0, DstOff = 0;
59
60  // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the
61  // same number of stores.  The loads and stores will get combined into
62  // ldm/stm later on.
63  while (EmittedNumMemOps < NumMemOps) {
64    for (i = 0;
65         i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
66      Loads[i] = DAG.getLoad(VT, dl, Chain,
67                             DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
68                                         DAG.getConstant(SrcOff, MVT::i32)),
69                             SrcPtrInfo.getWithOffset(SrcOff), isVolatile,
70                             false, false, 0);
71      TFOps[i] = Loads[i].getValue(1);
72      SrcOff += VTSize;
73    }
74    Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
75
76    for (i = 0;
77         i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
78      TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
79                              DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
80                                          DAG.getConstant(DstOff, MVT::i32)),
81                              DstPtrInfo.getWithOffset(DstOff),
82                              isVolatile, false, 0);
83      DstOff += VTSize;
84    }
85    Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
86
87    EmittedNumMemOps += i;
88  }
89
90  if (BytesLeft == 0)
91    return Chain;
92
93  // Issue loads / stores for the trailing (1 - 3) bytes.
94  unsigned BytesLeftSave = BytesLeft;
95  i = 0;
96  while (BytesLeft) {
97    if (BytesLeft >= 2) {
98      VT = MVT::i16;
99      VTSize = 2;
100    } else {
101      VT = MVT::i8;
102      VTSize = 1;
103    }
104
105    Loads[i] = DAG.getLoad(VT, dl, Chain,
106                           DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
107                                       DAG.getConstant(SrcOff, MVT::i32)),
108                           SrcPtrInfo.getWithOffset(SrcOff),
109                           false, false, false, 0);
110    TFOps[i] = Loads[i].getValue(1);
111    ++i;
112    SrcOff += VTSize;
113    BytesLeft -= VTSize;
114  }
115  Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
116
117  i = 0;
118  BytesLeft = BytesLeftSave;
119  while (BytesLeft) {
120    if (BytesLeft >= 2) {
121      VT = MVT::i16;
122      VTSize = 2;
123    } else {
124      VT = MVT::i8;
125      VTSize = 1;
126    }
127
128    TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
129                            DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
130                                        DAG.getConstant(DstOff, MVT::i32)),
131                            DstPtrInfo.getWithOffset(DstOff), false, false, 0);
132    ++i;
133    DstOff += VTSize;
134    BytesLeft -= VTSize;
135  }
136  return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
137}
138
139// Adjust parameters for memset, EABI uses format (ptr, size, value),
140// GNU library uses (ptr, value, size)
141// See RTABI section 4.3.4
142SDValue ARMSelectionDAGInfo::
143EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
144                        SDValue Chain, SDValue Dst,
145                        SDValue Src, SDValue Size,
146                        unsigned Align, bool isVolatile,
147                        MachinePointerInfo DstPtrInfo) const {
148  // Use default for non AAPCS (or Darwin) subtargets
149  if (!Subtarget->isAAPCS_ABI() || Subtarget->isTargetDarwin())
150    return SDValue();
151
152  const ARMTargetLowering &TLI =
153    *static_cast<const ARMTargetLowering*>(DAG.getTarget().getTargetLowering());
154  TargetLowering::ArgListTy Args;
155  TargetLowering::ArgListEntry Entry;
156
157  // First argument: data pointer
158  Type *IntPtrTy = TLI.getDataLayout()->getIntPtrType(*DAG.getContext());
159  Entry.Node = Dst;
160  Entry.Ty = IntPtrTy;
161  Args.push_back(Entry);
162
163  // Second argument: buffer size
164  Entry.Node = Size;
165  Entry.Ty = IntPtrTy;
166  Entry.isSExt = false;
167  Args.push_back(Entry);
168
169  // Extend or truncate the argument to be an i32 value for the call.
170  if (Src.getValueType().bitsGT(MVT::i32))
171    Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
172  else
173    Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
174
175  // Third argument: value to fill
176  Entry.Node = Src;
177  Entry.Ty = Type::getInt32Ty(*DAG.getContext());
178  Entry.isSExt = true;
179  Args.push_back(Entry);
180
181  // Emit __eabi_memset call
182  TargetLowering::CallLoweringInfo CLI(Chain,
183                    Type::getVoidTy(*DAG.getContext()), // return type
184                    false, // return sign ext
185                    false, // return zero ext
186                    false, // is var arg
187                    false, // is in regs
188                    0,     // number of fixed arguments
189                    TLI.getLibcallCallingConv(RTLIB::MEMSET), // call conv
190                    false, // is tail call
191                    false, // does not return
192                    false, // is return val used
193                    DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET),
194                                          TLI.getPointerTy()), // callee
195                    Args, DAG, dl);
196  std::pair<SDValue,SDValue> CallResult =
197    TLI.LowerCallTo(CLI);
198
199  return CallResult.second;
200}
201