/* 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::yul; class FullSSAReverseLoad: public ASTCopier { public: FullSSAReverseLoad(std::map const& _variableNames): m_variableNames(_variableNames) {} Expression operator()(FunctionCall const& _funCall) override { if (_funCall.functionName.name == "phi_load"_yulstring) { yulAssert(_funCall.arguments.size() == 1, ""); Literal const* literal = std::get_if(&_funCall.arguments.front()); yulAssert(literal && literal->kind == LiteralKind::String, ""); yulAssert(m_variableNames.count(literal->value), ""); return Identifier{ _funCall.location, m_variableNames.at(literal->value) }; } return ASTCopier::operator()(_funCall); } private: map const& m_variableNames; }; void FullSSAReverse::run(OptimiserStepContext& _context, Block& _ast) { FullSSAReverse fullSSAReverse{_context.dispenser}; fullSSAReverse(_ast); _ast = FullSSAReverseLoad{fullSSAReverse.m_variableNames}.translate(_ast); } void FullSSAReverse::operator()(Block& _block) { util::iterateReplacing( _block.statements, [&](Statement& _stmt) -> std::optional> { if (auto* expressionStatement = std::get_if(&_stmt)) if (auto* functionCall = std::get_if(&expressionStatement->expression)) if (functionCall->functionName.name == "phi_store"_yulstring) { yulAssert(functionCall->arguments.size() == 2, ""); Literal const* literal = std::get_if(&functionCall->arguments.front()); yulAssert(literal && literal->kind == LiteralKind::String, ""); vector result; if (m_variableNames.count(literal->value)) result.emplace_back(Assignment{ functionCall->location, {Identifier{literal->location, m_variableNames.at(literal->value)}}, make_unique(move(functionCall->arguments.back())) }); else { YulString newName = m_nameDispenser.newName(literal->value); m_variableNames[literal->value] = newName; result.emplace_back(VariableDeclaration{ functionCall->location, {TypedName{literal->location, newName, YulString{}}}, make_unique(move(functionCall->arguments.back())) }); } return result; } visit(_stmt); return {}; } ); } void FullSSAReverse::operator()(FunctionDefinition& _funDef) { set oldFunctionReturns; swap(m_currentFunctionReturns, oldFunctionReturns); vector bodyPrefix; for (auto& var: _funDef.returnVariables) { YulString newName = m_nameDispenser.newName(var.name); m_variableNames[var.name] = newName; m_currentFunctionReturns.emplace(var.name); bodyPrefix.emplace_back(VariableDeclaration{ var.location, {var}, make_unique(Identifier{var.location, newName}) }); var.name = newName; } bodyPrefix += std::move(_funDef.body.statements); _funDef.body.statements = std::move(bodyPrefix); ASTModifier::operator()(_funDef); swap(m_currentFunctionReturns, oldFunctionReturns); }