mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8250 from ethereum/run-opt-on-user-asm-8031
Run yul optimizer on user code without refs
This commit is contained in:
commit
aa15ea7e8e
@ -423,18 +423,12 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
// so we essentially only optimize the ABI functions.
|
// so we essentially only optimize the ABI functions.
|
||||||
if (_optimiserSettings.runYulOptimiser && _localVariables.empty())
|
if (_optimiserSettings.runYulOptimiser && _localVariables.empty())
|
||||||
{
|
{
|
||||||
bool const isCreation = m_runtimeContext != nullptr;
|
|
||||||
yul::GasMeter meter(dialect, isCreation, _optimiserSettings.expectedExecutionsPerDeployment);
|
|
||||||
yul::Object obj;
|
yul::Object obj;
|
||||||
obj.code = parserResult;
|
obj.code = parserResult;
|
||||||
obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo);
|
obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo);
|
||||||
yul::OptimiserSuite::run(
|
|
||||||
dialect,
|
optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers);
|
||||||
&meter,
|
|
||||||
obj,
|
|
||||||
_optimiserSettings.optimizeStackAllocation,
|
|
||||||
externallyUsedIdentifiers
|
|
||||||
);
|
|
||||||
analysisInfo = std::move(*obj.analysisInfo);
|
analysisInfo = std::move(*obj.analysisInfo);
|
||||||
parserResult = std::move(obj.code);
|
parserResult = std::move(obj.code);
|
||||||
|
|
||||||
@ -462,6 +456,29 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
updateSourceLocation();
|
updateSourceLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _dialect, OptimiserSettings const& _optimiserSettings, std::set<yul::YulString> const& _externalIdentifiers)
|
||||||
|
{
|
||||||
|
#ifdef SOL_OUTPUT_ASM
|
||||||
|
cout << yul::AsmPrinter(*dialect)(*_object.code) << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool const isCreation = runtimeContext() != nullptr;
|
||||||
|
yul::GasMeter meter(_dialect, isCreation, _optimiserSettings.expectedExecutionsPerDeployment);
|
||||||
|
yul::OptimiserSuite::run(
|
||||||
|
_dialect,
|
||||||
|
&meter,
|
||||||
|
_object,
|
||||||
|
_optimiserSettings.optimizeStackAllocation,
|
||||||
|
_externalIdentifiers
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef SOL_OUTPUT_ASM
|
||||||
|
cout << "After optimizer:" << endl;
|
||||||
|
cout << yul::AsmPrinter(*dialect)(*object.code) << endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
FunctionDefinition const& CompilerContext::resolveVirtualFunction(
|
FunctionDefinition const& CompilerContext::resolveVirtualFunction(
|
||||||
FunctionDefinition const& _function,
|
FunctionDefinition const& _function,
|
||||||
vector<ContractDefinition const*>::const_iterator _searchStart
|
vector<ContractDefinition const*>::const_iterator _searchStart
|
||||||
|
@ -32,9 +32,13 @@
|
|||||||
|
|
||||||
#include <libevmasm/Assembly.h>
|
#include <libevmasm/Assembly.h>
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
#include <libsolutil/Common.h>
|
#include <libsolutil/Common.h>
|
||||||
|
|
||||||
|
#include <libyul/AsmAnalysisInfo.h>
|
||||||
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@ -232,6 +236,8 @@ public:
|
|||||||
/// Otherwise returns "revert(0, 0)".
|
/// Otherwise returns "revert(0, 0)".
|
||||||
std::string revertReasonIfDebug(std::string const& _message = "");
|
std::string revertReasonIfDebug(std::string const& _message = "");
|
||||||
|
|
||||||
|
void optimizeYul(yul::Object& _object, yul::EVMDialect const& _dialect, OptimiserSettings const& _optimiserSetting, std::set<yul::YulString> const& _externalIdentifiers = {});
|
||||||
|
|
||||||
/// Appends arbitrary data to the end of the bytecode.
|
/// Appends arbitrary data to the end of the bytecode.
|
||||||
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
* Solidity compiler.
|
* Solidity compiler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/ast/ASTUtils.h>
|
#include <libsolidity/ast/ASTUtils.h>
|
||||||
#include <libsolidity/ast/TypeProvider.h>
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
@ -27,7 +28,16 @@
|
|||||||
#include <libsolidity/codegen/ContractCompiler.h>
|
#include <libsolidity/codegen/ContractCompiler.h>
|
||||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||||
|
|
||||||
|
#include <libyul/AsmAnalysisInfo.h>
|
||||||
|
#include <libyul/AsmAnalysis.h>
|
||||||
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/backends/evm/AsmCodeGen.h>
|
#include <libyul/backends/evm/AsmCodeGen.h>
|
||||||
|
#include <libyul/backends/evm/EVMMetrics.h>
|
||||||
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
|
#include <libyul/optimiser/Suite.h>
|
||||||
|
#include <libyul/Object.h>
|
||||||
|
#include <libyul/optimiser/ASTCopier.h>
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
#include <libevmasm/Assembly.h>
|
#include <libevmasm/Assembly.h>
|
||||||
@ -38,6 +48,7 @@
|
|||||||
#include <libsolutil/Whiskers.h>
|
#include <libsolutil/Whiskers.h>
|
||||||
|
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -788,10 +799,36 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
_assembly.appendInstruction(Instruction::POP);
|
_assembly.appendInstruction(Instruction::POP);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
solAssert(_inlineAssembly.annotation().analysisInfo, "");
|
|
||||||
|
yul::Block const* code = &_inlineAssembly.operations();
|
||||||
|
yul::AsmAnalysisInfo* analysisInfo = _inlineAssembly.annotation().analysisInfo.get();
|
||||||
|
|
||||||
|
// Only used in the scope below, but required to live outside to keep the
|
||||||
|
// shared_ptr's alive
|
||||||
|
yul::Object object = {};
|
||||||
|
|
||||||
|
// The optimiser cannot handle external references
|
||||||
|
if (
|
||||||
|
m_optimiserSettings.runYulOptimiser &&
|
||||||
|
_inlineAssembly.annotation().externalReferences.empty()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
yul::EVMDialect const* dialect = dynamic_cast<decltype(dialect)>(&_inlineAssembly.dialect());
|
||||||
|
solAssert(dialect, "");
|
||||||
|
|
||||||
|
// Create a modifiable copy of the code and analysis
|
||||||
|
object.code = make_shared<yul::Block>(yul::ASTCopier().translate(*code));
|
||||||
|
object.analysisInfo = make_shared<yul::AsmAnalysisInfo>(yul::AsmAnalyzer::analyzeStrictAssertCorrect(*dialect, object));
|
||||||
|
|
||||||
|
m_context.optimizeYul(object, *dialect, m_optimiserSettings);
|
||||||
|
|
||||||
|
code = object.code.get();
|
||||||
|
analysisInfo = object.analysisInfo.get();
|
||||||
|
}
|
||||||
|
|
||||||
yul::CodeGenerator::assemble(
|
yul::CodeGenerator::assemble(
|
||||||
_inlineAssembly.operations(),
|
*code,
|
||||||
*_inlineAssembly.annotation().analysisInfo,
|
*analysisInfo,
|
||||||
*m_context.assemblyPtr(),
|
*m_context.assemblyPtr(),
|
||||||
m_context.evmVersion(),
|
m_context.evmVersion(),
|
||||||
identifierAccess,
|
identifierAccess,
|
||||||
|
@ -84,6 +84,7 @@ public:
|
|||||||
virtual Expression translate(Expression const& _expression);
|
virtual Expression translate(Expression const& _expression);
|
||||||
virtual Statement translate(Statement const& _statement);
|
virtual Statement translate(Statement const& _statement);
|
||||||
|
|
||||||
|
Block translate(Block const& _block);
|
||||||
protected:
|
protected:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::vector<T> translateVector(std::vector<T> const& _values);
|
std::vector<T> translateVector(std::vector<T> const& _values);
|
||||||
@ -94,7 +95,6 @@ protected:
|
|||||||
return _v ? std::make_unique<T>(translate(*_v)) : nullptr;
|
return _v ? std::make_unique<T>(translate(*_v)) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block translate(Block const& _block);
|
|
||||||
Case translate(Case const& _case);
|
Case translate(Case const& _case);
|
||||||
virtual Identifier translate(Identifier const& _identifier);
|
virtual Identifier translate(Identifier const& _identifier);
|
||||||
Literal translate(Literal const& _literal);
|
Literal translate(Literal const& _literal);
|
||||||
|
@ -17,6 +17,7 @@ fi
|
|||||||
|
|
||||||
FORMATERROR=$(
|
FORMATERROR=$(
|
||||||
(
|
(
|
||||||
|
git grep -nIE "#include \"" -- '*.h' '*.cpp' | egrep -v -e "license.h" -e "BuildInfo.h" # Use include with <> characters
|
||||||
git grep -nIE "\<(if|for|while|switch)\(" -- '*.h' '*.cpp' # no space after "if", "for", "while" or "switch"
|
git grep -nIE "\<(if|for|while|switch)\(" -- '*.h' '*.cpp' # no space after "if", "for", "while" or "switch"
|
||||||
git grep -nIE "\<for\>\s*\([^=]*\>\s:\s.*\)" -- '*.h' '*.cpp' # no space before range based for-loop
|
git grep -nIE "\<for\>\s*\([^=]*\>\s:\s.*\)" -- '*.h' '*.cpp' # no space before range based for-loop
|
||||||
git grep -nIE "\<if\>\s*\(.*\)\s*\{\s*$" -- '*.h' '*.cpp' # "{\n" on same line as "if" / "for"
|
git grep -nIE "\<if\>\s*\(.*\)\s*\{\s*$" -- '*.h' '*.cpp' # "{\n" on same line as "if" / "for"
|
||||||
|
@ -155,6 +155,7 @@ function test_solc_behaviour()
|
|||||||
rm "$stdout_path.bak"
|
rm "$stdout_path.bak"
|
||||||
else
|
else
|
||||||
sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
|
sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
|
||||||
|
sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path"
|
||||||
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
|
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
|
||||||
# Remove trailing empty lines. Needs a line break to make OSX sed happy.
|
# Remove trailing empty lines. Needs a line break to make OSX sed happy.
|
||||||
sed -i.bak -e '1{/^$/d
|
sed -i.bak -e '1{/^$/d
|
||||||
|
1
test/cmdlineTests/optimizer_user_yul/args
Normal file
1
test/cmdlineTests/optimizer_user_yul/args
Normal file
@ -0,0 +1 @@
|
|||||||
|
--optimize --asm --metadata-hash none
|
37
test/cmdlineTests/optimizer_user_yul/input.sol
Normal file
37
test/cmdlineTests/optimizer_user_yul/input.sol
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
pragma solidity >=0.0;
|
||||||
|
|
||||||
|
contract C
|
||||||
|
{
|
||||||
|
constructor() public payable
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
|
||||||
|
// Can't be optimized due to external reference "a"
|
||||||
|
assembly
|
||||||
|
{
|
||||||
|
let x,y,z
|
||||||
|
|
||||||
|
sstore(0, 1)
|
||||||
|
|
||||||
|
for { } sload(4) { } {
|
||||||
|
z := exp(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
a := 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can be optimized due to no external references
|
||||||
|
assembly
|
||||||
|
{
|
||||||
|
let x,y,z
|
||||||
|
|
||||||
|
sstore(2, 3)
|
||||||
|
|
||||||
|
for { } sload(5) { } {
|
||||||
|
// Expected to be optimized out for yulOptimizer, but not for
|
||||||
|
// old optimizer
|
||||||
|
z := exp(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
test/cmdlineTests/optimizer_user_yul/output
Normal file
87
test/cmdlineTests/optimizer_user_yul/output
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
======= optimizer_user_yul/input.sol:C =======
|
||||||
|
EVM assembly:
|
||||||
|
/* "optimizer_user_yul/input.sol":24:489 contract C... */
|
||||||
|
mstore(0x40, 0x80)
|
||||||
|
/* "optimizer_user_yul/input.sol":72:77 int a */
|
||||||
|
0x00
|
||||||
|
/* "optimizer_user_yul/input.sol":38:487 constructor() public payable... */
|
||||||
|
dup1
|
||||||
|
0x00
|
||||||
|
dup1
|
||||||
|
/* "optimizer_user_yul/input.sol":176:177 1 */
|
||||||
|
0x01
|
||||||
|
/* "optimizer_user_yul/input.sol":173:174 0 */
|
||||||
|
0x00
|
||||||
|
/* "optimizer_user_yul/input.sol":166:178 sstore(0, 1) */
|
||||||
|
sstore
|
||||||
|
/* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */
|
||||||
|
tag_3:
|
||||||
|
/* "optimizer_user_yul/input.sol":197:198 4 */
|
||||||
|
0x04
|
||||||
|
/* "optimizer_user_yul/input.sol":191:199 sload(4) */
|
||||||
|
sload
|
||||||
|
/* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */
|
||||||
|
iszero
|
||||||
|
tag_5
|
||||||
|
jumpi
|
||||||
|
pop
|
||||||
|
/* "optimizer_user_yul/input.sol":215:224 exp(x, y) */
|
||||||
|
dup1
|
||||||
|
dup3
|
||||||
|
exp
|
||||||
|
/* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */
|
||||||
|
jump(tag_3)
|
||||||
|
tag_5:
|
||||||
|
/* "optimizer_user_yul/input.sol":187:190 { } */
|
||||||
|
pop
|
||||||
|
pop
|
||||||
|
pop
|
||||||
|
/* "optimizer_user_yul/input.sol":239:240 2 */
|
||||||
|
0x02
|
||||||
|
/* "optimizer_user_yul/input.sol":234:240 a := 2 */
|
||||||
|
swap1
|
||||||
|
pop
|
||||||
|
/* "optimizer_user_yul/input.sol":340:341 3 */
|
||||||
|
0x03
|
||||||
|
/* "optimizer_user_yul/input.sol":337:338 2 */
|
||||||
|
0x02
|
||||||
|
/* "optimizer_user_yul/input.sol":330:342 sstore(2, 3) */
|
||||||
|
sstore
|
||||||
|
/* "optimizer_user_yul/input.sol":347:480 for { } sload(5) { } {... */
|
||||||
|
tag_6:
|
||||||
|
/* "optimizer_user_yul/input.sol":361:362 5 */
|
||||||
|
0x05
|
||||||
|
/* "optimizer_user_yul/input.sol":355:363 sload(5) */
|
||||||
|
sload
|
||||||
|
tag_9
|
||||||
|
jumpi
|
||||||
|
jump(tag_8)
|
||||||
|
tag_9:
|
||||||
|
/* "optimizer_user_yul/input.sol":347:480 for { } sload(5) { } {... */
|
||||||
|
jump(tag_6)
|
||||||
|
tag_8:
|
||||||
|
/* "optimizer_user_yul/input.sol":311:484 {... */
|
||||||
|
pop
|
||||||
|
/* "optimizer_user_yul/input.sol":24:489 contract C... */
|
||||||
|
dataSize(sub_0)
|
||||||
|
dup1
|
||||||
|
dataOffset(sub_0)
|
||||||
|
0x00
|
||||||
|
codecopy
|
||||||
|
0x00
|
||||||
|
return
|
||||||
|
stop
|
||||||
|
|
||||||
|
sub_0: assembly {
|
||||||
|
/* "optimizer_user_yul/input.sol":24:489 contract C... */
|
||||||
|
mstore(0x40, 0x80)
|
||||||
|
/* "--CODEGEN--":12:13 */
|
||||||
|
0x00
|
||||||
|
/* "--CODEGEN--":9:10 */
|
||||||
|
dup1
|
||||||
|
/* "--CODEGEN--":2:14 */
|
||||||
|
revert
|
||||||
|
|
||||||
|
auxdata: AUXDATA REMOVED
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user