Coverage Report

Created: 2022-08-24 06:28

/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
}