Conversation
| | `unreachable` | `0x15` | | trap immediately | | ||
| | `return` | `0x09` | | return zero or one value from this function | | ||
| | `unreachable` | `0x0a` | | trap immediately | | ||
| | `end` | `0x0f` | | end a block, loop, or if | |
There was a problem hiding this comment.
In my postorder design, if has its own endif opcode. block and loop ends have an arity immediate, while in if+else+endif the arity immediate goes on the if to avoid being redundant between the else and the endif. Does your design omit arity immediates on end markers, and if so, how do you determine what to leave on the stack after a block exit?
There was a problem hiding this comment.
A new local AST node stack is created with the start of each effective block (including the if branches) and at the end of the block all the remaining stack elements are the block top level expressions of the effective block so an immediate expression count is not needed.
There was a problem hiding this comment.
Are you saying that the end of the block unconditionally pushes the last AST node of the block onto the AST node stack? This seems inconsistent with the arity-immediate used in br and br_if. If the arity is 0, they have no result-value operands, rather than just unconditionally having one operand.
There was a problem hiding this comment.
On Tue, Mar 29, 2016 at 4:33 PM, Dan Gohman notifications@github.com
wrote:
In BinaryEncoding.md
#628 (comment):|
select|0x05| | select one of two values based on condition |
|br|0x06| relative_depth =varuint32| break that targets a outer nested block |
|br_if|0x07| relative_depth =varuint32| conditional break that targets a outer nested block |
|br_table|0x08| see below | branch table control flow construct |
-|return|0x14| | return zero or one value from this function |
-|unreachable|0x15| | trap immediately |
+|return|0x09| | return zero or one value from this function |
+|unreachable|0x0a| | trap immediately |
+|end|0x0f| | end a block, loop, or if |In my postorder design, if has its own endif opcode. block and loop ends
have an arity immediate, while in if+else+endif the arity immediate goes
on the if to avoid being redundant between the else and the endif. Does
your design omit arity immediates on end markers, and if so, how do you
determine what to leave on the stack after a block exit?Yes, I omit the arities, so that when you fall off the end of the block,
you can have at most one return value (i.e. the last value on the stack). I
think that's sufficient; if you want to use a multi-value block in the
future, you have to use a br with arity. (And I'm still not convinced that
multi-arity blocks and ifs will be a thing in the future).—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/WebAssembly/design/pull/628/files/2766cd2fa08155d85e3e6197cacdf4921a3ff253#r57733287
There was a problem hiding this comment.
At the end of a block the last AST node on that blocks AST node stack is a result node of the block and the other AST nodes are the nodes with discarded expression results - if decoding into an AST tree then they are the AST nodes of the block and the break operators do not affect the number of child expressions that a block has.
The semantics of the arity-immediate used in the break operators is a matter I question! If interpreted as zero representing a single argument nop and 1 representing the values of a single expression then it works just fine. In the case of 0 there is an AST node representing zero values and in the case of 1 there is an AST node for the expression. But these do not affect the number of child nodes of a block which I presumed was what your 'arity immediate' encoded, or was it a type declaration for the block?
There was a problem hiding this comment.
@JSStats I have an implementation of a postorder encoder and decoder using one-value-per-stack-entry, and it: works well, has an elegant path to supporting multi-value expressions (by pushing each value on the stack separately), and is indeed focused on single-pass validation and SSA construction (stack entries represent SSA definitions -- they literally hold an MDefinition* in SM).
Instead of having seperate break0 and break1, my design uses the arity immediate proposal, but with a value-oriented interpretation: instead of specifying how many AST children are present, the arity field specifies how many values to expect. From an SSA construction perspective, actual values are what matter, and void "values" don't contribute to the task at hand.
There was a problem hiding this comment.
@sunfishcode You can have your stack of defs and avoid all the zero-value restrictions by simply pushing an integer count of the number of defs per AST node on the stack after the values - this would just be an implementation detail of how SM represents nodes during decoding. For example:
(nop) -> stack: 0
(i32.const 55) -> stack: (i32.const 55) 1
(block (nop) (i32.const 55)) -> 0 (i32.const 55) 1
This scales to more than one value
(tuple (i32.const 55) (i32.const 56)) -> stack: (i32.const 55) (i32.const 56) 2
And allows:
(i32.eqz (call $fn_returning_two_values_i32_f64))
That does not seem a big burden to avoid all the AST expressiveness restrictions and bloating the encoding with more annotations etc. Would you have any concerns with this solution?
There was a problem hiding this comment.
My concern would be that these extra counts would require extra logic to encode on the stack and to validate, and it's not clear to me what they contribute.
If your concern is dropping individual values of a multi-value expression, this can be implemented with or without these count entries.
There was a problem hiding this comment.
Here is an example of invalid code generation without the counts:
(block (i32.add (i32.const 55) (call $fn_returning_two_values_55_56)))
block_start
(i32.const 55) block_stack: 51
call $fn_returning_two_values_55_56 block_stack: 51 56 55
i32.add block_stack: 51 111
block_end parent_stack: 111
There was a problem hiding this comment.
This seems to be @sunfishcode wip Bug 1259295 - wasm: postorder
|
This should target binary 11 here: #641 |
Add opcodes for
elseandend. Remove theif_elseopcode. Remove counts from blocks and loops.Note also that this PR slightly rearranges the lower opcode space to put all the control operators in order and leave a little hole between
0x0aand0x0ffor adding acatchoperator in the future.