mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-23 20:20:06 +00:00
b35b52f97b
Computing the value numbers on demand, as we do now, can lead to different results depending on the order in which the users asks for the value numbers. To make things more stable, we compute them ahead of time.
589 lines
21 KiB
C++
589 lines
21 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 "opt/value_number_table.h"
|
|
|
|
#include "assembly_builder.h"
|
|
#include "gmock/gmock.h"
|
|
#include "opt/build_module.h"
|
|
#include "pass_fixture.h"
|
|
|
|
namespace {
|
|
|
|
using namespace spvtools;
|
|
|
|
using ::testing::HasSubstr;
|
|
using ::testing::MatchesRegex;
|
|
|
|
using ValueTableTest = PassTest<::testing::Test>;
|
|
|
|
TEST_F(ValueTableTest, SameInstructionSameValue) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpFAdd %5 %9 %9
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst), vtable.GetValueNumber(inst));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentInstructionSameValue) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpFAdd %5 %9 %9
|
|
%11 = OpFAdd %5 %9 %9
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(11);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, SameValueDifferentBlock) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpFAdd %5 %9 %9
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
%12 = OpFAdd %5 %9 %9
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentValue) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpFAdd %5 %9 %9
|
|
%11 = OpFAdd %5 %9 %10
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(11);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentValueDifferentBlock) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpFAdd %5 %9 %9
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
%12 = OpFAdd %5 %9 %10
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, SameLoad) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst = context->get_def_use_mgr()->GetDef(9);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst), vtable.GetValueNumber(inst));
|
|
}
|
|
|
|
// Two different loads, even from the same memory, must given different value
|
|
// numbers if the memory is not read-only.
|
|
TEST_F(ValueTableTest, DifferentFunctionLoad) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpLoad %5 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentUniformLoad) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Uniform %5
|
|
%8 = OpVariable %6 Uniform
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpLoad %5 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentInputLoad) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Input %5
|
|
%8 = OpVariable %6 Input
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpLoad %5 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentUniformConstantLoad) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer UniformConstant %5
|
|
%8 = OpVariable %6 UniformConstant
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpLoad %5 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, DifferentPushConstantLoad) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer PushConstant %5
|
|
%8 = OpVariable %6 PushConstant
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpLoad %5 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, SameCall) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypeFunction %5
|
|
%7 = OpTypePointer Function %5
|
|
%8 = OpVariable %7 Private
|
|
%2 = OpFunction %3 None %4
|
|
%9 = OpLabel
|
|
%10 = OpFunctionCall %5 %11
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%11 = OpFunction %5 None %6
|
|
%12 = OpLabel
|
|
%13 = OpLoad %5 %8
|
|
OpReturnValue %13
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst), vtable.GetValueNumber(inst));
|
|
}
|
|
|
|
// Function calls should be given a new value number, even if they are the same.
|
|
TEST_F(ValueTableTest, DifferentCall) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypeFunction %5
|
|
%7 = OpTypePointer Function %5
|
|
%8 = OpVariable %7 Private
|
|
%2 = OpFunction %3 None %4
|
|
%9 = OpLabel
|
|
%10 = OpFunctionCall %5 %11
|
|
%12 = OpFunctionCall %5 %11
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%11 = OpFunction %5 None %6
|
|
%13 = OpLabel
|
|
%14 = OpLoad %5 %8
|
|
OpReturnValue %14
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
// It is possible to have two instruction that compute the same numerical value,
|
|
// but with different types. They should have different value numbers.
|
|
TEST_F(ValueTableTest, DifferentTypes) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeInt 32 0
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%8 = OpLabel
|
|
%9 = OpVariable %7 Function
|
|
%10 = OpLoad %5 %9
|
|
%11 = OpIAdd %5 %10 %10
|
|
%12 = OpIAdd %6 %10 %10
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(11);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
TEST_F(ValueTableTest, CopyObject) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Function %5
|
|
%2 = OpFunction %3 None %4
|
|
%7 = OpLabel
|
|
%8 = OpVariable %6 Function
|
|
%9 = OpLoad %5 %8
|
|
%10 = OpCopyObject %5 %9
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
}
|
|
|
|
// Test that a phi where the operands have the same value assigned that value
|
|
// to the result of the phi.
|
|
TEST_F(ValueTableTest, PhiTest1) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Uniform %5
|
|
%7 = OpTypeBool
|
|
%8 = OpConstantTrue %7
|
|
%9 = OpVariable %6 Uniform
|
|
%2 = OpFunction %3 None %4
|
|
%10 = OpLabel
|
|
OpBranchConditional %8 %11 %12
|
|
%11 = OpLabel
|
|
%13 = OpLoad %5 %9
|
|
OpBranch %14
|
|
%12 = OpLabel
|
|
%15 = OpLoad %5 %9
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%16 = OpPhi %5 %13 %11 %15 %12
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(13);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(15);
|
|
ir::Instruction* phi = context->get_def_use_mgr()->GetDef(16);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi));
|
|
}
|
|
|
|
// When the values for the inputs to a phi do not match, then the phi should
|
|
// have its own value number.
|
|
TEST_F(ValueTableTest, PhiTest2) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Uniform %5
|
|
%7 = OpTypeBool
|
|
%8 = OpConstantTrue %7
|
|
%9 = OpVariable %6 Uniform
|
|
%10 = OpVariable %6 Uniform
|
|
%2 = OpFunction %3 None %4
|
|
%11 = OpLabel
|
|
OpBranchConditional %8 %12 %13
|
|
%12 = OpLabel
|
|
%14 = OpLoad %5 %9
|
|
OpBranch %15
|
|
%13 = OpLabel
|
|
%16 = OpLoad %5 %10
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
%17 = OpPhi %14 %12 %16 %13
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(14);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(16);
|
|
ir::Instruction* phi = context->get_def_use_mgr()->GetDef(17);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi));
|
|
EXPECT_NE(vtable.GetValueNumber(inst2), vtable.GetValueNumber(phi));
|
|
}
|
|
|
|
// Test that a phi node in a loop header gets a new value because one of its
|
|
// inputs comes from later in the loop.
|
|
TEST_F(ValueTableTest, PhiLoopTest) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
%3 = OpTypeVoid
|
|
%4 = OpTypeFunction %3
|
|
%5 = OpTypeFloat 32
|
|
%6 = OpTypePointer Uniform %5
|
|
%7 = OpTypeBool
|
|
%8 = OpConstantTrue %7
|
|
%9 = OpVariable %6 Uniform
|
|
%10 = OpVariable %6 Uniform
|
|
%2 = OpFunction %3 None %4
|
|
%11 = OpLabel
|
|
%12 = OpLoad %5 %9
|
|
OpSelectionMerge %13 None
|
|
OpBranchConditional %8 %14 %13
|
|
%14 = OpLabel
|
|
%15 = OpPhi %5 %12 %11 %16 %14
|
|
%16 = OpLoad %5 %9
|
|
OpLoopMerge %17 %14 None
|
|
OpBranchConditional %8 %14 %17
|
|
%17 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%18 = OpPhi %5 %12 %11 %16 %17
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
opt::ValueNumberTable vtable(context.get());
|
|
ir::Instruction* inst1 = context->get_def_use_mgr()->GetDef(12);
|
|
ir::Instruction* inst2 = context->get_def_use_mgr()->GetDef(16);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
|
|
|
|
ir::Instruction* phi1 = context->get_def_use_mgr()->GetDef(15);
|
|
EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi1));
|
|
|
|
ir::Instruction* phi2 = context->get_def_use_mgr()->GetDef(18);
|
|
EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi2));
|
|
EXPECT_NE(vtable.GetValueNumber(phi1), vtable.GetValueNumber(phi2));
|
|
}
|
|
} // anonymous namespace
|