summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
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