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).setChain(Chain) 125 .setCallee(TLI->getLibcallCallingConv(LC), 126 Type::getVoidTy(*DAG.getContext()), 127 DAG.getExternalSymbol(FunctionNames[AEABILibcall][AlignVariant], 128 TLI->getPointerTy()), std::move(Args), 0) 129 .setDiscardResult(); 130 std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI); 131 132 return CallResult.second; 133 } 134 135 SDValue 136 ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl, 137 SDValue Chain, 138 SDValue Dst, SDValue Src, 139 SDValue Size, unsigned Align, 140 bool isVolatile, bool AlwaysInline, 141 MachinePointerInfo DstPtrInfo, 142 MachinePointerInfo SrcPtrInfo) const { 143 const ARMSubtarget &Subtarget = 144 DAG.getMachineFunction().getSubtarget<ARMSubtarget>(); 145 // Do repeated 4-byte loads and stores. To be improved. 146 // This requires 4-byte alignment. 147 if ((Align & 3) != 0) 148 return SDValue(); 149 // This requires the copy size to be a constant, preferably 150 // within a subtarget-specific limit. 151 ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size); 152 if (!ConstantSize) 153 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align, 154 RTLIB::MEMCPY); 155 uint64_t SizeVal = ConstantSize->getZExtValue(); 156 if (!AlwaysInline && SizeVal > Subtarget.getMaxInlineSizeThreshold()) 157 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align, 158 RTLIB::MEMCPY); 159 160 unsigned BytesLeft = SizeVal & 3; 161 unsigned NumMemOps = SizeVal >> 2; 162 unsigned EmittedNumMemOps = 0; 163 EVT VT = MVT::i32; 164 unsigned VTSize = 4; 165 unsigned i = 0; 166 // Emit a maximum of 4 loads in Thumb1 since we have fewer registers 167 const unsigned MAX_LOADS_IN_LDM = Subtarget.isThumb1Only() ? 4 : 6; 168 SDValue TFOps[6]; 169 SDValue Loads[6]; 170 uint64_t SrcOff = 0, DstOff = 0; 171 172 // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the 173 // same number of stores. The loads and stores will get combined into 174 // ldm/stm later on. 175 while (EmittedNumMemOps < NumMemOps) { 176 for (i = 0; 177 i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) { 178 Loads[i] = DAG.getLoad(VT, dl, Chain, 179 DAG.getNode(ISD::ADD, dl, MVT::i32, Src, 180 DAG.getConstant(SrcOff, dl, MVT::i32)), 181 SrcPtrInfo.getWithOffset(SrcOff), isVolatile, 182 false, false, 0); 183 TFOps[i] = Loads[i].getValue(1); 184 SrcOff += VTSize; 185 } 186 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, 187 makeArrayRef(TFOps, i)); 188 189 for (i = 0; 190 i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) { 191 TFOps[i] = DAG.getStore(Chain, dl, Loads[i], 192 DAG.getNode(ISD::ADD, dl, MVT::i32, Dst, 193 DAG.getConstant(DstOff, dl, MVT::i32)), 194 DstPtrInfo.getWithOffset(DstOff), 195 isVolatile, false, 0); 196 DstOff += VTSize; 197 } 198 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, 199 makeArrayRef(TFOps, i)); 200 201 EmittedNumMemOps += i; 202 } 203 204 if (BytesLeft == 0) 205 return Chain; 206 207 // Issue loads / stores for the trailing (1 - 3) bytes. 208 unsigned BytesLeftSave = BytesLeft; 209 i = 0; 210 while (BytesLeft) { 211 if (BytesLeft >= 2) { 212 VT = MVT::i16; 213 VTSize = 2; 214 } else { 215 VT = MVT::i8; 216 VTSize = 1; 217 } 218 219 Loads[i] = DAG.getLoad(VT, dl, Chain, 220 DAG.getNode(ISD::ADD, dl, MVT::i32, Src, 221 DAG.getConstant(SrcOff, dl, MVT::i32)), 222 SrcPtrInfo.getWithOffset(SrcOff), 223 false, false, false, 0); 224 TFOps[i] = Loads[i].getValue(1); 225 ++i; 226 SrcOff += VTSize; 227 BytesLeft -= VTSize; 228 } 229 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, 230 makeArrayRef(TFOps, i)); 231 232 i = 0; 233 BytesLeft = BytesLeftSave; 234 while (BytesLeft) { 235 if (BytesLeft >= 2) { 236 VT = MVT::i16; 237 VTSize = 2; 238 } else { 239 VT = MVT::i8; 240 VTSize = 1; 241 } 242 243 TFOps[i] = DAG.getStore(Chain, dl, Loads[i], 244 DAG.getNode(ISD::ADD, dl, MVT::i32, Dst, 245 DAG.getConstant(DstOff, dl, MVT::i32)), 246 DstPtrInfo.getWithOffset(DstOff), false, false, 0); 247 ++i; 248 DstOff += VTSize; 249 BytesLeft -= VTSize; 250 } 251 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, 252 makeArrayRef(TFOps, i)); 253 } 254 255 256 SDValue ARMSelectionDAGInfo:: 257 EmitTargetCodeForMemmove(SelectionDAG &DAG, SDLoc dl, 258 SDValue Chain, 259 SDValue Dst, SDValue Src, 260 SDValue Size, unsigned Align, 261 bool isVolatile, 262 MachinePointerInfo DstPtrInfo, 263 MachinePointerInfo SrcPtrInfo) const { 264 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align, 265 RTLIB::MEMMOVE); 266 } 267 268 269 SDValue ARMSelectionDAGInfo:: 270 EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl, 271 SDValue Chain, SDValue Dst, 272 SDValue Src, SDValue Size, 273 unsigned Align, bool isVolatile, 274 MachinePointerInfo DstPtrInfo) const { 275 return EmitSpecializedLibcall(DAG, dl, Chain, Dst, Src, Size, Align, 276 RTLIB::MEMSET); 277 } 278