99a9cd5e646c3297dcd6455496d92ebd221f257d
[oota-llvm.git] / lib / Target / X86 / X86SelectionDAGInfo.cpp
1 //===-- X86SelectionDAGInfo.cpp - X86 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 X86SelectionDAGInfo class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #define DEBUG_TYPE "x86-selectiondag-info"
15 #include "X86TargetMachine.h"
16 #include "llvm/DerivedTypes.h"
17 #include "llvm/CodeGen/SelectionDAG.h"
18 using namespace llvm;
19
20 X86SelectionDAGInfo::X86SelectionDAGInfo(const X86TargetMachine &TM) :
21   TargetSelectionDAGInfo(TM),
22   Subtarget(&TM.getSubtarget<X86Subtarget>()),
23   TLI(*TM.getTargetLowering()) {
24 }
25
26 X86SelectionDAGInfo::~X86SelectionDAGInfo() {
27 }
28
29 SDValue
30 X86SelectionDAGInfo::EmitTargetCodeForMemset(SelectionDAG &DAG, DebugLoc dl,
31                                              SDValue Chain,
32                                              SDValue Dst, SDValue Src,
33                                              SDValue Size, unsigned Align,
34                                              bool isVolatile,
35                                          MachinePointerInfo DstPtrInfo) const {
36   ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
37
38   // If not DWORD aligned or size is more than the threshold, call the library.
39   // The libc version is likely to be faster for these cases. It can use the
40   // address value and run time information about the CPU.
41   if ((Align & 3) != 0 ||
42       !ConstantSize ||
43       ConstantSize->getZExtValue() >
44         Subtarget->getMaxInlineSizeThreshold()) {
45     SDValue InFlag(0, 0);
46
47     // Check to see if there is a specialized entry-point for memory zeroing.
48     ConstantSDNode *V = dyn_cast<ConstantSDNode>(Src);
49
50     if (const char *bzeroEntry =  V &&
51         V->isNullValue() ? Subtarget->getBZeroEntry() : 0) {
52       EVT IntPtr = TLI.getPointerTy();
53       const Type *IntPtrTy = getTargetData()->getIntPtrType(*DAG.getContext());
54       TargetLowering::ArgListTy Args;
55       TargetLowering::ArgListEntry Entry;
56       Entry.Node = Dst;
57       Entry.Ty = IntPtrTy;
58       Args.push_back(Entry);
59       Entry.Node = Size;
60       Args.push_back(Entry);
61       std::pair<SDValue,SDValue> CallResult =
62         TLI.LowerCallTo(Chain, Type::getVoidTy(*DAG.getContext()),
63                         false, false, false, false,
64                         0, CallingConv::C, false, /*isReturnValueUsed=*/false,
65                         DAG.getExternalSymbol(bzeroEntry, IntPtr), Args,
66                         DAG, dl);
67       return CallResult.second;
68     }
69
70     // Otherwise have the target-independent code call memset.
71     return SDValue();
72   }
73
74   uint64_t SizeVal = ConstantSize->getZExtValue();
75   SDValue InFlag(0, 0);
76   EVT AVT;
77   SDValue Count;
78   ConstantSDNode *ValC = dyn_cast<ConstantSDNode>(Src);
79   unsigned BytesLeft = 0;
80   bool TwoRepStos = false;
81   if (ValC) {
82     unsigned ValReg;
83     uint64_t Val = ValC->getZExtValue() & 255;
84
85     // If the value is a constant, then we can potentially use larger sets.
86     switch (Align & 3) {
87     case 2:   // WORD aligned
88       AVT = MVT::i16;
89       ValReg = X86::AX;
90       Val = (Val << 8) | Val;
91       break;
92     case 0:  // DWORD aligned
93       AVT = MVT::i32;
94       ValReg = X86::EAX;
95       Val = (Val << 8)  | Val;
96       Val = (Val << 16) | Val;
97       if (Subtarget->is64Bit() && ((Align & 0x7) == 0)) {  // QWORD aligned
98         AVT = MVT::i64;
99         ValReg = X86::RAX;
100         Val = (Val << 32) | Val;
101       }
102       break;
103     default:  // Byte aligned
104       AVT = MVT::i8;
105       ValReg = X86::AL;
106       Count = DAG.getIntPtrConstant(SizeVal);
107       break;
108     }
109
110     if (AVT.bitsGT(MVT::i8)) {
111       unsigned UBytes = AVT.getSizeInBits() / 8;
112       Count = DAG.getIntPtrConstant(SizeVal / UBytes);
113       BytesLeft = SizeVal % UBytes;
114     }
115
116     Chain  = DAG.getCopyToReg(Chain, dl, ValReg, DAG.getConstant(Val, AVT),
117                               InFlag);
118     InFlag = Chain.getValue(1);
119   } else {
120     AVT = MVT::i8;
121     Count  = DAG.getIntPtrConstant(SizeVal);
122     Chain  = DAG.getCopyToReg(Chain, dl, X86::AL, Src, InFlag);
123     InFlag = Chain.getValue(1);
124   }
125
126   Chain  = DAG.getCopyToReg(Chain, dl, Subtarget->is64Bit() ? X86::RCX :
127                                                               X86::ECX,
128                             Count, InFlag);
129   InFlag = Chain.getValue(1);
130   Chain  = DAG.getCopyToReg(Chain, dl, Subtarget->is64Bit() ? X86::RDI :
131                                                               X86::EDI,
132                             Dst, InFlag);
133   InFlag = Chain.getValue(1);
134
135   SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag);
136   SDValue Ops[] = { Chain, DAG.getValueType(AVT), InFlag };
137   Chain = DAG.getNode(X86ISD::REP_STOS, dl, Tys, Ops, array_lengthof(Ops));
138
139   if (TwoRepStos) {
140     InFlag = Chain.getValue(1);
141     Count  = Size;
142     EVT CVT = Count.getValueType();
143     SDValue Left = DAG.getNode(ISD::AND, dl, CVT, Count,
144                                DAG.getConstant((AVT == MVT::i64) ? 7 : 3, CVT));
145     Chain  = DAG.getCopyToReg(Chain, dl, (CVT == MVT::i64) ? X86::RCX :
146                                                              X86::ECX,
147                               Left, InFlag);
148     InFlag = Chain.getValue(1);
149     Tys = DAG.getVTList(MVT::Other, MVT::Flag);
150     SDValue Ops[] = { Chain, DAG.getValueType(MVT::i8), InFlag };
151     Chain = DAG.getNode(X86ISD::REP_STOS, dl, Tys, Ops, array_lengthof(Ops));
152   } else if (BytesLeft) {
153     // Handle the last 1 - 7 bytes.
154     unsigned Offset = SizeVal - BytesLeft;
155     EVT AddrVT = Dst.getValueType();
156     EVT SizeVT = Size.getValueType();
157
158     Chain = DAG.getMemset(Chain, dl,
159                           DAG.getNode(ISD::ADD, dl, AddrVT, Dst,
160                                       DAG.getConstant(Offset, AddrVT)),
161                           Src,
162                           DAG.getConstant(BytesLeft, SizeVT),
163                           Align, isVolatile, DstPtrInfo.getWithOffset(Offset));
164   }
165
166   // TODO: Use a Tokenfactor, as in memcpy, instead of a single chain.
167   return Chain;
168 }
169
170 SDValue
171 X86SelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
172                                         SDValue Chain, SDValue Dst, SDValue Src,
173                                         SDValue Size, unsigned Align,
174                                         bool isVolatile, bool AlwaysInline,
175                                          MachinePointerInfo DstPtrInfo,
176                                          MachinePointerInfo SrcPtrInfo) const {
177   // This requires the copy size to be a constant, preferrably
178   // within a subtarget-specific limit.
179   ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
180   if (!ConstantSize)
181     return SDValue();
182   uint64_t SizeVal = ConstantSize->getZExtValue();
183   if (!AlwaysInline && SizeVal > Subtarget->getMaxInlineSizeThreshold())
184     return SDValue();
185
186   /// If not DWORD aligned, call the library.
187   if ((Align & 3) != 0)
188     return SDValue();
189
190   // DWORD aligned
191   EVT AVT = MVT::i32;
192   if (Subtarget->is64Bit() && ((Align & 0x7) == 0))  // QWORD aligned
193     AVT = MVT::i64;
194
195   unsigned UBytes = AVT.getSizeInBits() / 8;
196   unsigned CountVal = SizeVal / UBytes;
197   SDValue Count = DAG.getIntPtrConstant(CountVal);
198   unsigned BytesLeft = SizeVal % UBytes;
199
200   SDValue InFlag(0, 0);
201   Chain  = DAG.getCopyToReg(Chain, dl, Subtarget->is64Bit() ? X86::RCX :
202                                                               X86::ECX,
203                             Count, InFlag);
204   InFlag = Chain.getValue(1);
205   Chain  = DAG.getCopyToReg(Chain, dl, Subtarget->is64Bit() ? X86::RDI :
206                                                               X86::EDI,
207                             Dst, InFlag);
208   InFlag = Chain.getValue(1);
209   Chain  = DAG.getCopyToReg(Chain, dl, Subtarget->is64Bit() ? X86::RSI :
210                                                               X86::ESI,
211                             Src, InFlag);
212   InFlag = Chain.getValue(1);
213
214   SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag);
215   SDValue Ops[] = { Chain, DAG.getValueType(AVT), InFlag };
216   SDValue RepMovs = DAG.getNode(X86ISD::REP_MOVS, dl, Tys, Ops,
217                                 array_lengthof(Ops));
218
219   SmallVector<SDValue, 4> Results;
220   Results.push_back(RepMovs);
221   if (BytesLeft) {
222     // Handle the last 1 - 7 bytes.
223     unsigned Offset = SizeVal - BytesLeft;
224     EVT DstVT = Dst.getValueType();
225     EVT SrcVT = Src.getValueType();
226     EVT SizeVT = Size.getValueType();
227     Results.push_back(DAG.getMemcpy(Chain, dl,
228                                     DAG.getNode(ISD::ADD, dl, DstVT, Dst,
229                                                 DAG.getConstant(Offset, DstVT)),
230                                     DAG.getNode(ISD::ADD, dl, SrcVT, Src,
231                                                 DAG.getConstant(Offset, SrcVT)),
232                                     DAG.getConstant(BytesLeft, SizeVT),
233                                     Align, isVolatile, AlwaysInline,
234                                     DstPtrInfo.getWithOffset(Offset),
235                                     SrcPtrInfo.getWithOffset(Offset)));
236   }
237
238   return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
239                      &Results[0], Results.size());
240 }