10b57cec5SDimitry Andric //===-- GenericToNVVM.cpp - Convert generic module to NVVM module - C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Convert generic global variables into either .global or .const access based 100b57cec5SDimitry Andric // on the variable's "constant" qualifier. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "MCTargetDesc/NVPTXBaseInfo.h" 150b57cec5SDimitry Andric #include "NVPTX.h" 160b57cec5SDimitry Andric #include "NVPTXUtilities.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h" 180b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 190b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 200b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 210b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 220b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 230b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 240b57cec5SDimitry Andric #include "llvm/IR/Module.h" 250b57cec5SDimitry Andric #include "llvm/IR/Operator.h" 260b57cec5SDimitry Andric #include "llvm/IR/ValueMap.h" 270b57cec5SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace llvm { 320b57cec5SDimitry Andric void initializeGenericToNVVMPass(PassRegistry &); 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric namespace { 360b57cec5SDimitry Andric class GenericToNVVM : public ModulePass { 370b57cec5SDimitry Andric public: 380b57cec5SDimitry Andric static char ID; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric GenericToNVVM() : ModulePass(ID) {} 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric bool runOnModule(Module &M) override; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {} 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric private: 470b57cec5SDimitry Andric Value *remapConstant(Module *M, Function *F, Constant *C, 480b57cec5SDimitry Andric IRBuilder<> &Builder); 490b57cec5SDimitry Andric Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F, 500b57cec5SDimitry Andric Constant *C, 510b57cec5SDimitry Andric IRBuilder<> &Builder); 520b57cec5SDimitry Andric Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 530b57cec5SDimitry Andric IRBuilder<> &Builder); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy; 560b57cec5SDimitry Andric typedef ValueMap<Constant *, Value *> ConstantToValueMapTy; 570b57cec5SDimitry Andric GVMapTy GVMap; 580b57cec5SDimitry Andric ConstantToValueMapTy ConstantToValueMap; 590b57cec5SDimitry Andric }; 600b57cec5SDimitry Andric } // end namespace 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric char GenericToNVVM::ID = 0; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric ModulePass *llvm::createGenericToNVVMPass() { return new GenericToNVVM(); } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric INITIALIZE_PASS( 670b57cec5SDimitry Andric GenericToNVVM, "generic-to-nvvm", 680b57cec5SDimitry Andric "Ensure that the global variables are in the global address space", false, 690b57cec5SDimitry Andric false) 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric bool GenericToNVVM::runOnModule(Module &M) { 720b57cec5SDimitry Andric // Create a clone of each global variable that has the default address space. 730b57cec5SDimitry Andric // The clone is created with the global address space specifier, and the pair 740b57cec5SDimitry Andric // of original global variable and its clone is placed in the GVMap for later 750b57cec5SDimitry Andric // use. 760b57cec5SDimitry Andric 77*349cc55cSDimitry Andric for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) { 78*349cc55cSDimitry Andric if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && 79*349cc55cSDimitry Andric !llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) && 80*349cc55cSDimitry Andric !GV.getName().startswith("llvm.")) { 810b57cec5SDimitry Andric GlobalVariable *NewGV = new GlobalVariable( 82*349cc55cSDimitry Andric M, GV.getValueType(), GV.isConstant(), GV.getLinkage(), 83*349cc55cSDimitry Andric GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV, 84*349cc55cSDimitry Andric GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); 85*349cc55cSDimitry Andric NewGV->copyAttributesFrom(&GV); 86*349cc55cSDimitry Andric GVMap[&GV] = NewGV; 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric // Return immediately, if every global variable has a specific address space 910b57cec5SDimitry Andric // specifier. 920b57cec5SDimitry Andric if (GVMap.empty()) { 930b57cec5SDimitry Andric return false; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric // Walk through the instructions in function defitinions, and replace any use 970b57cec5SDimitry Andric // of original global variables in GVMap with a use of the corresponding 980b57cec5SDimitry Andric // copies in GVMap. If necessary, promote constants to instructions. 990b57cec5SDimitry Andric for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { 1000b57cec5SDimitry Andric if (I->isDeclaration()) { 1010b57cec5SDimitry Andric continue; 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric IRBuilder<> Builder(I->getEntryBlock().getFirstNonPHIOrDbg()); 1040b57cec5SDimitry Andric for (Function::iterator BBI = I->begin(), BBE = I->end(); BBI != BBE; 1050b57cec5SDimitry Andric ++BBI) { 1060b57cec5SDimitry Andric for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; 1070b57cec5SDimitry Andric ++II) { 1080b57cec5SDimitry Andric for (unsigned i = 0, e = II->getNumOperands(); i < e; ++i) { 1090b57cec5SDimitry Andric Value *Operand = II->getOperand(i); 1100b57cec5SDimitry Andric if (isa<Constant>(Operand)) { 1110b57cec5SDimitry Andric II->setOperand( 1120b57cec5SDimitry Andric i, remapConstant(&M, &*I, cast<Constant>(Operand), Builder)); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric ConstantToValueMap.clear(); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Copy GVMap over to a standard value map. 1210b57cec5SDimitry Andric ValueToValueMapTy VM; 1220b57cec5SDimitry Andric for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I) 1230b57cec5SDimitry Andric VM[I->first] = I->second; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // Walk through the global variable initializers, and replace any use of 1260b57cec5SDimitry Andric // original global variables in GVMap with a use of the corresponding copies 1270b57cec5SDimitry Andric // in GVMap. The copies need to be bitcast to the original global variable 1280b57cec5SDimitry Andric // types, as we cannot use cvta in global variable initializers. 1290b57cec5SDimitry Andric for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { 1300b57cec5SDimitry Andric GlobalVariable *GV = I->first; 1310b57cec5SDimitry Andric GlobalVariable *NewGV = I->second; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // Remove GV from the map so that it can be RAUWed. Note that 1340b57cec5SDimitry Andric // DenseMap::erase() won't invalidate any iterators but this one. 1350b57cec5SDimitry Andric auto Next = std::next(I); 1360b57cec5SDimitry Andric GVMap.erase(I); 1370b57cec5SDimitry Andric I = Next; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType()); 1400b57cec5SDimitry Andric // At this point, the remaining uses of GV should be found only in global 1410b57cec5SDimitry Andric // variable initializers, as other uses have been already been removed 1420b57cec5SDimitry Andric // while walking through the instructions in function definitions. 1430b57cec5SDimitry Andric GV->replaceAllUsesWith(BitCastNewGV); 1445ffd83dbSDimitry Andric std::string Name = std::string(GV->getName()); 1450b57cec5SDimitry Andric GV->eraseFromParent(); 1460b57cec5SDimitry Andric NewGV->setName(Name); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric assert(GVMap.empty() && "Expected it to be empty by now"); 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric return true; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C, 1540b57cec5SDimitry Andric IRBuilder<> &Builder) { 1550b57cec5SDimitry Andric // If the constant C has been converted already in the given function F, just 1560b57cec5SDimitry Andric // return the converted value. 1570b57cec5SDimitry Andric ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C); 1580b57cec5SDimitry Andric if (CTII != ConstantToValueMap.end()) { 1590b57cec5SDimitry Andric return CTII->second; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric Value *NewValue = C; 1630b57cec5SDimitry Andric if (isa<GlobalVariable>(C)) { 1640b57cec5SDimitry Andric // If the constant C is a global variable and is found in GVMap, substitute 1650b57cec5SDimitry Andric // 1660b57cec5SDimitry Andric // addrspacecast GVMap[C] to addrspace(0) 1670b57cec5SDimitry Andric // 1680b57cec5SDimitry Andric // for our use of C. 1690b57cec5SDimitry Andric GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C)); 1700b57cec5SDimitry Andric if (I != GVMap.end()) { 1710b57cec5SDimitry Andric GlobalVariable *GV = I->second; 1720b57cec5SDimitry Andric NewValue = Builder.CreateAddrSpaceCast( 1730b57cec5SDimitry Andric GV, 1740b57cec5SDimitry Andric PointerType::get(GV->getValueType(), llvm::ADDRESS_SPACE_GENERIC)); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric } else if (isa<ConstantAggregate>(C)) { 1770b57cec5SDimitry Andric // If any element in the constant vector or aggregate C is or uses a global 1780b57cec5SDimitry Andric // variable in GVMap, the constant C needs to be reconstructed, using a set 1790b57cec5SDimitry Andric // of instructions. 1800b57cec5SDimitry Andric NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder); 1810b57cec5SDimitry Andric } else if (isa<ConstantExpr>(C)) { 1820b57cec5SDimitry Andric // If any operand in the constant expression C is or uses a global variable 1830b57cec5SDimitry Andric // in GVMap, the constant expression C needs to be reconstructed, using a 1840b57cec5SDimitry Andric // set of instructions. 1850b57cec5SDimitry Andric NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric ConstantToValueMap[C] = NewValue; 1890b57cec5SDimitry Andric return NewValue; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric Value *GenericToNVVM::remapConstantVectorOrConstantAggregate( 1930b57cec5SDimitry Andric Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { 1940b57cec5SDimitry Andric bool OperandChanged = false; 1950b57cec5SDimitry Andric SmallVector<Value *, 4> NewOperands; 1960b57cec5SDimitry Andric unsigned NumOperands = C->getNumOperands(); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric // Check if any element is or uses a global variable in GVMap, and thus 1990b57cec5SDimitry Andric // converted to another value. 2000b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2010b57cec5SDimitry Andric Value *Operand = C->getOperand(i); 2020b57cec5SDimitry Andric Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 2030b57cec5SDimitry Andric OperandChanged |= Operand != NewOperand; 2040b57cec5SDimitry Andric NewOperands.push_back(NewOperand); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric // If none of the elements has been modified, return C as it is. 2080b57cec5SDimitry Andric if (!OperandChanged) { 2090b57cec5SDimitry Andric return C; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric // If any of the elements has been modified, construct the equivalent 2130b57cec5SDimitry Andric // vector or aggregate value with a set instructions and the converted 2140b57cec5SDimitry Andric // elements. 215*349cc55cSDimitry Andric Value *NewValue = PoisonValue::get(C->getType()); 2160b57cec5SDimitry Andric if (isa<ConstantVector>(C)) { 2170b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2180b57cec5SDimitry Andric Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); 2190b57cec5SDimitry Andric NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } else { 2220b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2230b57cec5SDimitry Andric NewValue = 2240b57cec5SDimitry Andric Builder.CreateInsertValue(NewValue, NewOperands[i], makeArrayRef(i)); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric return NewValue; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 2320b57cec5SDimitry Andric IRBuilder<> &Builder) { 2330b57cec5SDimitry Andric bool OperandChanged = false; 2340b57cec5SDimitry Andric SmallVector<Value *, 4> NewOperands; 2350b57cec5SDimitry Andric unsigned NumOperands = C->getNumOperands(); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // Check if any operand is or uses a global variable in GVMap, and thus 2380b57cec5SDimitry Andric // converted to another value. 2390b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2400b57cec5SDimitry Andric Value *Operand = C->getOperand(i); 2410b57cec5SDimitry Andric Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 2420b57cec5SDimitry Andric OperandChanged |= Operand != NewOperand; 2430b57cec5SDimitry Andric NewOperands.push_back(NewOperand); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // If none of the operands has been modified, return C as it is. 2470b57cec5SDimitry Andric if (!OperandChanged) { 2480b57cec5SDimitry Andric return C; 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric // If any of the operands has been modified, construct the instruction with 2520b57cec5SDimitry Andric // the converted operands. 2530b57cec5SDimitry Andric unsigned Opcode = C->getOpcode(); 2540b57cec5SDimitry Andric switch (Opcode) { 2550b57cec5SDimitry Andric case Instruction::ICmp: 2560b57cec5SDimitry Andric // CompareConstantExpr (icmp) 2570b57cec5SDimitry Andric return Builder.CreateICmp(CmpInst::Predicate(C->getPredicate()), 2580b57cec5SDimitry Andric NewOperands[0], NewOperands[1]); 2590b57cec5SDimitry Andric case Instruction::FCmp: 2600b57cec5SDimitry Andric // CompareConstantExpr (fcmp) 2610b57cec5SDimitry Andric llvm_unreachable("Address space conversion should have no effect " 2620b57cec5SDimitry Andric "on float point CompareConstantExpr (fcmp)!"); 2630b57cec5SDimitry Andric case Instruction::ExtractElement: 2640b57cec5SDimitry Andric // ExtractElementConstantExpr 2650b57cec5SDimitry Andric return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); 2660b57cec5SDimitry Andric case Instruction::InsertElement: 2670b57cec5SDimitry Andric // InsertElementConstantExpr 2680b57cec5SDimitry Andric return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], 2690b57cec5SDimitry Andric NewOperands[2]); 2700b57cec5SDimitry Andric case Instruction::ShuffleVector: 2710b57cec5SDimitry Andric // ShuffleVector 2720b57cec5SDimitry Andric return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], 2730b57cec5SDimitry Andric NewOperands[2]); 2740b57cec5SDimitry Andric case Instruction::ExtractValue: 2750b57cec5SDimitry Andric // ExtractValueConstantExpr 2760b57cec5SDimitry Andric return Builder.CreateExtractValue(NewOperands[0], C->getIndices()); 2770b57cec5SDimitry Andric case Instruction::InsertValue: 2780b57cec5SDimitry Andric // InsertValueConstantExpr 2790b57cec5SDimitry Andric return Builder.CreateInsertValue(NewOperands[0], NewOperands[1], 2800b57cec5SDimitry Andric C->getIndices()); 2810b57cec5SDimitry Andric case Instruction::GetElementPtr: 2820b57cec5SDimitry Andric // GetElementPtrConstantExpr 2830b57cec5SDimitry Andric return cast<GEPOperator>(C)->isInBounds() 2840b57cec5SDimitry Andric ? Builder.CreateGEP( 2850b57cec5SDimitry Andric cast<GEPOperator>(C)->getSourceElementType(), 2860b57cec5SDimitry Andric NewOperands[0], 2870b57cec5SDimitry Andric makeArrayRef(&NewOperands[1], NumOperands - 1)) 2880b57cec5SDimitry Andric : Builder.CreateInBoundsGEP( 2890b57cec5SDimitry Andric cast<GEPOperator>(C)->getSourceElementType(), 2900b57cec5SDimitry Andric NewOperands[0], 2910b57cec5SDimitry Andric makeArrayRef(&NewOperands[1], NumOperands - 1)); 2920b57cec5SDimitry Andric case Instruction::Select: 2930b57cec5SDimitry Andric // SelectConstantExpr 2940b57cec5SDimitry Andric return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); 2950b57cec5SDimitry Andric default: 2960b57cec5SDimitry Andric // BinaryConstantExpr 2970b57cec5SDimitry Andric if (Instruction::isBinaryOp(Opcode)) { 2980b57cec5SDimitry Andric return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), 2990b57cec5SDimitry Andric NewOperands[0], NewOperands[1]); 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric // UnaryConstantExpr 3020b57cec5SDimitry Andric if (Instruction::isCast(Opcode)) { 3030b57cec5SDimitry Andric return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), 3040b57cec5SDimitry Andric NewOperands[0], C->getType()); 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr"); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric } 309