// Runs all passes on the given |module|.
void Run(ir::Module* module) {
+ bool modified = false;
for (const auto& pass : passes_) {
- // TODO(antiagainst): Currently we ignore the return value of the pass,
- // which indicates whether the module has been modified, since there is
- // nothing shared between passes right now.
- pass->Process(module);
+ modified |= pass->Process(module);
}
+ // Set the Id bound in the header in case a pass forgot to do so.
+ if (modified) module->SetIdBound(module->ComputeIdBound());
}
private:
)
add_spvtools_unittest(TARGET pass_manager
- SRCS test_pass_manager.cpp
+ SRCS module_utils.h
+ test_pass_manager.cpp
LIBS SPIRV-Tools-opt ${SPIRV_TOOLS}
)
)
add_spvtools_unittest(TARGET module
- SRCS test_module.cpp
+ SRCS module_utils.h
+ test_module.cpp
LIBS SPIRV-Tools-opt ${SPIRV_TOOLS}
)
--- /dev/null
+// Copyright (c) 2016 Google Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and/or associated documentation files (the
+// "Materials"), to deal in the Materials without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Materials, and to
+// permit persons to whom the Materials are furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Materials.
+//
+// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
+// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
+// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
+// https://www.khronos.org/registry/
+//
+// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
+#ifndef LIBSPIRV_TEST_OPT_MODULE_UTILS_H_
+#define LIBSPIRV_TEST_OPT_MODULE_UTILS_H_
+
+#include <vector>
+#include "opt/module.h"
+
+namespace spvtest {
+
+inline uint32_t GetIdBound(const spvtools::ir::Module& m) {
+ std::vector<uint32_t> binary;
+ m.ToBinary(&binary, false);
+ // The 5-word header must always exist.
+ EXPECT_LE(5u, binary.size());
+ // The bound is the fourth word.
+ return binary[3];
+}
+
+} // namespace spvtest
+
+#endif // LIBSPIRV_TEST_OPT_MODULE_UTILS_H_
#include "opt/libspirv.hpp"
#include "opt/module.h"
+#include "module_utils.h"
+
namespace {
using spvtools::ir::Module;
+using spvtest::GetIdBound;
using ::testing::Eq;
-uint32_t GetIdBound(const Module& m) {
- std::vector<uint32_t> binary;
- m.ToBinary(&binary, false);
- // The 5-word header must always exist.
- EXPECT_GE(5u, binary.size());
- // The bound is the fourth word.
- return binary[3];
-}
-
TEST(ModuleTest, SetIdBound) {
Module m;
// It's initialized to 0.
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-#include "pass_fixture.h"
+#include "gmock/gmock.h"
+
+#include "module_utils.h"
#include "opt/make_unique.h"
+#include "pass_fixture.h"
namespace {
using namespace spvtools;
+using spvtest::GetIdBound;
+using ::testing::Eq;
TEST(PassManager, Interface) {
opt::PassManager manager;
RunAndCheck(text.c_str(), (text + "OpSource ESSL 310\nOpNop\n").c_str());
}
+// A pass that appends an OpTypeVoid instruction that uses a given id.
+class AppendTypeVoidInstPass : public opt::Pass {
+ public:
+ AppendTypeVoidInstPass(uint32_t result_id) : result_id_(result_id) {}
+ const char* name() const override { return "AppendTypeVoidInstPass"; }
+ bool Process(ir::Module* module) override {
+ auto inst = MakeUnique<ir::Instruction>(SpvOpTypeVoid, 0, result_id_,
+ std::vector<ir::Operand>{});
+ module->AddType(std::move(inst));
+ return true;
+ }
+
+ private:
+ uint32_t result_id_;
+};
+
+TEST(PassManager, RecomputeIdBoundAutomatically) {
+ ir::Module module;
+ EXPECT_THAT(GetIdBound(module), Eq(0u));
+
+ opt::PassManager manager;
+ manager.Run(&module);
+ manager.AddPass<AppendOpNopPass>();
+ // With no ID changes, the ID bound does not change.
+ EXPECT_THAT(GetIdBound(module), Eq(0u));
+
+ // Now we force an Id of 100 to be used.
+ manager.AddPass(MakeUnique<AppendTypeVoidInstPass>(100));
+ EXPECT_THAT(GetIdBound(module), Eq(0u));
+ manager.Run(&module);
+ // The Id has been updated automatically, even though the pass
+ // did not update it.
+ EXPECT_THAT(GetIdBound(module), Eq(101u));
+
+ // Try one more time!
+ manager.AddPass(MakeUnique<AppendTypeVoidInstPass>(200));
+ manager.Run(&module);
+ EXPECT_THAT(GetIdBound(module), Eq(201u));
+
+ // Add another pass, but which uses a lower Id.
+ manager.AddPass(MakeUnique<AppendTypeVoidInstPass>(10));
+ manager.Run(&module);
+ // The Id stays high.
+ EXPECT_THAT(GetIdBound(module), Eq(201u));
+}
+
} // anonymous namespace