summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-10-25 22:05:31 +0200
committerGitHub <noreply@github.com>2023-10-25 22:05:31 +0200
commitea6bcd01d95466c9178380f9031a2be9505bdf23 (patch)
tree6f2cc2c9a670d849f6ca7ced4a673741c9870c39
parent6ba0f3d282714fa60be2634fbdf48a8ab5a3997d (diff)
downloadbinaryen-ea6bcd01d95466c9178380f9031a2be9505bdf23.tar.gz
binaryen-ea6bcd01d95466c9178380f9031a2be9505bdf23.tar.bz2
binaryen-ea6bcd01d95466c9178380f9031a2be9505bdf23.zip
[analysis] Implement Flat lattice (#6039)
Given a type `T`, `Flat<T>` is the lattice where none of the values of `T` are comparable except with themselves, but they are all greater than a common bottom element not in `T` and less than a common top element also not in `T`.
-rw-r--r--src/analysis/lattices/flat.h93
-rw-r--r--test/gtest/lattices.cpp103
2 files changed, 196 insertions, 0 deletions
diff --git a/src/analysis/lattices/flat.h b/src/analysis/lattices/flat.h
new file mode 100644
index 000000000..c34f8fc7c
--- /dev/null
+++ b/src/analysis/lattices/flat.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_analysis_lattices_flat_h
+#define wasm_analysis_lattices_flat_h
+
+#include <variant>
+
+#if __cplusplus >= 202002L
+#include <concepts>
+#endif
+
+#include "../lattice.h"
+#include "support/utilities.h"
+
+namespace wasm::analysis {
+
+#if __cplusplus >= 202002L
+
+template<typename T>
+concept Flattenable = std::copyable<T> && std::equality_comparable<T>;
+
+// Given a type T, Flat<T> is the lattice where none of the values of T are
+// comparable except with themselves, but they are all greater than a common
+// bottom element not in T and less than a common top element also not in T.
+template<Flattenable T>
+#else
+template<typename T>
+#endif
+struct Flat {
+private:
+ struct Bot {};
+ struct Top {};
+
+public:
+ struct Element : std::variant<Bot, T, Top> {
+ bool isBottom() const noexcept { return std::get_if<Bot>(this); }
+ bool isTop() const noexcept { return std::get_if<Top>(this); }
+ const T* getVal() const noexcept { return std::get_if<T>(this); }
+ T* getVal() noexcept { return std::get_if<T>(this); }
+ };
+
+ Element getBottom() const noexcept { return Element{Bot{}}; }
+ Element getTop() const noexcept { return Element{Top{}}; }
+ Element get(T&& val) const noexcept { return Element{std::move(val)}; }
+
+ LatticeComparison compare(const Element& a, const Element& b) const noexcept {
+ if (a.index() < b.index()) {
+ return LESS;
+ } else if (a.index() > b.index()) {
+ return GREATER;
+ } else if (auto pA = a.getVal(); pA && *pA != *b.getVal()) {
+ return NO_RELATION;
+ } else {
+ return EQUAL;
+ }
+ }
+ bool join(Element& self, const Element& other) const noexcept {
+ switch (compare(self, other)) {
+ case LESS:
+ self = other;
+ return true;
+ case NO_RELATION:
+ self = Element{Top{}};
+ return true;
+ case GREATER:
+ case EQUAL:
+ return false;
+ }
+ WASM_UNREACHABLE("unexpected comparison result");
+ }
+};
+
+#if __cplusplus >= 202002L
+static_assert(Lattice<Flat<int>>);
+#endif
+
+} // namespace wasm::analysis
+
+#endif // wasm_analysis_lattices_flat_h
diff --git a/test/gtest/lattices.cpp b/test/gtest/lattices.cpp
index 75b232b8e..44b8d0132 100644
--- a/test/gtest/lattices.cpp
+++ b/test/gtest/lattices.cpp
@@ -15,6 +15,7 @@
*/
#include "analysis/lattices/bool.h"
+#include "analysis/lattices/flat.h"
#include "analysis/lattices/int.h"
#include "analysis/lattices/inverted.h"
#include "gtest/gtest.h"
@@ -194,3 +195,105 @@ TEST(InvertedLattice, DoubleInverted) {
EXPECT_FALSE(identity.getBottom());
EXPECT_TRUE(identity.getTop());
}
+
+TEST(FlatLattice, GetBottom) {
+ analysis::Flat<int> flat;
+ EXPECT_TRUE(flat.getBottom().isBottom());
+ EXPECT_FALSE(flat.getBottom().getVal());
+ EXPECT_FALSE(flat.getBottom().isTop());
+}
+
+TEST(FlatLattice, GetVal) {
+ analysis::Flat<int> flat;
+ EXPECT_FALSE(flat.get(10).isBottom());
+ ASSERT_TRUE(flat.get(10).getVal());
+ EXPECT_FALSE(flat.get(10).isTop());
+
+ auto val = flat.get(10);
+ EXPECT_EQ(*val.getVal(), 10);
+}
+
+TEST(FlatLattice, GetTop) {
+ analysis::Flat<int> flat;
+ EXPECT_FALSE(flat.getTop().isBottom());
+ EXPECT_FALSE(flat.getTop().getVal());
+ EXPECT_TRUE(flat.getTop().isTop());
+}
+
+TEST(FlatLattice, Compare) {
+ analysis::Flat<int> flat;
+ auto bot = flat.getBottom();
+ auto a = flat.get(0);
+ auto b = flat.get(1);
+ auto top = flat.getTop();
+
+ EXPECT_EQ(flat.compare(bot, bot), analysis::EQUAL);
+ EXPECT_EQ(flat.compare(bot, a), analysis::LESS);
+ EXPECT_EQ(flat.compare(bot, b), analysis::LESS);
+ EXPECT_EQ(flat.compare(bot, top), analysis::LESS);
+
+ EXPECT_EQ(flat.compare(a, bot), analysis::GREATER);
+ EXPECT_EQ(flat.compare(a, a), analysis::EQUAL);
+ EXPECT_EQ(flat.compare(a, b), analysis::NO_RELATION);
+ EXPECT_EQ(flat.compare(a, top), analysis::LESS);
+
+ EXPECT_EQ(flat.compare(b, bot), analysis::GREATER);
+ EXPECT_EQ(flat.compare(b, a), analysis::NO_RELATION);
+ EXPECT_EQ(flat.compare(b, b), analysis::EQUAL);
+ EXPECT_EQ(flat.compare(b, top), analysis::LESS);
+
+ EXPECT_EQ(flat.compare(top, bot), analysis::GREATER);
+ EXPECT_EQ(flat.compare(top, a), analysis::GREATER);
+ EXPECT_EQ(flat.compare(top, b), analysis::GREATER);
+ EXPECT_EQ(flat.compare(top, top), analysis::EQUAL);
+}
+
+TEST(FlatLattice, Join) {
+ analysis::Flat<int> flat;
+ auto elem = flat.getBottom();
+
+ // bot u bot = bot
+ EXPECT_FALSE(flat.join(elem, flat.getBottom()));
+ EXPECT_TRUE(elem.isBottom());
+
+ // bot u top = top
+ EXPECT_TRUE(flat.join(elem, flat.getTop()));
+ EXPECT_TRUE(elem.isTop());
+
+ // bot u 10 = 10
+ elem = flat.getBottom();
+ EXPECT_TRUE(flat.join(elem, flat.get(10)));
+ ASSERT_TRUE(elem.getVal());
+ EXPECT_EQ(*elem.getVal(), 10);
+
+ // 10 u bot = 10
+ EXPECT_FALSE(flat.join(elem, flat.getBottom()));
+ ASSERT_TRUE(elem.getVal());
+ EXPECT_EQ(*elem.getVal(), 10);
+
+ // 10 u 10 = 10
+ EXPECT_FALSE(flat.join(elem, flat.get(10)));
+ ASSERT_TRUE(elem.getVal());
+ EXPECT_EQ(*elem.getVal(), 10);
+
+ // 10 u 999 = top
+ EXPECT_TRUE(flat.join(elem, flat.get(999)));
+ ASSERT_TRUE(elem.isTop());
+
+ // 10 u top = top
+ elem = flat.get(10);
+ EXPECT_TRUE(flat.join(elem, flat.getTop()));
+ ASSERT_TRUE(elem.isTop());
+
+ // top u bot = top
+ EXPECT_FALSE(flat.join(elem, flat.getBottom()));
+ EXPECT_TRUE(elem.isTop());
+
+ // top u 10 = top
+ EXPECT_FALSE(flat.join(elem, flat.get(10)));
+ EXPECT_TRUE(elem.isTop());
+
+ // top u top = top
+ EXPECT_FALSE(flat.join(elem, flat.getTop()));
+ EXPECT_TRUE(elem.isTop());
+}