| Dan Gohman | 9becddd | 2010-04-16 23:04:22 +0000 | [diff] [blame] | 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 | #define DEBUG_TYPE "arm-selectiondag-info" | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 15 | #include "ARMTargetMachine.h" | 
| Renato Golin | 4cd5187 | 2011-05-22 21:41:23 +0000 | [diff] [blame] | 16 | #include "llvm/DerivedTypes.h" | 
|  | 17 | #include "llvm/CodeGen/SelectionDAG.h" | 
| Dan Gohman | 9becddd | 2010-04-16 23:04:22 +0000 | [diff] [blame] | 18 | using namespace llvm; | 
|  | 19 |  | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 20 | ARMSelectionDAGInfo::ARMSelectionDAGInfo(const TargetMachine &TM) | 
|  | 21 | : TargetSelectionDAGInfo(TM), | 
|  | 22 | Subtarget(&TM.getSubtarget<ARMSubtarget>()) { | 
| Dan Gohman | 9becddd | 2010-04-16 23:04:22 +0000 | [diff] [blame] | 23 | } | 
|  | 24 |  | 
|  | 25 | ARMSelectionDAGInfo::~ARMSelectionDAGInfo() { | 
|  | 26 | } | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 27 |  | 
|  | 28 | SDValue | 
|  | 29 | ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl, | 
|  | 30 | SDValue Chain, | 
|  | 31 | SDValue Dst, SDValue Src, | 
|  | 32 | SDValue Size, unsigned Align, | 
|  | 33 | bool isVolatile, bool AlwaysInline, | 
| Chris Lattner | 2510de2 | 2010-09-21 05:40:29 +0000 | [diff] [blame] | 34 | MachinePointerInfo DstPtrInfo, | 
|  | 35 | MachinePointerInfo SrcPtrInfo) const { | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 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(); | 
| Chris Lattner | 0ab5e2c | 2011-04-15 05:18:47 +0000 | [diff] [blame] | 40 | // This requires the copy size to be a constant, preferably | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 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 | const unsigned MAX_LOADS_IN_LDM = 6; | 
|  | 56 | SDValue TFOps[MAX_LOADS_IN_LDM]; | 
|  | 57 | SDValue Loads[MAX_LOADS_IN_LDM]; | 
|  | 58 | uint64_t SrcOff = 0, DstOff = 0; | 
|  | 59 |  | 
|  | 60 | // Emit up to MAX_LOADS_IN_LDM loads, then a TokenFactor barrier, then the | 
|  | 61 | // same number of stores.  The loads and stores will get combined into | 
|  | 62 | // ldm/stm later on. | 
|  | 63 | while (EmittedNumMemOps < NumMemOps) { | 
|  | 64 | for (i = 0; | 
|  | 65 | i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) { | 
|  | 66 | Loads[i] = DAG.getLoad(VT, dl, Chain, | 
|  | 67 | DAG.getNode(ISD::ADD, dl, MVT::i32, Src, | 
|  | 68 | DAG.getConstant(SrcOff, MVT::i32)), | 
| Chris Lattner | 2510de2 | 2010-09-21 05:40:29 +0000 | [diff] [blame] | 69 | SrcPtrInfo.getWithOffset(SrcOff), isVolatile, | 
|  | 70 | false, 0); | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 71 | TFOps[i] = Loads[i].getValue(1); | 
|  | 72 | SrcOff += VTSize; | 
|  | 73 | } | 
|  | 74 | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); | 
|  | 75 |  | 
|  | 76 | for (i = 0; | 
|  | 77 | i < MAX_LOADS_IN_LDM && EmittedNumMemOps + i < NumMemOps; ++i) { | 
|  | 78 | TFOps[i] = DAG.getStore(Chain, dl, Loads[i], | 
|  | 79 | DAG.getNode(ISD::ADD, dl, MVT::i32, Dst, | 
|  | 80 | DAG.getConstant(DstOff, MVT::i32)), | 
| Chris Lattner | 2510de2 | 2010-09-21 05:40:29 +0000 | [diff] [blame] | 81 | DstPtrInfo.getWithOffset(DstOff), | 
|  | 82 | isVolatile, false, 0); | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 83 | DstOff += VTSize; | 
|  | 84 | } | 
|  | 85 | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); | 
|  | 86 |  | 
|  | 87 | EmittedNumMemOps += i; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | if (BytesLeft == 0) | 
|  | 91 | return Chain; | 
|  | 92 |  | 
|  | 93 | // Issue loads / stores for the trailing (1 - 3) bytes. | 
|  | 94 | unsigned BytesLeftSave = BytesLeft; | 
|  | 95 | i = 0; | 
|  | 96 | while (BytesLeft) { | 
|  | 97 | if (BytesLeft >= 2) { | 
|  | 98 | VT = MVT::i16; | 
|  | 99 | VTSize = 2; | 
|  | 100 | } else { | 
|  | 101 | VT = MVT::i8; | 
|  | 102 | VTSize = 1; | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | Loads[i] = DAG.getLoad(VT, dl, Chain, | 
|  | 106 | DAG.getNode(ISD::ADD, dl, MVT::i32, Src, | 
|  | 107 | DAG.getConstant(SrcOff, MVT::i32)), | 
| Chris Lattner | 2510de2 | 2010-09-21 05:40:29 +0000 | [diff] [blame] | 108 | SrcPtrInfo.getWithOffset(SrcOff), false, false, 0); | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 109 | TFOps[i] = Loads[i].getValue(1); | 
|  | 110 | ++i; | 
|  | 111 | SrcOff += VTSize; | 
|  | 112 | BytesLeft -= VTSize; | 
|  | 113 | } | 
|  | 114 | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); | 
|  | 115 |  | 
|  | 116 | i = 0; | 
|  | 117 | BytesLeft = BytesLeftSave; | 
|  | 118 | while (BytesLeft) { | 
|  | 119 | if (BytesLeft >= 2) { | 
|  | 120 | VT = MVT::i16; | 
|  | 121 | VTSize = 2; | 
|  | 122 | } else { | 
|  | 123 | VT = MVT::i8; | 
|  | 124 | VTSize = 1; | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | TFOps[i] = DAG.getStore(Chain, dl, Loads[i], | 
|  | 128 | DAG.getNode(ISD::ADD, dl, MVT::i32, Dst, | 
|  | 129 | DAG.getConstant(DstOff, MVT::i32)), | 
| Chris Lattner | 2510de2 | 2010-09-21 05:40:29 +0000 | [diff] [blame] | 130 | DstPtrInfo.getWithOffset(DstOff), false, false, 0); | 
| Dan Gohman | bb919df | 2010-05-11 17:31:57 +0000 | [diff] [blame] | 131 | ++i; | 
|  | 132 | DstOff += VTSize; | 
|  | 133 | BytesLeft -= VTSize; | 
|  | 134 | } | 
|  | 135 | return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i); | 
|  | 136 | } | 
| Renato Golin | 4cd5187 | 2011-05-22 21:41:23 +0000 | [diff] [blame] | 137 |  | 
|  | 138 | // Adjust parameters for memset, EABI uses format (ptr, size, value), | 
|  | 139 | // GNU library uses (ptr, value, size) | 
|  | 140 | // See RTABI section 4.3.4 | 
|  | 141 | SDValue | 
|  | 142 | ARMSelectionDAGInfo::EmitTargetCodeForMemset(SelectionDAG &DAG, DebugLoc dl, | 
|  | 143 | SDValue Chain, SDValue Dst, | 
|  | 144 | SDValue Src, SDValue Size, | 
|  | 145 | unsigned Align, bool isVolatile, | 
|  | 146 | MachinePointerInfo DstPtrInfo) const | 
|  | 147 | { | 
|  | 148 | // Use default for non AAPCS subtargets | 
|  | 149 | if (!Subtarget->isAAPCS_ABI()) | 
|  | 150 | return SDValue(); | 
|  | 151 |  | 
|  | 152 | const ARMTargetLowering &TLI = | 
|  | 153 | *static_cast<const ARMTargetLowering*>(DAG.getTarget().getTargetLowering()); | 
|  | 154 | TargetLowering::ArgListTy Args; | 
|  | 155 | TargetLowering::ArgListEntry Entry; | 
|  | 156 |  | 
|  | 157 | // First argument: data pointer | 
|  | 158 | const Type *IntPtrTy = TLI.getTargetData()->getIntPtrType(*DAG.getContext()); | 
|  | 159 | Entry.Node = Dst; | 
|  | 160 | Entry.Ty = IntPtrTy; | 
|  | 161 | Args.push_back(Entry); | 
|  | 162 |  | 
|  | 163 | // Second argument: buffer size | 
|  | 164 | Entry.Node = Size; | 
|  | 165 | Entry.Ty = IntPtrTy; | 
|  | 166 | Entry.isSExt = false; | 
|  | 167 | Args.push_back(Entry); | 
|  | 168 |  | 
|  | 169 | // Extend or truncate the argument to be an i32 value for the call. | 
|  | 170 | if (Src.getValueType().bitsGT(MVT::i32)) | 
|  | 171 | Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src); | 
|  | 172 | else | 
|  | 173 | Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src); | 
|  | 174 |  | 
|  | 175 | // Third argument: value to fill | 
|  | 176 | Entry.Node = Src; | 
|  | 177 | Entry.Ty = Type::getInt32Ty(*DAG.getContext()); | 
|  | 178 | Entry.isSExt = true; | 
|  | 179 | Args.push_back(Entry); | 
|  | 180 |  | 
|  | 181 | // Emit __eabi_memset call | 
|  | 182 | std::pair<SDValue,SDValue> CallResult = | 
|  | 183 | TLI.LowerCallTo(Chain, | 
|  | 184 | Type::getVoidTy(*DAG.getContext()), // return type | 
|  | 185 | false, // return sign ext | 
|  | 186 | false, // return zero ext | 
|  | 187 | false, // is var arg | 
|  | 188 | false, // is in regs | 
|  | 189 | 0,     // number of fixed arguments | 
|  | 190 | TLI.getLibcallCallingConv(RTLIB::MEMSET), // call conv | 
|  | 191 | false, // is tail call | 
|  | 192 | false, // is return val used | 
|  | 193 | DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET), | 
|  | 194 | TLI.getPointerTy()), // callee | 
|  | 195 | Args, DAG, dl); // arg list, DAG and debug | 
|  | 196 |  | 
|  | 197 | return CallResult.second; | 
|  | 198 | } |