1251607Sdim//===-- GenericToNVVM.cpp - Convert generic module to NVVM module - C++ -*-===// 2251607Sdim// 3251607Sdim// The LLVM Compiler Infrastructure 4251607Sdim// 5251607Sdim// This file is distributed under the University of Illinois Open Source 6251607Sdim// License. See LICENSE.TXT for details. 7251607Sdim// 8251607Sdim//===----------------------------------------------------------------------===// 9251607Sdim// 10251607Sdim// Convert generic global variables into either .global or .const access based 11251607Sdim// on the variable's "constant" qualifier. 12251607Sdim// 13251607Sdim//===----------------------------------------------------------------------===// 14251607Sdim 15251607Sdim#include "NVPTX.h" 16251607Sdim#include "NVPTXUtilities.h" 17251607Sdim#include "MCTargetDesc/NVPTXBaseInfo.h" 18251607Sdim 19251607Sdim#include "llvm/PassManager.h" 20251607Sdim#include "llvm/IR/Constants.h" 21251607Sdim#include "llvm/IR/DerivedTypes.h" 22251607Sdim#include "llvm/IR/Instructions.h" 23251607Sdim#include "llvm/IR/Intrinsics.h" 24251607Sdim#include "llvm/IR/Module.h" 25251607Sdim#include "llvm/IR/Operator.h" 26251607Sdim#include "llvm/ADT/ValueMap.h" 27251607Sdim#include "llvm/CodeGen/MachineFunctionAnalysis.h" 28251607Sdim#include "llvm/CodeGen/ValueTypes.h" 29251607Sdim#include "llvm/IR/IRBuilder.h" 30251607Sdim 31251607Sdimusing namespace llvm; 32251607Sdim 33251607Sdimnamespace llvm { 34251607Sdimvoid initializeGenericToNVVMPass(PassRegistry &); 35251607Sdim} 36251607Sdim 37251607Sdimnamespace { 38251607Sdimclass GenericToNVVM : public ModulePass { 39251607Sdimpublic: 40251607Sdim static char ID; 41251607Sdim 42251607Sdim GenericToNVVM() : ModulePass(ID) {} 43251607Sdim 44251607Sdim virtual bool runOnModule(Module &M); 45251607Sdim 46251607Sdim virtual void getAnalysisUsage(AnalysisUsage &AU) const { 47251607Sdim } 48251607Sdim 49251607Sdimprivate: 50251607Sdim Value *getOrInsertCVTA(Module *M, Function *F, GlobalVariable *GV, 51251607Sdim IRBuilder<> &Builder); 52251607Sdim Value *remapConstant(Module *M, Function *F, Constant *C, 53251607Sdim IRBuilder<> &Builder); 54251607Sdim Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F, 55251607Sdim Constant *C, 56251607Sdim IRBuilder<> &Builder); 57251607Sdim Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 58251607Sdim IRBuilder<> &Builder); 59251607Sdim void remapNamedMDNode(Module *M, NamedMDNode *N); 60251607Sdim MDNode *remapMDNode(Module *M, MDNode *N); 61251607Sdim 62251607Sdim typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy; 63251607Sdim typedef ValueMap<Constant *, Value *> ConstantToValueMapTy; 64251607Sdim GVMapTy GVMap; 65251607Sdim ConstantToValueMapTy ConstantToValueMap; 66251607Sdim}; 67251607Sdim} 68251607Sdim 69251607Sdimchar GenericToNVVM::ID = 0; 70251607Sdim 71251607SdimModulePass *llvm::createGenericToNVVMPass() { return new GenericToNVVM(); } 72251607Sdim 73251607SdimINITIALIZE_PASS( 74251607Sdim GenericToNVVM, "generic-to-nvvm", 75251607Sdim "Ensure that the global variables are in the global address space", false, 76251607Sdim false) 77251607Sdim 78251607Sdimbool GenericToNVVM::runOnModule(Module &M) { 79251607Sdim // Create a clone of each global variable that has the default address space. 80251607Sdim // The clone is created with the global address space specifier, and the pair 81251607Sdim // of original global variable and its clone is placed in the GVMap for later 82251607Sdim // use. 83251607Sdim 84251607Sdim for (Module::global_iterator I = M.global_begin(), E = M.global_end(); 85251607Sdim I != E;) { 86251607Sdim GlobalVariable *GV = I++; 87251607Sdim if (GV->getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && 88251607Sdim !llvm::isTexture(*GV) && !llvm::isSurface(*GV) && 89251607Sdim !GV->getName().startswith("llvm.")) { 90251607Sdim GlobalVariable *NewGV = new GlobalVariable( 91251607Sdim M, GV->getType()->getElementType(), GV->isConstant(), 92251607Sdim GV->getLinkage(), GV->hasInitializer() ? GV->getInitializer() : NULL, 93251607Sdim "", GV, GV->getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); 94251607Sdim NewGV->copyAttributesFrom(GV); 95251607Sdim GVMap[GV] = NewGV; 96251607Sdim } 97251607Sdim } 98251607Sdim 99251607Sdim // Return immediately, if every global variable has a specific address space 100251607Sdim // specifier. 101251607Sdim if (GVMap.empty()) { 102251607Sdim return false; 103251607Sdim } 104251607Sdim 105251607Sdim // Walk through the instructions in function defitinions, and replace any use 106251607Sdim // of original global variables in GVMap with a use of the corresponding 107251607Sdim // copies in GVMap. If necessary, promote constants to instructions. 108251607Sdim for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { 109251607Sdim if (I->isDeclaration()) { 110251607Sdim continue; 111251607Sdim } 112251607Sdim IRBuilder<> Builder(I->getEntryBlock().getFirstNonPHIOrDbg()); 113251607Sdim for (Function::iterator BBI = I->begin(), BBE = I->end(); BBI != BBE; 114251607Sdim ++BBI) { 115251607Sdim for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; 116251607Sdim ++II) { 117251607Sdim for (unsigned i = 0, e = II->getNumOperands(); i < e; ++i) { 118251607Sdim Value *Operand = II->getOperand(i); 119251607Sdim if (isa<Constant>(Operand)) { 120251607Sdim II->setOperand( 121251607Sdim i, remapConstant(&M, I, cast<Constant>(Operand), Builder)); 122251607Sdim } 123251607Sdim } 124251607Sdim } 125251607Sdim } 126251607Sdim ConstantToValueMap.clear(); 127251607Sdim } 128251607Sdim 129251607Sdim // Walk through the metadata section and update the debug information 130251607Sdim // associated with the global variables in the default address space. 131251607Sdim for (Module::named_metadata_iterator I = M.named_metadata_begin(), 132251607Sdim E = M.named_metadata_end(); 133251607Sdim I != E; I++) { 134251607Sdim remapNamedMDNode(&M, I); 135251607Sdim } 136251607Sdim 137251607Sdim // Walk through the global variable initializers, and replace any use of 138251607Sdim // original global variables in GVMap with a use of the corresponding copies 139251607Sdim // in GVMap. The copies need to be bitcast to the original global variable 140251607Sdim // types, as we cannot use cvta in global variable initializers. 141251607Sdim for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { 142251607Sdim GlobalVariable *GV = I->first; 143251607Sdim GlobalVariable *NewGV = I->second; 144251607Sdim ++I; 145251607Sdim Constant *BitCastNewGV = ConstantExpr::getBitCast(NewGV, GV->getType()); 146251607Sdim // At this point, the remaining uses of GV should be found only in global 147251607Sdim // variable initializers, as other uses have been already been removed 148251607Sdim // while walking through the instructions in function definitions. 149251607Sdim for (Value::use_iterator UI = GV->use_begin(), UE = GV->use_end(); 150251607Sdim UI != UE;) { 151251607Sdim Use &U = (UI++).getUse(); 152251607Sdim U.set(BitCastNewGV); 153251607Sdim } 154251607Sdim std::string Name = GV->getName(); 155251607Sdim GV->removeDeadConstantUsers(); 156251607Sdim GV->eraseFromParent(); 157251607Sdim NewGV->setName(Name); 158251607Sdim } 159251607Sdim GVMap.clear(); 160251607Sdim 161251607Sdim return true; 162251607Sdim} 163251607Sdim 164251607SdimValue *GenericToNVVM::getOrInsertCVTA(Module *M, Function *F, 165251607Sdim GlobalVariable *GV, 166251607Sdim IRBuilder<> &Builder) { 167251607Sdim PointerType *GVType = GV->getType(); 168251607Sdim Value *CVTA = NULL; 169251607Sdim 170251607Sdim // See if the address space conversion requires the operand to be bitcast 171251607Sdim // to i8 addrspace(n)* first. 172251607Sdim EVT ExtendedGVType = EVT::getEVT(GVType->getElementType(), true); 173251607Sdim if (!ExtendedGVType.isInteger() && !ExtendedGVType.isFloatingPoint()) { 174251607Sdim // A bitcast to i8 addrspace(n)* on the operand is needed. 175251607Sdim LLVMContext &Context = M->getContext(); 176251607Sdim unsigned int AddrSpace = GVType->getAddressSpace(); 177251607Sdim Type *DestTy = PointerType::get(Type::getInt8Ty(Context), AddrSpace); 178251607Sdim CVTA = Builder.CreateBitCast(GV, DestTy, "cvta"); 179251607Sdim // Insert the address space conversion. 180251607Sdim Type *ResultType = 181251607Sdim PointerType::get(Type::getInt8Ty(Context), llvm::ADDRESS_SPACE_GENERIC); 182251607Sdim SmallVector<Type *, 2> ParamTypes; 183251607Sdim ParamTypes.push_back(ResultType); 184251607Sdim ParamTypes.push_back(DestTy); 185251607Sdim Function *CVTAFunction = Intrinsic::getDeclaration( 186251607Sdim M, Intrinsic::nvvm_ptr_global_to_gen, ParamTypes); 187251607Sdim CVTA = Builder.CreateCall(CVTAFunction, CVTA, "cvta"); 188251607Sdim // Another bitcast from i8 * to <the element type of GVType> * is 189251607Sdim // required. 190251607Sdim DestTy = 191251607Sdim PointerType::get(GVType->getElementType(), llvm::ADDRESS_SPACE_GENERIC); 192251607Sdim CVTA = Builder.CreateBitCast(CVTA, DestTy, "cvta"); 193251607Sdim } else { 194251607Sdim // A simple CVTA is enough. 195251607Sdim SmallVector<Type *, 2> ParamTypes; 196251607Sdim ParamTypes.push_back(PointerType::get(GVType->getElementType(), 197251607Sdim llvm::ADDRESS_SPACE_GENERIC)); 198251607Sdim ParamTypes.push_back(GVType); 199251607Sdim Function *CVTAFunction = Intrinsic::getDeclaration( 200251607Sdim M, Intrinsic::nvvm_ptr_global_to_gen, ParamTypes); 201251607Sdim CVTA = Builder.CreateCall(CVTAFunction, GV, "cvta"); 202251607Sdim } 203251607Sdim 204251607Sdim return CVTA; 205251607Sdim} 206251607Sdim 207251607SdimValue *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C, 208251607Sdim IRBuilder<> &Builder) { 209251607Sdim // If the constant C has been converted already in the given function F, just 210251607Sdim // return the converted value. 211251607Sdim ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C); 212251607Sdim if (CTII != ConstantToValueMap.end()) { 213251607Sdim return CTII->second; 214251607Sdim } 215251607Sdim 216251607Sdim Value *NewValue = C; 217251607Sdim if (isa<GlobalVariable>(C)) { 218251607Sdim // If the constant C is a global variable and is found in GVMap, generate a 219251607Sdim // set set of instructions that convert the clone of C with the global 220251607Sdim // address space specifier to a generic pointer. 221251607Sdim // The constant C cannot be used here, as it will be erased from the 222251607Sdim // module eventually. And the clone of C with the global address space 223251607Sdim // specifier cannot be used here either, as it will affect the types of 224251607Sdim // other instructions in the function. Hence, this address space conversion 225251607Sdim // is required. 226251607Sdim GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C)); 227251607Sdim if (I != GVMap.end()) { 228251607Sdim NewValue = getOrInsertCVTA(M, F, I->second, Builder); 229251607Sdim } 230251607Sdim } else if (isa<ConstantVector>(C) || isa<ConstantArray>(C) || 231251607Sdim isa<ConstantStruct>(C)) { 232251607Sdim // If any element in the constant vector or aggregate C is or uses a global 233251607Sdim // variable in GVMap, the constant C needs to be reconstructed, using a set 234251607Sdim // of instructions. 235251607Sdim NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder); 236251607Sdim } else if (isa<ConstantExpr>(C)) { 237251607Sdim // If any operand in the constant expression C is or uses a global variable 238251607Sdim // in GVMap, the constant expression C needs to be reconstructed, using a 239251607Sdim // set of instructions. 240251607Sdim NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); 241251607Sdim } 242251607Sdim 243251607Sdim ConstantToValueMap[C] = NewValue; 244251607Sdim return NewValue; 245251607Sdim} 246251607Sdim 247251607SdimValue *GenericToNVVM::remapConstantVectorOrConstantAggregate( 248251607Sdim Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { 249251607Sdim bool OperandChanged = false; 250251607Sdim SmallVector<Value *, 4> NewOperands; 251251607Sdim unsigned NumOperands = C->getNumOperands(); 252251607Sdim 253251607Sdim // Check if any element is or uses a global variable in GVMap, and thus 254251607Sdim // converted to another value. 255251607Sdim for (unsigned i = 0; i < NumOperands; ++i) { 256251607Sdim Value *Operand = C->getOperand(i); 257251607Sdim Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 258251607Sdim OperandChanged |= Operand != NewOperand; 259251607Sdim NewOperands.push_back(NewOperand); 260251607Sdim } 261251607Sdim 262251607Sdim // If none of the elements has been modified, return C as it is. 263251607Sdim if (!OperandChanged) { 264251607Sdim return C; 265251607Sdim } 266251607Sdim 267251607Sdim // If any of the elements has been modified, construct the equivalent 268251607Sdim // vector or aggregate value with a set instructions and the converted 269251607Sdim // elements. 270251607Sdim Value *NewValue = UndefValue::get(C->getType()); 271251607Sdim if (isa<ConstantVector>(C)) { 272251607Sdim for (unsigned i = 0; i < NumOperands; ++i) { 273251607Sdim Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); 274251607Sdim NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); 275251607Sdim } 276251607Sdim } else { 277251607Sdim for (unsigned i = 0; i < NumOperands; ++i) { 278251607Sdim NewValue = 279251607Sdim Builder.CreateInsertValue(NewValue, NewOperands[i], makeArrayRef(i)); 280251607Sdim } 281251607Sdim } 282251607Sdim 283251607Sdim return NewValue; 284251607Sdim} 285251607Sdim 286251607SdimValue *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 287251607Sdim IRBuilder<> &Builder) { 288251607Sdim bool OperandChanged = false; 289251607Sdim SmallVector<Value *, 4> NewOperands; 290251607Sdim unsigned NumOperands = C->getNumOperands(); 291251607Sdim 292251607Sdim // Check if any operand is or uses a global variable in GVMap, and thus 293251607Sdim // converted to another value. 294251607Sdim for (unsigned i = 0; i < NumOperands; ++i) { 295251607Sdim Value *Operand = C->getOperand(i); 296251607Sdim Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 297251607Sdim OperandChanged |= Operand != NewOperand; 298251607Sdim NewOperands.push_back(NewOperand); 299251607Sdim } 300251607Sdim 301251607Sdim // If none of the operands has been modified, return C as it is. 302251607Sdim if (!OperandChanged) { 303251607Sdim return C; 304251607Sdim } 305251607Sdim 306251607Sdim // If any of the operands has been modified, construct the instruction with 307251607Sdim // the converted operands. 308251607Sdim unsigned Opcode = C->getOpcode(); 309251607Sdim switch (Opcode) { 310251607Sdim case Instruction::ICmp: 311251607Sdim // CompareConstantExpr (icmp) 312251607Sdim return Builder.CreateICmp(CmpInst::Predicate(C->getPredicate()), 313251607Sdim NewOperands[0], NewOperands[1]); 314251607Sdim case Instruction::FCmp: 315251607Sdim // CompareConstantExpr (fcmp) 316251607Sdim assert(false && "Address space conversion should have no effect " 317251607Sdim "on float point CompareConstantExpr (fcmp)!"); 318251607Sdim return C; 319251607Sdim case Instruction::ExtractElement: 320251607Sdim // ExtractElementConstantExpr 321251607Sdim return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); 322251607Sdim case Instruction::InsertElement: 323251607Sdim // InsertElementConstantExpr 324251607Sdim return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], 325251607Sdim NewOperands[2]); 326251607Sdim case Instruction::ShuffleVector: 327251607Sdim // ShuffleVector 328251607Sdim return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], 329251607Sdim NewOperands[2]); 330251607Sdim case Instruction::ExtractValue: 331251607Sdim // ExtractValueConstantExpr 332251607Sdim return Builder.CreateExtractValue(NewOperands[0], C->getIndices()); 333251607Sdim case Instruction::InsertValue: 334251607Sdim // InsertValueConstantExpr 335251607Sdim return Builder.CreateInsertValue(NewOperands[0], NewOperands[1], 336251607Sdim C->getIndices()); 337251607Sdim case Instruction::GetElementPtr: 338251607Sdim // GetElementPtrConstantExpr 339251607Sdim return cast<GEPOperator>(C)->isInBounds() 340251607Sdim ? Builder.CreateGEP( 341251607Sdim NewOperands[0], 342251607Sdim makeArrayRef(&NewOperands[1], NumOperands - 1)) 343251607Sdim : Builder.CreateInBoundsGEP( 344251607Sdim NewOperands[0], 345251607Sdim makeArrayRef(&NewOperands[1], NumOperands - 1)); 346251607Sdim case Instruction::Select: 347251607Sdim // SelectConstantExpr 348251607Sdim return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); 349251607Sdim default: 350251607Sdim // BinaryConstantExpr 351251607Sdim if (Instruction::isBinaryOp(Opcode)) { 352251607Sdim return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), 353251607Sdim NewOperands[0], NewOperands[1]); 354251607Sdim } 355251607Sdim // UnaryConstantExpr 356251607Sdim if (Instruction::isCast(Opcode)) { 357251607Sdim return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), 358251607Sdim NewOperands[0], C->getType()); 359251607Sdim } 360251607Sdim assert(false && "GenericToNVVM encountered an unsupported ConstantExpr"); 361251607Sdim return C; 362251607Sdim } 363251607Sdim} 364251607Sdim 365251607Sdimvoid GenericToNVVM::remapNamedMDNode(Module *M, NamedMDNode *N) { 366251607Sdim 367251607Sdim bool OperandChanged = false; 368251607Sdim SmallVector<MDNode *, 16> NewOperands; 369251607Sdim unsigned NumOperands = N->getNumOperands(); 370251607Sdim 371251607Sdim // Check if any operand is or contains a global variable in GVMap, and thus 372251607Sdim // converted to another value. 373251607Sdim for (unsigned i = 0; i < NumOperands; ++i) { 374251607Sdim MDNode *Operand = N->getOperand(i); 375251607Sdim MDNode *NewOperand = remapMDNode(M, Operand); 376251607Sdim OperandChanged |= Operand != NewOperand; 377251607Sdim NewOperands.push_back(NewOperand); 378251607Sdim } 379251607Sdim 380251607Sdim // If none of the operands has been modified, return immediately. 381251607Sdim if (!OperandChanged) { 382251607Sdim return; 383251607Sdim } 384251607Sdim 385251607Sdim // Replace the old operands with the new operands. 386251607Sdim N->dropAllReferences(); 387251607Sdim for (SmallVector<MDNode *, 16>::iterator I = NewOperands.begin(), 388251607Sdim E = NewOperands.end(); 389251607Sdim I != E; ++I) { 390251607Sdim N->addOperand(*I); 391251607Sdim } 392251607Sdim} 393251607Sdim 394251607SdimMDNode *GenericToNVVM::remapMDNode(Module *M, MDNode *N) { 395251607Sdim 396251607Sdim bool OperandChanged = false; 397251607Sdim SmallVector<Value *, 8> NewOperands; 398251607Sdim unsigned NumOperands = N->getNumOperands(); 399251607Sdim 400251607Sdim // Check if any operand is or contains a global variable in GVMap, and thus 401251607Sdim // converted to another value. 402251607Sdim for (unsigned i = 0; i < NumOperands; ++i) { 403251607Sdim Value *Operand = N->getOperand(i); 404251607Sdim Value *NewOperand = Operand; 405251607Sdim if (Operand) { 406251607Sdim if (isa<GlobalVariable>(Operand)) { 407251607Sdim GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(Operand)); 408251607Sdim if (I != GVMap.end()) { 409251607Sdim NewOperand = I->second; 410251607Sdim if (++i < NumOperands) { 411251607Sdim NewOperands.push_back(NewOperand); 412251607Sdim // Address space of the global variable follows the global variable 413251607Sdim // in the global variable debug info (see createGlobalVariable in 414251607Sdim // lib/Analysis/DIBuilder.cpp). 415251607Sdim NewOperand = 416251607Sdim ConstantInt::get(Type::getInt32Ty(M->getContext()), 417251607Sdim I->second->getType()->getAddressSpace()); 418251607Sdim } 419251607Sdim } 420251607Sdim } else if (isa<MDNode>(Operand)) { 421251607Sdim NewOperand = remapMDNode(M, cast<MDNode>(Operand)); 422251607Sdim } 423251607Sdim } 424251607Sdim OperandChanged |= Operand != NewOperand; 425251607Sdim NewOperands.push_back(NewOperand); 426251607Sdim } 427251607Sdim 428251607Sdim // If none of the operands has been modified, return N as it is. 429251607Sdim if (!OperandChanged) { 430251607Sdim return N; 431251607Sdim } 432251607Sdim 433251607Sdim // If any of the operands has been modified, create a new MDNode with the new 434251607Sdim // operands. 435251607Sdim return MDNode::get(M->getContext(), makeArrayRef(NewOperands)); 436251607Sdim} 437