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