Skip to content

Commit da36098

Browse files
authored
[SPIR-V] Add capability trimming pass (microsoft#5518)
This new optimization passes determines the required capabilities for a module, and strips unneeded capabilities. This means if some dead-code uses a capability, it won't be added as a requirement for the module anymore. This interacts with `[[vk::ext_capabilities]]` and [[vk::ext_extension]]` attributes, as the extension/capability they declare could be stripped if not required. Still markes as draft for now as there are inconsistencies with debug instruction I need to figure out: - if 2 DebugScope are generated, SPIRV-Tools squash them into 1. - seems like we started to generated the wrong ones, but test didn't saw the 2 conflicting scopes, only checked the first one.
1 parent ce8268a commit da36098

13 files changed

+107
-15
lines changed

tools/clang/lib/SPIRV/CapabilityVisitor.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,6 @@ bool CapabilityVisitor::visit(SpirvImageOp *instr) {
453453
instr->getStorageClass());
454454
if (instr->hasOffset() || instr->hasConstOffsets())
455455
addCapability(spv::Capability::ImageGatherExtended);
456-
if (instr->hasMinLod())
457-
addCapability(spv::Capability::MinLod);
458456
if (instr->isSparse())
459457
addCapability(spv::Capability::SparseResidency);
460458

@@ -864,6 +862,13 @@ bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) {
864862
addCapability(spv::Capability::Shader);
865863
addCapability(spv::Capability::Linkage);
866864
}
865+
866+
// SPIRV-Tools now has a pass to trim superfluous capabilities. This means we
867+
// can remove most capability-selection logic from here, and just add
868+
// capabilities by default. SPIRV-Tools will clean those up. Note: this pass
869+
// supports only some capabilities. This list should be expanded to match the
870+
// supported capabilities.
871+
addCapability(spv::Capability::MinLod);
867872
return true;
868873
}
869874

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -883,10 +883,10 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
883883
!dsetbindingsToCombineImageSampler.empty() ||
884884
spirvOptions.signaturePacking;
885885

