/src/solidity/libyul/optimiser/ForLoopConditionOutOfBody.cpp
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 | | #include <libyul/optimiser/ForLoopConditionOutOfBody.h> |
20 | | #include <libyul/optimiser/Semantics.h> |
21 | | #include <libyul/AST.h> |
22 | | #include <libyul/Utilities.h> |
23 | | |
24 | | #include <libsolutil/CommonData.h> |
25 | | |
26 | | using namespace solidity; |
27 | | using namespace solidity::yul; |
28 | | |
29 | | void ForLoopConditionOutOfBody::run(OptimiserStepContext& _context, Block& _ast) |
30 | 311k | { |
31 | 311k | ForLoopConditionOutOfBody{_context.dialect}(_ast); |
32 | 311k | } |
33 | | |
34 | | void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop) |
35 | 916k | { |
36 | 916k | ASTModifier::operator()(_forLoop); |
37 | | |
38 | 916k | if ( |
39 | 916k | !m_dialect.booleanNegationFunctionHandle() || |
40 | 916k | !std::holds_alternative<Literal>(*_forLoop.condition) || |
41 | 916k | std::get<Literal>(*_forLoop.condition).value.value() == 0 || |
42 | 916k | _forLoop.body.statements.empty() || |
43 | 916k | !std::holds_alternative<If>(_forLoop.body.statements.front()) |
44 | 916k | ) |
45 | 826k | return; |
46 | | |
47 | 90.3k | If& firstStatement = std::get<If>(_forLoop.body.statements.front()); |
48 | 90.3k | if ( |
49 | 90.3k | firstStatement.body.statements.empty() || |
50 | 90.3k | !std::holds_alternative<Break>(firstStatement.body.statements.front()) |
51 | 90.3k | ) |
52 | 755 | return; |
53 | 89.5k | if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable()) |
54 | 4.40k | return; |
55 | | |
56 | 85.1k | std::optional<BuiltinHandle> iszero = m_dialect.booleanNegationFunctionHandle(); |
57 | 85.1k | yulAssert(iszero.has_value()); |
58 | 85.1k | auto const& isZeroHandle = *iszero; |
59 | 85.1k | langutil::DebugData::ConstPtr debugData = debugDataOf(*firstStatement.condition); |
60 | | |
61 | 85.1k | if ( |
62 | 85.1k | std::holds_alternative<FunctionCall>(*firstStatement.condition) && |
63 | 85.1k | std::holds_alternative<BuiltinName>(std::get<FunctionCall>(*firstStatement.condition).functionName) && |
64 | 85.1k | std::get<BuiltinName>(std::get<FunctionCall>(*firstStatement.condition).functionName).handle == isZeroHandle |
65 | 85.1k | ) |
66 | 52.0k | _forLoop.condition = std::make_unique<Expression>(std::move(std::get<FunctionCall>(*firstStatement.condition).arguments.front())); |
67 | 33.1k | else |
68 | 33.1k | _forLoop.condition = std::make_unique<Expression>(FunctionCall{ |
69 | 33.1k | debugData, |
70 | 33.1k | BuiltinName{debugData, isZeroHandle}, |
71 | 33.1k | util::make_vector<Expression>( |
72 | 33.1k | std::move(*firstStatement.condition) |
73 | 33.1k | ) |
74 | 33.1k | }); |
75 | | |
76 | 85.1k | _forLoop.body.statements.erase(_forLoop.body.statements.begin()); |
77 | 85.1k | } |
78 | | |