pass_manager_test.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright (c) 2016 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <initializer_list>
  15. #include <memory>
  16. #include <string>
  17. #include <utility>
  18. #include <vector>
  19. #include "gmock/gmock.h"
  20. #include "source/util/make_unique.h"
  21. #include "test/opt/module_utils.h"
  22. #include "test/opt/pass_fixture.h"
  23. namespace spvtools {
  24. namespace opt {
  25. namespace {
  26. using spvtest::GetIdBound;
  27. using ::testing::Eq;
  28. // A null pass whose construtors accept arguments
  29. class NullPassWithArgs : public NullPass {
  30. public:
  31. NullPassWithArgs(uint32_t) {}
  32. NullPassWithArgs(std::string) {}
  33. NullPassWithArgs(const std::vector<int>&) {}
  34. NullPassWithArgs(const std::vector<int>&, uint32_t) {}
  35. const char* name() const override { return "null-with-args"; }
  36. };
  37. TEST(PassManager, Interface) {
  38. PassManager manager;
  39. EXPECT_EQ(0u, manager.NumPasses());
  40. manager.AddPass<StripDebugInfoPass>();
  41. EXPECT_EQ(1u, manager.NumPasses());
  42. EXPECT_STREQ("strip-debug", manager.GetPass(0)->name());
  43. manager.AddPass(MakeUnique<NullPass>());
  44. EXPECT_EQ(2u, manager.NumPasses());
  45. EXPECT_STREQ("strip-debug", manager.GetPass(0)->name());
  46. EXPECT_STREQ("null", manager.GetPass(1)->name());
  47. manager.AddPass<StripDebugInfoPass>();
  48. EXPECT_EQ(3u, manager.NumPasses());
  49. EXPECT_STREQ("strip-debug", manager.GetPass(0)->name());
  50. EXPECT_STREQ("null", manager.GetPass(1)->name());
  51. EXPECT_STREQ("strip-debug", manager.GetPass(2)->name());
  52. manager.AddPass<NullPassWithArgs>(1u);
  53. manager.AddPass<NullPassWithArgs>("null pass args");
  54. manager.AddPass<NullPassWithArgs>(std::initializer_list<int>{1, 2});
  55. manager.AddPass<NullPassWithArgs>(std::initializer_list<int>{1, 2}, 3);
  56. EXPECT_EQ(7u, manager.NumPasses());
  57. EXPECT_STREQ("strip-debug", manager.GetPass(0)->name());
  58. EXPECT_STREQ("null", manager.GetPass(1)->name());
  59. EXPECT_STREQ("strip-debug", manager.GetPass(2)->name());
  60. EXPECT_STREQ("null-with-args", manager.GetPass(3)->name());
  61. EXPECT_STREQ("null-with-args", manager.GetPass(4)->name());
  62. EXPECT_STREQ("null-with-args", manager.GetPass(5)->name());
  63. EXPECT_STREQ("null-with-args", manager.GetPass(6)->name());
  64. }
  65. // A pass that appends an OpNop instruction to the debug1 section.
  66. class AppendOpNopPass : public Pass {
  67. public:
  68. const char* name() const override { return "AppendOpNop"; }
  69. Status Process() override {
  70. context()->AddDebug1Inst(MakeUnique<Instruction>(context()));
  71. return Status::SuccessWithChange;
  72. }
  73. };
  74. // A pass that appends specified number of OpNop instructions to the debug1
  75. // section.
  76. class AppendMultipleOpNopPass : public Pass {
  77. public:
  78. explicit AppendMultipleOpNopPass(uint32_t num_nop) : num_nop_(num_nop) {}
  79. const char* name() const override { return "AppendOpNop"; }
  80. Status Process() override {
  81. for (uint32_t i = 0; i < num_nop_; i++) {
  82. context()->AddDebug1Inst(MakeUnique<Instruction>(context()));
  83. }
  84. return Status::SuccessWithChange;
  85. }
  86. private:
  87. uint32_t num_nop_;
  88. };
  89. // A pass that duplicates the last instruction in the debug1 section.
  90. class DuplicateInstPass : public Pass {
  91. public:
  92. const char* name() const override { return "DuplicateInst"; }
  93. Status Process() override {
  94. auto inst = MakeUnique<Instruction>(*(--context()->debug1_end()));
  95. context()->AddDebug1Inst(std::move(inst));
  96. return Status::SuccessWithChange;
  97. }
  98. };
  99. using PassManagerTest = PassTest<::testing::Test>;
  100. TEST_F(PassManagerTest, Run) {
  101. const std::string text = "OpMemoryModel Logical GLSL450\nOpSource ESSL 310\n";
  102. AddPass<AppendOpNopPass>();
  103. AddPass<AppendOpNopPass>();
  104. RunAndCheck(text, text + "OpNop\nOpNop\n");
  105. RenewPassManger();
  106. AddPass<AppendOpNopPass>();
  107. AddPass<DuplicateInstPass>();
  108. RunAndCheck(text, text + "OpNop\nOpNop\n");
  109. RenewPassManger();
  110. AddPass<DuplicateInstPass>();
  111. AddPass<AppendOpNopPass>();
  112. RunAndCheck(text, text + "OpSource ESSL 310\nOpNop\n");
  113. RenewPassManger();
  114. AddPass<AppendMultipleOpNopPass>(3);
  115. RunAndCheck(text, text + "OpNop\nOpNop\nOpNop\n");
  116. }
  117. // A pass that appends an OpTypeVoid instruction that uses a given id.
  118. class AppendTypeVoidInstPass : public Pass {
  119. public:
  120. explicit AppendTypeVoidInstPass(uint32_t result_id) : result_id_(result_id) {}
  121. const char* name() const override { return "AppendTypeVoidInstPass"; }
  122. Status Process() override {
  123. auto inst = MakeUnique<Instruction>(context(), SpvOpTypeVoid, 0, result_id_,
  124. std::vector<Operand>{});
  125. context()->AddType(std::move(inst));
  126. return Status::SuccessWithChange;
  127. }
  128. private:
  129. uint32_t result_id_;
  130. };
  131. TEST(PassManager, RecomputeIdBoundAutomatically) {
  132. PassManager manager;
  133. std::unique_ptr<Module> module(new Module());
  134. IRContext context(SPV_ENV_UNIVERSAL_1_2, std::move(module),
  135. manager.consumer());
  136. EXPECT_THAT(GetIdBound(*context.module()), Eq(0u));
  137. manager.Run(&context);
  138. manager.AddPass<AppendOpNopPass>();
  139. // With no ID changes, the ID bound does not change.
  140. EXPECT_THAT(GetIdBound(*context.module()), Eq(0u));
  141. // Now we force an Id of 100 to be used.
  142. manager.AddPass(MakeUnique<AppendTypeVoidInstPass>(100));
  143. EXPECT_THAT(GetIdBound(*context.module()), Eq(0u));
  144. manager.Run(&context);
  145. // The Id has been updated automatically, even though the pass
  146. // did not update it.
  147. EXPECT_THAT(GetIdBound(*context.module()), Eq(101u));
  148. // Try one more time!
  149. manager.AddPass(MakeUnique<AppendTypeVoidInstPass>(200));
  150. manager.Run(&context);
  151. EXPECT_THAT(GetIdBound(*context.module()), Eq(201u));
  152. // Add another pass, but which uses a lower Id.
  153. manager.AddPass(MakeUnique<AppendTypeVoidInstPass>(10));
  154. manager.Run(&context);
  155. // The Id stays high.
  156. EXPECT_THAT(GetIdBound(*context.module()), Eq(201u));
  157. }
  158. } // anonymous namespace
  159. } // namespace opt
  160. } // namespace spvtools