Skip to content

Commit 4b038e3

Browse files
committed
Extend knowledge base.
1 parent 729db52 commit 4b038e3

File tree

4 files changed

+119
-9
lines changed

4 files changed

+119
-9
lines changed

libyul/optimiser/KnowledgeBase.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@ bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
4040
// current values to turn `sub(_a, _b)` into a nonzero constant.
4141
// If that fails, try `eq(_a, _b)`.
4242

43-
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, util::make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
44-
if (holds_alternative<Literal>(expr1))
45-
return valueOfLiteral(std::get<Literal>(expr1)) != 0;
43+
if (optional<u256> difference = differenceIfKnownConstant(_a, _b))
44+
return difference != 0;
4645

4746
Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, util::make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
4847
if (holds_alternative<Literal>(expr2))
@@ -51,21 +50,42 @@ bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
5150
return false;
5251
}
5352

53+
optional<u256> KnowledgeBase::differenceIfKnownConstant(YulString _a, YulString _b)
54+
{
55+
// Try to use the simplification rules together with the
56+
// current values to turn `sub(_a, _b)` into a constant.
57+
58+
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, util::make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
59+
if (Literal const* value = get_if<Literal>(&expr1))
60+
return valueOfLiteral(*value);
61+
62+
return {};
63+
}
64+
5465
bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b)
5566
{
5667
// Try to use the simplification rules together with the
5768
// current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32.
5869

59-
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, util::make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
60-
if (holds_alternative<Literal>(expr1))
61-
{
62-
u256 val = valueOfLiteral(std::get<Literal>(expr1));
63-
return val >= 32 && val <= u256(0) - 32;
64-
}
70+
if (optional<u256> difference = differenceIfKnownConstant(_a, _b))
71+
return difference >= 32 && difference <= u256(0) - 32;
6572

6673
return false;
6774
}
6875

76+
bool KnowledgeBase::knownToBeZero(YulString _a)
77+
{
78+
return valueIfKnownConstant(_a) == u256{};
79+
}
80+
81+
optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a)
82+
{
83+
if (m_variableValues.count(_a))
84+
if (Literal const* literal = get_if<Literal>(m_variableValues.at(_a).value))
85+
return valueOfLiteral(*literal);
86+
return {};
87+
}
88+
6989
Expression KnowledgeBase::simplify(Expression _expression)
7090
{
7191
bool startedRecursion = (m_recursionCounter == 0);

libyul/optimiser/KnowledgeBase.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <libyul/ASTForward.h>
2525
#include <libyul/YulString.h>
2626

27+
#include <libsolutil/Common.h>
28+
2729
#include <map>
2830

2931
namespace solidity::yul
@@ -46,8 +48,11 @@ class KnowledgeBase
4648
{}
4749

4850
bool knownToBeDifferent(YulString _a, YulString _b);
51+
std::optional<u256> differenceIfKnownConstant(YulString _a, YulString _b);
4952
bool knownToBeDifferentByAtLeast32(YulString _a, YulString _b);
5053
bool knownToBeEqual(YulString _a, YulString _b) const { return _a == _b; }
54+
bool knownToBeZero(YulString _a);
55+
std::optional<u256> valueIfKnownConstant(YulString _a);
5156

5257
private:
5358
Expression simplify(Expression _expression);

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ set(libyul_sources
136136
libyul/FunctionSideEffects.cpp
137137
libyul/FunctionSideEffects.h
138138
libyul/Inliner.cpp
139+
libyul/KnowledgeBaseTest.cpp
139140
libyul/Metrics.cpp
140141
libyul/ObjectCompilerTest.cpp
141142
libyul/ObjectCompilerTest.h

test/libyul/KnowledgeBaseTest.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* Unit tests for KnowledgeBase
19+
*/
20+
21+
#include <test/Common.h>
22+
23+
#include <test/libyul/Common.h>
24+
25+
#include <libyul/Object.h>
26+
#include <libyul/optimiser/KnowledgeBase.h>
27+
#include <libyul/optimiser/SSAValueTracker.h>
28+
#include <libyul/optimiser/DataFlowAnalyzer.h>
29+
#include <libyul/backends/evm/EVMDialect.h>
30+
31+
#include <liblangutil/ErrorReporter.h>
32+
33+
#include <boost/test/unit_test.hpp>
34+
35+
using namespace std;
36+
using namespace solidity::langutil;
37+
38+
namespace solidity::yul::test
39+
{
40+
41+
class KnowledgeBaseTest
42+
{
43+
protected:
44+
KnowledgeBase constructKnowledgeBase(string const& _source)
45+
{
46+
ErrorList errorList;
47+
shared_ptr<Object> object;
48+
shared_ptr<AsmAnalysisInfo> analysisInfo;
49+
std::tie(object, analysisInfo) = yul::test::parse(_source, m_dialect, errorList);
50+
BOOST_REQUIRE(object && errorList.empty() && object->code);
51+
52+
SSAValueTracker ssaValues;
53+
ssaValues(*object->code);
54+
for (auto const& [name, expression]: ssaValues.values())
55+
m_values[name].value = expression;
56+
57+
return KnowledgeBase(m_dialect, m_values);
58+
}
59+
60+
EVMDialect m_dialect{EVMVersion{}, true};
61+
map<YulString, AssignedValue> m_values;
62+
};
63+
64+
BOOST_FIXTURE_TEST_SUITE(KnowledgeBase, KnowledgeBaseTest)
65+
66+
BOOST_AUTO_TEST_CASE(basic)
67+
{
68+
yul::KnowledgeBase kb = constructKnowledgeBase(R"({
69+
let a := calldataload(0)
70+
let b := calldataload(0)
71+
let zero := 0
72+
let c := add(b, 0)
73+
let d := mul(b, 0)
74+
let e := sub(a, b)
75+
})");
76+
77+
BOOST_CHECK(!kb.knownToBeDifferent("a"_yulstring, "b"_yulstring));
78+
BOOST_CHECK(kb.valueIfKnownConstant("zero"_yulstring) == u256(0));
79+
80+
}
81+
82+
BOOST_AUTO_TEST_SUITE_END()
83+
84+
}

0 commit comments

Comments
 (0)