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 77349cc55cSDimitry Andric for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) { 78349cc55cSDimitry Andric if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && 79349cc55cSDimitry Andric !llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) && 80349cc55cSDimitry Andric !GV.getName().startswith("llvm.")) { 810b57cec5SDimitry Andric GlobalVariable *NewGV = new GlobalVariable( 82349cc55cSDimitry Andric M, GV.getValueType(), GV.isConstant(), GV.getLinkage(), 83349cc55cSDimitry Andric GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV, 84349cc55cSDimitry Andric GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); 85349cc55cSDimitry Andric NewGV->copyAttributesFrom(&GV); 86*81ad6265SDimitry Andric NewGV->copyMetadata(&GV, /*Offset=*/0); 87349cc55cSDimitry Andric GVMap[&GV] = NewGV; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric // Return immediately, if every global variable has a specific address space 920b57cec5SDimitry Andric // specifier. 930b57cec5SDimitry Andric if (GVMap.empty()) { 940b57cec5SDimitry Andric return false; 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric // Walk through the instructions in function defitinions, and replace any use 980b57cec5SDimitry Andric // of original global variables in GVMap with a use of the corresponding 990b57cec5SDimitry Andric // copies in GVMap. If necessary, promote constants to instructions. 10004eeddc0SDimitry Andric for (Function &F : M) { 10104eeddc0SDimitry Andric if (F.isDeclaration()) { 1020b57cec5SDimitry Andric continue; 1030b57cec5SDimitry Andric } 10404eeddc0SDimitry Andric IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHIOrDbg()); 10504eeddc0SDimitry Andric for (BasicBlock &BB : F) { 10604eeddc0SDimitry Andric for (Instruction &II : BB) { 10704eeddc0SDimitry Andric for (unsigned i = 0, e = II.getNumOperands(); i < e; ++i) { 10804eeddc0SDimitry Andric Value *Operand = II.getOperand(i); 1090b57cec5SDimitry Andric if (isa<Constant>(Operand)) { 11004eeddc0SDimitry Andric II.setOperand( 11104eeddc0SDimitry Andric i, remapConstant(&M, &F, cast<Constant>(Operand), Builder)); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric ConstantToValueMap.clear(); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric // Copy GVMap over to a standard value map. 1200b57cec5SDimitry Andric ValueToValueMapTy VM; 1210b57cec5SDimitry Andric for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I) 1220b57cec5SDimitry Andric VM[I->first] = I->second; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Walk through the global variable initializers, and replace any use of 1250b57cec5SDimitry Andric // original global variables in GVMap with a use of the corresponding copies 1260b57cec5SDimitry Andric // in GVMap. The copies need to be bitcast to the original global variable 1270b57cec5SDimitry Andric // types, as we cannot use cvta in global variable initializers. 1280b57cec5SDimitry Andric for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { 1290b57cec5SDimitry Andric GlobalVariable *GV = I->first; 1300b57cec5SDimitry Andric GlobalVariable *NewGV = I->second; 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // Remove GV from the map so that it can be RAUWed. Note that 1330b57cec5SDimitry Andric // DenseMap::erase() won't invalidate any iterators but this one. 1340b57cec5SDimitry Andric auto Next = std::next(I); 1350b57cec5SDimitry Andric GVMap.erase(I); 1360b57cec5SDimitry Andric I = Next; 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType()); 1390b57cec5SDimitry Andric // At this point, the remaining uses of GV should be found only in global 1400b57cec5SDimitry Andric // variable initializers, as other uses have been already been removed 1410b57cec5SDimitry Andric // while walking through the instructions in function definitions. 1420b57cec5SDimitry Andric GV->replaceAllUsesWith(BitCastNewGV); 1435ffd83dbSDimitry Andric std::string Name = std::string(GV->getName()); 1440b57cec5SDimitry Andric GV->eraseFromParent(); 1450b57cec5SDimitry Andric NewGV->setName(Name); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric assert(GVMap.empty() && "Expected it to be empty by now"); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric return true; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C, 1530b57cec5SDimitry Andric IRBuilder<> &Builder) { 1540b57cec5SDimitry Andric // If the constant C has been converted already in the given function F, just 1550b57cec5SDimitry Andric // return the converted value. 1560b57cec5SDimitry Andric ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C); 1570b57cec5SDimitry Andric if (CTII != ConstantToValueMap.end()) { 1580b57cec5SDimitry Andric return CTII->second; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric Value *NewValue = C; 1620b57cec5SDimitry Andric if (isa<GlobalVariable>(C)) { 1630b57cec5SDimitry Andric // If the constant C is a global variable and is found in GVMap, substitute 1640b57cec5SDimitry Andric // 1650b57cec5SDimitry Andric // addrspacecast GVMap[C] to addrspace(0) 1660b57cec5SDimitry Andric // 1670b57cec5SDimitry Andric // for our use of C. 1680b57cec5SDimitry Andric GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C)); 1690b57cec5SDimitry Andric if (I != GVMap.end()) { 1700b57cec5SDimitry Andric GlobalVariable *GV = I->second; 1710b57cec5SDimitry Andric NewValue = Builder.CreateAddrSpaceCast( 1720b57cec5SDimitry Andric GV, 1730b57cec5SDimitry Andric PointerType::get(GV->getValueType(), llvm::ADDRESS_SPACE_GENERIC)); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } else if (isa<ConstantAggregate>(C)) { 1760b57cec5SDimitry Andric // If any element in the constant vector or aggregate C is or uses a global 1770b57cec5SDimitry Andric // variable in GVMap, the constant C needs to be reconstructed, using a set 1780b57cec5SDimitry Andric // of instructions. 1790b57cec5SDimitry Andric NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder); 1800b57cec5SDimitry Andric } else if (isa<ConstantExpr>(C)) { 1810b57cec5SDimitry Andric // If any operand in the constant expression C is or uses a global variable 1820b57cec5SDimitry Andric // in GVMap, the constant expression C needs to be reconstructed, using a 1830b57cec5SDimitry Andric // set of instructions. 1840b57cec5SDimitry Andric NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric ConstantToValueMap[C] = NewValue; 1880b57cec5SDimitry Andric return NewValue; 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric Value *GenericToNVVM::remapConstantVectorOrConstantAggregate( 1920b57cec5SDimitry Andric Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { 1930b57cec5SDimitry Andric bool OperandChanged = false; 1940b57cec5SDimitry Andric SmallVector<Value *, 4> NewOperands; 1950b57cec5SDimitry Andric unsigned NumOperands = C->getNumOperands(); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Check if any element is or uses a global variable in GVMap, and thus 1980b57cec5SDimitry Andric // converted to another value. 1990b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2000b57cec5SDimitry Andric Value *Operand = C->getOperand(i); 2010b57cec5SDimitry Andric Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 2020b57cec5SDimitry Andric OperandChanged |= Operand != NewOperand; 2030b57cec5SDimitry Andric NewOperands.push_back(NewOperand); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric // If none of the elements has been modified, return C as it is. 2070b57cec5SDimitry Andric if (!OperandChanged) { 2080b57cec5SDimitry Andric return C; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric // If any of the elements has been modified, construct the equivalent 2120b57cec5SDimitry Andric // vector or aggregate value with a set instructions and the converted 2130b57cec5SDimitry Andric // elements. 214349cc55cSDimitry Andric Value *NewValue = PoisonValue::get(C->getType()); 2150b57cec5SDimitry Andric if (isa<ConstantVector>(C)) { 2160b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2170b57cec5SDimitry Andric Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); 2180b57cec5SDimitry Andric NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric } else { 2210b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2220b57cec5SDimitry Andric NewValue = 2230b57cec5SDimitry Andric Builder.CreateInsertValue(NewValue, NewOperands[i], makeArrayRef(i)); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric return NewValue; 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 2310b57cec5SDimitry Andric IRBuilder<> &Builder) { 2320b57cec5SDimitry Andric bool OperandChanged = false; 2330b57cec5SDimitry Andric SmallVector<Value *, 4> NewOperands; 2340b57cec5SDimitry Andric unsigned NumOperands = C->getNumOperands(); 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Check if any operand is or uses a global variable in GVMap, and thus 2370b57cec5SDimitry Andric // converted to another value. 2380b57cec5SDimitry Andric for (unsigned i = 0; i < NumOperands; ++i) { 2390b57cec5SDimitry Andric Value *Operand = C->getOperand(i); 2400b57cec5SDimitry Andric Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 2410b57cec5SDimitry Andric OperandChanged |= Operand != NewOperand; 2420b57cec5SDimitry Andric NewOperands.push_back(NewOperand); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric // If none of the operands has been modified, return C as it is. 2460b57cec5SDimitry Andric if (!OperandChanged) { 2470b57cec5SDimitry Andric return C; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric // If any of the operands has been modified, construct the instruction with 2510b57cec5SDimitry Andric // the converted operands. 2520b57cec5SDimitry Andric unsigned Opcode = C->getOpcode(); 2530b57cec5SDimitry Andric switch (Opcode) { 2540b57cec5SDimitry Andric case Instruction::ICmp: 2550b57cec5SDimitry Andric // CompareConstantExpr (icmp) 2560b57cec5SDimitry Andric return Builder.CreateICmp(CmpInst::Predicate(C->getPredicate()), 2570b57cec5SDimitry Andric NewOperands[0], NewOperands[1]); 2580b57cec5SDimitry Andric case Instruction::FCmp: 2590b57cec5SDimitry Andric // CompareConstantExpr (fcmp) 2600b57cec5SDimitry Andric llvm_unreachable("Address space conversion should have no effect " 2610b57cec5SDimitry Andric "on float point CompareConstantExpr (fcmp)!"); 2620b57cec5SDimitry Andric case Instruction::ExtractElement: 2630b57cec5SDimitry Andric // ExtractElementConstantExpr 2640b57cec5SDimitry Andric return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); 2650b57cec5SDimitry Andric case Instruction::InsertElement: 2660b57cec5SDimitry Andric // InsertElementConstantExpr 2670b57cec5SDimitry Andric return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], 2680b57cec5SDimitry Andric NewOperands[2]); 2690b57cec5SDimitry Andric case Instruction::ShuffleVector: 2700b57cec5SDimitry Andric // ShuffleVector 2710b57cec5SDimitry Andric return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], 2720b57cec5SDimitry Andric NewOperands[2]); 2730b57cec5SDimitry Andric case Instruction::InsertValue: 2740b57cec5SDimitry Andric // InsertValueConstantExpr 2750b57cec5SDimitry Andric return Builder.CreateInsertValue(NewOperands[0], NewOperands[1], 2760b57cec5SDimitry Andric C->getIndices()); 2770b57cec5SDimitry Andric case Instruction::GetElementPtr: 2780b57cec5SDimitry Andric // GetElementPtrConstantExpr 279*81ad6265SDimitry Andric return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(), 2800b57cec5SDimitry Andric NewOperands[0], 281*81ad6265SDimitry Andric makeArrayRef(&NewOperands[1], NumOperands - 1), "", 282*81ad6265SDimitry Andric cast<GEPOperator>(C)->isInBounds()); 2830b57cec5SDimitry Andric case Instruction::Select: 2840b57cec5SDimitry Andric // SelectConstantExpr 2850b57cec5SDimitry Andric return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); 2860b57cec5SDimitry Andric default: 2870b57cec5SDimitry Andric // BinaryConstantExpr 2880b57cec5SDimitry Andric if (Instruction::isBinaryOp(Opcode)) { 2890b57cec5SDimitry Andric return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), 2900b57cec5SDimitry Andric NewOperands[0], NewOperands[1]); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric // UnaryConstantExpr 2930b57cec5SDimitry Andric if (Instruction::isCast(Opcode)) { 2940b57cec5SDimitry Andric return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), 2950b57cec5SDimitry Andric NewOperands[0], C->getType()); 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr"); 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 300