[Feature Request] Support do { ... } while (expr); syntax
🚀 Feature Request
Motivation
Gas optimizing, try to be less instructions in code.
module me::test2 {
fun main() {
let i = 0;
loop {
i = i + 1;
i = i + 2;
if (i > 8) {
i = i + 2;
i = i + 3;
i = i + 4;
return
}
}
}
}
Result:
// Move bytecode v6
module d1b58e44ea11ffd326a280c453b080fd.test2 {
main() {
L0: loc0: u64
B0:
0: LdU64(0)
1: StLoc[0](loc0: u64)
B1:
2: MoveLoc[0](loc0: u64)
3: LdU64(1)
4: Add
5: LdU64(2)
6: Add
7: StLoc[0](loc0: u64)
8: CopyLoc[0](loc0: u64)
9: LdU64(8)
10: Gt
11: BrFalse(22)
B2:
12: Branch(13)
B3:
13: MoveLoc[0](loc0: u64)
14: LdU64(2)
15: Add
16: LdU64(3)
17: Add
18: LdU64(4)
19: Add
20: Pop
21: Ret
B4:
22: Branch(2)
}
}
12: Branch(13) is simply wasting gas.
11: BrFalse(22)
22: Branch(2)
Why not just do 11: BrFalse(2) .
i = i + x don't mean anything, I just want say there is some unnecessary branching instructions.
Is your feature request related to a problem? Please describe.
Pitch
Describe the solution you'd like
Describe alternatives you've considered
Are you willing to open a pull request? (See CONTRIBUTING)
Additional context
hi, this code
fun main() {
let i = 0;
while (true) {
i = i + 1;
i = i + 2;
if (i < 9) {
continue
};
i = i + 2;
i = i + 3;
i = i + 4;
break
};
}
generated
main() {
L0: i: u64
B0:
0: LdU64(0)
1: StLoc[0](i: u64)
B1:
2: MoveLoc[0](i: u64)
3: LdU64(1)
4: Add
5: LdU64(2)
6: Add
7: StLoc[0](i: u64)
8: CopyLoc[0](i: u64)
9: LdU64(9)
10: Lt
11: BrFalse(13)
B2:
12: Branch(2)
B3:
13: MoveLoc[0](i: u64)
14: LdU64(2)
15: Add
16: LdU64(3)
17: Add
18: LdU64(4)
19: Add
20: Pop
21: Ret
}
very interesting.
well, it looks loop generates one more branch than while (true). very interesting.
I'm not sure this is expected behavior or not, but
fun main() {
let i = 0;
while (true) {
i = i + 1;
if (i > 5) {
return
}
}
}
generates
main() {
L0: i: u64
B0:
0: LdU64(0)
1: StLoc[0](i: u64)
B1:
2: MoveLoc[0](i: u64)
3: LdU64(1)
4: Add
5: StLoc[0](i: u64)
6: CopyLoc[0](i: u64)
7: LdU64(5)
8: Gt
9: BrFalse(11)
B2:
10: Ret
B3:
11: Branch(2)
}
but,
fun main() {
let i = 0;
loop {
i = i + 1;
if (i > 5) {
return
}
}
}
generates
main() {
L0: i: u64
B0:
0: LdU64(0)
1: StLoc[0](i: u64)
B1:
2: MoveLoc[0](i: u64)
3: LdU64(1)
4: Add
5: StLoc[0](i: u64)
6: CopyLoc[0](i: u64)
7: LdU64(5)
8: Gt
9: BrFalse(12)
B2:
10: Branch(11)
B3:
11: Ret
B4:
12: Branch(2)
}
hi, more interesting idea came up.
fun main() {
let i = 0;
i = i + 2;
i = i + 3;
i = i + 4;
while (true) {
if (i < 18) {
i = i + 1;
i = i + 2;
continue
};
break
}
}
generates
main() {
L0: i#1#0: u64
B0:
0: LdU64(0)
1: LdU64(2)
2: Add
3: LdU64(3)
4: Add
5: LdU64(4)
6: Add
7: StLoc[0](i#1#0: u64)
B1:
8: CopyLoc[0](i#1#0: u64)
9: LdU64(18)
10: Lt
11: BrFalse(19)
B2:
12: MoveLoc[0](i#1#0: u64)
13: LdU64(1)
14: Add
15: LdU64(2)
16: Add
17: StLoc[0](i#1#0: u64)
18: Branch(8)
B3:
19: Ret
}
hi, more interesting idea came up.
fun main() { let i = 0; i = i + 2; i = i + 3; i = i + 4; while (true) { if (i < 18) { i = i + 1; i = i + 2; continue }; break } }generates
main() { L0: i#1#0: u64 B0: 0: LdU64(0) 1: LdU64(2) 2: Add 3: LdU64(3) 4: Add 5: LdU64(4) 6: Add 7: StLoc[0](i#1#0: u64) B1: 8: CopyLoc[0](i#1#0: u64) 9: LdU64(18) 10: Lt 11: BrFalse(19) B2: 12: MoveLoc[0](i#1#0: u64) 13: LdU64(1) 14: Add 15: LdU64(2) 16: Add 17: StLoc[0](i#1#0: u64) 18: Branch(8) B3: 19: Ret }
Interesting but still not on be optimized. I would like suppose be
2: MoveLoc[0](loc0: u64)
3: LdU64(1)
4: Add
5: LdU64(2)
6: Add
7: StLoc[0](loc0: u64)
8: CopyLoc[0](loc0: u64)
9: LdU64(18)
10: Gt
11: BrFalse(2)
I wish we could programming in assembly lol
you can actually. move ir is available. https://github.com/move-language/move/tree/main/language/move-ir-compiler https://github.com/move-language/move/tree/main/language/move-vm/transactional-tests/tests/control_flow
you can actually. move ir is available. https://github.com/move-language/move/tree/main/language/move-ir-compiler https://github.com/move-language/move/tree/main/language/move-vm/transactional-tests/tests/control_flow
Interesting!