LLVM 23.0.0git
NVVMReflect.cpp
Go to the documentation of this file.
1//===- NVVMReflect.cpp - NVVM Emulate conditional compilation -------------===//
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// This pass replaces occurrences of __nvvm_reflect("foo") and llvm.nvvm.reflect
10// with an integer.
11//
12// We choose the value we use by looking at metadata in the module itself. Note
13// that we intentionally only have one way to choose these values, because other
14// parts of LLVM (particularly, InstCombineCall) rely on being able to predict
15// the values chosen by this pass.
16//
17// If we see an unknown string, we replace its call with 0.
18//
19//===----------------------------------------------------------------------===//
20
21#include "NVPTX.h"
26#include "llvm/IR/Constants.h"
28#include "llvm/IR/Function.h"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/IR/IntrinsicsNVPTX.h"
32#include "llvm/IR/Module.h"
33#include "llvm/IR/PassManager.h"
34#include "llvm/IR/Type.h"
35#include "llvm/Pass.h"
37#include "llvm/Support/Debug.h"
42
43using namespace llvm;
44
45#define DEBUG_TYPE "nvvm-reflect"
46
47#define NVVM_REFLECT_FUNCTION "__nvvm_reflect"
48#define NVVM_REFLECT_OCL_FUNCTION "__nvvm_reflect_ocl"
49// Argument of reflect call to retrive arch number.
50#define CUDA_ARCH_NAME "__CUDA_ARCH"
51// Argument of reflect call to retrive ftz mode.
52#define CUDA_FTZ_NAME "__CUDA_FTZ"
53// Name of module metadata where ftz mode is stored.
54#define CUDA_FTZ_MODULE_NAME "nvvm-reflect-ftz"
55
56namespace {
57class NVVMReflect {
58 // Map from reflect function call arguments to the value to replace the call
59 // with. Should include __CUDA_FTZ and __CUDA_ARCH values.
60 StringMap<unsigned> ReflectMap;
61 bool handleReflectFunction(Module &M, StringRef ReflectName);
62 void populateReflectMap(Module &M);
63 void foldReflectCall(CallInst *Call, Constant *NewValue);
64
65public:
66 // __CUDA_FTZ is assigned in `runOnModule` by checking nvvm-reflect-ftz module
67 // metadata.
68 explicit NVVMReflect(unsigned SmVersion)
69 : ReflectMap({{CUDA_ARCH_NAME, SmVersion * 10}}) {}
70 bool runOnModule(Module &M);
71};
72
73class NVVMReflectLegacyPass : public ModulePass {
74 NVVMReflect Impl;
75
76public:
77 static char ID;
78 NVVMReflectLegacyPass(unsigned SmVersion) : ModulePass(ID), Impl(SmVersion) {}
79 bool runOnModule(Module &M) override;
80};
81} // namespace
82
83ModulePass *llvm::createNVVMReflectPass(unsigned SmVersion) {
84 return new NVVMReflectLegacyPass(SmVersion);
85}
86
87static cl::opt<bool>
88 NVVMReflectEnabled("nvvm-reflect-enable", cl::init(true), cl::Hidden,
89 cl::desc("NVVM reflection, enabled by default"));
90
91char NVVMReflectLegacyPass::ID = 0;
92INITIALIZE_PASS(NVVMReflectLegacyPass, "nvvm-reflect",
93 "Replace occurrences of __nvvm_reflect() calls with 0/1", false,
94 false)
95
96// Allow users to specify additional key/value pairs to reflect. These key/value
97// pairs are the last to be added to the ReflectMap, and therefore will take
98// precedence over initial values (i.e. __CUDA_FTZ from module medadata and
99// __CUDA_ARCH from SmVersion).
100static cl::list<std::string> ReflectList(
101 "nvvm-reflect-add", cl::value_desc("name=<int>"), cl::Hidden,
102 cl::desc("A key=value pair. Replace __nvvm_reflect(name) with value."),
103 cl::ValueRequired);
104
105// Set the ReflectMap with, first, the value of __CUDA_FTZ from module metadata,
106// and then the key/value pairs from the command line.
107void NVVMReflect::populateReflectMap(Module &M) {
109 M.getModuleFlag(CUDA_FTZ_MODULE_NAME)))
110 ReflectMap[CUDA_FTZ_NAME] = Flag->getSExtValue();
111
112 for (StringRef Option : ReflectList) {
113 LLVM_DEBUG(dbgs() << "ReflectOption : " << Option << "\n");
114 auto [Name, Val] = Option.split('=');
115 if (Name.empty())
116 report_fatal_error("Empty name in nvvm-reflect-add option '" + Option +
117 "'");
118 if (Val.empty())
119 report_fatal_error("Missing value in nvvm-reflect-add option '" + Option +
120 "'");
121 unsigned ValInt;
122 if (!to_integer(Val.trim(), ValInt, 10))
123 report_fatal_error("integer value expected in nvvm-reflect-add option '" +
124 Option + "'");
125 ReflectMap[Name] = ValInt;
126 }
127}
128
129/// Process a reflect function by finding all its calls and replacing them with
130/// appropriate constant values. For __CUDA_FTZ, uses the module flag value.
131/// For __CUDA_ARCH, uses SmVersion * 10. For all other strings, uses 0.
132bool NVVMReflect::handleReflectFunction(Module &M, StringRef ReflectName) {
133 Function *F = M.getFunction(ReflectName);
134 if (!F)
135 return false;
136 assert(F->isDeclaration() && "_reflect function should not have a body");
137 assert(F->getReturnType()->isIntegerTy() &&
138 "_reflect's return type should be integer");
139
140 const bool Changed = !F->use_empty();
141 for (User *U : make_early_inc_range(F->users())) {
142 // Reflect function calls look like:
143 // @arch = private unnamed_addr addrspace(1) constant [12 x i8]
144 // c"__CUDA_ARCH\00" call i32 @__nvvm_reflect(ptr addrspacecast (ptr
145 // addrspace(1) @arch to ptr)) We need to extract the string argument from
146 // the call (i.e. "__CUDA_ARCH")
147 auto *Call = dyn_cast<CallInst>(U);
148 if (!Call)
150 "__nvvm_reflect can only be used in a call instruction");
151 if (Call->getNumOperands() != 2)
152 report_fatal_error("__nvvm_reflect requires exactly one argument");
153
154 auto *GlobalStr =
156 if (!GlobalStr)
157 report_fatal_error("__nvvm_reflect argument must be a constant string");
158
159 auto *ConstantStr =
161 if (!ConstantStr)
162 report_fatal_error("__nvvm_reflect argument must be a string constant");
163 if (!ConstantStr->isCString())
165 "__nvvm_reflect argument must be a null-terminated string");
166
167 StringRef ReflectArg = ConstantStr->getAsString().drop_back();
168 if (ReflectArg.empty())
169 report_fatal_error("__nvvm_reflect argument cannot be empty");
170 // Now that we have extracted the string argument, we can look it up in the
171 // ReflectMap
172 unsigned ReflectVal = 0; // The default value is 0
173 if (ReflectMap.contains(ReflectArg))
174 ReflectVal = ReflectMap[ReflectArg];
175
176 LLVM_DEBUG(dbgs() << "Replacing call of reflect function " << F->getName()
177 << "(" << ReflectArg << ") with value " << ReflectVal
178 << "\n");
179 auto *NewValue = ConstantInt::get(Call->getType(), ReflectVal);
180 foldReflectCall(Call, NewValue);
182 }
183
184 // Remove the __nvvm_reflect function from the module
185 F->eraseFromParent();
186 return Changed;
187}
188
189void NVVMReflect::foldReflectCall(CallInst *Call, Constant *NewValue) {
190 SmallVector<Instruction *, 8> Worklist;
191 // Replace an instruction with a constant and add all users of the instruction
192 // to the worklist
193 auto ReplaceInstructionWithConst = [&](Instruction *I, Constant *C) {
194 for (User *U : I->users())
195 if (auto *UI = dyn_cast<Instruction>(U))
196 Worklist.push_back(UI);
197 I->replaceAllUsesWith(C);
198 };
199
200 ReplaceInstructionWithConst(Call, NewValue);
201
202 auto &DL = Call->getModule()->getDataLayout();
203 while (!Worklist.empty()) {
204 auto *I = Worklist.pop_back_val();
205 if (Constant *C = ConstantFoldInstruction(I, DL)) {
206 ReplaceInstructionWithConst(I, C);
208 I->eraseFromParent();
209 } else if (I->isTerminator()) {
210 ConstantFoldTerminator(I->getParent());
211 }
212 }
213}
214
215bool NVVMReflect::runOnModule(Module &M) {
217 return false;
218 populateReflectMap(M);
219 bool Changed = true;
220 Changed |= handleReflectFunction(M, NVVM_REFLECT_FUNCTION);
221 Changed |= handleReflectFunction(M, NVVM_REFLECT_OCL_FUNCTION);
222 Changed |=
223 handleReflectFunction(M, Intrinsic::getName(Intrinsic::nvvm_reflect));
224 return Changed;
225}
226
227bool NVVMReflectLegacyPass::runOnModule(Module &M) {
228 return Impl.runOnModule(M);
229}
230
232 return NVVMReflect(SmVersion).runOnModule(M) ? PreservedAnalyses::none()
234}
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
static cl::opt< std::string > GlobalStr("nvptx-lower-global-ctor-dtor-id", cl::desc("Override unique ID of ctor/dtor globals."), cl::init(""), cl::Hidden)
#define CUDA_FTZ_MODULE_NAME
#define NVVM_REFLECT_OCL_FUNCTION
#define NVVM_REFLECT_FUNCTION
static cl::opt< bool > NVVMReflectEnabled("nvvm-reflect-enable", cl::init(true), cl::Hidden, cl::desc("NVVM reflection, enabled by default"))
#define CUDA_ARCH_NAME
#define CUDA_FTZ_NAME
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Value * getArgOperand(unsigned i) const
This class represents a function call, abstracting a target machine's calling convention.
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
Definition Module.h:320
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
void push_back(const T &Elt)
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:128
bool contains(StringRef Key) const
contains - Return true if the element is in the map, false otherwise.
Definition StringMap.h:269
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
unsigned getNumOperands() const
Definition User.h:229
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:713
CallInst * Call
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
This namespace contains all of the command line option processing machinery.
Definition MCSchedule.h:35
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract_or_null(Y &&MD)
Extract a Value from Metadata, allowing null.
Definition Metadata.h:683
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions=false, const TargetLibraryInfo *TLI=nullptr, DomTreeUpdater *DTU=nullptr)
If a terminator instruction is predicated on a constant value, convert it into an unconditional branc...
Definition Local.cpp:134
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI Constant * ConstantFoldInstruction(const Instruction *I, const DataLayout &DL, const TargetLibraryInfo *TLI=nullptr)
ConstantFoldInstruction - Try to constant fold the specified instruction.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
LLVM_ABI bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction is not used, and the instruction will return.
Definition Local.cpp:403
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
ModulePass * createNVVMReflectPass(unsigned int SmVersion)
bool to_integer(StringRef S, N &Num, unsigned Base=0)
Convert the string S to an integer of the specified type using the radix Base. If Base is 0,...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:860
PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM)