Skip to content

Commit 5438c76

Browse files
christianparpartchriseth
authored andcommitted
[yul] Implements EVM codegen for break/continue plus respective tests & ChangeLog entry.
1 parent 889c476 commit 5438c76

File tree

5 files changed

+55
-4
lines changed

5 files changed

+55
-4
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Language Features:
44

55

66
Compiler Features:
7+
* Yul: Adds break and continue keywords to for-loop syntax.
78

89

910
Bugfixes:

libyul/backends/evm/EVMCodeTransform.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -634,14 +634,34 @@ void CodeTransform::operator()(ForLoop const& _forLoop)
634634
checkStackHeight(&_forLoop);
635635
}
636636

637-
void CodeTransform::operator()(Break const&)
637+
int CodeTransform::appendPopUntil(int _targetDepth)
638638
{
639-
yulAssert(false, "Code generation for break statement in Yul is not implemented yet.");
639+
int const stackDiffAfter = m_assembly.stackHeight() - _targetDepth;
640+
for (int i = 0; i < stackDiffAfter; ++i)
641+
m_assembly.appendInstruction(solidity::Instruction::POP);
642+
return stackDiffAfter;
643+
}
644+
645+
void CodeTransform::operator()(Break const& _break)
646+
{
647+
yulAssert(!m_context->forLoopStack.empty(), "Invalid break-statement. Requires surrounding for-loop in code generation.");
648+
m_assembly.setSourceLocation(_break.location);
649+
650+
Context::JumpInfo const& jump = m_context->forLoopStack.top().done;
651+
m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight));
652+
653+
checkStackHeight(&_break);
640654
}
641655

642-
void CodeTransform::operator()(Continue const&)
656+
void CodeTransform::operator()(Continue const& _continue)
643657
{
644-
yulAssert(false, "Code generation for continue statement in Yul is not implemented yet.");
658+
yulAssert(!m_context->forLoopStack.empty(), "Invalid continue-statement. Requires surrounding for-loop in code generation.");
659+
m_assembly.setSourceLocation(_continue.location);
660+
661+
Context::JumpInfo const& jump = m_context->forLoopStack.top().post;
662+
m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight));
663+
664+
checkStackHeight(&_continue);
645665
}
646666

647667
void CodeTransform::operator()(Block const& _block)

libyul/backends/evm/EVMCodeTransform.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ class CodeTransform: public boost::static_visitor<>
217217
/// and corrects the stack height to the target stack height.
218218
void stackError(StackTooDeepError _error, int _targetStackSize);
219219

220+
/// Ensures stack height is down to @p _targetDepth by appending POP instructions to the output assembly.
221+
/// Returns the number of POP statements that have been appended.
222+
int appendPopUntil(int _targetDepth);
223+
220224
AbstractAssembly& m_assembly;
221225
AsmAnalysisInfo& m_info;
222226
Scope* m_scope = nullptr;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
contract C {
2+
function f() public returns (uint i) {
3+
assembly {
4+
for {} lt(i, 10) { i := add(i, 1) }
5+
{
6+
if eq(i, 6) { break }
7+
i := add(i, 1)
8+
}
9+
}
10+
}
11+
}
12+
// ----
13+
// f() -> 6
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
contract C {
2+
function f() public returns (uint k) {
3+
assembly {
4+
for {let i := 0} lt(i, 10) { i := add(i, 1) }
5+
{
6+
if eq(mod(i, 2), 0) { continue }
7+
k := add(k, 1)
8+
}
9+
}
10+
}
11+
}
12+
// ----
13+
// f() -> 5

0 commit comments

Comments
 (0)