123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // 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 <map>
- #include <memory>
- #include <string>
- #include <vector>
- #include "gmock/gmock.h"
- #include "gtest/gtest.h"
- #include "source/opt/build_module.h"
- #include "source/opt/cfg.h"
- #include "source/opt/ir_context.h"
- #include "source/opt/pass.h"
- #include "source/opt/propagator.h"
- namespace spvtools {
- namespace opt {
- namespace {
- using ::testing::UnorderedElementsAre;
- class PropagatorTest : public testing::Test {
- protected:
- virtual void TearDown() {
- ctx_.reset(nullptr);
- values_.clear();
- values_vec_.clear();
- }
- void Assemble(const std::string& input) {
- ctx_ = BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, input);
- ASSERT_NE(nullptr, ctx_) << "Assembling failed for shader:\n"
- << input << "\n";
- }
- bool Propagate(const SSAPropagator::VisitFunction& visit_fn) {
- SSAPropagator propagator(ctx_.get(), visit_fn);
- bool retval = false;
- for (auto& fn : *ctx_->module()) {
- retval |= propagator.Run(&fn);
- }
- return retval;
- }
- const std::vector<uint32_t>& GetValues() {
- values_vec_.clear();
- for (const auto& it : values_) {
- values_vec_.push_back(it.second);
- }
- return values_vec_;
- }
- std::unique_ptr<IRContext> ctx_;
- std::map<uint32_t, uint32_t> values_;
- std::vector<uint32_t> values_vec_;
- };
- TEST_F(PropagatorTest, LocalPropagate) {
- 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 %y "y"
- OpName %z "z"
- OpName %outparm "outparm"
- OpDecorate %outparm Location 0
- %void = OpTypeVoid
- %3 = OpTypeFunction %void
- %int = OpTypeInt 32 1
- %_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
- %5 = OpLabel
- %x = OpVariable %_ptr_Function_int Function
- %y = OpVariable %_ptr_Function_int Function
- %z = OpVariable %_ptr_Function_int Function
- OpStore %x %int_4
- OpStore %y %int_3
- OpStore %z %int_1
- %20 = OpLoad %int %z
- OpStore %outparm %20
- OpReturn
- OpFunctionEnd
- )";
- Assemble(spv_asm);
- const auto visit_fn = [this](Instruction* instr, BasicBlock** dest_bb) {
- *dest_bb = nullptr;
- if (instr->opcode() == SpvOpStore) {
- uint32_t lhs_id = instr->GetSingleWordOperand(0);
- uint32_t rhs_id = instr->GetSingleWordOperand(1);
- Instruction* rhs_def = ctx_->get_def_use_mgr()->GetDef(rhs_id);
- if (rhs_def->opcode() == SpvOpConstant) {
- uint32_t val = rhs_def->GetSingleWordOperand(2);
- values_[lhs_id] = val;
- return SSAPropagator::kInteresting;
- }
- }
- return SSAPropagator::kVarying;
- };
- EXPECT_TRUE(Propagate(visit_fn));
- EXPECT_THAT(GetValues(), UnorderedElementsAre(4, 3, 1));
- }
- TEST_F(PropagatorTest, 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
- %6 = OpSGreaterThan %bool %5 %int_3
- OpSelectionMerge %25 None
- OpBranchConditional %6 %22 %23
- %22 = OpLabel
- %7 = OpLoad %int %int_4
- OpBranch %25
- %23 = OpLabel
- %8 = OpLoad %int %int_4
- OpBranch %25
- %25 = OpLabel
- %35 = OpPhi %int %7 %22 %8 %23
- OpStore %outparm %35
- OpReturn
- OpFunctionEnd
- )";
- Assemble(spv_asm);
- Instruction* phi_instr = nullptr;
- const auto visit_fn = [this, &phi_instr](Instruction* instr,
- BasicBlock** dest_bb) {
- *dest_bb = nullptr;
- if (instr->opcode() == SpvOpLoad) {
- uint32_t rhs_id = instr->GetSingleWordOperand(2);
- Instruction* rhs_def = ctx_->get_def_use_mgr()->GetDef(rhs_id);
- if (rhs_def->opcode() == SpvOpConstant) {
- uint32_t val = rhs_def->GetSingleWordOperand(2);
- values_[instr->result_id()] = val;
- return SSAPropagator::kInteresting;
- }
- } else if (instr->opcode() == SpvOpPhi) {
- phi_instr = instr;
- SSAPropagator::PropStatus retval;
- for (uint32_t i = 2; i < instr->NumOperands(); i += 2) {
- uint32_t phi_arg_id = instr->GetSingleWordOperand(i);
- auto it = values_.find(phi_arg_id);
- if (it != values_.end()) {
- EXPECT_EQ(it->second, 4u);
- retval = SSAPropagator::kInteresting;
- values_[instr->result_id()] = it->second;
- } else {
- retval = SSAPropagator::kNotInteresting;
- break;
- }
- }
- return retval;
- }
- return SSAPropagator::kVarying;
- };
- EXPECT_TRUE(Propagate(visit_fn));
- // The propagator should've concluded that the Phi instruction has a constant
- // value of 4.
- EXPECT_NE(phi_instr, nullptr);
- EXPECT_EQ(values_[phi_instr->result_id()], 4u);
- EXPECT_THAT(GetValues(), UnorderedElementsAre(4u, 4u, 4u));
- }
- } // namespace
- } // namespace opt
- } // namespace spvtools
|