mirror of
https://github.com/luau-lang/luau.git
synced 2025-04-08 21:00:54 +01:00
Start to implement some stuff according to pg 9.
This commit is contained in:
parent
bf51d9e613
commit
6e996d1899
2 changed files with 60 additions and 23 deletions
|
@ -1,6 +1,7 @@
|
||||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Luau/Common.h"
|
||||||
#include "Luau/Id.h"
|
#include "Luau/Id.h"
|
||||||
#include "Luau/UnionFind.h"
|
#include "Luau/UnionFind.h"
|
||||||
|
|
||||||
|
@ -23,15 +24,44 @@ struct EClass final
|
||||||
std::vector<std::pair<L, Id>> parents;
|
std::vector<std::pair<L, Id>> parents;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// In Definition 2.1, an EGraph is composed with a tuple (U, M, H) where
|
|
||||||
/// - U: [`EGraph::unionfind`]
|
|
||||||
/// - M: [`EGraph::classes`]
|
|
||||||
/// - H: [`EGraph::hashcons`]
|
|
||||||
///
|
|
||||||
/// See <https://arxiv.org/pdf/2004.03082>.
|
/// See <https://arxiv.org/pdf/2004.03082>.
|
||||||
template<typename L, typename N>
|
template<typename L, typename N>
|
||||||
struct EGraph final
|
class EGraph final
|
||||||
{
|
{
|
||||||
|
/// A union-find data structure 𝑈 stores an equivalence relation over e-class ids.
|
||||||
|
UnionFind unionfind;
|
||||||
|
|
||||||
|
/// The e-class map 𝑀 maps e-class ids to e-classes. All equivalent e-class ids map to the same
|
||||||
|
/// e-class, i.e., 𝑎 ≡id 𝑏 iff 𝑀[𝑎] is the same set as 𝑀[𝑏]. An e-class id 𝑎 is said to refer to the
|
||||||
|
/// e-class 𝑀[find(𝑎)].
|
||||||
|
std::unordered_map<Id, EClass<L, typename N::Data>> classes;
|
||||||
|
|
||||||
|
/// The hashcons 𝐻 is a map from e-nodes to e-class ids.
|
||||||
|
std::unordered_map<L, Id, typename L::Hash> hashcons;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
void canonicalize(T&& enode)
|
||||||
|
{
|
||||||
|
// An e-node 𝑛 is canonical iff 𝑛 = canonicalize(𝑛), where
|
||||||
|
// canonicalize(𝑓(𝑎1, 𝑎2, ...)) = 𝑓(find(𝑎1), find(𝑎2), ...).
|
||||||
|
for (Id& id : enode.operands())
|
||||||
|
id = find(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Id makeEClass(const L& enode)
|
||||||
|
{
|
||||||
|
Id id = unionfind.makeSet();
|
||||||
|
classes.insert_or_assign(id, EClass<L, typename N::Data>{
|
||||||
|
id,
|
||||||
|
{enode},
|
||||||
|
{}, // TODO: analysis make
|
||||||
|
{},
|
||||||
|
});
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
// TODO: static_assert L <: Language
|
// TODO: static_assert L <: Language
|
||||||
// TODO: static_assert N <: Analysis<L>
|
// TODO: static_assert N <: Analysis<L>
|
||||||
|
|
||||||
|
@ -43,11 +73,6 @@ struct EGraph final
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::optional<Id> lookup(T&& enode) const
|
std::optional<Id> lookup(T&& enode) const
|
||||||
{
|
{
|
||||||
// An e-node 𝑛 is canonical iff 𝑛 = canonicalize(𝑛), where
|
|
||||||
// canonicalize(𝑓(𝑎1, 𝑎2, ...)) = 𝑓(find(𝑎1), find(𝑎2), ...).
|
|
||||||
for (Id& id : enode->operands())
|
|
||||||
id = find(id);
|
|
||||||
|
|
||||||
if (auto it = hashcons.find(enode); it != hashcons.end())
|
if (auto it = hashcons.find(enode); it != hashcons.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
|
@ -56,25 +81,26 @@ struct EGraph final
|
||||||
|
|
||||||
Id add(L enode)
|
Id add(L enode)
|
||||||
{
|
{
|
||||||
|
canonicalize(enode);
|
||||||
|
|
||||||
if (auto id = lookup(enode))
|
if (auto id = lookup(enode))
|
||||||
return *id;
|
return *id;
|
||||||
|
|
||||||
Id id{hashcons.size()};
|
Id id = makeEClass(enode);
|
||||||
|
for (Id operand : enode.operands())
|
||||||
|
(*this)[operand].parents.push_back({enode, id});
|
||||||
|
|
||||||
hashcons.insert_or_assign(enode, id);
|
hashcons.insert_or_assign(enode, id);
|
||||||
|
// TODO clean = false
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
EClass<L, typename N::Data>& operator[](Id id)
|
||||||
/// A union-find data structure 𝑈 stores an equivalence relation over e-class ids.
|
{
|
||||||
UnionFind unionfind;
|
auto it = classes.find(find(id));
|
||||||
|
LUAU_ASSERT(it != classes.end());
|
||||||
/// The e-class map 𝑀 maps e-class ids to e-classes. All equivalent e-class ids map to the same
|
return it->second;
|
||||||
/// e-class, i.e., 𝑎 ≡id 𝑏 iff 𝑀[𝑎] is the same set as 𝑀[𝑏]. An e-class id 𝑎 is said to refer to the
|
}
|
||||||
/// e-class 𝑀[find(𝑎)].
|
|
||||||
std::unordered_map<Id, EClass<L, typename N::Data>> classes;
|
|
||||||
|
|
||||||
/// The hashcons 𝐻 is a map from e-nodes to e-class ids.
|
|
||||||
std::unordered_map<L, Id, typename L::Hash> hashcons;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Luau::EqSat
|
} // namespace Luau::EqSat
|
||||||
|
|
|
@ -47,4 +47,15 @@ TEST_CASE("egraph_hashconsing")
|
||||||
CHECK(id2 != id3);
|
CHECK(id2 != id3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("egraph_data")
|
||||||
|
{
|
||||||
|
EGraph egraph;
|
||||||
|
|
||||||
|
EqSat::Id id1 = egraph.add(Bool{true});
|
||||||
|
EqSat::Id id2 = egraph.add(Bool{false});
|
||||||
|
|
||||||
|
CHECK(egraph[id1].data == std::nullopt); // TODO: true
|
||||||
|
CHECK(egraph[id2].data == std::nullopt); // TODO: false
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
|
Loading…
Add table
Reference in a new issue