]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/NVPTX/NVPTXLowerAggrCopies.cpp
MFV r316928: 7256 low probability race in zfs_get_data
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / NVPTX / NVPTXLowerAggrCopies.cpp
1 //===- NVPTXLowerAggrCopies.cpp - ------------------------------*- C++ -*--===//
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 // \file
11 // Lower aggregate copies, memset, memcpy, memmov intrinsics into loops when
12 // the size is large or is not a compile-time constant.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "NVPTXLowerAggrCopies.h"
17 #include "llvm/CodeGen/StackProtector.h"
18 #include "llvm/IR/Constants.h"
19 #include "llvm/IR/DataLayout.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/IRBuilder.h"
22 #include "llvm/IR/Instructions.h"
23 #include "llvm/IR/IntrinsicInst.h"
24 #include "llvm/IR/Intrinsics.h"
25 #include "llvm/IR/LLVMContext.h"
26 #include "llvm/IR/Module.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
29
30 #define DEBUG_TYPE "nvptx"
31
32 using namespace llvm;
33
34 namespace {
35
36 // actual analysis class, which is a functionpass
37 struct NVPTXLowerAggrCopies : public FunctionPass {
38   static char ID;
39
40   NVPTXLowerAggrCopies() : FunctionPass(ID) {}
41
42   void getAnalysisUsage(AnalysisUsage &AU) const override {
43     AU.addPreserved<StackProtector>();
44   }
45
46   bool runOnFunction(Function &F) override;
47
48   static const unsigned MaxAggrCopySize = 128;
49
50   StringRef getPassName() const override {
51     return "Lower aggregate copies/intrinsics into loops";
52   }
53 };
54
55 char NVPTXLowerAggrCopies::ID = 0;
56
57 // Lower memcpy to loop.
58 void convertMemCpyToLoop(Instruction *ConvertedInst, Value *SrcAddr,
59                          Value *DstAddr, Value *CopyLen, bool SrcIsVolatile,
60                          bool DstIsVolatile, LLVMContext &Context,
61                          Function &F) {
62   Type *TypeOfCopyLen = CopyLen->getType();
63
64   BasicBlock *OrigBB = ConvertedInst->getParent();
65   BasicBlock *NewBB =
66       ConvertedInst->getParent()->splitBasicBlock(ConvertedInst, "split");
67   BasicBlock *LoopBB = BasicBlock::Create(Context, "loadstoreloop", &F, NewBB);
68
69   OrigBB->getTerminator()->setSuccessor(0, LoopBB);
70   IRBuilder<> Builder(OrigBB->getTerminator());
71
72   // SrcAddr and DstAddr are expected to be pointer types,
73   // so no check is made here.
74   unsigned SrcAS = cast<PointerType>(SrcAddr->getType())->getAddressSpace();
75   unsigned DstAS = cast<PointerType>(DstAddr->getType())->getAddressSpace();
76
77   // Cast pointers to (char *)
78   SrcAddr = Builder.CreateBitCast(SrcAddr, Builder.getInt8PtrTy(SrcAS));
79   DstAddr = Builder.CreateBitCast(DstAddr, Builder.getInt8PtrTy(DstAS));
80
81   IRBuilder<> LoopBuilder(LoopBB);
82   PHINode *LoopIndex = LoopBuilder.CreatePHI(TypeOfCopyLen, 0);
83   LoopIndex->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), OrigBB);
84
85   // load from SrcAddr+LoopIndex
86   // TODO: we can leverage the align parameter of llvm.memcpy for more efficient
87   // word-sized loads and stores.
88   Value *Element =
89       LoopBuilder.CreateLoad(LoopBuilder.CreateInBoundsGEP(
90                                  LoopBuilder.getInt8Ty(), SrcAddr, LoopIndex),
91                              SrcIsVolatile);
92   // store at DstAddr+LoopIndex
93   LoopBuilder.CreateStore(Element,
94                           LoopBuilder.CreateInBoundsGEP(LoopBuilder.getInt8Ty(),
95                                                         DstAddr, LoopIndex),
96                           DstIsVolatile);
97
98   // The value for LoopIndex coming from backedge is (LoopIndex + 1)
99   Value *NewIndex =
100       LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(TypeOfCopyLen, 1));
101   LoopIndex->addIncoming(NewIndex, LoopBB);
102
103   LoopBuilder.CreateCondBr(LoopBuilder.CreateICmpULT(NewIndex, CopyLen), LoopBB,
104                            NewBB);
105 }
106
107 // Lower memmove to IR. memmove is required to correctly copy overlapping memory
108 // regions; therefore, it has to check the relative positions of the source and
109 // destination pointers and choose the copy direction accordingly.
110 //
111 // The code below is an IR rendition of this C function:
112 //
113 // void* memmove(void* dst, const void* src, size_t n) {
114 //   unsigned char* d = dst;
115 //   const unsigned char* s = src;
116 //   if (s < d) {
117 //     // copy backwards
118 //     while (n--) {
119 //       d[n] = s[n];
120 //     }
121 //   } else {
122 //     // copy forward
123 //     for (size_t i = 0; i < n; ++i) {
124 //       d[i] = s[i];
125 //     }
126 //   }
127 //   return dst;
128 // }
129 void convertMemMoveToLoop(Instruction *ConvertedInst, Value *SrcAddr,
130                           Value *DstAddr, Value *CopyLen, bool SrcIsVolatile,
131                           bool DstIsVolatile, LLVMContext &Context,
132                           Function &F) {
133   Type *TypeOfCopyLen = CopyLen->getType();
134   BasicBlock *OrigBB = ConvertedInst->getParent();
135
136   // Create the a comparison of src and dst, based on which we jump to either
137   // the forward-copy part of the function (if src >= dst) or the backwards-copy
138   // part (if src < dst).
139   // SplitBlockAndInsertIfThenElse conveniently creates the basic if-then-else
140   // structure. Its block terminators (unconditional branches) are replaced by
141   // the appropriate conditional branches when the loop is built.
142   ICmpInst *PtrCompare = new ICmpInst(ConvertedInst, ICmpInst::ICMP_ULT,
143                                       SrcAddr, DstAddr, "compare_src_dst");
144   TerminatorInst *ThenTerm, *ElseTerm;
145   SplitBlockAndInsertIfThenElse(PtrCompare, ConvertedInst, &ThenTerm,
146                                 &ElseTerm);
147
148   // Each part of the function consists of two blocks:
149   //   copy_backwards:        used to skip the loop when n == 0
150   //   copy_backwards_loop:   the actual backwards loop BB
151   //   copy_forward:          used to skip the loop when n == 0
152   //   copy_forward_loop:     the actual forward loop BB
153   BasicBlock *CopyBackwardsBB = ThenTerm->getParent();
154   CopyBackwardsBB->setName("copy_backwards");
155   BasicBlock *CopyForwardBB = ElseTerm->getParent();
156   CopyForwardBB->setName("copy_forward");
157   BasicBlock *ExitBB = ConvertedInst->getParent();
158   ExitBB->setName("memmove_done");
159
160   // Initial comparison of n == 0 that lets us skip the loops altogether. Shared
161   // between both backwards and forward copy clauses.
162   ICmpInst *CompareN =
163       new ICmpInst(OrigBB->getTerminator(), ICmpInst::ICMP_EQ, CopyLen,
164                    ConstantInt::get(TypeOfCopyLen, 0), "compare_n_to_0");
165
166   // Copying backwards.
167   BasicBlock *LoopBB =
168       BasicBlock::Create(Context, "copy_backwards_loop", &F, CopyForwardBB);
169   IRBuilder<> LoopBuilder(LoopBB);
170   PHINode *LoopPhi = LoopBuilder.CreatePHI(TypeOfCopyLen, 0);
171   Value *IndexPtr = LoopBuilder.CreateSub(
172       LoopPhi, ConstantInt::get(TypeOfCopyLen, 1), "index_ptr");
173   Value *Element = LoopBuilder.CreateLoad(
174       LoopBuilder.CreateInBoundsGEP(SrcAddr, IndexPtr), "element");
175   LoopBuilder.CreateStore(Element,
176                           LoopBuilder.CreateInBoundsGEP(DstAddr, IndexPtr));
177   LoopBuilder.CreateCondBr(
178       LoopBuilder.CreateICmpEQ(IndexPtr, ConstantInt::get(TypeOfCopyLen, 0)),
179       ExitBB, LoopBB);
180   LoopPhi->addIncoming(IndexPtr, LoopBB);
181   LoopPhi->addIncoming(CopyLen, CopyBackwardsBB);
182   BranchInst::Create(ExitBB, LoopBB, CompareN, ThenTerm);
183   ThenTerm->eraseFromParent();
184
185   // Copying forward.
186   BasicBlock *FwdLoopBB =
187       BasicBlock::Create(Context, "copy_forward_loop", &F, ExitBB);
188   IRBuilder<> FwdLoopBuilder(FwdLoopBB);
189   PHINode *FwdCopyPhi = FwdLoopBuilder.CreatePHI(TypeOfCopyLen, 0, "index_ptr");
190   Value *FwdElement = FwdLoopBuilder.CreateLoad(
191       FwdLoopBuilder.CreateInBoundsGEP(SrcAddr, FwdCopyPhi), "element");
192   FwdLoopBuilder.CreateStore(
193       FwdElement, FwdLoopBuilder.CreateInBoundsGEP(DstAddr, FwdCopyPhi));
194   Value *FwdIndexPtr = FwdLoopBuilder.CreateAdd(
195       FwdCopyPhi, ConstantInt::get(TypeOfCopyLen, 1), "index_increment");
196   FwdLoopBuilder.CreateCondBr(FwdLoopBuilder.CreateICmpEQ(FwdIndexPtr, CopyLen),
197                               ExitBB, FwdLoopBB);
198   FwdCopyPhi->addIncoming(FwdIndexPtr, FwdLoopBB);
199   FwdCopyPhi->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), CopyForwardBB);
200
201   BranchInst::Create(ExitBB, FwdLoopBB, CompareN, ElseTerm);
202   ElseTerm->eraseFromParent();
203 }
204
205 // Lower memset to loop.
206 void convertMemSetToLoop(Instruction *ConvertedInst, Value *DstAddr,
207                          Value *CopyLen, Value *SetValue, LLVMContext &Context,
208                          Function &F) {
209   BasicBlock *OrigBB = ConvertedInst->getParent();
210   BasicBlock *NewBB =
211       ConvertedInst->getParent()->splitBasicBlock(ConvertedInst, "split");
212   BasicBlock *LoopBB = BasicBlock::Create(Context, "loadstoreloop", &F, NewBB);
213
214   OrigBB->getTerminator()->setSuccessor(0, LoopBB);
215   IRBuilder<> Builder(OrigBB->getTerminator());
216
217   // Cast pointer to the type of value getting stored
218   unsigned dstAS = cast<PointerType>(DstAddr->getType())->getAddressSpace();
219   DstAddr = Builder.CreateBitCast(DstAddr,
220                                   PointerType::get(SetValue->getType(), dstAS));
221
222   IRBuilder<> LoopBuilder(LoopBB);
223   PHINode *LoopIndex = LoopBuilder.CreatePHI(CopyLen->getType(), 0);
224   LoopIndex->addIncoming(ConstantInt::get(CopyLen->getType(), 0), OrigBB);
225
226   LoopBuilder.CreateStore(
227       SetValue,
228       LoopBuilder.CreateInBoundsGEP(SetValue->getType(), DstAddr, LoopIndex),
229       false);
230
231   Value *NewIndex =
232       LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(CopyLen->getType(), 1));
233   LoopIndex->addIncoming(NewIndex, LoopBB);
234
235   LoopBuilder.CreateCondBr(LoopBuilder.CreateICmpULT(NewIndex, CopyLen), LoopBB,
236                            NewBB);
237 }
238
239 bool NVPTXLowerAggrCopies::runOnFunction(Function &F) {
240   SmallVector<LoadInst *, 4> AggrLoads;
241   SmallVector<MemIntrinsic *, 4> MemCalls;
242
243   const DataLayout &DL = F.getParent()->getDataLayout();
244   LLVMContext &Context = F.getParent()->getContext();
245
246   // Collect all aggregate loads and mem* calls.
247   for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
248     for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE;
249          ++II) {
250       if (LoadInst *LI = dyn_cast<LoadInst>(II)) {
251         if (!LI->hasOneUse())
252           continue;
253
254         if (DL.getTypeStoreSize(LI->getType()) < MaxAggrCopySize)
255           continue;
256
257         if (StoreInst *SI = dyn_cast<StoreInst>(LI->user_back())) {
258           if (SI->getOperand(0) != LI)
259             continue;
260           AggrLoads.push_back(LI);
261         }
262       } else if (MemIntrinsic *IntrCall = dyn_cast<MemIntrinsic>(II)) {
263         // Convert intrinsic calls with variable size or with constant size
264         // larger than the MaxAggrCopySize threshold.
265         if (ConstantInt *LenCI = dyn_cast<ConstantInt>(IntrCall->getLength())) {
266           if (LenCI->getZExtValue() >= MaxAggrCopySize) {
267             MemCalls.push_back(IntrCall);
268           }
269         } else {
270           MemCalls.push_back(IntrCall);
271         }
272       }
273     }
274   }
275
276   if (AggrLoads.size() == 0 && MemCalls.size() == 0) {
277     return false;
278   }
279
280   //
281   // Do the transformation of an aggr load/copy/set to a loop
282   //
283   for (LoadInst *LI : AggrLoads) {
284     StoreInst *SI = dyn_cast<StoreInst>(*LI->user_begin());
285     Value *SrcAddr = LI->getOperand(0);
286     Value *DstAddr = SI->getOperand(1);
287     unsigned NumLoads = DL.getTypeStoreSize(LI->getType());
288     Value *CopyLen = ConstantInt::get(Type::getInt32Ty(Context), NumLoads);
289
290     convertMemCpyToLoop(/* ConvertedInst */ SI,
291                         /* SrcAddr */ SrcAddr, /* DstAddr */ DstAddr,
292                         /* CopyLen */ CopyLen,
293                         /* SrcIsVolatile */ LI->isVolatile(),
294                         /* DstIsVolatile */ SI->isVolatile(),
295                         /* Context */ Context,
296                         /* Function F */ F);
297
298     SI->eraseFromParent();
299     LI->eraseFromParent();
300   }
301
302   // Transform mem* intrinsic calls.
303   for (MemIntrinsic *MemCall : MemCalls) {
304     if (MemCpyInst *Memcpy = dyn_cast<MemCpyInst>(MemCall)) {
305       convertMemCpyToLoop(/* ConvertedInst */ Memcpy,
306                           /* SrcAddr */ Memcpy->getRawSource(),
307                           /* DstAddr */ Memcpy->getRawDest(),
308                           /* CopyLen */ Memcpy->getLength(),
309                           /* SrcIsVolatile */ Memcpy->isVolatile(),
310                           /* DstIsVolatile */ Memcpy->isVolatile(),
311                           /* Context */ Context,
312                           /* Function F */ F);
313     } else if (MemMoveInst *Memmove = dyn_cast<MemMoveInst>(MemCall)) {
314       convertMemMoveToLoop(/* ConvertedInst */ Memmove,
315                            /* SrcAddr */ Memmove->getRawSource(),
316                            /* DstAddr */ Memmove->getRawDest(),
317                            /* CopyLen */ Memmove->getLength(),
318                            /* SrcIsVolatile */ Memmove->isVolatile(),
319                            /* DstIsVolatile */ Memmove->isVolatile(),
320                            /* Context */ Context,
321                            /* Function F */ F);
322
323     } else if (MemSetInst *Memset = dyn_cast<MemSetInst>(MemCall)) {
324       convertMemSetToLoop(/* ConvertedInst */ Memset,
325                           /* DstAddr */ Memset->getRawDest(),
326                           /* CopyLen */ Memset->getLength(),
327                           /* SetValue */ Memset->getValue(),
328                           /* Context */ Context,
329                           /* Function F */ F);
330     }
331     MemCall->eraseFromParent();
332   }
333
334   return true;
335 }
336
337 } // namespace
338
339 namespace llvm {
340 void initializeNVPTXLowerAggrCopiesPass(PassRegistry &);
341 }
342
343 INITIALIZE_PASS(NVPTXLowerAggrCopies, "nvptx-lower-aggr-copies",
344                 "Lower aggregate copies, and llvm.mem* intrinsics into loops",
345                 false, false)
346
347 FunctionPass *llvm::createLowerAggrCopies() {
348   return new NVPTXLowerAggrCopies();
349 }