-
Notifications
You must be signed in to change notification settings - Fork 701
Add postorder opcodes #628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -317,18 +317,20 @@ It is legal to have several entries with the same type. | |
| | Name | Opcode | Immediate | Description | | ||
| | ---- | ---- | ---- | ---- | | ||
| | `nop` | `0x00` | | no operation | | ||
| | `block` | `0x01` | count = `varuint32` | a sequence of expressions, the last of which yields a value | | ||
| | `loop` | `0x02` | count = `varuint32` | a block which can also form control flow loops | | ||
| | `if` | `0x03` | | high-level one-armed if | | ||
| | `if_else` | `0x04` | | high-level two-armed if | | ||
| | `block` | `0x01` | | begin a sequence of expressions, the last of which yields a value | | ||
| | `loop` | `0x02` | | begin a block which can also form control flow loops | | ||
| | `if` | `0x03` | | begin if expression | | ||
| | `else` | `0x04` | | begin else expression of if | | ||
| | `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 | | ||
|
|
||
| The `br_table` operator has an immediate operand which is encoded as follows: | ||
| Note that there is no explicit `if_else` opcode, as the else clause is encoded with the `else` bytecode. | ||
|
|
||
| | Field | Type | Description | | ||
| | ---- | ---- | ---- | | ||
|
|
@@ -343,15 +345,15 @@ out of range, `br_table` branches to the default target. | |
| ## Basic operators ([described here](AstSemantics.md#constants)) | ||
| | Name | Opcode | Immediate | Description | | ||
| | ---- | ---- | ---- | ---- | | ||
| | `i32.const` | `0x0a` | value = `varint32` | a constant value interpreted as `i32` | | ||
| | `i64.const` | `0x0b` | value = `varint64` | a constant value interpreted as `i64` | | ||
| | `f64.const` | `0x0c` | value = `uint64` | a constant value interpreted as `f64` | | ||
| | `f32.const` | `0x0d` | value = `uint32` | a constant value interpreted as `f32` | | ||
| | `get_local` | `0x0e` | local_index = `varuint32` | read a local variable or parameter | | ||
| | `set_local` | `0x0f` | local_index = `varuint32` | write a local variable or parameter | | ||
| | `call` | `0x12` | function_index = `varuint32` | call a function by its index | | ||
| | `call_indirect` | `0x13` | signature_index = `varuint32` | call a function indirect with an expected signature | | ||
| | `call_import` | `0x1f` | import_index = `varuint32` | call an imported function by its index | | ||
| | `i32.const` | `0x10` | value = `varint32` | a constant value interpreted as `i32` | | ||
| | `i64.const` | `0x11` | value = `varint64` | a constant value interpreted as `i64` | | ||
| | `f64.const` | `0x12` | value = `uint64` | a constant value interpreted as `f64` | | ||
| | `f32.const` | `0x13` | value = `uint32` | a constant value interpreted as `f32` | | ||
| | `get_local` | `0x14` | local_index = `varuint32` | read a local variable or parameter | | ||
| | `set_local` | `0x15` | local_index = `varuint32` | write a local variable or parameter | | ||
| | `call` | `0x16` | function_index = `varuint32` | call a function by its index | | ||
| | `call_indirect` | `0x17` | signature_index = `varuint32` | call a function indirect with an expected signature | | ||
| | `call_import` | `0x18` | import_index = `varuint32` | call an imported function by its index | | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the plan to add an operator table there seems little need to be re-organising now or plan for a |
||
| ## Memory-related operators ([described here](AstSemantics.md#linear-memory-accesses)) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my postorder design,
ifhas its ownendifopcode.blockandloopends have an arity immediate, while inif+else+endifthe arity immediate goes on theifto avoid being redundant between theelseand theendif. Does your design omit arity immediates onendmarkers, and if so, how do you determine what to leave on the stack after a block exit?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A new local AST node stack is created with the start of each effective block (including the
ifbranches) 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
brandbr_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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Tue, Mar 29, 2016 at 4:33 PM, Dan Gohman notifications@github.com
wrote:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
nopand 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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
break0andbreak1, 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, andvoid"values" don't contribute to the task at hand.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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:
This scales to more than one value
And allows:
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an example of invalid code generation without the counts:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be @sunfishcode wip Bug 1259295 - wasm: postorder