Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ce1c397
Added -keep-all-resources to keep even optimized out resources in ref…
Nielsbishere Sep 4, 2025
fe0612c
Believe it or not, clang format
Nielsbishere Sep 4, 2025
7401388
Merge main into branch
Nielsbishere Nov 4, 2025
23881d1
Added a test to see if keep all resources works. TODO: It seems like …
Nielsbishere Nov 4, 2025
1041b0b
Updated unit test now that I've been able to correctly run it. keep a…
Nielsbishere Nov 4, 2025
c8c58da
Removed KeepAllResources from intermediate flags, because unlike cons…
Nielsbishere Nov 7, 2025
5a6913a
Added MarkUnusedResources to DxilModule, it interacts with the new fl…
Nielsbishere Nov 7, 2025
41e37b5
Merge branch 'main' of https://github.com/Microsoft/DirectXShaderComp…
Nielsbishere Nov 7, 2025
3c68d94
Added unit test for different functions in a lib file not using vs us…
Nielsbishere Nov 7, 2025
af1fe2a
Copied the complex test from consistent bindings but all resources ar…
Nielsbishere Nov 7, 2025
526f511
Clang format
Nielsbishere Nov 7, 2025
33b6805
Fixed missing initialization, causing problems in unit tests
Nielsbishere Nov 7, 2025
74a7ab0
Deleted accidental add
Nielsbishere Nov 7, 2025
e8b9862
Added -fhlsl-unused-resource-bindings<value> with options strip or re…
Nielsbishere Nov 12, 2025
24fd761
Updated unit tests
Nielsbishere Nov 12, 2025
4e25384
Clang format that somehow doesn't get formatted correctly?
Nielsbishere Nov 12, 2025
620ae36
Removed ConsistentBindings from intermediate flags and moved it to Dx…
Nielsbishere Nov 13, 2025
642044b
Updated release notes and help for a more accurate description
Nielsbishere Nov 13, 2025
0abad78
Clang format
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 `keep-all`. `strip` will strip unused resources before generating bindings for resources without a `: register`, and `keep-all` will keep them around even for reflection (while marking them with D3D_SIF_UNUSED). See [explanation](https://github.com/microsoft/DirectXShaderCompiler/pull/7643#issuecomment-3496917202) for more details.

### Version 1.8.2505

Expand Down
6 changes: 6 additions & 0 deletions include/dxc/DXIL/DxilConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@

namespace hlsl {

enum class UnusedResourceBinding : uint32_t { Strip, Reserved, KeepAll, Count };

static_assert(UnusedResourceBinding::Count <= UnusedResourceBinding(7),
"Only 3 bits are reserved for UnusedResourceBinding by HLOptions "
"and ShaderFlags");

/* <py>
import hctdb_instrhelp
</py> */
Expand Down
12 changes: 8 additions & 4 deletions include/dxc/DXIL/DxilModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@ class DxilModule {
const std::vector<std::unique_ptr<DxilResource>> &GetUAVs() const;

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

bool RenameResourcesWithPrefix(const std::string &prefix);
bool RenameResourceGlobalsWithBinding(bool bKeepName = true);
Expand Down Expand Up @@ -287,6 +289,9 @@ class DxilModule {
// Intermediate options that do not make it to DXIL
void SetLegacyResourceReservation(bool legacyResourceReservation);
bool GetLegacyResourceReservation() const;

void SetUnusedResourceBinding(UnusedResourceBinding unusedResourceBinding);
UnusedResourceBinding GetUnusedResourceBinding() const;
void ClearIntermediateOptions();

// Hull and Domain shaders.
Expand Down Expand Up @@ -344,9 +349,7 @@ class DxilModule {
DXIL::PrimitiveTopology::Undefined;
unsigned m_ActiveStreamMask = 0;

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

llvm::LLVMContext &m_Ctx;
llvm::Module *m_pModule = nullptr;
Expand Down Expand Up @@ -383,6 +386,7 @@ class DxilModule {
bool m_bUseMinPrecision = true; // use min precision by default;
bool m_bAllResourcesBound = false;
bool m_bResMayAlias = false;
UnusedResourceBinding m_unusedResourceBinding = UnusedResourceBinding::Strip;

// properties from HLModule that should not make it to the final DXIL
uint32_t m_IntermediateFlags = 0;
Expand Down
3 changes: 3 additions & 0 deletions include/dxc/DXIL/DxilResourceBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class DxilResourceBase {
llvm::Value *GetHandle() const;
bool IsAllocated() const;
bool IsUnbounded() const;
bool IsUnused() const;

void SetKind(DxilResourceBase::Kind ResourceKind);
void SetSpaceID(unsigned SpaceID);
Expand All @@ -55,6 +56,7 @@ class DxilResourceBase {
void SetGlobalName(const std::string &Name);
void SetHandle(llvm::Value *pHandle);
void SetHLSLType(llvm::Type *Ty);
void SetIsUnused(bool IsUnused);

// TODO: check whether we can make this a protected method.
void SetID(unsigned ID);
Expand All @@ -75,6 +77,7 @@ class DxilResourceBase {
unsigned m_SpaceID; // Root signature space.
unsigned m_LowerBound; // Range lower bound.
unsigned m_RangeSize; // Range size in entries.
bool m_IsUnused;
llvm::Constant *m_pSymbol; // Global variable.
std::string m_Name; // Unmangled name of the global variable.
llvm::Value
Expand Down
13 changes: 12 additions & 1 deletion include/dxc/DXIL/DxilShaderFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
namespace hlsl {
class DxilModule;
struct DxilFunctionProps;
enum class UnusedResourceBinding : uint32_t;
}

namespace llvm {
Expand Down Expand Up @@ -219,6 +220,14 @@ class ShaderFlags {
void SetRequiresGroup(bool flag) { m_bRequiresGroup = flag; }
bool GetRequiresGroup() const { return m_bRequiresGroup; }

void SetUnusedResourceBinding(UnusedResourceBinding bindings) {
m_UnusedResourceBinding = unsigned(bindings);
}

UnusedResourceBinding GetUnusedResourceBinding() {
return UnusedResourceBinding(m_UnusedResourceBinding);
}

private:
// Bit: 0
unsigned
Expand Down Expand Up @@ -359,7 +368,9 @@ class ShaderFlags {
unsigned m_bRequiresGroup : 1; // SHADER_FEATURE_OPT_REQUIRES_GROUP
// (OptFeatureInfo_RequiresGroup)

uint32_t m_align1 : 23; // align to 64 bit.
unsigned m_UnusedResourceBinding : 3;

uint32_t m_align1 : 20; // align to 64 bit.
};

} // namespace hlsl
5 changes: 3 additions & 2 deletions 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) {}
bUnusedResourceBinding(0), unused(0) {}
uint32_t GetHLOptionsRaw() const;
void SetHLOptionsRaw(uint32_t data);
unsigned bDefaultRowMajor : 1;
Expand All @@ -70,7 +70,8 @@ struct HLOptions {
unsigned bLegacyResourceReservation : 1;
unsigned bForceZeroStoreLifetimes : 1;
unsigned bResMayAlias : 1;
unsigned unused : 19;
unsigned bUnusedResourceBinding : 3;
unsigned unused : 17;
};

typedef std::unordered_map<const llvm::Function *,
Expand Down
5 changes: 4 additions & 1 deletion include/dxc/Support/HLSLOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/ArgList.h"

#include "dxc/DXIL/DxilConstants.h"
#include "dxc/Support/WinIncludes.h"

#include "dxc/dxcapi.h"
Expand Down Expand Up @@ -227,7 +228,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 UnusedResourceBinding =
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'keep-all' (keep all unused resources around but mark them with D3D_SIF_UNUSED for reflection).">;

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

Expand Down
10 changes: 8 additions & 2 deletions lib/DXIL/DxilMetadataHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,9 @@ void DxilMDHelper::GetDxilResources(const MDOperand &MDO, const MDTuple *&pSRVs,

void DxilMDHelper::EmitDxilResourceBase(const DxilResourceBase &R,
Metadata *ppMDVals[]) {
ppMDVals[kDxilResourceBaseID] = Uint32ToConstMD(R.GetID());
assert(R.GetID() < (1u << 31) && "R.GetId() out of bounds");
uint32_t idAndIsUnused = R.GetID() | (R.IsUnused() ? (1u << 31) : 0);
ppMDVals[kDxilResourceBaseID] = Uint32ToConstMD(idAndIsUnused);
Constant *GlobalSymbol = R.GetGlobalSymbol();
// For sm66+, global symbol will be mutated into handle type.
// Save hlsl type by generate bitcast on global symbol.
Expand Down Expand Up @@ -722,7 +724,11 @@ void DxilMDHelper::LoadDxilResourceBase(const MDOperand &MDO,
IFTBOOL(pTupleMD->getNumOperands() >= kDxilResourceBaseNumFields,
DXC_E_INCORRECT_DXIL_METADATA);

R.SetID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID)));
uint32_t idAndIsUnused =
ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID));

R.SetID(idAndIsUnused << 1 >> 1);
R.SetIsUnused(idAndIsUnused >> 31);
Constant *GlobalSymbol = dyn_cast<Constant>(
ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable)));
// For sm66+, global symbol will be mutated into handle type.
Expand Down
90 changes: 84 additions & 6 deletions lib/DXIL/DxilModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,15 @@ bool DxilModule::GetLegacyResourceReservation() const {
return (m_IntermediateFlags & LegacyResourceReservation) != 0;
}

void DxilModule::SetUnusedResourceBinding(
UnusedResourceBinding unusedResourceBinding) {
m_unusedResourceBinding = unusedResourceBinding;
}

UnusedResourceBinding DxilModule::GetUnusedResourceBinding() const {
return m_unusedResourceBinding;
}

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

unsigned DxilModule::GetInputControlPointCount() const {
Expand Down Expand Up @@ -1021,8 +1030,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 @@ -1031,6 +1041,7 @@ static void RemoveResourcesWithUnusedSymbolsHelper(
Constant *symbol = (*c)->GetGlobalSymbol();
symbol->removeDeadConstantUsers();
if (symbol->user_empty()) {
modif = true;
p = vec.erase(c);
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(symbol))
eraseList.insert(GV);
Expand All @@ -1044,14 +1055,80 @@ static void RemoveResourcesWithUnusedSymbolsHelper(
for (auto gv : eraseList) {
gv->eraseFromParent();
}
return modif;
}
} // namespace

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

bool DxilModule::RemoveEmptyBuffers() {

bool mod = false;
unsigned resID = 0;
std::unordered_set<GlobalVariable *>
eraseList; // Need in case of duplicate defs of lib resources

for (auto p = m_CBuffers.begin(); p != m_CBuffers.end();) {

auto c = p++;

Constant *symbol = (*c)->GetGlobalSymbol();

if (!c->get()->GetSize()) {
p = m_CBuffers.erase(c);
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(symbol))
eraseList.insert(GV);
mod = true;
continue;
}

if ((*c)->GetID() != resID)
(*c)->SetID(resID);

resID++;
}

for (auto gv : eraseList)
gv->eraseFromParent();

return mod;
}

namespace {
template <typename TResource>
static bool MarkResourcesUnused(std::vector<std::unique_ptr<TResource>> &vec) {

bool modif = false;

for (auto p = vec.begin(); p != vec.end();) {
auto c = p++;
Constant *symbol = (*c)->GetGlobalSymbol();
symbol->removeDeadConstantUsers();
if (symbol->user_empty()) {
(*c)->SetIsUnused(true);
modif = true;
continue;
}
}

return modif;
}
} // namespace

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

namespace {
Expand Down Expand Up @@ -1533,6 +1610,7 @@ void DxilModule::LoadDxilMetadata() {
m_bUseMinPrecision = !m_ShaderFlags.GetUseNativeLowPrecision();
m_bDisableOptimizations = m_ShaderFlags.GetDisableOptimizations();
m_bAllResourcesBound = m_ShaderFlags.GetAllResourcesBound();
m_unusedResourceBinding = m_ShaderFlags.GetUnusedResourceBinding();
m_bResMayAlias = !m_ShaderFlags.GetResMayNotAlias();
}

Expand Down
4 changes: 3 additions & 1 deletion lib/DXIL/DxilResourceBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace hlsl {
DxilResourceBase::DxilResourceBase(Class C)
: m_Class(C), m_Kind(Kind::Invalid), m_ID(UINT_MAX), m_SpaceID(0),
m_LowerBound(0), m_RangeSize(0), m_pSymbol(nullptr), m_pHandle(nullptr),
m_pHLSLTy(nullptr) {}
m_pHLSLTy(nullptr), m_IsUnused(false) {}

DxilResourceBase::Class DxilResourceBase::GetClass() const { return m_Class; }
DxilResourceBase::Kind DxilResourceBase::GetKind() const { return m_Kind; }
Expand Down Expand Up @@ -48,6 +48,7 @@ llvm::Type *DxilResourceBase::GetHLSLType() const {
}
bool DxilResourceBase::IsAllocated() const { return m_LowerBound != UINT_MAX; }
bool DxilResourceBase::IsUnbounded() const { return m_RangeSize == UINT_MAX; }
bool DxilResourceBase::IsUnused() const { return m_IsUnused; }

void DxilResourceBase::SetClass(Class C) { m_Class = C; }
void DxilResourceBase::SetID(unsigned ID) { m_ID = ID; }
Expand All @@ -56,6 +57,7 @@ void DxilResourceBase::SetLowerBound(unsigned LB) { m_LowerBound = LB; }
void DxilResourceBase::SetRangeSize(unsigned RangeSize) {
m_RangeSize = RangeSize;
}
void DxilResourceBase::SetIsUnused(bool IsUnused) { m_IsUnused = IsUnused; }
void DxilResourceBase::SetGlobalSymbol(llvm::Constant *pGV) { m_pSymbol = pGV; }
void DxilResourceBase::SetGlobalName(const std::string &Name) { m_Name = Name; }
void DxilResourceBase::SetHandle(llvm::Value *pHandle) { m_pHandle = pHandle; }
Expand Down
3 changes: 2 additions & 1 deletion lib/DXIL/DxilShaderFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ ShaderFlags::ShaderFlags()
m_bAdvancedTextureOps(false), m_bWriteableMSAATextures(false),
m_bReserved(false), m_bSampleCmpGradientOrBias(false),
m_bExtendedCommandInfo(false), m_bUsesDerivatives(false),
m_bRequiresGroup(false), m_align1(0) {
m_bRequiresGroup(false), m_UnusedResourceBinding(0), m_align1(0) {
// Silence unused field warnings
(void)m_align1;
}
Expand Down Expand Up @@ -412,6 +412,7 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
flag.SetUseNativeLowPrecision(!M->GetUseMinPrecision());
flag.SetDisableOptimizations(M->GetDisableOptimization());
flag.SetAllResourcesBound(M->GetAllResourcesBound());
flag.SetUnusedResourceBinding(M->GetUnusedResourceBinding());

bool hasDouble = false;
// ddiv dfma drcp d2i d2u i2d u2d.
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.UnusedResourceBinding = UnusedResourceBinding::Strip;
else if (UnusedResources == "keep-all")
opts.UnusedResourceBinding = UnusedResourceBinding::KeepAll;
else {
errors << "Error: Invalid value for -fhlsl-unused-resource-bindings option "
"specified ("
<< UnusedResources << "). Must be one of: strip, keep-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
Loading