mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-19 11:30:15 +00:00
56d0f50357
Based on the OpLine spec, an OpLine instruction must be applied to the instructions physically following it up to the first occurrence of the next end of block, the next OpLine instruction, or the next OpNoLine instruction. ``` OpLine %file 0 0 OpNoLine OpLine %file 1 1 OpStore %foo %int_1 %value = OpLoad %int %foo OpLine %file 2 2 ``` For the above code, the current spirv-opt keeps three line instructions `OpLine %file 0 0`, `OpNoLine`, and `OpLine %file 1 1` in `std::vector<Instruction> dbg_line_insts_` of Instruction class for `OpStore %foo %int_1`. It does not put any line instruction to `std::vector<Instruction> dbg_line_insts_` of `%value = OpLoad %int %foo` even though `OpLine %file 1 1` must be applied to `%value = OpLoad %int %foo` based on the spec. This results in the missing line information for `%value = OpLoad %int %foo` while each spirv-opt pass optimizes the code. We have to put `OpLine %file 1 1` to `std::vector<Instruction> dbg_line_insts_` of both `%value = OpLoad %int %foo` and `OpStore %foo %int_1`. This commit conducts the line instruction propagation and skips emitting the eliminated line instructions at the end, which are the same with PropagateLineInfoPass and RedundantLineInfoElimPass. This commit removes PropagateLineInfoPass and RedundantLineInfoElimPass. KhronosGroup/glslang#2440 is a related PR that stop using PropagateLineInfoPass and RedundantLineInfoElimPass from glslang. When the code in this PR applied, the glslang tests will pass.
3410 lines
90 KiB
C++
3410 lines
90 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"
|
|
#include "test/opt/pass_utils.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
namespace {
|
|
|
|
using DeadBranchElimTest = PassTest<::testing::Test>;
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenElseTrue) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v;
|
|
// if (true)
|
|
// v = vec4(0.0,0.0,0.0,0.0);
|
|
// else
|
|
// v = vec4(1.0,1.0,1.0,1.0);
|
|
// gl_FragColor = v;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpName %BaseColor "BaseColor"
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_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 %7
|
|
%19 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpSelectionMerge %20 None
|
|
OpBranchConditional %true %21 %22
|
|
%21 = OpLabel
|
|
OpStore %v %14
|
|
OpBranch %20
|
|
%22 = OpLabel
|
|
OpStore %v %16
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%19 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
OpStore %v %14
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenElseFalse) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v;
|
|
// if (false)
|
|
// v = vec4(0.0,0.0,0.0,0.0);
|
|
// else
|
|
// v = vec4(1.0,1.0,1.0,1.0);
|
|
// gl_FragColor = v;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpName %BaseColor "BaseColor"
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_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 %7
|
|
%19 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpSelectionMerge %20 None
|
|
OpBranchConditional %false %21 %22
|
|
%21 = OpLabel
|
|
OpStore %v %14
|
|
OpBranch %20
|
|
%22 = OpLabel
|
|
OpStore %v %16
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%19 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpStore %v %16
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenElseNull) {
|
|
// For booleans OpConstantNull should be treated similar to OpConstantFalse.
|
|
//
|
|
// From the SPIR-V spec:
|
|
// OpConstantNull: Declares a new null constant value.
|
|
// The null value is type dependent, defined as follows:
|
|
// - Scalar Boolean: false
|
|
// ...
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpName %BaseColor "BaseColor"
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%9 = OpConstantNull %bool
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_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 %7
|
|
%19 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpSelectionMerge %20 None
|
|
OpBranchConditional %9 %21 %22
|
|
%21 = OpLabel
|
|
OpStore %v %14
|
|
OpBranch %20
|
|
%22 = OpLabel
|
|
OpStore %v %16
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%19 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpStore %v %16
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenTrue) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v = BaseColor;
|
|
// if (true)
|
|
// v = v * vec4(0.5,0.5,0.5,0.5);
|
|
// 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
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%7 = 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
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float_0_5 = OpConstant %float 0.5
|
|
%15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %7
|
|
%17 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%18 = OpLoad %v4float %BaseColor
|
|
OpStore %v %18
|
|
OpSelectionMerge %19 None
|
|
OpBranchConditional %true %20 %19
|
|
%20 = OpLabel
|
|
%21 = OpLoad %v4float %v
|
|
%22 = OpFMul %v4float %21 %15
|
|
OpStore %v %22
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%17 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%18 = OpLoad %v4float %BaseColor
|
|
OpStore %v %18
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%21 = OpLoad %v4float %v
|
|
%22 = OpFMul %v4float %21 %15
|
|
OpStore %v %22
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenFalse) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v = BaseColor;
|
|
// if (false)
|
|
// v = v * vec4(0.5,0.5,0.5,0.5);
|
|
// 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
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%7 = 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
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%float_0_5 = OpConstant %float 0.5
|
|
%15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %7
|
|
%17 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%18 = OpLoad %v4float %BaseColor
|
|
OpStore %v %18
|
|
OpSelectionMerge %19 None
|
|
OpBranchConditional %false %20 %19
|
|
%20 = OpLabel
|
|
%21 = OpLoad %v4float %v
|
|
%22 = OpFMul %v4float %21 %15
|
|
OpStore %v %22
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%17 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%18 = OpLoad %v4float %BaseColor
|
|
OpStore %v %18
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenElsePhiTrue) {
|
|
// Test handling of phi in merge block after dead branch elimination.
|
|
// Note: The SPIR-V has had store/load elimination and phi insertion
|
|
//
|
|
// #version 140
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v;
|
|
// if (true)
|
|
// v = vec4(0.0,0.0,0.0,0.0);
|
|
// else
|
|
// v = vec4(1.0,1.0,1.0,1.0);
|
|
// gl_FragColor = v;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%5 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %5
|
|
%17 = OpLabel
|
|
OpSelectionMerge %18 None
|
|
OpBranchConditional %true %19 %20
|
|
%19 = OpLabel
|
|
OpBranch %18
|
|
%20 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%21 = OpPhi %v4float %12 %19 %14 %20
|
|
OpStore %gl_FragColor %21
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %5
|
|
%17 = OpLabel
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
OpStore %gl_FragColor %12
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfThenElsePhiFalse) {
|
|
// Test handling of phi in merge block after dead branch elimination.
|
|
// Note: The SPIR-V has had store/load elimination and phi insertion
|
|
//
|
|
// #version 140
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v;
|
|
// if (true)
|
|
// v = vec4(0.0,0.0,0.0,0.0);
|
|
// else
|
|
// v = vec4(1.0,1.0,1.0,1.0);
|
|
// gl_FragColor = v;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%5 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %5
|
|
%17 = OpLabel
|
|
OpSelectionMerge %18 None
|
|
OpBranchConditional %false %19 %20
|
|
%19 = OpLabel
|
|
OpBranch %18
|
|
%20 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%21 = OpPhi %v4float %12 %19 %14 %20
|
|
OpStore %gl_FragColor %21
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %5
|
|
%17 = OpLabel
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
OpStore %gl_FragColor %14
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, CompoundIfThenElseFalse) {
|
|
// #version 140
|
|
//
|
|
// layout(std140) uniform U_t
|
|
// {
|
|
// bool g_B ;
|
|
// } ;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v;
|
|
// if (false) {
|
|
// if (g_B)
|
|
// v = vec4(0.0,0.0,0.0,0.0);
|
|
// else
|
|
// v = vec4(1.0,1.0,1.0,1.0);
|
|
// } else {
|
|
// if (g_B)
|
|
// v = vec4(1.0,1.0,1.0,1.0);
|
|
// else
|
|
// v = vec4(0.0,0.0,0.0,0.0);
|
|
// }
|
|
// gl_FragColor = v;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %U_t "U_t"
|
|
OpMemberName %U_t 0 "g_B"
|
|
OpName %_ ""
|
|
OpName %v "v"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpMemberDecorate %U_t 0 Offset 0
|
|
OpDecorate %U_t Block
|
|
OpDecorate %_ DescriptorSet 0
|
|
%void = OpTypeVoid
|
|
%8 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%uint = OpTypeInt 32 0
|
|
%U_t = OpTypeStruct %uint
|
|
%_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
|
|
%uint_0 = OpConstant %uint 0
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %8
|
|
%25 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpSelectionMerge %26 None
|
|
OpBranchConditional %false %27 %28
|
|
%27 = OpLabel
|
|
%29 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
|
|
%30 = OpLoad %uint %29
|
|
%31 = OpINotEqual %bool %30 %uint_0
|
|
OpSelectionMerge %32 None
|
|
OpBranchConditional %31 %33 %34
|
|
%33 = OpLabel
|
|
OpStore %v %21
|
|
OpBranch %32
|
|
%34 = OpLabel
|
|
OpStore %v %23
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
OpBranch %26
|
|
%28 = OpLabel
|
|
%35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
|
|
%36 = OpLoad %uint %35
|
|
%37 = OpINotEqual %bool %36 %uint_0
|
|
OpSelectionMerge %38 None
|
|
OpBranchConditional %37 %39 %40
|
|
%39 = OpLabel
|
|
OpStore %v %23
|
|
OpBranch %38
|
|
%40 = OpLabel
|
|
OpStore %v %21
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%41 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %41
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %8
|
|
%25 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
|
|
%36 = OpLoad %uint %35
|
|
%37 = OpINotEqual %bool %36 %uint_0
|
|
OpSelectionMerge %38 None
|
|
OpBranchConditional %37 %39 %40
|
|
%40 = OpLabel
|
|
OpStore %v %21
|
|
OpBranch %38
|
|
%39 = OpLabel
|
|
OpStore %v %23
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%41 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %41
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, PreventOrphanMerge) {
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%7 = 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
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float_0_5 = OpConstant %float 0.5
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %7
|
|
%16 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%17 = OpLoad %v4float %BaseColor
|
|
OpStore %v %17
|
|
OpSelectionMerge %18 None
|
|
OpBranchConditional %true %19 %20
|
|
%19 = OpLabel
|
|
OpKill
|
|
%20 = OpLabel
|
|
%21 = OpLoad %v4float %v
|
|
%22 = OpVectorTimesScalar %v4float %21 %float_0_5
|
|
OpStore %v %22
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%16 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%17 = OpLoad %v4float %BaseColor
|
|
OpStore %v %17
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
OpKill
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, HandleOrphanMerge) {
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %foo_ "foo("
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpDecorate %gl_FragColor Location 0
|
|
%void = OpTypeVoid
|
|
%6 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%9 = OpTypeFunction %v4float
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float_0 = OpConstant %float 0
|
|
%13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %6
|
|
%17 = OpLabel
|
|
%18 = OpFunctionCall %v4float %foo_
|
|
OpStore %gl_FragColor %18
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%foo_ = OpFunction %v4float None %9
|
|
%19 = OpLabel
|
|
OpSelectionMerge %20 None
|
|
OpBranchConditional %true %21 %22
|
|
%21 = OpLabel
|
|
OpReturnValue %13
|
|
%22 = OpLabel
|
|
OpReturnValue %15
|
|
%20 = OpLabel
|
|
%23 = OpUndef %v4float
|
|
OpReturnValue %23
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%foo_ = OpFunction %v4float None %9
|
|
%19 = OpLabel
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
OpReturnValue %13
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, KeepContinueTargetWhenKillAfterMerge) {
|
|
// #version 450
|
|
// void main() {
|
|
// bool c;
|
|
// bool d;
|
|
// while(c) {
|
|
// if(d) {
|
|
// continue;
|
|
// }
|
|
// if(false) {
|
|
// continue;
|
|
// }
|
|
// discard;
|
|
// }
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %c "c"
|
|
OpName %d "d"
|
|
%void = OpTypeVoid
|
|
%6 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%_ptr_Function_bool = OpTypePointer Function %bool
|
|
%false = OpConstantFalse %bool
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %6
|
|
%10 = OpLabel
|
|
%c = OpVariable %_ptr_Function_bool Function
|
|
%d = OpVariable %_ptr_Function_bool Function
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%15 = OpLoad %bool %c
|
|
OpBranchConditional %15 %16 %12
|
|
%16 = OpLabel
|
|
%17 = OpLoad %bool %d
|
|
OpSelectionMerge %18 None
|
|
OpBranchConditional %17 %19 %18
|
|
%19 = OpLabel
|
|
OpBranch %13
|
|
%18 = OpLabel
|
|
OpSelectionMerge %20 None
|
|
OpBranchConditional %false %21 %20
|
|
%21 = OpLabel
|
|
OpBranch %13
|
|
%20 = OpLabel
|
|
OpKill
|
|
%13 = OpLabel
|
|
OpBranch %11
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %6
|
|
%10 = OpLabel
|
|
%c = OpVariable %_ptr_Function_bool Function
|
|
%d = OpVariable %_ptr_Function_bool Function
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%15 = OpLoad %bool %c
|
|
OpBranchConditional %15 %16 %12
|
|
%16 = OpLabel
|
|
%17 = OpLoad %bool %d
|
|
OpSelectionMerge %18 None
|
|
OpBranchConditional %17 %19 %18
|
|
%19 = OpLabel
|
|
OpBranch %13
|
|
%18 = OpLabel
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
OpKill
|
|
%13 = OpLabel
|
|
OpBranch %11
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, DecorateDeleted) {
|
|
// Note: SPIR-V hand-edited to add decoration
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v = BaseColor;
|
|
// if (false)
|
|
// v = v * vec4(0.5,0.5,0.5,0.5);
|
|
// gl_FragColor = v;
|
|
// }
|
|
|
|
const std::string predefs_before =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpDecorate %22 RelaxedPrecision
|
|
%void = OpTypeVoid
|
|
%7 = 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
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%float_0_5 = OpConstant %float 0.5
|
|
%15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string predefs_after =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%8 = 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
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%float_0_5 = OpConstant %float 0.5
|
|
%16 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %7
|
|
%17 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%18 = OpLoad %v4float %BaseColor
|
|
OpStore %v %18
|
|
OpSelectionMerge %19 None
|
|
OpBranchConditional %false %20 %19
|
|
%20 = OpLabel
|
|
%21 = OpLoad %v4float %v
|
|
%22 = OpFMul %v4float %21 %15
|
|
OpStore %v %22
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %8
|
|
%18 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%19 = OpLoad %v4float %BaseColor
|
|
OpStore %v %19
|
|
OpBranch %20
|
|
%20 = OpLabel
|
|
%23 = OpLoad %v4float %v
|
|
OpStore %gl_FragColor %23
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs_before + before,
|
|
predefs_after + after, true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, LoopInDeadBranch) {
|
|
// #version 450
|
|
//
|
|
// layout(location = 0) in vec4 BaseColor;
|
|
// layout(location = 0) out vec4 OutColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 v = BaseColor;
|
|
// if (false)
|
|
// for (int i=0; i<3; i++)
|
|
// v = v * 0.5;
|
|
// OutColor = v;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %OutColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %v "v"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %i "i"
|
|
OpName %OutColor "OutColor"
|
|
OpDecorate %BaseColor Location 0
|
|
OpDecorate %OutColor Location 0
|
|
%void = OpTypeVoid
|
|
%8 = 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
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_0 = OpConstant %int 0
|
|
%int_3 = OpConstant %int 3
|
|
%float_0_5 = OpConstant %float 0.5
|
|
%int_1 = OpConstant %int 1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%OutColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %8
|
|
%22 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
%23 = OpLoad %v4float %BaseColor
|
|
OpStore %v %23
|
|
OpSelectionMerge %24 None
|
|
OpBranchConditional %false %25 %24
|
|
%25 = OpLabel
|
|
OpStore %i %int_0
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
OpLoopMerge %27 %28 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%30 = OpLoad %int %i
|
|
%31 = OpSLessThan %bool %30 %int_3
|
|
OpBranchConditional %31 %32 %27
|
|
%32 = OpLabel
|
|
%33 = OpLoad %v4float %v
|
|
%34 = OpVectorTimesScalar %v4float %33 %float_0_5
|
|
OpStore %v %34
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%35 = OpLoad %int %i
|
|
%36 = OpIAdd %int %35 %int_1
|
|
OpStore %i %36
|
|
OpBranch %26
|
|
%27 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%37 = OpLoad %v4float %v
|
|
OpStore %OutColor %37
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %8
|
|
%22 = OpLabel
|
|
%v = OpVariable %_ptr_Function_v4float Function
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
%23 = OpLoad %v4float %BaseColor
|
|
OpStore %v %23
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%37 = OpLoad %v4float %v
|
|
OpStore %OutColor %37
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SwitchLiveCase) {
|
|
// #version 450
|
|
//
|
|
// layout (location=0) in vec4 BaseColor;
|
|
// layout (location=0) out vec4 OutColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// switch (1) {
|
|
// case 0:
|
|
// OutColor = vec4(0.0,0.0,0.0,0.0);
|
|
// break;
|
|
// case 1:
|
|
// OutColor = vec4(0.125,0.125,0.125,0.125);
|
|
// break;
|
|
// case 2:
|
|
// OutColor = vec4(0.25,0.25,0.25,0.25);
|
|
// break;
|
|
// default:
|
|
// OutColor = vec4(1.0,1.0,1.0,1.0);
|
|
// }
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %OutColor %BaseColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %OutColor "OutColor"
|
|
OpName %BaseColor "BaseColor"
|
|
OpDecorate %OutColor Location 0
|
|
OpDecorate %BaseColor Location 0
|
|
%void = OpTypeVoid
|
|
%6 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%int_1 = OpConstant %int 1
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%OutColor = OpVariable %_ptr_Output_v4float Output
|
|
%float_0 = OpConstant %float 0
|
|
%13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_0_125 = OpConstant %float 0.125
|
|
%15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
|
|
%float_0_25 = OpConstant %float 0.25
|
|
%17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
|
|
%float_1 = OpConstant %float 1
|
|
%19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %6
|
|
%21 = OpLabel
|
|
OpSelectionMerge %22 None
|
|
OpSwitch %int_1 %23 0 %24 1 %25 2 %26
|
|
%23 = OpLabel
|
|
OpStore %OutColor %19
|
|
OpBranch %22
|
|
%24 = OpLabel
|
|
OpStore %OutColor %13
|
|
OpBranch %22
|
|
%25 = OpLabel
|
|
OpStore %OutColor %15
|
|
OpBranch %22
|
|
%26 = OpLabel
|
|
OpStore %OutColor %17
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %6
|
|
%21 = OpLabel
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
OpStore %OutColor %15
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SwitchLiveDefault) {
|
|
// #version 450
|
|
//
|
|
// layout (location=0) in vec4 BaseColor;
|
|
// layout (location=0) out vec4 OutColor;
|
|
//
|
|
// void main()
|
|
// {
|
|
// switch (7) {
|
|
// case 0:
|
|
// OutColor = vec4(0.0,0.0,0.0,0.0);
|
|
// break;
|
|
// case 1:
|
|
// OutColor = vec4(0.125,0.125,0.125,0.125);
|
|
// break;
|
|
// case 2:
|
|
// OutColor = vec4(0.25,0.25,0.25,0.25);
|
|
// break;
|
|
// default:
|
|
// OutColor = vec4(1.0,1.0,1.0,1.0);
|
|
// }
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %OutColor %BaseColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %OutColor "OutColor"
|
|
OpName %BaseColor "BaseColor"
|
|
OpDecorate %OutColor Location 0
|
|
OpDecorate %BaseColor Location 0
|
|
%void = OpTypeVoid
|
|
%6 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%int_7 = OpConstant %int 7
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%OutColor = OpVariable %_ptr_Output_v4float Output
|
|
%float_0 = OpConstant %float 0
|
|
%13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_0_125 = OpConstant %float 0.125
|
|
%15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
|
|
%float_0_25 = OpConstant %float 0.25
|
|
%17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
|
|
%float_1 = OpConstant %float 1
|
|
%19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %6
|
|
%21 = OpLabel
|
|
OpSelectionMerge %22 None
|
|
OpSwitch %int_7 %23 0 %24 1 %25 2 %26
|
|
%23 = OpLabel
|
|
OpStore %OutColor %19
|
|
OpBranch %22
|
|
%24 = OpLabel
|
|
OpStore %OutColor %13
|
|
OpBranch %22
|
|
%25 = OpLabel
|
|
OpStore %OutColor %15
|
|
OpBranch %22
|
|
%26 = OpLabel
|
|
OpStore %OutColor %17
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %6
|
|
%21 = OpLabel
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
OpStore %OutColor %19
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SwitchLiveCaseBreakFromLoop) {
|
|
// This sample does not directly translate to GLSL/HLSL as
|
|
// direct breaks from a loop cannot be made from a switch.
|
|
// This construct is currently formed by inlining a function
|
|
// containing early returns from the cases of a switch. The
|
|
// function is wrapped in a one-trip loop and returns are
|
|
// translated to branches to the loop's merge block.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %OutColor %BaseColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %oc "oc"
|
|
OpName %OutColor "OutColor"
|
|
OpName %BaseColor "BaseColor"
|
|
OpDecorate %OutColor Location 0
|
|
OpDecorate %BaseColor Location 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%false = OpConstantFalse %bool
|
|
%int = OpTypeInt 32 1
|
|
%int_1 = OpConstant %int 1
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
%17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_0_125 = OpConstant %float 0.125
|
|
%19 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125
|
|
%float_0_25 = OpConstant %float 0.25
|
|
%21 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25
|
|
%float_1 = OpConstant %float 1
|
|
%23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%OutColor = 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 %7
|
|
%26 = OpLabel
|
|
%oc = OpVariable %_ptr_Function_v4float Function
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
OpLoopMerge %28 %29 None
|
|
OpBranch %30
|
|
%30 = OpLabel
|
|
OpSelectionMerge %31 None
|
|
OpSwitch %int_1 %31 0 %32 1 %33 2 %34
|
|
%32 = OpLabel
|
|
OpStore %oc %17
|
|
OpBranch %28
|
|
%33 = OpLabel
|
|
OpStore %oc %19
|
|
OpBranch %28
|
|
%34 = OpLabel
|
|
OpStore %oc %21
|
|
OpBranch %28
|
|
%31 = OpLabel
|
|
OpStore %oc %23
|
|
OpBranch %28
|
|
%29 = OpLabel
|
|
OpBranchConditional %false %27 %28
|
|
%28 = OpLabel
|
|
%35 = OpLoad %v4float %oc
|
|
OpStore %OutColor %35
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %7
|
|
%26 = OpLabel
|
|
%oc = OpVariable %_ptr_Function_v4float Function
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
OpLoopMerge %28 %29 None
|
|
OpBranch %30
|
|
%30 = OpLabel
|
|
OpBranch %33
|
|
%33 = OpLabel
|
|
OpStore %oc %19
|
|
OpBranch %28
|
|
%29 = OpLabel
|
|
OpBranch %27
|
|
%28 = OpLabel
|
|
%35 = OpLoad %v4float %oc
|
|
OpStore %OutColor %35
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after,
|
|
true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, LeaveContinueBackedge) {
|
|
const std::string text = R"(
|
|
; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
|
|
; CHECK: [[continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]]
|
|
; CHECK-NEXT: [[merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%void = OpTypeVoid
|
|
%funcTy = OpTypeFunction %void
|
|
%func = OpFunction %void None %funcTy
|
|
%1 = OpLabel
|
|
OpBranch %2
|
|
%2 = OpLabel
|
|
OpLoopMerge %3 %4 None
|
|
OpBranch %4
|
|
%4 = OpLabel
|
|
; Be careful we don't remove the backedge to %2 despite never taking it.
|
|
OpBranchConditional %false %2 %3
|
|
%3 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) {
|
|
const std::string text = R"(
|
|
; CHECK: OpBranch [[header:%\w+]]
|
|
; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
|
|
; CHECK-NEXT: OpBranch [[continue]]
|
|
; CHECK-NEXT: [[continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[extra:%\w+]] [[merge]]
|
|
; CHECK-NEXT: [[extra]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header]]
|
|
; CHECK-NEXT: [[merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%void = OpTypeVoid
|
|
%funcTy = OpTypeFunction %void
|
|
%func = OpFunction %void None %funcTy
|
|
%1 = OpLabel
|
|
OpBranch %2
|
|
%2 = OpLabel
|
|
OpLoopMerge %3 %4 None
|
|
OpBranch %4
|
|
%4 = OpLabel
|
|
; Be careful we don't remove the backedge to %2 despite never taking it.
|
|
OpBranchConditional %false %5 %3
|
|
; This block remains live despite being unreachable.
|
|
%5 = OpLabel
|
|
OpBranch %2
|
|
%3 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, RemovePhiWithUnreachableContinue) {
|
|
const std::string text = R"(
|
|
; CHECK: [[entry:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header:%\w+]]
|
|
; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
|
|
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
|
; CHECK-NEXT: [[ret]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK: [[continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header]]
|
|
; CHECK: [[merge]] = OpLabel
|
|
; CHECK-NEXT: OpUnreachable
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%void = OpTypeVoid
|
|
%funcTy = OpTypeFunction %void
|
|
%func = OpFunction %void None %funcTy
|
|
%1 = OpLabel
|
|
OpBranch %2
|
|
%2 = OpLabel
|
|
%phi = OpPhi %bool %false %1 %true %continue
|
|
OpLoopMerge %merge %continue None
|
|
OpBranch %3
|
|
%3 = OpLabel
|
|
OpReturn
|
|
%continue = OpLabel
|
|
OpBranch %2
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, UnreachableLoopMergeAndContinueTargets) {
|
|
const std::string text = R"(
|
|
; CHECK: [[undef:%\w+]] = OpUndef %bool
|
|
; CHECK: OpSelectionMerge [[header:%\w+]]
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] [[else_lab:%\w+]]
|
|
; CHECK: OpPhi %bool %false [[if_lab]] %false [[else_lab]] [[undef]] [[continue:%\w+]]
|
|
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
|
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
|
; CHECK-NEXT: [[ret]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK: [[continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header]]
|
|
; CHECK: [[merge]] = OpLabel
|
|
; CHECK-NEXT: OpUnreachable
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%void = OpTypeVoid
|
|
%funcTy = OpTypeFunction %void
|
|
%func = OpFunction %void None %funcTy
|
|
%1 = OpLabel
|
|
%c = OpUndef %bool
|
|
OpSelectionMerge %2 None
|
|
OpBranchConditional %c %if %else
|
|
%if = OpLabel
|
|
OpBranch %2
|
|
%else = OpLabel
|
|
OpBranch %2
|
|
%2 = OpLabel
|
|
%phi = OpPhi %bool %false %if %false %else %true %continue
|
|
OpLoopMerge %merge %continue None
|
|
OpBranch %3
|
|
%3 = OpLabel
|
|
OpReturn
|
|
%continue = OpLabel
|
|
OpBranch %2
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
TEST_F(DeadBranchElimTest, EarlyReconvergence) {
|
|
const std::string text = R"(
|
|
; CHECK-NOT: OpBranchConditional
|
|
; CHECK: [[logical:%\w+]] = OpLogicalOr
|
|
; CHECK-NOT: OpPhi
|
|
; CHECK: OpLogicalAnd {{%\w+}} {{%\w+}} [[logical]]
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %func "func"
|
|
OpExecutionMode %func OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%func_ty = OpTypeFunction %void
|
|
%func = OpFunction %void None %func_ty
|
|
%1 = OpLabel
|
|
OpSelectionMerge %2 None
|
|
OpBranchConditional %false %3 %4
|
|
%3 = OpLabel
|
|
%12 = OpLogicalNot %bool %true
|
|
OpBranch %2
|
|
%4 = OpLabel
|
|
OpSelectionMerge %14 None
|
|
OpBranchConditional %false %5 %6
|
|
%5 = OpLabel
|
|
%10 = OpLogicalAnd %bool %true %false
|
|
OpBranch %7
|
|
%6 = OpLabel
|
|
%11 = OpLogicalOr %bool %true %false
|
|
OpBranch %7
|
|
%7 = OpLabel
|
|
; This phi is in a block preceeding the merge %14!
|
|
%8 = OpPhi %bool %10 %5 %11 %6
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
OpBranch %2
|
|
%2 = OpLabel
|
|
%9 = OpPhi %bool %12 %3 %8 %14
|
|
%13 = OpLogicalAnd %bool %true %9
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloating) {
|
|
const std::string text = R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NEXT: OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK-NEXT: OpFunctionEnd
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%1 = OpTypeFunction %void
|
|
%func = OpFunction %void None %1
|
|
%2 = OpLabel
|
|
OpReturn
|
|
%3 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloatingJoin) {
|
|
const std::string text = R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NEXT: OpFunctionParameter
|
|
; CHECK-NEXT: OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK-NEXT: OpFunctionEnd
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%1 = OpTypeFunction %void %bool
|
|
%func = OpFunction %void None %1
|
|
%bool_param = OpFunctionParameter %bool
|
|
%2 = OpLabel
|
|
OpReturn
|
|
%3 = OpLabel
|
|
OpSelectionMerge %6 None
|
|
OpBranchConditional %bool_param %4 %5
|
|
%4 = OpLabel
|
|
OpBranch %6
|
|
%5 = OpLabel
|
|
OpBranch %6
|
|
%6 = OpLabel
|
|
%7 = OpPhi %bool %true %4 %false %6
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksDeadPhi) {
|
|
const std::string text = R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NEXT: OpFunctionParameter
|
|
; CHECK-NEXT: OpLabel
|
|
; CHECK-NEXT: OpBranch [[label:%\w+]]
|
|
; CHECK-NEXT: [[label]] = OpLabel
|
|
; CHECK-NEXT: OpLogicalNot %bool %true
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK-NEXT: OpFunctionEnd
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%1 = OpTypeFunction %void %bool
|
|
%func = OpFunction %void None %1
|
|
%bool_param = OpFunctionParameter %bool
|
|
%2 = OpLabel
|
|
OpBranch %3
|
|
%4 = OpLabel
|
|
OpBranch %3
|
|
%3 = OpLabel
|
|
%5 = OpPhi %bool %true %2 %false %4
|
|
%6 = OpLogicalNot %bool %5
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksPartiallyDeadPhi) {
|
|
const std::string text = R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter
|
|
; CHECK-NEXT: OpLabel
|
|
; CHECK-NEXT: OpBranchConditional [[param]] [[merge:%\w+]] [[br:%\w+]]
|
|
; CHECK-NEXT: [[merge]] = OpLabel
|
|
; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool %true %2 %false [[br]]
|
|
; CHECK-NEXT: OpLogicalNot %bool [[phi]]
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK-NEXT: [[br]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[merge]]
|
|
; CHECK-NEXT: OpFunctionEnd
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%1 = OpTypeFunction %void %bool
|
|
%func = OpFunction %void None %1
|
|
%bool_param = OpFunctionParameter %bool
|
|
%2 = OpLabel
|
|
OpBranchConditional %bool_param %3 %7
|
|
%7 = OpLabel
|
|
OpBranch %3
|
|
%4 = OpLabel
|
|
OpBranch %3
|
|
%3 = OpLabel
|
|
%5 = OpPhi %bool %true %2 %false %7 %false %4
|
|
%6 = OpLogicalNot %bool %5
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, LiveHeaderDeadPhi) {
|
|
const std::string text = R"(
|
|
; CHECK: OpLabel
|
|
; CHECK-NOT: OpBranchConditional
|
|
; CHECK-NOT: OpPhi
|
|
; CHECK: OpLogicalNot %bool %false
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%false = OpConstantFalse %bool
|
|
%func_ty = OpTypeFunction %void
|
|
%func = OpFunction %void None %func_ty
|
|
%1 = OpLabel
|
|
OpSelectionMerge %3 None
|
|
OpBranchConditional %true %2 %3
|
|
%2 = OpLabel
|
|
OpBranch %3
|
|
%3 = OpLabel
|
|
%5 = OpPhi %bool %true %3 %false %2
|
|
%6 = OpLogicalNot %bool %5
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksLive) {
|
|
const std::string text = R"(
|
|
; CHECK: [[entry:%\w+]] = OpLabel
|
|
; CHECK-NOT: OpSelectionMerge
|
|
; CHECK: OpBranch [[header:%\w+]]
|
|
; CHECK-NEXT: [[header]] = OpLabel
|
|
; CHECK-NEXT: OpPhi %bool %true [[entry]] %false [[backedge:%\w+]]
|
|
; CHECK-NEXT: OpLoopMerge
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%false = OpConstantFalse %bool
|
|
%func_ty = OpTypeFunction %void %bool
|
|
%func = OpFunction %void None %func_ty
|
|
%param = OpFunctionParameter %bool
|
|
%entry = OpLabel
|
|
OpSelectionMerge %if_merge None
|
|
; This dead branch is included to ensure the pass does work.
|
|
OpBranchConditional %false %if_merge %loop_header
|
|
%loop_header = OpLabel
|
|
; Both incoming edges are live, so the phi should be untouched.
|
|
%phi = OpPhi %bool %true %entry %false %backedge
|
|
OpLoopMerge %loop_merge %continue None
|
|
OpBranchConditional %param %loop_merge %continue
|
|
%continue = OpLabel
|
|
OpBranch %backedge
|
|
%backedge = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpBranch %if_merge
|
|
%if_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksUnreachable) {
|
|
const std::string text = R"(
|
|
; CHECK: [[entry:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header:%\w+]]
|
|
; CHECK-NEXT: [[header]] = OpLabel
|
|
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
|
|
; CHECK-NEXT: OpBranch [[merge]]
|
|
; CHECK-NEXT: [[merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
; CHECK-NEXT: [[continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header]]
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%false = OpConstantFalse %bool
|
|
%func_ty = OpTypeFunction %void %bool
|
|
%func = OpFunction %void None %func_ty
|
|
%param = OpFunctionParameter %bool
|
|
%entry = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
; Since the continue is unreachable, %backedge will be removed. The phi will
|
|
; instead require an edge from %continue.
|
|
%phi = OpPhi %bool %true %entry %false %backedge
|
|
OpLoopMerge %merge %continue None
|
|
OpBranch %merge
|
|
%continue = OpLabel
|
|
OpBranch %backedge
|
|
%backedge = OpLabel
|
|
OpBranch %loop_header
|
|
%merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, NoUnnecessaryChanges) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %func "func"
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef = OpUndef %bool
|
|
%functy = OpTypeFunction %void
|
|
%func = OpFunction %void None %functy
|
|
%1 = OpLabel
|
|
OpBranch %2
|
|
%2 = OpLabel
|
|
OpLoopMerge %4 %5 None
|
|
OpBranch %6
|
|
%6 = OpLabel
|
|
OpReturn
|
|
%5 = OpLabel
|
|
OpBranch %2
|
|
%4 = OpLabel
|
|
OpUnreachable
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
auto result = SinglePassRunToBinary<DeadBranchElimPass>(text, true);
|
|
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, ExtraBackedgePartiallyDead) {
|
|
const std::string text = R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: [[header:%\w+]] = OpLabel
|
|
; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
|
|
; CHECK: [[merge]] = OpLabel
|
|
; CHECK: [[continue]] = OpLabel
|
|
; CHECK: OpBranch [[extra:%\w+]]
|
|
; CHECK: [[extra]] = OpLabel
|
|
; CHECK-NOT: OpSelectionMerge
|
|
; CHECK-NEXT: OpBranch [[else:%\w+]]
|
|
; CHECK-NEXT: [[else]] = OpLabel
|
|
; CHECK-NEXT: OpLogicalOr
|
|
; CHECK-NEXT: OpBranch [[backedge:%\w+]]
|
|
; CHECK-NEXT: [[backedge:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header]]
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpName %func "func"
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%false = OpConstantFalse %bool
|
|
%func_ty = OpTypeFunction %void %bool
|
|
%func = OpFunction %void None %func_ty
|
|
%param = OpFunctionParameter %bool
|
|
%entry = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %continue None
|
|
OpBranchConditional %param %loop_merge %continue
|
|
%continue = OpLabel
|
|
OpBranch %extra
|
|
%extra = OpLabel
|
|
OpSelectionMerge %backedge None
|
|
OpBranchConditional %false %then %else
|
|
%then = OpLabel
|
|
%and = OpLogicalAnd %bool %true %false
|
|
OpBranch %backedge
|
|
%else = OpLabel
|
|
%or = OpLogicalOr %bool %true %false
|
|
OpBranch %backedge
|
|
%backedge = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, UnreachableContinuePhiInMerge) {
|
|
const std::string text = R"(
|
|
; CHECK: [[entry:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header:%\w+]]
|
|
; CHECK-NEXT: [[header]] = OpLabel
|
|
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None
|
|
; CHECK-NEXT: OpBranch [[label:%\w+]]
|
|
; CHECK-NEXT: [[label]] = OpLabel
|
|
; CHECK-NEXT: [[fadd:%\w+]] = OpFAdd
|
|
; CHECK-NEXT: OpBranch [[label:%\w+]]
|
|
; CHECK-NEXT: [[label]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[merge]]
|
|
; CHECK-NEXT: [[continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[header]]
|
|
; CHECK-NEXT: [[merge]] = OpLabel
|
|
; CHECK-NEXT: OpStore {{%\w+}} [[fadd]]
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %o
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
|
|
OpSourceExtension "GL_GOOGLE_include_directive"
|
|
OpName %main "main"
|
|
OpName %o "o"
|
|
OpName %S "S"
|
|
OpMemberName %S 0 "a"
|
|
OpName %U_t "U_t"
|
|
OpMemberName %U_t 0 "g_F"
|
|
OpMemberName %U_t 1 "g_F2"
|
|
OpDecorate %o Location 0
|
|
OpMemberDecorate %S 0 Offset 0
|
|
OpMemberDecorate %U_t 0 Volatile
|
|
OpMemberDecorate %U_t 0 Offset 0
|
|
OpMemberDecorate %U_t 1 Offset 4
|
|
OpDecorate %U_t BufferBlock
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%float_0 = OpConstant %float 0
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_0 = OpConstant %int 0
|
|
%int_10 = OpConstant %int 10
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float_1 = OpConstant %float 1
|
|
%float_5 = OpConstant %float 5
|
|
%int_1 = OpConstant %int 1
|
|
%_ptr_Output_float = OpTypePointer Output %float
|
|
%o = OpVariable %_ptr_Output_float Output
|
|
%S = OpTypeStruct %float
|
|
%U_t = OpTypeStruct %S %S
|
|
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
|
|
%main = OpFunction %void None %7
|
|
%22 = OpLabel
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %float %float_0 %22 %25 %26
|
|
%27 = OpPhi %int %int_0 %22 %28 %26
|
|
OpLoopMerge %29 %26 None
|
|
OpBranch %40
|
|
%40 = OpLabel
|
|
%25 = OpFAdd %float %24 %float_1
|
|
OpSelectionMerge %30 None
|
|
OpBranchConditional %true %31 %30
|
|
%31 = OpLabel
|
|
OpBranch %29
|
|
%30 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%28 = OpIAdd %int %27 %int_1
|
|
%32 = OpSLessThan %bool %27 %int_10
|
|
; continue block branches to the header or another none dead block.
|
|
OpBranchConditional %32 %23 %29
|
|
%29 = OpLabel
|
|
%33 = OpPhi %float %24 %26 %25 %31
|
|
OpStore %o %33
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, NonStructuredIf) {
|
|
const std::string text = R"(
|
|
; CHECK-NOT: OpBranchConditional
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Logical OpenCL
|
|
OpDecorate %func LinkageAttributes "func" Export
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%functy = OpTypeFunction %void
|
|
%func = OpFunction %void None %functy
|
|
%entry = OpLabel
|
|
OpBranchConditional %true %then %else
|
|
%then = OpLabel
|
|
OpBranch %final
|
|
%else = OpLabel
|
|
OpBranch %final
|
|
%final = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, ReorderBlocks) {
|
|
const std::string text = R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: OpBranch [[label:%\w+]]
|
|
; CHECK: [[label:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpLogicalNot
|
|
; CHECK-NEXT: OpBranch [[label:%\w+]]
|
|
; CHECK: [[label]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %func "func"
|
|
OpExecutionMode %func OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%func_ty = OpTypeFunction %void
|
|
%func = OpFunction %void None %func_ty
|
|
%1 = OpLabel
|
|
OpSelectionMerge %3 None
|
|
OpBranchConditional %true %2 %3
|
|
%3 = OpLabel
|
|
OpReturn
|
|
%2 = OpLabel
|
|
%not = OpLogicalNot %bool %true
|
|
OpBranch %3
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) {
|
|
// Checks are not important. The validation post optimization is the
|
|
// important part.
|
|
const std::string text = R"(
|
|
; CHECK: OpLabel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %func "func"
|
|
OpExecutionMode %func OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%func_ty = OpTypeFunction %void
|
|
%func = OpFunction %void None %func_ty
|
|
%1 = OpLabel
|
|
OpSelectionMerge %3 None
|
|
OpBranchConditional %true %2 %3
|
|
%3 = OpLabel
|
|
OpReturn
|
|
%2 = OpLabel
|
|
OpBranch %4
|
|
%4 = OpLabel
|
|
OpBranch %3
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) {
|
|
// Checks are not important. The validation post optimization is the
|
|
// important part.
|
|
const std::string text = R"(
|
|
; CHECK: OpLabel
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %func "func"
|
|
OpExecutionMode %func OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%func_ty = OpTypeFunction %void
|
|
%func = OpFunction %void None %func_ty
|
|
%1 = OpLabel
|
|
OpSelectionMerge %3 None
|
|
OpBranchConditional %true %2 %3
|
|
%3 = OpLabel
|
|
OpBranch %5
|
|
%5 = OpLabel
|
|
OpReturn
|
|
%2 = OpLabel
|
|
OpBranch %4
|
|
%4 = OpLabel
|
|
OpBranch %3
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit1) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to the merge node, then the OpSelectionMerge instruction is positioned
|
|
// correctly.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NEXT: OpLabel
|
|
; CHECK-NEXT: OpBranch [[taken_branch:%\w+]]
|
|
; CHECK-NEXT: [[taken_branch]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[merge]] {{%\w+}}
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpSelectionMerge %outer_merge None
|
|
OpBranchConditional %true %bb1 %bb3
|
|
%bb1 = OpLabel
|
|
OpBranchConditional %undef_bool %outer_merge %bb2
|
|
%bb2 = OpLabel
|
|
OpBranch %outer_merge
|
|
%bb3 = OpLabel
|
|
OpBranch %outer_merge
|
|
%outer_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit2) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to the merge node, then the OpSelectionMerge instruction is positioned
|
|
// correctly.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NEXT: OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK-NEXT: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[inner_merge:%\w+]]
|
|
; CHECK: [[inner_merge]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[outer_merge:%\w+]]
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[outer_merge]:%\w+]] {{%\w+}}
|
|
; CHECK: [[outer_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpSelectionMerge %outer_merge None
|
|
OpBranchConditional %true %bb1 %bb5
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %inner_merge None
|
|
OpBranchConditional %undef_bool %bb2 %bb3
|
|
%bb2 = OpLabel
|
|
OpBranch %inner_merge
|
|
%bb3 = OpLabel
|
|
OpBranch %inner_merge
|
|
%inner_merge = OpLabel
|
|
OpBranchConditional %undef_bool %outer_merge %bb4
|
|
%bb4 = OpLabel
|
|
OpBranch %outer_merge
|
|
%bb5 = OpLabel
|
|
OpBranch %outer_merge
|
|
%outer_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithConditionalExit) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to the merge node, then we keep the OpSelectionMerge on that branch.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%undef_int = OpUndef %uint
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
|
|
; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 1 [[bb3:%\w+]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpSwitch %undef_int %sel_merge 1 %bb3
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to a loop surrounding the selection merge, then we do not keep the
|
|
// OpSelectionMerge instruction.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_merge]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpBranchConditional %undef_bool %bb3 %loop_merge
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to continue of a loop surrounding the selection merge, then we do not keep
|
|
// the OpSelectionMerge instruction.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(;
|
|
; CHECK: OpLabel
|
|
; CHECK: [[loop_header:%\w+]] = OpLabel
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_cont]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_header]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpBranchConditional %undef_bool %bb3 %cont
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop2) {
|
|
// Same as |SelectionMergeWithExitToLoop|, except the switch goes to the loop
|
|
// merge or the selection merge. In this case, we do not need an
|
|
// OpSelectionMerge either.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_merge]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpBranchConditional %undef_bool %sel_merge %loop_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue2) {
|
|
// Same as |SelectionMergeWithExitToLoopContinue|, except the branch goes to
|
|
// the loop continue or the selection merge. In this case, we do not need an
|
|
// OpSelectionMerge either.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: [[loop_header:%\w+]] = OpLabel
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_cont]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_cont]] = OpLabel
|
|
; CHECK: OpBranch [[loop_header]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpBranchConditional %undef_bool %sel_merge %cont
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop3) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to the merge of a surrounding loop, the selection merge, and another block
|
|
// inside the selection merge, then we must keep the OpSelectionMerge
|
|
// instruction on that branch.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%undef_int = OpUndef %uint
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
|
|
; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpSwitch %undef_int %sel_merge 0 %loop_merge 1 %bb3
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue3) {
|
|
// Checks that if a selection merge construct contains a conditional branch
|
|
// to the merge of a surrounding loop, the selection merge, and another block
|
|
// inside the selection merge, then we must keep the OpSelectionMerge
|
|
// instruction on that branch.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%undef_int = OpUndef %uint
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: [[loop_header:%\w+]] = OpLabel
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_continue:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None
|
|
; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_continue]] 1 [[bb3:%\w+]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_continue]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_header]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpSwitch %undef_int %sel_merge 0 %cont 1 %bb3
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop4) {
|
|
// Same as |SelectionMergeWithExitToLoop|, except the branch in the selection
|
|
// construct is an |OpSwitch| instead of an |OpConditionalBranch|. The
|
|
// OpSelectionMerge instruction is not needed in this case either.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%undef_int = OpUndef %uint
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpSwitch %undef_int %bb3 0 %loop_merge 1 %bb3
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue4) {
|
|
// Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
|
|
// selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
|
|
// The OpSelectionMerge instruction is not needed in this case either.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%undef_int = OpUndef %uint
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_cont]] 1 [[bb3:%\w+]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
|
|
; CHECK: [[sel_merge]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %sel_merge None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpSwitch %undef_int %bb3 0 %cont 1 %bb3
|
|
%bb3 = OpLabel
|
|
OpBranch %sel_merge
|
|
%bb4 = OpLabel
|
|
OpBranch %sel_merge
|
|
%sel_merge = OpLabel
|
|
OpBranch %loop_merge
|
|
%cont = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeSameAsLoopContinue) {
|
|
// Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the
|
|
// selection construct is an |OpSwitch| instead of an |OpConditionalBranch|.
|
|
// The OpSelectionMerge instruction is not needed in this case either.
|
|
const std::string predefs = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%void = OpTypeVoid
|
|
%func_type = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%undef_bool = OpUndef %bool
|
|
)";
|
|
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: [[loop_header:%\w+]] = OpLabel
|
|
; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]]
|
|
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
|
; CHECK: [[bb1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NEXT: OpSelectionMerge [[loop_cont]]
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]]
|
|
; CHECK: [[bb3]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[loop_cont]]
|
|
; CHECK: [[loop_cont]] = OpLabel
|
|
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[loop_header]] [[loop_merge]]
|
|
; CHECK: [[loop_merge]] = OpLabel
|
|
; CHECK-NEXT: OpReturn
|
|
%main = OpFunction %void None %func_type
|
|
%entry_bb = OpLabel
|
|
OpBranch %loop_header
|
|
%loop_header = OpLabel
|
|
OpLoopMerge %loop_merge %cont None
|
|
OpBranch %bb1
|
|
%bb1 = OpLabel
|
|
OpSelectionMerge %cont None
|
|
OpBranchConditional %true %bb2 %bb4
|
|
%bb2 = OpLabel
|
|
OpBranchConditional %undef_bool %bb3 %cont
|
|
%bb3 = OpLabel
|
|
OpBranch %cont
|
|
%bb4 = OpLabel
|
|
OpBranch %cont
|
|
%cont = OpLabel
|
|
OpBranchConditional %undef_bool %loop_header %loop_merge
|
|
%loop_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// The selection merge in the loop naming the continue target as merge is
|
|
// invalid, but handled by this pass so validation is disabled.
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, false);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) {
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpSelectionMerge [[merge1:%\w+]]
|
|
; CHECK: [[merge1]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[preheader:%\w+]]
|
|
; CHECK: [[preheader]] = OpLabel
|
|
; CHECK-NOT: OpLabel
|
|
; CHECK: OpBranch [[header:%\w+]]
|
|
; CHECK: [[header]] = OpLabel
|
|
; CHECK-NOT: OpLabel
|
|
; CHECK: OpLoopMerge [[merge2:%\w+]]
|
|
; CHECK: [[merge2]] = OpLabel
|
|
; CHECK-NEXT: OpUnreachable
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource ESSL 310
|
|
OpName %main "main"
|
|
OpName %h "h"
|
|
OpName %i "i"
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%_ptr_Function_bool = OpTypePointer Function %bool
|
|
%true = OpConstantTrue %bool
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_1 = OpConstant %int 1
|
|
%int_0 = OpConstant %int 0
|
|
%27 = OpUndef %bool
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%h = OpVariable %_ptr_Function_bool Function
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
OpSelectionMerge %11 None
|
|
OpBranchConditional %27 %10 %11
|
|
%10 = OpLabel
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
OpSelectionMerge %14 None
|
|
OpBranchConditional %true %13 %14
|
|
%13 = OpLabel
|
|
OpStore %i %int_1
|
|
OpBranch %19
|
|
%19 = OpLabel
|
|
OpLoopMerge %21 %22 None
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%26 = OpSGreaterThan %bool %int_1 %int_0
|
|
OpBranchConditional %true %20 %21
|
|
%20 = OpLabel
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
OpBranch %19
|
|
%21 = OpLabel
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, DontFoldBackedge) {
|
|
const std::string body =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%2 = OpFunction %void None %4
|
|
%7 = OpLabel
|
|
OpBranch %8
|
|
%8 = OpLabel
|
|
OpLoopMerge %9 %10 None
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
%12 = OpUndef %bool
|
|
OpSelectionMerge %10 None
|
|
OpBranchConditional %12 %13 %10
|
|
%13 = OpLabel
|
|
OpBranch %9
|
|
%10 = OpLabel
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
OpBranchConditional %false %8 %9
|
|
%9 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(body, body, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, FoldBackedgeToHeader) {
|
|
const std::string body =
|
|
R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: [[header:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpLoopMerge {{%\w+}} [[cont:%\w+]]
|
|
; CHECK: [[cont]] = OpLabel
|
|
; This branch may not be in the continue block, but must come after it.
|
|
; CHECK: OpBranch [[header]]
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%2 = OpFunction %void None %4
|
|
%7 = OpLabel
|
|
OpBranch %8
|
|
%8 = OpLabel
|
|
OpLoopMerge %9 %10 None
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
%12 = OpUndef %bool
|
|
OpSelectionMerge %10 None
|
|
OpBranchConditional %12 %13 %10
|
|
%13 = OpLabel
|
|
OpBranch %9
|
|
%10 = OpLabel
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
OpBranchConditional %true %8 %9
|
|
%9 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// The selection merge in the loop naming the continue target as merge is
|
|
// invalid, but handled by this pass so validation is disabled.
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(body, false);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, UnreachableMergeAndContinueSameBlock) {
|
|
const std::string spirv = R"(
|
|
; CHECK: OpLabel
|
|
; CHECK: [[outer:%\w+]] = OpLabel
|
|
; CHECK-NEXT: OpLoopMerge [[outer_merge:%\w+]] [[outer_cont:%\w+]] None
|
|
; CHECK-NEXT: OpBranch [[inner:%\w+]]
|
|
; CHECK: [[inner]] = OpLabel
|
|
; CHECK: OpLoopMerge [[outer_cont]] [[inner_cont:%\w+]] None
|
|
; CHECK: [[inner_cont]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[inner]]
|
|
; CHECK: [[outer_cont]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[outer]]
|
|
; CHECK: [[outer_merge]] = OpLabel
|
|
; CHECK-NEXT: OpUnreachable
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %main "main"
|
|
OpExecutionMode %main LocalSize 1 1 1
|
|
%void = OpTypeVoid
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%void_fn = OpTypeFunction %void
|
|
%main = OpFunction %void None %void_fn
|
|
%entry = OpLabel
|
|
OpBranch %outer_loop
|
|
%outer_loop = OpLabel
|
|
OpLoopMerge %outer_merge %outer_continue None
|
|
OpBranch %inner_loop
|
|
%inner_loop = OpLabel
|
|
OpLoopMerge %outer_continue %inner_continue None
|
|
OpBranch %inner_body
|
|
%inner_body = OpLabel
|
|
OpSelectionMerge %inner_continue None
|
|
OpBranchConditional %true %ret %inner_continue
|
|
%ret = OpLabel
|
|
OpReturn
|
|
%inner_continue = OpLabel
|
|
OpBranchConditional %true %outer_continue %inner_loop
|
|
%outer_continue = OpLabel
|
|
OpBranchConditional %true %outer_merge %outer_loop
|
|
%outer_merge = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
|
|
}
|
|
|
|
// Fold a switch with a nested break. The only case should be the default.
|
|
TEST_F(DeadBranchElimTest, FoldSwitchWithNestedBreak) {
|
|
const std::string spirv = R"(
|
|
; CHECK: OpSwitch %int_3 [[case_bb:%\w+]]{{[[:space:]]}}
|
|
; CHECK: [[case_bb]] = OpLabel
|
|
; CHECK-NEXT: OpUndef
|
|
; CHECK-NEXT: OpSelectionMerge
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %2 "main"
|
|
OpSource GLSL 450
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_3 = OpConstant %int 3
|
|
%int_1 = OpConstant %int 1
|
|
%bool = OpTypeBool
|
|
%2 = OpFunction %void None %4
|
|
%10 = OpLabel
|
|
OpSelectionMerge %11 None
|
|
OpSwitch %int_3 %12 3 %13
|
|
%12 = OpLabel
|
|
OpBranch %11
|
|
%13 = OpLabel
|
|
%14 = OpUndef %bool
|
|
OpSelectionMerge %15 None
|
|
OpBranchConditional %14 %16 %15
|
|
%16 = OpLabel
|
|
OpBranch %11
|
|
%15 = OpLabel
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, FoldBranchWithBreakToSwitch) {
|
|
const std::string spirv = R"(
|
|
; CHECK: OpSelectionMerge [[sel_merge:%\w+]]
|
|
; CHECK-NEXT: OpSwitch {{%\w+}} {{%\w+}} 3 [[bb:%\w+]]
|
|
; CHECK: [[bb]] = OpLabel
|
|
; CHECK-NEXT: OpBranch [[bb2:%\w+]]
|
|
; CHECK: [[bb2]] = OpLabel
|
|
; CHECK-NOT: OpSelectionMerge
|
|
; CHECK: OpFunctionEnd
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %2 "main"
|
|
OpSource GLSL 450
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_3 = OpConstant %int 3
|
|
%int_1 = OpConstant %int 1
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%2 = OpFunction %void None %4
|
|
%10 = OpLabel
|
|
%undef_int = OpUndef %int
|
|
OpSelectionMerge %11 None
|
|
OpSwitch %undef_int %12 3 %13
|
|
%12 = OpLabel
|
|
OpBranch %11
|
|
%13 = OpLabel
|
|
OpSelectionMerge %15 None
|
|
OpBranchConditional %true %16 %15
|
|
%16 = OpLabel
|
|
%14 = OpUndef %bool
|
|
OpBranchConditional %14 %11 %17
|
|
%17 = OpLabel
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(spirv, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, IfInSwitch) {
|
|
// #version 310 es
|
|
//
|
|
// void main()
|
|
// {
|
|
// switch(0)
|
|
// {
|
|
// case 0:
|
|
// if(false)
|
|
// {
|
|
// }
|
|
// else
|
|
// {
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
const std::string before =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource ESSL 310
|
|
OpName %main "main"
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpSelectionMerge %9 None
|
|
OpSwitch %int_0 %9 0 %8
|
|
%8 = OpLabel
|
|
OpSelectionMerge %13 None
|
|
OpBranchConditional %false %12 %13
|
|
%12 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
OpBranch %9
|
|
%9 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource ESSL 310
|
|
OpName %main "main"
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%int_0 = OpConstant %int 0
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%main = OpFunction %void None %4
|
|
%9 = OpLabel
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
OpBranch %12
|
|
%12 = OpLabel
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(before, after, true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithSingleCase) {
|
|
const std::string text = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%8 = OpUndef %bool
|
|
%main = OpFunction %void None %4
|
|
%9 = OpLabel
|
|
OpSelectionMerge %10 None
|
|
OpSwitch %uint_0 %11
|
|
%11 = OpLabel
|
|
OpSelectionMerge %12 None
|
|
OpBranchConditional %8 %10 %12
|
|
%12 = OpLabel
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<DeadBranchElimPass>(text, text, true, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithTwoCases) {
|
|
const std::string text = R"(
|
|
; CHECK: OpSelectionMerge [[merge:%\w+]] None
|
|
; CHECK-NEXT: OpSwitch %uint_0 [[bb:%\w+\n]]
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%8 = OpUndef %bool
|
|
%main = OpFunction %void None %4
|
|
%9 = OpLabel
|
|
OpSelectionMerge %10 None
|
|
OpSwitch %uint_0 %11 1 %12
|
|
%11 = OpLabel
|
|
OpSelectionMerge %13 None
|
|
OpBranchConditional %8 %10 %13
|
|
%13 = OpLabel
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
TEST_F(DeadBranchElimTest, DebugInformation) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
%ext = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
%name = OpString "test"
|
|
OpName %main "main"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%5 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%float_0 = OpConstant %float 0
|
|
|
|
; CHECK: [[value:%\w+]] = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%float_1 = OpConstant %float 1
|
|
%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
|
|
%null_expr = OpExtInst %void %ext DebugExpression
|
|
%src = OpExtInst %void %ext DebugSource %name
|
|
%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
|
|
%ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %void
|
|
%dbg_main = OpExtInst %void %ext DebugFunction %name %ty %src 0 0 %cu %name FlagIsProtected|FlagIsPrivate 0 %main
|
|
|
|
; CHECK: [[bb1:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugLexicalBlock [[src:%\w+]] 1 0 [[dbg_main:%\w+]]
|
|
; CHECK: [[bb2:%\w+]] = OpExtInst %void [[ext]] DebugLexicalBlock [[src]] 2 0 [[dbg_main]]
|
|
; CHECK: [[bb3:%\w+]] = OpExtInst %void [[ext]] DebugLexicalBlock [[src]] 3 0 [[dbg_main]]
|
|
%bb1 = OpExtInst %void %ext DebugLexicalBlock %src 1 0 %dbg_main
|
|
%bb2 = OpExtInst %void %ext DebugLexicalBlock %src 2 0 %dbg_main
|
|
%bb3 = OpExtInst %void %ext DebugLexicalBlock %src 3 0 %dbg_main
|
|
|
|
%dbg_f = OpExtInst %void %ext DebugTypeBasic %name %uint_32 Float
|
|
; CHECK: [[dbg_foo:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable {{%\w+}} [[ty:%\w+]] [[src]] 0 0 [[dbg_main]]
|
|
%dbg_foo = OpExtInst %void %ext DebugLocalVariable %name %dbg_f %src 0 0 %dbg_main FlagIsLocal
|
|
; CHECK: [[dbg_bar:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable {{%\w+}} [[ty]] [[src]] 1 0 [[bb3]]
|
|
%dbg_bar = OpExtInst %void %ext DebugLocalVariable %name %dbg_f %src 1 0 %bb3 FlagIsLocal
|
|
|
|
%main = OpFunction %void None %5
|
|
%17 = OpLabel
|
|
; CHECK-NOT: DebugScope [[dbg_main]]
|
|
; CHECK-NOT: OpLine {{%\w+}} 0 0
|
|
%scope0 = OpExtInst %void %ext DebugScope %dbg_main
|
|
OpLine %name 0 0
|
|
OpSelectionMerge %18 None
|
|
OpBranchConditional %true %19 %20
|
|
%19 = OpLabel
|
|
; CHECK: DebugScope [[bb1]]
|
|
; CHECK: OpLine {{%\w+}} 1 0
|
|
%scope1 = OpExtInst %void %ext DebugScope %bb1
|
|
OpLine %name 1 0
|
|
OpBranch %18
|
|
%20 = OpLabel
|
|
; CHECK-NOT: DebugScope [[bb2]]
|
|
; CHECK-NOT: OpLine {{%\w+}} 2 0
|
|
%scope2 = OpExtInst %void %ext DebugScope %bb2
|
|
OpLine %name 2 0
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
|
|
; CHECK: DebugScope [[bb3]]
|
|
; CHECK: OpLine {{%\w+}} 3 0
|
|
; CHECK: DebugValue [[dbg_foo]] [[value]]
|
|
; CHECK: OpLine {{%\w+}} 4 0
|
|
; CHECK: OpStore %gl_FragColor [[value]]
|
|
; CHECK: DebugDeclare [[dbg_bar]] %gl_FragColor
|
|
; CHECK: DebugValue [[dbg_bar]] [[value]]
|
|
%scope3 = OpExtInst %void %ext DebugScope %bb3
|
|
OpLine %name 3 0
|
|
%21 = OpPhi %v4float %12 %19 %14 %20
|
|
%decl0 = OpExtInst %void %ext DebugValue %dbg_foo %21 %null_expr
|
|
OpLine %name 4 0
|
|
OpStore %gl_FragColor %21
|
|
%decl1 = OpExtInst %void %ext DebugDeclare %dbg_bar %gl_FragColor %null_expr
|
|
%decl2 = OpExtInst %void %ext DebugValue %dbg_bar %21 %null_expr
|
|
OpLine %name 5 0
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
|
|
}
|
|
|
|
// TODO(greg-lunarg): Add tests to verify handling of these cases:
|
|
//
|
|
// More complex control flow
|
|
// Others?
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|