From ec1b56d9b15579391740400fc8aad88b99102f63 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 28 Apr 2020 07:56:45 +0200 Subject: [PATCH] Fix invalid flow assumption in 'if' compilation --- src/compiler.ts | 6 +-- tests/compiler/while.optimized.wat | 30 +++++++++++ tests/compiler/while.ts | 32 +++++++++++ tests/compiler/while.untouched.wat | 86 ++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 5 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index d58380c8a8..06775c956c 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -2581,11 +2581,7 @@ export class Compiler extends DiagnosticEmitter { } elseFlow.freeScopedLocals(); this.currentFlow = flow; - if (elseTerminates && !thenTerminates) { - flow.inherit(thenFlow); - } else { - flow.inheritMutual(thenFlow, elseFlow); - } + flow.inheritMutual(thenFlow, elseFlow); return module.if(condExpr, module.flatten(thenStmts), module.flatten(elseStmts) diff --git a/tests/compiler/while.optimized.wat b/tests/compiler/while.optimized.wat index 3336e8bdf4..9a365e4cff 100644 --- a/tests/compiler/while.optimized.wat +++ b/tests/compiler/while.optimized.wat @@ -1415,6 +1415,36 @@ call $~lib/builtins/abort unreachable end + i32.const 0 + global.set $while/ran + i32.const 0 + local.set $3 + loop $while-continue|067 + local.get $3 + i32.const 1 + i32.add + local.tee $3 + i32.const 1 + i32.lt_s + br_if $while-continue|067 + end + i32.const 1 + global.set $while/ran + i32.const 0 + global.set $while/ran + i32.const 0 + local.set $3 + loop $while-continue|08 + local.get $3 + i32.const 1 + i32.add + local.tee $3 + i32.const 1 + i32.lt_s + br_if $while-continue|08 + end + i32.const 1 + global.set $while/ran ) (func $~start global.get $~started diff --git a/tests/compiler/while.ts b/tests/compiler/while.ts index 43e5e768f7..cd0f4ffd46 100644 --- a/tests/compiler/while.ts +++ b/tests/compiler/while.ts @@ -175,3 +175,35 @@ function testRefAutorelease(): void { ran = false; testRefAutorelease(); assert(ran); + +function testIfImplicitContinueThen(): void { + var i = 0; + while (true) { + i++; + if (i < 1) { + // continue + } else { + break; + } + } + ran = true; +} +ran = false; +testIfImplicitContinueThen(); +assert(ran); + +function testIfImplicitContinueElse(): void { + var i = 0; + while (true) { + i++; + if (i >= 1) { + break; + } else { + // continue + } + } + ran = true; +} +ran = false; +testIfImplicitContinueElse(); +assert(ran); diff --git a/tests/compiler/while.untouched.wat b/tests/compiler/while.untouched.wat index 76367f1ad1..7caedb7a8b 100644 --- a/tests/compiler/while.untouched.wat +++ b/tests/compiler/while.untouched.wat @@ -2154,6 +2154,66 @@ local.get $1 call $~lib/rt/pure/__release ) + (func $while/testIfImplicitContinueThen + (local $0 i32) + (local $1 i32) + i32.const 0 + local.set $0 + block $while-break|0 + loop $while-continue|0 + i32.const 1 + local.set $1 + local.get $1 + if + local.get $0 + i32.const 1 + i32.add + local.set $0 + local.get $0 + i32.const 1 + i32.lt_s + if + nop + else + br $while-break|0 + end + br $while-continue|0 + end + end + end + i32.const 1 + global.set $while/ran + ) + (func $while/testIfImplicitContinueElse + (local $0 i32) + (local $1 i32) + i32.const 0 + local.set $0 + block $while-break|0 + loop $while-continue|0 + i32.const 1 + local.set $1 + local.get $1 + if + local.get $0 + i32.const 1 + i32.add + local.set $0 + local.get $0 + i32.const 1 + i32.ge_s + if + br $while-break|0 + else + nop + end + br $while-continue|0 + end + end + end + i32.const 1 + global.set $while/ran + ) (func $start:while i32.const 0 global.set $while/ran @@ -2310,6 +2370,32 @@ call $~lib/builtins/abort unreachable end + i32.const 0 + global.set $while/ran + call $while/testIfImplicitContinueThen + global.get $while/ran + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 193 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + global.set $while/ran + call $while/testIfImplicitContinueElse + global.get $while/ran + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 209 + i32.const 1 + call $~lib/builtins/abort + unreachable + end ) (func $~start global.get $~started