From 981123a63e0108bc0b67343ed245586c065d0f37 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 13 Aug 2015 06:29:36 -0800 Subject: [PATCH 1/3] Simplify the control-flow operators. This decomposes high-level control structures into low-level primitive operations. `break` becomes a generalized "branch forward" and `continue` becomes a generalized "branch backward". Along with `switch`, this is sufficient to represent all control transfers, making specialized constructs redundant. --- AstSemantics.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/AstSemantics.md b/AstSemantics.md index c559e0c6..6b7f7ce8 100644 --- a/AstSemantics.md +++ b/AstSemantics.md @@ -258,22 +258,22 @@ others, etc. WebAssembly offers basic structured control flow. All control flow structures are statements. - * `block`: a fixed-length sequence of statements - * `if`: if statement - * `do_while`: do while statement, basically a loop with a conditional branch - (back to the top of the loop) - * `forever`: infinite loop statement (like `while (1)`), basically an - unconditional branch (back to the top of the loop) - * `continue`: continue to start of nested loop - * `break`: break to end from nested loop or block + * `block`: a fixed-length sequence of statements that may be exited early via a `break` + * `loop`: a fixed-length sequence of statements that may be restarted at the beginning via a `continue` + * `break`: exit a lexically enclosing `block` + * `break_if`: like `break`, but has a `bool` operand and does nothing if the operand is false + * `continue`: restart a lexically enclosing `loop` + * `continue_if`: like `continue`, but has a `bool` operand and does nothing if the operand is false * `return`: return zero or more values from this function * `switch`: switch statement with fallthrough -Loops (`do_while` and `forever`) may only be entered via fallthrough at the top. -In particular, loops may not be entered directly via a `break`, `continue`, or -`switch` destination. Break and continue statements can only target blocks or -loops in which they are nested. These rules guarantee that all control flow -graphs are well-structured. +`break` and `break_if` specify a lexically enclosing `block` to exit from, +which need not be the innermost `block`. `continue` and `continue_if` specify a +lexically enclosing `loop` to restart, which need not be the innermost `loop`. + +As a consequence of these rules and the nesting structure of the AST, `block` +and `loop` nodes may only be entered via fallthrough at the top. These rules +guarantee that all control flow graphs are well-structured. Structured control flow provides simple and size-efficient binary encoding and compilation. Any control flow—even irreducible—can be transformed into structured From d2b38c3254391f1e21b215946d88eb4ca5554add Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 13 Aug 2015 06:29:43 -0800 Subject: [PATCH 2/3] Add a `select` operator, to take the place of if-else blocks. This isn't strictly necessary, but it closely corresponds to conditional-move instructions in common ISAs, and it fills a common need with the removal if if-else. --- AstSemantics.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AstSemantics.md b/AstSemantics.md index 6b7f7ce8..646bd291 100644 --- a/AstSemantics.md +++ b/AstSemantics.md @@ -403,6 +403,7 @@ results into the result type. * `i32.clz`: sign-agnostic count leading zero bits (defined for all values, including zero) * `i32.ctz`: sign-agnostic count trailing zero bits (defined for all values, including zero) * `i32.popcnt`: sign-agnostic count number of one bits + * `int32.select`: select between two values with a condition (not short-circuiting) Shifts interpret their shift count operand as an unsigned value. When the shift count is at least the bitwidth of the shift, `shl` and `shr_u` produce `0`, and @@ -421,8 +422,8 @@ The same operations are available on 64-bit integers as the those available for Floating point arithmetic follows the IEEE 754-2008 standard, except that: - The sign bit and significand bit pattern of any NaN value returned from a - floating point arithmetic operation other than `neg`, `abs`, and `copysign` - are not specified. In particular, the "NaN propagation" + floating point arithmetic operation other than `neg`, `abs`, `copysign`, + and `select` are not specified. In particular, the "NaN propagation" section of IEEE 754-2008 is not required. NaNs do propagate through arithmetic operations according to IEEE 754-2008 rules, the difference here is that they do so without necessarily preserving the specific bit patterns @@ -467,6 +468,7 @@ implementations of the remaining required operations. * `f32.sqrt`: square root * `f32.min`: minimum (binary operator); if either operand is NaN, returns NaN * `f32.max`: maximum (binary operator); if either operand is NaN, returns NaN + * `float32.select`: select between two values with a condition (not short-circuiting) * `f64.add`: addition * `f64.sub`: subtraction @@ -488,6 +490,7 @@ implementations of the remaining required operations. * `f64.sqrt`: square root * `f64.min`: minimum (binary operator); if either operand is NaN, returns NaN * `f64.max`: maximum (binary operator); if either operand is NaN, returns NaN + * `float64.select`: select between two values with a condition (not short-circuiting) `min` and `max` operations treat `-0.0` as being effectively less than `0.0`. From 5319e94aea63269d290349bf64c18cb431ce2bfb Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 14 Sep 2015 15:30:13 -0700 Subject: [PATCH 3/3] Eliminate the break/continue distinction, and convert `switch`. --- AstSemantics.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/AstSemantics.md b/AstSemantics.md index 646bd291..5c422e31 100644 --- a/AstSemantics.md +++ b/AstSemantics.md @@ -258,18 +258,18 @@ others, etc. WebAssembly offers basic structured control flow. All control flow structures are statements. - * `block`: a fixed-length sequence of statements that may be exited early via a `break` - * `loop`: a fixed-length sequence of statements that may be restarted at the beginning via a `continue` - * `break`: exit a lexically enclosing `block` - * `break_if`: like `break`, but has a `bool` operand and does nothing if the operand is false - * `continue`: restart a lexically enclosing `loop` - * `continue_if`: like `continue`, but has a `bool` operand and does nothing if the operand is false + * `block`: a fixed-length sequence of statements with a branch target at the end + * `loop`: a fixed-length sequence of statements with a branch target at the beginning + * `br`: branch to the branch target of a lexically enclosing `block` or `loop` + * `br_if`: like `br`, but has a `bool` operand and does nothing if the operand is false + * `br_unless`: like `br`, but has a `bool` operand and does nothing if the operand is true * `return`: return zero or more values from this function - * `switch`: switch statement with fallthrough + * `switch`: like `br_if` but has an integer operand, an arbitrary number of possible + branch targets, and a default branch target. -`break` and `break_if` specify a lexically enclosing `block` to exit from, -which need not be the innermost `block`. `continue` and `continue_if` specify a -lexically enclosing `loop` to restart, which need not be the innermost `loop`. +`br`, `br_if`, `br_unless`, and `switch` specify branch targets of lexically +enclosing `block` and `loop` constructs, which need not be the innermost `block` +or `loop`. As a consequence of these rules and the nesting structure of the AST, `block` and `loop` nodes may only be entered via fallthrough at the top. These rules