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 initializeGenericToNVVMPass(PassRegistry
&);
36 class GenericToNVVM
: public ModulePass
{
40 GenericToNVVM() : ModulePass(ID
) {}
42 bool runOnModule(Module
&M
) override
;
44 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{}
47 Value
*remapConstant(Module
*M
, Function
*F
, Constant
*C
,
48 IRBuilder
<> &Builder
);
49 Value
*remapConstantVectorOrConstantAggregate(Module
*M
, Function
*F
,
51 IRBuilder
<> &Builder
);
52 Value
*remapConstantExpr(Module
*M
, Function
*F
, ConstantExpr
*C
,
53 IRBuilder
<> &Builder
);
55 typedef ValueMap
<GlobalVariable
*, GlobalVariable
*> GVMapTy
;
56 typedef ValueMap
<Constant
*, Value
*> ConstantToValueMapTy
;
58 ConstantToValueMapTy ConstantToValueMap
;
62 char GenericToNVVM::ID
= 0;
64 ModulePass
*llvm::createGenericToNVVMPass() { return new GenericToNVVM(); }
67 GenericToNVVM
, "generic-to-nvvm",
68 "Ensure that the global variables are in the global address space", false,
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
77 for (Module::global_iterator I
= M
.global_begin(), E
= M
.global_end();
79 GlobalVariable
*GV
= &*I
++;
80 if (GV
->getType()->getAddressSpace() == llvm::ADDRESS_SPACE_GENERIC
&&
81 !llvm::isTexture(*GV
) && !llvm::isSurface(*GV
) &&
82 !llvm::isSampler(*GV
) && !GV
->getName().startswith("llvm.")) {
83 GlobalVariable
*NewGV
= new GlobalVariable(
84 M
, GV
->getValueType(), GV
->isConstant(),
86 GV
->hasInitializer() ? GV
->getInitializer() : nullptr,
87 "", GV
, GV
->getThreadLocalMode(), llvm::ADDRESS_SPACE_GLOBAL
);
88 NewGV
->copyAttributesFrom(GV
);
93 // Return immediately, if every global variable has a specific address space
99 // Walk through the instructions in function defitinions, and replace any use
100 // of original global variables in GVMap with a use of the corresponding
101 // copies in GVMap. If necessary, promote constants to instructions.
102 for (Module::iterator I
= M
.begin(), E
= M
.end(); I
!= E
; ++I
) {
103 if (I
->isDeclaration()) {
106 IRBuilder
<> Builder(I
->getEntryBlock().getFirstNonPHIOrDbg());
107 for (Function::iterator BBI
= I
->begin(), BBE
= I
->end(); BBI
!= BBE
;
109 for (BasicBlock::iterator II
= BBI
->begin(), IE
= BBI
->end(); II
!= IE
;
111 for (unsigned i
= 0, e
= II
->getNumOperands(); i
< e
; ++i
) {
112 Value
*Operand
= II
->getOperand(i
);
113 if (isa
<Constant
>(Operand
)) {
115 i
, remapConstant(&M
, &*I
, cast
<Constant
>(Operand
), Builder
));
120 ConstantToValueMap
.clear();
123 // Copy GVMap over to a standard value map.
124 ValueToValueMapTy VM
;
125 for (auto I
= GVMap
.begin(), E
= GVMap
.end(); I
!= E
; ++I
)
126 VM
[I
->first
] = I
->second
;
128 // Walk through the global variable initializers, and replace any use of
129 // original global variables in GVMap with a use of the corresponding copies
130 // in GVMap. The copies need to be bitcast to the original global variable
131 // types, as we cannot use cvta in global variable initializers.
132 for (GVMapTy::iterator I
= GVMap
.begin(), E
= GVMap
.end(); I
!= E
;) {
133 GlobalVariable
*GV
= I
->first
;
134 GlobalVariable
*NewGV
= I
->second
;
136 // Remove GV from the map so that it can be RAUWed. Note that
137 // DenseMap::erase() won't invalidate any iterators but this one.
138 auto Next
= std::next(I
);
142 Constant
*BitCastNewGV
= ConstantExpr::getPointerCast(NewGV
, GV
->getType());
143 // At this point, the remaining uses of GV should be found only in global
144 // variable initializers, as other uses have been already been removed
145 // while walking through the instructions in function definitions.
146 GV
->replaceAllUsesWith(BitCastNewGV
);
147 std::string Name
= GV
->getName();
148 GV
->eraseFromParent();
149 NewGV
->setName(Name
);
151 assert(GVMap
.empty() && "Expected it to be empty by now");
156 Value
*GenericToNVVM::remapConstant(Module
*M
, Function
*F
, Constant
*C
,
157 IRBuilder
<> &Builder
) {
158 // If the constant C has been converted already in the given function F, just
159 // return the converted value.
160 ConstantToValueMapTy::iterator CTII
= ConstantToValueMap
.find(C
);
161 if (CTII
!= ConstantToValueMap
.end()) {
166 if (isa
<GlobalVariable
>(C
)) {
167 // If the constant C is a global variable and is found in GVMap, substitute
169 // addrspacecast GVMap[C] to addrspace(0)
172 GVMapTy::iterator I
= GVMap
.find(cast
<GlobalVariable
>(C
));
173 if (I
!= GVMap
.end()) {
174 GlobalVariable
*GV
= I
->second
;
175 NewValue
= Builder
.CreateAddrSpaceCast(
177 PointerType::get(GV
->getValueType(), llvm::ADDRESS_SPACE_GENERIC
));
179 } else if (isa
<ConstantAggregate
>(C
)) {
180 // If any element in the constant vector or aggregate C is or uses a global
181 // variable in GVMap, the constant C needs to be reconstructed, using a set
183 NewValue
= remapConstantVectorOrConstantAggregate(M
, F
, C
, Builder
);
184 } else if (isa
<ConstantExpr
>(C
)) {
185 // If any operand in the constant expression C is or uses a global variable
186 // in GVMap, the constant expression C needs to be reconstructed, using a
187 // set of instructions.
188 NewValue
= remapConstantExpr(M
, F
, cast
<ConstantExpr
>(C
), Builder
);
191 ConstantToValueMap
[C
] = NewValue
;
195 Value
*GenericToNVVM::remapConstantVectorOrConstantAggregate(
196 Module
*M
, Function
*F
, Constant
*C
, IRBuilder
<> &Builder
) {
197 bool OperandChanged
= false;
198 SmallVector
<Value
*, 4> NewOperands
;
199 unsigned NumOperands
= C
->getNumOperands();
201 // Check if any element is or uses a global variable in GVMap, and thus
202 // converted to another value.
203 for (unsigned i
= 0; i
< NumOperands
; ++i
) {
204 Value
*Operand
= C
->getOperand(i
);
205 Value
*NewOperand
= remapConstant(M
, F
, cast
<Constant
>(Operand
), Builder
);
206 OperandChanged
|= Operand
!= NewOperand
;
207 NewOperands
.push_back(NewOperand
);
210 // If none of the elements has been modified, return C as it is.
211 if (!OperandChanged
) {
215 // If any of the elements has been modified, construct the equivalent
216 // vector or aggregate value with a set instructions and the converted
218 Value
*NewValue
= UndefValue::get(C
->getType());
219 if (isa
<ConstantVector
>(C
)) {
220 for (unsigned i
= 0; i
< NumOperands
; ++i
) {
221 Value
*Idx
= ConstantInt::get(Type::getInt32Ty(M
->getContext()), i
);
222 NewValue
= Builder
.CreateInsertElement(NewValue
, NewOperands
[i
], Idx
);
225 for (unsigned i
= 0; i
< NumOperands
; ++i
) {
227 Builder
.CreateInsertValue(NewValue
, NewOperands
[i
], makeArrayRef(i
));
234 Value
*GenericToNVVM::remapConstantExpr(Module
*M
, Function
*F
, ConstantExpr
*C
,
235 IRBuilder
<> &Builder
) {
236 bool OperandChanged
= false;
237 SmallVector
<Value
*, 4> NewOperands
;
238 unsigned NumOperands
= C
->getNumOperands();
240 // Check if any operand is or uses a global variable in GVMap, and thus
241 // converted to another value.
242 for (unsigned i
= 0; i
< NumOperands
; ++i
) {
243 Value
*Operand
= C
->getOperand(i
);
244 Value
*NewOperand
= remapConstant(M
, F
, cast
<Constant
>(Operand
), Builder
);
245 OperandChanged
|= Operand
!= NewOperand
;
246 NewOperands
.push_back(NewOperand
);
249 // If none of the operands has been modified, return C as it is.
250 if (!OperandChanged
) {
254 // If any of the operands has been modified, construct the instruction with
255 // the converted operands.
256 unsigned Opcode
= C
->getOpcode();
258 case Instruction::ICmp
:
259 // CompareConstantExpr (icmp)
260 return Builder
.CreateICmp(CmpInst::Predicate(C
->getPredicate()),
261 NewOperands
[0], NewOperands
[1]);
262 case Instruction::FCmp
:
263 // CompareConstantExpr (fcmp)
264 llvm_unreachable("Address space conversion should have no effect "
265 "on float point CompareConstantExpr (fcmp)!");
266 case Instruction::ExtractElement
:
267 // ExtractElementConstantExpr
268 return Builder
.CreateExtractElement(NewOperands
[0], NewOperands
[1]);
269 case Instruction::InsertElement
:
270 // InsertElementConstantExpr
271 return Builder
.CreateInsertElement(NewOperands
[0], NewOperands
[1],
273 case Instruction::ShuffleVector
:
275 return Builder
.CreateShuffleVector(NewOperands
[0], NewOperands
[1],
277 case Instruction::ExtractValue
:
278 // ExtractValueConstantExpr
279 return Builder
.CreateExtractValue(NewOperands
[0], C
->getIndices());
280 case Instruction::InsertValue
:
281 // InsertValueConstantExpr
282 return Builder
.CreateInsertValue(NewOperands
[0], NewOperands
[1],
284 case Instruction::GetElementPtr
:
285 // GetElementPtrConstantExpr
286 return cast
<GEPOperator
>(C
)->isInBounds()
288 cast
<GEPOperator
>(C
)->getSourceElementType(),
290 makeArrayRef(&NewOperands
[1], NumOperands
- 1))
291 : Builder
.CreateInBoundsGEP(
292 cast
<GEPOperator
>(C
)->getSourceElementType(),
294 makeArrayRef(&NewOperands
[1], NumOperands
- 1));
295 case Instruction::Select
:
296 // SelectConstantExpr
297 return Builder
.CreateSelect(NewOperands
[0], NewOperands
[1], NewOperands
[2]);
299 // BinaryConstantExpr
300 if (Instruction::isBinaryOp(Opcode
)) {
301 return Builder
.CreateBinOp(Instruction::BinaryOps(C
->getOpcode()),
302 NewOperands
[0], NewOperands
[1]);
305 if (Instruction::isCast(Opcode
)) {
306 return Builder
.CreateCast(Instruction::CastOps(C
->getOpcode()),
307 NewOperands
[0], C
->getType());
309 llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr");