Add support for tesc, tese and geom to EliminateDead*Components (#4990)

This commit is contained in:
Greg Fischer 2022-11-18 15:08:18 -07:00 коммит произвёл GitHub
Родитель 1a7f71afb4
Коммит 46ca66e699
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 633 добавлений и 27 удалений

Просмотреть файл

@ -28,17 +28,26 @@ namespace opt {
namespace {
constexpr uint32_t kAccessChainBaseInIdx = 0;
constexpr uint32_t kAccessChainIndex0InIdx = 1;
constexpr uint32_t kAccessChainIndex1InIdx = 2;
constexpr uint32_t kConstantValueInIdx = 0;
} // namespace
Pass::Status EliminateDeadInputComponentsPass::Process() {
// Process non-vertex only if explicitly allowed.
auto stage = context()->GetStage();
const auto stage = context()->GetStage();
if (stage != spv::ExecutionModel::Vertex && vertex_shader_only_)
return Status::SuccessWithoutChange;
// Current functionality assumes shader capability.
if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
return Status::SuccessWithoutChange;
// Current functionality assumes vert, frag, tesc, tese or geom shader.
// TODO(issue #4988): Add GLCompute.
if (stage != spv::ExecutionModel::Vertex &&
stage != spv::ExecutionModel::Fragment &&
stage != spv::ExecutionModel::TessellationControl &&
stage != spv::ExecutionModel::TessellationEvaluation &&
stage != spv::ExecutionModel::Geometry)
return Status::SuccessWithoutChange;
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = context()->get_type_mgr();
bool modified = false;
@ -52,23 +61,39 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
if (ptr_type == nullptr) {
continue;
}
const auto sclass = ptr_type->storage_class();
if (output_instead_) {
if (ptr_type->storage_class() != spv::StorageClass::Output) {
if (sclass != spv::StorageClass::Output) {
continue;
}
} else {
if (ptr_type->storage_class() != spv::StorageClass::Input) {
if (sclass != spv::StorageClass::Input) {
continue;
}
}
const analysis::Array* arr_type = ptr_type->pointee_type()->AsArray();
// For tesc, or input variables in tese or geom shaders,
// there is a outer per-vertex-array that must be ignored
// for the purposes of this analysis/optimization. Do the
// analysis on the inner type in these cases.
bool skip_first_index = false;
auto core_type = ptr_type->pointee_type();
if (stage == spv::ExecutionModel::TessellationControl ||
(sclass == spv::StorageClass::Input &&
(stage == spv::ExecutionModel::TessellationEvaluation ||
stage == spv::ExecutionModel::Geometry))) {
auto arr_type = core_type->AsArray();
if (!arr_type) continue;
core_type = arr_type->element_type();
skip_first_index = true;
}
const analysis::Array* arr_type = core_type->AsArray();
if (arr_type != nullptr) {
// Only process array if input of vertex shader, or output of
// fragment shader. Otherwise, if one shader has a runtime index and the
// other does not, interface incompatibility can occur.
if (!((ptr_type->storage_class() == spv::StorageClass::Input &&
if (!((sclass == spv::StorageClass::Input &&
stage == spv::ExecutionModel::Vertex) ||
(ptr_type->storage_class() == spv::StorageClass::Output &&
(sclass == spv::StorageClass::Output &&
stage == spv::ExecutionModel::Fragment)))
continue;
unsigned arr_len_id = arr_type->LengthId();
@ -88,13 +113,13 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
}
continue;
}
const analysis::Struct* struct_type = ptr_type->pointee_type()->AsStruct();
const analysis::Struct* struct_type = core_type->AsStruct();
if (struct_type == nullptr) continue;
const auto elt_types = struct_type->element_types();
unsigned original_max = static_cast<unsigned>(elt_types.size()) - 1;
unsigned max_idx = FindMaxIndex(var, original_max);
unsigned max_idx = FindMaxIndex(var, original_max, skip_first_index);
if (max_idx != original_max) {
ChangeStructLength(var, max_idx + 1);
ChangeIOVarStructLength(var, max_idx + 1);
vars_to_move.push_back(&var);
modified = true;
}
@ -112,13 +137,15 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
unsigned EliminateDeadInputComponentsPass::FindMaxIndex(Instruction& var,
unsigned original_max) {
unsigned EliminateDeadInputComponentsPass::FindMaxIndex(
const Instruction& var, const unsigned original_max,
const bool skip_first_index) {
unsigned max = 0;
bool seen_non_const_ac = false;
assert(var.opcode() == spv::Op::OpVariable && "must be variable");
context()->get_def_use_mgr()->WhileEachUser(
var.result_id(), [&max, &seen_non_const_ac, var, this](Instruction* use) {
var.result_id(), [&max, &seen_non_const_ac, var, skip_first_index,
this](Instruction* use) {
auto use_opcode = use->opcode();
if (use_opcode == spv::Op::OpLoad || use_opcode == spv::Op::OpStore ||
use_opcode == spv::Op::OpCopyMemory ||
@ -132,13 +159,17 @@ unsigned EliminateDeadInputComponentsPass::FindMaxIndex(Instruction& var,
return true;
}
// OpAccessChain with no indices currently not optimized
if (use->NumInOperands() == 1) {
if (use->NumInOperands() == 1 ||
(skip_first_index && use->NumInOperands() == 2)) {
seen_non_const_ac = true;
return false;
}
unsigned base_id = use->GetSingleWordInOperand(kAccessChainBaseInIdx);
const unsigned base_id =
use->GetSingleWordInOperand(kAccessChainBaseInIdx);
USE_ASSERT(base_id == var.result_id() && "unexpected base");
unsigned idx_id = use->GetSingleWordInOperand(kAccessChainIndex0InIdx);
const unsigned in_idx = skip_first_index ? kAccessChainIndex1InIdx
: kAccessChainIndex0InIdx;
const unsigned idx_id = use->GetSingleWordInOperand(in_idx);
Instruction* idx_inst = context()->get_def_use_mgr()->GetDef(idx_id);
if (idx_inst->opcode() != spv::Op::OpConstant) {
seen_non_const_ac = true;
@ -171,12 +202,17 @@ void EliminateDeadInputComponentsPass::ChangeArrayLength(Instruction& arr_var,
def_use_mgr->AnalyzeInstUse(&arr_var);
}
void EliminateDeadInputComponentsPass::ChangeStructLength(
Instruction& struct_var, unsigned length) {
void EliminateDeadInputComponentsPass::ChangeIOVarStructLength(
Instruction& io_var, unsigned length) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::Pointer* ptr_type =
type_mgr->GetType(struct_var.type_id())->AsPointer();
const analysis::Struct* struct_ty = ptr_type->pointee_type()->AsStruct();
type_mgr->GetType(io_var.type_id())->AsPointer();
auto core_type = ptr_type->pointee_type();
// Check for per-vertex-array of struct from tesc, tese and geom and grab
// embedded struct type.
const auto arr_type = core_type->AsArray();
if (arr_type) core_type = arr_type->element_type();
const analysis::Struct* struct_ty = core_type->AsStruct();
assert(struct_ty && "expecting struct type");
const auto orig_elt_types = struct_ty->element_types();
std::vector<const analysis::Type*> new_elt_types;
@ -194,14 +230,19 @@ void EliminateDeadInputComponentsPass::ChangeStructLength(
}
type_mgr->AttachDecoration(*dec, &new_struct_ty);
}
analysis::Type* reg_new_struct_ty =
type_mgr->GetRegisteredType(&new_struct_ty);
analysis::Pointer new_ptr_ty(reg_new_struct_ty, ptr_type->storage_class());
analysis::Type* reg_new_var_ty = type_mgr->GetRegisteredType(&new_struct_ty);
if (arr_type) {
analysis::Array new_arr_ty(reg_new_var_ty, arr_type->length_info());
reg_new_var_ty = type_mgr->GetRegisteredType(&new_arr_ty);
}
auto sclass =
output_instead_ ? spv::StorageClass::Output : spv::StorageClass::Input;
analysis::Pointer new_ptr_ty(reg_new_var_ty, sclass);
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
struct_var.SetResultType(new_ptr_ty_id);
io_var.SetResultType(new_ptr_ty_id);
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->AnalyzeInstUse(&struct_var);
def_use_mgr->AnalyzeInstUse(&io_var);
}
} // namespace opt

Просмотреть файл

@ -52,13 +52,15 @@ class EliminateDeadInputComponentsPass : public Pass {
// Find the max constant used to index the variable declared by |var|
// through OpAccessChain or OpInBoundsAccessChain. If any non-constant
// indices or non-Op*AccessChain use of |var|, return |original_max|.
unsigned FindMaxIndex(Instruction& var, unsigned original_max);
unsigned FindMaxIndex(const Instruction& var, const unsigned original_max,
const bool skip_first_index = false);
// Change the length of the array |inst| to |length|
void ChangeArrayLength(Instruction& inst, unsigned length);
// Change the length of the struct |struct_var| to |length|
void ChangeStructLength(Instruction& struct_var, unsigned length);
// Change the length of the struct in |io_var| to |length|. |io_var|
// is either the struct or a per-vertex-array of the struct.
void ChangeIOVarStructLength(Instruction& io_var, unsigned length);
// Process output variables instead
bool output_instead_;

Просмотреть файл

@ -686,6 +686,569 @@ TEST_F(ElimDeadInputComponentsTest, VertexOnly) {
true);
}
TEST_F(ElimDeadInputComponentsTest, TescInput) {
// Eliminate PointSize, ClipDistance, CullDistance from gl_in[]
//
// #version 450
//
// layout (vertices = 4) out;
//
// void main()
// {
// vec4 pos = gl_in[gl_InvocationID].gl_Position;
// gl_out[gl_InvocationID].gl_Position = pos;
// }
const std::string text = R"(
OpCapability Tessellation
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main" %gl_in %gl_InvocationID %gl_out
OpExecutionMode %main OutputVertices 4
OpSource GLSL 450
OpName %main "main"
OpName %pos "pos"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpMemberName %gl_PerVertex 1 "gl_PointSize"
OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex 3 "gl_CullDistance"
OpName %gl_in "gl_in"
OpName %gl_InvocationID "gl_InvocationID"
OpName %gl_PerVertex_0 "gl_PerVertex"
OpMemberName %gl_PerVertex_0 0 "gl_Position"
OpName %gl_out "gl_out"
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex Block
OpDecorate %gl_InvocationID BuiltIn InvocationId
OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
OpDecorate %gl_PerVertex_0 Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%uint_32 = OpConstant %uint 32
%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
%int = OpTypeInt 32 1
%_ptr_Input_int = OpTypePointer Input %int
%gl_InvocationID = OpVariable %_ptr_Input_int Input
%int_0 = OpConstant %int 0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_PerVertex_0 = OpTypeStruct %v4float
%uint_4 = OpConstant %uint 4
%_arr_gl_PerVertex_0_uint_4 = OpTypeArray %gl_PerVertex_0 %uint_4
%_ptr_Output__arr_gl_PerVertex_0_uint_4 = OpTypePointer Output %_arr_gl_PerVertex_0_uint_4
%gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_0_uint_4 Output
%_ptr_Output_v4float = OpTypePointer Output %v4float
; CHECK: %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
; CHECK: [[sty:%\w+]] = OpTypeStruct %v4float
; CHECK: [[asty:%\w+]] = OpTypeArray [[sty]] %uint_32
; CHECK: [[pasty:%\w+]] = OpTypePointer Input [[asty]]
; CHECK: %gl_in = OpVariable [[pasty]] Input
%main = OpFunction %void None %3
%5 = OpLabel
%pos = OpVariable %_ptr_Function_v4float Function
%21 = OpLoad %int %gl_InvocationID
%24 = OpAccessChain %_ptr_Input_v4float %gl_in %21 %int_0
%25 = OpLoad %v4float %24
OpStore %pos %25
%31 = OpLoad %int %gl_InvocationID
%32 = OpLoad %v4float %pos
%34 = OpAccessChain %_ptr_Output_v4float %gl_out %31 %int_0
OpStore %34 %32
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_3);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true, false,
false);
}
TEST_F(ElimDeadInputComponentsTest, TescOutput) {
// Eliminate PointSize, ClipDistance, CullDistance from gl_out[]
//
// #version 450
//
// layout (vertices = 4) out;
//
// void main()
// {
// vec4 pos = gl_in[gl_InvocationID].gl_Position;
// gl_out[gl_InvocationID].gl_Position = pos;
// }
const std::string text = R"(
OpCapability Tessellation
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main" %gl_in %gl_InvocationID %gl_out
OpExecutionMode %main OutputVertices 4
OpSource GLSL 450
OpName %main "main"
OpName %pos "pos"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpName %gl_in "gl_in"
OpName %gl_InvocationID "gl_InvocationID"
OpName %gl_PerVertex_0 "gl_PerVertex"
OpMemberName %gl_PerVertex_0 0 "gl_Position"
OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
OpName %gl_out "gl_out"
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpDecorate %gl_PerVertex Block
OpDecorate %gl_InvocationID BuiltIn InvocationId
OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex_0 Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float
%uint_32 = OpConstant %uint 32
%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
%int = OpTypeInt 32 1
%_ptr_Input_int = OpTypePointer Input %int
%gl_InvocationID = OpVariable %_ptr_Input_int Input
%int_0 = OpConstant %int 0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%uint_4 = OpConstant %uint 4
%_arr_gl_PerVertex_0_uint_4 = OpTypeArray %gl_PerVertex_0 %uint_4
%_ptr_Output__arr_gl_PerVertex_0_uint_4 = OpTypePointer Output %_arr_gl_PerVertex_0_uint_4
%gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_0_uint_4 Output
%_ptr_Output_v4float = OpTypePointer Output %v4float
; CHECK: [[sty:%\w+]] = OpTypeStruct %v4float
; CHECK: [[asty:%\w+]] = OpTypeArray [[sty]] %uint_4
; CHECK: [[pasty:%\w+]] = OpTypePointer Output [[asty]]
; CHECK: %gl_out = OpVariable [[pasty]] Output
%main = OpFunction %void None %3
%5 = OpLabel
%pos = OpVariable %_ptr_Function_v4float Function
%21 = OpLoad %int %gl_InvocationID
%24 = OpAccessChain %_ptr_Input_v4float %gl_in %21 %int_0
%25 = OpLoad %v4float %24
OpStore %pos %25
%31 = OpLoad %int %gl_InvocationID
%32 = OpLoad %v4float %pos
%34 = OpAccessChain %_ptr_Output_v4float %gl_out %31 %int_0
OpStore %34 %32
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_3);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true, true,
false);
}
TEST_F(ElimDeadInputComponentsTest, TeseInput) {
// Eliminate PointSize, ClipDistance, CullDistance from gl_in[]
//
// #version 450
//
// layout(triangles, ccw) in;
// layout(fractional_odd_spacing) in;
// layout(point_mode) in;
//
// void main()
// {
// vec4 p = gl_in[1].gl_Position;
// gl_Position = p;
// }
const std::string text = R"(
OpCapability Tessellation
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main" %gl_in %_
OpExecutionMode %main Triangles
OpExecutionMode %main SpacingFractionalOdd
OpExecutionMode %main VertexOrderCcw
OpExecutionMode %main PointMode
OpSource GLSL 450
OpName %main "main"
OpName %p "p"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpMemberName %gl_PerVertex 1 "gl_PointSize"
OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex 3 "gl_CullDistance"
OpName %gl_in "gl_in"
OpName %gl_PerVertex_0 "gl_PerVertex"
OpMemberName %gl_PerVertex_0 0 "gl_Position"
OpName %_ ""
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex Block
OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
OpDecorate %gl_PerVertex_0 Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%uint_32 = OpConstant %uint 32
%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_0 = OpConstant %int 0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_PerVertex_0 = OpTypeStruct %v4float
%_ptr_Output_gl_PerVertex_0 = OpTypePointer Output %gl_PerVertex_0
%_ = OpVariable %_ptr_Output_gl_PerVertex_0 Output
%_ptr_Output_v4float = OpTypePointer Output %v4float
; CHECK: %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
; CHECK: [[sty:%\w+]] = OpTypeStruct %v4float
; CHECK: [[asty:%\w+]] = OpTypeArray [[sty]] %uint_32
; CHECK: [[pasty:%\w+]] = OpTypePointer Input [[asty]]
; CHECK: %gl_in = OpVariable [[pasty]] Input
%main = OpFunction %void None %3
%5 = OpLabel
%p = OpVariable %_ptr_Function_v4float Function
%22 = OpAccessChain %_ptr_Input_v4float %gl_in %int_1 %int_0
%23 = OpLoad %v4float %22
OpStore %p %23
%27 = OpLoad %v4float %p
%29 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %29 %27
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_3);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true, false,
false);
}
TEST_F(ElimDeadInputComponentsTest, TeseOutput) {
// Eliminate PointSize, ClipDistance, CullDistance from gl_out
//
// #version 450
//
// layout(triangles, ccw) in;
// layout(fractional_odd_spacing) in;
// layout(point_mode) in;
//
// void main()
// {
// vec4 p = gl_in[1].gl_Position;
// gl_Position = p;
// }
const std::string text = R"(
OpCapability Tessellation
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main" %gl_in %_
OpExecutionMode %main Triangles
OpExecutionMode %main SpacingFractionalOdd
OpExecutionMode %main VertexOrderCcw
OpExecutionMode %main PointMode
OpSource GLSL 450
OpName %main "main"
OpName %p "p"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpName %gl_in "gl_in"
OpName %gl_PerVertex_0 "gl_PerVertex"
OpMemberName %gl_PerVertex_0 0 "gl_Position"
OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
OpName %_ ""
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpDecorate %gl_PerVertex Block
OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex_0 Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float
%uint_32 = OpConstant %uint 32
%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%int_0 = OpConstant %int 0
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%_ptr_Output_gl_PerVertex_0 = OpTypePointer Output %gl_PerVertex_0
%_ = OpVariable %_ptr_Output_gl_PerVertex_0 Output
%_ptr_Output_v4float = OpTypePointer Output %v4float
; CHECK: %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
; CHECK: %_ = OpVariable %_ptr_Output_gl_PerVertex Output
%main = OpFunction %void None %3
%5 = OpLabel
%p = OpVariable %_ptr_Function_v4float Function
%22 = OpAccessChain %_ptr_Input_v4float %gl_in %int_1 %int_0
%23 = OpLoad %v4float %22
OpStore %p %23
%27 = OpLoad %v4float %p
%29 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %29 %27
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_3);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true, true,
false);
}
TEST_F(ElimDeadInputComponentsTest, GeomInput) {
// Eliminate PointSize, ClipDistance, CullDistance from gl_in[]
//
// #version 450
//
// layout(triangle_strip, max_vertices = 3) out;
// layout(triangles) in;
//
// void main()
// {
// for (int i = 0; i < 3; i++)
// {
// gl_Position = gl_in[i].gl_Position;
// EmitVertex();
// }
// EndPrimitive();
// }
const std::string text = R"(
OpCapability Geometry
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %_ %gl_in
OpExecutionMode %main Triangles
OpExecutionMode %main Invocations 1
OpExecutionMode %main OutputTriangleStrip
OpExecutionMode %main OutputVertices 3
OpSource GLSL 460
OpName %main "main"
OpName %i "i"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpName %_ ""
OpName %gl_PerVertex_0 "gl_PerVertex"
OpMemberName %gl_PerVertex_0 0 "gl_Position"
OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
OpName %gl_in "gl_in"
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpDecorate %gl_PerVertex Block
OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex_0 Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_3 = OpConstant %int 3
%bool = OpTypeBool
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float
%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
%_ = OpVariable %_ptr_Output_gl_PerVertex Output
%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%uint_3 = OpConstant %uint 3
%_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
%_ptr_Input__arr_gl_PerVertex_0_uint_3 = OpTypePointer Input %_arr_gl_PerVertex_0_uint_3
%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_0_uint_3 Input
%_ptr_Input_v4float = OpTypePointer Input %v4float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%int_1 = OpConstant %int 1
; CHECK: [[asty:%\w+]] = OpTypeArray %gl_PerVertex %uint_3
; CHECK: [[pasty:%\w+]] = OpTypePointer Input [[asty]]
; CHECK: %gl_in = OpVariable [[pasty]] Input
%main = OpFunction %void None %3
%5 = OpLabel
%i = OpVariable %_ptr_Function_int Function
OpStore %i %int_0
OpBranch %10
%10 = OpLabel
OpLoopMerge %12 %13 None
OpBranch %14
%14 = OpLabel
%15 = OpLoad %int %i
%18 = OpSLessThan %bool %15 %int_3
OpBranchConditional %18 %11 %12
%11 = OpLabel
%32 = OpLoad %int %i
%34 = OpAccessChain %_ptr_Input_v4float %gl_in %32 %int_0
%35 = OpLoad %v4float %34
%37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %37 %35
OpEmitVertex
OpBranch %13
%13 = OpLabel
%38 = OpLoad %int %i
%40 = OpIAdd %int %38 %int_1
OpStore %i %40
OpBranch %10
%12 = OpLabel
OpEndPrimitive
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_3);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true, false,
false);
}
TEST_F(ElimDeadInputComponentsTest, GeomOutput) {
// Eliminate PointSize, ClipDistance, CullDistance from gl_out
//
// #version 450
//
// layout(triangle_strip, max_vertices = 3) out;
// layout(triangles) in;
//
// void main()
// {
// for (int i = 0; i < 3; i++)
// {
// gl_Position = gl_in[i].gl_Position;
// EmitVertex();
// }
// EndPrimitive();
// }
const std::string text = R"(
OpCapability Geometry
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %_ %gl_in
OpExecutionMode %main Triangles
OpExecutionMode %main Invocations 1
OpExecutionMode %main OutputTriangleStrip
OpExecutionMode %main OutputVertices 3
OpSource GLSL 460
OpName %main "main"
OpName %i "i"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpMemberName %gl_PerVertex 1 "gl_PointSize"
OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex 3 "gl_CullDistance"
OpName %_ ""
OpName %gl_PerVertex_0 "gl_PerVertex"
OpMemberName %gl_PerVertex_0 0 "gl_Position"
OpName %gl_in "gl_in"
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex Block
OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
OpDecorate %gl_PerVertex_0 Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_3 = OpConstant %int 3
%bool = OpTypeBool
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
%_ = OpVariable %_ptr_Output_gl_PerVertex Output
%gl_PerVertex_0 = OpTypeStruct %v4float
%uint_3 = OpConstant %uint 3
%_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
%_ptr_Input__arr_gl_PerVertex_0_uint_3 = OpTypePointer Input %_arr_gl_PerVertex_0_uint_3
%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_0_uint_3 Input
%_ptr_Input_v4float = OpTypePointer Input %v4float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%int_1 = OpConstant %int 1
; CHECK: %_ptr_Output_gl_PerVertex_0 = OpTypePointer Output %gl_PerVertex_0
; CHECK: %_ = OpVariable %_ptr_Output_gl_PerVertex_0 Output
%main = OpFunction %void None %3
%5 = OpLabel
%i = OpVariable %_ptr_Function_int Function
OpStore %i %int_0
OpBranch %10
%10 = OpLabel
OpLoopMerge %12 %13 None
OpBranch %14
%14 = OpLabel
%15 = OpLoad %int %i
%18 = OpSLessThan %bool %15 %int_3
OpBranchConditional %18 %11 %12
%11 = OpLabel
%32 = OpLoad %int %i
%34 = OpAccessChain %_ptr_Input_v4float %gl_in %32 %int_0
%35 = OpLoad %v4float %34
%37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %37 %35
OpEmitVertex
OpBranch %13
%13 = OpLabel
%38 = OpLoad %int %i
%40 = OpIAdd %int %38 %int_1
OpStore %i %40
OpBranch %10
%12 = OpLabel
OpEndPrimitive
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_VULKAN_1_3);
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<EliminateDeadInputComponentsPass>(text, true, true,
false);
}
} // namespace
} // namespace opt
} // namespace spvtools