/* 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 dev; using namespace yul; namespace { ExpressionStatement makePopExpressionStatement(langutil::SourceLocation const& _location, Expression&& _expression) { return {_location, FunctionalInstruction{ _location, solidity::Instruction::POP, {std::move(_expression)} }}; } } void StructuralSimplifier::operator()(Block& _block) { pushScope(false); simplify(_block.statements); popScope(); } boost::optional StructuralSimplifier::hasLiteralValue(Expression const& _expression) const { Expression const* expr = &_expression; if (expr->type() == typeid(Identifier)) { Identifier const& ident = boost::get(*expr); if (m_value.count(ident.name)) expr = m_value.at(ident.name); } if (expr && expr->type() == typeid(Literal)) { Literal const& literal = boost::get(*expr); return valueOfLiteral(literal); } return boost::optional(); } void StructuralSimplifier::simplify(std::vector& _statements) { using OptionalStatements = boost::optional>; GenericFallbackReturnsVisitor const visitor( [&](If& _ifStmt) -> OptionalStatements { if (_ifStmt.body.statements.empty()) { OptionalStatements s = vector{}; s->emplace_back(makePopExpressionStatement(_ifStmt.location, std::move(*_ifStmt.condition))); return s; } if (expressionAlwaysTrue(*_ifStmt.condition)) return {std::move(_ifStmt.body.statements)}; else if (expressionAlwaysFalse(*_ifStmt.condition)) return {vector{}}; return {}; }, [&](Switch& _switchStmt) -> OptionalStatements { auto& cases = _switchStmt.cases; if (cases.size() == 1) { auto& switchCase = cases.front(); auto loc = locationOf(*_switchStmt.expression); if (switchCase.value) { OptionalStatements s = vector{}; s->emplace_back(If{ std::move(_switchStmt.location), make_unique(FunctionalInstruction{ std::move(loc), solidity::Instruction::EQ, {std::move(*switchCase.value), std::move(*_switchStmt.expression)} }), std::move(switchCase.body)}); return s; } else { OptionalStatements s = vector{}; s->emplace_back(makePopExpressionStatement(loc, std::move(*_switchStmt.expression))); s->emplace_back(std::move(switchCase.body)); return s; } } // Replace the whole switch with the resulting case body if arg. is // a constant else if (boost::optional const constExprVal = hasLiteralValue(*_switchStmt.expression)) { Block* matchingCaseBlock = nullptr; Case* defaultCase = nullptr; for (auto& _case: cases) { if (_case.value && valueOfLiteral(*_case.value) == constExprVal) { matchingCaseBlock = &_case.body; break; } else if (!_case.value) defaultCase = &_case; } if (!matchingCaseBlock && defaultCase) matchingCaseBlock = &defaultCase->body; OptionalStatements s = vector{}; if (matchingCaseBlock) s->emplace_back(std::move(*matchingCaseBlock)); return s; } // Remove cases with empty body if no default case exists auto const defaultCase = boost::find_if( cases, [](Case const& _case) { return !_case.value; }); if ( (defaultCase != cases.end() && defaultCase->body.statements.empty()) || defaultCase == cases.end() ) boost::remove_erase_if( cases, [](Case const& _case) { return _case.body.statements.empty(); } ); return {}; }, [&](ForLoop& _forLoop) -> OptionalStatements { if (expressionAlwaysFalse(*_forLoop.condition)) return {std::move(_forLoop.pre.statements)}; else return {}; } ); iterateReplacing( _statements, [&](Statement& _stmt) -> OptionalStatements { visit(_stmt); OptionalStatements result = boost::apply_visitor(visitor, _stmt); if (result) simplify(*result); return result; } ); } bool StructuralSimplifier::expressionAlwaysTrue(Expression const& _expression) { return boost::apply_visitor(GenericFallbackReturnsVisitor( [&](Identifier const& _identifier) -> bool { if (auto expr = m_value[_identifier.name]) return expressionAlwaysTrue(*expr); return false; }, [](Literal const& _literal) -> bool { static YulString const trueString("true"); return (_literal.kind == LiteralKind::Boolean && _literal.value == trueString) || (_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) != u256(0)) ; } ), _expression); } bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression) { return boost::apply_visitor(GenericFallbackReturnsVisitor( [&](Identifier const& _identifier) -> bool { if (auto expr = m_value[_identifier.name]) return expressionAlwaysFalse(*expr); return false; }, [](Literal const& _literal) -> bool { static YulString const falseString("false"); return (_literal.kind == LiteralKind::Boolean && _literal.value == falseString) || (_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) == u256(0)) ; } ), _expression); }