/src/solidity/libyul/optimiser/KnowledgeBase.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** |
19 | | * Class that can answer questions about values of variables and their relations. |
20 | | */ |
21 | | |
22 | | #include <libyul/optimiser/KnowledgeBase.h> |
23 | | |
24 | | #include <libyul/AST.h> |
25 | | #include <libyul/Utilities.h> |
26 | | #include <libyul/optimiser/SimplificationRules.h> |
27 | | #include <libyul/optimiser/DataFlowAnalyzer.h> |
28 | | |
29 | | #include <libsolutil/CommonData.h> |
30 | | |
31 | | #include <variant> |
32 | | |
33 | | using namespace std; |
34 | | using namespace solidity; |
35 | | using namespace solidity::yul; |
36 | | |
37 | | bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b) |
38 | 0 | { |
39 | | // Try to use the simplification rules together with the |
40 | | // current values to turn `sub(_a, _b)` into a nonzero constant. |
41 | | // If that fails, try `eq(_a, _b)`. |
42 | |
|
43 | 0 | if (optional<u256> difference = differenceIfKnownConstant(_a, _b)) |
44 | 0 | return difference != 0; |
45 | | |
46 | 0 | Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, util::make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})}); |
47 | 0 | if (holds_alternative<Literal>(expr2)) |
48 | 0 | return valueOfLiteral(std::get<Literal>(expr2)) == 0; |
49 | | |
50 | 0 | return false; |
51 | 0 | } |
52 | | |
53 | | optional<u256> KnowledgeBase::differenceIfKnownConstant(YulString _a, YulString _b) |
54 | 0 | { |
55 | | // Try to use the simplification rules together with the |
56 | | // current values to turn `sub(_a, _b)` into a constant. |
57 | |
|
58 | 0 | Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, util::make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})}); |
59 | 0 | if (Literal const* value = get_if<Literal>(&expr1)) |
60 | 0 | return valueOfLiteral(*value); |
61 | | |
62 | 0 | return {}; |
63 | 0 | } |
64 | | |
65 | | bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b) |
66 | 0 | { |
67 | | // Try to use the simplification rules together with the |
68 | | // current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32. |
69 | |
|
70 | 0 | if (optional<u256> difference = differenceIfKnownConstant(_a, _b)) |
71 | 0 | return difference >= 32 && difference <= u256(0) - 32; |
72 | | |
73 | 0 | return false; |
74 | 0 | } |
75 | | |
76 | | bool KnowledgeBase::knownToBeZero(YulString _a) |
77 | 0 | { |
78 | 0 | return valueIfKnownConstant(_a) == u256{}; |
79 | 0 | } |
80 | | |
81 | | optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a) |
82 | 0 | { |
83 | 0 | if (AssignedValue const* value = m_variableValues(_a)) |
84 | 0 | if (Literal const* literal = get_if<Literal>(value->value)) |
85 | 0 | return valueOfLiteral(*literal); |
86 | 0 | return {}; |
87 | 0 | } |
88 | | |
89 | | Expression KnowledgeBase::simplify(Expression _expression) |
90 | 0 | { |
91 | 0 | m_counter = 0; |
92 | 0 | return simplifyRecursively(move(_expression)); |
93 | 0 | } |
94 | | |
95 | | Expression KnowledgeBase::simplifyRecursively(Expression _expression) |
96 | 0 | { |
97 | 0 | if (m_counter++ > 100) |
98 | 0 | return _expression; |
99 | | |
100 | 0 | if (holds_alternative<FunctionCall>(_expression)) |
101 | 0 | for (Expression& arg: std::get<FunctionCall>(_expression).arguments) |
102 | 0 | arg = simplifyRecursively(arg); |
103 | |
|
104 | 0 | if (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_variableValues)) |
105 | 0 | return simplifyRecursively(match->action().toExpression(debugDataOf(_expression))); |
106 | | |
107 | 0 | return _expression; |
108 | 0 | } |