Backed out changeset 15a3458b4d11 (bug 1254142) for bustage. r=backout on a CLOSED TREE
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 30 Mar 2016 14:27:34 +0200
changeset 291064 be61ede92adbcad7000db7ba128276ced1ce73b2
parent 291063 69a7e03cf1f8ee309ab4bf38d1761693a30191d2
child 291065 88df6d5a1f21bd9c8298f3503620a9647ef3d857
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1254142
milestone48.0a1
backs out15a3458b4d114f6494370c5eae2583e77e6c73f5
Backed out changeset 15a3458b4d11 (bug 1254142) for bustage. r=backout on a CLOSED TREE
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmIonCompile.cpp
js/src/asmjs/WasmTextToBinary.cpp
js/src/jit-test/tests/wasm/basic-control-flow.js
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -554,22 +554,25 @@ static bool
 DecodeBranch(FunctionDecoder& f, Expr expr, ExprType* type)
 {
     MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf);
 
     uint32_t relativeDepth;
     if (!f.d().readVarU32(&relativeDepth))
         return f.fail("expected relative depth");
 
-    ExprType brType;
-    if (!DecodeExpr(f, &brType))
+    if (!f.branchWithType(relativeDepth, ExprType::Void))
+        return f.fail("branch depth exceeds current nesting level");
+
+    Expr value;
+    if (!f.d().readExpr(&value))
         return f.fail("expected branch value");
 
