LLVM 23.0.0git
DXILWriterPass.cpp
Go to the documentation of this file.
1//===- DXILWriterPass.cpp - Bitcode writing pass --------------------------===//
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// DXILWriterPass implementation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "DXILWriterPass.h"
14#include "DXILBitcodeWriter.h"
16#include "llvm/ADT/DenseMap.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringRef.h"
20#include "llvm/IR/Constants.h"
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/IR/LLVMContext.h"
26#include "llvm/IR/Module.h"
27#include "llvm/IR/PassManager.h"
29#include "llvm/Pass.h"
32
33using namespace llvm;
34using namespace llvm::dxil;
35
36namespace {
37class WriteDXILPass : public llvm::ModulePass {
38 raw_ostream &OS; // raw_ostream to print on
39
40public:
41 static char ID; // Pass identification, replacement for typeid
42 WriteDXILPass() : ModulePass(ID), OS(dbgs()) {
44 }
45
46 explicit WriteDXILPass(raw_ostream &o) : ModulePass(ID), OS(o) {
48 }
49
50 StringRef getPassName() const override { return "Bitcode Writer"; }
51
52 bool runOnModule(Module &M) override {
53 const auto DIMap = DXILDebugInfoPass::run(M);
54 WriteDXILToFile(M, OS, DIMap);
55 return false;
56 }
57 void getAnalysisUsage(AnalysisUsage &AU) const override {
58 AU.setPreservesAll();
59 }
60};
61
62static void legalizeLifetimeIntrinsics(Module &M) {
63 LLVMContext &Ctx = M.getContext();
64 Type *I64Ty = IntegerType::get(Ctx, 64);
65 Type *PtrTy = PointerType::get(Ctx, 0);
66 Intrinsic::ID LifetimeIIDs[2] = {Intrinsic::lifetime_start,
67 Intrinsic::lifetime_end};
68 for (Intrinsic::ID &IID : LifetimeIIDs) {
69 Function *F = M.getFunction(Intrinsic::getName(IID, {PtrTy}, &M));
70 if (!F)
71 continue;
72
73 // Get or insert an LLVM 3.7-compliant lifetime intrinsic function of the
74 // form `void @llvm.lifetime.[start/end](i64, ptr)` with the NoUnwind
75 // attribute
76 AttributeList Attr;
77 Attr = Attr.addFnAttribute(Ctx, Attribute::NoUnwind);
78 FunctionCallee LifetimeCallee = M.getOrInsertFunction(
79 Intrinsic::getBaseName(IID), Attr, Type::getVoidTy(Ctx), I64Ty, PtrTy);
80
81 // Replace all calls to lifetime intrinsics with calls to the
82 // LLVM 3.7-compliant version of the lifetime intrinsic
83 for (User *U : make_early_inc_range(F->users())) {
85 assert(CI &&
86 "Expected user of a lifetime intrinsic function to be a CallInst");
87
88 // LLVM 3.7 lifetime intrinics require an i8* operand, so we insert
89 // a bitcast to ensure that is the case
90 Value *PtrOperand = CI->getArgOperand(0);
91 PointerType *PtrOpPtrTy = cast<PointerType>(PtrOperand->getType());
92 Value *NoOpBitCast = CastInst::Create(Instruction::BitCast, PtrOperand,
93 PtrOpPtrTy, "", CI->getIterator());
94
95 // LLVM 3.7 lifetime intrinsics have an explicit size operand, whose value
96 // we can obtain from the pointer operand which must be an AllocaInst (as
97 // of https://github.com/llvm/llvm-project/pull/149310)
98 AllocaInst *AI = dyn_cast<AllocaInst>(PtrOperand);
99 assert(AI &&
100 "The pointer operand of a lifetime intrinsic call must be an "
101 "AllocaInst");
102 std::optional<TypeSize> AllocSize =
104 assert(AllocSize.has_value() &&
105 "Expected the allocation size of AllocaInst to be known");
106 CallInst *NewCI = CallInst::Create(
107 LifetimeCallee,
108 {ConstantInt::get(I64Ty, AllocSize.value().getFixedValue()),
109 NoOpBitCast},
110 "", CI->getIterator());
112 NewCI->addParamAttr(1, ParamAttr);
113
114 CI->eraseFromParent();
115 }
116
117 F->eraseFromParent();
118 }
119}
120
121static void removeLifetimeIntrinsics(Module &M) {
122 Intrinsic::ID LifetimeIIDs[2] = {Intrinsic::lifetime_start,
123 Intrinsic::lifetime_end};
124 for (Intrinsic::ID &IID : LifetimeIIDs) {
125 Function *F = M.getFunction(Intrinsic::getBaseName(IID));
126 if (!F)
127 continue;
128
129 for (User *U : make_early_inc_range(F->users())) {
131 assert(CI && "Expected user of lifetime function to be a CallInst");
133 assert(BCI && "Expected pointer operand of CallInst to be a BitCastInst");
134 CI->eraseFromParent();
135 BCI->eraseFromParent();
136 }
137 F->eraseFromParent();
138 }
139}
140
141class EmbedDXILPass : public llvm::ModulePass {
142public:
143 static char ID; // Pass identification, replacement for typeid
144 EmbedDXILPass() : ModulePass(ID) {
146 }
147
148 StringRef getPassName() const override { return "DXIL Embedder"; }
149
150 bool runOnModule(Module &M) override {
151 std::string Data;
152 llvm::raw_string_ostream OS(Data);
153
154 // Perform late legalization of lifetime intrinsics that would otherwise
155 // fail the Module Verifier if performed in an earlier pass
156 legalizeLifetimeIntrinsics(M);
157
158 const auto DIMap = DXILDebugInfoPass::run(M);
159 WriteDXILToFile(M, OS, DIMap);
160
161 // We no longer need lifetime intrinsics after bitcode serialization, so we
162 // simply remove them to keep the Module Verifier happy after our
163 // not-so-legal legalizations
164 removeLifetimeIntrinsics(M);
165
166 Constant *ModuleConstant =
168 auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,
170 ModuleConstant, "dx.dxil");
171 GV->setSection("DXIL");
172 GV->setAlignment(Align(4));
173 appendToCompilerUsed(M, {GV});
174 return true;
175 }
176
177 void getAnalysisUsage(AnalysisUsage &AU) const override {
178 AU.setPreservesAll();
179 }
180};
181} // namespace
182
183char WriteDXILPass::ID = 0;
184INITIALIZE_PASS_BEGIN(WriteDXILPass, "dxil-write-bitcode", "Write Bitcode",
185 false, true)
187INITIALIZE_PASS_END(WriteDXILPass, "dxil-write-bitcode", "Write Bitcode", false,
188 true)
189
191 return new WriteDXILPass(Str);
192}
193
194char EmbedDXILPass::ID = 0;
195INITIALIZE_PASS(EmbedDXILPass, "dxil-embed", "Embed DXIL", false, true)
196
197ModulePass *llvm::createDXILEmbedderPass() { return new EmbedDXILPass(); }
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
@ ParamAttr
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file provides a bitcode writing pass.
This file defines the DenseMap class.
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
Machine Check Debug Module
This is the interface to build a ModuleSummaryIndex for a module.
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file contains some templates that are useful if you are working with the STL at all.
an instruction to allocate memory on the stack
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
void setPreservesAll()
Set by analyses that do not transform their input at all.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
Definition Attributes.h:105
This class represents a no-op cast from one type to another.
AttributeSet getParamAttributes(unsigned ArgNo) const
Return the param attributes for this call.
Value * getArgOperand(unsigned i) const
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static LLVM_ABI CastInst * Create(Instruction::CastOps, Value *S, Type *Ty, const Twine &Name="", InsertPosition InsertBefore=nullptr)
Provides a way to construct any of the CastInst subclasses using an opcode instead of the subclass's ...
static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)
get() constructor - Return a constant with array type with an element count and element type matching...
Definition Constants.h:865
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
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.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:354
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
Legacy wrapper pass to provide the ModuleSummaryIndex object.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:286
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
self_iterator getIterator()
Definition ilist_node.h:123
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
LLVM_ABI StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
LLVM_ABI StringRef getBaseName(ID id)
Return the LLVM name for an intrinsic, without encoded types for overloading, such as "llvm....
DXILDebugInfoMap run(Module &M)
void WriteDXILToFile(const Module &M, raw_ostream &Out, const DXILDebugInfoMap &DebugInfo)
Write the specified module to the specified raw output stream.
This is an optimization pass for GlobalISel generic memory operations.
ArrayRef< CharT > arrayRefFromStringRef(StringRef Input)
Construct a string ref from an array ref of unsigned chars.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
ModulePass * createDXILWriterPass(raw_ostream &Str)
Create and return a pass that writes the module to the specified ostream.
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 raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
void initializeEmbedDXILPassPass(PassRegistry &)
Initializer for dxil embedder pass.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
ModulePass * createDXILEmbedderPass()
Create and return a pass that writes the module to a global variable in the module for later emission...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
void initializeWriteDXILPassPass(PassRegistry &)
Initializer for dxil writer pass.