| 1 | //===- DXContainerGlobals.cpp - DXContainer global generator 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 | // DXContainerGlobalsPass implementation. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "DXILRootSignature.h" |
| 14 | #include "DXILShaderFlags.h" |
| 15 | #include "DirectX.h" |
| 16 | #include "llvm/ADT/SmallVector.h" |
| 17 | #include "llvm/ADT/StringExtras.h" |
| 18 | #include "llvm/ADT/StringRef.h" |
| 19 | #include "llvm/Analysis/DXILMetadataAnalysis.h" |
| 20 | #include "llvm/Analysis/DXILResource.h" |
| 21 | #include "llvm/BinaryFormat/DXContainer.h" |
| 22 | #include "llvm/CodeGen/Passes.h" |
| 23 | #include "llvm/IR/Constants.h" |
| 24 | #include "llvm/IR/Module.h" |
| 25 | #include "llvm/InitializePasses.h" |
| 26 | #include "llvm/MC/DXContainerInfo.h" |
| 27 | #include "llvm/MC/DXContainerPSVInfo.h" |
| 28 | #include "llvm/MC/MCDXContainerWriter.h" |
| 29 | #include "llvm/Pass.h" |
| 30 | #include "llvm/Support/CommandLine.h" |
| 31 | #include "llvm/Support/Compression.h" |
| 32 | #include "llvm/Support/MD5.h" |
| 33 | #include "llvm/Support/Path.h" |
| 34 | #include "llvm/TargetParser/Triple.h" |
| 35 | #include "llvm/Transforms/Utils/ModuleUtils.h" |
| 36 | #include <cstdint> |
| 37 | |
| 38 | using namespace llvm; |
| 39 | using namespace llvm::dxil; |
| 40 | using namespace llvm::mcdxbc; |
| 41 | |
| 42 | static cl::opt<bool> ShaderHashDependsOnSource( |
| 43 | "dx-Zss" , cl::desc("Compute Shader Hash considering source information" )); |
| 44 | extern cl::opt<std::string> PdbDebugPath; |
| 45 | extern cl::opt<bool> SourceInDebugModule; |
| 46 | cl::opt<bool> PdbInPrivate("dx-pdb-in-private" , |
| 47 | cl::desc("Store PDB in private user data" )); |
| 48 | |
| 49 | namespace { |
| 50 | class DXContainerGlobals : public llvm::ModulePass { |
| 51 | |
| 52 | GlobalVariable *buildContainerGlobal(Module &M, Constant *Content, |
| 53 | StringRef Name, StringRef SectionName); |
| 54 | void addSection(Module &M, SmallVector<GlobalValue *> &Globals, |
| 55 | StringRef SectionData, StringRef MetadataName, |
| 56 | StringRef SectionName); |
| 57 | GlobalVariable *getFeatureFlags(Module &M); |
| 58 | void computeShaderHashAndDebugName(Module &M, |
| 59 | SmallVector<GlobalValue *> &Globals); |
| 60 | GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name, |
| 61 | StringRef SectionName); |
| 62 | void addSignature(Module &M, SmallVector<GlobalValue *> &Globals); |
| 63 | void addRootSignature(Module &M, SmallVector<GlobalValue *> &Globals); |
| 64 | void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV); |
| 65 | void addPipelineStateValidationInfo(Module &M, |
| 66 | SmallVector<GlobalValue *> &Globals); |
| 67 | void addCompilerVersion(Module &M, SmallVector<GlobalValue *> &Globals); |
| 68 | void addSourceInfo(Module &M, SmallVector<GlobalValue *> &Globals); |
| 69 | |
| 70 | public: |
| 71 | static char ID; // Pass identification, replacement for typeid |
| 72 | DXContainerGlobals() : ModulePass(ID) {} |
| 73 | |
| 74 | StringRef getPassName() const override { |
| 75 | return "DXContainer Global Emitter" ; |
| 76 | } |
| 77 | |
| 78 | bool runOnModule(Module &M) override; |
| 79 | |
| 80 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 81 | AU.setPreservesAll(); |
| 82 | AU.addRequired<ShaderFlagsAnalysisWrapper>(); |
| 83 | AU.addRequired<RootSignatureAnalysisWrapper>(); |
| 84 | AU.addRequired<DXILMetadataAnalysisWrapperPass>(); |
| 85 | AU.addRequired<DXILResourceTypeWrapperPass>(); |
| 86 | AU.addRequired<DXILResourceWrapperPass>(); |
| 87 | } |
| 88 | }; |
| 89 | |
| 90 | } // namespace |
| 91 | |
| 92 | bool DXContainerGlobals::runOnModule(Module &M) { |
| 93 | llvm::SmallVector<GlobalValue *> Globals; |
| 94 | Globals.push_back(Elt: getFeatureFlags(M)); |
| 95 | computeShaderHashAndDebugName(M, Globals); |
| 96 | addSignature(M, Globals); |
| 97 | addRootSignature(M, Globals); |
| 98 | addPipelineStateValidationInfo(M, Globals); |
| 99 | addCompilerVersion(M, Globals); |
| 100 | addSourceInfo(M, Globals); |
| 101 | appendToCompilerUsed(M, Values: Globals); |
| 102 | return true; |
| 103 | } |
| 104 | |
| 105 | GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) { |
| 106 | uint64_t CombinedFeatureFlags = getAnalysis<ShaderFlagsAnalysisWrapper>() |
| 107 | .getShaderFlags() |
| 108 | .getCombinedFlags() |
| 109 | .getFeatureFlags(); |
| 110 | |
| 111 | Constant *FeatureFlagsConstant = |
| 112 | ConstantInt::get(Context&: M.getContext(), V: APInt(64, CombinedFeatureFlags)); |
| 113 | return buildContainerGlobal(M, Content: FeatureFlagsConstant, Name: "dx.sfi0" , SectionName: "SFI0" ); |
| 114 | } |
| 115 | |
| 116 | void DXContainerGlobals::addSection(Module &M, |
| 117 | SmallVector<GlobalValue *> &Globals, |
| 118 | StringRef SectionData, |
| 119 | StringRef MetadataName, |
| 120 | StringRef SectionName) { |
| 121 | Constant *SectionConstant = ConstantDataArray::getString( |
| 122 | Context&: M.getContext(), Initializer: SectionData, /*AddNull*/ false); |
| 123 | Globals.emplace_back( |
| 124 | Args: buildContainerGlobal(M, Content: SectionConstant, Name: MetadataName, SectionName)); |
| 125 | } |
| 126 | |
| 127 | void DXContainerGlobals::computeShaderHashAndDebugName( |
| 128 | Module &M, SmallVector<GlobalValue *> &Globals) { |
| 129 | ConstantDataArray *DXILConstant; |
| 130 | MD5 Digest; |
| 131 | dxbc::ShaderHash HashData = {.Flags: 0, .Digest: {0}}; |
| 132 | |
| 133 | if (ShaderHashDependsOnSource) { |
| 134 | if (auto *ILDB = M.getNamedGlobal(Name: "dx.ildb" )) { |
| 135 | DXILConstant = cast<ConstantDataArray>(Val: ILDB->getInitializer()); |
| 136 | HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource); |
| 137 | } else { |
| 138 | reportFatalUsageError(reason: "/Zss requires debug info (/Zi or /Zs)" ); |
| 139 | } |
| 140 | } else { |
| 141 | DXILConstant = |
| 142 | cast<ConstantDataArray>(Val: M.getNamedGlobal(Name: "dx.dxil" )->getInitializer()); |
| 143 | } |
| 144 | |
| 145 | Digest.update(Str: DXILConstant->getRawDataValues()); |
| 146 | MD5::MD5Result MD5 = Digest.final(); |
| 147 | |
| 148 | memcpy(dest: reinterpret_cast<void *>(&HashData.Digest), src: MD5.data(), n: 16); |
| 149 | if (sys::IsBigEndianHost) |
| 150 | HashData.swapBytes(); |
| 151 | StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash)); |
| 152 | |
| 153 | Constant *ModuleConstant = |
| 154 | ConstantDataArray::get(Context&: M.getContext(), Elts: arrayRefFromStringRef(Input: Data)); |
| 155 | Globals.emplace_back( |
| 156 | Args: buildContainerGlobal(M, Content: ModuleConstant, Name: "dx.hash" , SectionName: "HASH" )); |
| 157 | |
| 158 | if (M.debug_compile_units().empty()) |
| 159 | return; |
| 160 | |
| 161 | SmallString<40> DebugNameStr; |
| 162 | Digest.stringifyResult(Result&: MD5, Str&: DebugNameStr); |
| 163 | DebugNameStr += ".pdb" ; |
| 164 | if (!PdbDebugPath.empty() || PdbInPrivate) { |
| 165 | if (!PdbDebugPath.empty()) { |
| 166 | StringRef DebugFile = PdbDebugPath.getValue(); |
| 167 | SmallString<256> AbsoluteDebugName; |
| 168 | if (sys::path::is_separator(value: DebugFile.back())) { |
| 169 | // If PDB output path was specified as a directory, put the MD5.pdb file |
| 170 | // there. |
| 171 | AbsoluteDebugName = DebugFile; |
| 172 | sys::path::append(path&: AbsoluteDebugName, a: DebugNameStr); |
| 173 | } else { |
| 174 | // Otherwise, use PDB output path as a user-provided PDB file name. |
| 175 | DebugNameStr = DebugFile; |
| 176 | AbsoluteDebugName = DebugNameStr; |
| 177 | } |
| 178 | |
| 179 | // Pass PDB name to DXContainerPDBPass via PDBNAME section. |
| 180 | addSection(M, Globals, SectionData: AbsoluteDebugName, MetadataName: "dx.pdb.name" , |
| 181 | SectionName: PdbFileNameSectionName); |
| 182 | } |
| 183 | |
| 184 | // Pass module hash to DXContainerPDBPass. |
| 185 | Globals.emplace_back(Args: buildContainerGlobal( |
| 186 | M, Content: ConstantDataArray::get(Context&: M.getContext(), Elts: ArrayRef(HashData.Digest)), |
| 187 | Name: "dx.pdb.hash" , SectionName: ModuleHashSectionName)); |
| 188 | } |
| 189 | |
| 190 | // Emit ILDN part in debug info mode. |
| 191 | mcdxbc::DebugName DebugName; |
| 192 | DebugName.setFilename(DebugNameStr); |
| 193 | SmallString<64> ILDNData; |
| 194 | raw_svector_ostream OS(ILDNData); |
| 195 | DebugName.write(OS); |
| 196 | addSection(M, Globals, SectionData: ILDNData, MetadataName: "dx.ildn" , SectionName: "ILDN" ); |
| 197 | } |
| 198 | |
| 199 | GlobalVariable *DXContainerGlobals::buildContainerGlobal( |
| 200 | Module &M, Constant *Content, StringRef Name, StringRef SectionName) { |
| 201 | auto *GV = new llvm::GlobalVariable( |
| 202 | M, Content->getType(), true, GlobalValue::PrivateLinkage, Content, Name); |
| 203 | GV->setSection(SectionName); |
| 204 | GV->setAlignment(Align(4)); |
| 205 | return GV; |
| 206 | } |
| 207 | |
| 208 | GlobalVariable *DXContainerGlobals::buildSignature(Module &M, Signature &Sig, |
| 209 | StringRef Name, |
| 210 | StringRef SectionName) { |
| 211 | SmallString<256> Data; |
| 212 | raw_svector_ostream OS(Data); |
| 213 | Sig.write(OS); |
| 214 | Constant *Constant = |
| 215 | ConstantDataArray::getString(Context&: M.getContext(), Initializer: Data, /*AddNull*/ false); |
| 216 | return buildContainerGlobal(M, Content: Constant, Name, SectionName); |
| 217 | } |
| 218 | |
| 219 | void DXContainerGlobals::addSignature(Module &M, |
| 220 | SmallVector<GlobalValue *> &Globals) { |
| 221 | // FIXME: support graphics shader. |
| 222 | // see issue https://github.com/llvm/llvm-project/issues/90504. |
| 223 | |
| 224 | Signature InputSig; |
| 225 | Globals.emplace_back(Args: buildSignature(M, Sig&: InputSig, Name: "dx.isg1" , SectionName: "ISG1" )); |
| 226 | |
| 227 | Signature OutputSig; |
| 228 | Globals.emplace_back(Args: buildSignature(M, Sig&: OutputSig, Name: "dx.osg1" , SectionName: "OSG1" )); |
| 229 | } |
| 230 | |
| 231 | void DXContainerGlobals::addRootSignature(Module &M, |
| 232 | SmallVector<GlobalValue *> &Globals) { |
| 233 | |
| 234 | dxil::ModuleMetadataInfo &MMI = |
| 235 | getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata(); |
| 236 | |
| 237 | // Root Signature in Library don't compile to DXContainer. |
| 238 | if (MMI.ShaderProfile == llvm::Triple::Library) |
| 239 | return; |
| 240 | |
| 241 | auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo(); |
| 242 | const Function *EntryFunction = nullptr; |
| 243 | |
| 244 | if (MMI.ShaderProfile != llvm::Triple::RootSignature) { |
| 245 | assert(MMI.EntryPropertyVec.size() == 1); |
| 246 | EntryFunction = MMI.EntryPropertyVec[0].Entry; |
| 247 | } |
| 248 | |
| 249 | const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(F: EntryFunction); |
| 250 | if (!RS) |
| 251 | return; |
| 252 | |
| 253 | SmallString<256> Data; |
| 254 | raw_svector_ostream OS(Data); |
| 255 | |
| 256 | RS->write(OS); |
| 257 | |
| 258 | addSection(M, Globals, SectionData: Data, MetadataName: "dx.rts0" , SectionName: "RTS0" ); |
| 259 | } |
| 260 | |
| 261 | void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) { |
| 262 | const DXILResourceMap &DRM = |
| 263 | getAnalysis<DXILResourceWrapperPass>().getResourceMap(); |
| 264 | DXILResourceTypeMap &DRTM = |
| 265 | getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap(); |
| 266 | |
| 267 | auto MakeBinding = |
| 268 | [](const dxil::ResourceInfo::ResourceBinding &Binding, |
| 269 | const dxbc::PSV::ResourceType Type, const dxil::ResourceKind Kind, |
| 270 | const dxbc::PSV::ResourceFlags Flags = dxbc::PSV::ResourceFlags()) { |
| 271 | dxbc::PSV::v2::ResourceBindInfo BindInfo; |
| 272 | BindInfo.Type = Type; |
| 273 | BindInfo.LowerBound = Binding.LowerBound; |
| 274 | assert( |
| 275 | (Binding.Size == 0 || |
| 276 | (uint64_t)Binding.LowerBound + Binding.Size - 1 <= UINT32_MAX) && |
| 277 | "Resource range is too large" ); |
| 278 | BindInfo.UpperBound = (Binding.Size == 0) |
| 279 | ? UINT32_MAX |
| 280 | : Binding.LowerBound + Binding.Size - 1; |
| 281 | BindInfo.Space = Binding.Space; |
| 282 | BindInfo.Kind = static_cast<dxbc::PSV::ResourceKind>(Kind); |
| 283 | BindInfo.Flags = Flags; |
| 284 | return BindInfo; |
| 285 | }; |
| 286 | |
| 287 | for (const dxil::ResourceInfo &RI : DRM.cbuffers()) { |
| 288 | if (!RI.hasBinding()) |
| 289 | continue; |
| 290 | const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding(); |
| 291 | PSV.Resources.push_back(Elt: MakeBinding(Binding, dxbc::PSV::ResourceType::CBV, |
| 292 | dxil::ResourceKind::CBuffer)); |
| 293 | } |
| 294 | for (const dxil::ResourceInfo &RI : DRM.samplers()) { |
| 295 | if (!RI.hasBinding()) |
| 296 | continue; |
| 297 | const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding(); |
| 298 | PSV.Resources.push_back(Elt: MakeBinding(Binding, |
| 299 | dxbc::PSV::ResourceType::Sampler, |
| 300 | dxil::ResourceKind::Sampler)); |
| 301 | } |
| 302 | for (const dxil::ResourceInfo &RI : DRM.srvs()) { |
| 303 | if (!RI.hasBinding()) |
| 304 | continue; |
| 305 | const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding(); |
| 306 | |
| 307 | dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()]; |
| 308 | dxbc::PSV::ResourceType ResType; |
| 309 | if (TypeInfo.isStruct()) |
| 310 | ResType = dxbc::PSV::ResourceType::SRVStructured; |
| 311 | else if (TypeInfo.isTyped()) |
| 312 | ResType = dxbc::PSV::ResourceType::SRVTyped; |
| 313 | else |
| 314 | ResType = dxbc::PSV::ResourceType::SRVRaw; |
| 315 | |
| 316 | PSV.Resources.push_back( |
| 317 | Elt: MakeBinding(Binding, ResType, TypeInfo.getResourceKind())); |
| 318 | } |
| 319 | for (const dxil::ResourceInfo &RI : DRM.uavs()) { |
| 320 | if (!RI.hasBinding()) |
| 321 | continue; |
| 322 | const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding(); |
| 323 | |
| 324 | dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()]; |
| 325 | dxbc::PSV::ResourceType ResType; |
| 326 | if (RI.hasCounter()) |
| 327 | ResType = dxbc::PSV::ResourceType::UAVStructuredWithCounter; |
| 328 | else if (TypeInfo.isStruct()) |
| 329 | ResType = dxbc::PSV::ResourceType::UAVStructured; |
| 330 | else if (TypeInfo.isTyped()) |
| 331 | ResType = dxbc::PSV::ResourceType::UAVTyped; |
| 332 | else |
| 333 | ResType = dxbc::PSV::ResourceType::UAVRaw; |
| 334 | |
| 335 | dxbc::PSV::ResourceFlags Flags; |
| 336 | Flags.Bits.UsedByAtomic64 = RI.HasAtomic64Use; |
| 337 | |
| 338 | PSV.Resources.push_back( |
| 339 | Elt: MakeBinding(Binding, ResType, TypeInfo.getResourceKind(), Flags)); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | void DXContainerGlobals::addPipelineStateValidationInfo( |
| 344 | Module &M, SmallVector<GlobalValue *> &Globals) { |
| 345 | SmallString<256> Data; |
| 346 | raw_svector_ostream OS(Data); |
| 347 | PSVRuntimeInfo PSV; |
| 348 | PSV.BaseData.MinimumWaveLaneCount = 0; |
| 349 | PSV.BaseData.MaximumWaveLaneCount = std::numeric_limits<uint32_t>::max(); |
| 350 | |
| 351 | dxil::ModuleMetadataInfo &MMI = |
| 352 | getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata(); |
| 353 | assert(MMI.EntryPropertyVec.size() == 1 || |
| 354 | MMI.ShaderProfile == Triple::Library || |
| 355 | MMI.ShaderProfile == Triple::RootSignature); |
| 356 | PSV.BaseData.ShaderStage = |
| 357 | static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel); |
| 358 | |
| 359 | addResourcesForPSV(M, PSV); |
| 360 | |
| 361 | // Hardcoded values here to unblock loading the shader into D3D. |
| 362 | // |
| 363 | // TODO: Lots more stuff to do here! |
| 364 | // |
| 365 | // See issue https://github.com/llvm/llvm-project/issues/96674. |
| 366 | switch (MMI.ShaderProfile) { |
| 367 | case Triple::Compute: |
| 368 | PSV.BaseData.NumThreadsX = MMI.EntryPropertyVec[0].NumThreadsX; |
| 369 | PSV.BaseData.NumThreadsY = MMI.EntryPropertyVec[0].NumThreadsY; |
| 370 | PSV.BaseData.NumThreadsZ = MMI.EntryPropertyVec[0].NumThreadsZ; |
| 371 | if (MMI.EntryPropertyVec[0].WaveSizeMin) { |
| 372 | PSV.BaseData.MinimumWaveLaneCount = MMI.EntryPropertyVec[0].WaveSizeMin; |
| 373 | PSV.BaseData.MaximumWaveLaneCount = |
| 374 | MMI.EntryPropertyVec[0].WaveSizeMax |
| 375 | ? MMI.EntryPropertyVec[0].WaveSizeMax |
| 376 | : MMI.EntryPropertyVec[0].WaveSizeMin; |
| 377 | } |
| 378 | break; |
| 379 | default: |
| 380 | break; |
| 381 | } |
| 382 | |
| 383 | if (MMI.ShaderProfile != Triple::Library && |
| 384 | MMI.ShaderProfile != Triple::RootSignature) |
| 385 | PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName(); |
| 386 | |
| 387 | PSV.finalize(Stage: MMI.ShaderProfile); |
| 388 | PSV.write(OS); |
| 389 | addSection(M, Globals, SectionData: Data, MetadataName: "dx.psv0" , SectionName: "PSV0" ); |
| 390 | } |
| 391 | |
| 392 | void DXContainerGlobals::addCompilerVersion( |
| 393 | Module &M, SmallVector<GlobalValue *> &Globals) { |
| 394 | if (M.debug_compile_units().empty()) |
| 395 | return; |
| 396 | |
| 397 | SmallString<256> Data; |
| 398 | raw_svector_ostream OS(Data); |
| 399 | mcdxbc::CompilerVersion CompilerVersion; |
| 400 | CompilerVersion.write(OS); |
| 401 | addSection(M, Globals, SectionData: Data, MetadataName: "dx.vers" , SectionName: "VERS" ); |
| 402 | } |
| 403 | |
| 404 | void DXContainerGlobals::addSourceInfo(Module &M, |
| 405 | SmallVector<GlobalValue *> &Globals) { |
| 406 | dxil::ModuleMetadataInfo &MMI = |
| 407 | getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata(); |
| 408 | |
| 409 | if (!MMI.SourceInfo || SourceInDebugModule) |
| 410 | return; |
| 411 | |
| 412 | MMI.SourceInfo->computeEntries(); |
| 413 | MMI.SourceInfo->finalize(); |
| 414 | SmallString<256> Data; |
| 415 | raw_svector_ostream OS(Data); |
| 416 | MMI.SourceInfo->write(OS); |
| 417 | addSection(M, Globals, SectionData: Data, MetadataName: "dx.srci" , SectionName: "SRCI" ); |
| 418 | } |
| 419 | |
| 420 | char DXContainerGlobals::ID = 0; |
| 421 | INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals" , |
| 422 | "DXContainer Global Emitter" , false, true) |
| 423 | INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper) |
| 424 | INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass) |
| 425 | INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass) |
| 426 | INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass) |
| 427 | INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals" , |
| 428 | "DXContainer Global Emitter" , false, true) |
| 429 | |
| 430 | ModulePass *llvm::createDXContainerGlobalsPass() { |
| 431 | return new DXContainerGlobals(); |
| 432 | } |
| 433 | |