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, 158 PointerType::get(GV->getValueType(), llvm::ADDRESS_SPACE_GENERIC)); 159 } 160 } else if (isa<ConstantAggregate>(C)) { 161 // If any element in the constant vector or aggregate C is or uses a global 162 // variable in GVMap, the constant C needs to be reconstructed, using a set 163 // of instructions. 164 NewValue = remapConstantVectorOrConstantAggregate(M, F, C, Builder); 165 } else if (isa<ConstantExpr>(C)) { 166 // If any operand in the constant expression C is or uses a global variable 167 // in GVMap, the constant expression C needs to be reconstructed, using a 168 // set of instructions. 169 NewValue = remapConstantExpr(M, F, cast<ConstantExpr>(C), Builder); 170 } 171 172 ConstantToValueMap[C] = NewValue; 173 return NewValue; 174 } 175 176 Value *GenericToNVVM::remapConstantVectorOrConstantAggregate( 177 Module *M, Function *F, Constant *C, IRBuilder<> &Builder) { 178 bool OperandChanged = false; 179 SmallVector<Value *, 4> NewOperands; 180 unsigned NumOperands = C->getNumOperands(); 181 182 // Check if any element is or uses a global variable in GVMap, and thus 183 // converted to another value. 184 for (unsigned i = 0; i < NumOperands; ++i) { 185 Value *Operand = C->getOperand(i); 186 Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 187 OperandChanged |= Operand != NewOperand; 188 NewOperands.push_back(NewOperand); 189 } 190 191 // If none of the elements has been modified, return C as it is. 192 if (!OperandChanged) { 193 return C; 194 } 195 196 // If any of the elements has been modified, construct the equivalent 197 // vector or aggregate value with a set instructions and the converted 198 // elements. 199 Value *NewValue = PoisonValue::get(C->getType()); 200 if (isa<ConstantVector>(C)) { 201 for (unsigned i = 0; i < NumOperands; ++i) { 202 Value *Idx = ConstantInt::get(Type::getInt32Ty(M->getContext()), i); 203 NewValue = Builder.CreateInsertElement(NewValue, NewOperands[i], Idx); 204 } 205 } else { 206 for (unsigned i = 0; i < NumOperands; ++i) { 207 NewValue = 208 Builder.CreateInsertValue(NewValue, NewOperands[i], ArrayRef(i)); 209 } 210 } 211 212 return NewValue; 213 } 214 215 Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C, 216 IRBuilder<> &Builder) { 217 bool OperandChanged = false; 218 SmallVector<Value *, 4> NewOperands; 219 unsigned NumOperands = C->getNumOperands(); 220 221 // Check if any operand is or uses a global variable in GVMap, and thus 222 // converted to another value. 223 for (unsigned i = 0; i < NumOperands; ++i) { 224 Value *Operand = C->getOperand(i); 225 Value *NewOperand = remapConstant(M, F, cast<Constant>(Operand), Builder); 226 OperandChanged |= Operand != NewOperand; 227 NewOperands.push_back(NewOperand); 228 } 229 230 // If none of the operands has been modified, return C as it is. 231 if (!OperandChanged) { 232 return C; 233 } 234 235 // If any of the operands has been modified, construct the instruction with 236 // the converted operands. 237 unsigned Opcode = C->getOpcode(); 238 switch (Opcode) { 239 case Instruction::ICmp: 240 // CompareConstantExpr (icmp) 241 return Builder.CreateICmp(CmpInst::Predicate(C->getPredicate()), 242 NewOperands[0], NewOperands[1]); 243 case Instruction::FCmp: 244 // CompareConstantExpr (fcmp) 245 llvm_unreachable("Address space conversion should have no effect " 246 "on float point CompareConstantExpr (fcmp)!"); 247 case Instruction::ExtractElement: 248 // ExtractElementConstantExpr 249 return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]); 250 case Instruction::InsertElement: 251 // InsertElementConstantExpr 252 return Builder.CreateInsertElement(NewOperands[0], NewOperands[1], 253 NewOperands[2]); 254 case Instruction::ShuffleVector: 255 // ShuffleVector 256 return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1], 257 NewOperands[2]); 258 case Instruction::GetElementPtr: 259 // GetElementPtrConstantExpr 260 return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(), 261 NewOperands[0], 262 ArrayRef(&NewOperands[1], NumOperands - 1), "", 263 cast<GEPOperator>(C)->isInBounds()); 264 case Instruction::Select: 265 // SelectConstantExpr 266 return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]); 267 default: 268 // BinaryConstantExpr 269 if (Instruction::isBinaryOp(Opcode)) { 270 return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()), 271 NewOperands[0], NewOperands[1]); 272 } 273 // UnaryConstantExpr 274 if (Instruction::isCast(Opcode)) { 275 return Builder.CreateCast(Instruction::CastOps(C->getOpcode()), 276 NewOperands[0], C->getType()); 277 } 278 llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr"); 279 } 280 } 281 282 namespace { 283 class GenericToNVVMLegacyPass : public ModulePass { 284 public: 285 static char ID; 286 287 GenericToNVVMLegacyPass() : ModulePass(ID) {} 288 289 bool runOnModule(Module &M) override; 290 }; 291 } // namespace 292 293 char GenericToNVVMLegacyPass::ID = 0; 294 295 ModulePass *llvm::createGenericToNVVMLegacyPass() { 296 return new GenericToNVVMLegacyPass(); 297 } 298 299 INITIALIZE_PASS( 300 GenericToNVVMLegacyPass, "generic-to-nvvm", 301 "Ensure that the global variables are in the global address space", false, 302 false) 303 304 bool GenericToNVVMLegacyPass::runOnModule(Module &M) { 305 return GenericToNVVM().runOnModule(M); 306 } 307 308 PreservedAnalyses GenericToNVVMPass::run(Module &M, ModuleAnalysisManager &AM) { 309 return GenericToNVVM().runOnModule(M) ? PreservedAnalyses::none() 310 : PreservedAnalyses::all(); 311 } 312