From 1e40fa42510ac1c4ac8dfbc33f1f6fd47073e8ad Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 15 Jul 2026 11:04:29 +0100 Subject: [PATCH] Handle dummy/empty switches in SPIR-V disassembly * Slang seems to sometimes output dummy switches which aren't needed and confuse the disassembly. In cases they are needed we need to identify when a break to them short-circuits other control flow and close them. --- .../shaders/spirv/spirv_disassemble.cpp | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index c220c6ada..5657f24c6 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -286,6 +286,8 @@ rdcstr Reflector::Disassemble(const rdcstr &entryPoint, // stack of structured CFG constructs rdcarray cfgStack; + std::map escapeHatches; + // set of labels that must be printed because we have gotos for them std::set printLabels; @@ -741,6 +743,22 @@ rdcstr Reflector::Disassemble(const rdcstr &entryPoint, Id selector = switch32.selector; cfg.defaultTarget = switch32.def; + // a heuristic - ignore slang's dummy switch(0) as they are often not needed + if(constants.find(selector) != constants.end() && + specConstants.find(selector) == specConstants.end()) + { + int32_t val = EvaluateConstant(selector, {}).value.s32v[0]; + + if(val == 0 && switch32.targets.empty()) + { + // we might see a goto to this, if this is an inlined function with a return that + // needs to jump over several ifs (effectively). If we print this label, then need + // to truncate the cfgs to close the ifs + escapeHatches[cfg.mergeTarget] = cfgStack.size(); + continue; + } + } + const DataType &type = dataTypes[idTypes[selector]]; RDCASSERT(type.type == DataType::ScalarType); const uint32_t selectorWidth = type.scalar().width; @@ -1002,6 +1020,24 @@ rdcstr Reflector::Disassemble(const rdcstr &entryPoint, // print the label if we decided it was needed if(printLabels.find(decoded.result) != printLabels.end()) { + auto escapeIt = escapeHatches.find(decoded.result); + if(escapeIt != escapeHatches.end()) + { + while(cfgStack.size() > escapeIt->second) + { + indent.resize(indent.size() - 2); + + if(cfgStack.back().type == StructuredCFG::Switch) + indent.resize(indent.size() - 2); + + ret += indent; + ret += "} // escape hatch\n"; + lineNum++; + + cfgStack.pop_back(); + } + } + ret += idName(decoded.result) + ":\n"; lineNum++; }