Make TargetLowering::getPointerTy() taking DataLayout as an argument
[oota-llvm.git] / lib / Target / ARM / ARMSelectionDAGInfo.cpp
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 #include "ARMTargetMachine.h"
15 #include "llvm/CodeGen/SelectionDAG.h"
16 #include "llvm/IR/DerivedTypes.h"
17 using namespace llvm;
18
19 #define DEBUG_TYPE "arm-selectiondag-info"
20
21 ARMSelectionDAGInfo::ARMSelectionDAGInfo(const DataLayout &DL)
22     : TargetSelectionDAGInfo(&DL) {}
23
24 ARMSelectionDAGInfo::~ARMSelectionDAGInfo() {
25 }
26
27 // Emit, if possible, a specialized version of the given Libcall. Typically this
28 // means selecting the appropriately aligned version, but we also convert memset
29 // of 0 into memclr.
30 SDValue ARMSelectionDAGInfo::
31 EmitSpecializedLibcall(SelectionDAG &DAG, SDLoc dl,
32                        SDValue Chain,
33                        SDValue Dst, SDValue Src,
34                        SDValue Size, unsigned Align,
35                        RTLIB::Libcall LC) const {
36   const ARMSubtarget &Subtarget =
37       DAG.getMachineFunction().getSubtarget<ARMSubtarget>();
38   const ARMTargetLowering *TLI = Subtarget.getTargetLowering();
39
40   // Only use a specialized AEABI function if the default version of this
41   // Libcall is an AEABI function.
42   if (std::strncmp(TLI->getLibcallName(LC), "__aeabi", 7) != 0)
43     return SDValue();
44
45   // Translate RTLIB::Libcall to AEABILibcall. We only do this in order to be
46   // able to translate memset to memclr and use the value to index the function
47   // name array.
48   enum {
49     AEABI_MEMCPY = 0,
50     AEABI_MEMMOVE,
51     AEABI_MEMSET,
52     AEABI_MEMCLR
53   } AEABILibcall;
54   switch (LC) {
55   case RTLIB::MEMCPY:
56     AEABILibcall = AEABI_MEMCPY;
57     break;
58   case RTLIB::MEMMOVE:
59     AEABILibcall = AEABI_MEMMOVE;
60     break;
61   case RTLIB::MEMSET: 
62     AEABILibcall = AEABI_MEMSET;
63     if (ConstantSDNode *ConstantSrc = dyn_cast<ConstantSDNode>(Src))
64       if (ConstantSrc->getZExtValue() == 0)
65         AEABILibcall = AEABI_MEMCLR;
66     break;
67   default:
68     return SDValue();
69   }
70
71   // Choose the most-aligned libcall variant that we can
72   enum {
73     ALIGN1 = 0,
74     ALIGN4,
75     ALIGN8
76   } AlignVariant;
77   if ((Align & 7) == 0)
78     AlignVariant = ALIGN8;
79   else if ((Align & 3) == 0)
80     AlignVariant = ALIGN4;
81   else
82     AlignVariant = ALIGN1;
83
84   TargetLowering::ArgListTy Args;
85   TargetLowering::ArgListEntry Entry;
86   Entry.Ty = TLI->getDataLayout()->getIntPtrType(*DAG.getContext());
87   Entry.Node = Dst;
88   Args.push_back(Entry);
89   if (AEABILibcall == AEABI_MEMCLR) {
90     Entry.Node = Size;
91     Args.push_back(Entry);
92   } else if (AEABILibcall == AEABI_MEMSET) {
93     // Adjust parameters for memset, EABI uses format (ptr, size, value),
94     // GNU library uses (ptr, value, size)
95     // See RTABI section 4.3.4
96     Entry.Node = Size;
97     Args.push_back(Entry);
98
99     // Extend or truncate the argument to be an i32 value for the call.
100     if (Src.getValueType().bitsGT(MVT::i32))
101       Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
102     else if (Src.getValueType().bitsLT(MVT::i32))
103       Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
104
105     Entry.Node = Src; 
106     Entry.Ty = Type::getInt32Ty(*DAG.getContext());
107     Entry.isSExt = false;
108     Args.push_back(Entry);
109   } else {
110     Entry.Node = Src;
111     Args.push_back(Entry);
112     
113     Entry.Node = Size;
114     Args.push_back(Entry);
115   }
116
117   char const *FunctionNames[4][3] = {
118     { "__aeabi_memcpy",  "__aeabi_memcpy4",  "__aeabi_memcpy8"  },
119     { "__aeabi_memmove", "__aeabi_memmove4", "__aeabi_memmove8" },
120     { "__aeabi_memset",  "__aeabi_memset4",  "__aeabi_memset8"  },
121     { "__aeabi_memclr",  "__aeabi_memclr4",  "__aeabi_memclr8"  }
122   };
123   TargetLowering::CallLoweringInfo CLI(DAG);
124   CLI.setDebugLoc(dl)
125       .setChain(Chain)
126       .setCallee(
127            TLI->getLibcallCallingConv(LC), Type::getVoidTy(*DAG.getContext()),
128            DAG.getExternalSymbol(FunctionNames[AEABILibcall][AlignVariant],
129                                  TLI->getPointerTy(DAG.getDataLayout())),
130            std::move(Args), 0)
131       .setDiscardResult();
132   std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI);
133   
134   return CallResult.second;
135 }
136
137 SDValue
138 ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl,
139                                              SDValue Chain,
140                                              SDValue Dst, SDValue Src,
141                                              SDValue Size, unsigned Align,
142                                              bool isVolatile, bool AlwaysInline,
143                                              MachinePointerInfo DstPtrInfo,
144                                           MachinePointerInfo SrcPtrInfo) const {
145   const ARMSubtarget &Subtarget =
146       DAG.getMachineFunction().getSubtarget<ARMSubtarget>();
147   // Do repeated 4-byte loads and stores. To be improved.
148   // This requires 4-byte alignment.
149   if ((Align & 3) != 0)
150     return SDValue();
151   // This requires the copy size to be a constant, preferably
152   // within a subtarget-specific limit.
153   ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
154   if (!ConstantSize)
155     return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
156                                   RTLIB::MEMCPY);
157   uint64_t SizeVal = ConstantSize->getZExtValue();
158   if (!AlwaysInline && SizeVal > Subtarget.getMaxInlineSizeThreshold())
159     return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
160                                   RTLIB::MEMCPY);
161
162   unsigned BytesLeft = SizeVal & 3;
163   unsigned NumMemOps = SizeVal >> 2;
164   unsigned EmittedNumMemOps = 0;
165   EVT VT = MVT::i32;
166   unsigned VTSize = 4;
167   unsigned i = 0;
168   // Emit a maximum of 4 loads in Thumb1 since we have fewer registers
169   const unsigned MAX_LOADS_IN_LDM = Subtarget.isThumb1Only() ? 4 : 6;
170   SDValue TFOps[6];
171   SDValue Loads[6];
172   uint64_t SrcOff = 0, DstOff = 0;
173
174   // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the
175   // same number of stores.  The loads and stores will get combined into
176   // ldm/stm later on.
177   while (EmittedNumMemOps < NumMemOps) {
178     for (i = 0;
179          i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
180       Loads[i] = DAG.getLoad(VT, dl, Chain,
181                              DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
182                                          DAG.getConstant(SrcOff, dl, MVT::i32)),
183                              SrcPtrInfo.getWithOffset(SrcOff), isVolatile,
184                              false, false, 0);
185       TFOps[i] = Loads[i].getValue(1);
186       SrcOff += VTSize;
187     }
188     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
189                         makeArrayRef(TFOps, i));
190
191     for (i = 0;
192          i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
193       TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
194                               DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
195                                           DAG.getConstant(DstOff, dl, MVT::i32)),
196                               DstPtrInfo.getWithOffset(DstOff),
197                               isVolatile, false, 0);
198       DstOff += VTSize;
199     }
200     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
201                         makeArrayRef(TFOps, i));
202
203     EmittedNumMemOps += i;
204   }
205
206   if (BytesLeft == 0)
207     return Chain;
208
209   // Issue loads / stores for the trailing (1 - 3) bytes.
210   unsigned BytesLeftSave = BytesLeft;
211   i = 0;
212   while (BytesLeft) {
213     if (BytesLeft >= 2) {
214       VT = MVT::i16;
215       VTSize = 2;
216     } else {
217       VT = MVT::i8;
218       VTSize = 1;
219     }
220
221     Loads[i] = DAG.getLoad(VT, dl, Chain,
222                            DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
223                                        DAG.getConstant(SrcOff, dl, MVT::i32)),
224                            SrcPtrInfo.getWithOffset(SrcOff),
225                            false, false, false, 0);
226     TFOps[i] = Loads[i].getValue(1);
227     ++i;
228     SrcOff += VTSize;
229     BytesLeft -= VTSize;
230   }
231   Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
232                       makeArrayRef(TFOps, i));
233
234   i = 0;
235   BytesLeft = BytesLeftSave;
236   while (BytesLeft) {
237     if (BytesLeft >= 2) {
238       VT = MVT::i16;
239       VTSize = 2;
240     } else {
241       VT = MVT::i8;
242       VTSize = 1;
243     }
244
245     TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
246                             DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
247                                         DAG.getConstant(DstOff, dl, MVT::i32)),
248                             DstPtrInfo.getWithOffset(DstOff), false, false, 0);
249     ++i;
250     DstOff += VTSize;
251     BytesLeft -= VTSize;
252   }
253   return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
254                      makeArrayRef(TFOps, i));
255 }
256
257
258 SDValue ARMSelectionDAGInfo::
259 EmitTargetCodeForMemmove(SelectionDAG &DAG, SDLoc dl,
260                          SDValue Chain,
261                          SDValue Dst, SDValue Src,
262                          SDValue Size, unsigned Align,
263                          bool isVolatile,
264                          MachinePointerInfo DstPtrInfo,
265                          MachinePointerInfo SrcPtrInfo) const {
266   return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
267                                 RTLIB::MEMMOVE);
268 }
269
270
271 SDValue ARMSelectionDAGInfo::
272 EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
273                         SDValue Chain, SDValue Dst,
274                         SDValue Src, SDValue Size,
275                         unsigned Align, bool isVolatile,
276                         MachinePointerInfo DstPtrInfo) const {
277   return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
278                                 RTLIB::MEMSET);
279 }