mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Free variables directly after visiting RHS of Variable Declarations during EVMCodeTransform.
This commit is contained in:
parent
a783449195
commit
def0ebbb3e
@ -6,6 +6,7 @@ Language Features:
|
|||||||
Compiler Features:
|
Compiler Features:
|
||||||
* Code Generator: Evaluate ``keccak256`` of string literals at compile-time.
|
* Code Generator: Evaluate ``keccak256`` of string literals at compile-time.
|
||||||
* Peephole Optimizer: Remove unnecessary masking of tags.
|
* Peephole Optimizer: Remove unnecessary masking of tags.
|
||||||
|
* Yul EVM Code Transform: Free stack slots directly after visiting the right-hand-side of variable declarations instead of at the end of the statement only.
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* Type Checker: Fix overload resolution in combination with ``{value: ...}``.
|
* Type Checker: Fix overload resolution in combination with ``{value: ...}``.
|
||||||
|
@ -141,7 +141,7 @@ bool CodeTransform::unreferenced(Scope::Variable const& _var) const
|
|||||||
return !m_context->variableReferences.count(&_var) || m_context->variableReferences[&_var] == 0;
|
return !m_context->variableReferences.count(&_var) || m_context->variableReferences[&_var] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::freeUnusedVariables()
|
void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop)
|
||||||
{
|
{
|
||||||
if (!m_allowStackOpt)
|
if (!m_allowStackOpt)
|
||||||
return;
|
return;
|
||||||
@ -154,11 +154,12 @@ void CodeTransform::freeUnusedVariables()
|
|||||||
deleteVariable(var);
|
deleteVariable(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_unusedStackSlots.count(m_assembly.stackHeight() - 1))
|
if (_popUnusedSlotsAtStackTop)
|
||||||
{
|
while (m_unusedStackSlots.count(m_assembly.stackHeight() - 1))
|
||||||
yulAssert(m_unusedStackSlots.erase(m_assembly.stackHeight() - 1), "");
|
{
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
yulAssert(m_unusedStackSlots.erase(m_assembly.stackHeight() - 1), "");
|
||||||
}
|
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::deleteVariable(Scope::Variable const& _var)
|
void CodeTransform::deleteVariable(Scope::Variable const& _var)
|
||||||
@ -181,6 +182,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
{
|
{
|
||||||
std::visit(*this, *_varDecl.value);
|
std::visit(*this, *_varDecl.value);
|
||||||
expectDeposit(static_cast<int>(numVariables), static_cast<int>(heightAtStart));
|
expectDeposit(static_cast<int>(numVariables), static_cast<int>(heightAtStart));
|
||||||
|
freeUnusedVariables(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -161,8 +161,9 @@ protected:
|
|||||||
bool unreferenced(Scope::Variable const& _var) const;
|
bool unreferenced(Scope::Variable const& _var) const;
|
||||||
/// Marks slots of variables that are not used anymore
|
/// Marks slots of variables that are not used anymore
|
||||||
/// and were defined in the current scope for reuse.
|
/// and were defined in the current scope for reuse.
|
||||||
/// Also POPs unused topmost stack slots.
|
/// Also POPs unused topmost stack slots,
|
||||||
void freeUnusedVariables();
|
/// unless @a _popUnusedSlotsAtStackTop is set to false.
|
||||||
|
void freeUnusedVariables(bool _popUnusedSlotsAtStackTop = true);
|
||||||
/// Marks the stack slot of @a _var to be reused.
|
/// Marks the stack slot of @a _var to be reused.
|
||||||
void deleteVariable(Scope::Variable const& _var);
|
void deleteVariable(Scope::Variable const& _var);
|
||||||
|
|
||||||
|
@ -345,6 +345,69 @@ BOOST_AUTO_TEST_CASE(reuse_slots_function_with_gaps)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_to_last_used)
|
||||||
|
{
|
||||||
|
string in = R"({
|
||||||
|
let x := 5
|
||||||
|
let y := x // y should reuse the stack slot of x
|
||||||
|
sstore(y, y)
|
||||||
|
})";
|
||||||
|
BOOST_CHECK_EQUAL(assemble(in),
|
||||||
|
"PUSH1 0x5 "
|
||||||
|
"DUP1 SWAP1 POP "
|
||||||
|
"DUP1 DUP2 SSTORE "
|
||||||
|
"POP "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_to_last_used_expr)
|
||||||
|
{
|
||||||
|
string in = R"({
|
||||||
|
let x := 5
|
||||||
|
let y := add(x, 2) // y should reuse the stack slot of x
|
||||||
|
sstore(y, y)
|
||||||
|
})";
|
||||||
|
BOOST_CHECK_EQUAL(assemble(in),
|
||||||
|
"PUSH1 0x5 "
|
||||||
|
"PUSH1 0x2 DUP2 ADD "
|
||||||
|
"SWAP1 POP "
|
||||||
|
"DUP1 DUP2 SSTORE "
|
||||||
|
"POP "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_to_not_last_used)
|
||||||
|
{
|
||||||
|
string in = R"({
|
||||||
|
let x := 5
|
||||||
|
let y := x // y should not reuse the stack slot of x, since x is still used below
|
||||||
|
sstore(y, x)
|
||||||
|
})";
|
||||||
|
BOOST_CHECK_EQUAL(assemble(in),
|
||||||
|
"PUSH1 0x5 "
|
||||||
|
"DUP1 "
|
||||||
|
"DUP2 DUP2 SSTORE "
|
||||||
|
"POP POP "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_not_same_scope)
|
||||||
|
{
|
||||||
|
string in = R"({
|
||||||
|
let x := 5
|
||||||
|
{
|
||||||
|
let y := x // y should not reuse the stack slot of x, since x is not in the same scope
|
||||||
|
sstore(y, y)
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
BOOST_CHECK_EQUAL(assemble(in),
|
||||||
|
"PUSH1 0x5 "
|
||||||
|
"DUP1 "
|
||||||
|
"DUP1 DUP2 SSTORE "
|
||||||
|
"POP POP "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user