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 { 3206c3fb27SDimitry Andric void initializeGenericToNVVMLegacyPassPass(PassRegistry &); 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric namespace { 3606c3fb27SDimitry Andric class GenericToNVVM { 370b57cec5SDimitry Andric public: 3806c3fb27SDimitry Andric bool runOnModule(Module &M); 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric private: 410b57cec5SDimitry Andric Value *remapConstant(Module *M, Function *F, Constant *C, 420b57cec5SDimitry Andric IRBuilder<> &Builder); 430b57cec5SDimitry Andric Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F, 440b57cec5SDimitry Andric Constant *C, 450b57cec5SDimitry Andric IRBuilder<> &Builder); 460b57cec5SDimitry Andric Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 470b57cec5SDimitry Andric IRBuilder<> &Builder); 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy; 500b57cec5SDimitry Andric typedef ValueMap<Constant *, Value *> ConstantToValueMapTy; 510b57cec5SDimitry Andric GVMapTy GVMap; 520b57cec5SDimitry Andric ConstantToValueMapTy ConstantToValueMap; 530b57cec5SDimitry Andric }; 540b57cec5SDimitry Andric } // end namespace 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric bool GenericToNVVM::runOnModule(Module &M) { 570b57cec5SDimitry Andric // Create a clone of each global variable that has the default address space. 580b57cec5SDimitry Andric // The clone is created with the global address space specifier, and the pair 590b57cec5SDimitry Andric // of original global variable and its clone is placed in the GVMap for later 600b57cec5SDimitry Andric // use. 610b57cec5SDimitry Andric 62349cc55cSDimitry Andric for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) { 63349cc55cSDimitry Andric if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && 64349cc55cSDimitry Andric !llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) && 65*5f757f3fSDimitry Andric !GV.getName().starts_with("llvm.")) { 660b57cec5SDimitry Andric GlobalVariable *NewGV = new GlobalVariable( 67349cc55cSDimitry Andric M, GV.getValueType(), GV.isConstant(), GV.getLinkage(), 68349cc55cSDimitry Andric GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV, 69349cc55cSDimitry Andric GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); 70349cc55cSDimitry Andric NewGV->copyAttributesFrom(&GV); 7181ad6265SDimitry Andric NewGV->copyMetadata(&GV, /*Offset=*/0); 72349cc55cSDimitry Andric GVMap[&GV] = NewGV; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric // Return immediately, if every global variable has a specific address space 770b57cec5SDimitry Andric // specifier. 780b57cec5SDimitry Andric if (GVMap.empty()) { 790b57cec5SDimitry Andric return false; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric // Walk through the instructions in function defitinions, and replace any use 830b57cec5SDimitry Andric // of original global variables in GVMap with a use of the corresponding 840b57cec5SDimitry Andric // copies in GVMap. If necessary, promote constants to instructions. 8504eeddc0SDimitry Andric for (Function &F : M) { 8604eeddc0SDimitry Andric if (F.isDeclaration()) { 870b57cec5SDimitry Andric continue; 880b57cec5SDimitry Andric } 8904eeddc0SDimitry Andric IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHIOrDbg()); 9004eeddc0SDimitry Andric for (BasicBlock &BB : F) { 9104eeddc0SDimitry Andric for (Instruction &II : BB) { 9204eeddc0SDimitry Andric for (unsigned i = 0, e = II.getNumOperands(); i < e; ++i) { 9304eeddc0SDimitry Andric Value *Operand = II.getOperand(i); 940b57cec5SDimitry Andric if (isa<Constant>(Operand)) { 9504eeddc0SDimitry Andric II.setOperand( 9604eeddc0SDimitry Andric i, remapConstant(&M, &F, cast<Constant>(Operand), Builder)); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric ConstantToValueMap.clear(); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // Copy GVMap over to a standard value map. 1050b57cec5SDimitry Andric ValueToValueMapTy VM; 1060b57cec5SDimitry Andric for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I) 1070b57cec5SDimitry Andric VM[I->first] = I->second; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric // Walk through the global variable initializers, and replace any use of 1100b57cec5SDimitry Andric // original global variables in GVMap with a use of the corresponding copies 1110b57cec5SDimitry Andric // in GVMap. The copies need to be bitcast to the original global variable 1120b57cec5SDimitry Andric // types, as we cannot use cvta in global variable initializers. 1130b57cec5SDimitry Andric for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { 1140b57cec5SDimitry Andric GlobalVariable *GV = I->first; 1150b57cec5SDimitry Andric GlobalVariable *NewGV = I->second; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // Remove GV from the map so that it can be RAUWed. Note that 1180b57cec5SDimitry Andric // DenseMap::erase() won't invalidate any iterators but this one. 1190b57cec5SDimitry Andric auto Next = std::next(I); 1200b57cec5SDimitry Andric GVMap.erase(I); 1210b57cec5SDimitry Andric I = Next; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType()); 1240b57cec5SDimitry Andric // At this point, the remaining uses of GV should be found only in global 1250b57cec5SDimitry Andric // variable initializers, as other uses have been already been removed 1260b57cec5SDimitry Andric // while walking through the instructions in function definitions. 1270b57cec5SDimitry Andric GV->replaceAllUsesWith(BitCastNewGV); 1285ffd83dbSDimitry Andric std::string Name = std::string(GV->getName()); 1290b57cec5SDimitry Andric GV->eraseFromParent(); 1300b57cec5SDimitry Andric NewGV->setName(Name); 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric assert(GVMap.empty() && "Expected it to be empty by now"); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric return true; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C, 1380b57cec5SDimitry Andric IRBuilder<> &Builder) { 1390b57cec5SDimitry Andric // If the constant C has been converted already in the given function F, just 1400b57cec5SDimitry Andric // return the converted value. 1410b57cec5SDimitry Andric ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C); 1420b57cec5SDimitry Andric if (CTII != ConstantToValueMap.end()) { 1430b57cec5SDimitry Andric return CTII->second; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric Value *NewValue = C; 1470b57cec5SDimitry Andric if (isa<GlobalVariable>(C)) { 1480b57cec5SDimitry Andric // If the constant C is a global variable and is found in GVMap, substitute 1490b57cec5SDimitry Andric // 1500b57cec5SDimitry Andric // addrspacecast GVMap[C] to addrspace(0) 1510b57cec5SDimitry Andric // 1520b57cec5SDimitry Andric // for our use of C. 1530b57cec5SDimitry Andric GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C)); 1540b57cec5SDimitry Andric if (I != GVMap.end()) { 1550b57cec5SDimitry Andric GlobalVariable *GV = I->second; 1560b57cec5SDimitry Andric NewValue = Builder.CreateAddrSpaceCast( 1570b57cec5SDimitry Andric GV, 1580b57cec5SDimitry Andric PointerType::get(GV->getValueType(), llvm::ADDRESS_SPACE_GENERIC)); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric } else if (isa<ConstantAggregate>(C)) { 1610b57cec5SDimitry Andric // If any element in the constant vector or aggregate C is or uses a global 1620b57cec5SDimitry Andric // variable in GVMap, the constant C needs to be reconstructed, using a set 1630b57cec5SDimitry Andric // of instructions. 1640b57cec5SDimitry Andric NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder); 1650b57cec5SDimitry Andric } else if (isa<ConstantExpr>(C)) { 1660b57cec5SDimitry Andric // If any operand in the constant expression C is or uses a global variable 1670b57cec5SDimitry Andric // in GVMap, the constant expression C needs to be reconstructed, using a 1680b57cec5SDimitry Andric // set of instructions. 1690b57cec5SDimitry Andric NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric ConstantToValueMap[C] = NewValue; 1730b57cec5SDimitry Andric return NewValue; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric Value *GenericToNVVM::remapConstantVectorOrConstantAggregate( 1770b57cec5SDimitry Andric Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { 1780b57cec5SDimitry Andric bool OperandChanged = false; 1790b57cec5SDimitry Andric SmallVector<Value *, 4> NewOperands; 1800b57cec5SDimitry Andric unsigned NumOperands = C->getNumOperands(); 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric // Check if any element is or uses a global variable in GVMap, and thus 1830b57cec5SDimitry Andric // converted to another value. 1840b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 1850b57cec5SDimitry Andric Value *Operand = C->getOperand(i); 1860b57cec5SDimitry Andric Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 1870b57cec5SDimitry Andric OperandChanged |= Operand != NewOperand; 1880b57cec5SDimitry Andric NewOperands.push_back(NewOperand); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric // If none of the elements has been modified, return C as it is. 1920b57cec5SDimitry Andric if (!OperandChanged) { 1930b57cec5SDimitry Andric return C; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // If any of the elements has been modified, construct the equivalent 1970b57cec5SDimitry Andric // vector or aggregate value with a set instructions and the converted 1980b57cec5SDimitry Andric // elements. 199349cc55cSDimitry Andric Value *NewValue = PoisonValue::get(C->getType()); 2000b57cec5SDimitry Andric if (isa<ConstantVector>(C)) { 2010b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2020b57cec5SDimitry Andric Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); 2030b57cec5SDimitry Andric NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric } else { 2060b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2070b57cec5SDimitry Andric NewValue = 208bdd1243dSDimitry Andric Builder.CreateInsertValue(NewValue, NewOperands[i], ArrayRef(i)); 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric return NewValue; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 2160b57cec5SDimitry Andric IRBuilder<> &Builder) { 2170b57cec5SDimitry Andric bool OperandChanged = false; 2180b57cec5SDimitry Andric SmallVector<Value *, 4> NewOperands; 2190b57cec5SDimitry Andric unsigned NumOperands = C->getNumOperands(); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric // Check if any operand is or uses a global variable in GVMap, and thus 2220b57cec5SDimitry Andric // converted to another value. 2230b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2240b57cec5SDimitry Andric Value *Operand = C->getOperand(i); 2250b57cec5SDimitry Andric Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 2260b57cec5SDimitry Andric OperandChanged |= Operand != NewOperand; 2270b57cec5SDimitry Andric NewOperands.push_back(NewOperand); 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric // If none of the operands has been modified, return C as it is. 2310b57cec5SDimitry Andric if (!OperandChanged) { 2320b57cec5SDimitry Andric return C; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // If any of the operands has been modified, construct the instruction with 2360b57cec5SDimitry Andric // the converted operands. 2370b57cec5SDimitry Andric unsigned Opcode = C->getOpcode(); 2380b57cec5SDimitry Andric switch (Opcode) { 2390b57cec5SDimitry Andric case Instruction::ICmp: 2400b57cec5SDimitry Andric // CompareConstantExpr (icmp) 2410b57cec5SDimitry Andric return Builder.CreateICmp(CmpInst::Predicate(C->getPredicate()), 2420b57cec5SDimitry Andric NewOperands[0], NewOperands[1]); 2430b57cec5SDimitry Andric case Instruction::FCmp: 2440b57cec5SDimitry Andric // CompareConstantExpr (fcmp) 2450b57cec5SDimitry Andric llvm_unreachable("Address space conversion should have no effect " 2460b57cec5SDimitry Andric "on float point CompareConstantExpr (fcmp)!"); 2470b57cec5SDimitry Andric case Instruction::ExtractElement: 2480b57cec5SDimitry Andric // ExtractElementConstantExpr 2490b57cec5SDimitry Andric return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); 2500b57cec5SDimitry Andric case Instruction::InsertElement: 2510b57cec5SDimitry Andric // InsertElementConstantExpr 2520b57cec5SDimitry Andric return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], 2530b57cec5SDimitry Andric NewOperands[2]); 2540b57cec5SDimitry Andric case Instruction::ShuffleVector: 2550b57cec5SDimitry Andric // ShuffleVector 2560b57cec5SDimitry Andric return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], 2570b57cec5SDimitry Andric NewOperands[2]); 2580b57cec5SDimitry Andric case Instruction::GetElementPtr: 2590b57cec5SDimitry Andric // GetElementPtrConstantExpr 26081ad6265SDimitry Andric return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(), 2610b57cec5SDimitry Andric NewOperands[0], 262bdd1243dSDimitry Andric ArrayRef(&NewOperands[1], NumOperands - 1), "", 26381ad6265SDimitry Andric cast<GEPOperator>(C)->isInBounds()); 2640b57cec5SDimitry Andric case Instruction::Select: 2650b57cec5SDimitry Andric // SelectConstantExpr 2660b57cec5SDimitry Andric return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); 2670b57cec5SDimitry Andric default: 2680b57cec5SDimitry Andric // BinaryConstantExpr 2690b57cec5SDimitry Andric if (Instruction::isBinaryOp(Opcode)) { 2700b57cec5SDimitry Andric return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), 2710b57cec5SDimitry Andric NewOperands[0], NewOperands[1]); 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric // UnaryConstantExpr 2740b57cec5SDimitry Andric if (Instruction::isCast(Opcode)) { 2750b57cec5SDimitry Andric return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), 2760b57cec5SDimitry Andric NewOperands[0], C->getType()); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr"); 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric } 28106c3fb27SDimitry Andric 28206c3fb27SDimitry Andric namespace { 28306c3fb27SDimitry Andric class GenericToNVVMLegacyPass : public ModulePass { 28406c3fb27SDimitry Andric public: 28506c3fb27SDimitry Andric static char ID; 28606c3fb27SDimitry Andric 28706c3fb27SDimitry Andric GenericToNVVMLegacyPass() : ModulePass(ID) {} 28806c3fb27SDimitry Andric 28906c3fb27SDimitry Andric bool runOnModule(Module &M) override; 29006c3fb27SDimitry Andric }; 29106c3fb27SDimitry Andric } // namespace 29206c3fb27SDimitry Andric 29306c3fb27SDimitry Andric char GenericToNVVMLegacyPass::ID = 0; 29406c3fb27SDimitry Andric 29506c3fb27SDimitry Andric ModulePass *llvm::createGenericToNVVMLegacyPass() { 29606c3fb27SDimitry Andric return new GenericToNVVMLegacyPass(); 29706c3fb27SDimitry Andric } 29806c3fb27SDimitry Andric 29906c3fb27SDimitry Andric INITIALIZE_PASS( 30006c3fb27SDimitry Andric GenericToNVVMLegacyPass, "generic-to-nvvm", 30106c3fb27SDimitry Andric "Ensure that the global variables are in the global address space", false, 30206c3fb27SDimitry Andric false) 30306c3fb27SDimitry Andric 30406c3fb27SDimitry Andric bool GenericToNVVMLegacyPass::runOnModule(Module &M) { 30506c3fb27SDimitry Andric return GenericToNVVM().runOnModule(M); 30606c3fb27SDimitry Andric } 30706c3fb27SDimitry Andric 30806c3fb27SDimitry Andric PreservedAnalyses GenericToNVVMPass::run(Module &M, ModuleAnalysisManager &AM) { 30906c3fb27SDimitry Andric return GenericToNVVM().runOnModule(M) ? PreservedAnalyses::none() 31006c3fb27SDimitry Andric : PreservedAnalyses::all(); 31106c3fb27SDimitry Andric } 312