summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2019-02-19 10:14:59 -0800
committerGitHub <noreply@github.com>2019-02-19 10:14:59 -0800
commit3564b71c25d7691267f5f7d8b95f10fd5929090a (patch)
treeca81e10e93bc10b8ade61f96ff642152540f9e8f
parent8b820ed0021ab1a6ad5dad3972cfbf2cecb77e45 (diff)
downloadbinaryen-3564b71c25d7691267f5f7d8b95f10fd5929090a.tar.gz
binaryen-3564b71c25d7691267f5f7d8b95f10fd5929090a.tar.bz2
binaryen-3564b71c25d7691267f5f7d8b95f10fd5929090a.zip
NaN fuzzing improvements (#1913)
* make DE_NAN avoid creating nan literals in the first place * add a reducer option `--denan` to not introduce nans in destructive reduction * add a `Literal::isNaN()` method * also remove the default exception logging from the fuzzer js glue, which is a source of non-useful VM differences (like nan nondeterminism) * added an option `--no-fuzz-nans` to make it easy to avoid nans when fuzzing (without hacking the source and recompiling). Background: trying to get fuzzing on jsc working despite this open issue: https://bugs.webkit.org/show_bug.cgi?id=175691
-rw-r--r--scripts/fuzz_opt.py12
-rw-r--r--src/literal.h2
-rw-r--r--src/tools/fuzzing.h25
-rw-r--r--src/tools/js-wrapper.h2
-rw-r--r--src/tools/wasm-opt.cpp8
-rw-r--r--src/tools/wasm-reduce.cpp30
-rw-r--r--src/wasm/literal.cpp11
-rw-r--r--test/passes/emit-js-wrapper=a.js.wast.js10
-rw-r--r--test/passes/translate-to-fuzz.txt36
-rw-r--r--test/passes/translate-to-fuzz_no-fuzz-nans.txt580
-rw-r--r--test/passes/translate-to-fuzz_no-fuzz-nans.wast99
11 files changed, 764 insertions, 51 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index c8f67b2ae..58751a72e 100644
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -27,9 +27,12 @@ from test.shared import options
# parameters
-LOG_LIMIT = 125
+FUZZ_OPTS = ['--mvp-features'] # may want to add '--no-fuzz-nans' for cross-VM testing
+
INPUT_SIZE_LIMIT = 250 * 1024
+LOG_LIMIT = 125
+
# utilities
@@ -122,9 +125,8 @@ def run_vms(prefix):
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']))]
+ results += [fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js', '--', prefix + 'wasm']))]
+ # results += [fix_output(run_vm([os.path.expanduser('~/.jsvu/jsc'), 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()]))]
@@ -146,7 +148,7 @@ def test_one(infile, opts):
# 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'] + FUZZ_OPTS)
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)
diff --git a/src/literal.h b/src/literal.h
index 2e3f901cc..7646b5d29 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -110,6 +110,8 @@ public:
bool operator==(const Literal& other) const;
bool operator!=(const Literal& other) const;
+ bool isNaN();
+
static uint32_t NaNPayload(float f);
static uint64_t NaNPayload(double f);
static float setQuietNaN(float f);
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index 63e7dca43..90b7d61b1 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -123,8 +123,15 @@ public:
std::cout << "shrink level: " << options.passOptions.shrinkLevel << '\n';
}
- void build(FeatureSet features_) {
+ void setFeatures(FeatureSet features_) {
features = features_;
+ }
+
+ void setAllowNaNs(bool allowNaNs_) {
+ allowNaNs = allowNaNs_;
+ }
+
+ void build() {
setupMemory();
setupTable();
setupGlobals();
@@ -137,7 +144,7 @@ public:
if (HANG_LIMIT > 0) {
addHangLimitSupport();
}
- if (DE_NAN) {
+ if (!allowNaNs) {
addDeNanSupport();
}
finalizeTable();
@@ -178,7 +185,7 @@ private:
// Optionally remove NaNs, which are a source of nondeterminism (which makes
// cross-VM comparisons harder)
// TODO: de-NaN SIMD values
- static const bool DE_NAN = true;
+ bool allowNaNs = true;
// Features allowed to be emitted
FeatureSet features = FeatureSet::All;
@@ -361,7 +368,7 @@ private:
}
Expression* makeDeNanOp(Expression* expr) {
- if (!DE_NAN) return expr;
+ if (allowNaNs) return expr;
if (expr->type == f32) {
return builder.makeCall("deNan32", { expr }, f32);
} else if (expr->type == f64) {
@@ -1213,7 +1220,7 @@ private:
return store;
}
- Literal makeLiteral(Type type) {
+ Literal makeArbitraryLiteral(Type type) {
if (type == v128) {
// generate each lane individually for random lane interpretation
switch (upTo(6)) {
@@ -1344,6 +1351,14 @@ private:
WASM_UNREACHABLE();
}
+ Literal makeLiteral(Type type) {
+ auto ret = makeArbitraryLiteral(type);
+ if (!allowNaNs && ret.isNaN()) {
+ ret = Literal::makeFromInt32(0, type);
+ }
+ return ret;
+ }
+
Expression* makeConst(Type type) {
auto* ret = wasm.allocator.alloc<Const>();
ret->value = makeLiteral(type);
diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h
index 765a638c5..433d6fc5a 100644
--- a/src/tools/js-wrapper.h
+++ b/src/tools/js-wrapper.h
@@ -103,7 +103,7 @@ static std::string generateJSWrapper(Module& wasm) {
}
ret += ";\n";
ret += "} catch (e) {\n";
- ret += " console.log('exception: ' + e);\n";
+ ret += " console.log('exception!' /* + e */);\n";
ret += "}\n";
}
return ret;
diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp
index 61e554276..d2f3d718c 100644
--- a/src/tools/wasm-opt.cpp
+++ b/src/tools/wasm-opt.cpp
@@ -71,6 +71,7 @@ int main(int argc, const char* argv[]) {
std::string extraFuzzCommand;
bool translateToFuzz = false;
bool fuzzPasses = false;
+ bool fuzzNaNs = true;
std::string emitJSWrapper;
std::string emitSpecWrapper;
std::string inputSourceMapFilename;
@@ -112,6 +113,9 @@ int main(int argc, const char* argv[]) {
.add("--fuzz-passes", "-fp", "Pick a random set of passes to run, useful for fuzzing. this depends on translate-to-fuzz (it picks the passes from the input)",
Options::Arguments::Zero,
[&](Options *o, const std::string& arguments) { fuzzPasses = true; })
+ .add("--no-fuzz-nans", "", "don't emit NaNs when fuzzing, and remove them at runtime as well (helps avoid nondeterminism between VMs)",
+ Options::Arguments::Zero,
+ [&](Options *o, const std::string& arguments) { fuzzNaNs = false; })
.add("--emit-js-wrapper", "-ejw", "Emit a JavaScript wrapper file that can run the wasm with some test values, useful for fuzzing",
Options::Arguments::One,
[&](Options *o, const std::string& arguments) { emitJSWrapper = arguments; })
@@ -166,7 +170,9 @@ int main(int argc, const char* argv[]) {
if (fuzzPasses) {
reader.pickPasses(options);
}
- reader.build(options.getFeatures());
+ reader.setFeatures(options.getFeatures());
+ reader.setAllowNaNs(fuzzNaNs);
+ reader.build();
if (options.passOptions.validate) {
if (!WasmValidator().validate(wasm, options.getFeatures())) {
WasmPrinter::printModule(&wasm);
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp
index 8b12c0ef1..bd5a0c1b8 100644
--- a/src/tools/wasm-reduce.cpp
+++ b/src/tools/wasm-reduce.cpp
@@ -221,11 +221,12 @@ static std::unordered_set<Name> functionsWeTriedToRemove;
struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<Reducer>>> {
std::string command, test, working;
- bool binary, verbose, debugInfo;
+ bool binary, deNan, verbose, debugInfo;
// test is the file we write to that the command will operate on
// working is the current temporary state, the reduction so far
- Reducer(std::string command, std::string test, std::string working, bool binary, bool verbose, bool debugInfo) : command(command), test(test), working(working), binary(binary), verbose(verbose), debugInfo(debugInfo) {}
+ Reducer(std::string command, std::string test, std::string working, bool binary, bool deNan, bool verbose, bool debugInfo) :
+ command(command), test(test), working(working), binary(binary), deNan(deNan), verbose(verbose), debugInfo(debugInfo) {}
// runs passes in order to reduce, until we can't reduce any more
// the criterion here is wasm binary size
@@ -360,8 +361,22 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
return (counter % factor) <= bonus;
}
+ bool isOkReplacement(Expression* with) {
+ if (deNan) {
+ if (auto* c = with->dynCast<Const>()) {
+ if (c->value.isNaN()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
// tests a reduction on the current traversal node, and undos if it failed
bool tryToReplaceCurrent(Expression* with) {
+ if (!isOkReplacement(with)) {
+ return false;
+ }
auto* curr = getCurrent();
//std::cerr << "try " << curr << " => " << with << '\n';
if (curr->type != with->type) return false;
@@ -383,6 +398,9 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
// tests a reduction on an arbitrary child
bool tryToReplaceChild(Expression*& child, Expression* with) {
+ if (!isOkReplacement(with)) {
+ return false;
+ }
if (child->type != with->type) return false;
if (!shouldTryToReduce()) return false;
auto* before = child;
@@ -865,6 +883,7 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
int main(int argc, const char* argv[]) {
std::string input, test, working, command;
bool binary = true,
+ deNan = false,
verbose = false,
debugInfo = false,
force = false;
@@ -899,6 +918,11 @@ int main(int argc, const char* argv[]) {
[&](Options* o, const std::string& argument) {
binary = false;
})
+ .add("--denan", "", "Avoid nans when reducing",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) {
+ deNan = true;
+ })
.add("--verbose", "-v", "Verbose output mode",
Options::Arguments::Zero,
[&](Options* o, const std::string& argument) {
@@ -997,7 +1021,7 @@ int main(int argc, const char* argv[]) {
bool stopping = false;
while (1) {
- Reducer reducer(command, test, working, binary, verbose, debugInfo);
+ Reducer reducer(command, test, working, binary, deNan, verbose, debugInfo);
// run binaryen optimization passes to reduce. passes are fast to run
// and can often reduce large amounts of code efficiently, as opposed
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index 5f358fa6b..4ec256aae 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -144,6 +144,17 @@ bool Literal::operator!=(const Literal& other) const {
return !(*this == other);
}
+bool Literal::isNaN() {
+ if (type == Type::f32 && std::isnan(getf32())) {
+ return true;
+ }
+ if (type == Type::f64 && std::isnan(getf64())) {
+ return true;
+ }
+ // TODO: SIMD?
+ return false;
+}
+
uint32_t Literal::NaNPayload(float f) {
assert(std::isnan(f) && "expected a NaN");
// SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
diff --git a/test/passes/emit-js-wrapper=a.js.wast.js b/test/passes/emit-js-wrapper=a.js.wast.js
index 9e8578781..2e127d189 100644
--- a/test/passes/emit-js-wrapper=a.js.wast.js
+++ b/test/passes/emit-js-wrapper=a.js.wast.js
@@ -51,33 +51,33 @@ try {
console.log('[fuzz-exec] calling $add');
console.log('[fuzz-exec] note result: $add => ' + literal(instance.exports.add(0, 0), 'i32'));
} catch (e) {
- console.log('exception: ' + e);
+ console.log('exception!' /* + e */);
}
if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
try {
console.log('[fuzz-exec] calling $no_return');
instance.exports.no_return(0);
} catch (e) {
- console.log('exception: ' + e);
+ console.log('exception!' /* + e */);
}
if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
try {
console.log('[fuzz-exec] calling $types');
instance.exports.types(0, 0, 0, 0, 0);
} catch (e) {
- console.log('exception: ' + e);
+ console.log('exception!' /* + e */);
}
if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
try {
console.log('[fuzz-exec] calling $types2');
instance.exports.types2(0, 0, 0);
} catch (e) {
- console.log('exception: ' + e);
+ console.log('exception!' /* + e */);
}
if (instance.exports.hangLimitInitializer) instance.exports.hangLimitInitializer();
try {
console.log('[fuzz-exec] calling $types3');
console.log('[fuzz-exec] note result: $types3 => ' + literal(instance.exports.types3(0, 0, 0), 'i32'));
} catch (e) {
- console.log('exception: ' + e);
+ console.log('exception!' /* + e */);
}
diff --git a/test/passes/translate-to-fuzz.txt b/test/passes/translate-to-fuzz.txt
index aefe33cb6..914703050 100644
--- a/test/passes/translate-to-fuzz.txt
+++ b/test/passes/translate-to-fuzz.txt
@@ -17,8 +17,8 @@
(import "fuzzing-support" "log-f64" (func $log-f64 (param f64)))
(memory $0 (shared 1 1))
(data (i32.const 0) "n\00\05E\00\00\00\00")
- (table $0 6 6 funcref)
- (elem (i32.const 0) $func_6 $func_12 $func_12 $func_12 $func_15 $func_16)
+ (table $0 10 10 funcref)
+ (elem (i32.const 0) $func_6 $func_12 $func_12 $func_12 $func_15 $func_16 $func_17 $func_17 $func_17 $func_17)
(global $global$0 (mut f32) (f32.const 536870912))
(global $global$1 (mut f32) (f32.const 2147483648))
(global $global$2 (mut f64) (f64.const -1048576))
@@ -526,7 +526,7 @@
(global.get $hangLimit)
)
(return
- (f32.const 865309568)
+ (f32.const 185009408)
)
)
(global.set $hangLimit
@@ -537,15 +537,9 @@
)
)
(if (result f32)
- (i32.eqz
- (if (result i32)
- (i32.const 709182789)
- (i32.const -4)
- (i32.const 873467920)
- )
- )
+ (i32.const 1230459474)
(block $label$5 (result f32)
- (f32.const 59953536565248)
+ (f32.const 121)
)
(block $label$6 (result f32)
(f32.const 1)
@@ -557,24 +551,4 @@
(i32.const 10)
)
)
- (func $deNan32 (; 19 ;) (param $0 f32) (result f32)
- (if (result f32)
- (f32.eq
- (local.get $0)
- (local.get $0)
- )
- (local.get $0)
- (f32.const 0)
- )
- )
- (func $deNan64 (; 20 ;) (param $0 f64) (result f64)
- (if (result f64)
- (f64.eq
- (local.get $0)
- (local.get $0)
- )
- (local.get $0)
- (f64.const 0)
- )
- )
)
diff --git a/test/passes/translate-to-fuzz_no-fuzz-nans.txt b/test/passes/translate-to-fuzz_no-fuzz-nans.txt
new file mode 100644
index 000000000..e35e68315
--- /dev/null
+++ b/test/passes/translate-to-fuzz_no-fuzz-nans.txt
@@ -0,0 +1,580 @@
+(module
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$vj (func (param i64)))
+ (type $FUNCSIG$vf (func (param f32)))
+ (type $FUNCSIG$vd (func (param f64)))
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$jddfiV (func (param f64 f64 f32 i32 v128) (result i64)))
+ (type $FUNCSIG$viViVjV (func (param i32 v128 i32 v128 i64 v128)))
+ (type $FUNCSIG$VVVVVii (func (param v128 v128 v128 v128 i32 i32) (result v128)))
+ (type $FUNCSIG$fddffj (func (param f64 f64 f32 f32 i64) (result f32)))
+ (type $FUNCSIG$j (func (result i64)))
+ (type $FUNCSIG$i (func (result i32)))
+ (type $FUNCSIG$f (func (result f32)))
+ (import "fuzzing-support" "log-i32" (func $log-i32 (param i32)))
+ (import "fuzzing-support" "log-i64" (func $log-i64 (param i64)))
+ (import "fuzzing-support" "log-f32" (func $log-f32 (param f32)))
+ (import "fuzzing-support" "log-f64" (func $log-f64 (param f64)))
+ (memory $0 (shared 1 1))
+ (data (i32.const 0) "n\00\05E\00\00\00\00")
+ (table $0 6 6 funcref)
+ (elem (i32.const 0) $func_6 $func_12 $func_12 $func_12 $func_15 $func_16)
+ (global $global$0 (mut f32) (f32.const 536870912))
+ (global $global$1 (mut f32) (f32.const 2147483648))
+ (global $global$2 (mut f64) (f64.const -1048576))
+ (global $global$3 (mut f64) (f64.const 23643))
+ (global $hangLimit (mut i32) (i32.const 10))
+ (export "func_4" (func $func_4))
+ (export "func_5" (func $func_5))
+ (export "func_6_invoker" (func $func_6_invoker))
+ (export "func_8" (func $func_8))
+ (export "func_8_invoker" (func $func_8_invoker))
+ (export "func_10" (func $func_10))
+ (export "func_10_invoker" (func $func_10_invoker))
+ (export "func_12" (func $func_12))
+ (export "func_13" (func $func_13))
+ (export "func_14" (func $func_14))
+ (export "func_16" (func $func_16))
+ (export "func_17" (func $func_17))
+ (export "hangLimitInitializer" (func $hangLimitInitializer))
+ (func $func_4 (; 4 ;) (type $FUNCSIG$v)
+ (local $0 f64)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (call $log-i32
+ (loop $label$22 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result i32)
+ (call $log-i32
+ (i32.const -16777216)
+ )
+ (br_if $label$22
+ (i32.const 520883468)
+ )
+ (i32.const 925912624)
+ )
+ )
+ )
+ (local.set $0
+ (local.tee $0
+ (local.get $0)
+ )
+ )
+ )
+ )
+ (func $func_5 (; 5 ;) (type $FUNCSIG$jddfiV) (param $0 f64) (param $1 f64) (param $2 f32) (param $3 i32) (param $4 v128) (result i64)
+ (local $5 i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i64.const 1)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (nop)
+ (return
+ (i64.const -16777216)
+ )
+ )
+ )
+ (func $func_6 (; 6 ;) (param $0 i32) (result i64)
+ (local $1 v128)
+ (local $2 f64)
+ (local $3 i32)
+ (local $4 v128)
+ (local $5 f64)
+ (local $6 f32)
+ (local $7 i64)
+ (local $8 i64)
+ (local $9 f64)
+ (local $10 i64)
+ (local $11 i64)
+ (local $12 v128)
+ (local $13 f32)
+ (local $14 i32)
+ (local $15 f64)
+ (local $16 f32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (local.get $7)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (i64.const 18014398509481984)
+ )
+ (func $func_6_invoker (; 7 ;) (type $FUNCSIG$v)
+ (drop
+ (call $func_6
+ (i32.const 225118223)
+ )
+ )
+ )
+ (func $func_8 (; 8 ;) (type $FUNCSIG$viViVjV) (param $0 i32) (param $1 v128) (param $2 i32) (param $3 v128) (param $4 i64) (param $5 v128)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (local.set $5
+ (local.tee $5
+ (loop $label$1 (result v128)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result v128)
+ (drop
+ (if (result i32)
+ (i32.eqz
+ (loop $label$25
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block
+ (block $label$26
+ (if
+ (local.get $0)
+ (nop)
+ (block $label$27
+ (nop)
+ (nop)
+ )
+ )
+ (block $label$28
+ (nop)
+ )
+ (local.set $4
+ (block $label$29 (result i64)
+ (call $log-f64
+ (f64.const 72)
+ )
+ (local.tee $4
+ (local.tee $4
+ (local.tee $4
+ (br_if $label$29
+ (block $label$30 (result i64)
+ (br_if $label$25
+ (local.get $2)
+ )
+ (i64.const 4294967229)
+ )
+ (i32.eqz
+ (i32.const 0)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (br_if $label$25
+ (i32.eqz
+ (local.tee $0
+ (local.tee $2
+ (local.tee $0
+ (local.tee $0
+ (local.tee $0
+ (local.tee $0
+ (local.tee $2
+ (local.tee $0
+ (i32.const 1215581264)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (local.tee $0
+ (loop $label$31
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$32
+ (local.set $2
+ (i32.const -127)
+ )
+ (br $label$25)
+ )
+ )
+ )
+ )
+ )
+ )
+ (i32.const 9282)
+ (block $label$33 (result i32)
+ (local.get $0)
+ )
+ )
+ )
+ (br_if $label$1
+ (i32.const -1)
+ )
+ (v128.const i32 0xb2 0xc0 0x0 0xb 0x0 0x2 0x1 0x1f 0x1 0xff 0x0 0xff 0x0 0xed 0xf 0xff)
+ )
+ )
+ )
+ )
+ (local.set $5
+ (v128.const i32 0x0 0x0 0x19 0x80 0x1b 0x2 0x0 0xeb 0x4a 0x1a 0x0 0x7f 0x80 0x12 0x5d 0x0)
+ )
+ )
+ )
+ (func $func_8_invoker (; 9 ;) (type $FUNCSIG$v)
+ (call $func_8
+ (i32.const 68)
+ (v128.const i32 0x70 0x38 0x37 0x25 0x3d 0x79 0x3c 0x31 0x2 0x9 0xc 0x15 0xa 0x3 0x4c 0x1f)
+ (i32.const 420088586)
+ (v128.const i32 0x9 0x1b 0xfe 0xff 0x0 0x0 0xfe 0xff 0x15 0x16 0xb 0x5f 0xe6 0xff 0x3d 0x46)
+ (i64.const 2055)
+ (v128.const i32 0x0 0x0 0x0 0x0 0x0 0x0 0xe0 0x43 0x0 0x0 0x0 0x0 0x0 0x60 0x6c 0x40)
+ )
+ )
+ (func $func_10 (; 10 ;) (type $FUNCSIG$vd) (param $0 f64)
+ (local $1 i32)
+ (local $2 i64)
+ (local $3 f64)
+ (local $4 f64)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (nop)
+ (br_if $label$0
+ (local.get $1)
+ )
+ )
+ )
+ (func $func_10_invoker (; 11 ;) (type $FUNCSIG$v)
+ (call $func_10
+ (f64.const 0)
+ )
+ (call $func_10
+ (f64.const -81)
+ )
+ (call $func_10
+ (f64.const -91)
+ )
+ )
+ (func $func_12 (; 12 ;) (type $FUNCSIG$VVVVVii) (param $0 v128) (param $1 v128) (param $2 v128) (param $3 v128) (param $4 i32) (param $5 i32) (result v128)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (v128.const i32 0x0 0x0 0x4 0xff 0x46 0x1d 0x37 0xff 0x2 0x0 0x0 0x6f 0x18 0x43 0x0 0x0)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (call $log-i64
+ (i64.const -17179869184)
+ )
+ (return
+ (local.get $0)
+ )
+ )
+ )
+ (func $func_13 (; 13 ;) (type $FUNCSIG$fddffj) (param $0 f64) (param $1 f64) (param $2 f32) (param $3 f32) (param $4 i64) (result f32)
+ (local $5 f32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (local.get $3)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (nop)
+ (return
+ (f32.const -562949953421312)
+ )
+ )
+ )
+ (func $func_14 (; 14 ;) (type $FUNCSIG$j) (result i64)
+ (local $0 v128)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i64.const -4294967295)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (call $log-f64
+ (f64.const 3.0085765013203267e-46)
+ )
+ (return
+ (i64.const 117901063)
+ )
+ )
+ )
+ (func $func_15 (; 15 ;)
+ (local $0 v128)
+ (local $1 i64)
+ (local $2 i32)
+ (local $3 f64)
+ (local $4 f64)
+ (local $5 v128)
+ (local $6 i64)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return)
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block $label$0
+ (local.set $5
+ (v128.const i32 0x4e 0x5d 0x1b 0x5d 0x54 0x1b 0x48 0x48 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xf8)
+ )
+ (nop)
+ )
+ )
+ (func $func_16 (; 16 ;) (type $FUNCSIG$i) (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 0)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (loop $label$0 (result i32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (i32.const 32767)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (block (result i32)
+ (block $label$1
+ (block $label$2
+ (block $label$3
+ (nop)
+ (nop)
+ )
+ (nop)
+ )
+ (nop)
+ (nop)
+ )
+ (br_if $label$0
+ (i32.const 1147035403)
+ )
+ (i32.const 1024)
+ )
+ )
+ )
+ (func $func_17 (; 17 ;) (type $FUNCSIG$f) (result f32)
+ (block
+ (if
+ (i32.eqz
+ (global.get $hangLimit)
+ )
+ (return
+ (f32.const 865309568)
+ )
+ )
+ (global.set $hangLimit
+ (i32.sub
+ (global.get $hangLimit)
+ (i32.const 1)
+ )
+ )
+ )
+ (if (result f32)
+ (i32.eqz
+ (if (result i32)
+ (i32.const 709182789)
+ (i32.const -4)
+ (i32.const 873467920)
+ )
+ )
+ (block $label$5 (result f32)
+ (f32.const 59953536565248)
+ )
+ (block $label$6 (result f32)
+ (f32.const 1)
+ )
+ )
+ )
+ (func $hangLimitInitializer (; 18 ;)
+ (global.set $hangLimit
+ (i32.const 10)
+ )
+ )
+ (func $deNan32 (; 19 ;) (param $0 f32) (result f32)
+ (if (result f32)
+ (f32.eq
+ (local.get $0)
+ (local.get $0)
+ )
+ (local.get $0)
+ (f32.const 0)
+ )
+ )
+ (func $deNan64 (; 20 ;) (param $0 f64) (result f64)
+ (if (result f64)
+ (f64.eq
+ (local.get $0)
+ (local.get $0)
+ )
+ (local.get $0)
+ (f64.const 0)
+ )
+ )
+)
diff --git a/test/passes/translate-to-fuzz_no-fuzz-nans.wast b/test/passes/translate-to-fuzz_no-fuzz-nans.wast
new file mode 100644
index 000000000..cbf25fde1
--- /dev/null
+++ b/test/passes/translate-to-fuzz_no-fuzz-nans.wast
@@ -0,0 +1,99 @@
+(module # fake module here, for test harness, but it's really not needed
+..
+any
+3INPUT
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
+<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
+
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
+<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
+
+INPUT
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
+<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
+
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+) # this isn't really needed either