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