LLVM 24.0.0git
DXILContainerPDB.cpp
Go to the documentation of this file.
1//===- DXILContainerPDB.cpp - DirectX PDB writer 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#include "DirectX.h"
11#include "llvm/ADT/ScopeExit.h"
12#include "llvm/ADT/StringSet.h"
17#include "llvm/IR/Analysis.h"
18#include "llvm/IR/Constants.h"
19#include "llvm/IR/Module.h"
20#include "llvm/IR/PassManager.h"
22#include "llvm/Pass.h"
28
29using namespace llvm;
30
31namespace {
32
33class DXILContainerPDBImpl : MCDXContainerBaseWriter {
34 Module *M = nullptr;
36
37 void reset() {
38 M = nullptr;
39 Parts.clear();
40 }
41
42public:
43 bool shouldSkipSection(StringRef SectionName, size_t SectionSize) override;
44 ArrayRef<MCDXContainerPart> collectParts() override;
45 bool runOnModule(Module &M);
46};
47
48class DXILContainerPDBLegacy : public ModulePass {
49public:
50 static char ID;
51 DXILContainerPDBLegacy() : ModulePass(ID) {}
52
53 StringRef getPassName() const override { return "DirectX PDB Emitter"; }
54
55 bool runOnModule(Module &M) override;
56
57 void getAnalysisUsage(AnalysisUsage &AU) const override {
58 AU.setPreservesAll();
59 }
60};
61
62} // namespace
63
64bool DXILContainerPDBImpl::shouldSkipSection(StringRef SectionName,
65 size_t SectionSize) {
66 if (MCDXContainerBaseWriter::shouldSkipSection(SectionName, SectionSize))
67 return true;
68 if (dxil::SlimDebug && SectionName == "ILDB")
69 return true;
70
71 // Skip sections that are irrelevant for debug info.
72 static const StringSet<> DebugSections{"ILDB", "ILDN", "HASH", "PDBI",
73 "SRCI", "STAT", "RDAT", "VERS"};
74 return !DebugSections.contains(SectionName);
75}
76
78 if (GV.hasInitializer())
79 if (const auto *Data =
81 return Data->getRawDataValues();
82 return {};
83}
84
85ArrayRef<MCDXContainerPart> DXILContainerPDBImpl::collectParts() {
86 Parts.clear();
87 for (const GlobalVariable &GV : M->globals()) {
88 StringRef Name = GV.getSection();
89 StringRef Data = getGlobalData(GV);
90
91 if (Data.empty())
92 continue;
93 if (shouldSkipSection(Name, Data.size()))
94 continue;
95
96 Parts.push_back({Name, Data});
97 }
98 return Parts;
99}
100
102 Constant *Content =
103 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
104 auto *GV =
105 new GlobalVariable(M, Content->getType(), true,
106 GlobalValue::PrivateLinkage, Content, "dx.priv");
107 GV->setSection("PRIV");
108 GV->setAlignment(Align(1));
109 return GV;
110}
111
112bool DXILContainerPDBImpl::runOnModule(Module &M) {
113 llvm::scope_exit Cleanup([&]() { reset(); });
114 this->M = &M;
115
116 SmallString<128> DebugFileName;
117 ArrayRef<char> ModuleHash;
118 for (const GlobalVariable &GV : M.globals()) {
119 if (GV.getSection() == PdbFileNameSectionName) {
120 assert(DebugFileName.empty() && "Duplicate PDBNAME section");
121 DebugFileName = getGlobalData(GV);
122 } else if (GV.getSection() == ModuleHashSectionName) {
123 assert(ModuleHash.empty() && "Duplicate PBDHASH section");
124 StringRef Data = getGlobalData(GV);
125 ModuleHash = ArrayRef(Data.data(), Data.size());
126 }
127 }
128
129 // PDB emission was not requested.
130 if (DebugFileName.empty() && !dxil::PdbInPrivate)
131 return false;
132 if (ModuleHash.empty())
133 report_fatal_error("Module hash for PDB not found");
134
135 bool DeleteAfterRead = false;
136 if (DebugFileName.empty()) {
137 if (std::error_code EC =
138 sys::fs::createTemporaryFile("dxil", "pdb", DebugFileName))
139 reportFatalInternalError("Failed to create temporary PDB file");
140 DeleteAfterRead = true;
141 }
142 llvm::scope_exit FileCleanup([&]() {
143 if (DeleteAfterRead)
144 sys::fs::remove(DebugFileName);
145 });
146
148 pdb::PDBFileBuilder Builder(Allocator);
149
150 // DirectXShaderCompiler uses block size 512.
151 if (Error Err = Builder.initialize(512))
152 reportFatalInternalError(std::move(Err));
153
154 // Reserved streams that should be empty.
155 static_assert(pdb::kSpecialStreamCount == 5 &&
156 "First 5 streams should be empty in DirectX PDB file");
157 for (uint32_t I = 0; I < pdb::kSpecialStreamCount; ++I) {
158 if (auto Err = Builder.getMsfBuilder().addStream(0).takeError())
159 reportFatalInternalError(std::move(Err));
160 }
161
162 // Add DXContainer stream.
163 if (auto Err = Builder.getMsfBuilder().addStream(0).takeError())
164 reportFatalInternalError(std::move(Err));
165
166 // InfoStream must be filled. Bitcode hash from HASH part is used for PDB
167 // GUID.
168 codeview::GUID PdbGuid;
169 assert(ModuleHash.size() == std::size(PdbGuid.Guid) &&
170 "Module hash length must be match GUID length");
171 std::copy_n(ModuleHash.begin(), std::size(PdbGuid.Guid), PdbGuid.Guid);
172
173 auto &InfoBuilder = Builder.getInfoBuilder();
174 InfoBuilder.setAge(1);
175 InfoBuilder.setGuid(PdbGuid);
176 InfoBuilder.setSignature(0);
177 InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
178
179 // Write DXContainer.
180 raw_svector_ostream OS(*Builder.getDXContainerData());
181 write(OS, M.getTargetTriple());
182
183 // Write PDB file.
184 codeview::GUID IgnoredOutGuid;
185 {
186 // FIXME(sandboxing): Remove this by routing output through OutputBackend.
187 auto BypassSandbox = sys::sandbox::scopedDisable();
188 if (Error Err = Builder.commit(DebugFileName, &IgnoredOutGuid))
189 reportFatalUsageError("Couldn't write to PDB file: " +
190 Twine(toString(std::move(Err))));
191 }
192
194 return false;
195
196 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
197 M.getContext().getVirtualFileSystem().getBufferForFile(
198 DebugFileName, /*FileSize=*/-1, /*RequiresNullTerminator=*/false,
199 /*IsVolatile=*/false, /*IsText=*/false);
200 if (!Buf)
201 reportFatalInternalError("Failed to read PDB for PRIV embedding");
202
203 appendToCompilerUsed(M, createPrivateDataGlobal(M, (*Buf)->getBuffer()));
204
205 return true;
206}
207
208char DXILContainerPDBLegacy::ID = 0;
209INITIALIZE_PASS(DXILContainerPDBLegacy, "dxil-container-pdb",
210 "DirectX PDB Emitter", false, true)
211
213 return new DXILContainerPDBLegacy();
214}
215
216bool DXILContainerPDBLegacy::runOnModule(Module &M) {
217 DXILContainerPDBImpl Impl;
218 return Impl.runOnModule(M);
219}
220
223 DXILContainerPDBImpl Impl;
224 Impl.runOnModule(M);
225 return PreservedAnalyses::all();
226}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static StringRef getGlobalData(const GlobalVariable &GV)
static GlobalVariable * createPrivateDataGlobal(Module &M, StringRef Data)
ManagedStatic< HTTPClientCleanup > Cleanup
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
Basic Register Allocator
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
StringSet - A set-like wrapper for the StringMap.
Defines the virtual file system interface vfs::FileSystem.
void setPreservesAll()
Set by analyses that do not transform their input at all.
static LLVM_ABI Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true, bool ByteString=false)
This method constructs a CDS and initializes it with a text string.
This is an important base class in LLVM.
Definition Constant.h:44
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool hasInitializer() const
Definitions have initializers, declarations don't.
virtual bool shouldSkipSection(StringRef SectionName, size_t SectionSize)
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
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool contains(StringRef key) const
Check if the set contains the given key.
Definition StringSet.h:60
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
Pass manager infrastructure for declaring and invalidating analyses.
cl::opt< bool > SlimDebug
cl::opt< bool > PdbInPrivate
@ kSpecialStreamCount
LLVM_ABI std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
LLVM_ABI std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, SmallVectorImpl< char > &ResultPath, OpenFlags Flags=OF_None)
Create a file in the system temporary directory.
Definition Path.cpp:936
ScopedSetting scopedDisable()
Definition IOSandbox.h:36
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
scope_exit(Callable) -> scope_exit< Callable >
ModulePass * createDXILContainerPDBLegacyPass()
std::array< uint32_t, 5 > ModuleHash
160 bits SHA1
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
static constexpr StringLiteral ModuleHashSectionName
Contains module hash.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:391
LLVM_ABI Error write(DWPWriter &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue, raw_pwrite_stream *OS=nullptr)
Definition DWP.cpp:746
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
static constexpr StringLiteral PdbFileNameSectionName
Contains PDB output file name.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
uint8_t Guid[16]
Definition GUID.h:23