mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-26 01:31:06 +00:00
8eddde2e70
The types of input and output variables must match for the pipeline. We cannot see the uses in all of the shader, so dead member elimination cannot safely change the type of input and output variables.
1088 lines
46 KiB
C++
1088 lines
46 KiB
C++
// Copyright (c) 2019 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "assembly_builder.h"
|
|
#include "gmock/gmock.h"
|
|
#include "pass_fixture.h"
|
|
#include "pass_utils.h"
|
|
|
|
namespace {
|
|
|
|
using namespace spvtools;
|
|
|
|
using EliminateDeadMemberTest = opt::PassTest<::testing::Test>;
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMember1) {
|
|
// Test that the member "y" is removed.
|
|
// Update OpMemberName for |y| and |z|.
|
|
// Update OpMemberDecorate for |y| and |z|.
|
|
// Update OpAccessChain for access to |z|.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
|
|
; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
|
|
; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %in_var_Position "in.var.Position"
|
|
OpName %main "main"
|
|
OpDecorate %gl_Position BuiltIn Position
|
|
OpDecorate %in_var_Position Location 0
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%int_2 = OpConstant %int 2
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%15 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%in_var_Position = OpVariable %_ptr_Input_v4float Input
|
|
%gl_Position = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %15
|
|
%17 = OpLabel
|
|
%18 = OpLoad %v4float %in_var_Position
|
|
%19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0
|
|
%20 = OpLoad %float %19
|
|
%21 = OpCompositeExtract %float %18 0
|
|
%22 = OpFAdd %float %21 %20
|
|
%23 = OpCompositeInsert %v4float %22 %18 0
|
|
%24 = OpCompositeExtract %float %18 1
|
|
%25 = OpCompositeInsert %v4float %24 %23 1
|
|
%26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
|
|
%27 = OpLoad %float %26
|
|
%28 = OpCompositeExtract %float %18 2
|
|
%29 = OpFAdd %float %28 %27
|
|
%30 = OpCompositeInsert %v4float %29 %25 2
|
|
OpStore %gl_Position %30
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberWithGroupDecorations) {
|
|
// Test that the member "y" is removed.
|
|
// Update OpGroupMemberDecorate for %type__Globals member 1 and 2.
|
|
// Update OpAccessChain for access to %type__Globals member 2.
|
|
const std::string text = R"(
|
|
; CHECK: OpDecorate [[gr1:%\w+]] Offset 0
|
|
; CHECK: OpDecorate [[gr2:%\w+]] Offset 4
|
|
; CHECK: OpDecorate [[gr3:%\w+]] Offset 8
|
|
; CHECK: [[gr1]] = OpDecorationGroup
|
|
; CHECK: [[gr2]] = OpDecorationGroup
|
|
; CHECK: [[gr3]] = OpDecorationGroup
|
|
; CHECK: OpGroupMemberDecorate [[gr1]] %type__Globals 0
|
|
; CHECK-NOT: OpGroupMemberDecorate [[gr2]]
|
|
; CHECK: OpGroupMemberDecorate [[gr3]] %type__Globals 1
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpName %_Globals "$Globals"
|
|
OpDecorate %gl_Position BuiltIn Position
|
|
OpDecorate %in_var_Position Location 0
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpDecorate %gr1 Offset 0
|
|
OpDecorate %gr2 Offset 4
|
|
OpDecorate %gr3 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%gr1 = OpDecorationGroup
|
|
%gr2 = OpDecorationGroup
|
|
%gr3 = OpDecorationGroup
|
|
OpGroupMemberDecorate %gr1 %type__Globals 0
|
|
OpGroupMemberDecorate %gr2 %type__Globals 1
|
|
OpGroupMemberDecorate %gr3 %type__Globals 2
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%int_2 = OpConstant %int 2
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%15 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%in_var_Position = OpVariable %_ptr_Input_v4float Input
|
|
%gl_Position = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %15
|
|
%17 = OpLabel
|
|
%18 = OpLoad %v4float %in_var_Position
|
|
%19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0
|
|
%20 = OpLoad %float %19
|
|
%21 = OpCompositeExtract %float %18 0
|
|
%22 = OpFAdd %float %21 %20
|
|
%23 = OpCompositeInsert %v4float %22 %18 0
|
|
%24 = OpCompositeExtract %float %18 1
|
|
%25 = OpCompositeInsert %v4float %24 %23 1
|
|
%26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
|
|
%27 = OpLoad %float %26
|
|
%28 = OpCompositeExtract %float %18 2
|
|
%29 = OpFAdd %float %28 %27
|
|
%30 = OpCompositeInsert %v4float %29 %25 2
|
|
OpStore %gl_Position %30
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// Skipping validation because of a bug in the validator. See issue #2376.
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, false);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateConstant) {
|
|
// Test that the member "x" is removed.
|
|
// Update the OpConstantComposite instruction.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
|
|
; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: OpConstantComposite %type__Globals %float_1 %float_2
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %in_var_Position "in.var.Position"
|
|
OpName %main "main"
|
|
OpDecorate %gl_Position BuiltIn Position
|
|
OpDecorate %in_var_Position Location 0
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%int = OpTypeInt 32 1
|
|
%int_1 = OpConstant %int 1
|
|
%float = OpTypeFloat 32
|
|
%float_0 = OpConstant %float 0
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%int_2 = OpConstant %int 2
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%13 = OpConstantComposite %type__Globals %float_0 %float_1 %float_2
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%19 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%in_var_Position = OpVariable %_ptr_Input_v4float Input
|
|
%gl_Position = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %19
|
|
%21 = OpLabel
|
|
%22 = OpLoad %v4float %in_var_Position
|
|
%23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1
|
|
%24 = OpLoad %float %23
|
|
%25 = OpCompositeExtract %float %22 0
|
|
%26 = OpFAdd %float %25 %24
|
|
%27 = OpCompositeInsert %v4float %26 %22 0
|
|
%28 = OpCompositeExtract %float %22 1
|
|
%29 = OpCompositeInsert %v4float %28 %27 1
|
|
%30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
|
|
%31 = OpLoad %float %30
|
|
%32 = OpCompositeExtract %float %22 2
|
|
%33 = OpFAdd %float %32 %31
|
|
%34 = OpCompositeInsert %v4float %33 %29 2
|
|
OpStore %gl_Position %34
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateCompositeConstruct) {
|
|
// Test that the member "x" is removed.
|
|
// Update the OpConstantComposite instruction.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
|
|
; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: OpCompositeConstruct %type__Globals %float_1 %float_2
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %in_var_Position "in.var.Position"
|
|
OpName %main "main"
|
|
OpDecorate %gl_Position BuiltIn Position
|
|
OpDecorate %in_var_Position Location 0
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%int = OpTypeInt 32 1
|
|
%int_1 = OpConstant %int 1
|
|
%float = OpTypeFloat 32
|
|
%float_0 = OpConstant %float 0
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%int_2 = OpConstant %int 2
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%19 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%in_var_Position = OpVariable %_ptr_Input_v4float Input
|
|
%gl_Position = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %19
|
|
%21 = OpLabel
|
|
%13 = OpCompositeConstruct %type__Globals %float_0 %float_1 %float_2
|
|
%22 = OpLoad %v4float %in_var_Position
|
|
%23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1
|
|
%24 = OpLoad %float %23
|
|
%25 = OpCompositeExtract %float %22 0
|
|
%26 = OpFAdd %float %25 %24
|
|
%27 = OpCompositeInsert %v4float %26 %22 0
|
|
%28 = OpCompositeExtract %float %22 1
|
|
%29 = OpCompositeInsert %v4float %28 %27 1
|
|
%30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
|
|
%31 = OpLoad %float %30
|
|
%32 = OpCompositeExtract %float %22 2
|
|
%33 = OpFAdd %float %32 %31
|
|
%34 = OpCompositeInsert %v4float %33 %29 2
|
|
OpStore %gl_Position %34
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract1) {
|
|
// Test that the members "x" and "z" are removed.
|
|
// Update the OpCompositeExtract instruction.
|
|
// Remove the OpCompositeInsert instruction since the member being inserted is
|
|
// dead.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
|
|
; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
|
|
; CHECK: %type__Globals = OpTypeStruct %float
|
|
; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
|
|
; CHECK: OpCompositeExtract %float [[ld]] 0
|
|
; CHECK-NOT: OpCompositeInsert
|
|
; CHECK: OpReturn
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %7
|
|
%8 = OpLabel
|
|
%9 = OpLoad %type__Globals %_Globals
|
|
%10 = OpCompositeExtract %float %9 1
|
|
%11 = OpCompositeInsert %type__Globals %10 %9 2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract2) {
|
|
// Test that the members "x" and "z" are removed.
|
|
// Update the OpCompositeExtract instruction.
|
|
// Update the OpCompositeInsert instruction.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
|
|
; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
|
|
; CHECK: %type__Globals = OpTypeStruct %float
|
|
; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
|
|
; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0
|
|
; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0
|
|
; CHECK: OpReturn
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %7
|
|
%8 = OpLabel
|
|
%9 = OpLoad %type__Globals %_Globals
|
|
%10 = OpCompositeExtract %float %9 1
|
|
%11 = OpCompositeInsert %type__Globals %10 %9 1
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract3) {
|
|
// Test that the members "x" and "z" are removed, and one member from the
|
|
// substruct. Update the OpCompositeExtract instruction. Update the
|
|
// OpCompositeInsert instruction.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
|
|
; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
|
|
; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
|
|
; CHECK: [[struct:%\w+]] = OpTypeStruct %float
|
|
; CHECK: %type__Globals = OpTypeStruct [[struct]]
|
|
; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
|
|
; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 0
|
|
; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 0
|
|
; CHECK: OpReturn
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 16
|
|
OpMemberDecorate %type__Globals 2 Offset 24
|
|
OpMemberDecorate %_struct_6 0 Offset 0
|
|
OpMemberDecorate %_struct_6 1 Offset 4
|
|
OpDecorate %type__Globals Block
|
|
%float = OpTypeFloat 32
|
|
%_struct_6 = OpTypeStruct %float %float
|
|
%type__Globals = OpTypeStruct %float %_struct_6 %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %7
|
|
%8 = OpLabel
|
|
%9 = OpLoad %type__Globals %_Globals
|
|
%10 = OpCompositeExtract %float %9 1 1
|
|
%11 = OpCompositeInsert %type__Globals %10 %9 1 1
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract4) {
|
|
// Test that the members "x" and "z" are removed, and one member from the
|
|
// substruct. Update the OpCompositeExtract instruction. Update the
|
|
// OpCompositeInsert instruction.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
|
|
; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
|
|
; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
|
|
; CHECK: [[struct:%\w+]] = OpTypeStruct %float
|
|
; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
|
|
; CHECK: %type__Globals = OpTypeStruct [[array]]
|
|
; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
|
|
; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 1 0
|
|
; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 1 0
|
|
; CHECK: OpReturn
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 16
|
|
OpMemberDecorate %type__Globals 2 Offset 80
|
|
OpMemberDecorate %_struct_6 0 Offset 0
|
|
OpMemberDecorate %_struct_6 1 Offset 4
|
|
OpDecorate %array ArrayStride 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0 ; 32-bit int, sign-less
|
|
%uint_4 = OpConstant %uint 4
|
|
%float = OpTypeFloat 32
|
|
%_struct_6 = OpTypeStruct %float %float
|
|
%array = OpTypeArray %_struct_6 %uint_4
|
|
%type__Globals = OpTypeStruct %float %array %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %7
|
|
%8 = OpLabel
|
|
%9 = OpLoad %type__Globals %_Globals
|
|
%10 = OpCompositeExtract %float %9 1 1 1
|
|
%11 = OpCompositeInsert %type__Globals %10 %9 1 1 1
|
|
OpReturn
|
|
OpFunctionEnd
|
|
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) {
|
|
// Test that the members "x" and "y" are removed.
|
|
// Member "z" is live because of the OpArrayLength instruction.
|
|
// Update the OpArrayLength instruction.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
|
|
; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
|
|
; CHECK: %type__Globals = OpTypeStruct %_runtimearr_float
|
|
; CHECK: OpArrayLength %uint %_Globals 0
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%float = OpTypeFloat 32
|
|
%_runtimearr_float = OpTypeRuntimeArray %float
|
|
%type__Globals = OpTypeStruct %float %float %_runtimearr_float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%9 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %9
|
|
%10 = OpLabel
|
|
%11 = OpLoad %type__Globals %_Globals
|
|
%12 = OpArrayLength %uint %_Globals 2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) {
|
|
// Test that all members are kept because of an OpStore.
|
|
// No change expected.
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %_Globals "$Globals2"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%9 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %9
|
|
%10 = OpLabel
|
|
%11 = OpLoad %type__Globals %_Globals
|
|
OpStore %_Globals2 %11
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) {
|
|
// Test that all members are kept because of an OpCopyMemory.
|
|
// No change expected.
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %_Globals "$Globals2"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%9 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %9
|
|
%10 = OpLabel
|
|
OpCopyMemory %_Globals2 %_Globals
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemorySized) {
|
|
// Test that all members are kept because of an OpCopyMemorySized.
|
|
// No change expected.
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
OpCapability Addresses
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %_Globals "$Globals2"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%uint_20 = OpConstant %uint 20
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%9 = OpTypeFunction %void
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %void None %9
|
|
%10 = OpLabel
|
|
OpCopyMemorySized %_Globals2 %_Globals %uint_20
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, KeepMembersOpReturnValue) {
|
|
// Test that all members are kept because of an OpCopyMemorySized.
|
|
// No change expected.
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical GLSL450
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %_Globals "$Globals2"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%uint_20 = OpConstant %uint 20
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%void = OpTypeVoid
|
|
%9 = OpTypeFunction %type__Globals
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%main = OpFunction %type__Globals None %9
|
|
%10 = OpLabel
|
|
%11 = OpLoad %type__Globals %_Globals
|
|
OpReturnValue %11
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberAccessChainWithArrays) {
|
|
// Leave only 1 member in each of the structs.
|
|
// Update OpMemberName, OpMemberDecorate, and OpAccessChain.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
|
|
; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
|
|
; CHECK: [[struct]] = OpTypeStruct %float
|
|
; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
|
|
; CHECK: %type__Globals = OpTypeStruct [[array]]
|
|
; CHECK: [[undef:%\w+]] = OpUndef %uint
|
|
; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals [[undef]] %uint_0 [[undef]] %uint_0
|
|
OpCapability Shader
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 16
|
|
OpMemberDecorate %type__Globals 2 Offset 48
|
|
OpMemberDecorate %_struct_4 0 Offset 0
|
|
OpMemberDecorate %_struct_4 1 Offset 4
|
|
OpDecorate %_arr__struct_4_uint_2 ArrayStride 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%uint_1 = OpConstant %uint 1
|
|
%uint_2 = OpConstant %uint 2
|
|
%uint_3 = OpConstant %uint 3
|
|
%float = OpTypeFloat 32
|
|
%_struct_4 = OpTypeStruct %float %float
|
|
%_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
|
|
%type__Globals = OpTypeStruct %float %_arr__struct_4_uint_2 %float
|
|
%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
|
|
%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
|
|
%void = OpTypeVoid
|
|
%15 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
|
|
%main = OpFunction %void None %15
|
|
%17 = OpLabel
|
|
%18 = OpUndef %uint
|
|
%19 = OpAccessChain %_ptr_Uniform_float %_Globals %18 %uint_1 %18 %uint_1
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberInboundsAccessChain) {
|
|
// Test that the member "y" is removed.
|
|
// Update OpMemberName for |y| and |z|.
|
|
// Update OpMemberDecorate for |y| and |z|.
|
|
// Update OpInboundsAccessChain for access to |z|.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
|
|
; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
|
|
; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
|
|
; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %uint_1
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %in_var_Position "in.var.Position"
|
|
OpName %main "main"
|
|
OpDecorate %gl_Position BuiltIn Position
|
|
OpDecorate %in_var_Position Location 0
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 8
|
|
OpDecorate %type__Globals Block
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%float = OpTypeFloat 32
|
|
%int_2 = OpConstant %int 2
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%15 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
|
|
%in_var_Position = OpVariable %_ptr_Input_v4float Input
|
|
%gl_Position = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %15
|
|
%17 = OpLabel
|
|
%18 = OpLoad %v4float %in_var_Position
|
|
%19 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
|
|
%20 = OpLoad %float %19
|
|
%21 = OpCompositeExtract %float %18 0
|
|
%22 = OpFAdd %float %21 %20
|
|
%23 = OpCompositeInsert %v4float %22 %18 0
|
|
%24 = OpCompositeExtract %float %18 1
|
|
%25 = OpCompositeInsert %v4float %24 %23 1
|
|
%26 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_2
|
|
%27 = OpLoad %float %26
|
|
%28 = OpCompositeExtract %float %18 2
|
|
%29 = OpFAdd %float %28 %27
|
|
%30 = OpCompositeInsert %v4float %29 %25 2
|
|
OpStore %gl_Position %30
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) {
|
|
// Test that the member "y" is removed.
|
|
// Update OpMemberName for |y| and |z|.
|
|
// Update OpMemberDecorate for |y| and |z|.
|
|
// Update OpInboundsAccessChain for access to |z|.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
|
|
; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
|
|
; CHECK: OpMemberDecorate %type__Globals 1 Offset 16
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
|
|
; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
|
|
; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
|
|
OpCapability Shader
|
|
OpCapability VariablePointersStorageBuffer
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%uint_1 = OpConstant %uint 1
|
|
%uint_2 = OpConstant %uint 2
|
|
%uint_3 = OpConstant %uint 3
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
|
|
%void = OpTypeVoid
|
|
%14 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
|
|
%main = OpFunction %void None %14
|
|
%16 = OpLabel
|
|
%17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
|
|
%18 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0
|
|
%19 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, RemoveMemberInBoundsPtrAccessChain) {
|
|
// Test that the member "y" is removed.
|
|
// Update OpMemberName for |y| and |z|.
|
|
// Update OpMemberDecorate for |y| and |z|.
|
|
// Update OpInboundsAccessChain for access to |z|.
|
|
const std::string text = R"(
|
|
; CHECK: OpName
|
|
; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
|
|
; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
|
|
; CHECK-NOT: OpMemberName
|
|
; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
|
|
; CHECK: OpMemberDecorate %type__Globals 1 Offset 16
|
|
; CHECK: %type__Globals = OpTypeStruct %float %float
|
|
; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
|
|
; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
|
|
; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
|
|
OpCapability Shader
|
|
OpCapability Addresses
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource HLSL 600
|
|
OpName %type__Globals "type.$Globals"
|
|
OpMemberName %type__Globals 0 "x"
|
|
OpMemberName %type__Globals 1 "y"
|
|
OpMemberName %type__Globals 2 "z"
|
|
OpName %_Globals "$Globals"
|
|
OpName %main "main"
|
|
OpDecorate %_Globals DescriptorSet 0
|
|
OpDecorate %_Globals Binding 0
|
|
OpMemberDecorate %type__Globals 0 Offset 0
|
|
OpMemberDecorate %type__Globals 1 Offset 4
|
|
OpMemberDecorate %type__Globals 2 Offset 16
|
|
OpDecorate %type__Globals Block
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%uint_1 = OpConstant %uint 1
|
|
%uint_2 = OpConstant %uint 2
|
|
%uint_3 = OpConstant %uint 3
|
|
%float = OpTypeFloat 32
|
|
%type__Globals = OpTypeStruct %float %float %float
|
|
%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
|
|
%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
|
|
%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
|
|
%void = OpTypeVoid
|
|
%14 = OpTypeFunction %void
|
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
|
%_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
|
|
%main = OpFunction %void None %14
|
|
%16 = OpLabel
|
|
%17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
|
|
%18 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0
|
|
%19 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, DontRemoveModfStructResultTypeMembers) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource HLSL 600
|
|
%float = OpTypeFloat 32
|
|
%void = OpTypeVoid
|
|
%21 = OpTypeFunction %void
|
|
%ModfStructType = OpTypeStruct %float %float
|
|
%main = OpFunction %void None %21
|
|
%22 = OpLabel
|
|
%23 = OpUndef %float
|
|
%24 = OpExtInst %ModfStructType %1 ModfStruct %23
|
|
%25 = OpCompositeExtract %float %24 1
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, DontChangeInputStructs) {
|
|
// The input for a shader has to match the type of the output from the
|
|
// previous shader in the pipeline. Because of that, we cannot change the
|
|
// types of input variables.
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %input_var
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource HLSL 600
|
|
%float = OpTypeFloat 32
|
|
%void = OpTypeVoid
|
|
%21 = OpTypeFunction %void
|
|
%in_var_type = OpTypeStruct %float %float
|
|
%in_ptr_type = OpTypePointer Input %in_var_type
|
|
%input_var = OpVariable %in_ptr_type Input
|
|
%main = OpFunction %void None %21
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
TEST_F(EliminateDeadMemberTest, DontChangeOutputStructs) {
|
|
// The output for a shader has to match the type of the output from the
|
|
// previous shader in the pipeline. Because of that, we cannot change the
|
|
// types of output variables.
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %output_var
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource HLSL 600
|
|
%float = OpTypeFloat 32
|
|
%void = OpTypeVoid
|
|
%21 = OpTypeFunction %void
|
|
%out_var_type = OpTypeStruct %float %float
|
|
%out_ptr_type = OpTypePointer Output %out_var_type
|
|
%output_var = OpVariable %out_ptr_type Output
|
|
%main = OpFunction %void None %21
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
|
|
text, /* skip_nop = */ true, /* do_validation = */ true);
|
|
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
|
}
|
|
|
|
} // namespace
|