Skip to content

Commit a7be3a7

Browse files
authored
spirv-opt: add Geometry capability to the trim pass (KhronosGroup#6278)
Adds support to strip Geometry capability from a module when not used. The capability is required by other instructions, but all require the Geometry execution mode, meaning checking OpEntryPoint or OpConditionalEntryPointINTEL is enough. 2 tests are disabled for now: KhronosGroup#6277 Related to microsoft/DirectXShaderCompiler#7715
1 parent 6c6152b commit a7be3a7

File tree

3 files changed

+185
-15
lines changed

3 files changed

+185
-15
lines changed

source/opt/trim_capabilities_pass.cpp

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace opt {
3838

3939
namespace {
4040
constexpr uint32_t kOpTypeFloatSizeIndex = 0;
41+
constexpr uint32_t kOpEntryPointExecutionModelIndex = 0;
4142
constexpr uint32_t kOpTypePointerStorageClassIndex = 0;
4243
constexpr uint32_t kTypeArrayTypeIndex = 0;
4344
constexpr uint32_t kOpTypeScalarBitWidthIndex = 0;
@@ -168,6 +169,30 @@ static std::optional<spv::Capability> Handler_OpTypeFloat_Float64(
168169
return size == 64 ? std::optional(spv::Capability::Float64) : std::nullopt;
169170
}
170171

172+
static std::optional<spv::Capability> Handler_OpEntryPoint_Geometry(
173+
const Instruction* instruction) {
174+
assert(instruction->opcode() == spv::Op::OpEntryPoint &&
175+
"This handler only support OpEntryPoint opcodes.");
176+
177+
auto execution_model = spv::ExecutionModel(
178+
instruction->GetSingleWordInOperand(kOpEntryPointExecutionModelIndex));
179+
return execution_model == spv::ExecutionModel::Geometry
180+
? std::optional(spv::Capability::Geometry)
181+
: std::nullopt;
182+
}
183+
184+
static std::optional<spv::Capability>
185+
Handler_OpConditionalEntryPointINTEL_Geometry(const Instruction* instruction) {
186+
assert(instruction->opcode() == spv::Op::OpConditionalEntryPointINTEL &&
187+
"This handler only support OpConditionalEntryPointINTEL opcodes.");
188+
189+
auto execution_model =
190+
spv::ExecutionModel(instruction->GetSingleWordInOperand(1));
191+
return execution_model == spv::ExecutionModel::Geometry
192+
? std::optional(spv::Capability::Geometry)
193+
: std::nullopt;
194+
}
195+
171196
static std::optional<spv::Capability>
172197
Handler_OpTypePointer_StorageInputOutput16(const Instruction* instruction) {
173198
assert(instruction->opcode() == spv::Op::OpTypePointer &&
@@ -425,22 +450,24 @@ Handler_OpImageSparseRead_StorageImageReadWithoutFormat(
425450
}
426451

427452
// Opcode of interest to determine capabilities requirements.
428-
constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 14> kOpcodeHandlers{{
453+
constexpr std::array<std::pair<spv::Op, OpcodeHandler>, 16> kOpcodeHandlers{{
429454
// clang-format off
430-
{spv::Op::OpImageRead, Handler_OpImageRead_StorageImageReadWithoutFormat},
431-
{spv::Op::OpImageWrite, Handler_OpImageWrite_StorageImageWriteWithoutFormat},
432-
{spv::Op::OpImageSparseRead, Handler_OpImageSparseRead_StorageImageReadWithoutFormat},
433-
{spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float16 },
434-
{spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float64 },
435-
{spv::Op::OpTypeImage, Handler_OpTypeImage_ImageMSArray},
436-
{spv::Op::OpTypeInt, Handler_OpTypeInt_Int16 },
437-
{spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 },
438-
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16},
439-
{spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16},
440-
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16},
441-
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16},
442-
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16},
443-
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageBuffer16BitAccess},
455+
{spv::Op::OpImageRead, Handler_OpImageRead_StorageImageReadWithoutFormat},
456+
{spv::Op::OpImageWrite, Handler_OpImageWrite_StorageImageWriteWithoutFormat},
457+
{spv::Op::OpImageSparseRead, Handler_OpImageSparseRead_StorageImageReadWithoutFormat},
458+
{spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float16 },
459+
{spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float64 },
460+
{spv::Op::OpTypeImage, Handler_OpTypeImage_ImageMSArray},
461+
{spv::Op::OpTypeInt, Handler_OpTypeInt_Int16 },
462+
{spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 },
463+
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16},
464+
{spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16},
465+
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16},
466+
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16},
467+
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16},
468+
{spv::Op::OpTypePointer, Handler_OpTypePointer_StorageBuffer16BitAccess},
469+
{spv::Op::OpEntryPoint, Handler_OpEntryPoint_Geometry },
470+
{spv::Op::OpConditionalEntryPointINTEL, Handler_OpConditionalEntryPointINTEL_Geometry },
444471
// clang-format on
445472
}};
446473

