brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.8 KiB · 7f190f3 Raw
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