1 //===-- ARMSelectionDAGInfo.cpp - ARM SelectionDAG Info -------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the ARMSelectionDAGInfo class.
12 //===----------------------------------------------------------------------===//
14 #include "ARMTargetMachine.h"
15 #include "llvm/CodeGen/SelectionDAG.h"
16 #include "llvm/IR/DerivedTypes.h"
19 #define DEBUG_TYPE "arm-selectiondag-info"
21 ARMSelectionDAGInfo::ARMSelectionDAGInfo(const DataLayout &DL)
22 : TargetSelectionDAGInfo(&DL) {}
24 ARMSelectionDAGInfo::~ARMSelectionDAGInfo() {
28 ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl,
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 =
36 DAG.getMachineFunction().getSubtarget<ARMSubtarget>();
37 // Do repeated 4-byte loads and stores. To be improved.
38 // This requires 4-byte alignment.
41 // This requires the copy size to be a constant, preferably
42 // within a subtarget-specific limit.
43 ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
46 uint64_t SizeVal = ConstantSize->getZExtValue();
47 if (!AlwaysInline && SizeVal > Subtarget.getMaxInlineSizeThreshold())
50 unsigned BytesLeft = SizeVal & 3;
51 unsigned NumMemOps = SizeVal >> 2;
52 unsigned EmittedNumMemOps = 0;
56 // Emit a maximum of 4 loads in Thumb1 since we have fewer registers
57 const unsigned MAX_LOADS_IN_LDM = Subtarget.isThumb1Only() ? 4 : 6;
60 uint64_t SrcOff = 0, DstOff = 0;
62 // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the
63 // same number of stores. The loads and stores will get combined into
65 while (EmittedNumMemOps < NumMemOps) {
67 i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
68 Loads[i] = DAG.getLoad(VT, dl, Chain,
69 DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
70 DAG.getConstant(SrcOff, MVT::i32)),
71 SrcPtrInfo.getWithOffset(SrcOff), isVolatile,
73 TFOps[i] = Loads[i].getValue(1);
76 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
77 makeArrayRef(TFOps, i));
80 i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) {
81 TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
82 DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
83 DAG.getConstant(DstOff, MVT::i32)),
84 DstPtrInfo.getWithOffset(DstOff),
85 isVolatile, false, 0);
88 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
89 makeArrayRef(TFOps, i));
91 EmittedNumMemOps += i;
97 // Issue loads / stores for the trailing (1 - 3) bytes.
98 unsigned BytesLeftSave = BytesLeft;
101 if (BytesLeft >= 2) {
109 Loads[i] = DAG.getLoad(VT, dl, Chain,
110 DAG.getNode(ISD::ADD, dl, MVT::i32, Src,
111 DAG.getConstant(SrcOff, MVT::i32)),
112 SrcPtrInfo.getWithOffset(SrcOff),
113 false, false, false, 0);
114 TFOps[i] = Loads[i].getValue(1);
119 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
120 makeArrayRef(TFOps, i));
123 BytesLeft = BytesLeftSave;
125 if (BytesLeft >= 2) {
133 TFOps[i] = DAG.getStore(Chain, dl, Loads[i],
134 DAG.getNode(ISD::ADD, dl, MVT::i32, Dst,
135 DAG.getConstant(DstOff, MVT::i32)),
136 DstPtrInfo.getWithOffset(DstOff), false, false, 0);
141 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
142 makeArrayRef(TFOps, i));
145 // Adjust parameters for memset, EABI uses format (ptr, size, value),
146 // GNU library uses (ptr, value, size)
147 // See RTABI section 4.3.4
148 SDValue ARMSelectionDAGInfo::
149 EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
150 SDValue Chain, SDValue Dst,
151 SDValue Src, SDValue Size,
152 unsigned Align, bool isVolatile,
153 MachinePointerInfo DstPtrInfo) const {
154 const ARMSubtarget &Subtarget =
155 DAG.getMachineFunction().getSubtarget<ARMSubtarget>();
156 // Use default for non-AAPCS (or MachO) subtargets
157 if (!Subtarget.isAAPCS_ABI() || Subtarget.isTargetMachO() ||
158 Subtarget.isTargetWindows())
161 const ARMTargetLowering &TLI = *Subtarget.getTargetLowering();
162 TargetLowering::ArgListTy Args;
163 TargetLowering::ArgListEntry Entry;
165 // First argument: data pointer
166 Type *IntPtrTy = TLI.getDataLayout()->getIntPtrType(*DAG.getContext());
169 Args.push_back(Entry);
171 // Second argument: buffer size
174 Entry.isSExt = false;
175 Args.push_back(Entry);
177 // Extend or truncate the argument to be an i32 value for the call.
178 if (Src.getValueType().bitsGT(MVT::i32))
179 Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
181 Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
183 // Third argument: value to fill
185 Entry.Ty = Type::getInt32Ty(*DAG.getContext());
187 Args.push_back(Entry);
189 // Emit __eabi_memset call
190 TargetLowering::CallLoweringInfo CLI(DAG);
191 CLI.setDebugLoc(dl).setChain(Chain)
192 .setCallee(TLI.getLibcallCallingConv(RTLIB::MEMSET),
193 Type::getVoidTy(*DAG.getContext()),
194 DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET),
195 TLI.getPointerTy()), std::move(Args), 0)
198 std::pair<SDValue,SDValue> CallResult = TLI.LowerCallTo(CLI);
199 return CallResult.second;