# Control Flow EVM doesn't have instructions for the custom control flows, however zink implements them with `JUMPI` and `JUMP`, which includes: - `if` - `block` - `loop` - `else` - `select` - `br` - `br_if` - `br_table` ## If-Else The beginning of an if construct with an implicit then block, plus and else block. The basic logic is, if non-zero, enter the if block, otherwise jump to the else block or the end of the if condition. ```wasm (if (result i32) (local.get 0) (then (i32.const 7)) (else (i32.const 8))) ``` The expected result is | Input | Result | | ----- | ------ | | 1 | 7 | | 0 | 8 | so in the compiled bytecode, the code snippet above will be ```yul PUSH1 0x00 // Load the params at 0x00 calldataload iszero // if is zero, jump to 0x0c, the else block. PUSH1 0x0c jumpi push1 0x07 // if is non-zero, enters the if block. // push 0x07 on stack. PUSH1 0x0f // jump to the end of the else block. jump jumpdest // destination of the else block, push 0x08 push1 0x08 // on stack. jumpdest // the end of the else block. PUSH1 0x00 // pack the result and return... mstore PUSH1 0x20 PUSH1 0x00 return ``` ## Select The `select (0x1B)` instruction comes from WebAssembly, it selects one of its first two operands based on whether its third operand is zero or not. Simple rust conditions in rust will be compiled to `select`. ```rust pub extern "C" fn if_else(x: u64, y: u64) -> u64 { if x > y { x } else { y } } ``` As we can see in the example above, we simply returns the bigger number from the 2 parameters, the logic in the two blocks of `if-else` is explicit direct, that will be compiled to `select`. ```wasm (module (type (;0;) (func (param i64 i64) (result i64))) (func $if_else (type 0) (param i64 i64) (result i64) local.get 0 local.get 1 local.get 0 local.get 1 i64.gt_u select)) ``` Since EVM doesn't have instruction like `select`, we need to provide it ourselves in our implementation like an external function, if zero pop the value on the top of the stack. ```rust const SELECT: [OpCode; 6] = [ OpCode::JUMPDEST, OpCode::POP, OpCode::PUSH1, OpCode::Data(0x06), OpCode::ADD, OpCode::JUMP, ]; ``` In the compiled code, we need to combine this function `select` with `jumpi` in EVM. ```yul PUSH1 0x00 // Load the parameters. calldataload PUSH1 0x20 calldataload PUSH1 0x00 calldataload PUSH1 0x20 calldataload lt // Compiled to `lt` because of the result of this // instruction is oppsited between EVM and WASM. pc swap2 // shift swap1 PUSH1 0x1c jumpi // `jumpi` for the if condition. JUMPDEST PUSH1 0x00 // Returns the value. mstore PUSH1 0x20 PUSH1 0x00 return JUMPDEST // Function select starts here. pop PUSH1 0x06 add jump ```