Add forwarding so that passes' ctor can have args.

Also removed the default argument value of `skip_nop` for function
`SinglePassRunAndCheck()` and `SinglePassRunAndDisassemble()`. This is
required to support variadic arguments.
This commit is contained in:
qining 2016-08-31 12:44:49 -04:00
parent 273920c554
commit 2ce67252c8
7 changed files with 85 additions and 27 deletions

View File

@ -50,9 +50,11 @@ class PassManager {
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.

0
test/opt/assembly_builder.h Executable file → Normal file
View File

View File

@ -34,9 +34,9 @@
#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 {
@ -57,10 +57,10 @@ class PassTest : public TestT {
// 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);
}
@ -71,17 +71,18 @@ class PassTest : public TestT {
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);
}
@ -89,23 +90,23 @@ class PassTest : public TestT {
// |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.

View File

@ -57,7 +57,8 @@ TEST_F(AssemblyBuilderTest, MinimalShader) {
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
JoinAllInsts(expected));
JoinAllInsts(expected),
/* skip_nop = */ false);
}
TEST_F(AssemblyBuilderTest, ShaderWithConstants) {
@ -170,7 +171,8 @@ TEST_F(AssemblyBuilderTest, ShaderWithConstants) {
// clang-format on
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
JoinAllInsts(expected));
JoinAllInsts(expected),
/* skip_nop = */ false);
}
TEST_F(AssemblyBuilderTest, SpecConstants) {
@ -250,7 +252,8 @@ TEST_F(AssemblyBuilderTest, SpecConstants) {
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
JoinAllInsts(expected));
JoinAllInsts(expected),
/* skip_nop = */ false);
}
TEST_F(AssemblyBuilderTest, AppendNames) {
@ -283,7 +286,8 @@ TEST_F(AssemblyBuilderTest, AppendNames) {
};
SinglePassRunAndCheck<opt::NullPass>(builder.GetCode(),
JoinAllInsts(expected));
JoinAllInsts(expected),
/* skip_nop = */ false);
}
} // anonymous namespace

View File

@ -53,7 +53,7 @@ TEST_P(FreezeSpecConstantValueTypeTest, PrimaryType) {
"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.

View File

@ -26,6 +26,8 @@
#include "gmock/gmock.h"
#include <initializer_list>
#include "module_utils.h"
#include "opt/make_unique.h"
#include "pass_fixture.h"
@ -36,6 +38,17 @@ using namespace spvtools;
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());
@ -54,6 +67,19 @@ TEST(PassManager, Interface) {
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.
@ -66,6 +92,24 @@ class AppendOpNopPass : public opt::Pass {
}
};
// 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"; }
@ -94,6 +138,10 @@ TEST_F(PassManagerTest, Run) {
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.

View File

@ -61,7 +61,8 @@ TEST_F(StripLineDebugInfoTest, LineNoLine) {
// 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 = {
@ -79,7 +80,8 @@ TEST_F(StripLineDebugInfoTest, LineNoLine) {
};
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*>>;
@ -89,7 +91,8 @@ TEST_P(StripDebugInfoTest, Kind) {
"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.