Skip to content

Commit ff710e6

Browse files
authored
wasm2js: unreachability fixes (#2037)
Also test in pass-debug mode, for better coverage.
1 parent f87de2a commit ff710e6

18 files changed

Lines changed: 2488 additions & 1898 deletions

check.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
binary_format_check, delete_from_orbit, fail, fail_with_error,
2828
fail_if_not_identical, fail_if_not_contained, has_vanilla_emcc,
2929
has_vanilla_llvm, minify_check, options, tests, requested, warnings,
30-
has_shell_timeout, fail_if_not_identical_to_file
30+
has_shell_timeout, fail_if_not_identical_to_file, with_pass_debug
3131
)
3232

3333
# For shared.num_failures. Cannot import directly because modifications made in
@@ -42,20 +42,6 @@
4242
assert os.path.exists(options.interpreter), 'interpreter not found'
4343

4444

45-
# run a check with BINARYEN_PASS_DEBUG set, to do full validation
46-
def with_pass_debug(check):
47-
old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG')
48-
try:
49-
os.environ['BINARYEN_PASS_DEBUG'] = '1'
50-
check()
51-
finally:
52-
if old_pass_debug is not None:
53-
os.environ['BINARYEN_PASS_DEBUG'] = old_pass_debug
54-
else:
55-
if 'BINARYEN_PASS_DEBUG' in os.environ:
56-
del os.environ['BINARYEN_PASS_DEBUG']
57-
58-
5945
def run_help_tests():
6046
print '[ checking --help is useful... ]\n'
6147

scripts/test/shared.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,3 +435,17 @@ def minify_check(wast, verify_final_result=True):
435435

436436
def files_with_pattern(*path_pattern):
437437
return sorted(glob.glob(os.path.join(*path_pattern)))
438+
439+
440+
# run a check with BINARYEN_PASS_DEBUG set, to do full validation
441+
def with_pass_debug(check):
442+
old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG')
443+
try:
444+
os.environ['BINARYEN_PASS_DEBUG'] = '1'
445+
check()
446+
finally:
447+
if old_pass_debug is not None:
448+
os.environ['BINARYEN_PASS_DEBUG'] = old_pass_debug
449+
else:
450+
if 'BINARYEN_PASS_DEBUG' in os.environ:
451+
del os.environ['BINARYEN_PASS_DEBUG']

scripts/test/wasm2js.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from support import run_command, split_wast
2020
from shared import (
2121
WASM2JS, MOZJS, NODEJS, fail_if_not_identical, options, tests,
22-
fail_if_not_identical_to_file
22+
fail_if_not_identical_to_file, with_pass_debug
2323
)
2424

2525
# tests with i64s, invokes, etc.
@@ -73,6 +73,8 @@ def test_wasm2js_output():
7373

7474
cmd += ['--allow-asserts']
7575
out = run_command(cmd)
76+
# also verify it passes pass-debug verifications
77+
with_pass_debug(lambda: run_command(cmd))
7678

7779
open('a.2asm.asserts.mjs', 'w').write(out)
7880

src/passes/I64ToI32Lowering.cpp

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
223223

