LLVM 22.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"
15#include "llvm/ADT/DenseMap.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/StringRef.h"
19#include "llvm/IR/Constants.h"
23#include "llvm/IR/Intrinsics.h"
24#include "llvm/IR/LLVMContext.h"
25#include "llvm/IR/Module.h"
26#include "llvm/IR/PassManager.h"
28#include "llvm/Pass.h"
31
32using namespace llvm;
33using namespace llvm::dxil;
34
35namespace {
36class WriteDXILPass : public llvm::ModulePass {
37 raw_ostream &OS; // raw_ostream to print on
38
39public:
40 static char ID; // Pass identification, replacement for typeid
41 WriteDXILPass() : ModulePass(ID), OS(dbgs()) {
43 }
44
45 explicit WriteDXILPass(raw_ostream &o) : ModulePass(ID), OS(o) {
47 }
48
49 StringRef getPassName() const override { return "Bitcode Writer"; }
50
51 bool runOnModule(Module &M) override {
52 WriteDXILToFile(M, OS);
53 return false;
54 }
55 void getAnalysisUsage(AnalysisUsage &AU) const override {
56 AU.setPreservesAll();
57 }
58};
59
60static void legalizeLifetimeIntrinsics(Module &M) {
61 LLVMContext &Ctx = M.getContext();
62 Type *I64Ty = IntegerType::get(Ctx, 64);
63 Type *PtrTy = PointerType::get(Ctx, 0);
64 Intrinsic::ID LifetimeIIDs[2] = {Intrinsic::lifetime_start,
65 Intrinsic::lifetime_end};
66 for (Intrinsic::ID &IID : LifetimeIIDs) {
67 Function *F = M.getFunction(Intrinsic::getName(IID, {PtrTy}, &M));
68 if (!F)
69 continue;
70
71 // Get or insert an LLVM 3.7-compliant lifetime intrinsic function of the
72 // form `void @llvm.lifetime.[start/end](i64, ptr)` with the NoUnwind
73 // attribute
74 AttributeList Attr;
75 Attr = Attr.addFnAttribute(Ctx, Attribute::NoUnwind);
76 FunctionCallee LifetimeCallee = M.getOrInsertFunction(
77 Intrinsic::getBaseName(IID), Attr, Type::getVoidTy(Ctx), I64Ty, PtrTy);
78
79 // Replace all calls to lifetime intrinsics with calls to the
80 // LLVM 3.7-compliant version of the lifetime intrinsic
81 for (User *U : make_early_inc_range(F->users())) {
83 assert(CI &&
84 "Expected user of a lifetime intrinsic function to be a CallInst");
85
86 // LLVM 3.7 lifetime intrinics require an i8* operand, so we insert
87 // a bitcast to ensure that is the case
88 Value *PtrOperand = CI->getArgOperand(0);
89 PointerType *PtrOpPtrTy = cast<PointerType>(PtrOperand->getType());
90 Value *NoOpBitCast = CastInst::Create(Instruction::BitCast, PtrOperand,
91 PtrOpPtrTy, "", CI->getIterator());
92
93 // LLVM 3.7 lifetime intrinsics have an explicit size operand, whose value
94 // we can obtain from the pointer operand which must be an AllocaInst (as
95 // of https://github.com/llvm/llvm-project/pull/149310)
96 AllocaInst *AI = dyn_cast<AllocaInst>(PtrOperand);
97 assert(AI &&
98 "The pointer operand of a lifetime intrinsic call must be an "
99 "AllocaInst");
100 std::optional<TypeSize> AllocSize =
102 assert(AllocSize.has_value() &&
103 "Expected the allocation size of AllocaInst to be known");
104 CallInst *NewCI = CallInst::Create(
105 LifetimeCallee,
106 {ConstantInt::get(I64Ty, AllocSize.value().getFixedValue()),
107 NoOpBitCast},
108 "", CI->getIterator());
110 NewCI->addParamAttr(1, ParamAttr);
111
112 CI->eraseFromParent();
113 }
114
115 F->eraseFromParent();
116 }
117}
118
119static void removeLifetimeIntrinsics(Module &M) {
120 Intrinsic::ID LifetimeIIDs[2] = {Intrinsic::lifetime_start,
121 Intrinsic::lifetime_end};
122 for (Intrinsic::ID &IID : LifetimeIIDs) {
123 Function *F = M.getFunction(Intrinsic::getBaseName(IID));
124 if (!F)
125 continue;
126
127 for (User *U : make_early_inc_range(F->users())) {
129 assert(CI && "Expected user of lifetime function to be a CallInst");
131 assert(BCI && "Expected pointer operand of CallInst to be a BitCastInst");
132 CI->eraseFromParent();
133 BCI->eraseFromParent();
134 }
135 F->eraseFromParent();
136 }
137}
138
139class EmbedDXILPass : public llvm::ModulePass {
140public:
141 static char ID; // Pass identification, replacement for typeid
142 EmbedDXILPass() : ModulePass(ID) {
144 }
145
146 StringRef getPassName() const override { return "DXIL Embedder"; }
147
148 bool runOnModule(Module &M) override {
149 std::string Data;
150 llvm::raw_string_ostream OS(Data);
151
152 Triple OriginalTriple = M.getTargetTriple();
153 // Set to DXIL triple when write to bitcode.
154 // Only the output bitcode need to be DXIL triple.
155 M.setTargetTriple(Triple("dxil-ms-dx"));
156
157 // Perform late legalization of lifetime intrinsics that would otherwise
158 // fail the Module Verifier if performed in an earlier pass
159 legalizeLifetimeIntrinsics(M);
160
161 WriteDXILToFile(M, OS);
162
163 // We no longer need lifetime intrinsics after bitcode serialization, so we
164 // simply remove them to keep the Module Verifier happy after our
165 // not-so-legal legalizations
166 removeLifetimeIntrinsics(M);
167
168 // Recover triple.
169 M.setTargetTriple(OriginalTriple);
170
171 Constant *ModuleConstant =
173 auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,
175 ModuleConstant, "dx.dxil");
176 GV->setSection("DXIL");
177 GV->setAlignment(Align(4));
178 appendToCompilerUsed(M, {GV});
179 return true;
180 }
181
182 void getAnalysisUsage(AnalysisUsage &AU) const override {
183 AU.setPreservesAll();
184 }
185};
186} // namespace
187
188char WriteDXILPass::ID = 0;
189INITIALIZE_PASS_BEGIN(WriteDXILPass, "dxil-write-bitcode", "Write Bitcode",
190 false, true)
192INITIALIZE_PASS_END(WriteDXILPass, "dxil-write-bitcode", "Write Bitcode", false,
193 true)
194
196 return new WriteDXILPass(Str);
197}
198
199char EmbedDXILPass::ID = 0;
200INITIALIZE_PASS(EmbedDXILPass, "dxil-embed", "Embed DXIL", false, true)
201
202ModulePass *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:55
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:69
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:715
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:319
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:45
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:281
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
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....
void WriteDXILToFile(const Module &M, raw_ostream &Out)
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:649
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:634
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
void initializeEmbedDXILPassPass(PassRegistry &)
Initializer for dxil embedder pass.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
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:565
void initializeWriteDXILPassPass(PassRegistry &)
Initializer for dxil writer pass.