diff options
author | chriseth <chris@ethereum.org> | 2018-10-17 03:40:10 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2018-10-24 23:52:28 +0800 |
commit | 57843f790c48fc653e12a9c4a8e01dc2e41dd56e (patch) | |
tree | ac51ba0c472a1bd1826d26d024ad8c81197f730d /test | |
parent | 01566c2e1af5b7f655fd593e5e1019e103d739a0 (diff) | |
download | dexon-solidity-57843f790c48fc653e12a9c4a8e01dc2e41dd56e.tar.gz dexon-solidity-57843f790c48fc653e12a9c4a8e01dc2e41dd56e.tar.zst dexon-solidity-57843f790c48fc653e12a9c4a8e01dc2e41dd56e.zip |
Interactive optimizer tool.
Diffstat (limited to 'test')
-rw-r--r-- | test/tools/CMakeLists.txt | 3 | ||||
-rw-r--r-- | test/tools/yulopti.cpp | 216 |
2 files changed, 219 insertions, 0 deletions
diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 65054fca..19a1d958 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -1,6 +1,9 @@ add_executable(solfuzzer fuzzer.cpp) target_link_libraries(solfuzzer PRIVATE libsolc evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_SYSTEM_LIBRARIES}) +add_executable(yulopti yulopti.cpp) +target_link_libraries(yulopti PRIVATE solidity ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_SYSTEM_LIBRARIES}) + add_executable(isoltest isoltest.cpp ../Options.cpp ../Common.cpp ../libsolidity/TestCase.cpp ../libsolidity/SyntaxTest.cpp ../libsolidity/AnalysisFramework.cpp ../libsolidity/SolidityExecutionFramework.cpp ../ExecutionFramework.cpp ../RPCSession.cpp ../libsolidity/ASTJSONTest.cpp ../libyul/YulOptimizerTest.cpp) diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp new file mode 100644 index 00000000..34d0f5c9 --- /dev/null +++ b/test/tools/yulopti.cpp @@ -0,0 +1,216 @@ +/* + 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 <http://www.gnu.org/licenses/>. +*/ +/** + * Interactive yul optimizer + */ + +#include <libdevcore/CommonIO.h> +#include <libsolidity/inlineasm/AsmAnalysis.h> +#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libsolidity/parsing/Scanner.h> +#include <libsolidity/parsing/Parser.h> +#include <libsolidity/inlineasm/AsmData.h> +#include <libsolidity/inlineasm/AsmParser.h> +#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libsolidity/interface/SourceReferenceFormatter.h> +#include <libsolidity/interface/ErrorReporter.h> + +#include <libyul/optimiser/BlockFlattener.h> +#include <libyul/optimiser/Disambiguator.h> +#include <libyul/optimiser/CommonSubexpressionEliminator.h> +#include <libyul/optimiser/NameCollector.h> +#include <libyul/optimiser/ExpressionSplitter.h> +#include <libyul/optimiser/FunctionGrouper.h> +#include <libyul/optimiser/FunctionHoister.h> +#include <libyul/optimiser/ExpressionInliner.h> +#include <libyul/optimiser/FullInliner.h> +#include <libyul/optimiser/MainFunction.h> +#include <libyul/optimiser/Rematerialiser.h> +#include <libyul/optimiser/ExpressionSimplifier.h> +#include <libyul/optimiser/UnusedPruner.h> +#include <libyul/optimiser/ExpressionJoiner.h> + +#include <libdevcore/JSON.h> + +#include <boost/program_options.hpp> + +#include <string> +#include <sstream> +#include <iostream> + +using namespace std; +using namespace dev; +using namespace dev::solidity; +using namespace dev::solidity::assembly; +using namespace dev::yul; + +namespace po = boost::program_options; + +class YulOpti +{ +public: + void printErrors(Scanner const& _scanner) + { + SourceReferenceFormatter formatter(cout, [&](string const&) -> Scanner const& { return _scanner; }); + + for (auto const& error: m_errors) + formatter.printExceptionInformation( + *error, + (error->type() == Error::Type::Warning) ? "Warning" : "Error" + ); + } + + bool parse(string const& _input) + { + ErrorReporter errorReporter(m_errors); + shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(_input), ""); + m_ast = assembly::Parser(errorReporter, assembly::AsmFlavour::Strict).parse(scanner, false); + if (!m_ast || !errorReporter.errors().empty()) + { + cout << "Error parsing source." << endl; + printErrors(*scanner); + return false; + } + m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); + AsmAnalyzer analyzer( + *m_analysisInfo, + errorReporter, + EVMVersion::byzantium(), + boost::none, + AsmFlavour::Strict + ); + if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) + { + cout << "Error analyzing source." << endl; + printErrors(*scanner); + return false; + } + return true; + } + + void runInteractive(string source) + { + bool disambiguated = false; + while (true) + { + cout << "----------------------" << endl; + cout << source << endl; + if (!parse(source)) + return; + if (!disambiguated) + { + *m_ast = boost::get<assembly::Block>(Disambiguator(*m_analysisInfo)(*m_ast)); + m_analysisInfo.reset(); + m_nameDispenser = make_shared<NameDispenser>(*m_ast); + disambiguated = true; + } + cout << "(q)quit/(f)flatten/(c)se/(x)plit/(j)oin/(g)rouper/(h)oister/(e)xpr inline/(i)nline/(s)implify/(u)nusedprune? "; + cout.flush(); + int option = readStandardInputChar(); + cout << ' ' << char(option) << endl; + switch (option) + { + case 'q': + return; + case 'f': + BlockFlattener{}(*m_ast); + break; + case 'c': + (CommonSubexpressionEliminator{})(*m_ast); + break; + case 'x': + ExpressionSplitter{*m_nameDispenser}(*m_ast); + break; + case 'j': + ExpressionJoiner::run(*m_ast); + break; + case 'g': + (FunctionGrouper{})(*m_ast); + break; + case 'h': + (FunctionHoister{})(*m_ast); + break; + case 'e': + ExpressionInliner{*m_ast}.run(); + break; + case 'i': + FullInliner(*m_ast, *m_nameDispenser).run(); + break; + case 's': + ExpressionSimplifier::run(*m_ast); + break; + case 'u': + UnusedPruner::runUntilStabilised(*m_ast); + break; + default: + cout << "Unknown option." << endl; + } + source = AsmPrinter{}(*m_ast); + } + } + +private: + ErrorList m_errors; + shared_ptr<assembly::Block> m_ast; + shared_ptr<AsmAnalysisInfo> m_analysisInfo; + shared_ptr<NameDispenser> m_nameDispenser; +}; + +int main(int argc, char** argv) +{ + po::options_description options( + R"(yulopti, yul optimizer exploration tool. +Usage: yulopti [Options] <file> +Reads <file> as yul code and applies optimizer steps to it, +interactively read from stdin. + +Allowed options)", + po::options_description::m_default_line_length, + po::options_description::m_default_line_length - 23); + options.add_options() + ( + "input-file", + po::value<string>(), + "input file" + ) + ("help", "Show this help screen."); + + // All positional options should be interpreted as input files + po::positional_options_description filesPositions; + filesPositions.add("input-file", 1); + + po::variables_map arguments; + try + { + po::command_line_parser cmdLineParser(argc, argv); + cmdLineParser.options(options).positional(filesPositions); + po::store(cmdLineParser.run(), arguments); + } + catch (po::error const& _exception) + { + cerr << _exception.what() << endl; + return 1; + } + + string input; + if (arguments.count("input-file")) + YulOpti{}.runInteractive(readFileAsString(arguments["input-file"].as<string>())); + else + cout << options; + + return 0; +} |