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())) {
82 CallInst *CI = dyn_cast<CallInst>(U);
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())) {
128 CallInst *CI = dyn_cast<CallInst>(U);
129 assert(CI && "Expected user of lifetime function to be a CallInst");
130 BitCastInst *BCI = dyn_cast<BitCastInst>(CI->getArgOperand(1));
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;
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
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 =
172 ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));
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)
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
Definition: Attributes.cpp:762
This file contains the declarations for the subclasses of Constant, which represent the different fla...
dxil write Write Bitcode
dxil write bitcode
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
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.
raw_pwrite_stream & OS
an instruction to allocate memory on the stack
Definition: Instructions.h:64
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
AttributeList addFnAttribute(LLVMContext &C, Attribute::AttrKind Kind) const
Add a function attribute to the list.
Definition: Attributes.h:593
This class represents a no-op cast from one type to another.
AttributeSet getParamAttributes(unsigned ArgNo) const
Return the param attributes for this call.
Definition: InstrTypes.h:1435
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1292
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
Definition: InstrTypes.h:1506
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
This is an important base class in LLVM.
Definition: Constant.h:43
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:170
@ 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.
Definition: Instruction.cpp:86
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
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
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...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:112
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:85
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:47
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)
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:134
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:662
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
LLVM_ABI StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
Definition: Intrinsics.cpp:49
LLVM_ABI StringRef getBaseName(ID id)
Return the LLVM name for an intrinsic, without encoded types for overloading, such as "llvm....
Definition: Intrinsics.cpp:44
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.
Definition: AddressRanges.h:18
@ Write
Definition: CodeGenData.h:109
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:663
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition: DWP.cpp:622
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.
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...
void initializeWriteDXILPassPass(PassRegistry &)
Initializer for dxil writer pass.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39