Run yul optimizer on user code without refs

This commit is contained in:
Mathias Baumann 2020-02-04 12:01:13 +01:00
parent 3a4cb016ff
commit 1a3998648c
5 changed files with 202 additions and 4 deletions

View File

@ -20,6 +20,8 @@
* Solidity compiler.
*/
#include <functional>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTUtils.h>
#include <libsolidity/ast/TypeProvider.h>
@ -27,7 +29,16 @@
#include <libsolidity/codegen/ContractCompiler.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libyul/AsmAnalysisInfo.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>
#include <libyul/optimiser/Suite.h>
#include <libyul/Object.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/YulString.h>
#include <libevmasm/Instruction.h>
#include <libevmasm/Assembly.h>
@ -40,6 +51,13 @@
#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;
@ -788,10 +806,65 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
_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()
)
{
// 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
bool const isCreation = m_context.runtimeContext() != nullptr;
yul::GasMeter meter(*dialect, isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
yul::OptimiserSuite::run(
*dialect,
&meter,
object,
m_optimiserSettings.optimizeStackAllocation,
{}
);
#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(
_inlineAssembly.operations(),
*_inlineAssembly.annotation().analysisInfo,
*code,
*analysisInfo,
*m_context.assemblyPtr(),
m_context.evmVersion(),
identifierAccess,

View File

@ -84,6 +84,7 @@ public:
virtual Expression translate(Expression const& _expression);
virtual Statement translate(Statement const& _statement);
Block translate(Block const& _block);
protected:
template <typename T>
std::vector<T> translateVector(std::vector<T> const& _values);
@ -94,7 +95,6 @@ protected:
return _v ? std::make_unique<T>(translate(*_v)) : nullptr;
}
Block translate(Block const& _block);
Case translate(Case const& _case);
virtual Identifier translate(Identifier const& _identifier);
Literal translate(Literal const& _literal);

View File

@ -0,0 +1 @@
--optimize --asm --metadata-hash none

View 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)
}
}
}
}

View 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: 0xa164736f6c63782a302e362e332d646576656c6f702e323032302e322e362b636f6d6d69742e31353237396436392e6d6f640032
}