move icon indicating copy to clipboard operation
move copied to clipboard

[Feature Request] Support do { ... } while (expr); syntax

Open ghost opened this issue 2 years ago • 7 comments

🚀 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

ghost avatar Feb 17 '23 23:02 ghost

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.

honehone12 avatar Feb 22 '23 11:02 honehone12

well, it looks loop generates one more branch than while (true). very interesting.

honehone12 avatar Feb 22 '23 11:02 honehone12

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)
}

honehone12 avatar Feb 22 '23 12:02 honehone12

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
}

honehone12 avatar Feb 23 '23 06:02 honehone12

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

e99243506bigplay avatar Feb 23 '23 06:02 e99243506bigplay

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

honehone12 avatar Feb 23 '23 07:02 honehone12

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!

e99243506bigplay avatar Feb 23 '23 08:02 e99243506bigplay