Unify optimize yul code in CompilerContext/ContractCompiler

This commit is contained in:
Mathias Baumann 2020-02-06 16:32:33 +01:00
parent 1a3998648c
commit 80bd0f47cc
5 changed files with 41 additions and 53 deletions

View File

@ -423,18 +423,12 @@ void CompilerContext::appendInlineAssembly(
// so we essentially only optimize the ABI functions.
if (_optimiserSettings.runYulOptimiser && _localVariables.empty())
{
bool const isCreation = m_runtimeContext != nullptr;
yul::GasMeter meter(dialect, isCreation, _optimiserSettings.expectedExecutionsPerDeployment);
yul::Object obj;
obj.code = parserResult;
obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo);
yul::OptimiserSuite::run(
dialect,
&meter,
obj,
_optimiserSettings.optimizeStackAllocation,
externallyUsedIdentifiers
);
optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers);
analysisInfo = std::move(*obj.analysisInfo);
parserResult = std::move(obj.code);
@ -462,6 +456,29 @@ void CompilerContext::appendInlineAssembly(
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& _function,
vector<ContractDefinition const*>::const_iterator _searchStart

View File

@ -32,9 +32,13 @@
#include <libevmasm/Assembly.h>
#include <libevmasm/Instruction.h>
#include <liblangutil/ErrorReporter.h>
#include <liblangutil/EVMVersion.h>
#include <libsolutil/Common.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <functional>
#include <ostream>
#include <stack>
@ -232,6 +236,8 @@ public:
/// Otherwise returns "revert(0, 0)".
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.
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }

View File

@ -21,7 +21,6 @@
*/
#include <functional>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTUtils.h>
#include <libsolidity/ast/TypeProvider.h>
@ -30,8 +29,8 @@
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmData.h>
#include <libyul/AsmDataForward.h>
#include <libyul/backends/evm/AsmCodeGen.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/evm/EVMDialect.h>
@ -49,15 +48,9 @@
#include <libsolutil/Whiskers.h>
#include <boost/range/adaptor/reversed.hpp>
#include <algorithm>
// Change to "define" to output all intermediate code
#undef SOL_OUTPUT_ASM
#ifdef SOL_OUTPUT_ASM
#include <libyul/AsmPrinter.h>
#endif
using namespace std;
using namespace solidity;
using namespace solidity::evmasm;
@ -812,7 +805,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
// Only used in the scope below, but required to live outside to keep the
// shared_ptr's alive
yul::Object object;
yul::Object object = {};
// The optimiser cannot handle external references
if (
@ -820,48 +813,19 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
_inlineAssembly.annotation().externalReferences.empty()
)
{
// 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>();
{
ErrorList errList;
ErrorReporter errorReporter{errList};
yul::AsmAnalyzer analyzer(
*object.analysisInfo,
errorReporter,
_inlineAssembly.dialect()
);
solAssert(analyzer.analyze(*object.code), "Inline analysis failed.");
}
yul::EVMDialect const* dialect = dynamic_cast<decltype(dialect)>(&_inlineAssembly.dialect());
solAssert(dialect, "");
#ifdef SOL_OUTPUT_ASM
cout << yul::AsmPrinter(*dialect)(*object.code) << endl;
#endif
// 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));
bool const isCreation = m_context.runtimeContext() != nullptr;
yul::GasMeter meter(*dialect, isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
yul::OptimiserSuite::run(
*dialect,
&meter,
object,
m_optimiserSettings.optimizeStackAllocation,
{}
);
m_context.optimizeYul(object, *dialect, m_optimiserSettings);
#ifdef SOL_OUTPUT_ASM
cout << "After optimizer:" << endl;
cout << yul::AsmPrinter(*dialect)(*object.code) << endl;
#endif
code = object.code.get();
analysisInfo = object.analysisInfo.get();
}
solAssert(analysisInfo, "");
yul::CodeGenerator::assemble(
*code,
*analysisInfo,

View File

@ -155,6 +155,7 @@ function test_solc_behaviour()
rm "$stdout_path.bak"
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 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path"
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
# Remove trailing empty lines. Needs a line break to make OSX sed happy.
sed -i.bak -e '1{/^$/d

View File

@ -83,5 +83,5 @@ sub_0: assembly {
/* "--CODEGEN--":2:14 */
revert
auxdata: 0xa164736f6c63782a302e362e332d646576656c6f702e323032302e322e362b636f6d6d69742e31353237396436392e6d6f640032
auxdata: AUXDATA REMOVED
}