From ce1c397355c4aca2f5d3e1a934dc094d0d30251a Mon Sep 17 00:00:00 2001 From: Nielsbishere Date: Thu, 4 Sep 2025 10:40:29 +0200 Subject: [PATCH 1/2] Added -keep-all-resources to keep even optimized out resources in reflection. This isn't default to avoid DXIL bloat and because apps might assume that if a resource is missing that it's optimized out and use this info to avoid transitions or other optimizations. When a resource is unused but still present, it won't emit a createHandle, but the reflection info will still be there --- include/dxc/DXIL/DxilModule.h | 3 +++ include/dxc/HLSL/HLModule.h | 5 +++-- include/dxc/Support/HLSLOptions.h | 1 + include/dxc/Support/HLSLOptions.td | 3 +++ lib/DXIL/DxilModule.cpp | 10 ++++++++++ lib/DxcSupport/HLSLOptions.cpp | 4 ++++ lib/HLSL/DxilCondenseResources.cpp | 20 +++++++++++++------ lib/HLSL/DxilGenerationPass.cpp | 1 + lib/HLSL/HLModule.cpp | 15 ++++++++------ .../include/clang/Frontend/CodeGenOptions.h | 2 ++ tools/clang/lib/CodeGen/CGHLSLMS.cpp | 2 ++ .../clang/tools/dxcompiler/dxcompilerobj.cpp | 2 ++ 12 files changed, 54 insertions(+), 14 deletions(-) diff --git a/include/dxc/DXIL/DxilModule.h b/include/dxc/DXIL/DxilModule.h index 3f1ba12f86..0c8dbd56a8 100644 --- a/include/dxc/DXIL/DxilModule.h +++ b/include/dxc/DXIL/DxilModule.h @@ -287,6 +287,8 @@ class DxilModule { // Intermediate options that do not make it to DXIL void SetLegacyResourceReservation(bool legacyResourceReservation); bool GetLegacyResourceReservation() const; + void SetKeepAllResources(bool keepAllResources); + bool GetKeepAllResources() const; void ClearIntermediateOptions(); // Hull and Domain shaders. @@ -346,6 +348,7 @@ class DxilModule { enum IntermediateFlags : uint32_t { LegacyResourceReservation = 1 << 0, + KeepAllResources = 1 << 2 //To be compatible with ConsistentBindings in different PR }; llvm::LLVMContext &m_Ctx; diff --git a/include/dxc/HLSL/HLModule.h b/include/dxc/HLSL/HLModule.h index 653fc967d5..6edd77f781 100644 --- a/include/dxc/HLSL/HLModule.h +++ b/include/dxc/HLSL/HLModule.h @@ -54,7 +54,7 @@ struct HLOptions { bDisableOptimizations(false), PackingStrategy(0), bUseMinPrecision(false), bDX9CompatMode(false), bFXCCompatMode(false), bLegacyResourceReservation(false), bForceZeroStoreLifetimes(false), - unused(0) {} + bKeepAllResources(false), unused(0) {} uint32_t GetHLOptionsRaw() const; void SetHLOptionsRaw(uint32_t data); unsigned bDefaultRowMajor : 1; @@ -70,7 +70,8 @@ struct HLOptions { unsigned bLegacyResourceReservation : 1; unsigned bForceZeroStoreLifetimes : 1; unsigned bResMayAlias : 1; - unsigned unused : 19; + unsigned bKeepAllResources : 1; + unsigned unused : 18; }; typedef std::unordered_map, Flags<[DriverOption def nologo : Flag<["-", "/"], "nologo">, Group, Flags<[DriverOption, HelpHidden]>, HelpText<"Suppress copyright message">; +def keep_all_resources : Flag<["-", "/"], "keep-all-resources">, Group, Flags<[CoreOption]>, + HelpText<"Keep even optimized out resources for dxil reflection purposes.">; + ////////////////////////////////////////////////////////////////////////////// // Rewriter Options diff --git a/lib/DXIL/DxilModule.cpp b/lib/DXIL/DxilModule.cpp index f4abdd15aa..3af95122ea 100644 --- a/lib/DXIL/DxilModule.cpp +++ b/lib/DXIL/DxilModule.cpp @@ -586,6 +586,16 @@ bool DxilModule::GetLegacyResourceReservation() const { return (m_IntermediateFlags & LegacyResourceReservation) != 0; } +void DxilModule::SetKeepAllResources(bool keepAllResources) { + m_IntermediateFlags &= ~KeepAllResources; + if (keepAllResources) + m_IntermediateFlags |= KeepAllResources; +} + +bool DxilModule::GetKeepAllResources() const { + return (m_IntermediateFlags & KeepAllResources) != 0; +} + void DxilModule::ClearIntermediateOptions() { m_IntermediateFlags = 0; } unsigned DxilModule::GetInputControlPointCount() const { diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 06e6a1bed6..265f5b9576 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -871,6 +871,10 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, opts.TimeReport = Args.hasFlag(OPT_ftime_report, OPT_INVALID, false); opts.TimeTrace = Args.hasFlag(OPT_ftime_trace, OPT_INVALID, false) ? "-" : ""; opts.VerifyDiagnostics = Args.hasFlag(OPT_verify, OPT_INVALID, false); + + opts.KeepAllResources = + Args.hasFlag(OPT_keep_all_resources, OPT_INVALID, false); + if (Args.hasArg(OPT_ftime_trace_EQ)) opts.TimeTrace = Args.getLastArgValue(OPT_ftime_trace_EQ); if (Arg *A = Args.getLastArg(OPT_ftime_trace_granularity_EQ)) { diff --git a/lib/HLSL/DxilCondenseResources.cpp b/lib/HLSL/DxilCondenseResources.cpp index 09dd9cea64..dd78fcf86d 100644 --- a/lib/HLSL/DxilCondenseResources.cpp +++ b/lib/HLSL/DxilCondenseResources.cpp @@ -550,7 +550,8 @@ class DxilLowerCreateHandleForLib : public ModulePass { ResourceRegisterAllocator.GatherReservedRegisters(DM); // Remove unused resources. - DM.RemoveResourcesWithUnusedSymbols(); + if (!DM.GetKeepAllResources()) + DM.RemoveResourcesWithUnusedSymbols(); unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() + DM.GetSRVs().size() + DM.GetSamplers().size(); @@ -564,7 +565,9 @@ class DxilLowerCreateHandleForLib : public ModulePass { bool bLocalChanged = LegalizeResources(M, DVC); if (bLocalChanged) { // Remove unused resources. - DM.RemoveResourcesWithUnusedSymbols(); + + if (!DM.GetKeepAllResources()) + DM.RemoveResourcesWithUnusedSymbols(); } bChanged |= bLocalChanged; } @@ -2122,6 +2125,15 @@ void DxilLowerCreateHandleForLib::ReplaceResourceUserWithHandle( void DxilLowerCreateHandleForLib::TranslateDxilResourceUses( DxilResourceBase &res) { OP *hlslOP = m_DM->GetOP(); + + Value *GV = res.GetGlobalSymbol(); + + if (isa(GV)) + return; + + DXASSERT(isa(GV), + "DxilLowerCreateHandleForLib cannot deal with resources that aren't GlobalValue."); + // Generate createHandleFromBinding for sm66 and later. bool bCreateFromBinding = m_DM->GetShaderModel()->IsSM66Plus(); OP::OpCode createOp = bCreateFromBinding ? OP::OpCode::CreateHandleFromBinding @@ -2149,10 +2161,6 @@ void DxilLowerCreateHandleForLib::TranslateDxilResourceUses( Value *isUniformRes = hlslOP->GetI1Const(0); - Value *GV = res.GetGlobalSymbol(); - DXASSERT(isa(GV), - "DxilLowerCreateHandleForLib cannot deal with unused resources."); - Module *pM = m_DM->GetModule(); // TODO: add debug info to create handle. DIVariable *DIV = nullptr; diff --git a/lib/HLSL/DxilGenerationPass.cpp b/lib/HLSL/DxilGenerationPass.cpp index c3a6ad7dfc..4a5eb3d27a 100644 --- a/lib/HLSL/DxilGenerationPass.cpp +++ b/lib/HLSL/DxilGenerationPass.cpp @@ -155,6 +155,7 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, bool HasDebugInfo) { // bool m_bDisableOptimizations; M.SetDisableOptimization(H.GetHLOptions().bDisableOptimizations); M.SetLegacyResourceReservation(H.GetHLOptions().bLegacyResourceReservation); + M.SetKeepAllResources(H.GetHLOptions().bKeepAllResources); // bool m_bDisableMathRefactoring; // bool m_bEnableDoublePrecision; // bool m_bEnableDoubleExtensions; diff --git a/lib/HLSL/HLModule.cpp b/lib/HLSL/HLModule.cpp index bab6e23a30..9f1be75036 100644 --- a/lib/HLSL/HLModule.cpp +++ b/lib/HLSL/HLModule.cpp @@ -231,12 +231,12 @@ void HLModule::RemoveFunction(llvm::Function *F) { namespace { template bool RemoveResource(std::vector> &vec, - GlobalVariable *pVariable, bool keepAllocated) { + GlobalVariable *pVariable, bool keepAllocated, bool keepAllResources) { for (auto p = vec.begin(), e = vec.end(); p != e; ++p) { if ((*p)->GetGlobalSymbol() != pVariable) continue; - if (keepAllocated && (*p)->IsAllocated()) { + if ((keepAllocated && (*p)->IsAllocated()) || keepAllResources) { // Keep the resource, but it has no more symbol. (*p)->SetGlobalSymbol(UndefValue::get(pVariable->getType())); } else { @@ -262,16 +262,19 @@ void HLModule::RemoveGlobal(llvm::GlobalVariable *GV) { // register range from being allocated to other resources. bool keepAllocated = GetHLOptions().bLegacyResourceReservation; + // Keep all resources is for reflection purposes to simulate -Od with -spirv for dxil. + bool keepAllResources = GetHLOptions().bKeepAllResources; + // This could be considerably faster - check variable type to see which // resource type this is rather than scanning all lists, and look for // usage and removal patterns. - if (RemoveResource(m_CBuffers, GV, keepAllocated)) + if (RemoveResource(m_CBuffers, GV, keepAllocated, keepAllResources)) return; - if (RemoveResource(m_SRVs, GV, keepAllocated)) + if (RemoveResource(m_SRVs, GV, keepAllocated, keepAllResources)) return; - if (RemoveResource(m_UAVs, GV, keepAllocated)) + if (RemoveResource(m_UAVs, GV, keepAllocated, keepAllResources)) return; - if (RemoveResource(m_Samplers, GV, keepAllocated)) + if (RemoveResource(m_Samplers, GV, keepAllocated, keepAllResources)) return; // TODO: do m_TGSMVariables and m_StreamOutputs need maintenance? } diff --git a/tools/clang/include/clang/Frontend/CodeGenOptions.h b/tools/clang/include/clang/Frontend/CodeGenOptions.h index 859cba53da..f0077849f7 100644 --- a/tools/clang/include/clang/Frontend/CodeGenOptions.h +++ b/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -187,6 +187,8 @@ class CodeGenOptions : public CodeGenOptionsBase { bool HLSLOnlyWarnOnUnrollFail = false; /// Whether use legacy resource reservation. bool HLSLLegacyResourceReservation = false; + /// Whether to keep bindings even if they're optimized out. + bool HLSLKeepAllResources = false; /// Set [branch] on every if. bool HLSLPreferControlFlow = false; /// Set [flatten] on every if. diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index b5add521a6..92524aee28 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -400,6 +400,8 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM) opts.PackingStrategy = CGM.getCodeGenOpts().HLSLSignaturePackingStrategy; opts.bLegacyResourceReservation = CGM.getCodeGenOpts().HLSLLegacyResourceReservation; + opts.bKeepAllResources = + CGM.getCodeGenOpts().HLSLKeepAllResources; opts.bForceZeroStoreLifetimes = CGM.getCodeGenOpts().HLSLForceZeroStoreLifetimes; diff --git a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp index 84b568df9c..960c4cd883 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -1602,6 +1602,8 @@ class DxcCompiler : public IDxcCompiler3, compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl; compiler.getCodeGenOpts().HLSLLegacyResourceReservation = Opts.LegacyResourceReservation; + compiler.getCodeGenOpts().HLSLKeepAllResources = + Opts.KeepAllResources; compiler.getCodeGenOpts().HLSLDefines = defines; compiler.getCodeGenOpts().HLSLPreciseOutputs = Opts.PreciseOutputs; compiler.getCodeGenOpts().MainFileName = pMainFile; From fe0612c84b5dbaf534f24de22c5a00324046f658 Mon Sep 17 00:00:00 2001 From: Nielsbishere Date: Thu, 4 Sep 2025 10:56:32 +0200 Subject: [PATCH 2/2] Believe it or not, clang format --- include/dxc/DXIL/DxilModule.h | 3 ++- lib/HLSL/DxilCondenseResources.cpp | 6 +++--- lib/HLSL/HLModule.cpp | 6 ++++-- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 3 +-- tools/clang/tools/dxcompiler/dxcompilerobj.cpp | 3 +-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/dxc/DXIL/DxilModule.h b/include/dxc/DXIL/DxilModule.h index 0c8dbd56a8..13bed6f6f0 100644 --- a/include/dxc/DXIL/DxilModule.h +++ b/include/dxc/DXIL/DxilModule.h @@ -348,7 +348,8 @@ class DxilModule { enum IntermediateFlags : uint32_t { LegacyResourceReservation = 1 << 0, - KeepAllResources = 1 << 2 //To be compatible with ConsistentBindings in different PR + KeepAllResources = + 1 << 2 // To be compatible with ConsistentBindings in different PR }; llvm::LLVMContext &m_Ctx; diff --git a/lib/HLSL/DxilCondenseResources.cpp b/lib/HLSL/DxilCondenseResources.cpp index dd78fcf86d..70aa61fdf8 100644 --- a/lib/HLSL/DxilCondenseResources.cpp +++ b/lib/HLSL/DxilCondenseResources.cpp @@ -551,7 +551,7 @@ class DxilLowerCreateHandleForLib : public ModulePass { // Remove unused resources. if (!DM.GetKeepAllResources()) - DM.RemoveResourcesWithUnusedSymbols(); + DM.RemoveResourcesWithUnusedSymbols(); unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() + DM.GetSRVs().size() + DM.GetSamplers().size(); @@ -2131,8 +2131,8 @@ void DxilLowerCreateHandleForLib::TranslateDxilResourceUses( if (isa(GV)) return; - DXASSERT(isa(GV), - "DxilLowerCreateHandleForLib cannot deal with resources that aren't GlobalValue."); + DXASSERT(isa(GV), "DxilLowerCreateHandleForLib cannot deal with " + "resources that aren't GlobalValue."); // Generate createHandleFromBinding for sm66 and later. bool bCreateFromBinding = m_DM->GetShaderModel()->IsSM66Plus(); diff --git a/lib/HLSL/HLModule.cpp b/lib/HLSL/HLModule.cpp index 9f1be75036..a7a7a93080 100644 --- a/lib/HLSL/HLModule.cpp +++ b/lib/HLSL/HLModule.cpp @@ -231,7 +231,8 @@ void HLModule::RemoveFunction(llvm::Function *F) { namespace { template bool RemoveResource(std::vector> &vec, - GlobalVariable *pVariable, bool keepAllocated, bool keepAllResources) { + GlobalVariable *pVariable, bool keepAllocated, + bool keepAllResources) { for (auto p = vec.begin(), e = vec.end(); p != e; ++p) { if ((*p)->GetGlobalSymbol() != pVariable) continue; @@ -262,7 +263,8 @@ void HLModule::RemoveGlobal(llvm::GlobalVariable *GV) { // register range from being allocated to other resources. bool keepAllocated = GetHLOptions().bLegacyResourceReservation; - // Keep all resources is for reflection purposes to simulate -Od with -spirv for dxil. + // Keep all resources is for reflection purposes to simulate -Od with -spirv + // for dxil. bool keepAllResources = GetHLOptions().bKeepAllResources; // This could be considerably faster - check variable type to see which diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 92524aee28..7365abec0e 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -400,8 +400,7 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM) opts.PackingStrategy = CGM.getCodeGenOpts().HLSLSignaturePackingStrategy; opts.bLegacyResourceReservation = CGM.getCodeGenOpts().HLSLLegacyResourceReservation; - opts.bKeepAllResources = - CGM.getCodeGenOpts().HLSLKeepAllResources; + opts.bKeepAllResources = CGM.getCodeGenOpts().HLSLKeepAllResources; opts.bForceZeroStoreLifetimes = CGM.getCodeGenOpts().HLSLForceZeroStoreLifetimes; diff --git a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp index 960c4cd883..1ddad8e90c 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -1602,8 +1602,7 @@ class DxcCompiler : public IDxcCompiler3, compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl; compiler.getCodeGenOpts().HLSLLegacyResourceReservation = Opts.LegacyResourceReservation; - compiler.getCodeGenOpts().HLSLKeepAllResources = - Opts.KeepAllResources; + compiler.getCodeGenOpts().HLSLKeepAllResources = Opts.KeepAllResources; compiler.getCodeGenOpts().HLSLDefines = defines; compiler.getCodeGenOpts().HLSLPreciseOutputs = Opts.PreciseOutputs; compiler.getCodeGenOpts().MainFileName = pMainFile;