/src/solidity/libyul/optimiser/BlockHasher.h
Line | Count | Source |
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 | | * Optimiser component that calculates hash values for blocks. |
20 | | */ |
21 | | #pragma once |
22 | | |
23 | | #include <libyul/optimiser/ASTWalker.h> |
24 | | #include <libyul/ASTForward.h> |
25 | | #include <libyul/YulName.h> |
26 | | |
27 | | namespace solidity::yul |
28 | | { |
29 | | |
30 | | class HasherBase |
31 | | { |
32 | | public: |
33 | | static constexpr uint64_t fnvPrime = 1099511628211u; |
34 | | static constexpr uint64_t fnvEmptyHash = 14695981039346656037u; |
35 | | |
36 | | protected: |
37 | | void hash8(uint8_t _value) |
38 | 5.02G | { |
39 | 5.02G | m_hash *= fnvPrime; |
40 | 5.02G | m_hash ^= _value; |
41 | 5.02G | } |
42 | | void hash16(uint16_t _value) |
43 | 2.46G | { |
44 | 2.46G | hash8(static_cast<uint8_t>(_value & 0xFF)); |
45 | 2.46G | hash8(static_cast<uint8_t>(_value >> 8)); |
46 | 2.46G | } |
47 | | void hash32(uint32_t _value) |
48 | 1.23G | { |
49 | 1.23G | hash16(static_cast<uint16_t>(_value & 0xFFFF)); |
50 | 1.23G | hash16(static_cast<uint16_t>(_value >> 16)); |
51 | 1.23G | } |
52 | | void hash64(uint64_t _value) |
53 | 615M | { |
54 | 615M | hash32(static_cast<uint32_t>(_value & 0xFFFFFFFF)); |
55 | 615M | hash32(static_cast<uint32_t>(_value >> 32)); |
56 | 615M | } |
57 | | |
58 | | uint64_t m_hash = fnvEmptyHash; |
59 | | }; |
60 | | |
61 | | class ASTHasherBase: public HasherBase |
62 | | { |
63 | | protected: |
64 | | void hashLiteral(solidity::yul::Literal const& _literal); |
65 | | void hashFunctionCall(FunctionCall const& _functionCall); |
66 | | }; |
67 | | |
68 | | /** |
69 | | * Optimiser component that calculates hash values for blocks. |
70 | | * Syntactically equal blocks will have identical hashes and |
71 | | * blocks with equal hashes will likely be syntactically equal. |
72 | | * |
73 | | * The names of internally declared variables are replaced by |
74 | | * a simple counter, so differing names are not taken into account, |
75 | | * but only the order of references to declared variables. |
76 | | * |
77 | | * Similarly, the names of referenced external variables are not considered, |
78 | | * but replaced by a (distinct) counter as well. |
79 | | * |
80 | | * Prerequisite: Disambiguator, ForLoopInitRewriter |
81 | | */ |
82 | | class BlockHasher: public ASTWalker, public ASTHasherBase |
83 | | { |
84 | | public: |
85 | | |
86 | | using ASTWalker::operator(); |
87 | | |
88 | | void operator()(Literal const&) override; |
89 | | void operator()(Identifier const&) override; |
90 | | void operator()(FunctionCall const& _funCall) override; |
91 | | void operator()(ExpressionStatement const& _statement) override; |
92 | | void operator()(Assignment const& _assignment) override; |
93 | | void operator()(VariableDeclaration const& _varDecl) override; |
94 | | void operator()(If const& _if) override; |
95 | | void operator()(Switch const& _switch) override; |
96 | | void operator()(FunctionDefinition const&) override; |
97 | | void operator()(ForLoop const&) override; |
98 | | void operator()(Break const&) override; |
99 | | void operator()(Continue const&) override; |
100 | | void operator()(Leave const&) override; |
101 | | void operator()(Block const& _block) override; |
102 | | |
103 | | static std::map<Block const*, uint64_t> run(Block const& _block); |
104 | | |
105 | | |
106 | | private: |
107 | 2.56M | BlockHasher(std::map<Block const*, uint64_t>& _blockHashes): m_blockHashes(_blockHashes) {} |
108 | | |
109 | | std::map<Block const*, uint64_t>& m_blockHashes; |
110 | | |
111 | | struct VariableReference |
112 | | { |
113 | | size_t id = 0; |
114 | | bool isExternal = false; |
115 | | }; |
116 | | std::map<YulName, VariableReference> m_variableReferences; |
117 | | std::vector<YulName> m_externalReferences; |
118 | | size_t m_externalIdentifierCount = 0; |
119 | | size_t m_internalIdentifierCount = 0; |
120 | | }; |
121 | | |
122 | | |
123 | | /** |
124 | | * Computes hashes of expressions that are likely different for syntactically different expressions. |
125 | | * In contrast to the BlockHasher, hashes of identifiers are likely different if the identifiers |
126 | | * have a different name and the same if the name matches. |
127 | | * This means this hasher should only be used on disambiguated sources. |
128 | | */ |
129 | | class ExpressionHasher: public ASTWalker, public ASTHasherBase |
130 | | { |
131 | | public: |
132 | | /// Computes a hash of an expression that (in contrast to the behaviour of the class) |
133 | | /// distinguishes (up to hash collisions) variables with different names. |
134 | | static uint64_t run(Expression const& _e); |
135 | | |
136 | | using ASTWalker::operator(); |
137 | | |
138 | | void operator()(Literal const&) override; |
139 | | void operator()(Identifier const&) override; |
140 | | void operator()(FunctionCall const& _funCall) override; |
141 | | }; |
142 | | |
143 | | struct ExpressionHash |
144 | | { |
145 | | uint64_t operator()(Expression const& _expression) const |
146 | 154M | { |
147 | 154M | return ExpressionHasher::run(_expression); |
148 | 154M | } |
149 | | }; |
150 | | |
151 | | } |