149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski//===- NVPTXLowerAggrCopies.cpp - ------------------------------*- C++ -*--===// 249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// 349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// The LLVM Compiler Infrastructure 449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// 549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// This file is distributed under the University of Illinois Open Source 649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// License. See LICENSE.TXT for details. 749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// 849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski//===----------------------------------------------------------------------===// 949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// Lower aggregate copies, memset, memcpy, memmov intrinsics into loops when 1049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// the size is large or is not a compile-time constant. 1149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// 1249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski//===----------------------------------------------------------------------===// 1349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 1406cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth#include "NVPTXLowerAggrCopies.h" 150b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Constants.h" 160b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/DataLayout.h" 170b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Function.h" 180b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/IRBuilder.h" 190b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Instructions.h" 200b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/IntrinsicInst.h" 210b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Intrinsics.h" 220b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/LLVMContext.h" 230b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Module.h" 2449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski#include "llvm/Support/InstIterator.h" 2549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 2649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinskiusing namespace llvm; 2749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 283639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinskinamespace llvm { FunctionPass *createLowerAggrCopies(); } 2949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 3049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinskichar NVPTXLowerAggrCopies::ID = 0; 3149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 3249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// Lower MemTransferInst or load-store pair to loop 333639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinskistatic void convertTransferToLoop( 343639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski Instruction *splitAt, Value *srcAddr, Value *dstAddr, Value *len, 353639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski //unsigned numLoads, 363639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski bool srcVolatile, bool dstVolatile, LLVMContext &Context, Function &F) { 3749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Type *indType = len->getType(); 3849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 3949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski BasicBlock *origBB = splitAt->getParent(); 4049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski BasicBlock *newBB = splitAt->getParent()->splitBasicBlock(splitAt, "split"); 4149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski BasicBlock *loopBB = BasicBlock::Create(Context, "loadstoreloop", &F, newBB); 4249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 4349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski origBB->getTerminator()->setSuccessor(0, loopBB); 4449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski IRBuilder<> builder(origBB, origBB->getTerminator()); 4549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 4649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // srcAddr and dstAddr are expected to be pointer types, 4749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // so no check is made here. 483639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski unsigned srcAS = dyn_cast<PointerType>(srcAddr->getType())->getAddressSpace(); 493639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski unsigned dstAS = dyn_cast<PointerType>(dstAddr->getType())->getAddressSpace(); 5049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 5149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // Cast pointers to (char *) 5249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski srcAddr = builder.CreateBitCast(srcAddr, Type::getInt8PtrTy(Context, srcAS)); 5349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski dstAddr = builder.CreateBitCast(dstAddr, Type::getInt8PtrTy(Context, dstAS)); 5449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 5549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski IRBuilder<> loop(loopBB); 5649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // The loop index (ind) is a phi node. 5749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski PHINode *ind = loop.CreatePHI(indType, 0); 5849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // Incoming value for ind is 0 5949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski ind->addIncoming(ConstantInt::get(indType, 0), origBB); 6049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 6149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // load from srcAddr+ind 6249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *val = loop.CreateLoad(loop.CreateGEP(srcAddr, ind), srcVolatile); 6349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // store at dstAddr+ind 6449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski loop.CreateStore(val, loop.CreateGEP(dstAddr, ind), dstVolatile); 6549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 6649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // The value for ind coming from backedge is (ind + 1) 6749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *newind = loop.CreateAdd(ind, ConstantInt::get(indType, 1)); 6849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski ind->addIncoming(newind, loopBB); 6949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 7049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski loop.CreateCondBr(loop.CreateICmpULT(newind, len), loopBB, newBB); 7149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski} 7249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 7349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski// Lower MemSetInst to loop 7449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinskistatic void convertMemSetToLoop(Instruction *splitAt, Value *dstAddr, 7549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *len, Value *val, LLVMContext &Context, 7649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Function &F) { 7749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski BasicBlock *origBB = splitAt->getParent(); 7849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski BasicBlock *newBB = splitAt->getParent()->splitBasicBlock(splitAt, "split"); 7949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski BasicBlock *loopBB = BasicBlock::Create(Context, "loadstoreloop", &F, newBB); 8049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 8149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski origBB->getTerminator()->setSuccessor(0, loopBB); 8249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski IRBuilder<> builder(origBB, origBB->getTerminator()); 8349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 843639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski unsigned dstAS = dyn_cast<PointerType>(dstAddr->getType())->getAddressSpace(); 8549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 8649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // Cast pointer to the type of value getting stored 873639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski dstAddr = 883639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski builder.CreateBitCast(dstAddr, PointerType::get(val->getType(), dstAS)); 8949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 9049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski IRBuilder<> loop(loopBB); 9149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski PHINode *ind = loop.CreatePHI(len->getType(), 0); 9249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski ind->addIncoming(ConstantInt::get(len->getType(), 0), origBB); 9349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 9449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski loop.CreateStore(val, loop.CreateGEP(dstAddr, ind), false); 9549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 9649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *newind = loop.CreateAdd(ind, ConstantInt::get(len->getType(), 1)); 9749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski ind->addIncoming(newind, loopBB); 9849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 9949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski loop.CreateCondBr(loop.CreateICmpULT(newind, len), loopBB, newBB); 10049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski} 10149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 10249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinskibool NVPTXLowerAggrCopies::runOnFunction(Function &F) { 10349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski SmallVector<LoadInst *, 4> aggrLoads; 10449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski SmallVector<MemTransferInst *, 4> aggrMemcpys; 10549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski SmallVector<MemSetInst *, 4> aggrMemsets; 10649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 1073574eca1b02600bac4e625297f4ecf745f4c4f32Micah Villmow DataLayout *TD = &getAnalysis<DataLayout>(); 10849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski LLVMContext &Context = F.getParent()->getContext(); 10949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 11049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // 11149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // Collect all the aggrLoads, aggrMemcpys and addrMemsets. 11249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // 11349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski //const BasicBlock *firstBB = &F.front(); // first BB in F 11449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { 11549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski //BasicBlock *bb = BI; 11649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE; 1173639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski ++II) { 1183639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if (LoadInst *load = dyn_cast<LoadInst>(II)) { 11949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 1203639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if (load->hasOneUse() == false) 1213639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski continue; 12249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 1233639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if (TD->getTypeStoreSize(load->getType()) < MaxAggrCopySize) 1243639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski continue; 12549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 12649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski User *use = *(load->use_begin()); 1273639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if (StoreInst *store = dyn_cast<StoreInst>(use)) { 12849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski if (store->getOperand(0) != load) //getValueOperand 1293639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski continue; 13049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski aggrLoads.push_back(load); 13149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 1323639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski } else if (MemTransferInst *intr = dyn_cast<MemTransferInst>(II)) { 13349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *len = intr->getLength(); 13449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // If the number of elements being copied is greater 13549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // than MaxAggrCopySize, lower it to a loop 1363639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if (ConstantInt *len_int = dyn_cast<ConstantInt>(len)) { 13749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski if (len_int->getZExtValue() >= MaxAggrCopySize) { 13849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski aggrMemcpys.push_back(intr); 13949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 14049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } else { 14149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // turn variable length memcpy/memmov into loop 14249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski aggrMemcpys.push_back(intr); 14349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 1443639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski } else if (MemSetInst *memsetintr = dyn_cast<MemSetInst>(II)) { 14549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *len = memsetintr->getLength(); 1463639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if (ConstantInt *len_int = dyn_cast<ConstantInt>(len)) { 14749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski if (len_int->getZExtValue() >= MaxAggrCopySize) { 14849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski aggrMemsets.push_back(memsetintr); 14949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 15049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } else { 15149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // turn variable length memset into loop 15249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski aggrMemsets.push_back(memsetintr); 15349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 15449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 15549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 15649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 1573639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski if ((aggrLoads.size() == 0) && (aggrMemcpys.size() == 0) && 1583639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski (aggrMemsets.size() == 0)) 1593639ce2575660a0e6938d2e84e8bd9a738fd7051Justin Holewinski return false; 16049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 16149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // 16249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // Do the transformation of an aggr load/copy/set to a loop 16349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // 16449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski for (unsigned i = 0, e = aggrLoads.size(); i != e; ++i) { 16549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski LoadInst *load = aggrLoads[i]; 16649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski StoreInst *store = dyn_cast<StoreInst>(*load->use_begin()); 16749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *srcAddr = load->getOperand(0); 16849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *dstAddr = store->getOperand(1); 16949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski unsigned numLoads = TD->getTypeStoreSize(load->getType()); 17049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *len = ConstantInt::get(Type::getInt32Ty(Context), numLoads); 17149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 17249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski convertTransferToLoop(store, srcAddr, dstAddr, len, load->isVolatile(), 17349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski store->isVolatile(), Context, F); 17449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 17549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski store->eraseFromParent(); 17649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski load->eraseFromParent(); 17749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 17849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 17949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski for (unsigned i = 0, e = aggrMemcpys.size(); i != e; ++i) { 18049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski MemTransferInst *cpy = aggrMemcpys[i]; 18149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *len = cpy->getLength(); 18249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // llvm 2.7 version of memcpy does not have volatile 18349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // operand yet. So always making it non-volatile 18449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // optimistically, so that we don't see unnecessary 18549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski // st.volatile in ptx 18649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski convertTransferToLoop(cpy, cpy->getSource(), cpy->getDest(), len, false, 18749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski false, Context, F); 18849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski cpy->eraseFromParent(); 18949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 19049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 19149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski for (unsigned i = 0, e = aggrMemsets.size(); i != e; ++i) { 19249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski MemSetInst *memsetinst = aggrMemsets[i]; 19349683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *len = memsetinst->getLength(); 19449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski Value *val = memsetinst->getValue(); 19549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski convertMemSetToLoop(memsetinst, memsetinst->getDest(), len, val, Context, 19649683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski F); 19749683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski memsetinst->eraseFromParent(); 19849683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski } 19949683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 20049683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski return true; 20149683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski} 20249683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski 20349683f3c961379fbc088871a5d6304950f1f1cbcJustin HolewinskiFunctionPass *llvm::createLowerAggrCopies() { 20449683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski return new NVPTXLowerAggrCopies(); 20549683f3c961379fbc088871a5d6304950f1f1cbcJustin Holewinski} 206