Skip to content

Commit 2aa69e2

Browse files
committed
[analysis] Implement Flat lattice
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`.
1 parent 36232dc commit 2aa69e2

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

src/analysis/lattices/flat.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2023 WebAssembly Community Group participants
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef wasm_analysis_lattices_flat_h
18+
#define wasm_analysis_lattices_flat_h
19+
20+
#include <variant>
21+
22+
#if __cplusplus >= 202002L
23+
#include <concepts>
24+
#endif
25+
26+
#include "../lattice.h"
27+
#include "support/utilities.h"
28+
29+
namespace wasm::analysis {
30+
31+
#if __cplusplus >= 202002L
32+
33+
template<typename T>
34+
concept Flattenable = std::copyable<T> && std::equality_comparable<T>;
35+
36+
template<Flattenable T>
37+
#else
38+
template<typename T>
39+
#endif
40+
struct Flat {
41+
private:
42+
struct Bot {};
43+
struct Top {};
44+
45+
public:
46+
struct Element : std::variant<Bot, T, Top> {
47+
bool isBottom() const noexcept { return std::get_if<Bot>(this); }
48+
bool isTop() const noexcept { return std::get_if<Top>(this); }
49+
const T* getVal() const noexcept { return std::get_if<T>(this); }
50+
T* getVal() noexcept { return std::get_if<T>(this); }
51+
};
52+
53+
Element getBottom() const noexcept { return Element{Bot{}}; }
54+
Element getTop() const noexcept { return Element{Top{}}; }
55+
Element get(T&& val) const noexcept { return Element{std::move(val)}; }
56+
57+
LatticeComparison compare(const Element& a, const Element& b) const noexcept {
58+
if (a.index() < b.index()) {
59+
return LESS;
60+
} else if (a.index() > b.index()) {
61+
return GREATER;
62+
} else if (auto pA = a.getVal(); pA && *pA != *b.getVal()) {
63+
return NO_RELATION;
64+
} else {
65+
return EQUAL;
66+
}
67+
}
68+
bool join(Element& self, const Element& other) const noexcept {
69+
switch (compare(self, other)) {
70+
case LESS:
71+
self = other;
72+
return true;
73+
case NO_RELATION:
74+
self = Element{Top{}};
75+
return true;
76+
case GREATER:
77+
case EQUAL:
78+
return false;
79+
}
80+
WASM_UNREACHABLE("unexpected comparison result");
81+
}
82+
};
83+
84+
#if __cplusplus >= 202002L
85+
static_assert(Lattice<Flat<int>>);
86+
#endif
87+
88+
} // namespace wasm::analysis
89+
90+
#endif // wasm_analysis_lattices_flat_h

test/gtest/lattices.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include "analysis/lattices/bool.h"
18+
#include "analysis/lattices/flat.h"
1819
#include "analysis/lattices/int.h"
1920
#include "analysis/lattices/inverted.h"
2021
#include "gtest/gtest.h"
@@ -194,3 +195,105 @@ TEST(InvertedLattice, DoubleInverted) {
194195
EXPECT_FALSE(identity.getBottom());
195196
EXPECT_TRUE(identity.getTop());
196197
}
198+
199+
TEST(FlatLattice, GetBottom) {
200+
analysis::Flat<int> flat;
201+
EXPECT_TRUE(flat.getBottom().isBottom());
202+
EXPECT_FALSE(flat.getBottom().getVal());
203+
EXPECT_FALSE(flat.getBottom().isTop());
204+
}
205+
206+
TEST(FlatLattice, GetVal) {
207+
analysis::Flat<int> flat;
208+
EXPECT_FALSE(flat.get(10).isBottom());
209+
ASSERT_TRUE(flat.get(10).getVal());
210+
EXPECT_FALSE(flat.get(10).isTop());
211+
212+
auto val = flat.get(10);
213+
EXPECT_EQ(*val.getVal(), 10);
214+
}
215+
216+
TEST(FlatLattice, GetTop) {
217+
analysis::Flat<int> flat;
218+
EXPECT_FALSE(flat.getTop().isBottom());
219+
EXPECT_FALSE(flat.getTop().getVal());
220+
EXPECT_TRUE(flat.getTop().isTop());
221+
}
222+
223+
TEST(FlatLattice, Compare) {
224+
analysis::Flat<int> flat;
225+
auto bot = flat.getBottom();
226+
auto a = flat.get(0);
227+
auto b = flat.get(1);
228+
auto top = flat.getTop();
229+
230+
EXPECT_EQ(flat.compare(bot, bot), analysis::EQUAL);
231+
EXPECT_EQ(flat.compare(bot, a), analysis::LESS);
232+
EXPECT_EQ(flat.compare(bot, b), analysis::LESS);
233+
EXPECT_EQ(flat.compare(bot, top), analysis::LESS);
234+
235+
EXPECT_EQ(flat.compare(a, bot), analysis::GREATER);
236+
EXPECT_EQ(flat.compare(a, a), analysis::EQUAL);
237+
EXPECT_EQ(flat.compare(a, b), analysis::NO_RELATION);
238+
EXPECT_EQ(flat.compare(a, top), analysis::LESS);
239+
240+
EXPECT_EQ(flat.compare(b, bot), analysis::GREATER);
241+
EXPECT_EQ(flat.compare(b, a), analysis::NO_RELATION);
242+
EXPECT_EQ(flat.compare(b, b), analysis::EQUAL);
243+
EXPECT_EQ(flat.compare(b, top), analysis::LESS);
244+
245+
EXPECT_EQ(flat.compare(top, bot), analysis::GREATER);
246+
EXPECT_EQ(flat.compare(top, a), analysis::GREATER);
247+
EXPECT_EQ(flat.compare(top, b), analysis::GREATER);
248+
EXPECT_EQ(flat.compare(top, top), analysis::EQUAL);
249+
}
250+
251+
TEST(FlatLattice, Join) {
252+
analysis::Flat<int> flat;
253+
auto elem = flat.getBottom();
254+
255+
// bot u bot = bot
256+
EXPECT_FALSE(flat.join(elem, flat.getBottom()));
257+
EXPECT_TRUE(elem.isBottom());
258+
259+
// bot u top = top
260+
EXPECT_TRUE(flat.join(elem, flat.getTop()));
261+
EXPECT_TRUE(elem.isTop());
262+
263+
// bot u 10 = 10
264+
elem = flat.getBottom();
265+
EXPECT_TRUE(flat.join(elem, flat.get(10)));
266+
ASSERT_TRUE(elem.getVal());
267+
EXPECT_EQ(*elem.getVal(), 10);
268+
269+
// 10 u bot = 10
270+
EXPECT_FALSE(flat.join(elem, flat.getBottom()));
271+
ASSERT_TRUE(elem.getVal());
272+
EXPECT_EQ(*elem.getVal(), 10);
273+
274+
// 10 u 10 = 10
275+
EXPECT_FALSE(flat.join(elem, flat.get(10)));
276+
ASSERT_TRUE(elem.getVal());
277+
EXPECT_EQ(*elem.getVal(), 10);
278+
279+
// 10 u 999 = top
280+
EXPECT_TRUE(flat.join(elem, flat.get(999)));
281+
ASSERT_TRUE(elem.isTop());
282+
283+
// 10 u top = top
284+
elem = flat.get(10);
285+
EXPECT_TRUE(flat.join(elem, flat.getTop()));
286+
ASSERT_TRUE(elem.isTop());
287+
288+
// top u bot = top
289+
EXPECT_FALSE(flat.join(elem, flat.getBottom()));
290+
EXPECT_TRUE(elem.isTop());
291+
292+
// top u 10 = top
293+
EXPECT_FALSE(flat.join(elem, flat.get(10)));
294+
EXPECT_TRUE(elem.isTop());
295+
296+
// top u top = top
297+
EXPECT_FALSE(flat.join(elem, flat.getTop()));
298+
EXPECT_TRUE(elem.isTop());
299+
}

0 commit comments

Comments
 (0)