| //===-- GenericToNVVM.cpp - Convert generic module to NVVM module - C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Convert generic global variables into either .global or .const access based |
| // on the variable's "constant" qualifier. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MCTargetDesc/NVPTXBaseInfo.h" |
| #include "NVPTX.h" |
| #include "NVPTXUtilities.h" |
| #include "llvm/CodeGen/ValueTypes.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/IRBuilder.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/Intrinsics.h" |
| #include "llvm/IR/LegacyPassManager.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Operator.h" |
| #include "llvm/IR/ValueMap.h" |
| #include "llvm/Transforms/Utils/ValueMapper.h" |
| |
| using namespace llvm; |
| |
| namespace llvm { |
| void initializeGenericToNVVMPass(PassRegistry &); |
| } |
| |
| namespace { |
| class GenericToNVVM : public ModulePass { |
| public: |
| static char ID; |
| |
| GenericToNVVM() : ModulePass(ID) {} |
| |
| bool runOnModule(Module &M) override; |
| |
| void getAnalysisUsage(AnalysisUsage &AU) const override {} |
| |
| private: |
| Value *remapConstant(Module *M, Function *F, Constant *C, |
| IRBuilder<> &Builder); |
| Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F, |
| Constant *C, |
| IRBuilder<> &Builder); |
| Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C, |
| IRBuilder<> &Builder); |
| |
| typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy; |
| typedef ValueMap<Constant *, Value *> ConstantToValueMapTy; |
| GVMapTy GVMap; |
| ConstantToValueMapTy ConstantToValueMap; |
| }; |
| } // end namespace |
| |
| char GenericToNVVM::ID = 0; |
| |
| ModulePass *llvm::createGenericToNVVMPass() { return new GenericToNVVM(); } |
| |
| INITIALIZE_PASS( |
| GenericToNVVM, "generic-to-nvvm", |
| "Ensure that the global variables are in the global address space", false, |
| false) |
| |
| bool GenericToNVVM::runOnModule(Module &M) { |
| // Create a clone of each global variable that has the default address space. |
| // The clone is created with the global address space specifier, and the pair |
| // of original global variable and its clone is placed in the GVMap for later |
| // use. |
| |
| for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) { |
| if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && |
| !llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) && |
| !GV.getName().startswith("llvm.")) { |
| GlobalVariable *NewGV = new GlobalVariable( |
| M, GV.getValueType(), GV.isConstant(), GV.getLinkage(), |
| GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV, |
| GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); |
| NewGV->copyAttributesFrom(&GV); |
| GVMap[&GV] = NewGV; |
| } |
| } |
| |
| // Return immediately, if every global variable has a specific address space |
| // specifier. |
| if (GVMap.empty()) { |
| return false; |
| } |
| |
| // Walk through the instructions in function defitinions, and replace any use |
| // of original global variables in GVMap with a use of the corresponding |
| // copies in GVMap. If necessary, promote constants to instructions. |
| for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { |
| if (I->isDeclaration()) { |
| continue; |
| } |
| IRBuilder<> Builder(I->getEntryBlock().getFirstNonPHIOrDbg()); |
| for (Function::iterator BBI = I->begin(), BBE = I->end(); BBI != BBE; |
| ++BBI) { |
| for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; |
| ++II) { |
| for (unsigned i = 0, e = II->getNumOperands(); i < e; ++i) { |
| Value *Operand = II->getOperand(i); |
| if (isa<Constant>(Operand)) { |
| II->setOperand( |
| i, remapConstant(&M, &*I, cast<Constant>(Operand), Builder)); |
| } |
| } |
| } |
| } |
| ConstantToValueMap.clear(); |
| } |
| |
| // Copy GVMap over to a standard value map. |
| ValueToValueMapTy VM; |
| for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I) |
| VM[I->first] = I->second; |
| |
| // Walk through the global variable initializers, and replace any use of |
| // original global variables in GVMap with a use of the corresponding copies |
| // in GVMap. The copies need to be bitcast to the original global variable |
| // types, as we cannot use cvta in global variable initializers. |
| for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { |
| GlobalVariable *GV = I->first; |
| GlobalVariable *NewGV = I->second; |
| |
| // Remove GV from the map so that it can be RAUWed. Note that |
| // DenseMap::erase() won't invalidate any iterators but this one. |
| auto Next = std::next(I); |
| GVMap.erase(I); |
| I = Next; |
| |
| Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType()); |
| // At this point, the remaining uses of GV should be found only in global |
| // variable initializers, as other uses have been already been removed |
| // while walking through the instructions in function definitions. |
| GV->replaceAllUsesWith(BitCastNewGV); |
| std::string Name = std::string(GV->getName()); |
| GV->eraseFromParent(); |
| NewGV->setName(Name); |
| } |
| assert(GVMap.empty() && "Expected it to be empty by now"); |
| |
| return true; |
| } |
| |
| Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C, |
| IRBuilder<> &Builder) { |
| // If the constant C has been converted already in the given function F, just |
| // return the converted value. |
| ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C); |
| if (CTII != ConstantToValueMap.end()) { |
| return CTII->second; |
| } |
| |
| Value *NewValue = C; |
| if (isa<GlobalVariable>(C)) { |
| // If the constant C is a global variable and is found in GVMap, substitute |
| // |
| // addrspacecast GVMap[C] to addrspace(0) |
| // |
| // for our use of C. |
| GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C)); |
| if (I != GVMap.end()) { |
| GlobalVariable *GV = I->second; |
| NewValue = Builder.CreateAddrSpaceCast( |
| GV, |
| PointerType::get(GV->getValueType(), llvm::ADDRESS_SPACE_GENERIC)); |
| } |
| } else if (isa<ConstantAggregate>(C)) { |
| // If any element in the constant vector or aggregate C is or uses a global |
| // variable in GVMap, the constant C needs to be reconstructed, using a set |
| // of instructions. |
| NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder); |
| } else if (isa<ConstantExpr>(C)) { |
| // If any operand in the constant expression C is or uses a global variable |
| // in GVMap, the constant expression C needs to be reconstructed, using a |
| // set of instructions. |
| NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); |
| } |
| |
| ConstantToValueMap[C] = NewValue; |
| return NewValue; |
| } |
| |
| Value *GenericToNVVM::remapConstantVectorOrConstantAggregate( |
| Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { |
| bool OperandChanged = false; |
| SmallVector<Value *, 4> NewOperands; |
| unsigned NumOperands = C->getNumOperands(); |
| |
| // Check if any element is or uses a global variable in GVMap, and thus |
| // converted to another value. |
| for (unsigned i = 0; i < NumOperands; ++i) { |
| Value *Operand = C->getOperand(i); |
| Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); |
| OperandChanged |= Operand != NewOperand; |
| NewOperands.push_back(NewOperand); |
| } |
| |
| // If none of the elements has been modified, return C as it is. |
| if (!OperandChanged) { |
| return C; |
| } |
| |
| // If any of the elements has been modified, construct the equivalent |
| // vector or aggregate value with a set instructions and the converted |
| // elements. |
| Value *NewValue = PoisonValue::get(C->getType()); |
| if (isa<ConstantVector>(C)) { |
| for (unsigned i = 0; i < NumOperands; ++i) { |
| Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); |
| NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); |
| } |
| } else { |
| for (unsigned i = 0; i < NumOperands; ++i) { |
| NewValue = |
| Builder.CreateInsertValue(NewValue, NewOperands[i], makeArrayRef(i)); |
| } |
| } |
| |
| return NewValue; |
| } |
| |
| Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, |
| IRBuilder<> &Builder) { |
| bool OperandChanged = false; |
| SmallVector<Value *, 4> NewOperands; |
| unsigned NumOperands = C->getNumOperands(); |
| |
| // Check if any operand is or uses a global variable in GVMap, and thus |
| // converted to another value. |
| for (unsigned i = 0; i < NumOperands; ++i) { |
| Value *Operand = C->getOperand(i); |
| Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); |
| OperandChanged |= Operand != NewOperand; |
| NewOperands.push_back(NewOperand); |
| } |
| |
| // If none of the operands has been modified, return C as it is. |
| if (!OperandChanged) { |
| return C; |
| } |
| |
| // If any of the operands has been modified, construct the instruction with |
| // the converted operands. |
| unsigned Opcode = C->getOpcode(); |
| switch (Opcode) { |
| case Instruction::ICmp: |
| // CompareConstantExpr (icmp) |
| return Builder.CreateICmp(CmpInst::Predicate(C->getPredicate()), |
| NewOperands[0], NewOperands[1]); |
| case Instruction::FCmp: |
| // CompareConstantExpr (fcmp) |
| llvm_unreachable("Address space conversion should have no effect " |
| "on float point CompareConstantExpr (fcmp)!"); |
| case Instruction::ExtractElement: |
| // ExtractElementConstantExpr |
| return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); |
| case Instruction::InsertElement: |
| // InsertElementConstantExpr |
| return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], |
| NewOperands[2]); |
| case Instruction::ShuffleVector: |
| // ShuffleVector |
| return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], |
| NewOperands[2]); |
| case Instruction::ExtractValue: |
| // ExtractValueConstantExpr |
| return Builder.CreateExtractValue(NewOperands[0], C->getIndices()); |
| case Instruction::InsertValue: |
| // InsertValueConstantExpr |
| return Builder.CreateInsertValue(NewOperands[0], NewOperands[1], |
| C->getIndices()); |
| case Instruction::GetElementPtr: |
| // GetElementPtrConstantExpr |
| return cast<GEPOperator>(C)->isInBounds() |
| ? Builder.CreateGEP( |
| cast<GEPOperator>(C)->getSourceElementType(), |
| NewOperands[0], |
| makeArrayRef(&NewOperands[1], NumOperands - 1)) |
| : Builder.CreateInBoundsGEP( |
| cast<GEPOperator>(C)->getSourceElementType(), |
| NewOperands[0], |
| makeArrayRef(&NewOperands[1], NumOperands - 1)); |
| case Instruction::Select: |
| // SelectConstantExpr |
| return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); |
| default: |
| // BinaryConstantExpr |
| if (Instruction::isBinaryOp(Opcode)) { |
| return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), |
| NewOperands[0], NewOperands[1]); |
| } |
| // UnaryConstantExpr |
| if (Instruction::isCast(Opcode)) { |
| return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), |
| NewOperands[0], C->getType()); |
| } |
| llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr"); |
| } |
| } |