mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
YulStack: When Yul optimization is not requested, run Yul optimizer with a minimal sequence instead of disabling it
This commit is contained in:
parent
dff774d82f
commit
25be38905f
@ -11,6 +11,7 @@ Compiler Features:
|
|||||||
* Parser: Introduce ``pragma experimental solidity``, which will enable an experimental language mode that in particular has no stability guarantees between non-breaking releases and is not suited for production use.
|
* Parser: Introduce ``pragma experimental solidity``, which will enable an experimental language mode that in particular has no stability guarantees between non-breaking releases and is not suited for production use.
|
||||||
* Standard JSON Interface: Add ``ast`` file-level output for Yul input.
|
* Standard JSON Interface: Add ``ast`` file-level output for Yul input.
|
||||||
* Standard JSON Interface: Add ``irAst`` and ``irOptimizedAst`` contract-level outputs for Solidity input, providing AST in compact JSON format for IR and optimized IR.
|
* Standard JSON Interface: Add ``irAst`` and ``irOptimizedAst`` contract-level outputs for Solidity input, providing AST in compact JSON format for IR and optimized IR.
|
||||||
|
* Yul Optimizer: Stack-to-memory mover is now enabled by default whenever possible for via IR code generation and pure Yul compilation.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -304,7 +304,7 @@ Input Description
|
|||||||
// optimization-sequence:clean-up-sequence. For more information see
|
// optimization-sequence:clean-up-sequence. For more information see
|
||||||
// "The Optimizer > Selecting Optimizations".
|
// "The Optimizer > Selecting Optimizations".
|
||||||
// This field is optional, and if not provided, the default sequences for both
|
// This field is optional, and if not provided, the default sequences for both
|
||||||
// optimization and clean-up are used. If only one of the options is provivded
|
// optimization and clean-up are used. If only one of the sequences is provided
|
||||||
// the other will not be run.
|
// the other will not be run.
|
||||||
// If only the delimiter ":" is provided then neither the optimization nor the clean-up
|
// If only the delimiter ":" is provided then neither the optimization nor the clean-up
|
||||||
// sequence will be run.
|
// sequence will be run.
|
||||||
|
@ -103,8 +103,8 @@ struct OptimiserSettings
|
|||||||
case OptimisationPreset::Minimal: return minimal();
|
case OptimisationPreset::Minimal: return minimal();
|
||||||
case OptimisationPreset::Standard: return standard();
|
case OptimisationPreset::Standard: return standard();
|
||||||
case OptimisationPreset::Full: return full();
|
case OptimisationPreset::Full: return full();
|
||||||
default: solAssert(false, "");
|
|
||||||
}
|
}
|
||||||
|
util::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(OptimiserSettings const& _other) const
|
bool operator==(OptimiserSettings const& _other) const
|
||||||
|
@ -86,9 +86,6 @@ bool YulStack::parseAndAnalyze(std::string const& _sourceName, std::string const
|
|||||||
|
|
||||||
void YulStack::optimize()
|
void YulStack::optimize()
|
||||||
{
|
{
|
||||||
if (!m_optimiserSettings.runYulOptimiser)
|
|
||||||
return;
|
|
||||||
|
|
||||||
yulAssert(m_analysisSuccessful, "Analysis was not successful.");
|
yulAssert(m_analysisSuccessful, "Analysis was not successful.");
|
||||||
|
|
||||||
m_analysisSuccessful = false;
|
m_analysisSuccessful = false;
|
||||||
@ -159,13 +156,15 @@ void YulStack::optimize(Object& _object, bool _isCreation)
|
|||||||
unique_ptr<GasMeter> meter;
|
unique_ptr<GasMeter> meter;
|
||||||
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&dialect))
|
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&dialect))
|
||||||
meter = make_unique<GasMeter>(*evmDialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
|
meter = make_unique<GasMeter>(*evmDialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
|
||||||
|
|
||||||
OptimiserSuite::run(
|
OptimiserSuite::run(
|
||||||
dialect,
|
dialect,
|
||||||
meter.get(),
|
meter.get(),
|
||||||
_object,
|
_object,
|
||||||
m_optimiserSettings.optimizeStackAllocation,
|
// Defaults are the minimum necessary to avoid running into "Stack too deep" constantly.
|
||||||
m_optimiserSettings.yulOptimiserSteps,
|
m_optimiserSettings.runYulOptimiser ? m_optimiserSettings.optimizeStackAllocation : true,
|
||||||
m_optimiserSettings.yulOptimiserCleanupSteps,
|
m_optimiserSettings.runYulOptimiser ? m_optimiserSettings.yulOptimiserSteps : "u",
|
||||||
|
m_optimiserSettings.runYulOptimiser ? m_optimiserSettings.yulOptimiserCleanupSteps : "",
|
||||||
_isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment),
|
_isCreation ? nullopt : make_optional(m_optimiserSettings.expectedExecutionsPerDeployment),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
@ -231,7 +230,12 @@ YulStack::assembleEVMWithDeployed(optional<string_view> _deployName) const
|
|||||||
|
|
||||||
evmasm::Assembly assembly(m_evmVersion, true, {});
|
evmasm::Assembly assembly(m_evmVersion, true, {});
|
||||||
EthAssemblyAdapter adapter(assembly);
|
EthAssemblyAdapter adapter(assembly);
|
||||||
compileEVM(adapter, m_optimiserSettings.optimizeStackAllocation);
|
|
||||||
|
// NOTE: We always need stack optimization when Yul optimizer is disabled. It being disabled
|
||||||
|
// just means that we don't use the full step sequence. We still run it with the minimal steps
|
||||||
|
// required to avoid "stack too deep".
|
||||||
|
bool optimize = m_optimiserSettings.optimizeStackAllocation || !m_optimiserSettings.runYulOptimiser;
|
||||||
|
compileEVM(adapter, optimize);
|
||||||
|
|
||||||
assembly.optimise(evmasm::Assembly::OptimiserSettings::translateSettings(m_optimiserSettings, m_evmVersion));
|
assembly.optimise(evmasm::Assembly::OptimiserSettings::translateSettings(m_optimiserSettings, m_evmVersion));
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ echo '{}' | "$SOLC" - --yul --optimize &>/dev/null && fail "solc --yul --optimiz
|
|||||||
# Test yul and strict assembly output
|
# Test yul and strict assembly output
|
||||||
# Non-empty code results in non-empty binary representation with optimizations turned off,
|
# Non-empty code results in non-empty binary representation with optimizations turned off,
|
||||||
# while it results in empty binary representation with optimizations turned on.
|
# while it results in empty binary representation with optimizations turned on.
|
||||||
test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x := 0 }" "--yul"
|
test_solc_assembly_output "{ let x:u256 := 0:u256 mstore(0, x) }" "{ { let x := 0 mstore(0, x) } }" "--yul"
|
||||||
test_solc_assembly_output "{ let x:u256 := bitnot(7:u256) }" "{ let x := bitnot(7) }" "--yul"
|
test_solc_assembly_output "{ let x:u256 := bitnot(7:u256) mstore(0, x) }" "{ { let x := bitnot(7) mstore(0, x) } }" "--yul"
|
||||||
test_solc_assembly_output "{ let t:bool := not(true) }" "{ let t:bool := not(true) }" "--yul"
|
test_solc_assembly_output "{ let t:bool := not(true) if t { mstore(0, 1) } }" "{ { let t:bool := not(true) if t { mstore(0, 1) } } }" "--yul"
|
||||||
test_solc_assembly_output "{ let x := 0 }" "{ let x := 0 }" "--strict-assembly"
|
test_solc_assembly_output "{ let x := 0 mstore(0, x) }" "{ { let x := 0 mstore(0, x) } }" "--strict-assembly"
|
||||||
test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize"
|
test_solc_assembly_output "{ let x := 0 mstore(0, x) }" "{ { } }" "--strict-assembly --optimize"
|
||||||
|
Loading…
Reference in New Issue
Block a user