;; The idea is - we have 4 blocks, one inside another. We enter subsequent ;; blocks (how many we enter, depends on $blockfun's first arg) and then we ;; start leaving them. We "normally" (e.g. without br) exit some blocks (number ;; depending on $blockfun's 2nd arg) and then we break out of the outermost one ;; with the use of br_if. ;; When making this "path" through blocks, we also construct a result value. ;; The result value is initially 0 and upon each "normal" exit from a block, ;; one bit is being set to 1 in the result. Which bit is set, depends on the ;; block being left. Block 1 sets bit 0, block 2 sets bit 1, etc. ;; So, the entire function actually computes an integer with bits a1-a2 through ;; a1 set, with a1 and a2 being arguments to the function. ;; To keep things simple, we limit this to 4 block and 4 bits, that can be set (module (memory 0 1) (func $blockfun (param $blocks_to_enter i32) (param $ones_to_set i32) (result i32) i32.const 0 ;; initial result value get_local $blocks_to_enter i32.const 0 i32.eq br_if 0 ;; if number of blocks to enter is 0 - just return block $b1 (param i32) (result i32) get_local $blocks_to_enter i32.const 1 i32.sub set_local $blocks_to_enter get_local $blocks_to_enter if (param i32) (result i32) block $b2 (param i32) (result i32) get_local $blocks_to_enter i32.const 1 i32.sub set_local $blocks_to_enter get_local $blocks_to_enter if (param i32) (result i32) block $b3 (param i32) (result i32) get_local $blocks_to_enter i32.const 1 i32.sub set_local $blocks_to_enter get_local $blocks_to_enter if (param i32) (result i32) block $b4 (param i32) (result i32) get_local $ones_to_set i32.const 0 i32.eq br_if $b1 get_local $ones_to_set i32.const 1 i32.sub set_local $ones_to_set i32.const 8 ;; block $b4 adds (1 << 3) to the result i32.add end end get_local $ones_to_set i32.const 0 i32.eq br_if $b1 get_local $ones_to_set i32.const 1 i32.sub set_local $ones_to_set i32.const 4 ;; block $b3 adds (1 << 2) to the result i32.add end end get_local $ones_to_set i32.const 0 i32.eq br_if $b1 get_local $ones_to_set i32.const 1 i32.sub set_local $ones_to_set i32.const 2 ;; block $b2 adds (1 << 1) to the result i32.add end end get_local $ones_to_set i32.const 0 i32.eq br_if $b1 get_local $ones_to_set i32.const 1 i32.sub set_local $ones_to_set i32.const 1 ;; block $b1 adds (1 << 0) to the result i32.add end) (func $main (i32.store offset=0x0 align=4 (i32.const 0x0) (call $blockfun (i32.const 4) (i32.const 2))) (i32.store offset=0x0 align=4 (i32.const 0x4) (call $blockfun (i32.const 3) (i32.const 2))) (i32.store offset=0x0 align=4 (i32.const 0x8) (call $blockfun (i32.const 2) (i32.const 0))) (i32.store offset=0x0 align=4 (i32.const 0xC) (call $blockfun (i32.const 4) (i32.const 4))) ) (export "main" (func $main)))