SPIRV-Tools/test/opt/common_uniform_elim_test.cpp
Steven Perron 9e81c337f9
Place load after OpPhi instructions in block. (#2246)
We currently place the load instructions at the start of the basic block
that dominates all of the loads.  If that basic block contains OpPhi
instructions, then this will generate invalid code.  We just need to
search for a location that comes after all of the OpPhi instructions.

Fixes #2204.
2018-12-19 15:18:22 +00:00

1395 lines
38 KiB
C++

// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG Inc.
//
// 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 <string>
#include "test/opt/pass_fixture.h"
namespace spvtools {
namespace opt {
namespace {
using CommonUniformElimTest = PassTest<::testing::Test>;
TEST_F(CommonUniformElimTest, Basic1) {
// Note: This test exemplifies the following:
// - Common uniform (%_) load floated to nearest non-controlled block
// - Common extract (g_F) floated to non-controlled block
// - Non-common extract (g_F2) not floated, but common uniform load shared
//
// #version 140
// in vec4 BaseColor;
// in float fi;
//
// layout(std140) uniform U_t
// {
// float g_F;
// float g_F2;
// } ;
//
// void main()
// {
// vec4 v = BaseColor;
// if (fi > 0) {
// v = v * g_F;
// }
// else {
// float f2 = g_F2 - g_F;
// v = v * f2;
// }
// gl_FragColor = v;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 140
OpName %main "main"
OpName %v "v"
OpName %BaseColor "BaseColor"
OpName %fi "fi"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_F"
OpMemberName %U_t 1 "g_F2"
OpName %_ ""
OpName %f2 "f2"
OpName %gl_FragColor "gl_FragColor"
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t Block
OpDecorate %_ DescriptorSet 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
%BaseColor = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
%float_0 = OpConstant %float 0
%bool = OpTypeBool
%U_t = OpTypeStruct %float %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_float = OpTypePointer Uniform %float
%_ptr_Function_float = OpTypePointer Function %float
%int_1 = OpConstant %int 1
%_ptr_Output_v4float = OpTypePointer Output %v4float
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
const std::string before =
R"(%main = OpFunction %void None %11
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%f2 = OpVariable %_ptr_Function_float Function
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%28 = OpLoad %float %fi
%29 = OpFOrdGreaterThan %bool %28 %float_0
OpSelectionMerge %30 None
OpBranchConditional %29 %31 %32
%31 = OpLabel
%33 = OpLoad %v4float %v
%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%35 = OpLoad %float %34
%36 = OpVectorTimesScalar %v4float %33 %35
OpStore %v %36
OpBranch %30
%32 = OpLabel
%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1
%38 = OpLoad %float %37
%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%40 = OpLoad %float %39
%41 = OpFSub %float %38 %40
OpStore %f2 %41
%42 = OpLoad %v4float %v
%43 = OpLoad %float %f2
%44 = OpVectorTimesScalar %v4float %42 %43
OpStore %v %44
OpBranch %30
%30 = OpLabel
%45 = OpLoad %v4float %v
OpStore %gl_FragColor %45
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %11
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%f2 = OpVariable %_ptr_Function_float Function
%52 = OpLoad %U_t %_
%53 = OpCompositeExtract %float %52 0
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%28 = OpLoad %float %fi
%29 = OpFOrdGreaterThan %bool %28 %float_0
OpSelectionMerge %30 None
OpBranchConditional %29 %31 %32
%31 = OpLabel
%33 = OpLoad %v4float %v
%36 = OpVectorTimesScalar %v4float %33 %53
OpStore %v %36
OpBranch %30
%32 = OpLabel
%49 = OpCompositeExtract %float %52 1
%41 = OpFSub %float %49 %53
OpStore %f2 %41
%42 = OpLoad %v4float %v
%43 = OpLoad %float %f2
%44 = OpVectorTimesScalar %v4float %42 %43
OpStore %v %44
OpBranch %30
%30 = OpLabel
%45 = OpLoad %v4float %v
OpStore %gl_FragColor %45
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CommonUniformElimPass>(predefs + before,
predefs + after, true, true);
}
TEST_F(CommonUniformElimTest, Basic2) {
// Note: This test exemplifies the following:
// - Common uniform (%_) load floated to nearest non-controlled block
// - Common extract (g_F) floated to non-controlled block
// - Non-common extract (g_F2) not floated, but common uniform load shared
//
// #version 140
// in vec4 BaseColor;
// in float fi;
// in float fi2;
//
// layout(std140) uniform U_t
// {
// float g_F;
// float g_F2;
// } ;
//
// void main()
// {
// float f = fi;
// if (f < 0)
// f = -f;
// if (fi2 > 0) {
// f = f * g_F;
// }
// else {
// f = g_F2 - g_F;
// }
// gl_FragColor = f * BaseColor;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fi %fi2 %gl_FragColor %BaseColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 140
OpName %main "main"
OpName %f "f"
OpName %fi "fi"
OpName %fi2 "fi2"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_F"
OpMemberName %U_t 1 "g_F2"
OpName %_ ""
OpName %gl_FragColor "gl_FragColor"
OpName %BaseColor "BaseColor"
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t Block
OpDecorate %_ DescriptorSet 0
%void = OpTypeVoid
%11 = OpTypeFunction %void
%float = OpTypeFloat 32
%_ptr_Function_float = OpTypePointer Function %float
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
%float_0 = OpConstant %float 0
%bool = OpTypeBool
%fi2 = OpVariable %_ptr_Input_float Input
%U_t = OpTypeStruct %float %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_float = OpTypePointer Uniform %float
%int_1 = OpConstant %int 1
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
%_ptr_Input_v4float = OpTypePointer Input %v4float
%BaseColor = OpVariable %_ptr_Input_v4float Input
)";
const std::string before =
R"(%main = OpFunction %void None %11
%25 = OpLabel
%f = OpVariable %_ptr_Function_float Function
%26 = OpLoad %float %fi
OpStore %f %26
%27 = OpLoad %float %f
%28 = OpFOrdLessThan %bool %27 %float_0
OpSelectionMerge %29 None
OpBranchConditional %28 %30 %29
%30 = OpLabel
%31 = OpLoad %float %f
%32 = OpFNegate %float %31
OpStore %f %32
OpBranch %29
%29 = OpLabel
%33 = OpLoad %float %fi2
%34 = OpFOrdGreaterThan %bool %33 %float_0
OpSelectionMerge %35 None
OpBranchConditional %34 %36 %37
%36 = OpLabel
%38 = OpLoad %float %f
%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%40 = OpLoad %float %39
%41 = OpFMul %float %38 %40
OpStore %f %41
OpBranch %35
%37 = OpLabel
%42 = OpAccessChain %_ptr_Uniform_float %_ %int_1
%43 = OpLoad %float %42
%44 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%45 = OpLoad %float %44
%46 = OpFSub %float %43 %45
OpStore %f %46
OpBranch %35
%35 = OpLabel
%47 = OpLoad %v4float %BaseColor
%48 = OpLoad %float %f
%49 = OpVectorTimesScalar %v4float %47 %48
OpStore %gl_FragColor %49
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %11
%25 = OpLabel
%f = OpVariable %_ptr_Function_float Function
%26 = OpLoad %float %fi
OpStore %f %26
%27 = OpLoad %float %f
%28 = OpFOrdLessThan %bool %27 %float_0
OpSelectionMerge %29 None
OpBranchConditional %28 %30 %29
%30 = OpLabel
%31 = OpLoad %float %f
%32 = OpFNegate %float %31
OpStore %f %32
OpBranch %29
%29 = OpLabel
%56 = OpLoad %U_t %_
%57 = OpCompositeExtract %float %56 0
%33 = OpLoad %float %fi2
%34 = OpFOrdGreaterThan %bool %33 %float_0
OpSelectionMerge %35 None
OpBranchConditional %34 %36 %37
%36 = OpLabel
%38 = OpLoad %float %f
%41 = OpFMul %float %38 %57
OpStore %f %41
OpBranch %35
%37 = OpLabel
%53 = OpCompositeExtract %float %56 1
%46 = OpFSub %float %53 %57
OpStore %f %46
OpBranch %35
%35 = OpLabel
%47 = OpLoad %v4float %BaseColor
%48 = OpLoad %float %f
%49 = OpVectorTimesScalar %v4float %47 %48
OpStore %gl_FragColor %49
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CommonUniformElimPass>(predefs + before,
predefs + after, true, true);
}
TEST_F(CommonUniformElimTest, Basic3) {
// Note: This test exemplifies the following:
// - Existing common uniform (%_) load kept in place and shared
//
// #version 140
// in vec4 BaseColor;
// in float fi;
//
// layout(std140) uniform U_t
// {
// bool g_B;
// float g_F;
// } ;
//
// void main()
// {
// vec4 v = BaseColor;
// if (g_B)
// v = v * g_F;
// gl_FragColor = v;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor %fi
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 140
OpName %main "main"
OpName %v "v"
OpName %BaseColor "BaseColor"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_B"
OpMemberName %U_t 1 "g_F"
OpName %_ ""
OpName %gl_FragColor "gl_FragColor"
OpName %fi "fi"
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t Block
OpDecorate %_ DescriptorSet 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
%BaseColor = OpVariable %_ptr_Input_v4float Input
%uint = OpTypeInt 32 0
%U_t = OpTypeStruct %uint %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%int_1 = OpConstant %int 1
%_ptr_Uniform_float = OpTypePointer Uniform %float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
)";
const std::string before =
R"(%main = OpFunction %void None %10
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
%29 = OpLoad %uint %28
%30 = OpINotEqual %bool %29 %uint_0
OpSelectionMerge %31 None
OpBranchConditional %30 %32 %31
%32 = OpLabel
%33 = OpLoad %v4float %v
%34 = OpAccessChain %_ptr_Uniform_float %_ %int_1
%35 = OpLoad %float %34
%36 = OpVectorTimesScalar %v4float %33 %35
OpStore %v %36
OpBranch %31
%31 = OpLabel
%37 = OpLoad %v4float %v
OpStore %gl_FragColor %37
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %10
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%38 = OpLoad %U_t %_
%39 = OpCompositeExtract %uint %38 0
%30 = OpINotEqual %bool %39 %uint_0
OpSelectionMerge %31 None
OpBranchConditional %30 %32 %31
%32 = OpLabel
%33 = OpLoad %v4float %v
%41 = OpCompositeExtract %float %38 1
%36 = OpVectorTimesScalar %v4float %33 %41
OpStore %v %36
OpBranch %31
%31 = OpLabel
%37 = OpLoad %v4float %v
OpStore %gl_FragColor %37
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CommonUniformElimPass>(predefs + before,
predefs + after, true, true);
}
TEST_F(CommonUniformElimTest, Loop) {
// Note: This test exemplifies the following:
// - Common extract (g_F) shared between two loops
// #version 140
// in vec4 BC;
// in vec4 BC2;
//
// layout(std140) uniform U_t
// {
// float g_F;
// } ;
//
// void main()
// {
// vec4 v = BC;
// for (int i = 0; i < 4; i++)
// v[i] = v[i] / g_F;
// vec4 v2 = BC2;
// for (int i = 0; i < 4; i++)
// v2[i] = v2[i] * g_F;
// gl_FragColor = v + v2;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BC %BC2 %gl_FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 140
OpName %main "main"
OpName %v "v"
OpName %BC "BC"
OpName %i "i"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_F"
OpName %_ ""
OpName %v2 "v2"
OpName %BC2 "BC2"
OpName %i_0 "i"
OpName %gl_FragColor "gl_FragColor"
OpMemberDecorate %U_t 0 Offset 0
OpDecorate %U_t Block
OpDecorate %_ DescriptorSet 0
%void = OpTypeVoid
%13 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%BC = OpVariable %_ptr_Input_v4float Input
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_4 = OpConstant %int 4
%bool = OpTypeBool
%_ptr_Function_float = OpTypePointer Function %float
%U_t = OpTypeStruct %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%_ptr_Uniform_float = OpTypePointer Uniform %float
%int_1 = OpConstant %int 1
%BC2 = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
const std::string before =
R"(%main = OpFunction %void None %13
%28 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%i = OpVariable %_ptr_Function_int Function
%v2 = OpVariable %_ptr_Function_v4float Function
%i_0 = OpVariable %_ptr_Function_int Function
%29 = OpLoad %v4float %BC
OpStore %v %29
OpStore %i %int_0
OpBranch %30
%30 = OpLabel
OpLoopMerge %31 %32 None
OpBranch %33
%33 = OpLabel
%34 = OpLoad %int %i
%35 = OpSLessThan %bool %34 %int_4
OpBranchConditional %35 %36 %31
%36 = OpLabel
%37 = OpLoad %int %i
%38 = OpLoad %int %i
%39 = OpAccessChain %_ptr_Function_float %v %38
%40 = OpLoad %float %39
%41 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%42 = OpLoad %float %41
%43 = OpFDiv %float %40 %42
%44 = OpAccessChain %_ptr_Function_float %v %37
OpStore %44 %43
OpBranch %32
%32 = OpLabel
%45 = OpLoad %int %i
%46 = OpIAdd %int %45 %int_1
OpStore %i %46
OpBranch %30
%31 = OpLabel
%47 = OpLoad %v4float %BC2
OpStore %v2 %47
OpStore %i_0 %int_0
OpBranch %48
%48 = OpLabel
OpLoopMerge %49 %50 None
OpBranch %51
%51 = OpLabel
%52 = OpLoad %int %i_0
%53 = OpSLessThan %bool %52 %int_4
OpBranchConditional %53 %54 %49
%54 = OpLabel
%55 = OpLoad %int %i_0
%56 = OpLoad %int %i_0
%57 = OpAccessChain %_ptr_Function_float %v2 %56
%58 = OpLoad %float %57
%59 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%60 = OpLoad %float %59
%61 = OpFMul %float %58 %60
%62 = OpAccessChain %_ptr_Function_float %v2 %55
OpStore %62 %61
OpBranch %50
%50 = OpLabel
%63 = OpLoad %int %i_0
%64 = OpIAdd %int %63 %int_1
OpStore %i_0 %64
OpBranch %48
%49 = OpLabel
%65 = OpLoad %v4float %v
%66 = OpLoad %v4float %v2
%67 = OpFAdd %v4float %65 %66
OpStore %gl_FragColor %67
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %13
%28 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%i = OpVariable %_ptr_Function_int Function
%v2 = OpVariable %_ptr_Function_v4float Function
%i_0 = OpVariable %_ptr_Function_int Function
%72 = OpLoad %U_t %_
%73 = OpCompositeExtract %float %72 0
%29 = OpLoad %v4float %BC
OpStore %v %29
OpStore %i %int_0
OpBranch %30
%30 = OpLabel
OpLoopMerge %31 %32 None
OpBranch %33
%33 = OpLabel
%34 = OpLoad %int %i
%35 = OpSLessThan %bool %34 %int_4
OpBranchConditional %35 %36 %31
%36 = OpLabel
%37 = OpLoad %int %i
%38 = OpLoad %int %i
%39 = OpAccessChain %_ptr_Function_float %v %38
%40 = OpLoad %float %39
%43 = OpFDiv %float %40 %73
%44 = OpAccessChain %_ptr_Function_float %v %37
OpStore %44 %43
OpBranch %32
%32 = OpLabel
%45 = OpLoad %int %i
%46 = OpIAdd %int %45 %int_1
OpStore %i %46
OpBranch %30
%31 = OpLabel
%47 = OpLoad %v4float %BC2
OpStore %v2 %47
OpStore %i_0 %int_0
OpBranch %48
%48 = OpLabel
OpLoopMerge %49 %50 None
OpBranch %51
%51 = OpLabel
%52 = OpLoad %int %i_0
%53 = OpSLessThan %bool %52 %int_4
OpBranchConditional %53 %54 %49
%54 = OpLabel
%55 = OpLoad %int %i_0
%56 = OpLoad %int %i_0
%57 = OpAccessChain %_ptr_Function_float %v2 %56
%58 = OpLoad %float %57
%61 = OpFMul %float %58 %73
%62 = OpAccessChain %_ptr_Function_float %v2 %55
OpStore %62 %61
OpBranch %50
%50 = OpLabel
%63 = OpLoad %int %i_0
%64 = OpIAdd %int %63 %int_1
OpStore %i_0 %64
OpBranch %48
%49 = OpLabel
%65 = OpLoad %v4float %v
%66 = OpLoad %v4float %v2
%67 = OpFAdd %v4float %65 %66
OpStore %gl_FragColor %67
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CommonUniformElimPass>(predefs + before,
predefs + after, true, true);
}
TEST_F(CommonUniformElimTest, Volatile1) {
// Note: This test exemplifies the following:
// - Same test as Basic1 with the exception that
// the Load of g_F in else-branch is volatile
// - Common uniform (%_) load floated to nearest non-controlled block
//
// #version 140
// in vec4 BaseColor;
// in float fi;
//
// layout(std140) uniform U_t
// {
// float g_F;
// float g_F2;
// } ;
//
// void main()
// {
// vec4 v = BaseColor;
// if (fi > 0) {
// v = v * g_F;
// }
// else {
// float f2 = g_F2 - g_F;
// v = v * f2;
// }
// gl_FragColor = v;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 140
OpName %main "main"
OpName %v "v"
OpName %BaseColor "BaseColor"
OpName %fi "fi"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_F"
OpMemberName %U_t 1 "g_F2"
OpName %_ ""
OpName %f2 "f2"
OpName %gl_FragColor "gl_FragColor"
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t Block
OpDecorate %_ DescriptorSet 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
%BaseColor = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
%float_0 = OpConstant %float 0
%bool = OpTypeBool
%U_t = OpTypeStruct %float %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_float = OpTypePointer Uniform %float
%_ptr_Function_float = OpTypePointer Function %float
%int_1 = OpConstant %int 1
%_ptr_Output_v4float = OpTypePointer Output %v4float
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
const std::string before =
R"(%main = OpFunction %void None %11
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%f2 = OpVariable %_ptr_Function_float Function
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%28 = OpLoad %float %fi
%29 = OpFOrdGreaterThan %bool %28 %float_0
OpSelectionMerge %30 None
OpBranchConditional %29 %31 %32
%31 = OpLabel
%33 = OpLoad %v4float %v
%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%35 = OpLoad %float %34
%36 = OpVectorTimesScalar %v4float %33 %35
OpStore %v %36
OpBranch %30
%32 = OpLabel
%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1
%38 = OpLoad %float %37
%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%40 = OpLoad %float %39 Volatile
%41 = OpFSub %float %38 %40
OpStore %f2 %41
%42 = OpLoad %v4float %v
%43 = OpLoad %float %f2
%44 = OpVectorTimesScalar %v4float %42 %43
OpStore %v %44
OpBranch %30
%30 = OpLabel
%45 = OpLoad %v4float %v
OpStore %gl_FragColor %45
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %11
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%f2 = OpVariable %_ptr_Function_float Function
%50 = OpLoad %U_t %_
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%28 = OpLoad %float %fi
%29 = OpFOrdGreaterThan %bool %28 %float_0
OpSelectionMerge %30 None
OpBranchConditional %29 %31 %32
%31 = OpLabel
%33 = OpLoad %v4float %v
%47 = OpCompositeExtract %float %50 0
%36 = OpVectorTimesScalar %v4float %33 %47
OpStore %v %36
OpBranch %30
%32 = OpLabel
%49 = OpCompositeExtract %float %50 1
%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%40 = OpLoad %float %39 Volatile
%41 = OpFSub %float %49 %40
OpStore %f2 %41
%42 = OpLoad %v4float %v
%43 = OpLoad %float %f2
%44 = OpVectorTimesScalar %v4float %42 %43
OpStore %v %44
OpBranch %30
%30 = OpLabel
%45 = OpLoad %v4float %v
OpStore %gl_FragColor %45
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CommonUniformElimPass>(predefs + before,
predefs + after, true, true);
}
TEST_F(CommonUniformElimTest, Volatile2) {
// Note: This test exemplifies the following:
// - Same test as Basic1 with the exception that
// U_t is Volatile.
// - No optimizations are applied
//
// #version 430
// in vec4 BaseColor;
// in float fi;
//
// layout(std430) volatile buffer U_t
// {
// float g_F;
// float g_F2;
// };
//
//
// void main(void)
// {
// vec4 v = BaseColor;
// if (fi > 0) {
// v = v * g_F;
// } else {
// float f2 = g_F2 - g_F;
// v = v * f2;
// }
// }
const std::string text =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BaseColor %fi
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 430
OpName %main "main"
OpName %v "v"
OpName %BaseColor "BaseColor"
OpName %fi "fi"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_F"
OpMemberName %U_t 1 "g_F2"
OpName %_ ""
OpName %f2 "f2"
OpDecorate %BaseColor Location 0
OpDecorate %fi Location 0
OpMemberDecorate %U_t 0 Volatile
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Volatile
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t BufferBlock
OpDecorate %_ DescriptorSet 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%BaseColor = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
%float_0 = OpConstant %float 0
%bool = OpTypeBool
%U_t = OpTypeStruct %float %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_float = OpTypePointer Uniform %float
%_ptr_Function_float = OpTypePointer Function %float
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%f2 = OpVariable %_ptr_Function_float Function
%12 = OpLoad %v4float %BaseColor
OpStore %v %12
%15 = OpLoad %float %fi
%18 = OpFOrdGreaterThan %bool %15 %float_0
OpSelectionMerge %20 None
OpBranchConditional %18 %19 %31
%19 = OpLabel
%21 = OpLoad %v4float %v
%28 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%29 = OpLoad %float %28
%30 = OpVectorTimesScalar %v4float %21 %29
OpStore %v %30
OpBranch %20
%31 = OpLabel
%35 = OpAccessChain %_ptr_Uniform_float %_ %int_1
%36 = OpLoad %float %35
%37 = OpAccessChain %_ptr_Uniform_float %_ %int_0
%38 = OpLoad %float %37
%39 = OpFSub %float %36 %38
OpStore %f2 %39
%40 = OpLoad %v4float %v
%41 = OpLoad %float %f2
%42 = OpVectorTimesScalar %v4float %40 %41
OpStore %v %42
OpBranch %20
%20 = OpLabel
OpReturn
OpFunctionEnd
)";
Pass::Status res = std::get<1>(
SinglePassRunAndDisassemble<CommonUniformElimPass>(text, true, false));
EXPECT_EQ(res, Pass::Status::SuccessWithoutChange);
}
TEST_F(CommonUniformElimTest, Volatile3) {
// Note: This test exemplifies the following:
// - Same test as Volatile2 with the exception that
// the nested struct S is volatile
// - No optimizations are applied
//
// #version 430
// in vec4 BaseColor;
// in float fi;
//
// struct S {
// volatile float a;
// };
//
// layout(std430) buffer U_t
// {
// S g_F;
// S g_F2;
// };
//
//
// void main(void)
// {
// vec4 v = BaseColor;
// if (fi > 0) {
// v = v * g_F.a;
// } else {
// float f2 = g_F2.a - g_F.a;
// v = v * f2;
// }
// }
const std::string text =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BaseColor %fi
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 430
OpName %main "main"
OpName %v "v"
OpName %BaseColor "BaseColor"
OpName %fi "fi"
OpName %S "S"
OpMemberName %S 0 "a"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_F"
OpMemberName %U_t 1 "g_F2"
OpName %_ ""
OpName %f2 "f2"
OpDecorate %BaseColor Location 0
OpDecorate %fi Location 0
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 0 Volatile
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t BufferBlock
OpDecorate %_ DescriptorSet 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%BaseColor = OpVariable %_ptr_Input_v4float Input
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
%float_0 = OpConstant %float 0
%bool = OpTypeBool
%S = OpTypeStruct %float
%U_t = OpTypeStruct %S %S
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_float = OpTypePointer Uniform %float
%_ptr_Function_float = OpTypePointer Function %float
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%f2 = OpVariable %_ptr_Function_float Function
%12 = OpLoad %v4float %BaseColor
OpStore %v %12
%15 = OpLoad %float %fi
%18 = OpFOrdGreaterThan %bool %15 %float_0
OpSelectionMerge %20 None
OpBranchConditional %18 %19 %32
%19 = OpLabel
%21 = OpLoad %v4float %v
%29 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0
%30 = OpLoad %float %29
%31 = OpVectorTimesScalar %v4float %21 %30
OpStore %v %31
OpBranch %20
%32 = OpLabel
%36 = OpAccessChain %_ptr_Uniform_float %_ %int_1 %int_0
%37 = OpLoad %float %36
%38 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0
%39 = OpLoad %float %38
%40 = OpFSub %float %37 %39
OpStore %f2 %40
%41 = OpLoad %v4float %v
%42 = OpLoad %float %f2
%43 = OpVectorTimesScalar %v4float %41 %42
OpStore %v %43
OpBranch %20
%20 = OpLabel
OpReturn
OpFunctionEnd
)";
Pass::Status res = std::get<1>(
SinglePassRunAndDisassemble<CommonUniformElimPass>(text, true, false));
EXPECT_EQ(res, Pass::Status::SuccessWithoutChange);
}
TEST_F(CommonUniformElimTest, IteratorDanglingPointer) {
// Note: This test exemplifies the following:
// - Existing common uniform (%_) load kept in place and shared
//
// #version 140
// in vec4 BaseColor;
// in float fi;
//
// layout(std140) uniform U_t
// {
// bool g_B;
// float g_F;
// } ;
//
// uniform float alpha;
// uniform bool alpha_B;
//
// void main()
// {
// vec4 v = BaseColor;
// if (g_B) {
// v = v * g_F;
// if (alpha_B)
// v = v * alpha;
// else
// v = v * fi;
// }
// gl_FragColor = v;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor %fi
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 140
OpName %main "main"
OpName %v "v"
OpName %BaseColor "BaseColor"
OpName %U_t "U_t"
OpMemberName %U_t 0 "g_B"
OpMemberName %U_t 1 "g_F"
OpName %alpha "alpha"
OpName %alpha_B "alpha_B"
OpName %_ ""
OpName %gl_FragColor "gl_FragColor"
OpName %fi "fi"
OpMemberDecorate %U_t 0 Offset 0
OpMemberDecorate %U_t 1 Offset 4
OpDecorate %U_t Block
OpDecorate %_ DescriptorSet 0
%void = OpTypeVoid
%12 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v4float = OpTypePointer Input %v4float
%BaseColor = OpVariable %_ptr_Input_v4float Input
%uint = OpTypeInt 32 0
%U_t = OpTypeStruct %uint %float
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
%_ = OpVariable %_ptr_Uniform_U_t Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%int_1 = OpConstant %int 1
%_ptr_Uniform_float = OpTypePointer Uniform %float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
%_ptr_Input_float = OpTypePointer Input %float
%fi = OpVariable %_ptr_Input_float Input
%alpha = OpVariable %_ptr_Uniform_float Uniform
%alpha_B = OpVariable %_ptr_Uniform_uint Uniform
)";
const std::string before =
R"(%main = OpFunction %void None %12
%26 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%27 = OpLoad %v4float %BaseColor
OpStore %v %27
%28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
%29 = OpLoad %uint %28
%30 = OpINotEqual %bool %29 %uint_0
OpSelectionMerge %31 None
OpBranchConditional %30 %31 %32
%32 = OpLabel
%47 = OpLoad %v4float %v
OpStore %gl_FragColor %47
OpReturn
%31 = OpLabel
%33 = OpAccessChain %_ptr_Uniform_float %_ %int_1
%34 = OpLoad %float %33
%35 = OpLoad %v4float %v
%36 = OpVectorTimesScalar %v4float %35 %34
OpStore %v %36
%37 = OpLoad %uint %alpha_B
%38 = OpIEqual %bool %37 %uint_0
OpSelectionMerge %43 None
OpBranchConditional %38 %43 %39
%39 = OpLabel
%40 = OpLoad %float %alpha
%41 = OpLoad %v4float %v
%42 = OpVectorTimesScalar %v4float %41 %40
OpStore %v %42
OpBranch %50
%50 = OpLabel
%51 = OpLoad %v4float %v
OpStore %gl_FragColor %51
OpReturn
%43 = OpLabel
%44 = OpLoad %float %fi
%45 = OpLoad %v4float %v
%46 = OpVectorTimesScalar %v4float %45 %44
OpStore %v %46
OpBranch %60
%60 = OpLabel
%61 = OpLoad %v4float %v
OpStore %gl_FragColor %61
OpReturn
OpFunctionEnd
)";
const std::string after =
R"(%main = OpFunction %void None %12
%28 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
%29 = OpLoad %v4float %BaseColor
OpStore %v %29
%54 = OpLoad %U_t %_
%55 = OpCompositeExtract %uint %54 0
%32 = OpINotEqual %bool %55 %uint_0
OpSelectionMerge %33 None
OpBranchConditional %32 %33 %34
%34 = OpLabel
%35 = OpLoad %v4float %v
OpStore %gl_FragColor %35
OpReturn
%33 = OpLabel
%58 = OpLoad %float %alpha
%57 = OpCompositeExtract %float %54 1
%38 = OpLoad %v4float %v
%39 = OpVectorTimesScalar %v4float %38 %57
OpStore %v %39
%40 = OpLoad %uint %alpha_B
%41 = OpIEqual %bool %40 %uint_0
OpSelectionMerge %42 None
OpBranchConditional %41 %42 %43
%43 = OpLabel
%45 = OpLoad %v4float %v
%46 = OpVectorTimesScalar %v4float %45 %58
OpStore %v %46
OpBranch %47
%47 = OpLabel
%48 = OpLoad %v4float %v
OpStore %gl_FragColor %48
OpReturn
%42 = OpLabel
%49 = OpLoad %float %fi
%50 = OpLoad %v4float %v
%51 = OpVectorTimesScalar %v4float %50 %49
OpStore %v %51
OpBranch %52
%52 = OpLabel
%53 = OpLoad %v4float %v
OpStore %gl_FragColor %53
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CommonUniformElimPass>(predefs + before,
predefs + after, true, true);
}
TEST_F(CommonUniformElimTest, MixedConstantAndNonConstantIndexes) {
const std::string text = R"(
; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform
; CHECK: %501 = OpLabel
; CHECK: [[ld:%\w+]] = OpLoad
; CHECK-NOT: OpCompositeExtract {{%\w+}} {{%\w+}} 0 2 484
; CHECK: OpAccessChain {{%\w+}} [[var]] %int_0 %int_2 [[ld]]
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "ringeffectLayer_px" %gl_FragCoord %178 %182
OpExecutionMode %4 OriginUpperLeft
OpSource HLSL 500
OpDecorate %_arr_v4float_uint_10 ArrayStride 16
OpMemberDecorate %_struct_20 0 Offset 0
OpMemberDecorate %_struct_20 1 Offset 16
OpMemberDecorate %_struct_20 2 Offset 32
OpMemberDecorate %_struct_21 0 Offset 0
OpDecorate %_struct_21 Block
OpDecorate %23 DescriptorSet 0
OpDecorate %gl_FragCoord BuiltIn FragCoord
OpDecorate %178 Location 0
OpDecorate %182 Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%v2float = OpTypeVector %float 2
%_ptr_Function_v2float = OpTypePointer Function %v2float
%uint = OpTypeInt 32 0
%uint_10 = OpConstant %uint 10
%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10
%_struct_20 = OpTypeStruct %v4float %v4float %_arr_v4float_uint_10
%_struct_21 = OpTypeStruct %_struct_20
%_ptr_Uniform__struct_21 = OpTypePointer Uniform %_struct_21
%23 = OpVariable %_ptr_Uniform__struct_21 Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%_ptr_Uniform_float = OpTypePointer Uniform %float
%uint_3 = OpConstant %uint 3
%_ptr_Function_v4float = OpTypePointer Function %v4float
%float_0 = OpConstant %float 0
%43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%_ptr_Function_int = OpTypePointer Function %int
%int_5 = OpConstant %int 5
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%uint_5 = OpConstant %uint 5
%_arr_v2float_uint_5 = OpTypeArray %v2float %uint_5
%_ptr_Function__arr_v2float_uint_5 = OpTypePointer Function %_arr_v2float_uint_5
%82 = OpTypeImage %float 2D 0 0 0 1 Unknown
%_ptr_UniformConstant_82 = OpTypePointer UniformConstant %82
%86 = OpTypeSampler
%_ptr_UniformConstant_86 = OpTypePointer UniformConstant %86
%90 = OpTypeSampledImage %82
%v3float = OpTypeVector %float 3
%_ptr_Input_v4float = OpTypePointer Input %v4float
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
%178 = OpVariable %_ptr_Input_v4float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%182 = OpVariable %_ptr_Output_v4float Output
%4 = OpFunction %void None %3
%5 = OpLabel
%483 = OpVariable %_ptr_Function_v4float Function
%484 = OpVariable %_ptr_Function_int Function
%486 = OpVariable %_ptr_Function__arr_v2float_uint_5 Function
%179 = OpLoad %v4float %178
%493 = OpAccessChain %_ptr_Uniform_float %23 %int_0 %int_0 %uint_3
%494 = OpLoad %float %493
OpStore %483 %43
OpStore %484 %int_0
OpBranch %495
%495 = OpLabel
OpLoopMerge %496 %497 None
OpBranch %498
%498 = OpLabel
%499 = OpLoad %int %484
%500 = OpSLessThan %bool %499 %int_5
OpBranchConditional %500 %501 %496
%501 = OpLabel
%504 = OpVectorShuffle %v2float %179 %179 0 1
%505 = OpLoad %int %484
%506 = OpAccessChain %_ptr_Uniform_v4float %23 %int_0 %int_2 %505
%507 = OpLoad %v4float %506
%508 = OpVectorShuffle %v2float %507 %507 0 1
%509 = OpFAdd %v2float %504 %508
%512 = OpAccessChain %_ptr_Uniform_v4float %23 %int_0 %int_1
%513 = OpLoad %v4float %512
%514 = OpVectorShuffle %v2float %513 %513 0 1
%517 = OpVectorShuffle %v2float %513 %513 2 3
%518 = OpExtInst %v2float %1 FClamp %509 %514 %517
%519 = OpAccessChain %_ptr_Function_v2float %486 %505
OpStore %519 %518
OpBranch %497
%497 = OpLabel
%520 = OpLoad %int %484
%521 = OpIAdd %int %520 %int_1
OpStore %484 %521
OpBranch %495
%496 = OpLabel
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<CommonUniformElimPass>(text, true);
}
TEST_F(CommonUniformElimTest, LoadPlacedAfterPhi) {
const std::string text = R"(
; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform
; CHECK: OpSelectionMerge [[merge:%\w+]]
; CHECK: [[merge]] = OpLabel
; CHECK-NEXT: OpPhi
; CHECK-NEXT: OpLoad {{%\w+}} [[var]]
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
OpExecutionMode %2 OriginUpperLeft
OpSource ESSL 310
OpMemberDecorate %_struct_3 0 Offset 0
OpDecorate %_struct_3 Block
OpDecorate %4 DescriptorSet 0
OpDecorate %4 Binding 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%bool = OpTypeBool
%false = OpConstantFalse %bool
%uint = OpTypeInt 32 0
%v2uint = OpTypeVector %uint 2
%_struct_3 = OpTypeStruct %v2uint
%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
%4 = OpVariable %_ptr_Uniform__struct_3 Uniform
%uint_0 = OpConstant %uint 0
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%uint_2 = OpConstant %uint 2
%2 = OpFunction %void None %6
%15 = OpLabel
OpSelectionMerge %16 None
OpBranchConditional %false %17 %16
%17 = OpLabel
OpBranch %16
%16 = OpLabel
%18 = OpPhi %bool %false %15 %false %17
OpSelectionMerge %19 None
OpBranchConditional %false %20 %21
%20 = OpLabel
%22 = OpAccessChain %_ptr_Uniform_uint %4 %uint_0 %uint_0
%23 = OpLoad %uint %22
OpBranch %19
%21 = OpLabel
OpBranch %19
%19 = OpLabel
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<CommonUniformElimPass>(text, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Disqualifying cases: extensions, decorations, non-logical addressing,
// non-structured control flow
// Others?
} // namespace
} // namespace opt
} // namespace spvtools