/* 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 /** * Base class for both RedundantAssignEliminator and RedundantStoreEliminator. */ #pragma once #include #include #include #include namespace solidity::yul { struct Dialect; /** * Base class for both RedundantAssignEliminator and RedundantStoreEliminator. * * Prerequisite: Disambiguator, ForLoopInitRewriter. */ class RedundantStoreBase: public ASTWalker { public: explicit RedundantStoreBase(Dialect const& _dialect): m_dialect(_dialect) {} using ASTWalker::operator(); void operator()(If const& _if) override; void operator()(Switch const& _switch) override; void operator()(FunctionDefinition const&) override; void operator()(ForLoop const&) override; void operator()(Break const&) override; void operator()(Continue const&) override; protected: class State { public: enum Value { Unused, Undecided, Used }; State(Value _value = Undecided): m_value(_value) {} inline bool operator==(State _other) const { return m_value == _other.m_value; } inline bool operator!=(State _other) const { return !operator==(_other); } static inline void join(State& _a, State const& _b) { // Using "max" works here because of the order of the values in the enum. _a.m_value = Value(std::max(int(_a.m_value), int(_b.m_value))); } private: Value m_value = Undecided; }; using TrackedStores = std::map>; /// This function is called for a loop that is nested too deep to avoid /// horrible runtime and should just resolve the situation in a pragmatic /// and correct manner. virtual void shortcutNestedLoop(TrackedStores const& _beforeLoop) = 0; /// This function is called right before the scoped restore of the function definition. virtual void finalizeFunctionDefinition(FunctionDefinition const& /*_functionDefinition*/) {} /// Joins the assignment mapping of @a _source into @a _target according to the rules laid out /// above. /// Will destroy @a _source. static void merge(TrackedStores& _target, TrackedStores&& _source); static void merge(TrackedStores& _target, std::vector&& _source); Dialect const& m_dialect; std::set m_pendingRemovals; TrackedStores m_stores; /// Working data for traversing for-loops. struct ForLoopInfo { /// Tracked assignment states for each break statement. std::vector pendingBreakStmts; /// Tracked assignment states for each continue statement. std::vector pendingContinueStmts; }; ForLoopInfo m_forLoopInfo; size_t m_forLoopNestingDepth = 0; }; class StatementRemover: public ASTModifier { public: explicit StatementRemover(std::set const& _toRemove): m_toRemove(_toRemove) {} void operator()(Block& _block) override; private: std::set const& m_toRemove; }; }