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(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(Prefix: "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(Src: &GV); |
71 | NewGV->copyMetadata(Src: &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>(Val: Operand)) { |
95 | II.setOperand( |
96 | i, Val: remapConstant(M: &M, F: &F, C: cast<Constant>(Val: 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(x: I); |
120 | GVMap.erase(I); |
121 | I = Next; |
122 | |
123 | Constant *BitCastNewGV = ConstantExpr::getPointerCast(C: NewGV, Ty: 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(V: 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(Val: C); |
142 | if (CTII != ConstantToValueMap.end()) { |
143 | return CTII->second; |
144 | } |
145 | |
146 | Value *NewValue = C; |
147 | if (isa<GlobalVariable>(Val: 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(Val: cast<GlobalVariable>(Val: C)); |
154 | if (I != GVMap.end()) { |
155 | GlobalVariable *GV = I->second; |
156 | NewValue = Builder.CreateAddrSpaceCast( |
157 | V: GV, |
158 | DestTy: PointerType::get(ElementType: GV->getValueType(), AddressSpace: llvm::ADDRESS_SPACE_GENERIC)); |
159 | } |
160 | } else if (isa<ConstantAggregate>(Val: 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>(Val: 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, C: cast<ConstantExpr>(Val: 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, C: cast<Constant>(Val: Operand), Builder); |
187 | OperandChanged |= Operand != NewOperand; |
188 | NewOperands.push_back(Elt: 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(T: C->getType()); |
200 | if (isa<ConstantVector>(Val: C)) { |
201 | for (unsigned i = 0; i < NumOperands; ++i) { |
202 | Value *Idx = ConstantInt::get(Ty: Type::getInt32Ty(C&: M->getContext()), V: i); |
203 | NewValue = Builder.CreateInsertElement(Vec: NewValue, NewElt: NewOperands[i], Idx); |
204 | } |
205 | } else { |
206 | for (unsigned i = 0; i < NumOperands; ++i) { |
207 | NewValue = |
208 | Builder.CreateInsertValue(Agg: NewValue, Val: NewOperands[i], Idxs: 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_nocapture: i); |
225 | Value *NewOperand = remapConstant(M, F, C: cast<Constant>(Val: Operand), Builder); |
226 | OperandChanged |= Operand != NewOperand; |
227 | NewOperands.push_back(Elt: 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::ExtractElement: |
240 | // ExtractElementConstantExpr |
241 | return Builder.CreateExtractElement(Vec: NewOperands[0], Idx: NewOperands[1]); |
242 | case Instruction::InsertElement: |
243 | // InsertElementConstantExpr |
244 | return Builder.CreateInsertElement(Vec: NewOperands[0], NewElt: NewOperands[1], |
245 | Idx: NewOperands[2]); |
246 | case Instruction::ShuffleVector: |
247 | // ShuffleVector |
248 | return Builder.CreateShuffleVector(V1: NewOperands[0], V2: NewOperands[1], |
249 | Mask: NewOperands[2]); |
250 | case Instruction::GetElementPtr: |
251 | // GetElementPtrConstantExpr |
252 | return Builder.CreateGEP(Ty: cast<GEPOperator>(Val: C)->getSourceElementType(), |
253 | Ptr: NewOperands[0], |
254 | IdxList: ArrayRef(&NewOperands[1], NumOperands - 1), Name: "" , |
255 | NW: cast<GEPOperator>(Val: C)->isInBounds()); |
256 | case Instruction::Select: |
257 | // SelectConstantExpr |
258 | return Builder.CreateSelect(C: NewOperands[0], True: NewOperands[1], False: NewOperands[2]); |
259 | default: |
260 | // BinaryConstantExpr |
261 | if (Instruction::isBinaryOp(Opcode)) { |
262 | return Builder.CreateBinOp(Opc: Instruction::BinaryOps(C->getOpcode()), |
263 | LHS: NewOperands[0], RHS: NewOperands[1]); |
264 | } |
265 | // UnaryConstantExpr |
266 | if (Instruction::isCast(Opcode)) { |
267 | return Builder.CreateCast(Op: Instruction::CastOps(C->getOpcode()), |
268 | V: NewOperands[0], DestTy: C->getType()); |
269 | } |
270 | llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr" ); |
271 | } |
272 | } |
273 | |
274 | namespace { |
275 | class GenericToNVVMLegacyPass : public ModulePass { |
276 | public: |
277 | static char ID; |
278 | |
279 | GenericToNVVMLegacyPass() : ModulePass(ID) {} |
280 | |
281 | bool runOnModule(Module &M) override; |
282 | }; |
283 | } // namespace |
284 | |
285 | char GenericToNVVMLegacyPass::ID = 0; |
286 | |
287 | ModulePass *llvm::createGenericToNVVMLegacyPass() { |
288 | return new GenericToNVVMLegacyPass(); |
289 | } |
290 | |
291 | INITIALIZE_PASS( |
292 | GenericToNVVMLegacyPass, "generic-to-nvvm" , |
293 | "Ensure that the global variables are in the global address space" , false, |
294 | false) |
295 | |
296 | bool GenericToNVVMLegacyPass::runOnModule(Module &M) { |
297 | return GenericToNVVM().runOnModule(M); |
298 | } |
299 | |
300 | PreservedAnalyses GenericToNVVMPass::run(Module &M, ModuleAnalysisManager &AM) { |
301 | return GenericToNVVM().runOnModule(M) ? PreservedAnalyses::none() |
302 | : PreservedAnalyses::all(); |
303 | } |
304 | |