SPIRV-Tools/test/opt/ccp_test.cpp
Steven Perron 9d29c37ac5
Removing decorations when doing constant propagation. (#2444)
In constant propagation, decoration are transfered from the original
expression to the constant that will replace it.  This can be wrong
because there are no decorations that apply to constants.  We choose to
simply delete the decorations.

Fixes #2441
2019-03-13 10:40:49 -04:00

931 lines
29 KiB
C++

// Copyright (c) 2017 Google 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 "gmock/gmock.h"
#include "gtest/gtest.h"
#include "source/opt/ccp_pass.h"
#include "test/opt/pass_fixture.h"
#include "test/opt/pass_utils.h"
namespace spvtools {
namespace opt {
namespace {
using CCPTest = PassTest<::testing::Test>;
TEST_F(CCPTest, PropagateThroughPhis) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %x %outparm
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %x "x"
OpName %outparm "outparm"
OpDecorate %x Flat
OpDecorate %x Location 0
OpDecorate %outparm Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%bool = OpTypeBool
%_ptr_Function_int = OpTypePointer Function %int
%int_4 = OpConstant %int 4
%int_3 = OpConstant %int 3
%int_1 = OpConstant %int 1
%_ptr_Input_int = OpTypePointer Input %int
%x = OpVariable %_ptr_Input_int Input
%_ptr_Output_int = OpTypePointer Output %int
%outparm = OpVariable %_ptr_Output_int Output
%main = OpFunction %void None %3
%4 = OpLabel
%5 = OpLoad %int %x
%9 = OpIAdd %int %int_1 %int_3
%6 = OpSGreaterThan %bool %5 %int_3
OpSelectionMerge %25 None
OpBranchConditional %6 %22 %23
%22 = OpLabel
; CHECK: OpCopyObject %int %int_4
%7 = OpCopyObject %int %9
OpBranch %25
%23 = OpLabel
%8 = OpCopyObject %int %int_4
OpBranch %25
%25 = OpLabel
; %int_4 should have propagated to both OpPhi operands.
; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}}
%35 = OpPhi %int %7 %22 %8 %23
; This function always returns 4. DCE should get rid of everything else.
; CHECK OpStore %outparm %int_4
OpStore %outparm %35
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, SimplifyConditionals) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %outparm
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %outparm "outparm"
OpDecorate %outparm Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%bool = OpTypeBool
%_ptr_Function_int = OpTypePointer Function %int
%int_4 = OpConstant %int 4
%int_3 = OpConstant %int 3
%int_1 = OpConstant %int 1
%_ptr_Output_int = OpTypePointer Output %int
%outparm = OpVariable %_ptr_Output_int Output
%main = OpFunction %void None %3
%4 = OpLabel
%9 = OpIAdd %int %int_4 %int_3
%6 = OpSGreaterThan %bool %9 %int_3
OpSelectionMerge %25 None
; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]]
OpBranchConditional %6 %22 %23
; CHECK: [[bb_taken]] = OpLabel
%22 = OpLabel
; CHECK: OpCopyObject %int %int_7
%7 = OpCopyObject %int %9
OpBranch %25
; CHECK: [[bb_not_taken]] = OpLabel
%23 = OpLabel
; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4
%8 = OpCopyObject %int %int_4
OpBranch %25
%25 = OpLabel
; %int_7 should have propagated to the first OpPhi operand. But the else branch
; is not executable (conditional is always true), so no values should be
; propagated there and the value of the OpPhi should always be %int_7.
; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]]
%35 = OpPhi %int %7 %22 %8 %23
; Only the true path of the conditional is ever executed. The output of this
; function is always %int_7.
; CHECK: OpStore %outparm %int_7
OpStore %outparm %35
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, SimplifySwitches) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %outparm
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %outparm "outparm"
OpDecorate %outparm Location 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_23 = OpConstant %int 23
%int_42 = OpConstant %int 42
%int_14 = OpConstant %int 14
%int_15 = OpConstant %int 15
%int_4 = OpConstant %int 4
%_ptr_Output_int = OpTypePointer Output %int
%outparm = OpVariable %_ptr_Output_int Output
%main = OpFunction %void None %6
%15 = OpLabel
OpSelectionMerge %17 None
OpSwitch %int_23 %17 10 %18 13 %19 23 %20
%18 = OpLabel
OpBranch %17
%19 = OpLabel
OpBranch %17
%20 = OpLabel
OpBranch %17
%17 = OpLabel
%24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20
; The switch will always jump to label %20, which carries the value %int_15.
; CHECK: OpIAdd %int %int_15 %int_4
%22 = OpIAdd %int %24 %int_4
; Consequently, the return value will always be %int_19.
; CHECK: OpStore %outparm %int_19
OpStore %outparm %22
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, SimplifySwitchesDefaultBranch) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %outparm
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %outparm "outparm"
OpDecorate %outparm Location 0
%void = OpTypeVoid
%6 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_42 = OpConstant %int 42
%int_4 = OpConstant %int 4
%int_1 = OpConstant %int 1
%_ptr_Output_int = OpTypePointer Output %int
%outparm = OpVariable %_ptr_Output_int Output
%main = OpFunction %void None %6
%13 = OpLabel
%15 = OpIAdd %int %int_42 %int_4
OpSelectionMerge %16 None
; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}}
OpSwitch %15 %17 10 %18
%18 = OpLabel
OpBranch %16
%17 = OpLabel
OpBranch %16
%16 = OpLabel
%22 = OpPhi %int %int_42 %18 %int_1 %17
; The switch will always jump to the default label %17. This carries the value
; %int_1.
; CHECK: OpIAdd %int %int_1 %int_4
%20 = OpIAdd %int %22 %int_4
; Resulting in a return value of %int_5.
; CHECK: OpStore %outparm %int_5
OpStore %outparm %20
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, SimplifyIntVector) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %v "v"
OpName %OutColor "OutColor"
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%v4int = OpTypeVector %int 4
%_ptr_Function_v4int = OpTypePointer Function %v4int
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%int_3 = OpConstant %int 3
%int_4 = OpConstant %int 4
%14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%_ptr_Function_int = OpTypePointer Function %int
%_ptr_Output_v4int = OpTypePointer Output %v4int
%OutColor = OpVariable %_ptr_Output_v4int Output
%main = OpFunction %void None %3
%5 = OpLabel
%v = OpVariable %_ptr_Function_v4int Function
OpStore %v %14
%18 = OpAccessChain %_ptr_Function_int %v %uint_0
%19 = OpLoad %int %18
; The constant folder does not see through access chains. To get this, the
; vector would have to be scalarized.
; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1
%20 = OpIAdd %int %19 %int_1
%21 = OpAccessChain %_ptr_Function_int %v %uint_0
; CHECK: OpStore {{%\d+}} [[result_id]]
OpStore %21 %20
%24 = OpLoad %v4int %v
OpStore %OutColor %24
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, BadSimplifyFloatVector) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %OutColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %v "v"
OpName %OutColor "OutColor"
OpDecorate %OutColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Function_v4float = OpTypePointer Function %v4float
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%float_3 = OpConstant %float 3
%float_4 = OpConstant %float 4
%14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%_ptr_Function_float = OpTypePointer Function %float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%OutColor = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
OpStore %v %14
%18 = OpAccessChain %_ptr_Function_float %v %uint_0
%19 = OpLoad %float %18
; NOTE: This test should start failing once floating point folding is
; implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943).
; This should be checking that we are adding %float_1 + %float_1.
; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1
%20 = OpFAdd %float %19 %float_1
%21 = OpAccessChain %_ptr_Function_float %v %uint_0
; This should be checkint that we are storing %float_2 instead of result_it.
; CHECK: OpStore {{%\d+}} [[result_id]]
OpStore %21 %20
%24 = OpLoad %v4float %v
OpStore %OutColor %24
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, NoLoadStorePropagation) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %outparm
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %x "x"
OpName %outparm "outparm"
OpDecorate %outparm Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_23 = OpConstant %int 23
%_ptr_Output_int = OpTypePointer Output %int
%outparm = OpVariable %_ptr_Output_int Output
%main = OpFunction %void None %3
%5 = OpLabel
%x = OpVariable %_ptr_Function_int Function
OpStore %x %int_23
; int_23 should not propagate into this load.
; CHECK: [[load_id:%\d+]] = OpLoad %int %x
%12 = OpLoad %int %x
; Nor into this copy operation.
; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]]
%13 = OpCopyObject %int %12
; Likewise here.
; CHECK: OpStore %outparm [[copy_id]]
OpStore %outparm %13
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, HandleAbortInstructions) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%bool = OpTypeBool
; CHECK: %true = OpConstantTrue %bool
%int_3 = OpConstant %int 3
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%4 = OpLabel
%9 = OpIAdd %int %int_3 %int_1
%6 = OpSGreaterThan %bool %9 %int_3
OpSelectionMerge %23 None
; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
OpBranchConditional %6 %22 %23
%22 = OpLabel
OpKill
%23 = OpLabel
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, SSAWebCycles) {
// Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159
// When there is a cycle in the SSA def-use web, the propagator was getting
// into an infinite loop. SSA edges for Phi instructions should not be
// added to the edges to simulate.
const std::string spv_asm = 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
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_4 = OpConstant %int 4
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%_ptr_Output_int = OpTypePointer Output %int
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %11
%11 = OpLabel
%29 = OpPhi %int %int_0 %5 %22 %14
%30 = OpPhi %int %int_0 %5 %25 %14
OpLoopMerge %13 %14 None
OpBranch %15
%15 = OpLabel
%19 = OpSLessThan %bool %30 %int_4
; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
OpBranchConditional %19 %12 %13
%12 = OpLabel
; CHECK: OpIAdd %int %int_0 %int_0
%22 = OpIAdd %int %29 %30
OpBranch %14
%14 = OpLabel
; CHECK: OpPhi %int %int_0 {{%\d+}}
%25 = OpPhi %int %30 %12
OpBranch %11
%13 = OpLabel
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, LoopInductionVariables) {
// Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143
// We are failing to properly consider the induction variable for this loop
// as Varying.
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 430
OpName %main "main"
%void = OpTypeVoid
%5 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_10 = OpConstant %int 10
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %5
%12 = OpLabel
OpBranch %13
%13 = OpLabel
; This Phi should not have all constant arguments:
; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}}
%22 = OpPhi %int %int_0 %12 %21 %15
OpLoopMerge %14 %15 None
OpBranch %16
%16 = OpLabel
; The Phi should never be considered to have the value %int_0.
; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10
%18 = OpSLessThan %bool %22 %int_10
; This conditional was wrongly converted into an always-true jump due to the
; bad meet evaluation of %22.
; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}}
OpBranchConditional %18 %19 %14
%19 = OpLabel
OpBranch %15
%15 = OpLabel
; CHECK: OpIAdd %int [[phi_id]] %int_1
%21 = OpIAdd %int %22 %int_1
OpBranch %13
%14 = OpLabel
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
}
TEST_F(CCPTest, HandleCompositeWithUndef) {
// Check to make sure that CCP does not crash when given a "constant" struct
// with an undef. If at a later time CCP is enhanced to optimize this case,
// it is not wrong.
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpName %main "main"
%void = OpTypeVoid
%4 = OpTypeFunction %void
%int = OpTypeInt 32 1
%bool = OpTypeBool
%_struct_7 = OpTypeStruct %int %int
%int_1 = OpConstant %int 1
%9 = OpUndef %int
%10 = OpConstantComposite %_struct_7 %int_1 %9
%main = OpFunction %void None %4
%11 = OpLabel
%12 = OpCompositeExtract %int %10 0
%13 = OpCopyObject %int %12
OpReturn
OpFunctionEnd
)";
auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
}
TEST_F(CCPTest, SkipSpecConstantInstrucitons) {
const std::string spv_asm = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpName %main "main"
%void = OpTypeVoid
%4 = OpTypeFunction %void
%bool = OpTypeBool
%10 = OpSpecConstantFalse %bool
%main = OpFunction %void None %4
%11 = OpLabel
%12 = OpBranchConditional %10 %l1 %l2
%l1 = OpLabel
OpReturn
%l2 = OpLabel
OpReturn
OpFunctionEnd
)";
auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
}
TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
const std::string text = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func" %in
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
%false = OpConstantFalse %bool
%int0 = OpConstant %int 0
%int1 = OpConstant %int 1
%int6 = OpConstant %int 6
%int_ptr_Input = OpTypePointer Input %int
%in = OpVariable %int_ptr_Input Input
%undef = OpUndef %int
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpBranch %2
%2 = OpLabel
%outer_phi = OpPhi %int %int0 %1 %outer_add %15
%cond1 = OpSLessThanEqual %bool %outer_phi %int6
OpLoopMerge %3 %15 None
OpBranchConditional %cond1 %4 %3
%4 = OpLabel
%ld = OpLoad %int %in
%cond2 = OpSGreaterThanEqual %bool %int1 %ld
OpSelectionMerge %10 None
OpBranchConditional %cond2 %8 %9
%8 = OpLabel
OpBranch %10
%9 = OpLabel
OpBranch %10
%10 = OpLabel
%extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
OpBranch %11
%11 = OpLabel
%inner_phi = OpPhi %int %int0 %10 %inner_add %13
%cond3 = OpSLessThanEqual %bool %inner_phi %int6
OpLoopMerge %14 %13 None
OpBranchConditional %cond3 %12 %14
%12 = OpLabel
OpBranch %13
%13 = OpLabel
%inner_add = OpIAdd %int %inner_phi %int1
OpBranch %11
%14 = OpLabel
OpBranch %15
%15 = OpLabel
%outer_add = OpIAdd %int %extra_phi %int1
OpBranch %2
%3 = OpLabel
OpReturn
OpFunctionEnd
)";
auto res = SinglePassRunToBinary<CCPPass>(text, true);
EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
}
TEST_F(CCPTest, UndefInPhi) {
const std::string text = R"(
; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
; CHECK: [[phi:%\w+]] = OpPhi
; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
OpCapability Kernel
OpCapability Linkage
OpMemoryModel Logical OpenCL
OpDecorate %1 LinkageAttributes "func" Export
%void = OpTypeVoid
%bool = OpTypeBool
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%7 = OpUndef %uint
%8 = OpTypeFunction %void %bool
%1 = OpFunction %void None %8
%9 = OpFunctionParameter %bool
%10 = OpLabel
OpBranchConditional %9 %11 %12
%11 = OpLabel
OpBranch %13
%12 = OpLabel
OpBranch %14
%14 = OpLabel
OpBranchConditional %9 %13 %15
%15 = OpLabel
OpBranch %13
%13 = OpLabel
%16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
%17 = OpIAdd %uint %16 %uint_1
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
// Just test to make sure the constant fold rules are being used. Will rely on
// the folding test for specific testing of specific rules.
TEST_F(CCPTest, UseConstantFoldingRules) {
const std::string text = R"(
; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
; CHECK: OpReturnValue [[float1]]
OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
OpDecorate %1 LinkageAttributes "func" Export
%void = OpTypeVoid
%bool = OpTypeBool
%float = OpTypeFloat 32
%float_0 = OpConstant %float 0
%float_1 = OpConstant %float 1
%8 = OpTypeFunction %float
%1 = OpFunction %float None %8
%10 = OpLabel
%17 = OpFAdd %float %float_0 %float_1
OpReturnValue %17
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
// Test for #1300. Previously value for %5 would not settle during simulation.
TEST_F(CCPTest, SettlePhiLatticeValue) {
const std::string text = R"(
OpCapability Kernel
OpCapability Linkage
OpMemoryModel Logical OpenCL
OpDecorate %func LinkageAttributes "func" Export
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
%false = OpConstantFalse %bool
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpBranchConditional %true %2 %3
%3 = OpLabel
OpBranch %2
%2 = OpLabel
%5 = OpPhi %bool %true %1 %false %3
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunToBinary<CCPPass>(text, true);
}
TEST_F(CCPTest, NullBranchCondition) {
const std::string text = R"(
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
%null = OpConstantNull %bool
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpSelectionMerge %2 None
OpBranchConditional %null %2 %3
%3 = OpLabel
OpBranch %2
%2 = OpLabel
%phi = OpPhi %int %int_1 %1 %int_2 %3
%add = OpIAdd %int %int_1 %phi
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
TEST_F(CCPTest, UndefBranchCondition) {
const std::string text = R"(
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
; CHECK: [[phi:%\w+]] = OpPhi
; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
%undef = OpUndef %bool
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpSelectionMerge %2 None
OpBranchConditional %undef %2 %3
%3 = OpLabel
OpBranch %2
%2 = OpLabel
%phi = OpPhi %int %int_1 %1 %int_2 %3
%add = OpIAdd %int %int_1 %phi
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
TEST_F(CCPTest, NullSwitchCondition) {
const std::string text = R"(
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 1
%null = OpConstantNull %int
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpSelectionMerge %2 None
OpSwitch %null %2 0 %3
%3 = OpLabel
OpBranch %2
%2 = OpLabel
%phi = OpPhi %int %int_1 %1 %int_2 %3
%add = OpIAdd %int %int_1 %phi
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
TEST_F(CCPTest, UndefSwitchCondition) {
const std::string text = R"(
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
; CHECK: [[phi:%\w+]] = OpPhi
; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 1
%undef = OpUndef %int
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy
%1 = OpLabel
OpSelectionMerge %2 None
OpSwitch %undef %2 0 %3
%3 = OpLabel
OpBranch %2
%2 = OpLabel
%phi = OpPhi %int %int_1 %1 %int_2 %3
%add = OpIAdd %int %int_1 %phi
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
// Test for #1361.
TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
const std::string text = R"(
; CHECK: [[phi:%\w+]] = OpPhi
; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func" %in
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 1
%bool = OpTypeBool
%functy = OpTypeFunction %void
%ptr_int_Input = OpTypePointer Input %int
%in = OpVariable %ptr_int_Input Input
%struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
%struct_null = OpConstantNull %struct
%func = OpFunction %void None %functy
%1 = OpLabel
OpBranch %2
%2 = OpLabel
%phi = OpPhi %struct %struct_null %1 %5 %4
%extract = OpCompositeExtract %ptr_int_Input %phi 0
OpLoopMerge %3 %4 None
OpBranch %4
%4 = OpLabel
%5 = OpCompositeConstruct %struct %in %in
OpBranch %2
%3 = OpLabel
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
TEST_F(CCPTest, FoldWithDecoration) {
const std::string text = R"(
; CHECK: OpCapability
; CHECK-NOT: OpDecorate
; CHECK: OpFunctionEnd
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "main"
OpExecutionMode %2 OriginUpperLeft
OpSource ESSL 310
OpDecorate %3 RelaxedPrecision
%void = OpTypeVoid
%5 = OpTypeFunction %void
%float = OpTypeFloat 32
%v3float = OpTypeVector %float 3
%float_0 = OpConstant %float 0
%v4float = OpTypeVector %float 4
%10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%2 = OpFunction %void None %5
%11 = OpLabel
%3 = OpVectorShuffle %v3float %10 %10 0 1 2
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<CCPPass>(text, true);
}
} // namespace
} // namespace opt
} // namespace spvtools