aboutsummaryrefslogtreecommitdiffstats
path: root/liblll
diff options
context:
space:
mode:
authorbenjaminion <ben@edginet.org>2017-07-22 14:57:38 +0800
committerAlex Beregszaszi <alex@rtfs.hu>2017-10-02 19:01:15 +0800
commit326c7887a42a04b9e27e8ddb4d8c8d0715d814e1 (patch)
treefb0c62a248eed3a20721446986ae88a61f16c0f4 /liblll
parentc61610302aa2bfa029715b534719d25fe3949059 (diff)
downloaddexon-solidity-326c7887a42a04b9e27e8ddb4d8c8d0715d814e1.tar.gz
dexon-solidity-326c7887a42a04b9e27e8ddb4d8c8d0715d814e1.tar.zst
dexon-solidity-326c7887a42a04b9e27e8ddb4d8c8d0715d814e1.zip
LLL: Implement a switch expression.
Diffstat (limited to 'liblll')
-rw-r--r--liblll/CodeFragment.cpp38
1 files changed, 38 insertions, 0 deletions
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 254f436f..a7cb3699 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -514,6 +514,44 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.appendJump(begin);
m_asm << end.tag();
}
+ else if (us == "SWITCH")
+ {
+ requireMinSize(1);
+
+ bool hasDefault = (code.size() % 2 == 1);
+ int startDeposit = m_asm.deposit();
+ int targetDeposit = hasDefault ? code[code.size() - 1].m_asm.deposit() : 0;
+
+ // The conditions
+ AssemblyItems jumpTags;
+ for (unsigned i = 0; i < code.size() - 1; i += 2)
+ {
+ requireDeposit(i, 1);
+ m_asm.append(code[i].m_asm);
+ jumpTags.push_back(m_asm.appendJumpI());
+ }
+
+ // The default, if present
+ if (hasDefault)
+ m_asm.append(code[code.size() - 1].m_asm);
+
+ // The targets - appending in reverse makes the top case the most efficient.
+ if (code.size() > 1)
+ {
+ auto end = m_asm.appendJump();
+ for (int i = 2 * (code.size() / 2 - 1); i >= 0; i -= 2)
+ {
+ m_asm << jumpTags[i / 2].tag();
+ requireDeposit(i + 1, targetDeposit);
+ m_asm.append(code[i + 1].m_asm);
+ if (i != 0)
+ m_asm.appendJump(end);
+ }
+ m_asm << end.tag();
+ }
+
+ m_asm.setDeposit(startDeposit + targetDeposit);
+ }
else if (us == "ALLOC")
{
requireSize(1);