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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Convert generic global variables into either .global or .const access based 10 // 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 29 using namespace llvm; 30 31 namespace llvm { 32 void initializeGenericToNVVMLegacyPassPass(PassRegistry &); 33 } 34 35 namespace { 36 class GenericToNVVM { 37 public: 38 bool runOnModule(Module &M); 39 40 private: 41 Value *remapConstant(Module *M, Function *F, Constant *C, 42 IRBuilder<> &Builder); 43 Value *remapConstantVectorOrConstantAggregate(Module *M, Function *F, 44 Constant *C, 45 IRBuilder<> &Builder); 46 Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 47 IRBuilder<> &Builder); 48 49 typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy; 50 typedef ValueMap<Constant *, Value *> ConstantToValueMapTy; 51 GVMapTy GVMap; 52 ConstantToValueMapTy ConstantToValueMap; 53 }; 54 } // end namespace 55 56 bool GenericToNVVM::runOnModule(Module &M) { 57 // Create a clone of each global variable that has the default address space. 58 // The clone is created with the global address space specifier, and the pair 59 // of original global variable and its clone is placed in the GVMap for later 60 // use. 61 62 for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) { 63 if (GV.getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC && 64 !llvm::isTexture(GV) && !llvm::isSurface(GV) && !llvm::isSampler(GV) && 65 !GV.getName().starts_with("llvm.")) { 66 GlobalVariable *NewGV = new GlobalVariable( 67 M, GV.getValueType(), GV.isConstant(), GV.getLinkage(), 68 GV.hasInitializer() ? GV.getInitializer() : nullptr, "", &GV, 69 GV.getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL); 70 NewGV->copyAttributesFrom(&GV); 71 NewGV->copyMetadata(&GV, /*Offset=*/0); 72 GVMap[&GV] = NewGV; 73 } 74 } 75 76 // Return immediately, if every global variable has a specific address space 77 // specifier. 78 if (GVMap.empty()) { 79 return false; 80 } 81 82 // Walk through the instructions in function defitinions, and replace any use 83 // of original global variables in GVMap with a use of the corresponding 84 // copies in GVMap. If necessary, promote constants to instructions. 85 for (Function &F : M) { 86 if (F.isDeclaration()) { 87 continue; 88 } 89 IRBuilder<> Builder(&*F.getEntryBlock().getFirstNonPHIOrDbg()); 90 for (BasicBlock &BB : F) { 91 for (Instruction &II : BB) { 92 for (unsigned i = 0, e = II.getNumOperands(); i < e; ++i) { 93 Value *Operand = II.getOperand(i); 94 if (isa<Constant>(Operand)) { 95 II.setOperand( 96 i, remapConstant(&M, &F, cast<Constant>(Operand), Builder)); 97 } 98 } 99 } 100 } 101 ConstantToValueMap.clear(); 102 } 103 104 // Copy GVMap over to a standard value map. 105 ValueToValueMapTy VM; 106 for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I) 107 VM[I->first] = I->second; 108 109 // Walk through the global variable initializers, and replace any use of 110 // original global variables in GVMap with a use of the corresponding copies 111 // in GVMap. The copies need to be bitcast to the original global variable 112 // types, as we cannot use cvta in global variable initializers. 113 for (GVMapTy::iterator I = GVMap.begin(), E = GVMap.end(); I != E;) { 114 GlobalVariable *GV = I->first; 115 GlobalVariable *NewGV = I->second; 116 117 // Remove GV from the map so that it can be RAUWed. Note that 118 // DenseMap::erase() won't invalidate any iterators but this one. 119 auto Next = std::next(I); 120 GVMap.erase(I); 121 I = Next; 122 123 Constant *BitCastNewGV = ConstantExpr::getPointerCast(NewGV, GV->getType()); 124 // At this point, the remaining uses of GV should be found only in global 125 // variable initializers, as other uses have been already been removed 126 // while walking through the instructions in function definitions. 127 GV->replaceAllUsesWith(BitCastNewGV); 128 std::string Name = std::string(GV->getName()); 129 GV->eraseFromParent(); 130 NewGV->setName(Name); 131 } 132 assert(GVMap.empty() && "Expected it to be empty by now"); 133 134 return true; 135 } 136 137 Value *GenericToNVVM::remapConstant(Module *M, Function *F, Constant *C, 138 IRBuilder<> &Builder) { 139 // If the constant C has been converted already in the given function F, just 140 // return the converted value. 141 ConstantToValueMapTy::iterator CTII = ConstantToValueMap.find(C); 142 if (CTII != ConstantToValueMap.end()) { 143 return CTII->second; 144 } 145 146 Value *NewValue = C; 147 if (isa<GlobalVariable>(C)) { 148 // If the constant C is a global variable and is found in GVMap, substitute 149 // 150 // addrspacecast GVMap[C] to addrspace(0) 151 // 152 // for our use of C. 153 GVMapTy::iterator I = GVMap.find(cast<GlobalVariable>(C)); 154 if (I != GVMap.end()) { 155 GlobalVariable *GV = I->second; 156 NewValue = Builder.CreateAddrSpaceCast( 157 GV, PointerType::get(GV->getContext(), 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 global 161 // variable in GVMap, the constant C needs to be reconstructed, using a set 162 // of instructions. 163 NewValue = 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 variable 166 // in GVMap, the constant expression C needs to be reconstructed, using a 167 // set of instructions. 168 NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); 169 } 170 171 ConstantToValueMap[C] = NewValue; 172 return NewValue; 173 } 174 175 Value *GenericToNVVM::remapConstantVectorOrConstantAggregate( 176 Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { 177 bool OperandChanged = false; 178 SmallVector<Value *, 4> NewOperands; 179 unsigned NumOperands = C->getNumOperands(); 180 181 // Check if any element is or uses a global variable in GVMap, and thus 182 // converted to another value. 183 for (unsigned i = 0; i < NumOperands; ++i) { 184 Value *Operand = C->getOperand(i); 185 Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 186 OperandChanged |= Operand != NewOperand; 187 NewOperands.push_back(NewOperand); 188 } 189 190 // If none of the elements has been modified, return C as it is. 191 if (!OperandChanged) { 192 return C; 193 } 194 195 // If any of the elements has been modified, construct the equivalent 196 // vector or aggregate value with a set instructions and the converted 197 // elements. 198 Value *NewValue = PoisonValue::get(C->getType()); 199 if (isa<ConstantVector>(C)) { 200 for (unsigned i = 0; i < NumOperands; ++i) { 201 Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); 202 NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); 203 } 204 } else { 205 for (unsigned i = 0; i < NumOperands; ++i) { 206 NewValue = 207 Builder.CreateInsertValue(NewValue, NewOperands[i], ArrayRef(i)); 208 } 209 } 210 211 return NewValue; 212 } 213 214 Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 215 IRBuilder<> &Builder) { 216 bool OperandChanged = false; 217 SmallVector<Value *, 4> NewOperands; 218 unsigned NumOperands = C->getNumOperands(); 219 220 // Check if any operand is or uses a global variable in GVMap, and thus 221 // converted to another value. 222 for (unsigned i = 0; i < NumOperands; ++i) { 223 Value *Operand = C->getOperand(i); 224 Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 225 OperandChanged |= Operand != NewOperand; 226 NewOperands.push_back(NewOperand); 227 } 228 229 // If none of the operands has been modified, return C as it is. 230 if (!OperandChanged) { 231 return C; 232 } 233 234 // If any of the operands has been modified, construct the instruction with 235 // the converted operands. 236 unsigned Opcode = C->getOpcode(); 237 switch (Opcode) { 238 case Instruction::ExtractElement: 239 // ExtractElementConstantExpr 240 return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); 241 case Instruction::InsertElement: 242 // InsertElementConstantExpr 243 return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], 244 NewOperands[2]); 245 case Instruction::ShuffleVector: 246 // ShuffleVector 247 return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], 248 NewOperands[2]); 249 case Instruction::GetElementPtr: 250 // GetElementPtrConstantExpr 251 return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(), 252 NewOperands[0], 253 ArrayRef(&NewOperands[1], NumOperands - 1), "", 254 cast<GEPOperator>(C)->isInBounds()); 255 case Instruction::Select: 256 // SelectConstantExpr 257 return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); 258 default: 259 // BinaryConstantExpr 260 if (Instruction::isBinaryOp(Opcode)) { 261 return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), 262 NewOperands[0], NewOperands[1]); 263 } 264 // UnaryConstantExpr 265 if (Instruction::isCast(Opcode)) { 266 return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), 267 NewOperands[0], C->getType()); 268 } 269 llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr"); 270 } 271 } 272 273 namespace { 274 class GenericToNVVMLegacyPass : public ModulePass { 275 public: 276 static char ID; 277 278 GenericToNVVMLegacyPass() : ModulePass(ID) {} 279 280 bool runOnModule(Module &M) override; 281 }; 282 } // namespace 283 284 char GenericToNVVMLegacyPass::ID = 0; 285 286 ModulePass *llvm::createGenericToNVVMLegacyPass() { 287 return new GenericToNVVMLegacyPass(); 288 } 289 290 INITIALIZE_PASS( 291 GenericToNVVMLegacyPass, "generic-to-nvvm", 292 "Ensure that the global variables are in the global address space", false, 293 false) 294 295 bool GenericToNVVMLegacyPass::runOnModule(Module &M) { 296 return GenericToNVVM().runOnModule(M); 297 } 298 299 PreservedAnalyses GenericToNVVMPass::run(Module &M, ModuleAnalysisManager &AM) { 300 return GenericToNVVM().runOnModule(M) ? PreservedAnalyses::none() 301 : PreservedAnalyses::all(); 302 } 303