mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-28 10:41:04 +00:00
6cc772c3ce
At the moment specialization constants look like constants to ccp. This causes a problem because they are handled differently by the constant manager. I choose to simply skip over them, and not try to add them to the value table. We can do specialization before ccp if we want to be able to propagate these values. Fixes #1199.
587 lines
20 KiB
C++
587 lines
20 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 "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include "pass_fixture.h"
|
|
#include "pass_utils.h"
|
|
|
|
#include "opt/ccp_pass.h"
|
|
|
|
namespace {
|
|
|
|
using namespace spvtools;
|
|
|
|
using CCPTest = PassTest<::testing::Test>;
|
|
|
|
// TODO(dneto): Add Effcee as required dependency, and make this unconditional.
|
|
#ifdef SPIRV_EFFCEE
|
|
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<opt::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<opt::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<opt::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<opt::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<opt::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<opt::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<opt::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<opt::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+}} %int_0 {{%\d+}}
|
|
%25 = OpPhi %int %int_0 %5 %30 %14
|
|
OpBranch %11
|
|
%13 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<opt::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<opt::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<opt::CCPPass>(spv_asm, true);
|
|
EXPECT_EQ(std::get<1>(res), opt::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<opt::CCPPass>(spv_asm, true);
|
|
EXPECT_EQ(std::get<1>(res), opt::Pass::Status::SuccessWithoutChange);
|
|
}
|
|
#endif
|
|
|
|
} // namespace
|