LLVM 24.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"
22#include "NVPTXSubtarget.h"
27#include "llvm/IR/Constants.h"
29#include "llvm/IR/Function.h"
31#include "llvm/IR/Intrinsics.h"
32#include "llvm/IR/IntrinsicsNVPTX.h"
33#include "llvm/IR/Module.h"
34#include "llvm/IR/PassManager.h"
35#include "llvm/IR/Type.h"
36#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 const NVPTXOptions &CLOpts;
59 // Map from reflect function call arguments to the value to replace the call
60 // with. Should include __CUDA_FTZ and __CUDA_ARCH values.
61 StringMap<unsigned> ReflectMap;
62 bool handleReflectFunction(Module &M, StringRef ReflectName);
63 void populateReflectMap(Module &M);
64 void foldReflectCall(CallInst *Call, Constant *NewValue);
65
66public:
67 // __CUDA_FTZ is assigned in `runOnModule` by checking nvvm-reflect-ftz module
68 // metadata.
69 NVVMReflect(unsigned SmVersion, const NVPTXOptions &CLOpts)
70 : CLOpts(CLOpts), ReflectMap({{CUDA_ARCH_NAME, SmVersion * 10}}) {}
71 bool runOnModule(Module &M);
72};
73
74class NVVMReflectLegacyPass : public ModulePass {
75 unsigned SmVersion;
76
77public:
78 static char ID;
79 NVVMReflectLegacyPass(unsigned SmVersion)
80 : ModulePass(ID), SmVersion(SmVersion) {}
81 bool runOnModule(Module &M) override;
82};
83} // namespace
84
85ModulePass *llvm::createNVVMReflectPass(unsigned SmVersion) {
86 return new NVVMReflectLegacyPass(SmVersion);
87}
88
89char NVVMReflectLegacyPass::ID = 0;
90INITIALIZE_PASS(NVVMReflectLegacyPass, "nvvm-reflect",
91 "Replace occurrences of __nvvm_reflect() calls with 0/1", false,
92 false)
93
94// Set the ReflectMap with, first, the value of __CUDA_FTZ from module metadata,
95// and then the key/value pairs from the command line.
96void NVVMReflect::populateReflectMap(Module &M) {
98 M.getModuleFlag(CUDA_FTZ_MODULE_NAME)))
99 ReflectMap[CUDA_FTZ_NAME] = Flag->getSExtValue();
100
101 for (StringRef Option : CLOpts.nvvm_reflect_add) {
102 LLVM_DEBUG(dbgs() << "ReflectOption : " << Option << "\n");
103 auto [Name, Val] = Option.split('=');
104 if (Name.empty())
105 report_fatal_error("Empty name in nvvm-reflect-add option '" + Option +
106 "'");
107 if (Val.empty())
108 report_fatal_error("Missing value in nvvm-reflect-add option '" + Option +
109 "'");
110 unsigned ValInt;
111 if (!to_integer(Val.trim(), ValInt, 10))
112 report_fatal_error("integer value expected in nvvm-reflect-add option '" +
113 Option + "'");
114 ReflectMap[Name] = ValInt;
115 }
116}
117
118/// Process a reflect function by finding all its calls and replacing them with
119/// appropriate constant values. For __CUDA_FTZ, uses the module flag value.
120/// For __CUDA_ARCH, uses SmVersion * 10. For all other strings, uses 0.
121bool NVVMReflect::handleReflectFunction(Module &M, StringRef ReflectName) {
122 Function *F = M.getFunction(ReflectName);
123 if (!F)
124 return false;
125 assert(F->isDeclaration() && "_reflect function should not have a body");
126 assert(F->getReturnType()->isIntegerTy() &&
127 "_reflect's return type should be integer");
128
129 const bool Changed = !F->use_empty();
130 for (User *U : make_early_inc_range(F->users())) {
131 // Reflect function calls look like:
132 // @arch = private unnamed_addr addrspace(1) constant [12 x i8]
133 // c"__CUDA_ARCH\00" call i32 @__nvvm_reflect(ptr addrspacecast (ptr
134 // addrspace(1) @arch to ptr)) We need to extract the string argument from
135 // the call (i.e. "__CUDA_ARCH")
136 auto *Call = dyn_cast<CallInst>(U);
137 if (!Call)
139 "__nvvm_reflect can only be used in a call instruction");
140 if (Call->getNumOperands() != 2)
141 report_fatal_error("__nvvm_reflect requires exactly one argument");
142
143 auto *GlobalStr =
145 if (!GlobalStr)
146 report_fatal_error("__nvvm_reflect argument must be a constant string");
147
148 auto *ConstantStr =
150 if (!ConstantStr)
151 report_fatal_error("__nvvm_reflect argument must be a string constant");
152 if (!ConstantStr->isCString())
154 "__nvvm_reflect argument must be a null-terminated string");
155
156 StringRef ReflectArg = ConstantStr->getAsString().drop_back();
157 if (ReflectArg.empty())
158 report_fatal_error("__nvvm_reflect argument cannot be empty");
159 // Now that we have extracted the string argument, we can look it up in the
160 // ReflectMap
161 unsigned ReflectVal = 0; // The default value is 0
162 if (ReflectMap.contains(ReflectArg))
163 ReflectVal = ReflectMap[ReflectArg];
164
165 LLVM_DEBUG(dbgs() << "Replacing call of reflect function " << F->getName()
166 << "(" << ReflectArg << ") with value " << ReflectVal
167 << "\n");
168 auto *NewValue = ConstantInt::get(Call->getType(), ReflectVal);
169 foldReflectCall(Call, NewValue);
171 }
172
173 // Remove the __nvvm_reflect function from the module
174 F->eraseFromParent();
175 return Changed;
176}
177
178void NVVMReflect::foldReflectCall(CallInst *Call, Constant *NewValue) {
179 SmallVector<Instruction *, 8> Worklist;
180 // Replace an instruction with a constant and add all users of the instruction
181 // to the worklist
182 auto ReplaceInstructionWithConst = [&](Instruction *I, Constant *C) {
183 for (User *U : I->users())
184 if (auto *UI = dyn_cast<Instruction>(U))
185 Worklist.push_back(UI);
186 I->replaceAllUsesWith(C);
187 };
188
189 ReplaceInstructionWithConst(Call, NewValue);
190
191 auto &DL = Call->getDataLayout();
192 while (!Worklist.empty()) {
193 auto *I = Worklist.pop_back_val();
194 if (Constant *C = ConstantFoldInstruction(I, DL)) {
195 ReplaceInstructionWithConst(I, C);
197 I->eraseFromParent();
198 } else if (I->isTerminator()) {
199 ConstantFoldTerminator(I->getParent());
200 }
201 }
202}
203
204bool NVVMReflect::runOnModule(Module &M) {
205 if (!CLOpts.nvvm_reflect_enable)
206 return false;
207 populateReflectMap(M);
208 bool Changed = false;
209 Changed |= handleReflectFunction(M, NVVM_REFLECT_FUNCTION);
210 Changed |= handleReflectFunction(M, NVVM_REFLECT_OCL_FUNCTION);
211 Changed |=
212 handleReflectFunction(M, Intrinsic::getName(Intrinsic::nvvm_reflect));
213 return Changed;
214}
215
216bool NVVMReflectLegacyPass::runOnModule(Module &M) {
217 return NVVMReflect(SmVersion, getNVPTXOptions(M)).runOnModule(M);
218}
219
221 return NVVMReflect(SmVersion, getNVPTXOptions(M)).runOnModule(M)
224}
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
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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
#define CUDA_FTZ_MODULE_NAME
#define NVVM_REFLECT_OCL_FUNCTION
#define NVVM_REFLECT_FUNCTION
#define CUDA_ARCH_NAME
#define CUDA_FTZ_NAME
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static cl::opt< std::string > GlobalStr("spirv-lower-global-ctor-dtor-id", cl::desc("Override unique ID of ctor/dtor globals."), cl::init(""), cl::Hidden)
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:44
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:253
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
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:129
bool contains(StringRef Key) const
contains - Return true if the element is in the map, false otherwise.
Definition StringMap.h:270
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:257
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:707
CallInst * Call
LLVM_ABI StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
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:694
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:133
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:649
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:408
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
const NVPTXOptions & getNVPTXOptions(const LLVMContext &C)
ModulePass * createNVVMReflectPass(unsigned int SmVersion)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39