diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/literal.h | 2 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 25 | ||||
-rw-r--r-- | src/tools/js-wrapper.h | 2 | ||||
-rw-r--r-- | src/tools/wasm-opt.cpp | 8 | ||||
-rw-r--r-- | src/tools/wasm-reduce.cpp | 30 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 11 |
6 files changed, 68 insertions, 10 deletions
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 |