diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 2b4a888ee..2d81e833b 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -502,6 +502,7 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _ &meter, _object, _optimiserSettings.optimizeStackAllocation, + _optimiserSettings.yulOptimiserSteps, _externalIdentifiers ); diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index 16aae9493..cd82290af 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -23,12 +23,31 @@ #pragma once #include +#include namespace solidity::frontend { struct OptimiserSettings { + static char constexpr DefaultYulOptimiserSteps[] = + "dhfoDgvulfnTUtnIf" // None of these can make stack problems worse + "[" + "xarrscLM" // Turn into SSA and simplify + "cCTUtTOntnfDIul" // Perform structural simplification + "Lcul" // Simplify again + "Vcul jj" // Reverse SSA + + // should have good "compilability" property here. + + "eul" // Run functional expression inliner + "xarulrul" // Prune a bit more in SSA + "xarrcL" // Turn into SSA again and simplify + "gvif" // Run full inliner + "CTUcarrLsTOtfDncarrIulc" // SSA plus simplify + "]" + "jmuljuljul VcTOcul jmul"; // Make source short and pretty + /// No optimisations at all - not recommended. static OptimiserSettings none() { @@ -74,6 +93,7 @@ struct OptimiserSettings runConstantOptimiser == _other.runConstantOptimiser && optimizeStackAllocation == _other.optimizeStackAllocation && runYulOptimiser == _other.runYulOptimiser && + yulOptimiserSteps == _other.yulOptimiserSteps && expectedExecutionsPerDeployment == _other.expectedExecutionsPerDeployment; } @@ -95,6 +115,11 @@ struct OptimiserSettings bool optimizeStackAllocation = false; /// Yul optimiser with default settings. Will only run on certain parts of the code for now. bool runYulOptimiser = false; + /// Sequence of optimisation steps to be performed by Yul optimiser. + /// Note that there are some hard-coded steps in the optimiser and you cannot disable + /// them just by setting this to an empty string. Set @a runYulOptimiser to false if you want + /// no optimisations. + std::string yulOptimiserSteps = DefaultYulOptimiserSteps; /// This specifies an estimate on how often each opcode in this assembly will be executed, /// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage. size_t expectedExecutionsPerDeployment = 200; diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index e64420bd9..3988bc3fd 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -183,7 +183,8 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation) dialect, meter.get(), _object, - m_optimiserSettings.optimizeStackAllocation + m_optimiserSettings.optimizeStackAllocation, + m_optimiserSettings.yulOptimiserSteps ); } diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 338acd0e8..9f2511e72 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -79,6 +79,7 @@ void OptimiserSuite::run( GasMeter const* _meter, Object& _object, bool _optimizeStackAllocation, + string const& _optimisationSequence, set const& _externallyUsedIdentifiers ) { @@ -94,25 +95,12 @@ void OptimiserSuite::run( OptimiserSuite suite(_dialect, reservedIdentifiers, Debug::None, ast); - suite.runSequence( - "dhfoDgvulfnTUtnIf" // None of these can make stack problems worse - "[" - "xarrscLM" // Turn into SSA and simplify - "cCTUtTOntnfDIul" // Perform structural simplification - "Lcul" // Simplify again - "Vcul jj" // Reverse SSA + // Some steps depend on properties ensured by FunctionHoister, FunctionGrouper and + // ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely. + suite.runSequence("fgo", ast); - // should have good "compilability" property here. - - "eul" // Run functional expression inliner - "xarulrul" // Prune a bit more in SSA - "xarrcL" // Turn into SSA again and simplify - "gvif" // Run full inliner - "CTUcarrLsTOtfDncarrIulc" // SSA plus simplify - "]" - "jmuljuljul VcTOcul jmul", // Make source short and pretty - ast - ); + // Now the user-supplied part + suite.runSequence(_optimisationSequence, ast); // This is a tuning parameter, but actually just prevents infinite loops. size_t stackCompressorMaxIterations = 16; diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index 36df60ca6..790b2f9ad 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -62,6 +62,7 @@ public: GasMeter const* _meter, Object& _object, bool _optimizeStackAllocation, + std::string const& _optimisationSequence, std::set const& _externallyUsedIdentifiers = {} ); diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 2a5209b25..042d528db 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -74,6 +74,8 @@ #include +#include + #include #include @@ -342,7 +344,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line yul::Object obj; obj.code = m_ast; obj.analysisInfo = m_analysisInfo; - OptimiserSuite::run(*m_dialect, &meter, obj, true); + OptimiserSuite::run(*m_dialect, &meter, obj, true, solidity::frontend::OptimiserSettings::DefaultYulOptimiserSteps); } else {