diff options
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.cpp | 9 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.h | 3 | ||||
-rw-r--r-- | solc/CommandLineInterface.cpp | 25 | ||||
-rw-r--r-- | solc/CommandLineInterface.h | 2 | ||||
-rwxr-xr-x | test/cmdlineTests.sh | 43 |
6 files changed, 73 insertions, 10 deletions
diff --git a/Changelog.md b/Changelog.md index 7aa5a6be..72d51bff 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Language Features: Compiler Features: * Build System: LLL is not built anymore by default. Must configure it with CMake as `-DLLL=ON`. * Code generator: Do not perform redundant double cleanup on unsigned integers when loading from calldata. + * Commandline interface: Experimental ``--optimize`` option for assembly mode. * SMTChecker: SMTLib2 queries and responses passed via standard JSON compiler interface. * SMTChecker: Support ``msg``, ``tx`` and ``block`` member variables. * SMTChecker: Support ``gasleft()`` and ``blockhash()`` functions. diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp index 66ba42ee..f5eb7e41 100644 --- a/libsolidity/interface/AssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -34,6 +34,8 @@ #include <libevmasm/Assembly.h> +#include <libyul/optimiser/Suite.h> + using namespace std; using namespace dev; using namespace langutil; @@ -79,6 +81,13 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string return analyzeParsed(); } +void AssemblyStack::optimize() +{ + solAssert(m_language != Language::Assembly, "Optimization requested for loose assembly."); + yul::OptimiserSuite::run(*m_parserResult->code, *m_parserResult->analysisInfo); + solAssert(analyzeParsed(), "Invalid source code after optimization."); +} + bool AssemblyStack::analyzeParsed() { solAssert(m_parserResult, ""); diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h index 7ae0592e..0d04ffec 100644 --- a/libsolidity/interface/AssemblyStack.h +++ b/libsolidity/interface/AssemblyStack.h @@ -69,6 +69,9 @@ public: /// Multiple calls overwrite the previous state. bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source); + /// Run the optimizer suite. Can only be used with Yul or strict assembly. + void optimize(); + /// Run the assembly step (should only be called after parseAndAnalyze). MachineAssemblyObject assemble(Machine _machine) const; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e2baca7f..38e778c6 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -626,15 +626,15 @@ Allowed options)", ) ( g_argAssemble.c_str(), - "Switch to assembly mode, ignoring all options except --machine and assumes input is assembly." + "Switch to assembly mode, ignoring all options except --machine and --optimize and assumes input is assembly." ) ( g_argYul.c_str(), - "Switch to Yul mode, ignoring all options except --machine and assumes input is Yul." + "Switch to Yul mode, ignoring all options except --machine and --optimize and assumes input is Yul." ) ( g_argStrictAssembly.c_str(), - "Switch to strict assembly mode, ignoring all options except --machine and assumes input is strict assembly." + "Switch to strict assembly mode, ignoring all options except --machine and --optimize and assumes input is strict assembly." ) ( g_argMachine.c_str(), @@ -820,6 +820,7 @@ bool CommandLineInterface::processInput() using Machine = AssemblyStack::Machine; Input inputLanguage = m_args.count(g_argYul) ? Input::Yul : (m_args.count(g_argStrictAssembly) ? Input::StrictAssembly : Input::Assembly); Machine targetMachine = Machine::EVM; + bool optimize = m_args.count(g_argOptimize); if (m_args.count(g_argMachine)) { string machine = m_args[g_argMachine].as<string>(); @@ -835,7 +836,18 @@ bool CommandLineInterface::processInput() return false; } } - return assemble(inputLanguage, targetMachine); + if (optimize && inputLanguage == Input::Assembly) + { + serr() << + "Optimizer cannot be used for loose assembly. Use --" << + g_strStrictAssembly << + " or --" << + g_strYul << + "." << + endl; + return false; + } + return assemble(inputLanguage, targetMachine, optimize); } if (m_args.count(g_argLink)) { @@ -1179,7 +1191,8 @@ string CommandLineInterface::objectWithLinkRefsHex(eth::LinkerObject const& _obj bool CommandLineInterface::assemble( AssemblyStack::Language _language, - AssemblyStack::Machine _targetMachine + AssemblyStack::Machine _targetMachine, + bool _optimize ) { bool successful = true; @@ -1191,6 +1204,8 @@ bool CommandLineInterface::assemble( { if (!stack.parseAndAnalyze(src.first, src.second)) successful = false; + else if (_optimize) + stack.optimize(); } catch (Exception const& _exception) { diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 8dc00370..0b22ca29 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -59,7 +59,7 @@ private: /// @returns the full object with library placeholder hints in hex. static std::string objectWithLinkRefsHex(eth::LinkerObject const& _obj); - bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine); + bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine, bool _optimize); void outputCompilationResults(); diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 4838d088..fdc9fbe3 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -262,10 +262,45 @@ SOLTMPDIR=$(mktemp -d) ) rm -rf "$SOLTMPDIR" -printTask "Testing assemble, yul, strict-assembly..." -echo '{}' | "$SOLC" - --assemble &>/dev/null -echo '{}' | "$SOLC" - --yul &>/dev/null -echo '{}' | "$SOLC" - --strict-assembly &>/dev/null +test_solc_assembly_output() { + local input="${1}" + local expected="${2}" + local solc_args="${3}" + + local expected_object="object \"object\" { code "${expected}" }" + + output=$(echo "${input}" | "$SOLC" - ${solc_args} 2>/dev/null) + empty=$(echo $output | sed -ne '/'"${expected_object}"'/p') + if [ -z "$empty" ] + then + printError "Incorrect assembly output. Expected: " + echo -e ${expected} + printError "with arguments ${solc_args}, but got:" + echo "${output}" + exit 1 + fi +} + +printTask "Testing assemble, yul, strict-assembly and optimize..." +( + echo '{}' | "$SOLC" - --assemble &>/dev/null + echo '{}' | "$SOLC" - --yul &>/dev/null + echo '{}' | "$SOLC" - --strict-assembly &>/dev/null + + # Test options above in conjunction with --optimize. + # Using both, --assemble and --optimize should fail. + ! echo '{}' | "$SOLC" - --assemble --optimize &>/dev/null + + # Test yul and strict assembly output + # Non-empty code results in non-empty binary representation with optimizations turned off, + # while it results in empty binary representation with optimizations turned on. + test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x:u256 := 0:u256 }" "--yul" + test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ }" "--yul --optimize" + + test_solc_assembly_output "{ let x := 0 }" "{ let x := 0 }" "--strict-assembly" + test_solc_assembly_output "{ let x := 0 }" "{ }" "--strict-assembly --optimize" +) + printTask "Testing standard input..." SOLTMPDIR=$(mktemp -d) |