summaryrefslogtreecommitdiff
path: root/scripts/fuzz_opt.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/fuzz_opt.py')
-rw-r--r--scripts/fuzz_opt.py148
1 files changed, 76 insertions, 72 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index 49a2c3f73..e3a59a690 100644
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -17,6 +17,7 @@ import os
import difflib
import subprocess
import random
+import re
import shutil
import time
@@ -64,85 +65,88 @@ def randomize_pass_debug():
IGNORE = '[binaryen-fuzzer-ignore]'
-def test_one(infile, opts):
- def compare(x, y, comment):
- if x != y and x != IGNORE and y != IGNORE:
- message = ''.join([a.rstrip() + '\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')])
- raise Exception(str(comment) + ": Expected to have '%s' == '%s', diff:\n\n%s" % (
- x, y,
- message
- ))
-
- def run_vms(prefix):
- def fix_output(out):
- # exceptions may differ when optimizing, but an exception should occur. so ignore their types
- # also js engines print them out slightly differently
- return '\n'.join(map(lambda x: ' *exception*' if 'exception' in x else x, out.split('\n')))
-
- # normalize different vm output
- # also the binaryen optimizer can reorder traps (but not remove them), so
- # it really just matters if you trap, not how you trap
- return out.replace('unreachable executed', 'unreachable') \
- .replace('integer result unrepresentable', 'integer overflow') \
- .replace('invalid conversion to integer', 'integer overflow') \
- .replace('memory access out of bounds', 'index out of bounds') \
- .replace('integer divide by zero', 'divide by zero') \
- .replace('integer remainder by zero', 'remainder by zero') \
- .replace('remainder by zero', 'divide by zero') \
- .replace('divide result unrepresentable', 'integer overflow') \
- .replace('divide by zero', 'integer overflow') \
- .replace('index out of bounds', 'integer overflow') \
- .replace('out of bounds memory access', 'integer overflow')
-
- def fix_spec_output(out):
- out = fix_output(out)
- # spec shows a pointer when it traps, remove that
- out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.split('\n')))
- # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up
- out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.split('\n')))
- return out
-
- def run_vm(cmd):
- # ignore some vm assertions, if bugs have already been filed
- known_issues = [
- 'local count too large', # ignore this; can be caused by flatten, ssa, etc. passes
- 'liftoff-assembler.cc, line 239\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
- 'liftoff-register.h, line 86\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8632
- ]
- try:
- return run(cmd)
- except:
- output = run_unchecked(cmd)
- for issue in known_issues:
- if issue in output:
- return IGNORE
- raise
-
- results = []
- # append to this list to add results from VMs
- results += [fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js', '--', prefix + 'wasm']))]
- results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))]
- results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--no-wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))]
- # spec has no mechanism to not halt on a trap. so we just check until the first trap, basically
- # run(['../spec/interpreter/wasm', prefix + 'wasm'])
- # results += [fix_spec_output(run_unchecked(['../spec/interpreter/wasm', prefix + 'wasm', '-e', open(prefix + 'wat').read()]))]
-
- if len(results) == 0:
- results = [0]
-
- first = results[0]
- for i in range(len(results)):
- compare(first, results[i], 'comparing between vms at ' + str(i))
-
- return results
+def compare(x, y, comment):
+ if x != y and x != IGNORE and y != IGNORE:
+ message = ''.join([a.rstrip() + '\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')])
+ raise Exception(str(comment) + ": Expected to have '%s' == '%s', diff:\n\n%s" % (
+ x, y,
+ message
+ ))
+
+
+def run_vms(prefix):
+ def fix_output(out):
+ # large doubles may print slightly different on different VMs
+ def fix_double(x):
+ x = x.group(1)
+ if 'nan' in x or 'NaN' in x:
+ x = 'nan'
+ else:
+ x = x.replace('Infinity', 'inf')
+ x = str(float(x))
+ return 'f64.const ' + x
+ out = re.sub(r'f64\.const (-?[nanN:abcdefxIity\d+-.]+)', fix_double, out)
+
+ # mark traps from wasm-opt as exceptions, even though they didn't run in a vm
+ out = out.replace('[trap ', 'exception: [trap ')
+
+ # exceptions may differ when optimizing, but an exception should occur. so ignore their types
+ # also js engines print them out slightly differently
+ return '\n'.join(map(lambda x: ' *exception*' if 'exception' in x else x, out.split('\n')))
+
+ def fix_spec_output(out):
+ out = fix_output(out)
+ # spec shows a pointer when it traps, remove that
+ out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.split('\n')))
+ # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up
+ out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.split('\n')))
+ return out
+
+ def run_vm(cmd):
+ # ignore some vm assertions, if bugs have already been filed
+ known_issues = [
+ 'local count too large', # ignore this; can be caused by flatten, ssa, etc. passes
+ 'liftoff-assembler.cc, line 239\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
+ 'liftoff-assembler.cc, line 245\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
+ 'liftoff-register.h, line 86\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8632
+ ]
+ try:
+ return run(cmd)
+ except:
+ output = run_unchecked(cmd)
+ for issue in known_issues:
+ if issue in output:
+ return IGNORE
+ raise
+
+ results = []
+ # append to this list to add results from VMs
+ results += [fix_output(run_vm([in_bin('wasm-opt'), prefix + 'wasm', '--fuzz-exec-before']))]
+ results += [fix_output(run_vm([os.path.expanduser('d8'), '--experimental-wasm-sat_f2i_conversions', prefix + 'js', '--', prefix + 'wasm']))]
+ results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--experimental-wasm-sat_f2i_conversions', '--wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))]
+ results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--experimental-wasm-sat_f2i_conversions', '--no-wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))]
+ # spec has no mechanism to not halt on a trap. so we just check until the first trap, basically
+ # run(['../spec/interpreter/wasm', prefix + 'wasm'])
+ # results += [fix_spec_output(run_unchecked(['../spec/interpreter/wasm', prefix + 'wasm', '-e', open(prefix + 'wat').read()]))]
+
+ if len(results) == 0:
+ results = [0]
+
+ first = results[0]
+ for i in range(len(results)):
+ compare(first, results[i], 'comparing between vms at ' + str(i))
+
+ return results
+
+def test_one(infile, opts):
randomize_pass_debug()
bytes = 0
# fuzz vms
# gather VM outputs on input file
- run([in_bin('wasm-opt'), infile, '-ttf', '--emit-js-wrapper=a.js', '--emit-spec-wrapper=a.wat', '-o', 'a.wasm', '--mvp-features'])
+ run([in_bin('wasm-opt'), infile, '-ttf', '--emit-js-wrapper=a.js', '--emit-spec-wrapper=a.wat', '-o', 'a.wasm', '--mvp-features', '--enable-nontrapping-float-to-int'])
wasm_size = os.stat('a.wasm').st_size
bytes += wasm_size
print('pre js size :', os.stat('a.js').st_size, ' wasm size:', wasm_size)