Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9887b09
Added rewriter option ConsistentBindings (-consistent-bindings) for t…
Nielsbishere Jul 14, 2025
8454274
Option -consistent-bindings now properly generates bindings for not f…
Nielsbishere Jul 15, 2025
f60c594
Added a test for generating consistent bindings and changed tests to …
Nielsbishere Jul 15, 2025
74283d1
Applied clang format
Nielsbishere Jul 16, 2025
6f5689d
Now supporting multi dimensional register arrays for -consistent-bind…
Nielsbishere Aug 3, 2025
26a7f54
Removed rewriter option -consistent-bindings and now doing it in the …
Nielsbishere Sep 1, 2025
b63cdd2
Reset some incorrect merges
Nielsbishere Sep 1, 2025
8d7dc86
Cleanup for PR
Nielsbishere Sep 1, 2025
298ff34
clang format
Nielsbishere Sep 1, 2025
28b24f1
Clang format again
Nielsbishere Sep 1, 2025
cb9f345
Added two unit tests; one for more complex scenarios (e.g. overlappin…
Nielsbishere Nov 5, 2025
777a50e
RemoveResourcesWithUnusedSymbolsHelper and RemoveResourcesWithUnusedS…
Nielsbishere Nov 6, 2025
3fc2f2e
Applied clang format
Nielsbishere Nov 6, 2025
f5c545b
Merge upstream into fork
Nielsbishere Nov 6, 2025
ea760bf
Fixed an issue where resources without a global variable would not pr…
Nielsbishere Nov 7, 2025
9169ce0
Added -fhlsl-unused-resource-bindings<value> with options strip or re…
Nielsbishere Nov 12, 2025
6a15db9
Updated unit tests
Nielsbishere Nov 12, 2025
895724d
Merge branch 'main' of https://github.com/Microsoft/DirectXShaderComp…
Nielsbishere Nov 12, 2025
a633dc6
Clang format that somehow doesn't get formatted correctly?
Nielsbishere Nov 12, 2025
316e493
PR feedback, re. reserve-all, bChanged and revert formatting done to …
Nielsbishere Nov 13, 2025
68f20d6
Merge branch 'rewriter_generate_consistent_bindings' of https://githu…
Nielsbishere Nov 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The included licenses apply to the following files:
- Fixed regression: [#7508](https://github.com/microsoft/DirectXShaderCompiler/issues/7508) crash when calling `Load` with `status`.
- Header file `dxcpix.h` was added to the release package.
- Moved Linear Algebra (Cooperative Vector) DXIL Opcodes to experimental Shader Model 6.10
- Added `-fhlsl-unused-resource-bindings=<value>` an option to allow deciding on how to treat unused resource bindings in DXIL; `strip` (default) or `reserve-all`. `strip` will strip unused resources before generating bindings for resources without a `: register`, and `reserve-all` will keep them reserved for generated bindings while stripping them afterwards. See [explanation](https://github.com/microsoft/DirectXShaderCompiler/pull/7643#issuecomment-3496917202) for more details.

### Version 1.8.2505

Expand Down
5 changes: 4 additions & 1 deletion include/dxc/DXIL/DxilModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class DxilModule {
const std::vector<std::unique_ptr<DxilResource>> &GetUAVs() const;

void RemoveUnusedResources();
void RemoveResourcesWithUnusedSymbols();
bool RemoveResourcesWithUnusedSymbols();
void RemoveFunction(llvm::Function *F);

bool RenameResourcesWithPrefix(const std::string &prefix);
Expand Down Expand Up @@ -287,6 +287,8 @@ class DxilModule {
// Intermediate options that do not make it to DXIL
void SetLegacyResourceReservation(bool legacyResourceReservation);
bool GetLegacyResourceReservation() const;
void SetConsistentBindings(bool consistentBindings);
bool GetConsistentBindings() const;
void ClearIntermediateOptions();

// Hull and Domain shaders.
Expand Down Expand Up @@ -346,6 +348,7 @@ class DxilModule {

enum IntermediateFlags : uint32_t {
LegacyResourceReservation = 1 << 0,
ConsistentBindings = 1 << 1
};

llvm::LLVMContext &m_Ctx;
Expand Down
3 changes: 2 additions & 1 deletion include/dxc/HLSL/HLModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct HLOptions {
bDisableOptimizations(false), PackingStrategy(0),
bUseMinPrecision(false), bDX9CompatMode(false), bFXCCompatMode(false),
bLegacyResourceReservation(false), bForceZeroStoreLifetimes(false),
unused(0) {}
bConsistentBindings(false), unused(0) {}
uint32_t GetHLOptionsRaw() const;
void SetHLOptionsRaw(uint32_t data);
unsigned bDefaultRowMajor : 1;
Expand All @@ -70,6 +70,7 @@ struct HLOptions {
unsigned bLegacyResourceReservation : 1;
unsigned bForceZeroStoreLifetimes : 1;
unsigned bResMayAlias : 1;
unsigned bConsistentBindings : 1;
unsigned unused : 19;
};

Expand Down
6 changes: 5 additions & 1 deletion include/dxc/Support/HLSLOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ enum HlslFlags {
RewriteOption = (1 << 17),
};

enum class UnusedResourceBinding { Strip, ReserveAll };

enum ID {
OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
Expand Down Expand Up @@ -227,7 +229,9 @@ class DxcOpts {
std::string TimeTrace = ""; // OPT_ftime_trace[EQ]
unsigned TimeTraceGranularity = 500; // OPT_ftime_trace_granularity_EQ
bool VerifyDiagnostics = false; // OPT_verify
bool Verbose = false; // OPT_verbose
UnusedResourceBinding UnusedResources =
UnusedResourceBinding::Strip; // OPT_fhlsl_unused_resource_bindings_EQ
bool Verbose = false; // OPT_verbose

// Optimization pass enables, disables and selects
OptimizationToggles
Expand Down
3 changes: 3 additions & 0 deletions include/dxc/Support/HLSLOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,9 @@ def getprivate : JoinedOrSeparate<["-", "/"], "getprivate">, Flags<[DriverOption
def nologo : Flag<["-", "/"], "nologo">, Group<hlslcore_Group>, Flags<[DriverOption, HelpHidden]>,
HelpText<"Suppress copyright message">;

def fhlsl_unused_resource_bindings_EQ : Joined<["-"], "fhlsl-unused-resource-bindings=">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
HelpText<"Control handling of unused resource bindings:\n\t\t\t'strip' (default, unused resources are stripped and their binding slots are freed up).\n\t\t\t'reserve-all' (do not use binding slots of unused resources when assigning bindings).">;

//////////////////////////////////////////////////////////////////////////////
// Rewriter Options

Expand Down
27 changes: 21 additions & 6 deletions lib/DXIL/DxilModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,16 @@ bool DxilModule::GetLegacyResourceReservation() const {
return (m_IntermediateFlags & LegacyResourceReservation) != 0;
}

void DxilModule::SetConsistentBindings(bool consistentBindings) {
m_IntermediateFlags &= ~ConsistentBindings;
if (consistentBindings)
m_IntermediateFlags |= ConsistentBindings;
}

bool DxilModule::GetConsistentBindings() const {
return (m_IntermediateFlags & ConsistentBindings) != 0;
}

void DxilModule::ClearIntermediateOptions() { m_IntermediateFlags = 0; }

unsigned DxilModule::GetInputControlPointCount() const {
Expand Down Expand Up @@ -1021,8 +1031,9 @@ void DxilModule::RemoveUnusedResources() {

namespace {
template <typename TResource>
static void RemoveResourcesWithUnusedSymbolsHelper(
static bool RemoveResourcesWithUnusedSymbolsHelper(
std::vector<std::unique_ptr<TResource>> &vec) {
bool modif = false;
unsigned resID = 0;
std::unordered_set<GlobalVariable *>
eraseList; // Need in case of duplicate defs of lib resources
Expand All @@ -1034,6 +1045,7 @@ static void RemoveResourcesWithUnusedSymbolsHelper(
p = vec.erase(c);
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(symbol))
eraseList.insert(GV);
modif = true;
continue;
}
if ((*c)->GetID() != resID) {
Expand All @@ -1044,14 +1056,17 @@ static void RemoveResourcesWithUnusedSymbolsHelper(
for (auto gv : eraseList) {
gv->eraseFromParent();
}
return modif;
}
} // namespace

void DxilModule::RemoveResourcesWithUnusedSymbols() {
RemoveResourcesWithUnusedSymbolsHelper(m_SRVs);
RemoveResourcesWithUnusedSymbolsHelper(m_UAVs);
RemoveResourcesWithUnusedSymbolsHelper(m_CBuffers);
RemoveResourcesWithUnusedSymbolsHelper(m_Samplers);
bool DxilModule::RemoveResourcesWithUnusedSymbols() {
bool modif = false;
modif |= RemoveResourcesWithUnusedSymbolsHelper(m_SRVs);
modif |= RemoveResourcesWithUnusedSymbolsHelper(m_UAVs);
modif |= RemoveResourcesWithUnusedSymbolsHelper(m_CBuffers);
modif |= RemoveResourcesWithUnusedSymbolsHelper(m_Samplers);
return modif;
}

namespace {
Expand Down
15 changes: 15 additions & 0 deletions lib/DxcSupport/HLSLOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,21 @@ 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);

std::string UnusedResources =
Args.getLastArgValue(OPT_fhlsl_unused_resource_bindings_EQ, "strip");

if (UnusedResources == "strip")
opts.UnusedResources = UnusedResourceBinding::Strip;
else if (UnusedResources == "reserve-all")
opts.UnusedResources = UnusedResourceBinding::ReserveAll;
else {
errors << "Error: Invalid value for -fhlsl-unused-resource-bindings option "
"specified ("
<< UnusedResources << "). Must be one of: strip, reserve-all";
return 1;
}

opts.Verbose = Args.hasFlag(OPT_verbose, OPT_INVALID, false);
if (Args.hasArg(OPT_ftime_trace_EQ))
opts.TimeTrace = Args.getLastArgValue(OPT_ftime_trace_EQ);
Expand Down
11 changes: 7 additions & 4 deletions lib/HLSL/DxilCondenseResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,27 +550,30 @@ class DxilLowerCreateHandleForLib : public ModulePass {
ResourceRegisterAllocator.GatherReservedRegisters(DM);

// Remove unused resources.
DM.RemoveResourcesWithUnusedSymbols();
if (!DM.GetConsistentBindings())
bChanged |= DM.RemoveResourcesWithUnusedSymbols();

unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() +
DM.GetSRVs().size() + DM.GetSamplers().size();
bChanged = bChanged || (numResources != newResources);

if (0 == newResources)
return bChanged;

{
DxilValueCache *DVC = &getAnalysis<DxilValueCache>();
bool bLocalChanged = LegalizeResources(M, DVC);
if (bLocalChanged) {
if (bLocalChanged && !DM.GetConsistentBindings()) {
// Remove unused resources.
DM.RemoveResourcesWithUnusedSymbols();
bChanged |= DM.RemoveResourcesWithUnusedSymbols();
}
bChanged |= bLocalChanged;
}

bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);

if (DM.GetConsistentBindings())
bChanged |= DM.RemoveResourcesWithUnusedSymbols();

// Fill in top-level CBuffer variable usage bit
UpdateCBufferUsage();

Expand Down
1 change: 1 addition & 0 deletions lib/HLSL/DxilGenerationPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.SetConsistentBindings(H.GetHLOptions().bConsistentBindings);
// bool m_bDisableMathRefactoring;
// bool m_bEnableDoublePrecision;
// bool m_bEnableDoubleExtensions;
Expand Down
20 changes: 14 additions & 6 deletions lib/HLSL/HLModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,19 @@ void HLModule::RemoveFunction(llvm::Function *F) {
namespace {
template <typename TResource>
bool RemoveResource(std::vector<std::unique_ptr<TResource>> &vec,
GlobalVariable *pVariable, bool keepAllocated) {
GlobalVariable *pVariable, bool keepAllocated,
bool consistentBindings) {
for (auto p = vec.begin(), e = vec.end(); p != e; ++p) {
if ((*p)->GetGlobalSymbol() != pVariable)
continue;

if (keepAllocated && (*p)->IsAllocated()) {
if ((keepAllocated && (*p)->IsAllocated()) || consistentBindings) {
// Keep the resource, but it has no more symbol.
(*p)->SetGlobalSymbol(UndefValue::get(pVariable->getType()));
} else {
// Erase the resource alltogether and update IDs of subsequent ones
p = vec.erase(p);

for (e = vec.end(); p != e; ++p) {
unsigned ID = (*p)->GetID() - 1;
(*p)->SetID(ID);
Expand All @@ -262,16 +264,22 @@ void HLModule::RemoveGlobal(llvm::GlobalVariable *GV) {
// register range from being allocated to other resources.
bool keepAllocated = GetHLOptions().bLegacyResourceReservation;

// Consistent bindings are different than -flegacy-resource-reservation;
// We need the IDs to stay the same, but it's fine to remove unused registers.
// It's actually wanted, because that allows us to know what registers are
// optimized out.
bool consistentBindings = GetHLOptions().bConsistentBindings;

// 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, consistentBindings))
return;
if (RemoveResource(m_SRVs, GV, keepAllocated))
if (RemoveResource(m_SRVs, GV, keepAllocated, consistentBindings))
return;
if (RemoveResource(m_UAVs, GV, keepAllocated))
if (RemoveResource(m_UAVs, GV, keepAllocated, consistentBindings))
return;
if (RemoveResource(m_Samplers, GV, keepAllocated))
if (RemoveResource(m_Samplers, GV, keepAllocated, consistentBindings))
return;
// TODO: do m_TGSMVariables and m_StreamOutputs need maintenance?
}
Expand Down
2 changes: 2 additions & 0 deletions tools/clang/include/clang/Frontend/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
bool HLSLOnlyWarnOnUnrollFail = false;
/// Whether use legacy resource reservation.
bool HLSLLegacyResourceReservation = false;
/// Whether to keep bindings consistent even if optimized out.
bool HLSLConsistentBindings = false;
/// Set [branch] on every if.
bool HLSLPreferControlFlow = false;
/// Set [flatten] on every if.
Expand Down
1 change: 1 addition & 0 deletions tools/clang/lib/CodeGen/CGHLSLMS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM)
opts.PackingStrategy = CGM.getCodeGenOpts().HLSLSignaturePackingStrategy;
opts.bLegacyResourceReservation =
CGM.getCodeGenOpts().HLSLLegacyResourceReservation;
opts.bConsistentBindings = CGM.getCodeGenOpts().HLSLConsistentBindings;
opts.bForceZeroStoreLifetimes =
CGM.getCodeGenOpts().HLSLForceZeroStoreLifetimes;

Expand Down
Loading
Loading