Skip to content

Properly handle conditional continue in do loops #2055

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

Merged
merged 3 commits into from
Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2391,13 +2391,15 @@ export class Compiler extends DiagnosticEmitter {
var outerFlow = this.currentFlow;

// (block $break └►┐ flow
// (loop $continue ├◄───────────┐ recompile?
// (body) └─┐ bodyFlow │
// ┌─┘ │
// (loop $loop ├◄───────────┐ recompile?
// (?block $continue └─┐ │
// (body) │ bodyFlow │
// ) ┌─┘ │
// ┌◄┼►╢ │ breaks or terminates?
// (local.set $tcond (condition)) │ └─┐ condFlow │
// │ └─┐ │ but does not continue
// (br_if (cond) $loop) │ │ condFlow │
// │ ┌─┘ │
// (br_if (local.get $tcond) $continue) ├◄┴────────────┘ condition?
// ├◄┴────────────┘ condition?
// ) └─┐
// ) ┌─┘

Expand All @@ -2411,6 +2413,7 @@ export class Compiler extends DiagnosticEmitter {
flow.breakLabel = breakLabel;
var continueLabel = "do-continue|" + label;
flow.continueLabel = continueLabel;
var loopLabel = "do-loop|" + label;

// Compile the body (always executes)
var bodyFlow = flow.fork();
Expand All @@ -2424,7 +2427,8 @@ export class Compiler extends DiagnosticEmitter {
}

// Shortcut if body never falls through
if (bodyFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS)) {
var possiblyContinues = bodyFlow.isAny(FlowFlags.CONTINUES | FlowFlags.CONDITIONALLY_CONTINUES);
if (bodyFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS) && !possiblyContinues) {
bodyStmts.push(
module.unreachable()
);
Expand All @@ -2441,6 +2445,12 @@ export class Compiler extends DiagnosticEmitter {
);
let condKind = this.evaluateCondition(condExpr);

if (possiblyContinues) {
bodyStmts = [
module.block(continueLabel, bodyStmts)
];
}

// Shortcut if condition is always false
if (condKind == ConditionKind.FALSE) {
bodyStmts.push(
Expand All @@ -2454,21 +2464,16 @@ export class Compiler extends DiagnosticEmitter {
module.drop(condExpr)
);
bodyStmts.push(
module.br(continueLabel)
module.br(loopLabel)
);
flow.set(FlowFlags.TERMINATES);

} else {
let tcond = condFlow.getTempLocal(Type.bool);
bodyStmts.push(
module.local_set(tcond.index, condExpr, false) // bool
);
bodyStmts.push(
module.br(continueLabel,
module.local_get(tcond.index, TypeRef.I32)
module.br(loopLabel,
condExpr
)
);
condFlow.freeTempLocal(tcond);
flow.inherit(condFlow);

// Detect if local flags are incompatible before and after looping, and
Expand All @@ -2488,7 +2493,7 @@ export class Compiler extends DiagnosticEmitter {
outerFlow.popBreakLabel();
this.currentFlow = outerFlow;
var expr = module.block(breakLabel, [
module.loop(continueLabel,
module.loop(loopLabel,
module.flatten(bodyStmts)
)
]);
Expand Down
4 changes: 2 additions & 2 deletions tests/compiler/NonNullable.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
select
i32.eqz
if
loop $do-continue|0
loop $do-loop|0
local.get $3
i64.load
local.get $1
Expand All @@ -95,7 +95,7 @@
local.tee $0
i32.const 4
i32.ge_u
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
6 changes: 2 additions & 4 deletions tests/compiler/NonNullable.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
end
if
block $do-break|0
loop $do-continue|0
loop $do-loop|0
local.get $5
i64.load
local.get $6
Expand All @@ -93,9 +93,7 @@
local.get $4
i32.const 4
i32.ge_u
local.set $7
local.get $7
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions tests/compiler/builtins.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
select
i32.eqz
if
loop $do-continue|0
loop $do-loop|0
local.get $3
i64.load
local.get $1
Expand All @@ -151,7 +151,7 @@
local.tee $0
i32.const 4
i32.ge_u
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
6 changes: 2 additions & 4 deletions tests/compiler/builtins.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
end
if
block $do-break|0
loop $do-continue|0
loop $do-loop|0
local.get $5
i64.load
local.get $6
Expand All @@ -171,9 +171,7 @@
local.get $4
i32.const 4
i32.ge_u
local.set $7
local.get $7
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions tests/compiler/call-super.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1246,7 +1246,7 @@
block $__inlined_func$~lib/rt/itcms/interrupt
i32.const 2048
local.set $3
loop $do-continue|0
loop $do-loop|0
local.get $3
call $~lib/rt/itcms/step
i32.sub
Expand All @@ -1269,7 +1269,7 @@
local.get $3
i32.const 0
i32.gt_s
br_if $do-continue|0
br_if $do-loop|0
end
global.get $~lib/rt/itcms/total
local.tee $3
Expand Down
7 changes: 2 additions & 5 deletions tests/compiler/call-super.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1510,7 +1510,6 @@
)
(func $~lib/rt/itcms/interrupt
(local $0 i32)
(local $1 i32)
i32.const 0
drop
i32.const 0
Expand All @@ -1521,7 +1520,7 @@
i32.const 100
i32.div_u
local.set $0
loop $do-continue|0
loop $do-loop|0
local.get $0
call $~lib/rt/itcms/step
i32.sub
Expand Down Expand Up @@ -1549,9 +1548,7 @@
local.get $0
i32.const 0
i32.gt_s
local.set $1
local.get $1
br_if $do-continue|0
br_if $do-loop|0
end
i32.const 0
drop
Expand Down
4 changes: 2 additions & 2 deletions tests/compiler/class-implements.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,7 @@
block $__inlined_func$~lib/rt/itcms/interrupt
i32.const 2048
local.set $1
loop $do-continue|0
loop $do-loop|0
local.get $1
call $~lib/rt/itcms/step
i32.sub
Expand All @@ -1207,7 +1207,7 @@
local.get $1
i32.const 0
i32.gt_s
br_if $do-continue|0
br_if $do-loop|0
end
global.get $~lib/rt/itcms/total
local.tee $1
Expand Down
7 changes: 2 additions & 5 deletions tests/compiler/class-implements.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,6 @@
)
(func $~lib/rt/itcms/interrupt
(local $0 i32)
(local $1 i32)
i32.const 0
drop
i32.const 0
Expand All @@ -1531,7 +1530,7 @@
i32.const 100
i32.div_u
local.set $0
loop $do-continue|0
loop $do-loop|0
local.get $0
call $~lib/rt/itcms/step
i32.sub
Expand Down Expand Up @@ -1559,9 +1558,7 @@
local.get $0
i32.const 0
i32.gt_s
local.set $1
local.get $1
br_if $do-continue|0
br_if $do-loop|0
end
i32.const 0
drop
Expand Down
8 changes: 4 additions & 4 deletions tests/compiler/class-overloading-cast.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,7 @@
block $__inlined_func$~lib/rt/itcms/interrupt
i32.const 2048
local.set $1
loop $do-continue|0
loop $do-loop|0
local.get $1
call $~lib/rt/itcms/step
i32.sub
Expand All @@ -1221,7 +1221,7 @@
local.get $1
i32.const 0
i32.gt_s
br_if $do-continue|0
br_if $do-loop|0
end
global.get $~lib/rt/itcms/total
local.tee $1
Expand Down Expand Up @@ -1469,7 +1469,7 @@
select
i32.eqz
if
loop $do-continue|0
loop $do-loop|0
local.get $3
i64.load
local.get $1
Expand All @@ -1490,7 +1490,7 @@
local.tee $0
i32.const 4
i32.ge_u
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
13 changes: 4 additions & 9 deletions tests/compiler/class-overloading-cast.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,6 @@
)
(func $~lib/rt/itcms/interrupt
(local $0 i32)
(local $1 i32)
i32.const 0
drop
i32.const 0
Expand All @@ -1531,7 +1530,7 @@
i32.const 100
i32.div_u
local.set $0
loop $do-continue|0
loop $do-loop|0
local.get $0
call $~lib/rt/itcms/step
i32.sub
Expand Down Expand Up @@ -1559,9 +1558,7 @@
local.get $0
i32.const 0
i32.gt_s
local.set $1
local.get $1
br_if $do-continue|0
br_if $do-loop|0
end
i32.const 0
drop
Expand Down Expand Up @@ -2405,7 +2402,7 @@
end
if
block $do-break|0
loop $do-continue|0
loop $do-loop|0
local.get $5
i64.load
local.get $6
Expand All @@ -2429,9 +2426,7 @@
local.get $4
i32.const 4
i32.ge_u
local.set $7
local.get $7
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions tests/compiler/class-overloading.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1222,7 +1222,7 @@
block $__inlined_func$~lib/rt/itcms/interrupt
i32.const 2048
local.set $1
loop $do-continue|0
loop $do-loop|0
local.get $1
call $~lib/rt/itcms/step
i32.sub
Expand All @@ -1245,7 +1245,7 @@
local.get $1
i32.const 0
i32.gt_s
br_if $do-continue|0
br_if $do-loop|0
end
global.get $~lib/rt/itcms/total
local.tee $1
Expand Down Expand Up @@ -1493,7 +1493,7 @@
select
i32.eqz
if
loop $do-continue|0
loop $do-loop|0
local.get $3
i64.load
local.get $1
Expand All @@ -1514,7 +1514,7 @@
local.tee $0
i32.const 4
i32.ge_u
br_if $do-continue|0
br_if $do-loop|0
end
end
end
Expand Down
Loading