mirror of
https://github.com/luau-lang/luau.git
synced 2025-04-10 22:00:54 +01:00
Implement rebuild and show it works.
This commit is contained in:
parent
4183c31d23
commit
26f1d18c81
3 changed files with 124 additions and 4 deletions
|
@ -62,6 +62,8 @@ class EGraph final
|
||||||
/// The hashcons 𝐻 is a map from e-nodes to e-class ids.
|
/// The hashcons 𝐻 is a map from e-nodes to e-class ids.
|
||||||
std::unordered_map<L, Id, typename L::Hash> hashcons;
|
std::unordered_map<L, Id, typename L::Hash> hashcons;
|
||||||
|
|
||||||
|
VecDeque<std::pair<L, Id>> worklist;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void canonicalize(L& enode)
|
void canonicalize(L& enode)
|
||||||
{
|
{
|
||||||
|
@ -95,6 +97,7 @@ private:
|
||||||
for (Id operand : enode.operands())
|
for (Id operand : enode.operands())
|
||||||
get(operand).parents.push_back({enode, id});
|
get(operand).parents.push_back({enode, id});
|
||||||
|
|
||||||
|
worklist.push_back({enode, id});
|
||||||
hashcons.insert_or_assign(enode, id);
|
hashcons.insert_or_assign(enode, id);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
@ -104,9 +107,29 @@ private:
|
||||||
// For a canonicalized eclass, use `get(find(id))` or `egraph[id]`.
|
// For a canonicalized eclass, use `get(find(id))` or `egraph[id]`.
|
||||||
EClass<L, typename N::Data>& get(Id id)
|
EClass<L, typename N::Data>& get(Id id)
|
||||||
{
|
{
|
||||||
auto it = classes.find(id);
|
return classes.at(id);
|
||||||
LUAU_ASSERT(it != classes.end());
|
}
|
||||||
return it->second;
|
|
||||||
|
void repair(EClass<L, typename N::Data>& eclass)
|
||||||
|
{
|
||||||
|
// After canonicalizing the enodes, the eclass may contain multiple enodes that are equivalent.
|
||||||
|
std::unordered_map<L, Id, typename L::Hash> map;
|
||||||
|
for (auto& [enode, id] : eclass.parents)
|
||||||
|
{
|
||||||
|
// By removing the old enode from the hashcons map, we will always find our new canonicalized eclass id.
|
||||||
|
hashcons.erase(enode);
|
||||||
|
canonicalize(enode);
|
||||||
|
hashcons.insert_or_assign(enode, find(id));
|
||||||
|
|
||||||
|
if (auto it = map.find(enode); it != map.end())
|
||||||
|
merge(id, it->second);
|
||||||
|
|
||||||
|
map.insert_or_assign(enode, find(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
eclass.parents.clear();
|
||||||
|
for (auto& [enode, id] : map)
|
||||||
|
eclass.parents.push_back({std::move(enode), id});
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -150,9 +173,28 @@ public:
|
||||||
EClass<L, typename N::Data> eclass2 = get(id2);
|
EClass<L, typename N::Data> eclass2 = get(id2);
|
||||||
classes.erase(id2);
|
classes.erase(id2);
|
||||||
|
|
||||||
|
worklist.reserve(worklist.size() + eclass2.parents.size());
|
||||||
|
for (auto [enode, id] : eclass2.parents)
|
||||||
|
worklist.push_back({std::move(enode), id});
|
||||||
|
|
||||||
analysis.join(eclass1.data, eclass2.data);
|
analysis.join(eclass1.data, eclass2.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rebuild()
|
||||||
|
{
|
||||||
|
while (!worklist.empty())
|
||||||
|
{
|
||||||
|
auto [enode, id] = worklist.back();
|
||||||
|
worklist.pop_back();
|
||||||
|
repair(get(find(id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return classes.size();
|
||||||
|
}
|
||||||
|
|
||||||
EClass<L, typename N::Data>& operator[](Id id)
|
EClass<L, typename N::Data>& operator[](Id id)
|
||||||
{
|
{
|
||||||
return get(find(id));
|
return get(find(id));
|
||||||
|
|
|
@ -23,7 +23,8 @@ struct LanguageHash
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::size_t languageHash(const T& lang) {
|
std::size_t languageHash(const T& lang)
|
||||||
|
{
|
||||||
return LanguageHash<T>{}(lang);
|
return LanguageHash<T>{}(lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,4 +112,81 @@ TEST_CASE("egraph_merge")
|
||||||
CHECK(egraph[id2].data == true);
|
CHECK(egraph[id2].data == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("const_fold_true_and_true")
|
||||||
|
{
|
||||||
|
EGraph egraph;
|
||||||
|
|
||||||
|
EqSat::Id id1 = egraph.add(Bool{true});
|
||||||
|
EqSat::Id id2 = egraph.add(Bool{true});
|
||||||
|
EqSat::Id id3 = egraph.add(And{id1, id2});
|
||||||
|
|
||||||
|
CHECK(egraph[id3].data == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("const_fold_true_and_false")
|
||||||
|
{
|
||||||
|
EGraph egraph;
|
||||||
|
|
||||||
|
EqSat::Id id1 = egraph.add(Bool{true});
|
||||||
|
EqSat::Id id2 = egraph.add(Bool{false});
|
||||||
|
EqSat::Id id3 = egraph.add(And{id1, id2});
|
||||||
|
|
||||||
|
CHECK(egraph[id3].data == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("const_fold_false_and_false")
|
||||||
|
{
|
||||||
|
EGraph egraph;
|
||||||
|
|
||||||
|
EqSat::Id id1 = egraph.add(Bool{false});
|
||||||
|
EqSat::Id id2 = egraph.add(Bool{false});
|
||||||
|
EqSat::Id id3 = egraph.add(And{id1, id2});
|
||||||
|
|
||||||
|
CHECK(egraph[id3].data == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("implications")
|
||||||
|
{
|
||||||
|
EGraph egraph;
|
||||||
|
|
||||||
|
EqSat::Id t = egraph.add(Bool{true});
|
||||||
|
EqSat::Id f = egraph.add(Bool{false});
|
||||||
|
|
||||||
|
EqSat::Id a = egraph.add(Implies{t, t}); // true
|
||||||
|
EqSat::Id b = egraph.add(Implies{t, f}); // false
|
||||||
|
EqSat::Id c = egraph.add(Implies{f, t}); // true
|
||||||
|
EqSat::Id d = egraph.add(Implies{f, f}); // true
|
||||||
|
|
||||||
|
CHECK(egraph[a].data == true);
|
||||||
|
CHECK(egraph[b].data == false);
|
||||||
|
CHECK(egraph[c].data == true);
|
||||||
|
CHECK(egraph[d].data == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("merge_x_and_y")
|
||||||
|
{
|
||||||
|
EGraph egraph;
|
||||||
|
|
||||||
|
EqSat::Id x = egraph.add(Var{"x"});
|
||||||
|
EqSat::Id y = egraph.add(Var{"y"});
|
||||||
|
|
||||||
|
EqSat::Id a = egraph.add(Var{"a"});
|
||||||
|
EqSat::Id ax = egraph.add(And{a, x});
|
||||||
|
EqSat::Id ay = egraph.add(And{a, y});
|
||||||
|
|
||||||
|
egraph.merge(x, y); // [x y] [ax] [ay] [a]
|
||||||
|
CHECK_EQ(egraph.size(), 4);
|
||||||
|
CHECK_EQ(egraph.find(x), egraph.find(y));
|
||||||
|
CHECK_NE(egraph.find(ax), egraph.find(ay));
|
||||||
|
CHECK_NE(egraph.find(a), egraph.find(x));
|
||||||
|
CHECK_NE(egraph.find(a), egraph.find(y));
|
||||||
|
|
||||||
|
egraph.rebuild(); // [x y] [ax ay] [a]
|
||||||
|
CHECK_EQ(egraph.size(), 3);
|
||||||
|
CHECK_EQ(egraph.find(x), egraph.find(y));
|
||||||
|
CHECK_EQ(egraph.find(ax), egraph.find(ay));
|
||||||
|
CHECK_NE(egraph.find(a), egraph.find(x));
|
||||||
|
CHECK_NE(egraph.find(a), egraph.find(y));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
|
Loading…
Add table
Reference in a new issue