diff options
-rw-r--r-- | src/passes/DeNaN.cpp | 27 | ||||
-rw-r--r-- | test/passes/denan.txt | 55 | ||||
-rw-r--r-- | test/passes/denan.wast | 12 |
3 files changed, 86 insertions, 8 deletions
diff --git a/src/passes/DeNaN.cpp b/src/passes/DeNaN.cpp index 8d0462718..8dadb90de 100644 --- a/src/passes/DeNaN.cpp +++ b/src/passes/DeNaN.cpp @@ -22,6 +22,7 @@ // differ on wasm's nondeterminism around NaNs. // +#include "ir/names.h" #include "ir/properties.h" #include "pass.h" #include "wasm-builder.h" @@ -31,6 +32,9 @@ namespace wasm { struct DeNaN : public WalkerPass< ControlFlowWalker<DeNaN, UnifiedExpressionVisitor<DeNaN>>> { + + Name deNan32, deNan64; + void visitExpression(Expression* expr) { // If the expression returns a floating-point value, ensure it is not a // NaN. If we can do this at compile time, do it now, which is useful for @@ -53,13 +57,13 @@ struct DeNaN : public WalkerPass< if (c && c->value.isNaN()) { replacement = builder.makeConst(float(0)); } else { - replacement = builder.makeCall("deNan32", {expr}, Type::f32); + replacement = builder.makeCall(deNan32, {expr}, Type::f32); } } else if (expr->type == Type::f64) { if (c && c->value.isNaN()) { replacement = builder.makeConst(double(0)); } else { - replacement = builder.makeCall("deNan64", {expr}, Type::f64); + replacement = builder.makeCall(deNan64, {expr}, Type::f64); } } if (replacement) { @@ -86,12 +90,12 @@ struct DeNaN : public WalkerPass< fixes.push_back(builder.makeLocalSet( i, builder.makeCall( - "deNan32", {builder.makeLocalGet(i, Type::f32)}, Type::f32))); + deNan32, {builder.makeLocalGet(i, Type::f32)}, Type::f32))); } else if (func->getLocalType(i) == Type::f64) { fixes.push_back(builder.makeLocalSet( i, builder.makeCall( - "deNan64", {builder.makeLocalGet(i, Type::f64)}, Type::f64))); + deNan64, {builder.makeLocalGet(i, Type::f64)}, Type::f64))); } } if (!fixes.empty()) { @@ -105,8 +109,15 @@ struct DeNaN : public WalkerPass< } } - void visitModule(Module* module) { - // Add helper functions. + void doWalkModule(Module* module) { + // Pick names for the helper functions. + deNan32 = Names::getValidFunctionName(*module, "deNan32"); + deNan64 = Names::getValidFunctionName(*module, "deNan64"); + + ControlFlowWalker<DeNaN, UnifiedExpressionVisitor<DeNaN>>::doWalkModule( + module); + + // Add helper functions after the walk, so they are not instrumented. Builder builder(*module); auto add = [&](Name name, Type type, Literal literal, BinaryOp op) { auto* func = new Function; @@ -130,8 +141,8 @@ struct DeNaN : public WalkerPass< builder.makeConst(literal)); module->addFunction(func); }; - add("deNan32", Type::f32, Literal(float(0)), EqFloat32); - add("deNan64", Type::f64, Literal(double(0)), EqFloat64); + add(deNan32, Type::f32, Literal(float(0)), EqFloat32); + add(deNan64, Type::f64, Literal(double(0)), EqFloat64); } }; diff --git a/test/passes/denan.txt b/test/passes/denan.txt index 10794b03b..de592c7fd 100644 --- a/test/passes/denan.txt +++ b/test/passes/denan.txt @@ -155,3 +155,58 @@ ) ) ) +(module + (type $none_=>_none (func)) + (type $f32_=>_f32 (func (param f32) (result f32))) + (type $f64_=>_f64 (func (param f64) (result f64))) + (func $deNan32 + (nop) + ) + (func $deNan64 + (nop) + ) + (func $foo32 (param $x f32) (result f32) + (local.set $x + (call $deNan32_0 + (local.get $x) + ) + ) + (call $deNan32_0 + (call $foo32 + (local.get $x) + ) + ) + ) + (func $foo64 (param $x f64) (result f64) + (local.set $x + (call $deNan64_0 + (local.get $x) + ) + ) + (call $deNan64_0 + (call $foo64 + (local.get $x) + ) + ) + ) + (func $deNan32_0 (param $0 f32) (result f32) + (if (result f32) + (f32.eq + (local.get $0) + (local.get $0) + ) + (local.get $0) + (f32.const 0) + ) + ) + (func $deNan64_0 (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/denan.wast b/test/passes/denan.wast index 7ab0964b2..78405d3a4 100644 --- a/test/passes/denan.wast +++ b/test/passes/denan.wast @@ -35,3 +35,15 @@ (local.get $x) (i32.const 1))) ) +;; existing names should not be a problem +(module + (func $deNan32) + (func $deNan64) + (func $foo32 (param $x f32) (result f32) + (call $foo32 (local.get $x)) + ) + (func $foo64 (param $x f64) (result f64) + (call $foo64 (local.get $x)) + ) + +) |