diff --git a/include/dxc/DXIL/DxilModule.h b/include/dxc/DXIL/DxilModule.h index 3f1ba12f86..13bed6f6f0 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,8 @@ 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..70aa61fdf8 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..a7a7a93080 100644 --- a/lib/HLSL/HLModule.cpp +++ b/lib/HLSL/HLModule.cpp @@ -231,12 +231,13 @@ 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 +263,20 @@ 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..7365abec0e 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -400,6 +400,7 @@ 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..1ddad8e90c 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -1602,6 +1602,7 @@ 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;