void AddPass(std::unique_ptr<Pass> pass) {
passes_.push_back(std::move(pass));
}
- template <typename PassT>
- void AddPass() {
- passes_.emplace_back(new PassT);
+ // Uses the argument to construct a pass instance of type PassT, and adds the
+ // pass instance to this pass manger.
+ template <typename PassT, typename... Args>
+ void AddPass(Args&&... args) {
+ passes_.emplace_back(new PassT(std::forward<Args>(args)...));
}
// Returns the number of passes added.
#include <gtest/gtest.h>
#include "opt/libspirv.hpp"
+#include "opt/make_unique.h"
#include "opt/pass_manager.h"
#include "opt/passes.h"
-#include "opt/make_unique.h"
namespace spvtools {
// disassebles the optimized binary. Returns a tuple of disassembly string
// and the boolean value returned from pass Process() function.
std::tuple<std::string, bool> OptimizeAndDisassemble(
- opt::Pass* pass, const std::string& original, bool skip_nop = false) {
+ opt::Pass* pass, const std::string& original, bool skip_nop) {
std::unique_ptr<ir::Module> module = tools_.BuildModule(original);
- EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" << original
- << std::endl;
+ EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
+ << original << std::endl;
if (!module) {
return std::make_tuple(std::string(), false);
}
module->ToBinary(&binary, skip_nop);
std::string optimized;
EXPECT_EQ(SPV_SUCCESS, tools_.Disassemble(binary, &optimized))
- << "Disassembling failed for shader:\n" << original << std::endl;
+ << "Disassembling failed for shader:\n"
+ << original << std::endl;
return std::make_tuple(optimized, modified);
}
// Runs a single pass of class |PassT| on the binary assembled from the
// |assembly|, disassembles the optimized binary. Returns a tuple of
// disassembly string and the boolean value from the pass Process() function.
- template <typename PassT>
+ template <typename PassT, typename... Args>
std::tuple<std::string, bool> SinglePassRunAndDisassemble(
- const std::string& assembly, bool skip_nop = false) {
- auto pass = MakeUnique<PassT>();
+ const std::string& assembly, bool skip_nop, Args&&... args) {
+ auto pass = MakeUnique<PassT>(std::forward<Args>(args)...);
return OptimizeAndDisassemble(pass.get(), assembly, skip_nop);
}
// |original| assembly, and checks whether the optimized binary can be
// disassembled to the |expected| assembly. This does *not* involve pass
// manager. Callers are suggested to use SCOPED_TRACE() for better messages.
- template <typename PassT>
+ template <typename PassT, typename... Args>
void SinglePassRunAndCheck(const std::string& original,
- const std::string& expected,
- bool skip_nop = false) {
+ const std::string& expected, bool skip_nop,
+ Args&&... args) {
std::string optimized;
bool modified = false;
- std::tie(optimized, modified) =
- SinglePassRunAndDisassemble<PassT>(original, skip_nop);
+ std::tie(optimized, modified) = SinglePassRunAndDisassemble<PassT>(
+ original, skip_nop, std::forward<Args>(args)...);
// Check whether the pass returns the correct modification indication.
EXPECT_EQ(original != expected, modified);
EXPECT_EQ(expected, optimized);
}
// Adds a pass to be run.
- template <typename PassT>
- void AddPass() {
- manager_->AddPass<PassT>();
+ template <typename PassT, typename... Args>
+ void AddPass(Args&&... args) {
+ manager_->AddPass<PassT>(std::forward<Args>(args)...);
}
// Renews the pass manager, including clearing all previously added passes.
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
- JoinAllInsts(expected));
+ JoinAllInsts(expected),
+ /* skip_nop = */ false);
}
TEST_F(AssemblyBuilderTest, ShaderWithConstants) {
// clang-format on
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
- JoinAllInsts(expected));
+ JoinAllInsts(expected),
+ /* skip_nop = */ false);
}
TEST_F(AssemblyBuilderTest, SpecConstants) {
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
- JoinAllInsts(expected));
+ JoinAllInsts(expected),
+ /* skip_nop = */ false);
}
TEST_F(AssemblyBuilderTest, AppendNames) {
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
- JoinAllInsts(expected));
+ JoinAllInsts(expected),
+ /* skip_nop = */ false);
}
} // anonymous namespace
"OpCapability Shader", "OpMemoryModel Logical GLSL450",
test_case.type_decl, test_case.expected_frozen_const};
SinglePassRunAndCheck<opt::FreezeSpecConstantValuePass>(
- JoinAllInsts(text), JoinAllInsts(expected));
+ JoinAllInsts(text), JoinAllInsts(expected), /* skip_nop = */ false);
}
// Test each primary type.
#include "gmock/gmock.h"
+#include <initializer_list>
+
#include "module_utils.h"
#include "opt/make_unique.h"
#include "pass_fixture.h"
using spvtest::GetIdBound;
using ::testing::Eq;
+// A null pass whose construtors accept arguments
+class NullPassWithArgs : public opt::NullPass {
+ public:
+ NullPassWithArgs(uint32_t) : NullPass() {}
+ NullPassWithArgs(std::string) : NullPass() {}
+ NullPassWithArgs(const std::vector<int>&) : NullPass() {}
+ NullPassWithArgs(const std::vector<int>&, uint32_t) : NullPass() {}
+
+ const char* name() const override { return "null-with-args"; }
+};
+
TEST(PassManager, Interface) {
opt::PassManager manager;
EXPECT_EQ(0u, manager.NumPasses());
EXPECT_STREQ("strip-debug", manager.GetPass(0)->name());
EXPECT_STREQ("null", manager.GetPass(1)->name());
EXPECT_STREQ("strip-debug", manager.GetPass(2)->name());
+
+ manager.AddPass<NullPassWithArgs>(1u);
+ manager.AddPass<NullPassWithArgs>("null pass args");
+ manager.AddPass<NullPassWithArgs>(std::initializer_list<int>{1, 2});
+ manager.AddPass<NullPassWithArgs>(std::initializer_list<int>{1, 2}, 3);
+ EXPECT_EQ(7u, manager.NumPasses());
+ EXPECT_STREQ("strip-debug", manager.GetPass(0)->name());
+ EXPECT_STREQ("null", manager.GetPass(1)->name());
+ EXPECT_STREQ("strip-debug", manager.GetPass(2)->name());
+ EXPECT_STREQ("null-with-args", manager.GetPass(3)->name());
+ EXPECT_STREQ("null-with-args", manager.GetPass(4)->name());
+ EXPECT_STREQ("null-with-args", manager.GetPass(5)->name());
+ EXPECT_STREQ("null-with-args", manager.GetPass(6)->name());
}
// A pass that appends an OpNop instruction to the debug section.
}
};
+// A pass that appends specified number of OpNop instructions to the debug
+// section.
+class AppendMultipleOpNopPass : public opt::Pass {
+ public:
+ AppendMultipleOpNopPass(uint32_t num_nop) : num_nop_(num_nop) {}
+ const char* name() const override { return "AppendOpNop"; }
+ bool Process(ir::Module* module) override {
+ for (uint32_t i = 0; i < num_nop_; i++) {
+ auto inst = MakeUnique<ir::Instruction>();
+ module->AddDebugInst(std::move(inst));
+ }
+ return true;
+ }
+
+ private:
+ uint32_t num_nop_;
+};
+
// A pass that duplicates the last instruction in the debug section.
class DuplicateInstPass : public opt::Pass {
const char* name() const override { return "DuplicateInst"; }
AddPass<DuplicateInstPass>();
AddPass<AppendOpNopPass>();
RunAndCheck(text.c_str(), (text + "OpSource ESSL 310\nOpNop\n").c_str());
+
+ RenewPassManger();
+ AddPass<AppendMultipleOpNopPass>(3);
+ RunAndCheck(text.c_str(), (text + "OpNop\nOpNop\nOpNop\n").c_str());
}
// A pass that appends an OpTypeVoid instruction that uses a given id.
// clang-format on
};
SinglePassRunAndCheck<opt::StripDebugInfoPass>(JoinAllInsts(text),
- JoinNonDebugInsts(text));
+ JoinNonDebugInsts(text),
+ /* skip_nop = */ false);
// Let's add more debug instruction before the "OpString" instruction.
const std::vector<const char*> more_text = {
};
text.insert(text.begin() + 4, more_text.cbegin(), more_text.cend());
SinglePassRunAndCheck<opt::StripDebugInfoPass>(JoinAllInsts(text),
- JoinNonDebugInsts(text));
+ JoinNonDebugInsts(text),
+ /* skip_nop = */ false);
}
using StripDebugInfoTest = PassTest<::testing::TestWithParam<const char*>>;
"OpCapability Shader", "OpMemoryModel Logical GLSL450", GetParam(),
};
SinglePassRunAndCheck<opt::StripDebugInfoPass>(JoinAllInsts(text),
- JoinNonDebugInsts(text));
+ JoinNonDebugInsts(text),
+ /* skip_nop = */ false);
}
// Test each possible non-line debug instruction.