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: Support ``.`` as part of identifiers.
|
||||
* 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:
|
||||
|
@ -62,6 +62,7 @@ public:
|
||||
/// Retrieve the current height of the stack. This does not have to be zero
|
||||
/// at the beginning.
|
||||
virtual int stackHeight() const = 0;
|
||||
virtual void setStackHeight(int height) = 0;
|
||||
/// Append an EVM instruction.
|
||||
virtual void appendInstruction(dev::eth::Instruction _instruction) = 0;
|
||||
/// Append a constant.
|
||||
|
@ -57,6 +57,11 @@ int EthAssemblyAdapter::stackHeight() const
|
||||
return m_assembly.deposit();
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::setStackHeight(int height)
|
||||
{
|
||||
m_assembly.setDeposit(height);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendInstruction(dev::eth::Instruction _instruction)
|
||||
{
|
||||
m_assembly.append(_instruction);
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
explicit EthAssemblyAdapter(dev::eth::Assembly& _assembly);
|
||||
void setSourceLocation(langutil::SourceLocation const& _location) override;
|
||||
int stackHeight() const override;
|
||||
void setStackHeight(int height) override;
|
||||
void appendInstruction(dev::eth::Instruction _instruction) override;
|
||||
void appendConstant(dev::u256 const& _constant) 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
|
||||
/// at the beginning.
|
||||
int stackHeight() const override { return m_stackHeight; }
|
||||
void setStackHeight(int height) override { m_stackHeight = height; }
|
||||
/// Append an EVM instruction.
|
||||
void appendInstruction(dev::eth::Instruction _instruction) override;
|
||||
/// Append a constant.
|
||||
|
@ -490,19 +490,15 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
}
|
||||
|
||||
m_assembly.setSourceLocation(_function.location);
|
||||
int stackHeightBefore = m_assembly.stackHeight();
|
||||
AbstractAssembly::LabelID afterFunction = m_assembly.newLabelId();
|
||||
int const stackHeightBefore = m_assembly.stackHeight();
|
||||
|
||||
if (m_evm15)
|
||||
{
|
||||
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore);
|
||||
m_assembly.appendBeginsub(functionEntryID(_function.name, function), _function.parameters.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
|
||||
m_assembly.appendLabel(functionEntryID(_function.name, function));
|
||||
}
|
||||
|
||||
m_assembly.setStackHeight(height);
|
||||
|
||||
m_stackAdjustment += localStackAdjustment;
|
||||
|
||||
for (auto const& v: _function.returnVariables)
|
||||
@ -592,8 +588,8 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
else
|
||||
m_assembly.appendJump(stackHeightBefore - _function.returnVariables.size());
|
||||
m_stackAdjustment -= localStackAdjustment;
|
||||
m_assembly.appendLabel(afterFunction);
|
||||
checkStackHeight(&_function);
|
||||
m_assembly.setStackHeight(stackHeightBefore);
|
||||
}
|
||||
|
||||
void CodeTransform::operator()(ForLoop const& _forLoop)
|
||||
@ -727,11 +723,32 @@ void CodeTransform::visitExpression(Expression const& _expression)
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
// we may have a leftover jumpTarget
|
||||
if (jumpTarget)
|
||||
m_assembly.appendLabel(*jumpTarget);
|
||||
|
||||
freeUnusedVariables();
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
|
||||
void setSourceLocation(langutil::SourceLocation const&) override {}
|
||||
int stackHeight() const override { return m_stackHeight; }
|
||||
void setStackHeight(int height) override { m_stackHeight = height; }
|
||||
void appendInstruction(dev::eth::Instruction _instruction) override;
|
||||
void appendConstant(dev::u256 const& _constant) override;
|
||||
void appendLabel(LabelID _labelId) override;
|
||||
|
@ -277,16 +277,15 @@ BOOST_AUTO_TEST_CASE(functions_multi_return)
|
||||
let unused := 7
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0xB JUMP "
|
||||
"PUSH1 0x13 JUMP "
|
||||
"JUMPDEST PUSH1 0x0 SWAP3 SWAP2 POP POP JUMP " // f
|
||||
"JUMPDEST PUSH1 0x17 JUMP "
|
||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 SWAP1 SWAP2 JUMP " // g
|
||||
"JUMPDEST PUSH1 0x21 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 0x1D PUSH1 0x2 PUSH1 0x1 PUSH1 0x3 JUMP " // f(1, 2)
|
||||
"JUMPDEST PUSH1 0x27 PUSH1 0x4 PUSH1 0x3 PUSH1 0x3 JUMP " // f(3, 4)
|
||||
"JUMPDEST SWAP1 POP " // assignment to x
|
||||
"POP " // remove x
|
||||
"PUSH1 0x34 PUSH1 0xF JUMP " // g()
|
||||
"JUMPDEST PUSH1 0x3A PUSH1 0xF JUMP " // g()
|
||||
"PUSH1 0x30 PUSH1 0xB JUMP " // g()
|
||||
"JUMPDEST PUSH1 0x36 PUSH1 0xB JUMP " // g()
|
||||
"JUMPDEST SWAP2 POP SWAP2 POP " // assignments
|
||||
"POP POP " // removal of y and z
|
||||
"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