/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 #include #include #include #include #include using namespace std; using namespace solidity; using namespace solidity::yul; void SSAReverser::run(OptimiserStepContext&, Block& _block) { AssignmentCounter assignmentCounter; assignmentCounter(_block); SSAReverser{assignmentCounter}(_block); } void SSAReverser::operator()(Block& _block) { walkVector(_block.statements); util::iterateReplacingWindow<2>( _block.statements, [&](Statement& _stmt1, Statement& _stmt2) -> std::optional> { auto* varDecl = std::get_if(&_stmt1); if (!varDecl || varDecl->variables.size() != 1 || !varDecl->value) return {}; // Replaces // let a_1 := E // a := a_1 // with // a := E // let a_1 := a if (auto* assignment = std::get_if(&_stmt2)) { auto* identifier = std::get_if(assignment->value.get()); if ( assignment->variableNames.size() == 1 && identifier && identifier->name == varDecl->variables.front().name ) { // in the special case a == a_1, just remove the assignment if (assignment->variableNames.front().name == identifier->name) return util::make_vector(std::move(_stmt1)); else return util::make_vector( Assignment{ std::move(assignment->debugData), assignment->variableNames, std::move(varDecl->value) }, VariableDeclaration{ std::move(varDecl->debugData), std::move(varDecl->variables), std::make_unique(assignment->variableNames.front()) } ); } } // Replaces // let a_1 := E // let a := a_1 // with // let a := E // let a_1 := a else if (auto* varDecl2 = std::get_if(&_stmt2)) { auto* identifier = std::get_if(varDecl2->value.get()); if ( varDecl2->variables.size() == 1 && identifier && identifier->name == varDecl->variables.front().name && ( m_assignmentCounter.assignmentCount(varDecl2->variables.front().name) > m_assignmentCounter.assignmentCount(varDecl->variables.front().name) ) ) { auto varIdentifier2 = std::make_unique(Identifier{ varDecl2->variables.front().debugData, varDecl2->variables.front().name }); return util::make_vector( VariableDeclaration{ std::move(varDecl2->debugData), std::move(varDecl2->variables), std::move(varDecl->value) }, VariableDeclaration{ std::move(varDecl->debugData), std::move(varDecl->variables), std::move(varIdentifier2) } ); } } return {}; } ); }