CloneContext: Support inplace cloning

Add a new constructor that only takes a ProgramBuilder.
This allows cloning objects to and from the same ProgramBuilder.

Also clean up tests.

Change-Id: I7c7bbaced4956f9094d0a6231aa4d7f7b6f17d4c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49744
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Ben Clayton 2021-05-04 18:06:31 +00:00 committed by Commit Bot service account
parent 49a545c919
commit e5b315084d
3 changed files with 80 additions and 42 deletions

View File

@ -39,9 +39,15 @@ CloneContext::CloneContext(ProgramBuilder* to,
}
}
CloneContext::CloneContext(ProgramBuilder* builder)
: CloneContext(builder, nullptr, false) {}
CloneContext::~CloneContext() = default;
Symbol CloneContext::Clone(Symbol s) {
if (!src) {
return s; // In-place clone
}
return utils::GetOrCreate(cloned_symbols_, s, [&]() -> Symbol {
if (symbol_transform_) {
return symbol_transform_(s);

View File

@ -74,7 +74,7 @@ class CloneContext {
/// symbol.
using SymbolTransform = std::function<Symbol(Symbol)>;
/// Constructor
/// Constructor for cloning objects from `from` into `to`.
/// @param to the target ProgramBuilder to clone into
/// @param from the source Program to clone from
/// @param auto_clone_symbols clone all symbols in `from` before returning
@ -82,6 +82,10 @@ class CloneContext {
Program const* from,
bool auto_clone_symbols = true);
/// Constructor for cloning objects from and to the ProgramBuilder `builder`.
/// @param builder the ProgramBuilder
explicit CloneContext(ProgramBuilder* builder);
/// Destructor
~CloneContext();
@ -93,7 +97,8 @@ class CloneContext {
/// Clone() may use a function registered with ReplaceAll() to create a
/// transformed version of the object. See ReplaceAll() for more information.
///
/// The Node or sem::Type `a` must be owned by the Program #src.
/// If the CloneContext is cloning from a Program to a ProgramBuilder, then
/// the Node or sem::Type `a` must be owned by the Program #src.
///
/// @param a the `Node` or `sem::Type` to clone
/// @return the cloned node
@ -104,7 +109,9 @@ class CloneContext {
return nullptr;
}
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
if (src) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
}
// Have we cloned this object already, or was Replace() called for this
// object?
@ -133,7 +140,7 @@ class CloneContext {
// Does the type derive from ShareableCloneable?
if (Is<ShareableCloneable, kDontErrorOnImpossibleCast>(a)) {
// Yes. Record this src -> dst mapping so that future calls to Clone()
// Yes. Record this clone mapping so that future calls to Clone()
// return the same cloned object.
cloned_.emplace(a, cloned);
}
@ -153,7 +160,8 @@ class CloneContext {
/// Unlike Clone(), this method does not invoke or use any transformations
/// registered by ReplaceAll().
///
/// The Node or sem::Type `a` must be owned by the Program #src.
/// If the CloneContext is cloning from a Program to a ProgramBuilder, then
/// the Node or sem::Type `a` must be owned by the Program #src.
///
/// @param a the `Node` or `sem::Type` to clone
/// @return the cloned node
@ -164,7 +172,9 @@ class CloneContext {
return nullptr;
}
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
if (src) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
}
// Have we seen this object before? If so, return the previously cloned
// version instead of making yet another copy.
@ -371,7 +381,7 @@ class CloneContext {
/// @returns this CloneContext so calls can be chained
template <typename T, typename BEFORE, typename OBJECT>
CloneContext& InsertBefore(const std::vector<T>& vector,
BEFORE* before,
const BEFORE* before,
OBJECT* object) {
if (std::find(vector.begin(), vector.end(), before) == vector.end()) {
TINT_ICE(Diagnostics())
@ -393,7 +403,7 @@ class CloneContext {
/// @returns this CloneContext so calls can be chained
template <typename T, typename AFTER, typename OBJECT>
CloneContext& InsertAfter(const std::vector<T>& vector,
AFTER* after,
const AFTER* after,
OBJECT* object) {
if (std::find(vector.begin(), vector.end(), after) == vector.end()) {
TINT_ICE(Diagnostics())

View File

@ -126,17 +126,17 @@ struct ShareableTypes {
};
template <typename T>
struct CloneContextTest : public ::testing::Test {
struct CloneContextNodeTest : public ::testing::Test {
using Node = typename T::Node;
using Replaceable = typename T::Replaceable;
using Replacement = typename T::Replacement;
static constexpr bool is_unique = std::is_same<Node, UniqueNode>::value;
};
using CloneContextTestTypes = ::testing::Types<UniqueTypes, ShareableTypes>;
TYPED_TEST_SUITE(CloneContextTest, CloneContextTestTypes, /**/);
using CloneContextTestNodeTypes = ::testing::Types<UniqueTypes, ShareableTypes>;
TYPED_TEST_SUITE(CloneContextNodeTest, CloneContextTestNodeTypes, /**/);
TYPED_TEST(CloneContextTest, Clone) {
TYPED_TEST(CloneContextNodeTest, Clone) {
using Node = typename TestFixture::Node;
constexpr bool is_unique = TestFixture::is_unique;
@ -199,7 +199,7 @@ TYPED_TEST(CloneContextTest, Clone) {
EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
}
TYPED_TEST(CloneContextTest, CloneWithReplaceAll_Cloneable) {
TYPED_TEST(CloneContextNodeTest, CloneWithReplaceAll_Cloneable) {
using Node = typename TestFixture::Node;
using Replaceable = typename TestFixture::Replaceable;
using Replacement = typename TestFixture::Replacement;
@ -301,7 +301,7 @@ TYPED_TEST(CloneContextTest, CloneWithReplaceAll_Cloneable) {
EXPECT_FALSE(Is<Replacement>(cloned_root->b->b));
}
TYPED_TEST(CloneContextTest, CloneWithReplaceAll_Symbols) {
TYPED_TEST(CloneContextNodeTest, CloneWithReplaceAll_Symbols) {
using Node = typename TestFixture::Node;
Allocator a;
@ -342,7 +342,7 @@ TYPED_TEST(CloneContextTest, CloneWithReplaceAll_Symbols) {
EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("transformed<b->b>"));
}
TYPED_TEST(CloneContextTest, CloneWithoutTransform) {
TYPED_TEST(CloneContextNodeTest, CloneWithoutTransform) {
using Node = typename TestFixture::Node;
using Replacement = typename TestFixture::Replacement;
@ -363,7 +363,7 @@ TYPED_TEST(CloneContextTest, CloneWithoutTransform) {
EXPECT_EQ(cloned_node->name, cloned.Symbols().Get("root"));
}
TYPED_TEST(CloneContextTest, CloneWithReplace) {
TYPED_TEST(CloneContextNodeTest, CloneWithReplace) {
using Node = typename TestFixture::Node;
Allocator a;
@ -397,7 +397,7 @@ TYPED_TEST(CloneContextTest, CloneWithReplace) {
EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
}
TYPED_TEST(CloneContextTest, CloneWithInsertBefore) {
TYPED_TEST(CloneContextNodeTest, CloneWithInsertBefore) {
using Node = typename TestFixture::Node;
constexpr bool is_unique = TestFixture::is_unique;
@ -437,7 +437,7 @@ TYPED_TEST(CloneContextTest, CloneWithInsertBefore) {
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
TYPED_TEST(CloneContextTest, CloneWithInsertAfter) {
TYPED_TEST(CloneContextNodeTest, CloneWithInsertAfter) {
using Node = typename TestFixture::Node;
constexpr bool is_unique = TestFixture::is_unique;
@ -477,7 +477,26 @@ TYPED_TEST(CloneContextTest, CloneWithInsertAfter) {
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
TYPED_TEST(CloneContextTest, CloneWithReplaceAll_SameTypeTwice) {
TYPED_TEST(CloneContextNodeTest, CloneIntoSameBuilder) {
using Node = typename TestFixture::Node;
constexpr bool is_unique = TestFixture::is_unique;
ProgramBuilder builder;
CloneContext ctx(&builder);
Allocator allocator;
auto* original = allocator.Create<Node>(builder.Symbols().New());
auto* cloned_a = ctx.Clone(original);
auto* cloned_b = ctx.Clone(original);
EXPECT_NE(original, cloned_a);
EXPECT_NE(original, cloned_b);
if (is_unique) {
EXPECT_NE(cloned_a, cloned_b);
} else {
EXPECT_EQ(cloned_a, cloned_b);
}
}
TYPED_TEST(CloneContextNodeTest, CloneWithReplaceAll_SameTypeTwice) {
std::string node_name = TypeInfo::Of<typename TestFixture::Node>().name;
EXPECT_FATAL_FAILURE(
@ -494,7 +513,7 @@ TYPED_TEST(CloneContextTest, CloneWithReplaceAll_SameTypeTwice) {
node_name);
}
TYPED_TEST(CloneContextTest, CloneWithReplaceAll_BaseThenDerived) {
TYPED_TEST(CloneContextNodeTest, CloneWithReplaceAll_BaseThenDerived) {
std::string node_name = TypeInfo::Of<typename TestFixture::Node>().name;
std::string replaceable_name =
TypeInfo::Of<typename TestFixture::Replaceable>().name;
@ -515,7 +534,7 @@ TYPED_TEST(CloneContextTest, CloneWithReplaceAll_BaseThenDerived) {
node_name);
}
TYPED_TEST(CloneContextTest, CloneWithReplaceAll_DerivedThenBase) {
TYPED_TEST(CloneContextNodeTest, CloneWithReplaceAll_DerivedThenBase) {
std::string node_name = TypeInfo::Of<typename TestFixture::Node>().name;
std::string replaceable_name =
TypeInfo::Of<typename TestFixture::Replaceable>().name;
@ -535,20 +554,7 @@ TYPED_TEST(CloneContextTest, CloneWithReplaceAll_DerivedThenBase) {
replaceable_name);
}
TYPED_TEST(CloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder cloned;
Program original;
CloneContext ctx(&cloned, &original);
ctx.ReplaceAll([](Symbol s) { return s; });
ctx.ReplaceAll([](Symbol s) { return s; });
},
"internal compiler error: ReplaceAll(const SymbolTransform&) called "
"multiple times on the same CloneContext");
}
TYPED_TEST(CloneContextTest, CloneWithReplace_WithNotANode) {
TYPED_TEST(CloneContextNodeTest, CloneWithReplace_WithNotANode) {
EXPECT_FATAL_FAILURE(
{
using Node = typename TestFixture::Node;
@ -577,7 +583,22 @@ TYPED_TEST(CloneContextTest, CloneWithReplace_WithNotANode) {
"internal compiler error");
}
TYPED_TEST(CloneContextTest, CloneNewUnnamedSymbols) {
using CloneContextTest = ::testing::Test;
TEST_F(CloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder cloned;
Program original;
CloneContext ctx(&cloned, &original);
ctx.ReplaceAll([](Symbol s) { return s; });
ctx.ReplaceAll([](Symbol s) { return s; });
},
"internal compiler error: ReplaceAll(const SymbolTransform&) called "
"multiple times on the same CloneContext");
}
TEST_F(CloneContextTest, CloneNewUnnamedSymbols) {
ProgramBuilder builder;
Symbol old_a = builder.Symbols().New();
Symbol old_b = builder.Symbols().New();
@ -605,7 +626,7 @@ TYPED_TEST(CloneContextTest, CloneNewUnnamedSymbols) {
EXPECT_EQ(cloned.Symbols().NameFor(new_c), "tint_symbol_2_1");
}
TYPED_TEST(CloneContextTest, CloneNewSymbols) {
TEST_F(CloneContextTest, CloneNewSymbols) {
ProgramBuilder builder;
Symbol old_a = builder.Symbols().New("a");
Symbol old_b = builder.Symbols().New("b");
@ -633,7 +654,7 @@ TYPED_TEST(CloneContextTest, CloneNewSymbols) {
EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c_1");
}
TYPED_TEST(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
TEST_F(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
ProgramBuilder builder;
Symbol old_a = builder.Symbols().New("a");
Symbol old_b = builder.Symbols().New("b");
@ -661,15 +682,16 @@ TYPED_TEST(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c");
}
TYPED_TEST(CloneContextTest, ProgramIDs) {
TEST_F(CloneContextTest, ProgramIDs) {
ProgramBuilder dst;
Program src(ProgramBuilder{});
CloneContext ctx(&dst, &src);
Allocator allocator;
ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
auto* cloned = ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
EXPECT_EQ(cloned->program_id, dst.ID());
}
TYPED_TEST(CloneContextTest, ProgramIDs_ObjectNotOwnedBySrc) {
TEST_F(CloneContextTest, ProgramIDs_ObjectNotOwnedBySrc) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder dst;
@ -681,7 +703,7 @@ TYPED_TEST(CloneContextTest, ProgramIDs_ObjectNotOwnedBySrc) {
R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a))");
}
TYPED_TEST(CloneContextTest, ProgramIDs_ObjectNotOwnedByDst) {
TEST_F(CloneContextTest, ProgramIDs_ObjectNotOwnedByDst) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder dst;