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