-    if (!f.branchWithType(relativeDepth, brType))
-        return f.fail("branch depth exceeds current nesting level");
+    if (value != Expr::Nop)
+        return f.fail("NYI: branch values");
 
     if (expr == Expr::BrIf) {
         ExprType actual;
         if (!DecodeExpr(f, &actual))
             return false;
 
         if (!CheckType(f, actual, ValType::I32))
             return false;
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -12,19 +12,16 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "asmjs/WasmIonCompile.h"
-
-#include <functional>
-
 #include "asmjs/WasmGenerator.h"
 
 #include "jit/CodeGenerator.h"
 
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
 
@@ -936,46 +933,56 @@ class FunctionCompiler
   private:
     static bool hasPushed(MBasicBlock* block)
     {
         uint32_t numPushed = block->stackDepth() - block->info().firstStackSlot();
         MOZ_ASSERT(numPushed == 0 || numPushed == 1);
         return numPushed;
     }
 
+    static void push(MBasicBlock* block, MDefinition* def)
+    {
+        MOZ_ASSERT(!hasPushed(block));
+        block->push(def);
+    }
+
+    static void popAll(BlockVector* blocks)
+    {
+        for (MBasicBlock* block : *blocks)
+            block->pop();
+    }
+
   public:
-    void pushDef(MDefinition* def)
+    bool addJoinPredecessor(MDefinition* def, BlockVector* blocks)
     {
         if (inDeadCode())
-            return;
-        MOZ_ASSERT(!hasPushed(curBlock_));
-        if (def && def->type() != MIRType_None)
-            curBlock_->push(def);
-    }
-
-    typedef std::function<MBasicBlock*(size_t)> GetBlockFunction;
-
-    void ensurePushInvariants(GetBlockFunction getBlock, size_t numBlocks)
-    {
-        // Preserve the invariant that, for every iterated MBasicBlock,
+            return true;
+
+        // Preserve the invariant that, for every MBasicBlock in 'blocks',
         // either: every MBasicBlock has a non-void pushed expression OR no
         // MBasicBlock has any pushed expression. This is required by
         // MBasicBlock::addPredecessor.
-        bool allPushed = true;
-
-        for (size_t i = 0; allPushed && i < numBlocks; i++)
-            allPushed = hasPushed(getBlock(i));
-
-        if (!allPushed) {
-            for (size_t i = 0; i < numBlocks; i++) {
-                MBasicBlock* block = getBlock(i);
-                if (hasPushed(block))
-                    block->pop();
+        if (def) {
+            if (blocks->empty()) {
+                if (def->type() != MIRType_None)
+                    push(curBlock_, def);
+            } else {
+                if (hasPushed((*blocks)[0])) {
+                    if (def->type() == MIRType_None)
+                        popAll(blocks);
+                    else
+                        push(curBlock_, def);
+                }
             }
+        } else {
+            if (!blocks->empty() && hasPushed((*blocks)[0]))
+                popAll(blocks);
         }
+
+        return blocks->append(curBlock_);
     }
 
     bool joinIf(MBasicBlock* joinBlock, BlockVector* blocks, MDefinition** def)
     {
         MOZ_ASSERT_IF(curBlock_, blocks->back() == curBlock_);
         curBlock_ = joinBlock;
         return joinIfElse(nullptr, blocks, def);
     }
@@ -983,32 +990,21 @@ class FunctionCompiler
     void switchToElse(MBasicBlock* elseBlock)
     {
         if (!elseBlock)
             return;
         curBlock_ = elseBlock;
         mirGraph().moveBlockToEnd(curBlock_);
     }
 
-    bool addJoinPredecessor(MDefinition* def, BlockVector* blocks)
-    {
-        if (inDeadCode())
-            return true;
-        pushDef(def);
-        return blocks->append(curBlock_);
-    }
-
     bool joinIfElse(MDefinition* elseDef, BlockVector* blocks, MDefinition** def)
     {
         if (!addJoinPredecessor(elseDef, blocks))
             return false;
 
-        auto getBlock = [&](size_t i) -> MBasicBlock* { return (*blocks)[i]; };
-        ensurePushInvariants(getBlock, blocks->length());
-
         if (blocks->empty()) {
             *def = nullptr;
             return true;
         }
 
         MBasicBlock* join;
         if (!goToNewBlock((*blocks)[0], &join))
             return false;
@@ -1027,21 +1023,21 @@ class FunctionCompiler
 
     bool startBlock()
     {
         MOZ_ASSERT_IF(blockDepth_ < blockPatches_.length(), blockPatches_[blockDepth_].empty());
         blockDepth_++;
         return true;
     }
 
-    bool finishBlock(MDefinition** def)
+    bool finishBlock()
     {
         MOZ_ASSERT(blockDepth_);
         uint32_t topLabel = --blockDepth_;
-        return bindBranches(topLabel, def);
+        return bindBranches(topLabel);
     }
 
     bool startLoop(MBasicBlock** loopHeader)
     {
         *loopHeader = nullptr;
 
         blockDepth_ += 2;
         loopDepth_++;
@@ -1072,28 +1068,33 @@ class FunctionCompiler
     {
         for (size_t i = 0, depth = b->stackDepth(); i < depth; i++) {
             MDefinition* def = b->getSlot(i);
             if (def->isUnused())
                 b->setSlot(i, def->toPhi()->getOperand(0));
         }
     }
 
-    bool setLoopBackedge(MBasicBlock* loopEntry, MBasicBlock* loopBody, MBasicBlock* backedge)
+    bool setLoopBackedge(MBasicBlock* loopEntry, MBasicBlock* loopBody, MBasicBlock* backedge,
+                         MDefinition** loopResult)
     {
         if (!loopEntry->setBackedgeAsmJS(backedge))
             return false;
 
         // Flag all redundant phis as unused.
         for (MPhiIterator phi = loopEntry->phisBegin(); phi != loopEntry->phisEnd(); phi++) {
             MOZ_ASSERT(phi->numOperands() == 2);
             if (phi->getOperand(0) == phi->getOperand(1))
                 phi->setUnused();
         }
 
+        // The loop result may also be referencing a recycled phi.
+        if (*loopResult && (*loopResult)->isUnused())
+            *loopResult = (*loopResult)->toPhi()->getOperand(0);
+
         // Fix up phis stored in the slots Vector of pending blocks.
         for (ControlFlowPatchVector& patches : blockPatches_) {
             for (ControlFlowPatch& p : patches) {
                 MBasicBlock* block = p.ins->block();
                 if (block->loopDepth() >= loopEntry->loopDepth())
                     fixupRedundantPhis(block);
             }
         }
@@ -1137,37 +1138,33 @@ class FunctionCompiler
         // Expr::Loop doesn't have an implicit backedge so temporarily set
         // aside the end of the loop body to bind backedges.
         MBasicBlock* loopBody = curBlock_;
         curBlock_ = nullptr;
 
         // TODO (bug 1253544): blocks branching to the top join to a single
         // backedge block. Could they directly be set as backedges of the loop
         // instead?
-        MDefinition* _;
-        if (!bindBranches(headerLabel, &_))
+        if (!bindBranches(headerLabel))
             return false;
 
         MOZ_ASSERT(loopHeader->loopDepth() == loopDepth_);
 
         if (curBlock_) {
             // We're on the loop backedge block, created by bindBranches.
-            if (hasPushed(curBlock_))
-                curBlock_->pop();
-
             MOZ_ASSERT(curBlock_->loopDepth() == loopDepth_);
             curBlock_->end(MGoto::New(alloc(), loopHeader));
-            if (!setLoopBackedge(loopHeader, loopBody, curBlock_))
+            if (!setLoopBackedge(loopHeader, loopBody, curBlock_, loopResult))
                 return false;
         }
 
         curBlock_ = loopBody;
 
         loopDepth_--;
-        if (!bindBranches(afterLabel, loopResult))
+        if (!bindBranches(afterLabel))
             return false;
 
         // If we have not created a new block in bindBranches, we're still on
         // the inner loop body, which loop depth is incorrect.
         if (curBlock_ && curBlock_->loopDepth() != loopDepth_) {
             MBasicBlock* out;
             if (!goToNewBlock(curBlock_, &out))
                 return false;
@@ -1183,47 +1180,43 @@ class FunctionCompiler
         uint32_t absolute = blockDepth_ - 1 - relative;
 
         if (absolute >= blockPatches_.length() && !blockPatches_.resize(absolute + 1))
             return false;
 
         return blockPatches_[absolute].append(ControlFlowPatch(ins, index));
     }
 
-    bool br(uint32_t relativeDepth, MDefinition* maybeValue)
+    bool br(uint32_t relativeDepth)
     {
         if (inDeadCode())
             return true;
 
         MGoto* jump = MGoto::NewAsm(alloc());
         if (!addControlFlowPatch(jump, relativeDepth, MGoto::TargetIndex))
             return false;
 
-        pushDef(maybeValue);
-
         curBlock_->end(jump);
         curBlock_ = nullptr;
         return true;
     }
 
-    bool brIf(uint32_t relativeDepth, MDefinition* maybeValue, MDefinition* condition)
+    bool brIf(uint32_t relativeDepth, MDefinition* condition)
     {
         if (inDeadCode())
             return true;
 
         MBasicBlock* joinBlock = nullptr;
         if (!newBlock(curBlock_, &joinBlock))
             return false;
 
         MTest* test = MTest::NewAsm(alloc(), condition, joinBlock);
         if (!addControlFlowPatch(test, relativeDepth, MTest::TrueBranchIndex))
             return false;
 
-        pushDef(maybeValue);
-
         curBlock_->end(test);
         curBlock_ = joinBlock;
         return true;
     }
 
     bool brTable(MDefinition* expr, uint32_t defaultDepth, const Uint32Vector& depths)
     {
         if (inDeadCode())
@@ -1322,31 +1315,24 @@ class FunctionCompiler
     bool goToExistingBlock(MBasicBlock* prev, MBasicBlock* next)
     {
         MOZ_ASSERT(prev);
         MOZ_ASSERT(next);
         prev->end(MGoto::New(alloc(), next));
         return next->addPredecessor(alloc(), prev);
     }
 
-    bool bindBranches(uint32_t absolute, MDefinition** def)
+    bool bindBranches(uint32_t absolute)
     {
-        if (absolute >= blockPatches_.length() || blockPatches_[absolute].empty()) {
-            *def = !inDeadCode() && hasPushed(curBlock_) ? curBlock_->pop() : nullptr;
+        if (absolute >= blockPatches_.length())
             return true;
-        }
 
         ControlFlowPatchVector& patches = blockPatches_[absolute];
-
-        auto getBlock = [&](size_t i) -> MBasicBlock* {
-            if (i < patches.length())
-                return patches[i].ins->block();
-            return curBlock_;
-        };
-        ensurePushInvariants(getBlock, patches.length() + !!curBlock_);
+        if (patches.empty())
+            return true;
 
         MBasicBlock* join = nullptr;
         MControlInstruction* ins = patches[0].ins;
         if (!newBlock(ins->block(), &join))
             return false;
 
         ins->replaceSuccessor(patches[0].index, join);
 
@@ -1356,18 +1342,16 @@ class FunctionCompiler
                 return false;
             ins->replaceSuccessor(patches[i].index, join);
         }
 
         if (curBlock_ && !goToExistingBlock(curBlock_, join))
             return false;
         curBlock_ = join;
 
-        *def = hasPushed(curBlock_) ? curBlock_->pop() : nullptr;
-
         patches.clear();
         return true;
     }
 };
 
 static bool
 EmitLiteral(FunctionCompiler& f, ValType type, MDefinition** def)
 {
@@ -2541,20 +2525,20 @@ EmitLoop(FunctionCompiler& f, MDefinitio
     f.addInterruptCheck();
 
     if (uint32_t numStmts = f.readVarU32()) {
         for (uint32_t i = 0; i < numStmts - 1; i++) {
             MDefinition* _;
             if (!EmitExpr(f, &_))
                 return false;
         }
-        MDefinition* last = nullptr;
-        if (!EmitExpr(f, &last))
+        if (!EmitExpr(f, def))
             return false;
-        f.pushDef(last);
+    } else {
+        *def = nullptr;
     }
 
     return f.closeLoop(loopHeader, def);
 }
 
 static bool
 EmitIfElse(FunctionCompiler& f, Expr op, MDefinition** def)
 {
@@ -2619,17 +2603,17 @@ EmitBrTable(FunctionCompiler& f, MDefini
     MDefinition* index;
     if (!EmitExpr(f, &index))
         return false;
 
     *def = nullptr;
 
     // Empty table
     if (!numCases)
-        return f.br(defaultDepth, nullptr);
+        return f.br(defaultDepth);
 
     return f.brTable(index, defaultDepth, depths);
 }
 
 static bool
 EmitReturn(FunctionCompiler& f, MDefinition** def)
 {
     ExprType ret = f.sig().ret();
@@ -2659,48 +2643,46 @@ EmitUnreachable(FunctionCompiler& f, MDe
 
 static bool
 EmitBlock(FunctionCompiler& f, MDefinition** def)
 {
     if (!f.startBlock())
         return false;
     if (uint32_t numStmts = f.readVarU32()) {
         for (uint32_t i = 0; i < numStmts - 1; i++) {
-            MDefinition* _ = nullptr;
+            MDefinition* _;
             if (!EmitExpr(f, &_))
                 return false;
         }
-        MDefinition* last = nullptr;
-        if (!EmitExpr(f, &last))
+        if (!EmitExpr(f, def))
             return false;
-        f.pushDef(last);
+    } else {
+        *def = nullptr;
     }
-    return f.finishBlock(def);
+    return f.finishBlock();
 }
 
 static bool
 EmitBranch(FunctionCompiler& f, Expr op, MDefinition** def)
 {
     MOZ_ASSERT(op == Expr::Br || op == Expr::BrIf);
 
     uint32_t relativeDepth = f.readVarU32();
 
-    MDefinition* maybeValue = nullptr;
-    if (!EmitExpr(f, &maybeValue))
-        return false;
+    MOZ_ALWAYS_TRUE(f.readExpr() == Expr::Nop);
 
     if (op == Expr::Br) {
-        if (!f.br(relativeDepth, maybeValue))
+        if (!f.br(relativeDepth))
             return false;
     } else {
         MDefinition* condition;
         if (!EmitExpr(f, &condition))
             return false;
 
-        if (!f.brIf(relativeDepth, maybeValue, condition))
+        if (!f.brIf(relativeDepth, condition))
             return false;
     }
 
     *def = nullptr;
     return true;
 }
 
 static bool
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -320,32 +320,28 @@ class WasmAstBlock : public WasmAstExpr
     const WasmAstExprVector& exprs() const { return exprs_; }
 };
 
 class WasmAstBranch : public WasmAstExpr
 {
     Expr expr_;
     WasmAstExpr* cond_;
     WasmRef target_;
-    WasmAstExpr* value_;
 
   public:
     static const WasmAstExprKind Kind = WasmAstExprKind::Branch;
-    explicit WasmAstBranch(Expr expr, WasmAstExpr* cond, WasmRef target, WasmAstExpr* value)
+    explicit WasmAstBranch(Expr expr, WasmAstExpr* cond, WasmRef target)
       : WasmAstExpr(Kind),
         expr_(expr),
         cond_(cond),
-        target_(target),
-        value_(value)
+        target_(target)
     {}
-
     Expr expr() const { return expr_; }
     WasmRef& target() { return target_; }
     WasmAstExpr& cond() const { MOZ_ASSERT(cond_); return *cond_; }
-    WasmAstExpr* maybeValue() const { return value_; }
 };
 
 class WasmAstCall : public WasmAstExpr
 {
     Expr expr_;
     WasmRef func_;
     WasmAstExprVector args_;
 
@@ -2077,40 +2073,24 @@ static WasmAstBranch*
 ParseBranch(WasmParseContext& c, Expr expr)
 {
     MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf);
 
     WasmRef target;
     if (!c.ts.matchRef(&target, c.error))
         return nullptr;
 
-    WasmAstExpr* value = nullptr;
-    if (c.ts.getIf(WasmToken::OpenParen)) {
-        value = ParseExprInsideParens(c);
-        if (!value)
-            return nullptr;
-        if (!c.ts.match(WasmToken::CloseParen, c.error))
-            return nullptr;
-    }
-
     WasmAstExpr* cond = nullptr;
     if (expr == Expr::BrIf) {
-        if (c.ts.getIf(WasmToken::OpenParen)) {
-            cond = ParseExprInsideParens(c);
-            if (!cond)
-                return nullptr;
-            if (!c.ts.match(WasmToken::CloseParen, c.error))
-                return nullptr;
-        } else {
-            cond = value;
-            value = nullptr;
-        }
+        cond = ParseExpr(c);
+        if (!cond)
+            return nullptr;
     }
 
-    return new(c.lifo) WasmAstBranch(expr, cond, target, value);
+    return new(c.lifo) WasmAstBranch(expr, cond, target);
 }
 
 static bool
 ParseArgs(WasmParseContext& c, WasmAstExprVector* args)
 {
     while (c.ts.getIf(WasmToken::OpenParen)) {
         WasmAstExpr* arg = ParseExprInsideParens(c);
         if (!arg || !args->append(arg))
@@ -3624,17 +3604,17 @@ EncodeBranch(Encoder& e, WasmAstBranch& 
     MOZ_ASSERT(br.expr() == Expr::Br || br.expr() == Expr::BrIf);
 
     if (!e.writeExpr(br.expr()))
         return false;
 
     if (!e.writeVarU32(br.target().index()))
         return false;
 
-    if (br.maybeValue() ? !EncodeExpr(e, *br.maybeValue()) : !e.writeExpr(Expr::Nop))
+    if (!e.writeExpr(Expr::Nop))
         return false;
 
     if (br.expr() == Expr::BrIf) {
         if (!EncodeExpr(e, br.cond()))
             return false;
     }
 
     return true;
--- a/js/src/jit-test/tests/wasm/basic-control-flow.js
+++ b/js/src/jit-test/tests/wasm/basic-control-flow.js
@@ -139,16 +139,18 @@ assertEq(wasmEvalText('(module (func (re
 assertEq(wasmEvalText('(module (func (result i32) (return (i32.const 1))) (export "" 0))')(), 1);
 assertEq(wasmEvalText('(module (func (if (return) (i32.const 0))) (export "" 0))')(), undefined);
 assertErrorMessage(() => wasmEvalText('(module (func (result f32) (return (i32.const 1))) (export "" 0))'), TypeError, mismatchError("i32", "f32"));
 assertThrowsInstanceOf(() => wasmEvalText('(module (func (result i32) (return)) (export "" 0))'), TypeError);
 
 // TODO: Reenable when syntactic arities are added for returns
 //assertThrowsInstanceOf(() => wasmEvalText('(module (func (return (i32.const 1))) (export "" 0))'), TypeError);
 
+// TODO: convert these to wasmEval and assert some results once they are implemented
+
 // ----------------------------------------------------------------------------
 // br / br_if
 
 assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0))) (export "" 0))'), TypeError, mismatchError("void", "i32"));
 assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br_if 0 (i32.const 0)))) (export "" 0))'), TypeError, mismatchError("void", "i32"));
 
 const DEPTH_OUT_OF_BOUNDS = /branch depth exceeds current nesting level/;
 
@@ -262,126 +264,16 @@ var isNonZero = wasmEvalText(`(module (f
   )
   (return (i32.const 1))
 ) (export "" 0))`);
 
 assertEq(isNonZero(0), 0);
 assertEq(isNonZero(1), 1);
 assertEq(isNonZero(-1), 1);
 
-// branches with values
-// br/br_if and block
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0))))'), TypeError, mismatchError("void", "i32"));
-assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0 (f32.const 42)))))'), TypeError, mismatchError("f32", "i32"));
-
-assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`), TypeError, mismatchError("void", "i32"));
-assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`), TypeError, mismatchError("void", "i32"));
-
-assertEq(wasmEvalText('(module (func (result i32) (block (br 0 (i32.const 42)) (i32.const 13))) (export "" 0))')(), 42);
-
-assertEq(wasmEvalText('(module (func) (func (block (br 0 (call 0)) (i32.const 13))) (export "" 0))')(), undefined);
-assertEq(wasmEvalText('(module (func) (func (block (br_if 0 (call 0) (i32.const 1)) (i32.const 13))) (export "" 0))')(), undefined);
-
-var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (i32.const 43))) (export "" 0))`);
-assertEq(f(0), 43);
-assertEq(f(1), 42);
-
-var f = wasmEvalText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (i32.const 43))) (export "" 0))`);
-assertEq(f(0), 43);
-assertEq(f(1), 42);
-
-var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`);
-assertEq(f(0), 43);
-assertEq(f(1), 42);
-
-var f = wasmEvalText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (br 0 (i32.const 43)))) (export "" 0))`);
-assertEq(f(0), 43);
-assertEq(f(1), 42);
-
-var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (if (get_local 0) (br 0 (i32.const 99))) (i32.const -1)))) (export "" 0))`);
-assertEq(f(0), 0);
-assertEq(f(1), 100);
-
-var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (br_if 0 (i32.const 99) (get_local 0)) (i32.const -1)))) (export "" 0))`);
-assertEq(f(0), 0);
-assertEq(f(1), 100);
-
-assertEq(wasmEvalText(`(module (func (result i32) (block (br 0 (return (i32.const 42))) (i32.const 0))) (export "" 0))`)(), 42);
-assertEq(wasmEvalText(`(module (func (result i32) (block (return (br 0 (i32.const 42))))) (export "" 0))`)(), 42);
-assertEq(wasmEvalText(`(module (func (result i32) (block (return (br 0 (i32.const 42))) (i32.const 0))) (export "" 0))`)(), 42);
-
-assertEq(wasmEvalText(`(module (func (result f32) (block (br 0 (i32.const 0))) (block (br 0 (f32.const 42)))) (export "" 0))`)(), 42);
-
-var called = 0;
-var imports = {
-    sideEffects: {
-        ifTrue(x) {assertEq(x, 13); called++;},
-        ifFalse(x) {assertEq(x, 37); called--;}
-    }
-}
-var f = wasmEvalText(`(module
- (import "sideEffects" "ifTrue" (param i32))
- (import "sideEffects" "ifFalse" (param i32))
- (func
-  (param i32) (result i32)
-  (block $outer
-   (if
-    (get_local 0)
-    (br $outer (call_import 0 (i32.const 13)))
-   )
-   (if
-    (i32.eqz (get_local 0))
-    (br $outer (call_import 1 (i32.const 37)))
-   )
-  )
-  (i32.const 42)
- )
-(export "" 0))`, imports);
-assertEq(f(0), 42);
-assertEq(called, -1);
-assertEq(f(1), 42);
-assertEq(called, 0);
-
-// br/br_if and loop
-assertEq(wasmEvalText(`(module (func (param i32) (result i32) (loop $out $in (br $out (get_local 0)))) (export "" 0))`)(1), 1);
-
-assertEq(wasmEvalText(`(module (func (param i32) (result i32)
-  (loop $out $in
-   (if (get_local 0) (br $in (i32.const 1)))
-   (if (get_local 0) (br $in (f32.const 2)))
-   (if (get_local 0) (br $in (f64.const 3)))
-   (if (get_local 0) (br $in))
-   (i32.const 7)
-  )
- ) (export "" 0))`)(0), 7);
-
-assertEq(wasmEvalText(`(module
- (func
-  (result i32)
-  (local i32)
-  (loop $out $in
-   (set_local 0 (i32.add (get_local 0) (i32.const 1)))
-   (if (i32.ge_s (get_local 0) (i32.const 7)) (br $out (get_local 0)))
-   (br $in)
-  )
- )
-(export "" 0))`)(), 7);
-
-assertEq(wasmEvalText(`(module
- (func
-  (result i32)
-  (local i32)
-  (loop $out $in
-   (set_local 0 (i32.add (get_local 0) (i32.const 1)))
-   (br_if $out (get_local 0) (i32.ge_s (get_local 0) (i32.const 7)))
-   (br $in)
-  )
- )
-(export "" 0))`)(), 7);
-
 // ----------------------------------------------------------------------------
 // loop
 
 assertErrorMessage(() => wasmEvalText('(module (func (loop (br 2))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
 
 assertEq(wasmEvalText('(module (func (loop)) (export "" 0))')(), undefined);
 assertEq(wasmEvalText('(module (func (result i32) (loop (i32.const 2)) (i32.const 1)) (export "" 0))')(), 1);