Path: blob/main/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
35271 views
//===-- GenericToNVVM.cpp - Convert generic module to NVVM module - C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Convert generic global variables into either .global or .const access based9// on the variable's "constant" qualifier.10//11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/NVPTXBaseInfo.h"14#include "NVPTX.h"15#include "NVPTXUtilities.h"16#include "llvm/CodeGen/ValueTypes.h"17#include "llvm/IR/Constants.h"18#include "llvm/IR/DerivedTypes.h"19#include "llvm/IR/IRBuilder.h"20#include "llvm/IR/Instructions.h"21#include "llvm/IR/Intrinsics.h"22#include "llvm/IR/LegacyPassManager.h"23#include "llvm/IR/Module.h"24#include "llvm/IR/Operator.h"25#include "llvm/IR/ValueMap.h"26#include "llvm/Transforms/Utils/ValueMapper.h"2728using namespace llvm;2930namespace llvm {31void initializeGenericToNVVMLegacyPassPass(PassRegistry &);32}3334namespace {35class GenericToNVVM {36public:37bool runOnModule(Module &M);3839private:40Value *remapConstant(Module *M, Function *F, Constant *C,41IRBuilder<> &Builder);42Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F,43Constant *C,44IRBuilder<> &Builder);45Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C,46IRBuilder<> &Builder);4748typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy;49typedef ValueMap<Constant *, Value *> ConstantToValueMapTy;50GVMapTy GVMap;51ConstantToValueMapTy ConstantToValueMap;52};53} // end namespace5455bool GenericToNVVM::runOnModule(Module &M) {56// Create a clone of each global variable that has the default address space.57// The clone is created with the global address space specifier, and the pair58// of original global variable and its clone is placed in the GVMap for later59// use.6061for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {62if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC &&63!llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) &&64!GV.getName().starts_with("llvm.")) {65GlobalVariable *NewGV = new GlobalVariable(66M, GV.getValueType(), GV.isConstant(), GV.getLinkage(),67GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV,68GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL);69NewGV->copyAttributesFrom(&GV);70NewGV->copyMetadata(&GV, /*Offset=*/0);71GVMap[&GV] = NewGV;72}73}7475// Return immediately, if every global variable has a specific address space76// specifier.77if (GVMap.empty()) {78return false;79}8081// Walk through the instructions in function defitinions, and replace any use82// of original global variables in GVMap with a use of the corresponding83// copies in GVMap. If necessary, promote constants to instructions.84for (Function &F : M) {85if (F.isDeclaration()) {86continue;87}88IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHIOrDbg());89for (BasicBlock &BB : F) {90for (Instruction &II : BB) {91for (unsigned i = 0, e = II.getNumOperands(); i < e; ++i) {92Value *Operand = II.getOperand(i);93if (isa<Constant>(Operand)) {94II.setOperand(95i, remapConstant(&M, &F, cast<Constant>(Operand), Builder));96}97}98}99}100ConstantToValueMap.clear();101}102103// Copy GVMap over to a standard value map.104ValueToValueMapTy VM;105for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I)106VM[I->first] = I->second;107108// Walk through the global variable initializers, and replace any use of109// original global variables in GVMap with a use of the corresponding copies110// in GVMap. The copies need to be bitcast to the original global variable111// types, as we cannot use cvta in global variable initializers.112for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) {113GlobalVariable *GV = I->first;114GlobalVariable *NewGV = I->second;115116// Remove GV from the map so that it can be RAUWed. Note that117// DenseMap::erase() won't invalidate any iterators but this one.118auto Next = std::next(I);119GVMap.erase(I);120I = Next;121122Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType());123// At this point, the remaining uses of GV should be found only in global124// variable initializers, as other uses have been already been removed125// while walking through the instructions in function definitions.126GV->replaceAllUsesWith(BitCastNewGV);127std::string Name = std::string(GV->getName());128GV->eraseFromParent();129NewGV->setName(Name);130}131assert(GVMap.empty() && "Expected it to be empty by now");132133return true;134}135136Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C,137IRBuilder<> &Builder) {138// If the constant C has been converted already in the given function F, just139// return the converted value.140ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C);141if (CTII != ConstantToValueMap.end()) {142return CTII->second;143}144145Value *NewValue = C;146if (isa<GlobalVariable>(C)) {147// If the constant C is a global variable and is found in GVMap, substitute148//149// addrspacecast GVMap[C] to addrspace(0)150//151// for our use of C.152GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C));153if (I != GVMap.end()) {154GlobalVariable *GV = I->second;155NewValue = Builder.CreateAddrSpaceCast(156GV,157PointerType::get(GV->getValueType(), llvm::ADDRESS_SPACE_GENERIC));158}159} else if (isa<ConstantAggregate>(C)) {160// If any element in the constant vector or aggregate C is or uses a global161// variable in GVMap, the constant C needs to be reconstructed, using a set162// of instructions.163NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder);164} else if (isa<ConstantExpr>(C)) {165// If any operand in the constant expression C is or uses a global variable166// in GVMap, the constant expression C needs to be reconstructed, using a167// set of instructions.168NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder);169}170171ConstantToValueMap[C] = NewValue;172return NewValue;173}174175Value *GenericToNVVM::remapConstantVectorOrConstantAggregate(176Module *M, Function *F, Constant *C, IRBuilder<> &Builder) {177bool OperandChanged = false;178SmallVector<Value *, 4> NewOperands;179unsigned NumOperands = C->getNumOperands();180181// Check if any element is or uses a global variable in GVMap, and thus182// converted to another value.183for (unsigned i = 0; i < NumOperands; ++i) {184Value *Operand = C->getOperand(i);185Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder);186OperandChanged |= Operand != NewOperand;187NewOperands.push_back(NewOperand);188}189190// If none of the elements has been modified, return C as it is.191if (!OperandChanged) {192return C;193}194195// If any of the elements has been modified, construct the equivalent196// vector or aggregate value with a set instructions and the converted197// elements.198Value *NewValue = PoisonValue::get(C->getType());199if (isa<ConstantVector>(C)) {200for (unsigned i = 0; i < NumOperands; ++i) {201Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i);202NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx);203}204} else {205for (unsigned i = 0; i < NumOperands; ++i) {206NewValue =207Builder.CreateInsertValue(NewValue, NewOperands[i], ArrayRef(i));208}209}210211return NewValue;212}213214Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C,215IRBuilder<> &Builder) {216bool OperandChanged = false;217SmallVector<Value *, 4> NewOperands;218unsigned NumOperands = C->getNumOperands();219220// Check if any operand is or uses a global variable in GVMap, and thus221// converted to another value.222for (unsigned i = 0; i < NumOperands; ++i) {223Value *Operand = C->getOperand(i);224Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder);225OperandChanged |= Operand != NewOperand;226NewOperands.push_back(NewOperand);227}228229// If none of the operands has been modified, return C as it is.230if (!OperandChanged) {231return C;232}233234// If any of the operands has been modified, construct the instruction with235// the converted operands.236unsigned Opcode = C->getOpcode();237switch (Opcode) {238case Instruction::ExtractElement:239// ExtractElementConstantExpr240return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]);241case Instruction::InsertElement:242// InsertElementConstantExpr243return Builder.CreateInsertElement(NewOperands[0], NewOperands[1],244NewOperands[2]);245case Instruction::ShuffleVector:246// ShuffleVector247return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1],248NewOperands[2]);249case Instruction::GetElementPtr:250// GetElementPtrConstantExpr251return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(),252NewOperands[0],253ArrayRef(&NewOperands[1], NumOperands - 1), "",254cast<GEPOperator>(C)->isInBounds());255case Instruction::Select:256// SelectConstantExpr257return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]);258default:259// BinaryConstantExpr260if (Instruction::isBinaryOp(Opcode)) {261return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()),262NewOperands[0], NewOperands[1]);263}264// UnaryConstantExpr265if (Instruction::isCast(Opcode)) {266return Builder.CreateCast(Instruction::CastOps(C->getOpcode()),267NewOperands[0], C->getType());268}269llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr");270}271}272273namespace {274class GenericToNVVMLegacyPass : public ModulePass {275public:276static char ID;277278GenericToNVVMLegacyPass() : ModulePass(ID) {}279280bool runOnModule(Module &M) override;281};282} // namespace283284char GenericToNVVMLegacyPass::ID = 0;285286ModulePass *llvm::createGenericToNVVMLegacyPass() {287return new GenericToNVVMLegacyPass();288}289290INITIALIZE_PASS(291GenericToNVVMLegacyPass, "generic-to-nvvm",292"Ensure that the global variables are in the global address space", false,293false)294295bool GenericToNVVMLegacyPass::runOnModule(Module &M) {296return GenericToNVVM().runOnModule(M);297}298299PreservedAnalyses GenericToNVVMPass::run(Module &M, ModuleAnalysisManager &AM) {300return GenericToNVVM().runOnModule(M) ? PreservedAnalyses::none()301: PreservedAnalyses::all();302}303304305