224224
void visitBlock(Block* curr) {
225225
if (curr->list.size() == 0) return;
226+
if (handleUnreachable(curr)) return;
226227
if (curr->type == i64) curr->type = i32;
227228
auto highBitsIt = labelHighBitVars.find(curr->name);
228229
if (!hasOutParam(curr->list.back())) {
@@ -272,13 +273,15 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
272273
}
273274

274275
void visitLoop(Loop* curr) {
276+
// TODO: in flat IR, no chance for an out param
275277
assert(labelHighBitVars.find(curr->name) == labelHighBitVars.end());
276278
if (curr->type != i64) return;
277279
curr->type = i32;
278280
setOutParam(curr, fetchOutParam(curr->body));
279281
}
280282

281283
void visitBreak(Break* curr) {
284+
// TODO: in flat IR, no chance for an out param
282285
if (!hasOutParam(curr->value)) return;
283286
assert(curr->value != nullptr);
284287
TempVar valHighBits = fetchOutParam(curr->value);
@@ -301,6 +304,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
301304
}
302305

303306
void visitSwitch(Switch* curr) {
307+
// TODO: in flat IR, no chance for an out param
304308
if (!hasOutParam(curr->value)) return;
305309
TempVar outParam = fetchOutParam(curr->value);
306310
TempVar tmp = getTemp();
@@ -478,8 +482,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
478482
}
479483

480484
void visitSetGlobal(SetGlobal* curr) {
481-
if (handleUnreachable(curr)) return;
482485
if (!originallyI64Globals.count(curr->name)) return;
486+
if (handleUnreachable(curr)) return;
483487
TempVar highBits = fetchOutParam(curr->value);
484488
auto* setHigh = builder->makeSetGlobal(
485489
makeHighName(curr->name),
@@ -550,6 +554,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
550554
TempVar ptrTemp = getTemp();
551555
SetLocal* setPtr = builder->makeSetLocal(ptrTemp, curr->ptr);
552556
curr->ptr = builder->makeGetLocal(ptrTemp, i32);
557+
curr->finalize();
553558
Store* storeHigh = builder->makeStore(
554559
4,
555560
curr->offset + 4,
@@ -941,11 +946,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
941946

942947
void visitUnary(Unary* curr) {
943948
if (!unaryNeedsLowering(curr->op)) return;
944-
if (curr->type == unreachable || curr->value->type == unreachable) {
945-
assert(!hasOutParam(curr->value));
946-
replaceCurrent(curr->value);
947-
return;
948-
}
949+
if (handleUnreachable(curr)) return;
949950
assert(hasOutParam(curr->value) || curr->type == i64 || curr->type == f64);
950951
switch (curr->op) {
951952
case ClzInt64:
@@ -1463,25 +1464,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
14631464
}
14641465

14651466
void visitBinary(Binary* curr) {
1467+
if (handleUnreachable(curr)) return;
14661468
if (!binaryNeedsLowering(curr->op)) return;
1467-
if (!hasOutParam(curr->left)) {
1468-
// left unreachable, replace self with left
1469-
replaceCurrent(curr->left);
1470-
if (hasOutParam(curr->right)) {
1471-
// free temp var
1472-
fetchOutParam(curr->right);
1473-
}
1474-
return;
1475-
}
1476-
if (!hasOutParam(curr->right)) {
1477-
// right unreachable, replace self with left then right
1478-
replaceCurrent(
1479-
builder->blockify(builder->makeDrop(curr->left), curr->right)
1480-
);
1481-
// free temp var
1482-
fetchOutParam(curr->left);
1483-
return;
1484-
}
14851469
// left and right reachable, lower normally
14861470
TempVar leftLow = getTemp();
14871471
TempVar leftHigh = fetchOutParam(curr->left);
@@ -1668,16 +1652,26 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
16681652

16691653
// If e.g. a select is unreachable, then one arm may have an out param
16701654
// but not the other. In this case dce should really have been run
1671-
// before; handle it in a simple way here.
1655+
// before; handle it in a simple way here by replacing the node with
1656+
// a block of its children.
1657+
// This is valid only for nodes that execute their children
1658+
// unconditionally before themselves, so it is not valid for an if,
1659+
// in particular.
16721660
bool handleUnreachable(Expression* curr) {
16731661
if (curr->type != unreachable) return false;
16741662
std::vector<Expression*> children;
1663+
bool hasUnreachable = false;
16751664
for (auto* child : ChildIterator(curr)) {
16761665
if (isConcreteType(child->type)) {
16771666
child = builder->makeDrop(child);
1667+
} else if (child->type == unreachable) {
1668+
hasUnreachable = true;
16781669
}
16791670
children.push_back(child);
16801671
}
1672+
if (!hasUnreachable) return false;
1673+
// This has an unreachable child, so we can replace it with
1674+
// the children.
16811675
auto* block = builder->makeBlock(children);
16821676
assert(block->type == unreachable);
16831677
replaceCurrent(block);

test/passes/flatten_i64-to-i32-lowering.txt

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@
206206
(local $1 i32)
207207
(local $1$hi i32)
208208
(local $i64toi32_i32$0 i32)
209-
(block $label$1
209+
(block
210210
(unreachable)
211211
(unreachable)
212212
)
@@ -239,3 +239,61 @@
239239
(nop)
240240
)
241241
)
242+
(module
243+
(type $0 (func (param i32 i32)))
244+
(type $1 (func))
245+
(global $f (mut i32) (i32.const -1412567121))
246+
(global $g (mut i32) (global.get $f))
247+
(global $f$hi (mut i32) (i32.const 305419896))
248+
(global $g$hi (mut i32) (global.get $f$hi))
249+
(global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
250+
(export "exp" (func $1))
251+
(func $call (; 0 ;) (type $0) (param $0 i32) (param $0$hi i32)
252+
(nop)
253+
)
254+
(func $1 (; 1 ;) (type $1)
255+
(local $0 i32)
256+
(local $0$hi i32)
257+
(local $i64toi32_i32$0 i32)
258+
(block
259+
(block
260+
(local.set $0
261+
(block (result i32)
262+
(local.set $i64toi32_i32$0
263+
(global.get $f$hi)
264+
)
265+
(global.get $f)
266+
)
267+
)
268+
(local.set $0$hi
269+
(local.get $i64toi32_i32$0)
270+
)
271+
)
272+
(call $call
273+
(block (result i32)
274+
(local.set $i64toi32_i32$0
275+
(local.get $0$hi)
276+
)
277+
(local.get $0)
278+
)
279+
(local.get $i64toi32_i32$0)
280+
)
281+
(nop)
282+
(block
283+
(global.set $f
284+
(block (result i32)
285+
(local.set $i64toi32_i32$0
286+
(i32.const 287454020)
287+
)
288+
(i32.const 1432778632)
289+
)
290+
)
291+
(global.set $f$hi
292+
(local.get $i64toi32_i32$0)
293+
)
294+
)
295+
(nop)
296+
)
297+
(nop)
298+
)
299+
)

test/passes/flatten_i64-to-i32-lowering.wast

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,13 @@
4141
)
4242
)
4343
)
44+
(module
45+
(global $f (mut i64) (i64.const 0x12345678ABCDEFAF))
46+
(global $g (mut i64) (global.get $f))
47+
(func $call (param i64))
48+
(func "exp"
49+
(call $call (global.get $f))
50+
(global.set $f (i64.const 0x1122334455667788))
51+
)
52+
)
53+

test/wasm2js/block.2asm.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,8 @@ function asmFunc(global, env, buffer) {
135135
$0 = 0;
136136
$1_1 = $0;
137137
block : {
138-
block47 : {
139-
$2_1 = 1;
140-
break block;
141-
}
138+
$2_1 = 1;
139+
break block;
142140
}
143141
$0 = $1_1 + $2_1 | 0;
144142
$5_1 = $0;
@@ -151,10 +149,8 @@ function asmFunc(global, env, buffer) {
151149
$0 = $9_1 + $10_1 | 0;
152150
$13_1 = $0;
153151
block51 : {
154-
block52 : {
155-
$14_1 = 8;
156-
break block51;
157-
}
152+
$14_1 = 8;
153+
break block51;
158154
}
159155
$0 = $13_1 + $14_1 | 0;
160156
return $0 | 0;

test/wasm2js/br.2asm.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -449,15 +449,14 @@ function asmFunc(global, env, buffer) {
449449
}
450450

451451
function $47() {
452-
var i64toi32_i32$0 = 0, $0 = 0, $0$hi = 0;
452+
var $0 = 0, $0$hi = 0, i64toi32_i32$1 = 0;
453453
block : {
454-
i64toi32_i32$0 = 0;
455454
$0 = 45;
456-
$0$hi = i64toi32_i32$0;
455+
$0$hi = 0;
457456
break block;
458457
}
459-
i64toi32_i32$0 = $0$hi;
460-
i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
458+
i64toi32_i32$1 = $0$hi;
459+
i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
461460
return $0 | 0;
462461
}
463462

@@ -519,10 +518,8 @@ function asmFunc(global, env, buffer) {
519518
function $54() {
520519
var $0 = 0;
521520
block : {
522-
block0 : {
523-
$0 = 8;
524-
break block;
525-
}
521+
$0 = 8;
522+
break block;
526523
}
527524
return 1 + $0 | 0 | 0;
528525
}

test/wasm2js/br_table.2asm.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49973,7 +49973,7 @@ function asmFunc(global, env, buffer) {
4997349973
}
4997449974

4997549975
function $54() {
49976-
var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0;
49976+
var i64toi32_i32$0 = 0, $1_1 = 0, $1$hi = 0, i64toi32_i32$1 = 0;
4997749977
block : {
4997849978
i64toi32_i32$0 = 0;
4997949979
$1_1 = 45;
@@ -49983,8 +49983,8 @@ function asmFunc(global, env, buffer) {
4998349983
break block;
4998449984
};
4998549985
}
49986-
i64toi32_i32$0 = $1$hi;
49987-
i64toi32_i32$HIGH_BITS = i64toi32_i32$0;
49986+
i64toi32_i32$1 = $1$hi;
49987+
i64toi32_i32$HIGH_BITS = i64toi32_i32$1;
4998849988
return $1_1 | 0;
4998949989
}
4999049990

test/wasm2js/br_table_temp.2asm.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49977,7 +49977,6 @@ function asmFunc(global, env, buffer) {
4997749977
break block;
4997849978
};
4997949979
}
49980-
i64toi32_i32$0 = $1$hi;
4998149980
return $1_1 | 0;
4998249981
}
4998349982

0 commit comments

Comments
 (0)