1207618Srdivacky//===-- ARMSelectionDAGInfo.cpp - ARM SelectionDAG Info -------------------===// 2207618Srdivacky// 3207618Srdivacky// The LLVM Compiler Infrastructure 4207618Srdivacky// 5207618Srdivacky// This file is distributed under the University of Illinois Open Source 6207618Srdivacky// License. See LICENSE.TXT for details. 7207618Srdivacky// 8207618Srdivacky//===----------------------------------------------------------------------===// 9207618Srdivacky// 10207618Srdivacky// This file implements the ARMSelectionDAGInfo class. 11207618Srdivacky// 12207618Srdivacky//===----------------------------------------------------------------------===// 13207618Srdivacky 14207618Srdivacky#define DEBUG_TYPE "arm-selectiondag-info" 15208599Srdivacky#include "ARMTargetMachine.h" 16223017Sdim#include "llvm/CodeGen/SelectionDAG.h" 17249423Sdim#include "llvm/IR/DerivedTypes.h" 18207618Srdivackyusing namespace llvm; 19207618Srdivacky 20208599SrdivackyARMSelectionDAGInfo::ARMSelectionDAGInfo(const TargetMachine &TM) 21208599Srdivacky : TargetSelectionDAGInfo(TM), 22208599Srdivacky Subtarget(&TM.getSubtarget<ARMSubtarget>()) { 23207618Srdivacky} 24207618Srdivacky 25207618SrdivackyARMSelectionDAGInfo::~ARMSelectionDAGInfo() { 26207618Srdivacky} 27208599Srdivacky 28208599SrdivackySDValue 29263508SdimARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl, 30208599Srdivacky SDValue Chain, 31208599Srdivacky SDValue Dst, SDValue Src, 32208599Srdivacky SDValue Size, unsigned Align, 33208599Srdivacky bool isVolatile, bool AlwaysInline, 34218893Sdim MachinePointerInfo DstPtrInfo, 35218893Sdim MachinePointerInfo SrcPtrInfo) const { 36208599Srdivacky // Do repeated 4-byte loads and stores. To be improved. 37208599Srdivacky // This requires 4-byte alignment. 38208599Srdivacky if ((Align & 3) != 0) 39208599Srdivacky return SDValue(); 40221345Sdim // This requires the copy size to be a constant, preferably 41208599Srdivacky // within a subtarget-specific limit. 42208599Srdivacky ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size); 43208599Srdivacky if (!ConstantSize) 44208599Srdivacky return SDValue(); 45208599Srdivacky uint64_t SizeVal = ConstantSize->getZExtValue(); 46208599Srdivacky if (!AlwaysInline && SizeVal > Subtarget->getMaxInlineSizeThreshold()) 47208599Srdivacky return SDValue(); 48208599Srdivacky 49208599Srdivacky unsigned BytesLeft = SizeVal & 3; 50208599Srdivacky unsigned NumMemOps = SizeVal >> 2; 51208599Srdivacky unsigned EmittedNumMemOps = 0; 52208599Srdivacky EVT VT = MVT::i32; 53208599Srdivacky unsigned VTSize = 4; 54208599Srdivacky unsigned i = 0; 55208599Srdivacky const unsigned MAX_LOADS_IN_LDM = 6; 56208599Srdivacky SDValue TFOps[MAX_LOADS_IN_LDM]; 57208599Srdivacky SDValue Loads[MAX_LOADS_IN_LDM]; 58208599Srdivacky uint64_t SrcOff = 0, DstOff = 0; 59208599Srdivacky 60208599Srdivacky // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the 61208599Srdivacky // same number of stores. The loads and stores will get combined into 62208599Srdivacky // ldm/stm later on. 63208599Srdivacky while (EmittedNumMemOps < NumMemOps) { 64208599Srdivacky for (i = 0; 65208599Srdivacky i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) { 66208599Srdivacky Loads[i] = DAG.getLoad(VT, dl, Chain, 67208599Srdivacky DAG.getNode(ISD::ADD, dl, MVT::i32, Src, 68208599Srdivacky DAG.getConstant(SrcOff, MVT::i32)), 69218893Sdim SrcPtrInfo.getWithOffset(SrcOff), isVolatile, 70234353Sdim false, false, 0); 71208599Srdivacky TFOps[i] = Loads[i].getValue(1); 72208599Srdivacky SrcOff += VTSize; 73208599Srdivacky } 74208599Srdivacky Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); 75208599Srdivacky 76208599Srdivacky for (i = 0; 77208599Srdivacky i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) { 78208599Srdivacky TFOps[i] = DAG.getStore(Chain, dl, Loads[i], 79208599Srdivacky DAG.getNode(ISD::ADD, dl, MVT::i32, Dst, 80208599Srdivacky DAG.getConstant(DstOff, MVT::i32)), 81218893Sdim DstPtrInfo.getWithOffset(DstOff), 82218893Sdim isVolatile, false, 0); 83208599Srdivacky DstOff += VTSize; 84208599Srdivacky } 85208599Srdivacky Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); 86208599Srdivacky 87208599Srdivacky EmittedNumMemOps += i; 88208599Srdivacky } 89208599Srdivacky 90208599Srdivacky if (BytesLeft == 0) 91208599Srdivacky return Chain; 92208599Srdivacky 93208599Srdivacky // Issue loads / stores for the trailing (1 - 3) bytes. 94208599Srdivacky unsigned BytesLeftSave = BytesLeft; 95208599Srdivacky i = 0; 96208599Srdivacky while (BytesLeft) { 97208599Srdivacky if (BytesLeft >= 2) { 98208599Srdivacky VT = MVT::i16; 99208599Srdivacky VTSize = 2; 100208599Srdivacky } else { 101208599Srdivacky VT = MVT::i8; 102208599Srdivacky VTSize = 1; 103208599Srdivacky } 104208599Srdivacky 105208599Srdivacky Loads[i] = DAG.getLoad(VT, dl, Chain, 106208599Srdivacky DAG.getNode(ISD::ADD, dl, MVT::i32, Src, 107208599Srdivacky DAG.getConstant(SrcOff, MVT::i32)), 108234353Sdim SrcPtrInfo.getWithOffset(SrcOff), 109234353Sdim false, false, false, 0); 110208599Srdivacky TFOps[i] = Loads[i].getValue(1); 111208599Srdivacky ++i; 112208599Srdivacky SrcOff += VTSize; 113208599Srdivacky BytesLeft -= VTSize; 114208599Srdivacky } 115208599Srdivacky Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); 116208599Srdivacky 117208599Srdivacky i = 0; 118208599Srdivacky BytesLeft = BytesLeftSave; 119208599Srdivacky while (BytesLeft) { 120208599Srdivacky if (BytesLeft >= 2) { 121208599Srdivacky VT = MVT::i16; 122208599Srdivacky VTSize = 2; 123208599Srdivacky } else { 124208599Srdivacky VT = MVT::i8; 125208599Srdivacky VTSize = 1; 126208599Srdivacky } 127208599Srdivacky 128208599Srdivacky TFOps[i] = DAG.getStore(Chain, dl, Loads[i], 129208599Srdivacky DAG.getNode(ISD::ADD, dl, MVT::i32, Dst, 130208599Srdivacky DAG.getConstant(DstOff, MVT::i32)), 131218893Sdim DstPtrInfo.getWithOffset(DstOff), false, false, 0); 132208599Srdivacky ++i; 133208599Srdivacky DstOff += VTSize; 134208599Srdivacky BytesLeft -= VTSize; 135208599Srdivacky } 136208599Srdivacky return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); 137208599Srdivacky} 138223017Sdim 139223017Sdim// Adjust parameters for memset, EABI uses format (ptr, size, value), 140223017Sdim// GNU library uses (ptr, value, size) 141223017Sdim// See RTABI section 4.3.4 142226633SdimSDValue ARMSelectionDAGInfo:: 143263508SdimEmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl, 144226633Sdim SDValue Chain, SDValue Dst, 145226633Sdim SDValue Src, SDValue Size, 146226633Sdim unsigned Align, bool isVolatile, 147226633Sdim MachinePointerInfo DstPtrInfo) const { 148234353Sdim // Use default for non AAPCS (or Darwin) subtargets 149234353Sdim if (!Subtarget->isAAPCS_ABI() || Subtarget->isTargetDarwin()) 150223017Sdim return SDValue(); 151223017Sdim 152223017Sdim const ARMTargetLowering &TLI = 153223017Sdim *static_cast<const ARMTargetLowering*>(DAG.getTarget().getTargetLowering()); 154223017Sdim TargetLowering::ArgListTy Args; 155223017Sdim TargetLowering::ArgListEntry Entry; 156223017Sdim 157223017Sdim // First argument: data pointer 158243830Sdim Type *IntPtrTy = TLI.getDataLayout()->getIntPtrType(*DAG.getContext()); 159223017Sdim Entry.Node = Dst; 160223017Sdim Entry.Ty = IntPtrTy; 161223017Sdim Args.push_back(Entry); 162223017Sdim 163223017Sdim // Second argument: buffer size 164223017Sdim Entry.Node = Size; 165223017Sdim Entry.Ty = IntPtrTy; 166223017Sdim Entry.isSExt = false; 167223017Sdim Args.push_back(Entry); 168223017Sdim 169223017Sdim // Extend or truncate the argument to be an i32 value for the call. 170223017Sdim if (Src.getValueType().bitsGT(MVT::i32)) 171223017Sdim Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src); 172223017Sdim else 173223017Sdim Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src); 174223017Sdim 175223017Sdim // Third argument: value to fill 176223017Sdim Entry.Node = Src; 177223017Sdim Entry.Ty = Type::getInt32Ty(*DAG.getContext()); 178223017Sdim Entry.isSExt = true; 179223017Sdim Args.push_back(Entry); 180223017Sdim 181223017Sdim // Emit __eabi_memset call 182239462Sdim TargetLowering::CallLoweringInfo CLI(Chain, 183223017Sdim Type::getVoidTy(*DAG.getContext()), // return type 184223017Sdim false, // return sign ext 185223017Sdim false, // return zero ext 186223017Sdim false, // is var arg 187223017Sdim false, // is in regs 188223017Sdim 0, // number of fixed arguments 189223017Sdim TLI.getLibcallCallingConv(RTLIB::MEMSET), // call conv 190223017Sdim false, // is tail call 191234353Sdim false, // does not return 192223017Sdim false, // is return val used 193223017Sdim DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET), 194223017Sdim TLI.getPointerTy()), // callee 195239462Sdim Args, DAG, dl); 196239462Sdim std::pair<SDValue,SDValue> CallResult = 197239462Sdim TLI.LowerCallTo(CLI); 198223017Sdim 199223017Sdim return CallResult.second; 200223017Sdim} 201