From 39dcae3d5af621d886787672f5d04cf57535f492 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Tue, 19 Apr 2016 11:47:47 -0700 Subject: [PATCH] Specialize NameMap::visit_children for ordered_map so that order is preserved when nodes change names or split or whatever. --- ir/ir-inline.h | 32 ++++++++++++++++++++++--- ir/namemap.h | 2 +- lib/ordered_map.h | 27 ++++++++++++++++++--- test/Makefile.am | 5 +++- test/unittests/namemap_order_test.cpp | 34 +++++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 test/unittests/namemap_order_test.cpp diff --git a/ir/ir-inline.h b/ir/ir-inline.h index fd3ca5bd62..e0dfae8770 100644 --- a/ir/ir-inline.h +++ b/ir/ir-inline.h @@ -76,9 +76,35 @@ std::ostream &operator<<(std::ostream &out, const IR::Vector &v) inline std::ostream &operator<<(std::ostream &out, const IR::Vector *v) { return v ? out << *v : out << ""; } +#include "lib/ordered_map.h" +template static inline void +namemap_insert_helper(typename MAP::iterator, typename MAP::key_type k, + typename MAP::mapped_type v, MAP &, MAP &new_symbols) { + new_symbols.emplace(std::move(k), std::move(v)); +} + +template static inline void +namemap_insert_helper(typename MAP::iterator, InputIterator b, InputIterator e, + MAP &, MAP &new_symbols) { + new_symbols.insert(b, e); +} + +template static inline void +namemap_insert_helper(typename ordered_map::iterator it, cstring k, T v, + ordered_map &symbols, ordered_map &) { + symbols.emplace_hint(it, std::move(k), std::move(v)); +} + +template static inline void +namemap_insert_helper(typename ordered_map::iterator it, + InputIterator b, InputIterator e, + ordered_map &symbols, ordered_map &) { + symbols.insert(it, b, e); +} + template class MAP /*= std::map */, class COMP /*= std::less*/, - class ALLOC /*= std::allocator>*/> + class ALLOC /*= std::allocator>*/> void IR::NameMap::visit_children(Visitor &v) { map_t new_symbols; for (auto i = symbols.begin(); i != symbols.end();) { @@ -88,14 +114,14 @@ void IR::NameMap::visit_children(Visitor &v) { } else if (n == i->second) { i++; } else if (auto m = dynamic_cast(n)) { - new_symbols.insert(m->symbols.begin(), m->symbols.end()); + namemap_insert_helper(i, m->symbols.begin(), m->symbols.end(), symbols, new_symbols); i = symbols.erase(i); } else if (auto s = dynamic_cast(n)) { if (match_name(i->first, s)) { i->second = s; i++; } else { - new_symbols.emplace(obj_name(s), std::move(s)); + namemap_insert_helper(i, cstring(obj_name(s)), std::move(s), symbols, new_symbols); i = symbols.erase(i); } } else { BUG("visitor returned invalid type %s for NameMap<%s>", diff --git a/ir/namemap.h b/ir/namemap.h index 667fcea3ca..73e7b668aa 100644 --- a/ir/namemap.h +++ b/ir/namemap.h @@ -5,7 +5,7 @@ namespace IR { template class MAP = std::map, class COMP = std::less, - class ALLOC = std::allocator>> + class ALLOC = std::allocator>> class NameMap : public Node { typedef MAP map_t; map_t symbols; diff --git a/lib/ordered_map.h b/lib/ordered_map.h index 1483d7d1c2..eb0ffd90bb 100644 --- a/lib/ordered_map.h +++ b/lib/ordered_map.h @@ -130,6 +130,22 @@ class ordered_map { if (it == data.end()) throw std::out_of_range("ordered_map"); return it->second; } + std::pair emplace(K &&k, V &&v) { + auto it = find(k); + if (it == data.end()) { + it = data.emplace(data.end(), std::move(k), std::move(v)); + data_map.emplace(&it->first, it); + return std::make_pair(it, true); } + return std::make_pair(it, false); } + std::pair emplace_hint(iterator pos, K &&k, V &&v) { + /* should be const_iterator pos, but glibc++ std::list is broken */ + auto it = find(k); + if (it == data.end()) { + it = data.emplace(pos, std::move(k), std::move(v)); + data_map.emplace(&it->first, it); + return std::make_pair(it, true); } + return std::make_pair(it, false); } + std::pair insert(const value_type &v) { auto it = find(v.first); if (it == data.end()) { @@ -137,15 +153,20 @@ class ordered_map { data_map.emplace(&it->first, it); return std::make_pair(it, true); } return std::make_pair(it, false); } - std::pair emplace(K &&k, V &&v) { - auto it = find(k); + std::pair insert(iterator pos, const value_type &v) { + /* should be const_iterator pos, but glibc++ std::list is broken */ + auto it = find(v.first); if (it == data.end()) { - it = data.emplace(data.end(), std::move(k), std::move(v)); + it = data.insert(pos, v); data_map.emplace(&it->first, it); return std::make_pair(it, true); } return std::make_pair(it, false); } template void insert(InputIterator b, InputIterator e) { while (b != e) insert(*b++); } + template + void insert(iterator pos, InputIterator b, InputIterator e) { + /* should be const_iterator pos, but glibc++ std::list is broken */ + while (b != e) insert(pos, *b++); } /* should be erase(const_iterator), but glibc++ std::list::erase is broken */ iterator erase(iterator pos) { diff --git a/test/Makefile.am b/test/Makefile.am index 4c7b40ea68..4daf870e4e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,7 +1,8 @@ # Unit tests check_PROGRAMS = exception_test format_test source_file_test path_test \ - enumerator_test default_test unittest_transform1 json_test + enumerator_test default_test unittest_transform1 json_test \ + namemap_order_test default_test_SOURCES = test/unittests/default_test.cpp default_test_LDADD = libp4ctoolkit.a @@ -19,6 +20,8 @@ json_test_SOURCES = test/unittests/json_test.cpp json_test_LDADD = libp4ctoolkit.a unittest_transform1_SOURCES = $(ir_SOURCES) test/unittests/transform1.cpp unittest_transform1_LDADD = libp4ctoolkit.a +namemap_order_test_SOURCES = $(ir_SOURCES) test/unittests/namemap_order_test.cpp +namemap_order_test_LDADD = libp4ctoolkit.a # Compiler tests diff --git a/test/unittests/namemap_order_test.cpp b/test/unittests/namemap_order_test.cpp new file mode 100644 index 0000000000..6d6256285b --- /dev/null +++ b/test/unittests/namemap_order_test.cpp @@ -0,0 +1,34 @@ +#include "ir/ir.h" +#include "ir/visitor.h" +#include + +class TestTrans : public Transform { + IR::Node *preorder(IR::TableProperty *a) override { + if (!a->isConstant) + a->name = "$new$"; + return a; + } + IR::Node *postorder(IR::TableProperties *p) override { + int count = 0; + for (auto &prop : p->properties) { + if (prop.first == "$new$") + assert(count == 0); + else + assert(count == 1); + ++count; } + return p; + } +}; + +int main() { + auto tp = new IR::TableProperties(); + tp->properties.add("a", new IR::TableProperty(Util::SourceInfo(), "a", + new IR::Annotations(new IR::Vector()), + new IR::Key(Util::SourceInfo(), new IR::Vector()), + false)); + tp->properties.add("b", new IR::TableProperty(Util::SourceInfo(), "b", + new IR::Annotations(new IR::Vector()), + new IR::Key(Util::SourceInfo(), new IR::Vector()), + true)); + tp->apply(TestTrans()); +}