From dab68e62545ed2d4d4f7f27de6fa4b05dd0b836a Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 6 Jan 2021 20:21:42 +0100 Subject: [PATCH] Prototype of a full SSA transformation. --- libyul/CMakeLists.txt | 4 + libyul/backends/evm/EVMDialect.cpp | 32 ++ libyul/optimiser/DataFlowAnalyzer.cpp | 2 +- libyul/optimiser/FullSSAReverse.cpp | 134 ++++++++ libyul/optimiser/FullSSAReverse.h | 52 +++ libyul/optimiser/FullSSATransform.cpp | 300 ++++++++++++++++++ libyul/optimiser/FullSSATransform.h | 59 ++++ libyul/optimiser/NameCollector.cpp | 12 + libyul/optimiser/NameCollector.h | 1 + .../optimiser/RedundantAssignEliminator.cpp | 14 +- libyul/optimiser/Suite.cpp | 6 + test/libyul/YulOptimizerTest.cpp | 34 ++ .../yulOptimizerTests/fullSSAReverse/load.yul | 13 + .../fullSSAReverse/store.yul | 13 + .../fullSSATransform/for.yul | 28 ++ .../fullSSATransform/for_break_continue.yul | 40 +++ .../fullSSATransform/for_increment.yul | 36 +++ .../fullSSATransform/for_nested.yul | 41 +++ .../fullSSATransform/function.yul | 25 ++ .../fullSSATransform/function_with_loop.yul | 48 +++ .../function_with_loop_and_leave.yul | 56 ++++ .../yulOptimizerTests/fullSSATransform/if.yul | 21 ++ .../fullSSATransform/if_resolve.yul | 19 ++ .../fullSSATransform/if_twice.yul | 31 ++ .../fullSSATransform/plain_reassign.yul | 13 + .../fullSSATransform/switch.yul | 35 ++ .../yulOptimizerTests/fullSSAandBack/for.yul | 16 + .../fullSSAandBack/for_break_continue.yul | 31 ++ .../fullSSAandBack/for_nested.yul | 23 ++ .../fullSSAandBack/function.yul | 22 ++ .../fullSSAandBack/function_with_loop.yul | 24 ++ .../function_with_loop_and_leave.yul | 35 ++ .../yulOptimizerTests/fullSSAandBack/if.yul | 15 + .../fullSSAandBack/if_twice.yul | 20 ++ .../fullSSAandBack/plain_reassign.yul | 9 + test/yulPhaser/Chromosome.cpp | 2 +- 36 files changed, 1263 insertions(+), 3 deletions(-) create mode 100644 libyul/optimiser/FullSSAReverse.cpp create mode 100644 libyul/optimiser/FullSSAReverse.h create mode 100644 libyul/optimiser/FullSSATransform.cpp create mode 100644 libyul/optimiser/FullSSATransform.h create mode 100644 test/libyul/yulOptimizerTests/fullSSAReverse/load.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAReverse/store.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/for.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/for_break_continue.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/for_increment.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/for_nested.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/function.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop_and_leave.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/if.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/if_resolve.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/if_twice.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/plain_reassign.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSATransform/switch.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/for.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/for_break_continue.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/for_nested.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/function.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop_and_leave.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/if.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/if_twice.yul create mode 100644 test/libyul/yulOptimizerTests/fullSSAandBack/plain_reassign.yul diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index df7f087e1..7a2e27689 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -125,6 +125,10 @@ add_library(yul optimiser/ForLoopInitRewriter.h optimiser/FullInliner.cpp optimiser/FullInliner.h + optimiser/FullSSAReverse.cpp + optimiser/FullSSAReverse.h + optimiser/FullSSATransform.cpp + optimiser/FullSSATransform.h optimiser/FunctionCallFinder.cpp optimiser/FunctionCallFinder.h optimiser/FunctionGrouper.cpp diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index ad8ff2634..a93cd2ccf 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -150,6 +150,38 @@ map createBuiltins(langutil::EVMVersion _evmVe builtins.emplace(createEVMFunction(name, opcode)); } + builtins.emplace(createFunction( + "phi_store", + 2, + 0, + SideEffects{false, false, false, false, true, SideEffects::None, SideEffects::None, SideEffects::None}, + {LiteralKind::String, nullopt}, + []( + FunctionCall const&, + AbstractAssembly&, + BuiltinContext&, + std::function + ) { + yulAssert(false, "leftover phi_store"); + } + )); + + builtins.emplace(createFunction( + "phi_load", + 1, + 1, + SideEffects{}, + {LiteralKind::String}, + []( + FunctionCall const&, + AbstractAssembly&, + BuiltinContext&, + std::function + ) { + yulAssert(false, "leftover phi_load"); + } + )); + if (_objectAccess) { builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, []( diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index b845d2722..1bdbb4ff2 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -1,4 +1,4 @@ -/*( +/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify diff --git a/libyul/optimiser/FullSSAReverse.cpp b/libyul/optimiser/FullSSAReverse.cpp new file mode 100644 index 000000000..7d383ddd5 --- /dev/null +++ b/libyul/optimiser/FullSSAReverse.cpp @@ -0,0 +1,134 @@ +/* + 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); +} diff --git a/libyul/optimiser/FullSSAReverse.h b/libyul/optimiser/FullSSAReverse.h new file mode 100644 index 000000000..1b01b46e9 --- /dev/null +++ b/libyul/optimiser/FullSSAReverse.h @@ -0,0 +1,52 @@ +/* + 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 + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace solidity::yul +{ +struct Dialect; + +class FullSSAReverse: public ASTModifier +{ +public: + static constexpr char const* name{"FullSSAReverse"}; + static void run(OptimiserStepContext& _context, Block& _ast); + using ASTModifier::operator(); + void operator()(Block& _block) override; + void operator()(FunctionDefinition& _funDef) override; +private: + FullSSAReverse(NameDispenser& _nameDispenser): m_nameDispenser(_nameDispenser) {} + NameDispenser& m_nameDispenser; + std::map m_variableNames; + std::set m_currentFunctionReturns; +}; + +} diff --git a/libyul/optimiser/FullSSATransform.cpp b/libyul/optimiser/FullSSATransform.cpp new file mode 100644 index 000000000..8e04ec911 --- /dev/null +++ b/libyul/optimiser/FullSSATransform.cpp @@ -0,0 +1,300 @@ +/* + 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 + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::yul; + +void FullSSATransform::run(OptimiserStepContext& _context, Block& _ast) +{ + FullSSATransform transform{_context}; + transform(_ast); +} + +FullSSATransform::FullSSATransform(OptimiserStepContext& _context): m_nameDispenser(_context.dispenser) +{ +} + +void FullSSATransform::operator()(VariableDeclaration& _varDecl) +{ + ASTModifier::operator()(_varDecl); + for (auto const& _var: _varDecl.variables) + { + yulAssert(!m_currentSSANames.count(_var.name), ""); + m_currentSSANames[_var.name] = _var.name; + } +} + +void FullSSATransform::operator()(Identifier& _identifier) +{ + yulAssert(m_currentSSANames.count(_identifier.name), ""); + _identifier.name = m_currentSSANames[_identifier.name]; +} + +void FullSSATransform::operator()(FunctionDefinition& _functionDefinition) +{ + vector oldFunctionReturnVariables; + swap(oldFunctionReturnVariables, m_currentFunctionReturnVariables); + + for (auto const& var: _functionDefinition.returnVariables) + m_currentFunctionReturnVariables.emplace_back(var.name); + + for (auto const& argument: _functionDefinition.parameters + _functionDefinition.returnVariables) + { + yulAssert(!m_currentSSANames.count(argument.name), ""); + m_currentSSANames[argument.name] = argument.name; + } + + (*this)(_functionDefinition.body); + + for (auto const& var: _functionDefinition.returnVariables) + _functionDefinition.body.statements.emplace_back(makePhiStore(var.name, m_currentSSANames[var.name])); + + swap(m_currentFunctionReturnVariables, oldFunctionReturnVariables); +} + +Statement FullSSATransform::makePhiStore(YulString _var, YulString _value) +{ + return ExpressionStatement{ + langutil::SourceLocation{}, // TODO + FunctionCall{ + langutil::SourceLocation{}, // TODO + Identifier{ + langutil::SourceLocation{}, + YulString{"phi_store"} + }, + { + Literal{ + langutil::SourceLocation{}, // TODO + LiteralKind::String, + _var, + YulString{} // TODO + }, + Identifier{ + langutil::SourceLocation{}, // TODO + _value + } + } + } + }; +} + +Expression FullSSATransform::makePhiLoad(YulString _var) +{ + return FunctionCall{ + langutil::SourceLocation{}, // TODO + Identifier{ + langutil::SourceLocation{}, + YulString{"phi_load"} + }, + { + Literal{ + langutil::SourceLocation{}, // TODO + LiteralKind::String, + _var, + YulString{} // TODO + } + } + }; +} + +void FullSSATransform::operator()(Block& _block) +{ + auto addReloads = [&](map const& _variables, vector& _statements) { + for (auto [origName, oldName]: _variables) + { + YulString newName = m_nameDispenser.newName(origName); + _statements.emplace_back( + VariableDeclaration{ + langutil::SourceLocation{}, + {TypedName{langutil::SourceLocation{}, newName, YulString{}}}, + make_unique(makePhiLoad(oldName)) + } + ); + m_currentSSANames[origName] = newName; + } + }; + auto saveAssignedVariables = [&](auto const& _names, vector& _result) { + map storedNames; + for (YulString var: _names) + if (m_currentSSANames.count(var)) + { + YulString currentName = m_currentSSANames[var]; + _result.emplace_back(makePhiStore(currentName, currentName)); + storedNames[var] = currentName; + } + return storedNames; + }; + auto restoreAssignedVariables = [&](map const& _storedNames, vector& _result) { + for (auto [origName, oldName]: _storedNames) + { + yulAssert(m_currentSSANames.count(origName), ""); + YulString currentName = m_currentSSANames[origName]; + _result.emplace_back(makePhiStore(oldName, currentName)); + } + }; + + using OptionalStatements = optional>; + util::iterateReplacing( + _block.statements, + [&](Statement& _stmt) -> OptionalStatements + { + return std::visit(util::GenericVisitor{ + [&](Assignment& _assignment) -> OptionalStatements { + visit(*_assignment.value); + vector result; + VariableDeclaration varDecl{ + _assignment.location, + {}, + std::move(_assignment.value) + }; + for (auto& var: _assignment.variableNames) + { + yulAssert(m_currentSSANames.count(var.name), ""); + YulString newName = m_nameDispenser.newName(var.name); + varDecl.variables.emplace_back(TypedName{ + var.location, + newName, + YulString{} + }); + m_currentSSANames[var.name] = newName; + } + result.emplace_back(move(varDecl)); + return result; + }, + [&](If& _if) -> OptionalStatements { + Assignments assignments; + assignments(_if); + vector result; + auto storedAssignedVariables = saveAssignedVariables(assignments.names(), result); + + (*this)(_if); + restoreAssignedVariables(storedAssignedVariables, _if.body.statements); + result.emplace_back(std::move(_if)); + + addReloads(storedAssignedVariables, result); + return result; + }, + [&](Switch& _switch) -> OptionalStatements { + Assignments assignments; + assignments(_switch); + vector result; + auto storedAssignedVariables = saveAssignedVariables(assignments.names(), result); + + visit(*_switch.expression); + auto saved = m_currentSSANames; + for (auto& switchCase: _switch.cases) + { + m_currentSSANames = saved; + if (switchCase.value) + (*this)(*switchCase.value); + (*this)(switchCase.body); + restoreAssignedVariables(storedAssignedVariables, switchCase.body.statements); + } + result.emplace_back(std::move(_switch)); + + addReloads(storedAssignedVariables, result); + return result; + }, + [&](ForLoop& _loop) -> OptionalStatements { + yulAssert(_loop.pre.statements.empty(), ""); + std::map oldLoopAssignments; + swap(oldLoopAssignments, m_currentLoopAssignments); + Assignments assignments; + assignments(_loop); + + vector result; + + if (auto* identifier = std::get_if(_loop.condition.get())) + { + if (assignments.names().count(identifier->name)) + { + yulAssert(m_currentSSANames.count(identifier->name), ""); + _loop.condition = make_unique(makePhiLoad(m_currentSSANames[identifier->name])); + } + } + else + yulAssert(holds_alternative(*_loop.condition), "for loop into body required"); + + m_currentLoopAssignments = saveAssignedVariables(assignments.names(), result); + + vector newBody; + addReloads(m_currentLoopAssignments, newBody); + + (*this)(_loop.body); + + newBody += std::move(_loop.body.statements); + _loop.body.statements = std::move(newBody); + + restoreAssignedVariables(m_currentLoopAssignments, _loop.body.statements); + + vector newPost; + addReloads(m_currentLoopAssignments, newPost); + + (*this)(_loop.post); + + restoreAssignedVariables(m_currentLoopAssignments, _loop.post.statements); + + newPost += std::move(_loop.post.statements); + _loop.post.statements = std::move(newPost); + + result.emplace_back(move(_loop)); + + addReloads(m_currentLoopAssignments, result); + + swap(m_currentLoopAssignments, oldLoopAssignments); + return result; + }, + [&](Continue& _continue) -> OptionalStatements { + vector result; + restoreAssignedVariables(m_currentLoopAssignments, result); + result.emplace_back(std::move(_continue)); + return result; + }, + [&](Break& _break) -> OptionalStatements { + vector result; + restoreAssignedVariables(m_currentLoopAssignments, result); + result.emplace_back(std::move(_break)); + return result; + }, + [&](Leave& _leaveStatement) -> OptionalStatements { + vector result; + for (YulString var: m_currentFunctionReturnVariables) + { + yulAssert(m_currentSSANames.count(var), ""); + result.emplace_back(makePhiStore(var, m_currentSSANames[var])); + } + result.emplace_back(std::move(_leaveStatement)); + return result; + }, + [&](auto& _stmt) -> OptionalStatements { (*this)(_stmt); return std::nullopt; } + }, _stmt); + } + ); +} diff --git a/libyul/optimiser/FullSSATransform.h b/libyul/optimiser/FullSSATransform.h new file mode 100644 index 000000000..7d34bf846 --- /dev/null +++ b/libyul/optimiser/FullSSATransform.h @@ -0,0 +1,59 @@ +/* + 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 + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace solidity::yul +{ +struct Dialect; + +class FullSSATransform: public ASTModifier +{ +public: + static constexpr char const* name{"FullSSATransform"}; + static void run(OptimiserStepContext& _context, Block& _ast); + explicit FullSSATransform(OptimiserStepContext& _context); + + using ASTModifier::operator(); + void operator()(VariableDeclaration& _varDecl) override; + void operator()(Identifier& _varDecl) override; + void operator()(FunctionDefinition& _functionDefinition) override; + void operator()(Block& _block) override; +private: + std::map m_currentSSANames; + NameDispenser& m_nameDispenser; + std::vector m_currentFunctionReturnVariables; + std::map m_currentLoopAssignments; + + static Statement makePhiStore(YulString _var, YulString _value); + static Expression makePhiLoad(YulString _var); +}; + +} diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp index bc0fccda4..6ea6c1dd7 100644 --- a/libyul/optimiser/NameCollector.cpp +++ b/libyul/optimiser/NameCollector.cpp @@ -44,6 +44,18 @@ void NameCollector::operator ()(FunctionDefinition const& _funDef) ASTWalker::operator ()(_funDef); } +void NameCollector::operator()(FunctionCall const& _funCall) +{ + if (_funCall.functionName.name == "phi_store"_yulstring || _funCall.functionName.name == "phi_load"_yulstring) + { + yulAssert(!_funCall.arguments.empty(), ""); + auto const* literal = std::get_if(&_funCall.arguments.front()); + yulAssert(literal && literal->kind == LiteralKind::String, ""); + m_names.emplace(literal->value); + } + ASTWalker::operator ()(_funCall); +} + void ReferencesCounter::operator()(Identifier const& _identifier) { ++m_references[_identifier.name]; diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h index 0bedab3f8..aed283886 100644 --- a/libyul/optimiser/NameCollector.h +++ b/libyul/optimiser/NameCollector.h @@ -43,6 +43,7 @@ public: using ASTWalker::operator (); void operator()(VariableDeclaration const& _varDecl) override; void operator()(FunctionDefinition const& _funDef) override; + void operator()(FunctionCall const& _funCall) override; std::set names() const { return m_names; } private: diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index cd528aedf..bd4cd542f 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -308,7 +308,19 @@ void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEli void AssignmentRemover::operator()(Block& _block) { boost::range::remove_erase_if(_block.statements, [&](Statement const& _statement) -> bool { - return holds_alternative(_statement) && m_toRemove.count(&std::get(_statement)); + if (auto const* assignment = std::get_if(&_statement)) + { + if (m_toRemove.count(assignment)) + return true; + // TODO: hack to generally get rid of assignments like a := a + if (assignment->variableNames.size() == 1) + { + if (auto const* identifier = std::get_if(assignment->value.get())) + if (identifier->name == assignment->variableNames.front().name) + return true; + } + } + return false; }); ASTModifier::operator()(_block); diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 3f59e89e6..54903bff0 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -190,6 +192,8 @@ map> const& OptimiserSuite::allSteps() ForLoopConditionOutOfBody, ForLoopInitRewriter, FullInliner, + FullSSAReverse, + FullSSATransform, FunctionGrouper, FunctionHoister, LiteralRematerialiser, @@ -229,6 +233,8 @@ map const& OptimiserSuite::stepNameToAbbreviationMap() {ForLoopConditionOutOfBody::name, 'O'}, {ForLoopInitRewriter::name, 'o'}, {FullInliner::name, 'i'}, + {FullSSAReverse::name, 'Z'}, + {FullSSATransform::name, 'z'}, {FunctionGrouper::name, 'g'}, {FunctionHoister::name, 'h'}, {LiteralRematerialiser::name, 'T'}, diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 9a8a32836..d3a819a54 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -168,6 +170,38 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line disambiguate(); ForLoopInitRewriter::run(*m_context, *m_object->code); } + else if (m_optimizerStep == "fullSSATransform") + { + disambiguate(); + ForLoopInitRewriter::run(*m_context, *m_object->code); + ForLoopConditionIntoBody::run(*m_context, *m_object->code); + FullSSATransform::run(*m_context, *m_object->code); + } + else if (m_optimizerStep == "fullSSAReverse") + { + disambiguate(); + FullSSAReverse::run(*m_context, *m_object->code); + ForLoopConditionOutOfBody::run(*m_context, *m_object->code); + } + else if (m_optimizerStep == "fullSSAandBack") + { + disambiguate(); + ForLoopInitRewriter::run(*m_context, *m_object->code); + ForLoopConditionIntoBody::run(*m_context, *m_object->code); + FullSSATransform::run(*m_context, *m_object->code); + + UnusedPruner::run(*m_context, *m_object->code); + + FullSSAReverse::run(*m_context, *m_object->code); + + RedundantAssignEliminator::run(*m_context, *m_object->code); + CommonSubexpressionEliminator::run(*m_context, *m_object->code); + Rematerialiser::run(*m_context, *m_object->code); + UnusedPruner::run(*m_context, *m_object->code); + RedundantAssignEliminator::run(*m_context, *m_object->code); + + ForLoopConditionOutOfBody::run(*m_context, *m_object->code); + } else if (m_optimizerStep == "commonSubexpressionEliminator") { disambiguate(); diff --git a/test/libyul/yulOptimizerTests/fullSSAReverse/load.yul b/test/libyul/yulOptimizerTests/fullSSAReverse/load.yul new file mode 100644 index 000000000..735230115 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAReverse/load.yul @@ -0,0 +1,13 @@ +{ + phi_store("a", 23) + let a := 42 + sstore(0, phi_load("a")) +} +// ---- +// step: fullSSAReverse +// +// { +// let a_1 := 23 +// let a := 42 +// sstore(0, a_1) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAReverse/store.yul b/test/libyul/yulOptimizerTests/fullSSAReverse/store.yul new file mode 100644 index 000000000..7cac709fd --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAReverse/store.yul @@ -0,0 +1,13 @@ +{ + phi_store("a", 42) + let b := 0 + phi_store("b", 23) +} +// ---- +// step: fullSSAReverse +// +// { +// let a_1 := 42 +// let b := 0 +// let b_2 := 23 +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/for.yul b/test/libyul/yulOptimizerTests/fullSSATransform/for.yul new file mode 100644 index 000000000..407847f27 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/for.yul @@ -0,0 +1,28 @@ +{ + let a := calldataload(42) + for {} a { sstore(1, a) } { + a := sub(a,1) + } + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := calldataload(42) +// phi_store("a", a) +// for { } +// phi_load("a") +// { +// let a_3 := phi_load("a") +// sstore(1, a_3) +// phi_store("a", a_3) +// } +// { +// let a_1 := phi_load("a") +// let a_2 := sub(a_1, 1) +// phi_store("a", a_2) +// } +// let a_4 := phi_load("a") +// sstore(0, a_4) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/for_break_continue.yul b/test/libyul/yulOptimizerTests/fullSSATransform/for_break_continue.yul new file mode 100644 index 000000000..1f2dbf45d --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/for_break_continue.yul @@ -0,0 +1,40 @@ +{ + let a := calldataload(42) + for {} a { sstore(1, a) } { + a := sub(a,1) + if lt(a,4) { continue } + if eq(a,42) { break } + } + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := calldataload(42) +// phi_store("a", a) +// for { } +// phi_load("a") +// { +// let a_3 := phi_load("a") +// sstore(1, a_3) +// phi_store("a", a_3) +// } +// { +// let a_1 := phi_load("a") +// let a_2 := sub(a_1, 1) +// if lt(a_2, 4) +// { +// phi_store("a", a_2) +// continue +// } +// if eq(a_2, 42) +// { +// phi_store("a", a_2) +// break +// } +// phi_store("a", a_2) +// } +// let a_4 := phi_load("a") +// sstore(0, a_4) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/for_increment.yul b/test/libyul/yulOptimizerTests/fullSSATransform/for_increment.yul new file mode 100644 index 000000000..febb60d26 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/for_increment.yul @@ -0,0 +1,36 @@ +{ + let a := 0 + for {} lt(a, 10) { + // checked increment + if eq(a, sub(0, 1)) { revert(0, 0) } + a := add(a, 1) + } { + sstore(a, 42) + } +} +// ---- +// step: fullSSATransform +// +// { +// let a := 0 +// phi_store("a", a) +// for { } +// true +// { +// let a_2 := phi_load("a") +// if eq(a_2, sub(0, 1)) { revert(0, 0) } +// let a_3 := add(a_2, 1) +// phi_store("a", a_3) +// } +// { +// let a_1 := phi_load("a") +// if iszero(lt(a_1, 10)) +// { +// phi_store("a", a_1) +// break +// } +// sstore(a_1, 42) +// phi_store("a", a_1) +// } +// let a_4 := phi_load("a") +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/for_nested.yul b/test/libyul/yulOptimizerTests/fullSSATransform/for_nested.yul new file mode 100644 index 000000000..72f2fbca7 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/for_nested.yul @@ -0,0 +1,41 @@ +{ + let a := calldataload(42) + for {} a { for {} a { a := sub(a, 1) } { sstore(1, a) }} { + a := sub(a,1) + } + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := calldataload(42) +// phi_store("a", a) +// for { } +// phi_load("a") +// { +// let a_3 := phi_load("a") +// phi_store("a_3", a_3) +// for { } +// phi_load("a_3") +// { +// let a_5 := phi_load("a_3") +// let a_6 := sub(a_5, 1) +// phi_store("a_3", a_6) +// } +// { +// let a_4 := phi_load("a_3") +// sstore(1, a_4) +// phi_store("a_3", a_4) +// } +// let a_7 := phi_load("a_3") +// phi_store("a", a_7) +// } +// { +// let a_1 := phi_load("a") +// let a_2 := sub(a_1, 1) +// phi_store("a", a_2) +// } +// let a_8 := phi_load("a") +// sstore(0, a_8) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/function.yul b/test/libyul/yulOptimizerTests/fullSSATransform/function.yul new file mode 100644 index 000000000..2517d0d17 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/function.yul @@ -0,0 +1,25 @@ +{ + function f(a, b) -> c { + c := calldataload(0) + sstore(0, a) + a := b + sstore(1, b) + c := calldataload(1) + } + sstore(2, f(calldataload(2), calldataload(3))) +} +// ---- +// step: fullSSATransform +// +// { +// function f(a, b) -> c +// { +// let c_1 := calldataload(0) +// sstore(0, a) +// let a_2 := b +// sstore(1, b) +// let c_3 := calldataload(1) +// phi_store("c", c_3) +// } +// sstore(2, f(calldataload(2), calldataload(3))) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop.yul b/test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop.yul new file mode 100644 index 000000000..c6525d3c3 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop.yul @@ -0,0 +1,48 @@ +{ + function f(a, b) -> c { + c := calldataload(0) + for {} gt(a,0) { a := sub(a,b) } { + c := calldataload(a) + } + c := calldataload(c) + } + sstore(2, f(calldataload(2), calldataload(3))) +} +// ---- +// step: fullSSATransform +// +// { +// function f(a, b) -> c +// { +// let c_1 := calldataload(0) +// phi_store("c_1", c_1) +// phi_store("a", a) +// for { } +// true +// { +// let c_5 := phi_load("c_1") +// let a_6 := phi_load("a") +// let a_7 := sub(a_6, b) +// phi_store("c_1", c_5) +// phi_store("a", a_7) +// } +// { +// let c_2 := phi_load("c_1") +// let a_3 := phi_load("a") +// if iszero(gt(a_3, 0)) +// { +// phi_store("c_1", c_2) +// phi_store("a", a_3) +// break +// } +// let c_4 := calldataload(a_3) +// phi_store("c_1", c_4) +// phi_store("a", a_3) +// } +// let c_8 := phi_load("c_1") +// let a_9 := phi_load("a") +// let c_10 := calldataload(c_8) +// phi_store("c", c_10) +// } +// sstore(2, f(calldataload(2), calldataload(3))) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop_and_leave.yul b/test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop_and_leave.yul new file mode 100644 index 000000000..ac3078c0b --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/function_with_loop_and_leave.yul @@ -0,0 +1,56 @@ +{ + function f(a, b) -> c { + c := calldataload(0) + for {} gt(a,0) { a := sub(a,b) } { + c := calldataload(a) + if lt(c, add(b, a)) { + leave + } + } + c := calldataload(c) + } + sstore(2, f(calldataload(2), calldataload(3))) +} +// ---- +// step: fullSSATransform +// +// { +// function f(a, b) -> c +// { +// let c_1 := calldataload(0) +// phi_store("c_1", c_1) +// phi_store("a", a) +// for { } +// true +// { +// let c_5 := phi_load("c_1") +// let a_6 := phi_load("a") +// let a_7 := sub(a_6, b) +// phi_store("c_1", c_5) +// phi_store("a", a_7) +// } +// { +// let c_2 := phi_load("c_1") +// let a_3 := phi_load("a") +// if iszero(gt(a_3, 0)) +// { +// phi_store("c_1", c_2) +// phi_store("a", a_3) +// break +// } +// let c_4 := calldataload(a_3) +// if lt(c_4, add(b, a_3)) +// { +// phi_store("c", c_4) +// leave +// } +// phi_store("c_1", c_4) +// phi_store("a", a_3) +// } +// let c_8 := phi_load("c_1") +// let a_9 := phi_load("a") +// let c_10 := calldataload(c_8) +// phi_store("c", c_10) +// } +// sstore(2, f(calldataload(2), calldataload(3))) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/if.yul b/test/libyul/yulOptimizerTests/fullSSATransform/if.yul new file mode 100644 index 000000000..d8c5d6c0d --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/if.yul @@ -0,0 +1,21 @@ +{ + let a := 1 + if calldataload(42) { + a := 2 + } + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := 1 +// phi_store("a", a) +// if calldataload(42) +// { +// let a_1 := 2 +// phi_store("a", a_1) +// } +// let a_2 := phi_load("a") +// sstore(0, a_2) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/if_resolve.yul b/test/libyul/yulOptimizerTests/fullSSATransform/if_resolve.yul new file mode 100644 index 000000000..98fe42fd0 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/if_resolve.yul @@ -0,0 +1,19 @@ +{ + let a := 42 + if calldataload(42) { a := 23 } + sstore(0, 42) +} +// ---- +// step: fullSSATransform +// +// { +// let a := 42 +// phi_store("a", a) +// if calldataload(42) +// { +// let a_1 := 23 +// phi_store("a", a_1) +// } +// let a_2 := phi_load("a") +// sstore(0, 42) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/if_twice.yul b/test/libyul/yulOptimizerTests/fullSSATransform/if_twice.yul new file mode 100644 index 000000000..48595b7e9 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/if_twice.yul @@ -0,0 +1,31 @@ +{ + let a := 1 + if calldataload(42) { + a := 2 + } + if calldataload(a) { + a := add(a, 4) + } + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := 1 +// phi_store("a", a) +// if calldataload(42) +// { +// let a_1 := 2 +// phi_store("a", a_1) +// } +// let a_2 := phi_load("a") +// phi_store("a_2", a_2) +// if calldataload(a_2) +// { +// let a_3 := add(a_2, 4) +// phi_store("a_2", a_3) +// } +// let a_4 := phi_load("a_2") +// sstore(0, a_4) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/plain_reassign.yul b/test/libyul/yulOptimizerTests/fullSSATransform/plain_reassign.yul new file mode 100644 index 000000000..786d0a95c --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/plain_reassign.yul @@ -0,0 +1,13 @@ +{ + let a := 1 + a := 2 + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := 1 +// let a_1 := 2 +// sstore(0, a_1) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSATransform/switch.yul b/test/libyul/yulOptimizerTests/fullSSATransform/switch.yul new file mode 100644 index 000000000..a9d8c4765 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSATransform/switch.yul @@ -0,0 +1,35 @@ +{ + let a := 1 + switch a + case 1 + { + a := calldataload(1) + } + case 2 + { + a := calldataload(a) + } + default + { + } + sstore(0, a) +} +// ---- +// step: fullSSATransform +// +// { +// let a := 1 +// phi_store("a", a) +// switch a +// case 1 { +// let a_1 := calldataload(1) +// phi_store("a", a_1) +// } +// case 2 { +// let a_2 := calldataload(a) +// phi_store("a", a_2) +// } +// default { phi_store("a", a) } +// let a_3 := phi_load("a") +// sstore(0, a_3) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/for.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/for.yul new file mode 100644 index 000000000..cdb5462bd --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/for.yul @@ -0,0 +1,16 @@ +{ + let a := calldataload(42) + for {} a { sstore(1, a) } { + a := sub(a,1) + } + sstore(0, a) +} +// ---- +// step: fullSSAandBack +// +// { +// let a_5 := calldataload(42) +// for { } a_5 { sstore(1, a_5) } +// { a_5 := sub(a_5, 1) } +// sstore(0, a_5) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/for_break_continue.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/for_break_continue.yul new file mode 100644 index 000000000..108e4cd8a --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/for_break_continue.yul @@ -0,0 +1,31 @@ +{ + let a := calldataload(42) + for {} a { sstore(1, a) } { + a := sub(a,1) + if lt(a,4) { continue } + if eq(a,42) { break } + } + sstore(0, a) +} +// ---- +// step: fullSSAandBack +// +// { +// let a_5 := calldataload(42) +// for { } a_5 { sstore(1, a_5) } +// { +// let a_2 := sub(a_5, 1) +// if lt(a_2, 4) +// { +// a_5 := a_2 +// continue +// } +// if eq(a_2, 42) +// { +// a_5 := a_2 +// break +// } +// a_5 := a_2 +// } +// sstore(0, a_5) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/for_nested.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/for_nested.yul new file mode 100644 index 000000000..2395e2f89 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/for_nested.yul @@ -0,0 +1,23 @@ +{ + let a := calldataload(42) + for {} a { for {} a { a := sub(a, 1) } { sstore(1, a) }} { + a := sub(a,1) + } + sstore(0, a) +} +// ---- +// step: fullSSAandBack +// +// { +// let a_9 := calldataload(42) +// for { } +// a_9 +// { +// let a_3_10 := a_9 +// for { } a_3_10 { a_3_10 := sub(a_3_10, 1) } +// { sstore(1, a_3_10) } +// a_9 := a_3_10 +// } +// { a_9 := sub(a_9, 1) } +// sstore(0, a_9) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/function.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/function.yul new file mode 100644 index 000000000..18a8f089a --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/function.yul @@ -0,0 +1,22 @@ +{ + function f(a, b) -> c { + c := calldataload(0) + sstore(0, a) + a := b + sstore(1, b) + c := calldataload(1) + } + sstore(2, f(calldataload(2), calldataload(3))) +} +// ---- +// step: fullSSAandBack +// +// { +// function f(a, b) -> c_4 +// { +// sstore(0, a) +// sstore(1, b) +// c_4 := calldataload(1) +// } +// sstore(2, f(calldataload(2), calldataload(3))) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop.yul new file mode 100644 index 000000000..ee40e981e --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop.yul @@ -0,0 +1,24 @@ +{ + function f(a, b) -> c { + c := calldataload(0) + for {} gt(a,0) { a := sub(a,b) } { + c := calldataload(a) + } + c := calldataload(c) + } + sstore(2, f(calldataload(2), calldataload(3))) +} +// ---- +// step: fullSSAandBack +// +// { +// function f(a, b) -> c_11 +// { +// let c_1_12 := calldataload(0) +// let a_13 := a +// for { } gt(a_13, c_11) { a_13 := sub(a_13, b) } +// { c_1_12 := calldataload(a_13) } +// c_11 := calldataload(c_1_12) +// } +// sstore(2, f(calldataload(2), calldataload(3))) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop_and_leave.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop_and_leave.yul new file mode 100644 index 000000000..1e8d357df --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/function_with_loop_and_leave.yul @@ -0,0 +1,35 @@ +{ + function f(a, b) -> c { + c := calldataload(0) + for {} gt(a,0) { a := sub(a,b) } { + c := calldataload(a) + if lt(c, add(b, a)) { + leave + } + } + c := calldataload(c) + } + sstore(2, f(calldataload(2), calldataload(3))) +} +// ---- +// step: fullSSAandBack +// +// { +// function f(a, b) -> c_11 +// { +// let c_1_12 := calldataload(0) +// let a_13 := a +// for { } gt(a_13, 0) { a_13 := sub(a_13, b) } +// { +// let c_4 := calldataload(a_13) +// if lt(c_4, add(b, a_13)) +// { +// c_11 := c_4 +// leave +// } +// c_1_12 := c_4 +// } +// c_11 := calldataload(c_1_12) +// } +// sstore(2, f(calldataload(2), calldataload(3))) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/if.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/if.yul new file mode 100644 index 000000000..ef9815fee --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/if.yul @@ -0,0 +1,15 @@ +{ + let a := 1 + if calldataload(42) { + a := 2 + } + sstore(0, a) +} +// ---- +// step: fullSSAandBack +// +// { +// let a_3 := 1 +// if calldataload(42) { a_3 := 2 } +// sstore(0, a_3) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/if_twice.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/if_twice.yul new file mode 100644 index 000000000..bdcab1356 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/if_twice.yul @@ -0,0 +1,20 @@ +{ + let a := 1 + if calldataload(42) { + a := 2 + } + if calldataload(a) { + a := add(a, 4) + } + sstore(0, a) +} +// ---- +// step: fullSSAandBack +// +// { +// let a_5 := 1 +// if calldataload(42) { a_5 := 2 } +// let a_2_6 := a_5 +// if calldataload(a_5) { a_2_6 := add(a_5, 4) } +// sstore(0, a_2_6) +// } diff --git a/test/libyul/yulOptimizerTests/fullSSAandBack/plain_reassign.yul b/test/libyul/yulOptimizerTests/fullSSAandBack/plain_reassign.yul new file mode 100644 index 000000000..3e6dd6c6b --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSSAandBack/plain_reassign.yul @@ -0,0 +1,9 @@ +{ + let a := calldataload(0) + a := calldataload(1) + sstore(0, a) +} +// ---- +// step: fullSSAandBack +// +// { sstore(0, calldataload(1)) } diff --git a/test/yulPhaser/Chromosome.cpp b/test/yulPhaser/Chromosome.cpp index ac4c49055..21bf7e5bb 100644 --- a/test/yulPhaser/Chromosome.cpp +++ b/test/yulPhaser/Chromosome.cpp @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_strin BOOST_TEST(chromosome.length() == allSteps.size()); BOOST_TEST(chromosome.optimisationSteps() == allSteps); - BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoighTLMRrmVatpud"); + BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoiZzghTLMRrmVatpud"); } BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_optimisation_step_names)