886+
// Run legalization passes
886887
if (spirvOptions.codeGenHighLevel) {
887888
beforeHlslLegalization = needsLegalization;
888889
} else {
889-
// Run legalization passes
890890
if (needsLegalization) {
891891
std::string messages;
892892
if (!spirvToolsLegalize(&m, &messages,
@@ -902,8 +902,8 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
902902
}
903903
}
904904

905-
// Run optimization passes
906905
if (theCompilerInstance.getCodeGenOpts().OptimizationLevel > 0) {
906+
// Run optimization passes
907907
std::string messages;
908908
if (!spirvToolsOptimize(&m, &messages)) {
909909
emitFatalError("failed to optimize SPIR-V: %0", {}) << messages;
@@ -914,6 +914,25 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
914914
return;
915915
}
916916
}
917+
918+
// Trim unused capabilities.
919+
// When optimizations are enabled, some optimization passes like DCE could
920+
// make some capabilities useless. To avoid logic duplication between this
921+
// pass, and DXC, DXC generates some capabilities unconditionally. This
922+
// means we should run this pass, even when optimizations are disabled.
923+
{
924+
std::string messages;
925+
if (!spirvToolsTrimCapabilities(&m, &messages)) {
926+
emitFatalError("failed to trim capabilities: %0", {}) << messages;
927+
emitNote("please file a bug report on "
928+
"https://github.com/Microsoft/DirectXShaderCompiler/issues "
929+
"with source code if possible",
930+
{});
931+
return;
932+
} else if (!messages.empty()) {
933+
emitWarning("SPIR-V capability trimming: %0", {}) << messages;
934+
}
935+
}
917936
}
918937

919938
// Validate the generated SPIR-V code
@@ -13998,6 +14017,28 @@ bool SpirvEmitter::spirvToolsValidate(std::vector<uint32_t> *mod,
1399814017
return tools.Validate(mod->data(), mod->size(), options);
1399914018
}
1400014019

14020+
bool SpirvEmitter::spirvToolsTrimCapabilities(std::vector<uint32_t> *mod,
14021+
std::string *messages) {
14022+
spvtools::Optimizer optimizer(featureManager.getTargetEnv());
14023+
optimizer.SetMessageConsumer(
14024+
[messages](spv_message_level_t /*level*/, const char * /*source*/,
14025+
const spv_position_t & /*position*/,
14026+
const char *message) { *messages += message; });
14027+
14028+
string::RawOstreamBuf printAllBuf(llvm::errs());
14029+
std::ostream printAllOS(&printAllBuf);
14030+
if (spirvOptions.printAll)
14031+
optimizer.SetPrintAll(&printAllOS);
14032+
14033+
spvtools::OptimizerOptions options;
14034+
options.set_run_validator(false);
14035+
options.set_preserve_bindings(spirvOptions.preserveBindings);
14036+
14037+
optimizer.RegisterPass(spvtools::CreateTrimCapabilitiesPass());
14038+
14039+
return optimizer.Run(mod->data(), mod->size(), mod, options);
14040+
}
14041+
1400114042
bool SpirvEmitter::spirvToolsOptimize(std::vector<uint32_t> *mod,
1400214043
std::string *messages) {
1400314044
spvtools::Optimizer optimizer(featureManager.getTargetEnv());

tools/clang/lib/SPIRV/SpirvEmitter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,14 @@ class SpirvEmitter : public ASTConsumer {
11871187
/// Returns true on success and false otherwise.
11881188
bool spirvToolsOptimize(std::vector<uint32_t> *mod, std::string *messages);
11891189

1190+
// \brief Calls SPIRV-Tools optimizer's, but only with the capability trimming
1191+
// pass. Removes unused capabilities from the given SPIR-V module |mod|, and
1192+
// returns info/warning/error messages via |messages|. This pass doesn't trim
1193+
// all capabilities. To see the list of supported capabilities, check the pass
1194+
// headers.
1195+
bool spirvToolsTrimCapabilities(std::vector<uint32_t> *mod,
1196+
std::string *messages);
1197+
11901198
/// \brief Helper function to run SPIRV-Tools optimizer's legalization passes.
11911199
/// Runs the SPIRV-Tools legalization on the given SPIR-V module |mod|, and
11921200
/// gets the info/warning/error messages via |messages|. If

tools/clang/test/CodeGenSPIRV/bezier.domain.hlsl2spv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %dxc -T ds_6_0 -E BezierEvalDS %s | FileCheck %s
1+
// RUN: %dxc -T ds_6_0 -E BezierEvalDS %s -O0 | FileCheck %s
22

33
#define MAX_POINTS 4
44

@@ -200,4 +200,4 @@ DS_OUTPUT BezierEvalDS( HS_CONSTANT_DATA_OUTPUT input,
200200
// %Output = OpVariable %_ptr_Function_DS_OUTPUT Function
201201
// %83 = OpLoad %DS_OUTPUT %Output
202202
// OpReturnValue %83
203-
// OpFunctionEnd
203+
// OpFunctionEnd

tools/clang/test/CodeGenSPIRV/bezier.hull.hlsl2spv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %dxc -T hs_6_0 -E SubDToBezierHS %s | FileCheck %s
1+
// RUN: %dxc -T hs_6_0 -E SubDToBezierHS %s -O0 | FileCheck %s
22

33
#define MAX_POINTS 3
44

tools/clang/test/CodeGenSPIRV/empty-struct-interface.vs.hlsl2spv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %dxc -T vs_6_0 -E main %s | FileCheck %s
1+
// RUN: %dxc -T vs_6_0 -E main %s -O0 | FileCheck %s
22

33
// There is no interface variable for VSIn or VSOut empty structs (See OpEntryPoint below).
44

tools/clang/test/CodeGenSPIRV/passthru-cs.hlsl2spv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %dxc -T cs_6_0 -E main %s | FileCheck %s
1+
// RUN: %dxc -T cs_6_0 -E main %s -O0 | FileCheck %s
22

33
// Source: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476330(v=vs.85).aspx
44

@@ -98,4 +98,4 @@ void main( uint3 DTid : SV_DispatchThreadID )
9898
// %43 = OpAccessChain %_ptr_Uniform_uint %BufferOut %uint_0 %41
9999
// OpStore %43 %42
100100
// OpReturn
101-
// OpFunctionEnd
101+
// OpFunctionEnd

tools/clang/test/CodeGenSPIRV/passthru-ps.hlsl2spv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %dxc -T ps_6_0 -E main %s | FileCheck %s
1+
// RUN: %dxc -T ps_6_0 -E main %s -O0 | FileCheck %s
22

33
float4 main(float4 input: COLOR): SV_Target
44
{
@@ -49,4 +49,4 @@ float4 main(float4 input: COLOR): SV_Target
4949
// %bb_entry = OpLabel
5050
// %19 = OpLoad %v4float %input
5151
// OpReturnValue %19
52-
// OpFunctionEnd
52+
// OpFunctionEnd

tools/clang/test/CodeGenSPIRV/passthru-vs.hlsl2spv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %dxc -T vs_6_0 -E main %s | FileCheck %s
1+
// RUN: %dxc -T vs_6_0 -E main %s -O0 | FileCheck %s
22

33
struct PSInput {
44
float4 position : SV_Position;
@@ -86,4 +86,4 @@ PSInput main(float4 position: POSITION, float4 color: COLOR) {
8686
// OpStore %35 %34
8787
// %36 = OpLoad %PSInput %result
8888
// OpReturnValue %36
89-
// OpFunctionEnd
89+
// OpFunctionEnd

0 commit comments

Comments
 (0)