mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Yul] Directly jump over a series of function definitions
Implement a AbstractAssembly::setStackHeight function Update the tests Update Changelog
This commit is contained in:
parent
b66950711e
commit
5d6cbd97df
@ -85,6 +85,7 @@ Compiler Features:
|
|||||||
* Yul: Adds break and continue keywords to for-loop syntax.
|
* Yul: Adds break and continue keywords to for-loop syntax.
|
||||||
* Yul: Support ``.`` as part of identifiers.
|
* Yul: Support ``.`` as part of identifiers.
|
||||||
* Yul Optimizer: Adds steps for detecting and removing of dead code.
|
* Yul Optimizer: Adds steps for detecting and removing of dead code.
|
||||||
|
* Yul Code Generator: Directly jump over a series of function definitions (instead of jumping over each one)
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -62,6 +62,7 @@ public:
|
|||||||
/// Retrieve the current height of the stack. This does not have to be zero
|
/// Retrieve the current height of the stack. This does not have to be zero
|
||||||
/// at the beginning.
|
/// at the beginning.
|
||||||
virtual int stackHeight() const = 0;
|
virtual int stackHeight() const = 0;
|
||||||
|
virtual void setStackHeight(int height) = 0;
|
||||||
/// Append an EVM instruction.
|
/// Append an EVM instruction.
|
||||||
virtual void appendInstruction(dev::eth::Instruction _instruction) = 0;
|
virtual void appendInstruction(dev::eth::Instruction _instruction) = 0;
|
||||||
/// Append a constant.
|
/// Append a constant.
|
||||||
|
@ -57,6 +57,11 @@ int EthAssemblyAdapter::stackHeight() const
|
|||||||
return m_assembly.deposit();
|
return m_assembly.deposit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EthAssemblyAdapter::setStackHeight(int height)
|
||||||
|
{
|
||||||
|
m_assembly.setDeposit(height);
|
||||||
|
}
|
||||||
|
|
||||||
void EthAssemblyAdapter::appendInstruction(dev::eth::Instruction _instruction)
|
void EthAssemblyAdapter::appendInstruction(dev::eth::Instruction _instruction)
|
||||||
{
|
{
|
||||||
m_assembly.append(_instruction);
|
m_assembly.append(_instruction);
|
||||||
|
@ -44,6 +44,7 @@ public:
|
|||||||
explicit EthAssemblyAdapter(dev::eth::Assembly& _assembly);
|
explicit EthAssemblyAdapter(dev::eth::Assembly& _assembly);
|
||||||
void setSourceLocation(langutil::SourceLocation const& _location) override;
|
void setSourceLocation(langutil::SourceLocation const& _location) override;
|
||||||
int stackHeight() const override;
|
int stackHeight() const override;
|
||||||
|
void setStackHeight(int height) override;
|
||||||
void appendInstruction(dev::eth::Instruction _instruction) override;
|
void appendInstruction(dev::eth::Instruction _instruction) override;
|
||||||
void appendConstant(dev::u256 const& _constant) override;
|
void appendConstant(dev::u256 const& _constant) override;
|
||||||
void appendLabel(LabelID _labelId) override;
|
void appendLabel(LabelID _labelId) override;
|
||||||
|
@ -45,6 +45,7 @@ public:
|
|||||||
/// Retrieve the current height of the stack. This does not have to be zero
|
/// Retrieve the current height of the stack. This does not have to be zero
|
||||||
/// at the beginning.
|
/// at the beginning.
|
||||||
int stackHeight() const override { return m_stackHeight; }
|
int stackHeight() const override { return m_stackHeight; }
|
||||||
|
void setStackHeight(int height) override { m_stackHeight = height; }
|
||||||
/// Append an EVM instruction.
|
/// Append an EVM instruction.
|
||||||
void appendInstruction(dev::eth::Instruction _instruction) override;
|
void appendInstruction(dev::eth::Instruction _instruction) override;
|
||||||
/// Append a constant.
|
/// Append a constant.
|
||||||
|
@ -490,19 +490,15 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_assembly.setSourceLocation(_function.location);
|
m_assembly.setSourceLocation(_function.location);
|
||||||
int stackHeightBefore = m_assembly.stackHeight();
|
int const stackHeightBefore = m_assembly.stackHeight();
|
||||||
AbstractAssembly::LabelID afterFunction = m_assembly.newLabelId();
|
|
||||||
|
|
||||||
if (m_evm15)
|
if (m_evm15)
|
||||||
{
|
|
||||||
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore);
|
|
||||||
m_assembly.appendBeginsub(functionEntryID(_function.name, function), _function.parameters.size());
|
m_assembly.appendBeginsub(functionEntryID(_function.name, function), _function.parameters.size());
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
|
|
||||||
m_assembly.appendLabel(functionEntryID(_function.name, function));
|
m_assembly.appendLabel(functionEntryID(_function.name, function));
|
||||||
}
|
|
||||||
|
m_assembly.setStackHeight(height);
|
||||||
|
|
||||||
m_stackAdjustment += localStackAdjustment;
|
m_stackAdjustment += localStackAdjustment;
|
||||||
|
|
||||||
for (auto const& v: _function.returnVariables)
|
for (auto const& v: _function.returnVariables)
|
||||||
@ -592,8 +588,8 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
else
|
else
|
||||||
m_assembly.appendJump(stackHeightBefore - _function.returnVariables.size());
|
m_assembly.appendJump(stackHeightBefore - _function.returnVariables.size());
|
||||||
m_stackAdjustment -= localStackAdjustment;
|
m_stackAdjustment -= localStackAdjustment;
|
||||||
m_assembly.appendLabel(afterFunction);
|
|
||||||
checkStackHeight(&_function);
|
checkStackHeight(&_function);
|
||||||
|
m_assembly.setStackHeight(stackHeightBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::operator()(ForLoop const& _forLoop)
|
void CodeTransform::operator()(ForLoop const& _forLoop)
|
||||||
@ -727,11 +723,32 @@ void CodeTransform::visitExpression(Expression const& _expression)
|
|||||||
|
|
||||||
void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
||||||
{
|
{
|
||||||
|
// Workaround boost bug:
|
||||||
|
// https://www.boost.org/doc/libs/1_63_0/libs/optional/doc/html/boost_optional/tutorial/gotchas/false_positive_with__wmaybe_uninitialized.html
|
||||||
|
boost::optional<AbstractAssembly::LabelID> jumpTarget = boost::make_optional(false, AbstractAssembly::LabelID());
|
||||||
|
|
||||||
for (auto const& statement: _statements)
|
for (auto const& statement: _statements)
|
||||||
{
|
{
|
||||||
freeUnusedVariables();
|
freeUnusedVariables();
|
||||||
|
auto const* functionDefinition = boost::get<FunctionDefinition>(&statement);
|
||||||
|
if (functionDefinition && !jumpTarget)
|
||||||
|
{
|
||||||
|
m_assembly.setSourceLocation(locationOf(statement));
|
||||||
|
jumpTarget = m_assembly.newLabelId();
|
||||||
|
m_assembly.appendJumpTo(*jumpTarget, 0);
|
||||||
|
}
|
||||||
|
else if (!functionDefinition && jumpTarget)
|
||||||
|
{
|
||||||
|
m_assembly.appendLabel(*jumpTarget);
|
||||||
|
jumpTarget = boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
boost::apply_visitor(*this, statement);
|
boost::apply_visitor(*this, statement);
|
||||||
}
|
}
|
||||||
|
// we may have a leftover jumpTarget
|
||||||
|
if (jumpTarget)
|
||||||
|
m_assembly.appendLabel(*jumpTarget);
|
||||||
|
|
||||||
freeUnusedVariables();
|
freeUnusedVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ public:
|
|||||||
|
|
||||||
void setSourceLocation(langutil::SourceLocation const&) override {}
|
void setSourceLocation(langutil::SourceLocation const&) override {}
|
||||||
int stackHeight() const override { return m_stackHeight; }
|
int stackHeight() const override { return m_stackHeight; }
|
||||||
|
void setStackHeight(int height) override { m_stackHeight = height; }
|
||||||
void appendInstruction(dev::eth::Instruction _instruction) override;
|
void appendInstruction(dev::eth::Instruction _instruction) override;
|
||||||
void appendConstant(dev::u256 const& _constant) override;
|
void appendConstant(dev::u256 const& _constant) override;
|
||||||
void appendLabel(LabelID _labelId) override;
|
void appendLabel(LabelID _labelId) override;
|
||||||
|
@ -277,16 +277,15 @@ BOOST_AUTO_TEST_CASE(functions_multi_return)
|
|||||||
let unused := 7
|
let unused := 7
|
||||||
})";
|
})";
|
||||||
BOOST_CHECK_EQUAL(assemble(in),
|
BOOST_CHECK_EQUAL(assemble(in),
|
||||||
"PUSH1 0xB JUMP "
|
"PUSH1 0x13 JUMP "
|
||||||
"JUMPDEST PUSH1 0x0 SWAP3 SWAP2 POP POP JUMP " // f
|
"JUMPDEST PUSH1 0x0 SWAP3 SWAP2 POP POP JUMP " // f
|
||||||
"JUMPDEST PUSH1 0x17 JUMP "
|
|
||||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 JUMP " // g
|
"JUMPDEST PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 JUMP " // g
|
||||||
"JUMPDEST PUSH1 0x21 PUSH1 0x2 PUSH1 0x1 PUSH1 0x3 JUMP " // f(1, 2)
|
"JUMPDEST PUSH1 0x1D PUSH1 0x2 PUSH1 0x1 PUSH1 0x3 JUMP " // f(1, 2)
|
||||||
"JUMPDEST PUSH1 0x2B PUSH1 0x4 PUSH1 0x3 PUSH1 0x3 JUMP " // f(3, 4)
|
"JUMPDEST PUSH1 0x27 PUSH1 0x4 PUSH1 0x3 PUSH1 0x3 JUMP " // f(3, 4)
|
||||||
"JUMPDEST SWAP1 POP " // assignment to x
|
"JUMPDEST SWAP1 POP " // assignment to x
|
||||||
"POP " // remove x
|
"POP " // remove x
|
||||||
"PUSH1 0x34 PUSH1 0xF JUMP " // g()
|
"PUSH1 0x30 PUSH1 0xB JUMP " // g()
|
||||||
"JUMPDEST PUSH1 0x3A PUSH1 0xF JUMP " // g()
|
"JUMPDEST PUSH1 0x36 PUSH1 0xB JUMP " // g()
|
||||||
"JUMPDEST SWAP2 POP SWAP2 POP " // assignments
|
"JUMPDEST SWAP2 POP SWAP2 POP " // assignments
|
||||||
"POP POP " // removal of y and z
|
"POP POP " // removal of y and z
|
||||||
"PUSH1 0x7 POP "
|
"PUSH1 0x7 POP "
|
||||||
|
28
test/libyul/objectCompiler/function_series.yul
Normal file
28
test/libyul/objectCompiler/function_series.yul
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
object "Contract" {
|
||||||
|
code {
|
||||||
|
function f() {}
|
||||||
|
function g() {}
|
||||||
|
sstore(0, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Assembly:
|
||||||
|
// /* "source":33:48 */
|
||||||
|
// jump(tag_1)
|
||||||
|
// tag_2:
|
||||||
|
// /* "source":46:48 */
|
||||||
|
// jump
|
||||||
|
// /* "source":53:68 */
|
||||||
|
// tag_3:
|
||||||
|
// /* "source":66:68 */
|
||||||
|
// jump
|
||||||
|
// tag_1:
|
||||||
|
// /* "source":83:84 */
|
||||||
|
// 0x01
|
||||||
|
// /* "source":80:81 */
|
||||||
|
// 0x00
|
||||||
|
// /* "source":73:85 */
|
||||||
|
// sstore
|
||||||
|
// Bytecode: 6007565b565b565b6001600055
|
||||||
|
// Opcodes: PUSH1 0x7 JUMP JUMPDEST JUMP JUMPDEST JUMP JUMPDEST PUSH1 0x1 PUSH1 0x0 SSTORE
|
Loading…
Reference in New Issue
Block a user