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
ARMSelectionDAGInfo(const DataLayout & DL)21 ARMSelectionDAGInfo::ARMSelectionDAGInfo(const DataLayout &DL)
22 : TargetSelectionDAGInfo(&DL) {}
23
~ARMSelectionDAGInfo()24 ARMSelectionDAGInfo::~ARMSelectionDAGInfo() {
25 }
26
27 SDValue
EmitTargetCodeForMemcpy(SelectionDAG & DAG,SDLoc dl,SDValue Chain,SDValue Dst,SDValue Src,SDValue Size,unsigned Align,bool isVolatile,bool AlwaysInline,MachinePointerInfo DstPtrInfo,MachinePointerInfo SrcPtrInfo) const28 ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl,
29 SDValue Chain,
30 SDValue Dst, SDValue Src,
31 SDValue Size, unsigned Align,
32 bool isVolatile, bool AlwaysInline,
33 MachinePointerInfo DstPtrInfo,
34 MachinePointerInfo SrcPtrInfo) const {
35 const ARMSubtarget &Subtarget = DAG.getTarget().getSubtarget<ARMSubtarget>();
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 // Emit a maximum of 4 loads in Thumb1 since we have fewer registers
56 const unsigned MAX_LOADS_IN_LDM = Subtarget.isThumb1Only() ? 4 : 6;
57 SDValue TFOps[6];
58 SDValue Loads[6];
59 uint64_t SrcOff = 0, DstOff = 0;
60
61 // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the
62 // same number of stores. The loads and stores will get combined into
63 // ldm/stm later on.
64 while (EmittedNumMemOps < NumMemOps) {
65 for (i = 0;
66 i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
67 Loads[i] = DAG.getLoad(VT, dl, Chain,
68 DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
69 DAG.getConstant(SrcOff, MVT::i32)),
70 SrcPtrInfo.getWithOffset(SrcOff), isVolatile,
71 false, false, 0);
72 TFOps[i] = Loads[i].getValue(1);
73 SrcOff += VTSize;
74 }
75 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
76 makeArrayRef(TFOps, i));
77
78 for (i = 0;
79 i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
80 TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
81 DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
82 DAG.getConstant(DstOff, MVT::i32)),
83 DstPtrInfo.getWithOffset(DstOff),
84 isVolatile, false, 0);
85 DstOff += VTSize;
86 }
87 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
88 makeArrayRef(TFOps, i));
89
90 EmittedNumMemOps += i;
91 }
92
93 if (BytesLeft == 0)
94 return Chain;
95
96 // Issue loads / stores for the trailing (1 - 3) bytes.
97 unsigned BytesLeftSave = BytesLeft;
98 i = 0;
99 while (BytesLeft) {
100 if (BytesLeft >= 2) {
101 VT = MVT::i16;
102 VTSize = 2;
103 } else {
104 VT = MVT::i8;
105 VTSize = 1;
106 }
107
108 Loads[i] = DAG.getLoad(VT, dl, Chain,
109 DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
110 DAG.getConstant(SrcOff, MVT::i32)),
111 SrcPtrInfo.getWithOffset(SrcOff),
112 false, false, false, 0);
113 TFOps[i] = Loads[i].getValue(1);
114 ++i;
115 SrcOff += VTSize;
116 BytesLeft -= VTSize;
117 }
118 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
119 makeArrayRef(TFOps, i));
120
121 i = 0;
122 BytesLeft = BytesLeftSave;
123 while (BytesLeft) {
124 if (BytesLeft >= 2) {
125 VT = MVT::i16;
126 VTSize = 2;
127 } else {
128 VT = MVT::i8;
129 VTSize = 1;
130 }
131
132 TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
133 DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
134 DAG.getConstant(DstOff, MVT::i32)),
135 DstPtrInfo.getWithOffset(DstOff), false, false, 0);
136 ++i;
137 DstOff += VTSize;
138 BytesLeft -= VTSize;
139 }
140 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
141 makeArrayRef(TFOps, i));
142 }
143
144 // Adjust parameters for memset, EABI uses format (ptr, size, value),
145 // GNU library uses (ptr, value, size)
146 // See RTABI section 4.3.4
147 SDValue ARMSelectionDAGInfo::
EmitTargetCodeForMemset(SelectionDAG & DAG,SDLoc dl,SDValue Chain,SDValue Dst,SDValue Src,SDValue Size,unsigned Align,bool isVolatile,MachinePointerInfo DstPtrInfo) const148 EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
149 SDValue Chain, SDValue Dst,
150 SDValue Src, SDValue Size,
151 unsigned Align, bool isVolatile,
152 MachinePointerInfo DstPtrInfo) const {
153 const ARMSubtarget &Subtarget = DAG.getTarget().getSubtarget<ARMSubtarget>();
154 // Use default for non-AAPCS (or MachO) subtargets
155 if (!Subtarget.isAAPCS_ABI() || Subtarget.isTargetMachO() ||
156 Subtarget.isTargetWindows())
157 return SDValue();
158
159 const ARMTargetLowering &TLI =
160 *static_cast<const ARMTargetLowering*>(DAG.getTarget().getTargetLowering());
161 TargetLowering::ArgListTy Args;
162 TargetLowering::ArgListEntry Entry;
163
164 // First argument: data pointer
165 Type *IntPtrTy = TLI.getDataLayout()->getIntPtrType(*DAG.getContext());
166 Entry.Node = Dst;
167 Entry.Ty = IntPtrTy;
168 Args.push_back(Entry);
169
170 // Second argument: buffer size
171 Entry.Node = Size;
172 Entry.Ty = IntPtrTy;
173 Entry.isSExt = false;
174 Args.push_back(Entry);
175
176 // Extend or truncate the argument to be an i32 value for the call.
177 if (Src.getValueType().bitsGT(MVT::i32))
178 Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
179 else
180 Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
181
182 // Third argument: value to fill
183 Entry.Node = Src;
184 Entry.Ty = Type::getInt32Ty(*DAG.getContext());
185 Entry.isSExt = true;
186 Args.push_back(Entry);
187
188 // Emit __eabi_memset call
189 TargetLowering::CallLoweringInfo CLI(DAG);
190 CLI.setDebugLoc(dl).setChain(Chain)
191 .setCallee(TLI.getLibcallCallingConv(RTLIB::MEMSET),
192 Type::getVoidTy(*DAG.getContext()),
193 DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET),
194 TLI.getPointerTy()), std::move(Args), 0)
195 .setDiscardResult();
196
197 std::pair<SDValue,SDValue> CallResult = TLI.LowerCallTo(CLI);
198 return CallResult.second;
199 }
200