1 //===-- GenericToNVVM.cpp - Convert generic module to NVVM module - C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Convert generic global variables into either .global or .const access based
10 // on the variable's "constant" qualifier.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/NVPTXBaseInfo.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"
32 void initializeGenericToNVVMLegacyPassPass(PassRegistry
&);
38 bool runOnModule(Module
&M
);
41 Value
*remapConstant(Module
*M
, Function
*F
, Constant
*C
,
42 IRBuilder
<> &Builder
);
43 Value
*remapConstantVectorOrConstantAggregate(Module
*M
, Function
*F
,
45 IRBuilder
<> &Builder
);
46 Value
*remapConstantExpr(Module
*M
, Function
*F
, ConstantExpr
*C
,
47 IRBuilder
<> &Builder
);
49 typedef ValueMap
<GlobalVariable
*, GlobalVariable
*> GVMapTy
;
50 typedef ValueMap
<Constant
*, Value
*> ConstantToValueMapTy
;
52 ConstantToValueMapTy ConstantToValueMap
;
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
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);
76 // Return immediately, if every global variable has a specific address space
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()) {
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
)) {
96 i
, remapConstant(&M
, &F
, cast
<Constant
>(Operand
), Builder
));
101 ConstantToValueMap
.clear();
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
;
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
;
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
);
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
);
132 assert(GVMap
.empty() && "Expected it to be empty by now");
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()) {
147 if (isa
<GlobalVariable
>(C
)) {
148 // If the constant C is a global variable and is found in GVMap, substitute
150 // addrspacecast GVMap[C] to addrspace(0)
153 GVMapTy::iterator I
= GVMap
.find(cast
<GlobalVariable
>(C
));
154 if (I
!= GVMap
.end()) {
155 GlobalVariable
*GV
= I
->second
;
156 NewValue
= Builder
.CreateAddrSpaceCast(
158 PointerType::get(GV
->getValueType(), llvm::ADDRESS_SPACE_GENERIC
));
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
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
);
172 ConstantToValueMap
[C
] = NewValue
;
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();
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
);
191 // If none of the elements has been modified, return C as it is.
192 if (!OperandChanged
) {
196 // If any of the elements has been modified, construct the equivalent
197 // vector or aggregate value with a set instructions and the converted
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
);
206 for (unsigned i
= 0; i
< NumOperands
; ++i
) {
208 Builder
.CreateInsertValue(NewValue
, NewOperands
[i
], ArrayRef(i
));
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();
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
);
230 // If none of the operands has been modified, return C as it is.
231 if (!OperandChanged
) {
235 // If any of the operands has been modified, construct the instruction with
236 // the converted operands.
237 unsigned Opcode
= C
->getOpcode();
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],
246 case Instruction::ShuffleVector
:
248 return Builder
.CreateShuffleVector(NewOperands
[0], NewOperands
[1],
250 case Instruction::GetElementPtr
:
251 // GetElementPtrConstantExpr
252 return Builder
.CreateGEP(cast
<GEPOperator
>(C
)->getSourceElementType(),
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]);
260 // BinaryConstantExpr
261 if (Instruction::isBinaryOp(Opcode
)) {
262 return Builder
.CreateBinOp(Instruction::BinaryOps(C
->getOpcode()),
263 NewOperands
[0], NewOperands
[1]);
266 if (Instruction::isCast(Opcode
)) {
267 return Builder
.CreateCast(Instruction::CastOps(C
->getOpcode()),
268 NewOperands
[0], C
->getType());
270 llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr");
275 class GenericToNVVMLegacyPass
: public ModulePass
{
279 GenericToNVVMLegacyPass() : ModulePass(ID
) {}
281 bool runOnModule(Module
&M
) override
;
285 char GenericToNVVMLegacyPass::ID
= 0;
287 ModulePass
*llvm::createGenericToNVVMLegacyPass() {
288 return new GenericToNVVMLegacyPass();
292 GenericToNVVMLegacyPass
, "generic-to-nvvm",
293 "Ensure that the global variables are in the global address space", false,
296 bool GenericToNVVMLegacyPass::runOnModule(Module
&M
) {
297 return GenericToNVVM().runOnModule(M
);
300 PreservedAnalyses
GenericToNVVMPass::run(Module
&M
, ModuleAnalysisManager
&AM
) {
301 return GenericToNVVM().runOnModule(M
) ? PreservedAnalyses::none()
302 : PreservedAnalyses::all();