SPIRV-Tools/test/opt/vector_dce_test.cpp
Steven Perron 9ba0879ddf Improve Vector DCE
Track live scalars in VDCE as if they were single element vectors.

Handle the extended instructions for GLSL in VDCE.

Handle composite construct instructions in VDCE.
2018-04-30 11:55:50 -04:00

1082 lines
33 KiB
C++

// Copyright (c) 2018 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 "pass_fixture.h"
#include "pass_utils.h"
namespace {
using namespace spvtools;
using VectorDCETest = PassTest<::testing::Test>;
TEST_F(VectorDCETest, InsertAfterInsertElim) {
// With two insertions to the same offset, the first is dead.
//
// Note: The SPIR-V assembly has had store/load elimination
// performed to allow the inserts and extracts to directly
// reference each other.
//
// #version 450
//
// layout (location=0) in float In0;
// layout (location=1) in float In1;
// layout (location=2) in vec2 In2;
// layout (location=0) out vec4 OutColor;
//
// void main()
// {
// vec2 v = In2;
// v.x = In0 + In1; // dead
// v.x = 0.0;
// OutColor = v.xyxy;
// }
const std::string before_predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In2 %In0 %In1 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In2 "In2"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %OutColor "OutColor"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_b"
OpMemberName %_Globals_ 1 "g_n"
OpName %_ ""
OpDecorate %In2 Location 2
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %OutColor Location 0
OpMemberDecorate %_Globals_ 0 Offset 0
OpMemberDecorate %_Globals_ 1 Offset 4
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
%void = OpTypeVoid
%11 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%_ptr_Function_v2float = OpTypePointer Function %v2float
%_ptr_Input_v2float = OpTypePointer Input %v2float
%In2 = OpVariable %_ptr_Input_v2float Input
%_ptr_Input_float = OpTypePointer Input %float
%In0 = OpVariable %_ptr_Input_float Input
%In1 = OpVariable %_ptr_Input_float Input
%uint = OpTypeInt 32 0
%_ptr_Function_float = OpTypePointer Function %float
%float_0 = OpConstant %float 0
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%int = OpTypeInt 32 1
%_Globals_ = OpTypeStruct %uint %int
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
)";
const std::string after_predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In2 %In0 %In1 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In2 "In2"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %OutColor "OutColor"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_b"
OpMemberName %_Globals_ 1 "g_n"
OpName %_ ""
OpDecorate %In2 Location 2
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %OutColor Location 0
OpMemberDecorate %_Globals_ 0 Offset 0
OpMemberDecorate %_Globals_ 1 Offset 4
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%_ptr_Function_v2float = OpTypePointer Function %v2float
%_ptr_Input_v2float = OpTypePointer Input %v2float
%In2 = OpVariable %_ptr_Input_v2float Input
%_ptr_Input_float = OpTypePointer Input %float
%In0 = OpVariable %_ptr_Input_float Input
%In1 = OpVariable %_ptr_Input_float Input
%uint = OpTypeInt 32 0
%_ptr_Function_float = OpTypePointer Function %float
%float_0 = OpConstant %float 0
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%int = OpTypeInt 32 1
%_Globals_ = OpTypeStruct %uint %int
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
)";
const std::string before =
R"(%main = OpFunction %void None %11
%25 = OpLabel
%26 = OpLoad %v2float %In2
%27 = OpLoad %float %In0
%28 = OpLoad %float %In1
%29 = OpFAdd %float %27 %28
%35 = OpCompositeInsert %v2float %29 %26 0
%37 = OpCompositeInsert %v2float %float_0 %35 0
%33 = OpVectorShuffle %v4float %37 %37 0 1 0 1
OpStore %OutColor %33
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %10
%23 = OpLabel
%24 = OpLoad %v2float %In2
%25 = OpLoad %float %In0
%26 = OpLoad %float %In1
%27 = OpFAdd %float %25 %26
%28 = OpCompositeInsert %v2float %27 %24 0
%29 = OpCompositeInsert %v2float %float_0 %24 0
%30 = OpVectorShuffle %v4float %29 %29 0 1 0 1
OpStore %OutColor %30
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<opt::VectorDCE>(before_predefs + before,
after_predefs + after, true, true);
}
TEST_F(VectorDCETest, DeadInsertInChainWithPhi) {
// Dead insert eliminated with phi in insertion chain.
//
// Note: The SPIR-V assembly has had store/load elimination
// performed to allow the inserts and extracts to directly
// reference each other.
//
// #version 450
//
// layout (location=0) in vec4 In0;
// layout (location=1) in float In1;
// layout (location=2) in float In2;
// layout (location=0) out vec4 OutColor;
//
// layout(std140, binding = 0 ) uniform _Globals_
// {
// bool g_b;
// };
//
// void main()
// {
// vec4 v = In0;
// v.z = In1 + In2;
// if (g_b) v.w = 1.0;
// OutColor = vec4(v.x,v.y,0.0,v.w);
// }
const std::string before_predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %In1 %In2 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %In2 "In2"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_b"
OpName %_ ""
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %In2 Location 2
OpMemberDecorate %_Globals_ 0 Offset 0
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%11 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%In1 = OpVariable %_ptr_Input_float Input
%In2 = OpVariable %_ptr_Input_float Input
%uint = OpTypeInt 32 0
%_ptr_Function_float = OpTypePointer Function %float
%_Globals_ = OpTypeStruct %uint
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%float_1 = OpConstant %float 1
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%float_0 = OpConstant %float 0
)";
const std::string after_predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %In1 %In2 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %In2 "In2"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_b"
OpName %_ ""
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %In2 Location 2
OpMemberDecorate %_Globals_ 0 Offset 0
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%In1 = OpVariable %_ptr_Input_float Input
%In2 = OpVariable %_ptr_Input_float Input
%uint = OpTypeInt 32 0
%_ptr_Function_float = OpTypePointer Function %float
%_Globals_ = OpTypeStruct %uint
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%float_1 = OpConstant %float 1
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%float_0 = OpConstant %float 0
)";
const std::string before =
R"(%main = OpFunction %void None %11
%31 = OpLabel
%32 = OpLoad %v4float %In0
%33 = OpLoad %float %In1
%34 = OpLoad %float %In2
%35 = OpFAdd %float %33 %34
%51 = OpCompositeInsert %v4float %35 %32 2
%37 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
%38 = OpLoad %uint %37
%39 = OpINotEqual %bool %38 %uint_0
OpSelectionMerge %40 None
OpBranchConditional %39 %41 %40
%41 = OpLabel
%53 = OpCompositeInsert %v4float %float_1 %51 3
OpBranch %40
%40 = OpLabel
%60 = OpPhi %v4float %51 %31 %53 %41
%55 = OpCompositeExtract %float %60 0
%57 = OpCompositeExtract %float %60 1
%59 = OpCompositeExtract %float %60 3
%49 = OpCompositeConstruct %v4float %55 %57 %float_0 %59
OpStore %OutColor %49
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %10
%27 = OpLabel
%28 = OpLoad %v4float %In0
%29 = OpLoad %float %In1
%30 = OpLoad %float %In2
%31 = OpFAdd %float %29 %30
%32 = OpCompositeInsert %v4float %31 %28 2
%33 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
%34 = OpLoad %uint %33
%35 = OpINotEqual %bool %34 %uint_0
OpSelectionMerge %36 None
OpBranchConditional %35 %37 %36
%37 = OpLabel
%38 = OpCompositeInsert %v4float %float_1 %28 3
OpBranch %36
%36 = OpLabel
%39 = OpPhi %v4float %28 %27 %38 %37
%40 = OpCompositeExtract %float %39 0
%41 = OpCompositeExtract %float %39 1
%42 = OpCompositeExtract %float %39 3
%43 = OpCompositeConstruct %v4float %40 %41 %float_0 %42
OpStore %OutColor %43
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<opt::VectorDCE>(before_predefs + before,
after_predefs + after, true, true);
}
TEST_F(VectorDCETest, DeadInsertWithScalars) {
// Dead insert which requires two passes to eliminate
//
// Note: The SPIR-V assembly has had store/load elimination
// performed to allow the inserts and extracts to directly
// reference each other.
//
// #version 450
//
// layout (location=0) in vec4 In0;
// layout (location=1) in float In1;
// layout (location=2) in float In2;
// layout (location=0) out vec4 OutColor;
//
// layout(std140, binding = 0 ) uniform _Globals_
// {
// bool g_b;
// bool g_b2;
// };
//
// void main()
// {
// vec4 v1, v2;
// v1 = In0;
// v1.y = In1 + In2; // dead, second pass
// if (g_b) v1.x = 1.0;
// v2.x = v1.x;
// v2.y = v1.y; // dead, first pass
// if (g_b2) v2.x = 0.0;
// OutColor = vec4(v2.x,v2.x,0.0,1.0);
// }
const std::string before_predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %In1 %In2 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %In2 "In2"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_b"
OpMemberName %_Globals_ 1 "g_b2"
OpName %_ ""
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %In2 Location 2
OpMemberDecorate %_Globals_ 0 Offset 0
OpMemberDecorate %_Globals_ 1 Offset 4
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%In1 = OpVariable %_ptr_Input_float Input
%In2 = OpVariable %_ptr_Input_float Input
%uint = OpTypeInt 32 0
%_Globals_ = OpTypeStruct %uint %uint
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%float_1 = OpConstant %float 1
%int_1 = OpConstant %int 1
%float_0 = OpConstant %float 0
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%27 = OpUndef %v4float
)";
const std::string after_predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %In1 %In2 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %In2 "In2"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_b"
OpMemberName %_Globals_ 1 "g_b2"
OpName %_ ""
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %In2 Location 2
OpMemberDecorate %_Globals_ 0 Offset 0
OpMemberDecorate %_Globals_ 1 Offset 4
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%In1 = OpVariable %_ptr_Input_float Input
%In2 = OpVariable %_ptr_Input_float Input
%uint = OpTypeInt 32 0
%_Globals_ = OpTypeStruct %uint %uint
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%float_1 = OpConstant %float 1
%int_1 = OpConstant %int 1
%float_0 = OpConstant %float 0
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%27 = OpUndef %v4float
)";
const std::string before =
R"(%main = OpFunction %void None %10
%28 = OpLabel
%29 = OpLoad %v4float %In0
%30 = OpLoad %float %In1
%31 = OpLoad %float %In2
%32 = OpFAdd %float %30 %31
%33 = OpCompositeInsert %v4float %32 %29 1
%34 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
%35 = OpLoad %uint %34
%36 = OpINotEqual %bool %35 %uint_0
OpSelectionMerge %37 None
OpBranchConditional %36 %38 %37
%38 = OpLabel
%39 = OpCompositeInsert %v4float %float_1 %33 0
OpBranch %37
%37 = OpLabel
%40 = OpPhi %v4float %33 %28 %39 %38
%41 = OpCompositeExtract %float %40 0
%42 = OpCompositeInsert %v4float %41 %27 0
%43 = OpCompositeExtract %float %40 1
%44 = OpCompositeInsert %v4float %43 %42 1
%45 = OpAccessChain %_ptr_Uniform_uint %_ %int_1
%46 = OpLoad %uint %45
%47 = OpINotEqual %bool %46 %uint_0
OpSelectionMerge %48 None
OpBranchConditional %47 %49 %48
%49 = OpLabel
%50 = OpCompositeInsert %v4float %float_0 %44 0
OpBranch %48
%48 = OpLabel
%51 = OpPhi %v4float %44 %37 %50 %49
%52 = OpCompositeExtract %float %51 0
%53 = OpCompositeExtract %float %51 0
%54 = OpCompositeConstruct %v4float %52 %53 %float_0 %float_1
OpStore %OutColor %54
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %10
%28 = OpLabel
%29 = OpLoad %v4float %In0
%34 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
%35 = OpLoad %uint %34
%36 = OpINotEqual %bool %35 %uint_0
OpSelectionMerge %37 None
OpBranchConditional %36 %38 %37
%38 = OpLabel
%39 = OpCompositeInsert %v4float %float_1 %29 0
OpBranch %37
%37 = OpLabel
%40 = OpPhi %v4float %29 %28 %39 %38
%41 = OpCompositeExtract %float %40 0
%42 = OpCompositeInsert %v4float %41 %27 0
%45 = OpAccessChain %_ptr_Uniform_uint %_ %int_1
%46 = OpLoad %uint %45
%47 = OpINotEqual %bool %46 %uint_0
OpSelectionMerge %48 None
OpBranchConditional %47 %49 %48
%49 = OpLabel
%50 = OpCompositeInsert %v4float %float_0 %42 0
OpBranch %48
%48 = OpLabel
%51 = OpPhi %v4float %42 %37 %50 %49
%52 = OpCompositeExtract %float %51 0
%53 = OpCompositeExtract %float %51 0
%54 = OpCompositeConstruct %v4float %52 %53 %float_0 %float_1
OpStore %OutColor %54
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<opt::DeadInsertElimPass>(
before_predefs + before, after_predefs + after, true, true);
}
TEST_F(VectorDCETest, InsertObjectLive) {
// Make sure that the object being inserted in an OpCompositeInsert
// is not removed when it is uses later on.
const std::string before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %In1 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%In1 = OpVariable %_ptr_Input_float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %10
%28 = OpLabel
%29 = OpLoad %v4float %In0
%30 = OpLoad %float %In1
%33 = OpCompositeInsert %v4float %30 %29 1
OpStore %OutColor %33
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<opt::DeadInsertElimPass>(before, before, true, true);
}
#ifdef SPIRV_EFFCEE
TEST_F(VectorDCETest, DeadInsertInCycle) {
// Dead insert in chain with cycle. Demonstrates analysis can handle
// cycles in chains going through scalars intermediate values.
//
// Note: The SPIR-V assembly has had store/load elimination
// performed to allow the inserts and extracts to directly
// reference each other.
//
// #version 450
//
// layout (location=0) in vec4 In0;
// layout (location=1) in float In1;
// layout (location=2) in float In2;
// layout (location=0) out vec4 OutColor;
//
// layout(std140, binding = 0 ) uniform _Globals_
// {
// int g_n ;
// };
//
// void main()
// {
// vec2 v = vec2(0.0, 1.0);
// for (int i = 0; i < g_n; i++) {
// v.x = v.x + 1;
// v.y = v.y * 0.9; // dead
// }
// OutColor = vec4(v.x);
// }
const std::string assembly =
R"(
; CHECK: [[init_val:%\w+]] = OpConstantComposite %v2float %float_0 %float_1
; CHECK: [[undef:%\w+]] = OpUndef %v2float
; CHECK: OpFunction
; CHECK: [[entry_lab:%\w+]] = OpLabel
; CHECK: [[loop_header:%\w+]] = OpLabel
; CHECK: OpPhi %v2float [[init_val]] [[entry_lab]] [[x_insert:%\w+]] {{%\w+}}
; CHECK: [[x_insert:%\w+]] = OpCompositeInsert %v2float %43 [[undef]] 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %OutColor %In0 %In1 %In2
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %_Globals_ "_Globals_"
OpMemberName %_Globals_ 0 "g_n"
OpName %_ ""
OpName %OutColor "OutColor"
OpName %In0 "In0"
OpName %In1 "In1"
OpName %In2 "In2"
OpMemberDecorate %_Globals_ 0 Offset 0
OpDecorate %_Globals_ Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 0
OpDecorate %OutColor Location 0
OpDecorate %In0 Location 0
OpDecorate %In1 Location 1
OpDecorate %In2 Location 2
%void = OpTypeVoid
%10 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%_ptr_Function_v2float = OpTypePointer Function %v2float
%float_0 = OpConstant %float 0
%float_1 = OpConstant %float 1
%16 = OpConstantComposite %v2float %float_0 %float_1
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%_Globals_ = OpTypeStruct %int
%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_
%_ = OpVariable %_ptr_Uniform__Globals_ Uniform
%_ptr_Uniform_int = OpTypePointer Uniform %int
%bool = OpTypeBool
%float_0_75 = OpConstant %float 0.75
%int_1 = OpConstant %int 1
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%In1 = OpVariable %_ptr_Input_float Input
%In2 = OpVariable %_ptr_Input_float Input
%main = OpFunction %void None %10
%29 = OpLabel
OpBranch %30
%30 = OpLabel
%31 = OpPhi %v2float %16 %29 %32 %33
%34 = OpPhi %int %int_0 %29 %35 %33
OpLoopMerge %36 %33 None
OpBranch %37
%37 = OpLabel
%38 = OpAccessChain %_ptr_Uniform_int %_ %int_0
%39 = OpLoad %int %38
%40 = OpSLessThan %bool %34 %39
OpBranchConditional %40 %41 %36
%41 = OpLabel
%42 = OpCompositeExtract %float %31 0
%43 = OpFAdd %float %42 %float_1
%44 = OpCompositeInsert %v2float %43 %31 0
%45 = OpCompositeExtract %float %44 1
%46 = OpFMul %float %45 %float_0_75
%32 = OpCompositeInsert %v2float %46 %44 1
OpBranch %33
%33 = OpLabel
%35 = OpIAdd %int %34 %int_1
OpBranch %30
%36 = OpLabel
%47 = OpCompositeExtract %float %31 0
%48 = OpCompositeConstruct %v4float %47 %47 %47 %47
OpStore %OutColor %48
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::VectorDCE>(assembly, true);
}
TEST_F(VectorDCETest, DeadLoadFeedingCompositeConstruct) {
// Detach the loads feeding the CompositeConstruct for the unused elements.
// TODO: Implement the rewrite for CompositeConstruct.
const std::string assembly =
R"(
; CHECK: [[undef:%\w+]] = OpUndef %float
; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Input_float %In0 %uint_2
; CHECK: [[load:%\w+]] = OpLoad %float [[ac]]
; CHECK: OpCompositeConstruct %v3float [[load]] [[undef]] [[undef]]
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
OpName %In0 "In0"
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%_ptr_Input_float = OpTypePointer Input %float
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%v3float = OpTypeVector %float 3
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%float_1 = OpConstant %float 1
%int_1 = OpConstant %int 1
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%23 = OpUndef %v3float
%main = OpFunction %void None %6
%24 = OpLabel
%25 = OpAccessChain %_ptr_Input_float %In0 %uint_0
%26 = OpLoad %float %25
%27 = OpAccessChain %_ptr_Input_float %In0 %uint_1
%28 = OpLoad %float %27
%29 = OpAccessChain %_ptr_Input_float %In0 %uint_2
%30 = OpLoad %float %29
%31 = OpCompositeConstruct %v3float %30 %28 %26
OpBranch %32
%32 = OpLabel
%33 = OpPhi %v3float %31 %24 %34 %35
%36 = OpPhi %int %int_0 %24 %37 %35
OpLoopMerge %38 %35 None
OpBranch %39
%39 = OpLabel
%40 = OpSLessThan %bool %36 %int_20
OpBranchConditional %40 %41 %38
%41 = OpLabel
%42 = OpCompositeExtract %float %33 0
%43 = OpFAdd %float %42 %float_1
%34 = OpCompositeInsert %v3float %43 %33 0
OpBranch %35
%35 = OpLabel
%37 = OpIAdd %int %36 %int_1
OpBranch %32
%38 = OpLabel
%44 = OpCompositeExtract %float %33 0
%45 = OpCompositeConstruct %v4float %44 %44 %44 %44
OpStore %OutColor %45
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::VectorDCE>(assembly, true);
}
TEST_F(VectorDCETest, DeadLoadFeedingVectorShuffle) {
// Detach the loads feeding the CompositeConstruct for the unused elements.
// TODO: Implement the rewrite for CompositeConstruct.
const std::string assembly =
R"(
; MemPass Type2Undef does not reuse and already existing undef.
; CHECK: {{%\w+}} = OpUndef %v3float
; CHECK: [[undef:%\w+]] = OpUndef %v3float
; CHECK: OpFunction
; CHECK: OpVectorShuffle %v3float {{%\w+}} [[undef]] 0 4 5
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %In0 %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
OpName %In0 "In0"
OpName %OutColor "OutColor"
OpDecorate %In0 Location 0
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Input_v4float = OpTypePointer Input %v4float
%In0 = OpVariable %_ptr_Input_v4float Input
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%_ptr_Input_float = OpTypePointer Input %float
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%v3float = OpTypeVector %float 3
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%float_1 = OpConstant %float 1
%vec_const = OpConstantComposite %v3float %float_1 %float_1 %float_1
%int_1 = OpConstant %int 1
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%23 = OpUndef %v3float
%main = OpFunction %void None %6
%24 = OpLabel
%25 = OpAccessChain %_ptr_Input_float %In0 %uint_0
%26 = OpLoad %float %25
%27 = OpAccessChain %_ptr_Input_float %In0 %uint_1
%28 = OpLoad %float %27
%29 = OpAccessChain %_ptr_Input_float %In0 %uint_2
%30 = OpLoad %float %29
%31 = OpCompositeConstruct %v3float %30 %28 %26
%sh = OpVectorShuffle %v3float %vec_const %31 0 4 5
OpBranch %32
%32 = OpLabel
%33 = OpPhi %v3float %sh %24 %34 %35
%36 = OpPhi %int %int_0 %24 %37 %35
OpLoopMerge %38 %35 None
OpBranch %39
%39 = OpLabel
%40 = OpSLessThan %bool %36 %int_20
OpBranchConditional %40 %41 %38
%41 = OpLabel
%42 = OpCompositeExtract %float %33 0
%43 = OpFAdd %float %42 %float_1
%34 = OpCompositeInsert %v3float %43 %33 0
OpBranch %35
%35 = OpLabel
%37 = OpIAdd %int %36 %int_1
OpBranch %32
%38 = OpLabel
%44 = OpCompositeExtract %float %33 0
%45 = OpCompositeConstruct %v4float %44 %44 %44 %44
OpStore %OutColor %45
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::VectorDCE>(assembly, true);
}
TEST_F(VectorDCETest, DeadInstThroughShuffle) {
// Dead insert in chain with cycle. Demonstrates analysis can handle
// cycles in chains.
//
// Note: The SPIR-V assembly has had store/load elimination
// performed to allow the inserts and extracts to directly
// reference each other.
//
// #version 450
//
// layout (location=0) out vec4 OutColor;
//
// void main()
// {
// vec2 v;
// v.x = 0.0;
// v.y = 0.1; // dead
// for (int i = 0; i < 20; i++) {
// v.x = v.x + 1;
// v = v * 0.9;
// }
// OutColor = vec4(v.x);
// }
const std::string assembly =
R"(
; CHECK: OpFunction
; CHECK-NOT: OpCompositeInsert %v2float {{%\w+}} 1
; CHECK: OpFunctionEnd
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
OpName %OutColor "OutColor"
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%float_0 = OpConstant %float 0
%float_0_100000001 = OpConstant %float 0.100000001
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%float_1 = OpConstant %float 1
%float_0_899999976 = OpConstant %float 0.899999976
%int_1 = OpConstant %int 1
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%58 = OpUndef %v2float
%main = OpFunction %void None %3
%5 = OpLabel
%49 = OpCompositeInsert %v2float %float_0 %58 0
%51 = OpCompositeInsert %v2float %float_0_100000001 %49 1
OpBranch %22
%22 = OpLabel
%60 = OpPhi %v2float %51 %5 %38 %25
%59 = OpPhi %int %int_0 %5 %41 %25
OpLoopMerge %24 %25 None
OpBranch %26
%26 = OpLabel
%30 = OpSLessThan %bool %59 %int_20
OpBranchConditional %30 %23 %24
%23 = OpLabel
%53 = OpCompositeExtract %float %60 0
%34 = OpFAdd %float %53 %float_1
%55 = OpCompositeInsert %v2float %34 %60 0
%38 = OpVectorTimesScalar %v2float %55 %float_0_899999976
OpBranch %25
%25 = OpLabel
%41 = OpIAdd %int %59 %int_1
OpBranch %22
%24 = OpLabel
%57 = OpCompositeExtract %float %60 0
%47 = OpCompositeConstruct %v4float %57 %57 %57 %57
OpStore %OutColor %47
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::VectorDCE>(assembly, true);
}
TEST_F(VectorDCETest, DeadInsertThroughOtherInst) {
// Dead insert in chain with cycle. Demonstrates analysis can handle
// cycles in chains.
//
// Note: The SPIR-V assembly has had store/load elimination
// performed to allow the inserts and extracts to directly
// reference each other.
//
// #version 450
//
// layout (location=0) out vec4 OutColor;
//
// void main()
// {
// vec2 v;
// v.x = 0.0;
// v.y = 0.1; // dead
// for (int i = 0; i < 20; i++) {
// v.x = v.x + 1;
// v = v * 0.9;
// }
// OutColor = vec4(v.x);
// }
const std::string assembly =
R"(
; CHECK: OpFunction
; CHECK-NOT: OpCompositeInsert %v2float {{%\w+}} 1
; CHECK: OpFunctionEnd
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
OpName %OutColor "OutColor"
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%float_0 = OpConstant %float 0
%float_0_100000001 = OpConstant %float 0.100000001
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%float_1 = OpConstant %float 1
%float_0_899999976 = OpConstant %float 0.899999976
%int_1 = OpConstant %int 1
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%58 = OpUndef %v2float
%main = OpFunction %void None %3
%5 = OpLabel
%49 = OpCompositeInsert %v2float %float_0 %58 0
%51 = OpCompositeInsert %v2float %float_0_100000001 %49 1
OpBranch %22
%22 = OpLabel
%60 = OpPhi %v2float %51 %5 %38 %25
%59 = OpPhi %int %int_0 %5 %41 %25
OpLoopMerge %24 %25 None
OpBranch %26
%26 = OpLabel
%30 = OpSLessThan %bool %59 %int_20
OpBranchConditional %30 %23 %24
%23 = OpLabel
%53 = OpCompositeExtract %float %60 0
%34 = OpFAdd %float %53 %float_1
%55 = OpCompositeInsert %v2float %34 %60 0
%38 = OpVectorTimesScalar %v2float %55 %float_0_899999976
OpBranch %25
%25 = OpLabel
%41 = OpIAdd %int %59 %int_1
OpBranch %22
%24 = OpLabel
%57 = OpCompositeExtract %float %60 0
%47 = OpCompositeConstruct %v4float %57 %57 %57 %57
OpStore %OutColor %47
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<opt::VectorDCE>(assembly, true);
}
#endif
} // anonymous namespace