299 lines · cpp
1//===-- GenericToNVVM.cpp - Convert generic module to NVVM module - C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Convert generic global variables into either .global or .const access based10// on the variable's "constant" qualifier.11//12//===----------------------------------------------------------------------===//13 14#include "MCTargetDesc/NVPTXBaseInfo.h"15#include "NVPTX.h"16#include "NVPTXUtilities.h"17#include "llvm/CodeGen/ValueTypes.h"18#include "llvm/IR/Constants.h"19#include "llvm/IR/DerivedTypes.h"20#include "llvm/IR/IRBuilder.h"21#include "llvm/IR/Instructions.h"22#include "llvm/IR/Intrinsics.h"23#include "llvm/IR/LegacyPassManager.h"24#include "llvm/IR/Module.h"25#include "llvm/IR/Operator.h"26#include "llvm/IR/ValueMap.h"27#include "llvm/Transforms/Utils/ValueMapper.h"28 29using namespace llvm;30 31namespace {32class GenericToNVVM {33public:34 bool runOnModule(Module &M);35 36private:37 Value *remapConstant(Module *M, Function *F, Constant *C,38 IRBuilder<> &Builder);39 Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F,40 Constant *C,41 IRBuilder<> &Builder);42 Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C,43 IRBuilder<> &Builder);44 45 typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy;46 typedef ValueMap<Constant *, Value *> ConstantToValueMapTy;47 GVMapTy GVMap;48 ConstantToValueMapTy ConstantToValueMap;49};50} // end namespace51 52bool GenericToNVVM::runOnModule(Module &M) {53 // Create a clone of each global variable that has the default address space.54 // The clone is created with the global address space specifier, and the pair55 // of original global variable and its clone is placed in the GVMap for later56 // use.57 58 for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {59 if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC &&60 !llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) &&61 !GV.getName().starts_with("llvm.")) {62 GlobalVariable *NewGV = new GlobalVariable(63 M, GV.getValueType(), GV.isConstant(), GV.getLinkage(),64 GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV,65 GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL);66 NewGV->copyAttributesFrom(&GV);67 NewGV->copyMetadata(&GV, /*Offset=*/0);68 GVMap[&GV] = NewGV;69 }70 }71 72 // Return immediately, if every global variable has a specific address space73 // specifier.74 if (GVMap.empty()) {75 return false;76 }77 78 // Walk through the instructions in function defitinions, and replace any use79 // of original global variables in GVMap with a use of the corresponding80 // copies in GVMap. If necessary, promote constants to instructions.81 for (Function &F : M) {82 if (F.isDeclaration()) {83 continue;84 }85 IRBuilder<> Builder(&*F.getEntryBlock().getFirstNonPHIOrDbg());86 for (BasicBlock &BB : F) {87 for (Instruction &II : BB) {88 for (unsigned i = 0, e = II.getNumOperands(); i < e; ++i) {89 Value *Operand = II.getOperand(i);90 if (isa<Constant>(Operand)) {91 II.setOperand(92 i, remapConstant(&M, &F, cast<Constant>(Operand), Builder));93 }94 }95 }96 }97 ConstantToValueMap.clear();98 }99 100 // Copy GVMap over to a standard value map.101 ValueToValueMapTy VM;102 for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I)103 VM[I->first] = I->second;104 105 // Walk through the global variable initializers, and replace any use of106 // original global variables in GVMap with a use of the corresponding copies107 // in GVMap. The copies need to be bitcast to the original global variable108 // types, as we cannot use cvta in global variable initializers.109 for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) {110 GlobalVariable *GV = I->first;111 GlobalVariable *NewGV = I->second;112 113 // Remove GV from the map so that it can be RAUWed. Note that114 // DenseMap::erase() won't invalidate any iterators but this one.115 auto Next = std::next(I);116 GVMap.erase(I);117 I = Next;118 119 Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType());120 // At this point, the remaining uses of GV should be found only in global121 // variable initializers, as other uses have been already been removed122 // while walking through the instructions in function definitions.123 GV->replaceAllUsesWith(BitCastNewGV);124 std::string Name = std::string(GV->getName());125 GV->eraseFromParent();126 NewGV->setName(Name);127 }128 assert(GVMap.empty() && "Expected it to be empty by now");129 130 return true;131}132 133Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C,134 IRBuilder<> &Builder) {135 // If the constant C has been converted already in the given function F, just136 // return the converted value.137 ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C);138 if (CTII != ConstantToValueMap.end()) {139 return CTII->second;140 }141 142 Value *NewValue = C;143 if (isa<GlobalVariable>(C)) {144 // If the constant C is a global variable and is found in GVMap, substitute145 //146 // addrspacecast GVMap[C] to addrspace(0)147 //148 // for our use of C.149 GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C));150 if (I != GVMap.end()) {151 GlobalVariable *GV = I->second;152 NewValue = Builder.CreateAddrSpaceCast(153 GV, PointerType::get(GV->getContext(), llvm::ADDRESS_SPACE_GENERIC));154 }155 } else if (isa<ConstantAggregate>(C)) {156 // If any element in the constant vector or aggregate C is or uses a global157 // variable in GVMap, the constant C needs to be reconstructed, using a set158 // of instructions.159 NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder);160 } else if (isa<ConstantExpr>(C)) {161 // If any operand in the constant expression C is or uses a global variable162 // in GVMap, the constant expression C needs to be reconstructed, using a163 // set of instructions.164 NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder);165 }166 167 ConstantToValueMap[C] = NewValue;168 return NewValue;169}170 171Value *GenericToNVVM::remapConstantVectorOrConstantAggregate(172 Module *M, Function *F, Constant *C, IRBuilder<> &Builder) {173 bool OperandChanged = false;174 SmallVector<Value *, 4> NewOperands;175 unsigned NumOperands = C->getNumOperands();176 177 // Check if any element is or uses a global variable in GVMap, and thus178 // converted to another value.179 for (unsigned i = 0; i < NumOperands; ++i) {180 Value *Operand = C->getOperand(i);181 Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder);182 OperandChanged |= Operand != NewOperand;183 NewOperands.push_back(NewOperand);184 }185 186 // If none of the elements has been modified, return C as it is.187 if (!OperandChanged) {188 return C;189 }190 191 // If any of the elements has been modified, construct the equivalent192 // vector or aggregate value with a set instructions and the converted193 // elements.194 Value *NewValue = PoisonValue::get(C->getType());195 if (isa<ConstantVector>(C)) {196 for (unsigned i = 0; i < NumOperands; ++i) {197 Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i);198 NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx);199 }200 } else {201 for (unsigned i = 0; i < NumOperands; ++i) {202 NewValue =203 Builder.CreateInsertValue(NewValue, NewOperands[i], ArrayRef(i));204 }205 }206 207 return NewValue;208}209 210Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C,211 IRBuilder<> &Builder) {212 bool OperandChanged = false;213 SmallVector<Value *, 4> NewOperands;214 unsigned NumOperands = C->getNumOperands();215 216 // Check if any operand is or uses a global variable in GVMap, and thus217 // converted to another value.218 for (unsigned i = 0; i < NumOperands; ++i) {219 Value *Operand = C->getOperand(i);220 Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder);221 OperandChanged |= Operand != NewOperand;222 NewOperands.push_back(NewOperand);223 }224 225 // If none of the operands has been modified, return C as it is.226 if (!OperandChanged) {227 return C;228 }229 230 // If any of the operands has been modified, construct the instruction with231 // the converted operands.232 unsigned Opcode = C->getOpcode();233 switch (Opcode) {234 case Instruction::ExtractElement:235 // ExtractElementConstantExpr236 return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]);237 case Instruction::InsertElement:238 // InsertElementConstantExpr239 return Builder.CreateInsertElement(NewOperands[0], NewOperands[1],240 NewOperands[2]);241 case Instruction::ShuffleVector:242 // ShuffleVector243 return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1],244 NewOperands[2]);245 case Instruction::GetElementPtr:246 // GetElementPtrConstantExpr247 return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(),248 NewOperands[0],249 ArrayRef(&NewOperands[1], NumOperands - 1), "",250 cast<GEPOperator>(C)->isInBounds());251 case Instruction::Select:252 // SelectConstantExpr253 return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]);254 default:255 // BinaryConstantExpr256 if (Instruction::isBinaryOp(Opcode)) {257 return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()),258 NewOperands[0], NewOperands[1]);259 }260 // UnaryConstantExpr261 if (Instruction::isCast(Opcode)) {262 return Builder.CreateCast(Instruction::CastOps(C->getOpcode()),263 NewOperands[0], C->getType());264 }265 llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr");266 }267}268 269namespace {270class GenericToNVVMLegacyPass : public ModulePass {271public:272 static char ID;273 274 GenericToNVVMLegacyPass() : ModulePass(ID) {}275 276 bool runOnModule(Module &M) override;277};278} // namespace279 280char GenericToNVVMLegacyPass::ID = 0;281 282ModulePass *llvm::createGenericToNVVMLegacyPass() {283 return new GenericToNVVMLegacyPass();284}285 286INITIALIZE_PASS(287 GenericToNVVMLegacyPass, "generic-to-nvvm",288 "Ensure that the global variables are in the global address space", false,289 false)290 291bool GenericToNVVMLegacyPass::runOnModule(Module &M) {292 return GenericToNVVM().runOnModule(M);293}294 295PreservedAnalyses GenericToNVVMPass::run(Module &M, ModuleAnalysisManager &AM) {296 return GenericToNVVM().runOnModule(M) ? PreservedAnalyses::none()297 : PreservedAnalyses::all();298}299