Merge pull request #6241 from ethereum/yul-bc-codegen

Yul codegen for break & continue statements
This commit is contained in:
chriseth 2019-03-28 14:48:50 +01:00 committed by GitHub
commit 2b0c653f57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 4 deletions

View File

@ -4,6 +4,7 @@ Language Features:
Compiler Features: Compiler Features:
* Yul: Adds break and continue keywords to for-loop syntax.
Bugfixes: Bugfixes:

View File

@ -633,14 +633,34 @@ void CodeTransform::operator()(ForLoop const& _forLoop)
checkStackHeight(&_forLoop); checkStackHeight(&_forLoop);
} }
void CodeTransform::operator()(Break const&) int CodeTransform::appendPopUntil(int _targetDepth)
{ {
yulAssert(false, "Code generation for break statement in Yul is not implemented yet."); int const stackDiffAfter = m_assembly.stackHeight() - _targetDepth;
for (int i = 0; i < stackDiffAfter; ++i)
m_assembly.appendInstruction(solidity::Instruction::POP);
return stackDiffAfter;
} }
void CodeTransform::operator()(Continue const&) void CodeTransform::operator()(Break const& _break)
{ {
yulAssert(false, "Code generation for continue statement in Yul is not implemented yet."); yulAssert(!m_context->forLoopStack.empty(), "Invalid break-statement. Requires surrounding for-loop in code generation.");
m_assembly.setSourceLocation(_break.location);
Context::JumpInfo const& jump = m_context->forLoopStack.top().done;
m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight));
checkStackHeight(&_break);
}
void CodeTransform::operator()(Continue const& _continue)
{
yulAssert(!m_context->forLoopStack.empty(), "Invalid continue-statement. Requires surrounding for-loop in code generation.");
m_assembly.setSourceLocation(_continue.location);
Context::JumpInfo const& jump = m_context->forLoopStack.top().post;
m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight));
checkStackHeight(&_continue);
} }
void CodeTransform::operator()(Block const& _block) void CodeTransform::operator()(Block const& _block)

View File

@ -217,6 +217,10 @@ private:
/// and corrects the stack height to the target stack height. /// and corrects the stack height to the target stack height.
void stackError(StackTooDeepError _error, int _targetStackSize); void stackError(StackTooDeepError _error, int _targetStackSize);
/// Ensures stack height is down to @p _targetDepth by appending POP instructions to the output assembly.
/// Returns the number of POP statements that have been appended.
int appendPopUntil(int _targetDepth);
AbstractAssembly& m_assembly; AbstractAssembly& m_assembly;
AsmAnalysisInfo& m_info; AsmAnalysisInfo& m_info;
Scope* m_scope = nullptr; Scope* m_scope = nullptr;

View File

@ -0,0 +1,13 @@
contract C {
function f() public returns (uint i) {
assembly {
for {} lt(i, 10) { i := add(i, 1) }
{
if eq(i, 6) { break }
i := add(i, 1)
}
}
}
}
// ----
// f() -> 6

View File

@ -0,0 +1,13 @@
contract C {
function f() public returns (uint k) {
assembly {
for {let i := 0} lt(i, 10) { i := add(i, 1) }
{
if eq(mod(i, 2), 0) { continue }
k := add(k, 1)
}
}
}
}
// ----
// f() -> 5

View File

@ -0,0 +1,20 @@
contract C {
function f(uint x) public returns (uint i) {
assembly {
for {} lt(i, 10) { i := add(i, 1) }
{
if eq(x, 0) { i := 2 break }
for {} lt(x, 3) { i := 17 x := 9 } {
if eq(x, 1) { continue }
if eq(x, 2) { break }
}
if eq(x, 4) { i := 90 }
}
}
}
}
// ----
// f(uint256): 0 -> 2
// f(uint256): 1 -> 18
// f(uint256): 2 -> 10
// f(uint256): 4 -> 91