| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- // Copyright (c) 2021 Google LLC.
- //
- // 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 "source/lint/divergence_analysis.h"
- #include <string>
- #include "gtest/gtest.h"
- #include "source/opt/build_module.h"
- #include "source/opt/ir_context.h"
- #include "source/opt/module.h"
- #include "spirv-tools/libspirv.h"
- namespace spvtools {
- namespace lint {
- namespace {
- void CLIMessageConsumer(spv_message_level_t level, const char*,
- const spv_position_t& position, const char* message) {
- switch (level) {
- case SPV_MSG_FATAL:
- case SPV_MSG_INTERNAL_ERROR:
- case SPV_MSG_ERROR:
- std::cerr << "error: line " << position.index << ": " << message
- << std::endl;
- break;
- case SPV_MSG_WARNING:
- std::cout << "warning: line " << position.index << ": " << message
- << std::endl;
- break;
- case SPV_MSG_INFO:
- std::cout << "info: line " << position.index << ": " << message
- << std::endl;
- break;
- default:
- break;
- }
- }
- class DivergenceTest : public ::testing::Test {
- protected:
- std::unique_ptr<opt::IRContext> context_;
- std::unique_ptr<DivergenceAnalysis> divergence_;
- void Build(std::string text, uint32_t function_id = 1) {
- context_ = BuildModule(SPV_ENV_UNIVERSAL_1_0, CLIMessageConsumer, text,
- SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
- ASSERT_NE(nullptr, context_.get());
- opt::Module* module = context_->module();
- ASSERT_NE(nullptr, module);
- // First function should have the given ID.
- ASSERT_NE(module->begin(), module->end());
- opt::Function* function = &*module->begin();
- ASSERT_EQ(function->result_id(), function_id);
- divergence_.reset(new DivergenceAnalysis(*context_));
- divergence_->Run(function);
- }
- };
- // Makes assertions a bit shorter.
- using Level = DivergenceAnalysis::DivergenceLevel;
- namespace {
- std::string Preamble() {
- return R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %1 "main" %x %y
- OpExecutionMode %1 OriginLowerLeft
- OpDecorate %y Flat
- %void = OpTypeVoid
- %void_f = OpTypeFunction %void
- %bool = OpTypeBool
- %float = OpTypeFloat 32
- %false = OpConstantFalse %bool
- %true = OpConstantTrue %bool
- %zero = OpConstant %float 0
- %one = OpConstant %float 1
- %x_t = OpTypePointer Input %float
- %x = OpVariable %x_t Input
- %y = OpVariable %x_t Input
- %1 = OpFunction %void None %void_f
- )";
- }
- } // namespace
- TEST_F(DivergenceTest, SimpleTest) {
- // pseudocode:
- // %10:
- // %11 = load x
- // if (%12 = (%11 < 0)) {
- // %13:
- // // do nothing
- // }
- // %14:
- // return
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %11 = OpLoad %float %x
- %12 = OpFOrdLessThan %bool %11 %zero
- OpSelectionMerge %14 None
- OpBranchConditional %12 %13 %14
- %13 = OpLabel
- OpBranch %14
- %14 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- // Control flow divergence.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(13));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14));
- // Value divergence.
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(0, divergence_->GetDivergenceSource(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(11, divergence_->GetDivergenceSource(12));
- }
- TEST_F(DivergenceTest, FlowTypesTest) {
- // pseudocode:
- // %10:
- // %11 = load x
- // %12 = x < 0 // data -> data
- // if (%12) {
- // %13: // data -> control
- // if (true) {
- // %14: // control -> control
- // }
- // %15:
- // %16 = 1
- // } else {
- // %17:
- // %18 = 2
- // }
- // %19:
- // %19 = phi(%16 from %15, %18 from %17) // control -> data
- // return
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %11 = OpLoad %float %x
- %12 = OpFOrdLessThan %bool %11 %zero
- OpSelectionMerge %19 None
- OpBranchConditional %12 %13 %17
- %13 = OpLabel
- OpSelectionMerge %15 None
- OpBranchConditional %true %14 %15
- %14 = OpLabel
- OpBranch %15
- %15 = OpLabel
- %16 = OpFAdd %float %zero %zero
- OpBranch %19
- %17 = OpLabel
- %18 = OpFAdd %float %zero %one
- OpBranch %19
- %19 = OpLabel
- %20 = OpPhi %float %16 %15 %18 %17
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(0, divergence_->GetDivergenceSource(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(11, divergence_->GetDivergenceSource(12));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(13));
- EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(13));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(13, divergence_->GetDivergenceSource(14));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(15));
- EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(15));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(16));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(17));
- EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(17));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(18));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(19));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(20));
- EXPECT_TRUE(divergence_->GetDivergenceSource(20) == 15 ||
- divergence_->GetDivergenceDependenceSource(20) == 17)
- << "Got: " << divergence_->GetDivergenceDependenceSource(20);
- }
- TEST_F(DivergenceTest, ExitDependenceTest) {
- // pseudocode:
- // %10:
- // %11 = load x
- // %12 = %11 < 0
- // %13:
- // do {
- // %14:
- // if (%12) {
- // %15:
- // continue;
- // }
- // %16:
- // %17:
- // continue;
- // } %18: while(false);
- // %19:
- // return
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %11 = OpLoad %float %x
- %12 = OpFOrdLessThan %bool %11 %zero ; data -> data
- OpBranch %13
- %13 = OpLabel
- OpLoopMerge %19 %18 None
- OpBranch %14
- %14 = OpLabel
- OpSelectionMerge %16 None
- OpBranchConditional %12 %15 %16
- %15 = OpLabel
- OpBranch %18 ; continue
- %16 = OpLabel
- OpBranch %17
- %17 = OpLabel
- OpBranch %18 ; continue
- %18 = OpLabel
- OpBranchConditional %false %13 %19
- %19 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(0, divergence_->GetDivergenceSource(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(11, divergence_->GetDivergenceSource(12));
- // Since both branches continue, there's no divergent control dependence
- // to 13.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(15));
- EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(15));
- // These two blocks are outside the if but are still control dependent.
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(16));
- EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(16));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17));
- EXPECT_EQ(12, divergence_->GetDivergenceSource(17));
- EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(17));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(18));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(19));
- }
- TEST_F(DivergenceTest, ReconvergencePromotionTest) {
- // pseudocode:
- // %10:
- // %11 = load y
- // %12 = %11 < 0
- // if (%12) {
- // %13:
- // %14:
- // %15:
- // if (true) {
- // %16:
- // }
- // // Reconvergence *not* guaranteed as
- // // control is not uniform on the IG level
- // // at %15.
- // %17:
- // %18:
- // %19:
- // %20 = load x
- // }
- // %21:
- // %22 = phi(%11, %20)
- // return
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %11 = OpLoad %float %y
- %12 = OpFOrdLessThan %bool %11 %zero
- OpSelectionMerge %21 None
- OpBranchConditional %12 %13 %21
- %13 = OpLabel
- OpBranch %14
- %14 = OpLabel
- OpBranch %15
- %15 = OpLabel
- OpSelectionMerge %17 None
- OpBranchConditional %true %16 %17
- %16 = OpLabel
- OpBranch %17
- %17 = OpLabel
- OpBranch %18
- %18 = OpLabel
- OpBranch %19
- %19 = OpLabel
- %20 = OpLoad %float %y
- OpBranch %21
- %21 = OpLabel
- %22 = OpPhi %float %11 %10 %20 %19
- OpReturn
- OpFunctionEnd
- )"));
- ASSERT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- ASSERT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(21));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(11));
- ASSERT_EQ(0, divergence_->GetDivergenceSource(11));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(12));
- ASSERT_EQ(11, divergence_->GetDivergenceSource(12));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(13));
- ASSERT_EQ(12, divergence_->GetDivergenceSource(13));
- ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(13));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(14));
- ASSERT_EQ(12, divergence_->GetDivergenceSource(14));
- ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(14));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(15));
- ASSERT_EQ(12, divergence_->GetDivergenceSource(15));
- ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(15));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(16));
- ASSERT_EQ(15, divergence_->GetDivergenceSource(16));
- ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17));
- ASSERT_EQ(12, divergence_->GetDivergenceSource(17));
- ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(18));
- ASSERT_EQ(12, divergence_->GetDivergenceSource(18));
- ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(19));
- ASSERT_EQ(12, divergence_->GetDivergenceSource(19));
- ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(20));
- ASSERT_EQ(0, divergence_->GetDivergenceSource(20));
- ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(22));
- ASSERT_EQ(19, divergence_->GetDivergenceSource(22));
- ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(15));
- }
- TEST_F(DivergenceTest, FunctionCallTest) {
- // pseudocode:
- // %2() {
- // %20:
- // %21 = load x
- // %22 = %21 < 0
- // if (%22) {
- // %23:
- // return
- // }
- // %24:
- // return
- // }
- //
- // main() {
- // %10:
- // %11 = %2();
- // // Reconvergence *not* guaranteed.
- // %12:
- // return
- // }
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %11 = OpFunctionCall %void %2
- OpBranch %12
- %12 = OpLabel
- OpReturn
- OpFunctionEnd
- %2 = OpFunction %void None %void_f
- %20 = OpLabel
- %21 = OpLoad %float %x
- %22 = OpFOrdLessThan %bool %21 %zero
- OpSelectionMerge %24 None
- OpBranchConditional %22 %23 %24
- %23 = OpLabel
- OpReturn
- %24 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- // Conservatively assume function return value is uniform.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(11));
- // TODO(dongja): blocks reachable from diverging function calls should be
- // divergent.
- // EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(12)); // Wrong!
- }
- TEST_F(DivergenceTest, LateMergeTest) {
- // pseudocode:
- // %10:
- // %11 = load y
- // %12 = %11 < 0
- // [merge: %15]
- // if (%12) {
- // %13:
- // }
- // %14: // Reconvergence hasn't happened by here.
- // %15:
- // return
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %11 = OpLoad %float %x
- %12 = OpFOrdLessThan %bool %11 %zero
- OpSelectionMerge %15 None
- OpBranchConditional %12 %13 %14
- %13 = OpLabel
- OpBranch %14
- %14 = OpLabel
- OpBranch %15
- %15 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
- // TODO(dongja):
- // EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14)); // Wrong!
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(15));
- }
- // The following series of tests makes sure that we find the least fixpoint.
- TEST_F(DivergenceTest, UniformFixpointTest) {
- // pseudocode:
- // %10:
- // %20 = load x
- // %21 = load y
- // do {
- // %11:
- // %12:
- // %13 = phi(%zero from %11, %14 from %16)
- // %14 = %13 + 1
- // %15 = %13 < 1
- // } %16: while (%15)
- // %17:
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %20 = OpLoad %float %x
- %21 = OpLoad %float %y
- OpBranch %11
- %11 = OpLabel
- %13 = OpPhi %float %zero %10 %14 %16
- OpLoopMerge %17 %16 None
- OpBranch %12
- %12 = OpLabel
- %14 = OpFAdd %float %13 %one
- %15 = OpFOrdLessThan %bool %13 %one
- OpBranch %16
- %16 = OpLabel
- OpBranchConditional %15 %11 %17
- %17 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(16));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
- }
- TEST_F(DivergenceTest, PartiallyUniformFixpointTest) {
- // pseudocode:
- // %10:
- // %20 = load x
- // %21 = load y
- // do {
- // %11:
- // %12:
- // %13 = phi(%zero from %11, %14 from %16)
- // %14 = %13 + 1
- // %15 = %13 < %21
- // } %16: while (%15)
- // %17:
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %20 = OpLoad %float %x
- %21 = OpLoad %float %y
- OpBranch %11
- %11 = OpLabel
- %13 = OpPhi %float %zero %10 %14 %16
- OpLoopMerge %17 %16 None
- OpBranch %12
- %12 = OpLabel
- %14 = OpFAdd %float %13 %one
- %15 = OpFOrdLessThan %bool %13 %21
- OpBranch %16
- %16 = OpLabel
- OpBranchConditional %15 %11 %17
- %17 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(16));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
- }
- TEST_F(DivergenceTest, DivergentFixpointTest) {
- // pseudocode:
- // %10:
- // %20 = load x
- // %21 = load y
- // do {
- // %11:
- // %12:
- // %13 = phi(%zero from %11, %14 from %16)
- // %14 = %13 + 1
- // %15 = %13 < %20
- // } %16: while (%15)
- // %17:
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %20 = OpLoad %float %x
- %21 = OpLoad %float %y
- OpBranch %11
- %11 = OpLabel
- %13 = OpPhi %float %zero %10 %14 %16
- OpLoopMerge %17 %16 None
- OpBranch %12
- %12 = OpLabel
- %14 = OpFAdd %float %13 %one
- %15 = OpFOrdLessThan %bool %13 %20
- OpBranch %16
- %16 = OpLabel
- OpBranchConditional %15 %11 %17
- %17 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
- }
- TEST_F(DivergenceTest, DivergentOverridesPartiallyUniformTest) {
- // pseudocode:
- // %10:
- // %20 = load x
- // %21 = load y
- // %11:
- // do {
- // %12:
- // %13 = phi(%21 from %11, %14 from %16)
- // %14 = %13 + 1
- // %15 = %13 < %20
- // } %16: while (%15)
- // %17:
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %20 = OpLoad %float %x
- %21 = OpLoad %float %y
- OpBranch %11
- %11 = OpLabel
- %13 = OpPhi %float %zero %10 %14 %16
- OpLoopMerge %17 %16 None
- OpBranch %12
- %12 = OpLabel
- %14 = OpFAdd %float %13 %one
- %15 = OpFOrdLessThan %bool %13 %20
- OpBranch %16
- %16 = OpLabel
- OpBranchConditional %15 %11 %17
- %17 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
- }
- TEST_F(DivergenceTest, NestedFixpointTest) {
- // pseudocode:
- // %10:
- // %20 = load x
- // %21 = load y
- // do {
- // %22:
- // %23:
- // %24 = phi(%zero from %22, %25 from %26)
- // %11:
- // do {
- // %12:
- // %13 = phi(%zero from %11, %14 from %16)
- // %14 = %13 + 1
- // %15 = %13 < %24
- // } %16: while (%15)
- // %17:
- // %25 = load x
- // } %26: while (false)
- // %27:
- // return
- ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
- %10 = OpLabel
- %20 = OpLoad %float %x
- %21 = OpLoad %float %y
- OpBranch %22
- %22 = OpLabel
- %24 = OpPhi %float %zero %10 %25 %26
- OpLoopMerge %27 %26 None
- OpBranch %23
- %23 = OpLabel
- OpBranch %11
- %11 = OpLabel
- %13 = OpPhi %float %zero %23 %14 %16
- OpLoopMerge %17 %16 None
- OpBranch %12
- %12 = OpLabel
- %14 = OpFAdd %float %13 %one
- %15 = OpFOrdLessThan %bool %13 %24
- OpBranch %16
- %16 = OpLabel
- OpBranchConditional %15 %11 %17
- %17 = OpLabel
- %25 = OpLoad %float %x
- OpBranch %26
- %26 = OpLabel
- OpBranchConditional %false %22 %27
- %27 = OpLabel
- OpReturn
- OpFunctionEnd
- )"));
- // This test makes sure that divergent values flowing upward can influence the
- // fixpoint of a loop.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
- // Control of the outer loop is still uniform.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(22));
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(23));
- // Seed divergent values.
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(24));
- EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(25));
- // Outer loop control.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(26));
- // Merged.
- EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(27));
- }
- } // namespace
- } // namespace lint
- } // namespace spvtools
|