blob: 23a5dcff42b5f8e816689a91872648767d532adb [file] [log] [blame]
Dan Gohman9becddd2010-04-16 23:04:22 +00001//===-- 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
Dan Gohmanbb919df2010-05-11 17:31:57 +000014#include "ARMTargetMachine.h"
Renato Golin4cd51872011-05-22 21:41:23 +000015#include "llvm/CodeGen/SelectionDAG.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000016#include "llvm/IR/DerivedTypes.h"
Dan Gohman9becddd2010-04-16 23:04:22 +000017using namespace llvm;
18
Chandler Carruth84e68b22014-04-22 02:41:26 +000019#define DEBUG_TYPE "arm-selectiondag-info"
20
Eric Christopher70e005a2014-06-12 23:39:49 +000021ARMSelectionDAGInfo::ARMSelectionDAGInfo(const DataLayout &DL)
22 : TargetSelectionDAGInfo(&DL) {}
Dan Gohman9becddd2010-04-16 23:04:22 +000023
24ARMSelectionDAGInfo::~ARMSelectionDAGInfo() {
25}
Dan Gohmanbb919df2010-05-11 17:31:57 +000026
John Brawn70605f72015-05-12 13:13:38 +000027// 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.
30SDValue ARMSelectionDAGInfo::
31EmitSpecializedLibcall(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;
Mehdi Aminia749f2a2015-07-09 02:09:52 +000086 Entry.Ty = DAG.getDataLayout().getIntPtrType(*DAG.getContext());
John Brawn70605f72015-05-12 13:13:38 +000087 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);
Mehdi Amini44ede332015-07-09 02:09:04 +0000124 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();
John Brawn70605f72015-05-12 13:13:38 +0000132 std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI);
133
134 return CallResult.second;
135}
136
Dan Gohmanbb919df2010-05-11 17:31:57 +0000137SDValue
Andrew Trickef9de2a2013-05-25 02:42:55 +0000138ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl,
Dan Gohmanbb919df2010-05-11 17:31:57 +0000139 SDValue Chain,
140 SDValue Dst, SDValue Src,
141 SDValue Size, unsigned Align,
142 bool isVolatile, bool AlwaysInline,
Chris Lattner2510de22010-09-21 05:40:29 +0000143 MachinePointerInfo DstPtrInfo,
144 MachinePointerInfo SrcPtrInfo) const {
Eric Christopher22b2ad22015-02-20 08:24:37 +0000145 const ARMSubtarget &Subtarget =
146 DAG.getMachineFunction().getSubtarget<ARMSubtarget>();
Dan Gohmanbb919df2010-05-11 17:31:57 +0000147 // Do repeated 4-byte loads and stores. To be improved.
148 // This requires 4-byte alignment.
149 if ((Align & 3) != 0)
150 return SDValue();
Chris Lattner0ab5e2c2011-04-15 05:18:47 +0000151 // This requires the copy size to be a constant, preferably
Dan Gohmanbb919df2010-05-11 17:31:57 +0000152 // within a subtarget-specific limit.
153 ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
154 if (!ConstantSize)
John Brawn70605f72015-05-12 13:13:38 +0000155 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
156 RTLIB::MEMCPY);
Dan Gohmanbb919df2010-05-11 17:31:57 +0000157 uint64_t SizeVal = ConstantSize->getZExtValue();
Eric Christopher70e005a2014-06-12 23:39:49 +0000158 if (!AlwaysInline && SizeVal > Subtarget.getMaxInlineSizeThreshold())
John Brawn70605f72015-05-12 13:13:38 +0000159 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
160 RTLIB::MEMCPY);
Dan Gohmanbb919df2010-05-11 17:31:57 +0000161
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;
James Molloya70697e2014-05-16 14:24:22 +0000168 // Emit a maximum of 4 loads in Thumb1 since we have fewer registers
Peter Collingbourne6679fc12015-06-05 18:01:28 +0000169 const unsigned MAX_LOADS_IN_LDM = Subtarget.isThumb1Only() ? 4 : 6;
James Molloya70697e2014-05-16 14:24:22 +0000170 SDValue TFOps[6];
171 SDValue Loads[6];
Dan Gohmanbb919df2010-05-11 17:31:57 +0000172 uint64_t SrcOff = 0, DstOff = 0;
173
Peter Collingbourne6679fc12015-06-05 18:01:28 +0000174 // 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));
Dan Gohmanbb919df2010-05-11 17:31:57 +0000190
Peter Collingbourne6679fc12015-06-05 18:01:28 +0000191 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));
Dan Gohmanbb919df2010-05-11 17:31:57 +0000202
Peter Collingbourne6679fc12015-06-05 18:01:28 +0000203 EmittedNumMemOps += i;
Dan Gohmanbb919df2010-05-11 17:31:57 +0000204 }
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,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000223 DAG.getConstant(SrcOff, dl, MVT::i32)),
Pete Cooper82cd9e82011-11-08 18:42:53 +0000224 SrcPtrInfo.getWithOffset(SrcOff),
225 false, false, false, 0);
Dan Gohmanbb919df2010-05-11 17:31:57 +0000226 TFOps[i] = Loads[i].getValue(1);
227 ++i;
228 SrcOff += VTSize;
229 BytesLeft -= VTSize;
230 }
Craig Topper48d114b2014-04-26 18:35:24 +0000231 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
Craig Topper2d2aa0c2014-04-30 07:17:30 +0000232 makeArrayRef(TFOps, i));
Dan Gohmanbb919df2010-05-11 17:31:57 +0000233
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,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000247 DAG.getConstant(DstOff, dl, MVT::i32)),
Chris Lattner2510de22010-09-21 05:40:29 +0000248 DstPtrInfo.getWithOffset(DstOff), false, false, 0);
Dan Gohmanbb919df2010-05-11 17:31:57 +0000249 ++i;
250 DstOff += VTSize;
251 BytesLeft -= VTSize;
252 }
Craig Topper48d114b2014-04-26 18:35:24 +0000253 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
Craig Topper2d2aa0c2014-04-30 07:17:30 +0000254 makeArrayRef(TFOps, i));
Dan Gohmanbb919df2010-05-11 17:31:57 +0000255}
Renato Golin4cd51872011-05-22 21:41:23 +0000256
John Brawn70605f72015-05-12 13:13:38 +0000257
258SDValue ARMSelectionDAGInfo::
259EmitTargetCodeForMemmove(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
Jim Grosbache7e2aca2011-09-13 20:30:37 +0000271SDValue ARMSelectionDAGInfo::
Andrew Trickef9de2a2013-05-25 02:42:55 +0000272EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
Jim Grosbache7e2aca2011-09-13 20:30:37 +0000273 SDValue Chain, SDValue Dst,
274 SDValue Src, SDValue Size,
275 unsigned Align, bool isVolatile,
276 MachinePointerInfo DstPtrInfo) const {
John Brawn70605f72015-05-12 13:13:38 +0000277 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align,
278 RTLIB::MEMSET);
Renato Golin4cd51872011-05-22 21:41:23 +0000279}