source/opt/trim_capabilities_pass.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class TrimCapabilitiesPass : public Pass {
8282
spv::Capability::FragmentShaderPixelInterlockEXT,
8383
spv::Capability::FragmentShaderSampleInterlockEXT,
8484
spv::Capability::FragmentShaderShadingRateInterlockEXT,
85+
spv::Capability::Geometry,
8586
spv::Capability::GroupNonUniform,
8687
spv::Capability::GroupNonUniformArithmetic,
8788
spv::Capability::GroupNonUniformClustered,

test/opt/trim_capabilities_pass_test.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3635,6 +3635,148 @@ TEST_F(TrimCapabilitiesPassTest, PhysicalStorageBuffer_RecursiveTypes) {
36353635
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
36363636
}
36373637

3638+
TEST_F(TrimCapabilitiesPassTest, Geometry_Remains) {
3639+
const std::string kTest = R"(
3640+
OpCapability Geometry
3641+
; CHECK: OpCapability Geometry
3642+
OpMemoryModel Logical GLSL450
3643+
OpEntryPoint Geometry %gs_main "gs_main" %gl_Position
3644+
OpExecutionMode %gs_main OutputVertices 3
3645+
OpExecutionMode %gs_main Invocations 1
3646+
OpExecutionMode %gs_main Triangles
3647+
OpExecutionMode %gs_main OutputTriangleStrip
3648+
OpSource HLSL 660
3649+
OpName %gs_main "gs_main"
3650+
OpDecorate %gl_Position BuiltIn Position
3651+
%float = OpTypeFloat 32
3652+
%v4float = OpTypeVector %float 4
3653+
%_ptr_Output_v4float = OpTypePointer Output %v4float
3654+
%void = OpTypeVoid
3655+
%7 = OpTypeFunction %void
3656+
%gl_Position = OpVariable %_ptr_Output_v4float Output
3657+
%gs_main = OpFunction %void None %7
3658+
%8 = OpLabel
3659+
OpEmitVertex
3660+
OpReturn
3661+
OpFunctionEnd
3662+
)";
3663+
const auto result =
3664+
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
3665+
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
3666+
}
3667+
3668+
// FIXME(6277): enable once spirv-opt supports SPV_INTEL_function_variants
3669+
#if 0
3670+
TEST_F(TrimCapabilitiesPassTest, Geometry_RemainsIntel) {
3671+
const std::string kTest = R"(
3672+
OpCapability Geometry
3673+
; CHECK: OpCapability Geometry
3674+
OpCapability SpecConditionalINTEL
3675+
OpExtension "SPV_INTEL_function_variants"
3676+
OpMemoryModel Logical GLSL450
3677+
OpConditionalEntryPointINTEL %false Geometry %gs_main "gs_main"
3678+
OpExecutionMode %gs_main OutputVertices 3
3679+
OpExecutionMode %gs_main Invocations 1
3680+
OpExecutionMode %gs_main Triangles
3681+
OpExecutionMode %gs_main OutputTriangleStrip
3682+
OpSource HLSL 660
3683+
OpName %gs_main "gs_main"
3684+
OpDecorate %gl_Position BuiltIn Position
3685+
%bool = OpTypeBool
3686+
%false = OpSpecConstantFalse %bool
3687+
%float = OpTypeFloat 32
3688+
%v4float = OpTypeVector %float 4
3689+
%_ptr_Output_v4float = OpTypePointer Output %v4float
3690+
%void = OpTypeVoid
3691+
%7 = OpTypeFunction %void
3692+
%gl_Position = OpVariable %_ptr_Output_v4float Output
3693+
%gs_main = OpFunction %void None %7
3694+
%8 = OpLabel
3695+
OpEmitVertex
3696+
OpReturn
3697+
OpFunctionEnd
3698+
)";
3699+
const auto result =
3700+
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
3701+
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
3702+
}
3703+
#endif
3704+
3705+
TEST_F(TrimCapabilitiesPassTest, Geometry_Removed) {
3706+
const std::string kTest = R"(
3707+
OpCapability Shader
3708+
OpCapability Geometry
3709+
; CHECK-NOT: OpCapability Geometry
3710+
OpMemoryModel Logical GLSL450
3711+
OpEntryPoint Fragment %ps_main "ps_main" %in_var_POSITION %out_var_SV_Target
3712+
OpExecutionMode %ps_main OriginUpperLeft
3713+
OpSource HLSL 660
3714+
OpName %in_var_POSITION "in.var.POSITION"
3715+
OpName %out_var_SV_Target "out.var.SV_Target"
3716+
OpName %ps_main "ps_main"
3717+
OpDecorate %in_var_POSITION Location 0
3718+
OpDecorate %out_var_SV_Target Location 0
3719+
%float = OpTypeFloat 32
3720+
%v4float = OpTypeVector %float 4
3721+
%_ptr_Input_v4float = OpTypePointer Input %v4float
3722+
%_ptr_Output_v4float = OpTypePointer Output %v4float
3723+
%void = OpTypeVoid
3724+
%9 = OpTypeFunction %void
3725+
%in_var_POSITION = OpVariable %_ptr_Input_v4float Input
3726+
%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
3727+
%ps_main = OpFunction %void None %9
3728+
%10 = OpLabel
3729+
%11 = OpLoad %v4float %in_var_POSITION
3730+
OpStore %out_var_SV_Target %11
3731+
OpReturn
3732+
OpFunctionEnd
3733+
)";
3734+
const auto result =
3735+
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
3736+
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
3737+
}
3738+
3739+
// FIXME(6277): enable once spirv-opt supports SPV_INTEL_function_variants
3740+
#if 0
3741+
TEST_F(TrimCapabilitiesPassTest, Geometry_RemovedIntel) {
3742+
const std::string kTest = R"(
3743+
OpCapability Shader
3744+
OpCapability Geometry
3745+
; CHECK-NOT: OpCapability Geometry
3746+
OpCapability SpecConditionalINTEL
3747+
OpExtension "SPV_INTEL_function_variants"
3748+
OpMemoryModel Logical GLSL450
3749+
OpConditionalEntryPointINTEL %false Fragment %ps_main "ps_main" %in_var_POSITION %out_var_SV_Target
3750+
OpExecutionMode %ps_main OriginUpperLeft
3751+
OpSource HLSL 660
3752+
OpName %in_var_POSITION "in.var.POSITION"
3753+
OpName %out_var_SV_Target "out.var.SV_Target"
3754+
OpName %ps_main "ps_main"
3755+
OpDecorate %in_var_POSITION Location 0
3756+
OpDecorate %out_var_SV_Target Location 0
3757+
%bool = OpTypeBool
3758+
%false = OpSpecConstantFalse %bool
3759+
%float = OpTypeFloat 32
3760+
%v4float = OpTypeVector %float 4
3761+
%_ptr_Input_v4float = OpTypePointer Input %v4float
3762+
%_ptr_Output_v4float = OpTypePointer Output %v4float
3763+
%void = OpTypeVoid
3764+
%9 = OpTypeFunction %void
3765+
%in_var_POSITION = OpVariable %_ptr_Input_v4float Input
3766+
%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
3767+
%ps_main = OpFunction %void None %9
3768+
%10 = OpLabel
3769+
%11 = OpLoad %v4float %in_var_POSITION
3770+
OpStore %out_var_SV_Target %11
3771+
OpReturn
3772+
OpFunctionEnd
3773+
)";
3774+
const auto result =
3775+
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
3776+
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
3777+
}
3778+
#endif
3779+
36383780
INSTANTIATE_TEST_SUITE_P(
36393781
TrimCapabilitiesPassTestSubgroupClustered_Unsigned_I,
36403782
TrimCapabilitiesPassTestSubgroupClustered_Unsigned,

0 commit comments

Comments
 (0)