Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
35271 views
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::ExtractElement:
240
// ExtractElementConstantExpr
241
return Builder.CreateExtractElement(NewOperands[0], NewOperands[1]);
242
case Instruction::InsertElement:
243
// InsertElementConstantExpr
244
return Builder.CreateInsertElement(NewOperands[0], NewOperands[1],
245
NewOperands[2]);
246
case Instruction::ShuffleVector:
247
// ShuffleVector
248
return Builder.CreateShuffleVector(NewOperands[0], NewOperands[1],
249
NewOperands[2]);
250
case Instruction::GetElementPtr:
251
// GetElementPtrConstantExpr
252
return Builder.CreateGEP(cast<GEPOperator>(C)->getSourceElementType(),
253
NewOperands[0],
254
ArrayRef(&NewOperands[1], NumOperands - 1), "",
255
cast<GEPOperator>(C)->isInBounds());
256
case Instruction::Select:
257
// SelectConstantExpr
258
return Builder.CreateSelect(NewOperands[0], NewOperands[1], NewOperands[2]);
259
default:
260
// BinaryConstantExpr
261
if (Instruction::isBinaryOp(Opcode)) {
262
return Builder.CreateBinOp(Instruction::BinaryOps(C->getOpcode()),
263
NewOperands[0], NewOperands[1]);
264
}
265
// UnaryConstantExpr
266
if (Instruction::isCast(Opcode)) {
267
return Builder.CreateCast(Instruction::CastOps(C->getOpcode()),
268
NewOperands[0], 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
305