diff --git a/src/passes/OptimizeForJS.cpp b/src/passes/OptimizeForJS.cpp index 589374c0650..b8d78fcf448 100644 --- a/src/passes/OptimizeForJS.cpp +++ b/src/passes/OptimizeForJS.cpp @@ -65,6 +65,25 @@ struct OptimizeForJSPass : public WalkerPass> { builder.makeLocalGet(temp.index, type), builder.makeConst(Literal::makeOne(type.getBasic()))))))); } + + void visitStore(Store* curr) { + // i64.store(x, C) ==> f64.store(x, C'), + // where C' <- reinterpret(C) + // and C' != NaN && !is_subnormal(C') + // + // Regarding 0x8000000000000000. Closure Compiler preserve -0.0 + // so it should be safe but make sure your minifactor does not + // turn -0.0 into +0.0. + if (curr->valueType == Type::i64 && curr->bytes == 8) { + if (auto* c = curr->value->dynCast()) { + double value = c->value.reinterpretf64(); + if (!std::isnan(value) && std::fpclassify(value) != FP_SUBNORMAL) { + curr->valueType = Type::f64; + c->set(Literal(value)); + } + } + } + } }; Pass* createOptimizeForJSPass() { return new OptimizeForJSPass(); } diff --git a/test/lit/passes/optimize-for-js.wast b/test/lit/passes/optimize-for-js.wast index c771f77a76d..a7f48253313 100644 --- a/test/lit/passes/optimize-for-js.wast +++ b/test/lit/passes/optimize-for-js.wast @@ -3,6 +3,11 @@ ;; RUN: | filecheck %s (module + (memory 0) + + ;; i32.popcnt(x) == 1, + ;; i64.popcnt(x) == 1 => !!x & !(x & (x - 1)) + ;; CHECK: (func $is-power-of-2_32 (param $x i32) (result i32) ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (i32.eqz @@ -80,4 +85,97 @@ (i64.const 1) ) ) + + ;; i64.store(ptr, C) => f64.store(ptr, reinterpret(C)) + + ;; CHECK: (func $store-const-zero (param $ptr i32) + ;; CHECK-NEXT: (f64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (f64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-const-zero (param $ptr i32) + (i64.store (local.get $ptr) (i64.const 0)) + ) + ;; CHECK: (func $store-const-smin (param $ptr i32) + ;; CHECK-NEXT: (f64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (f64.const -0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-const-smin (param $ptr i32) + (i64.store (local.get $ptr) (i64.const 0x8000000000000000)) + ) + ;; CHECK: (func $store-const-minus-inf (param $ptr i32) + ;; CHECK-NEXT: (f64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (f64.const -inf) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-const-minus-inf (param $ptr i32) + (i64.store (local.get $ptr) (i64.const 0xFFF0000000000000)) + ) + ;; CHECK: (func $store-const-one_subnorm_skip (param $ptr i32) + ;; CHECK-NEXT: (i64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (i64.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-const-one_subnorm_skip (param $ptr i32) + (i64.store (local.get $ptr) (i64.const 1)) + ) + ;; CHECK: (func $store-const-two_subnorm_skip (param $ptr i32) + ;; CHECK-NEXT: (i64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (i64.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-const-two_subnorm_skip (param $ptr i32) + (i64.store (local.get $ptr) (i64.const 2)) + ) + ;; CHECK: (func $store-unsafe-const-1_skip (param $ptr i32) + ;; CHECK-NEXT: (i64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (i64.const -1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-unsafe-const-1_skip (param $ptr i32) + (i64.store (local.get $ptr) (i64.const -1)) ;; will be NaN + ) + ;; CHECK: (func $store-unsafe-const-2_skip (param $ptr i32) + ;; CHECK-NEXT: (i64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (i64.const -2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-unsafe-const-2_skip (param $ptr i32) + (i64.store (local.get $ptr) (i64.const -2)) + ) + ;; CHECK: (func $store-unsafe-const-3_skip (param $ptr i32) + ;; CHECK-NEXT: (i64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (i64.const -2251799813685248) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-unsafe-const-3_skip (param $ptr i32) + (i64.store (local.get $ptr) (i64.const 0xFFF8000000000000)) + ) + ;; CHECK: (func $store-non-const_skip (param $ptr i32) (param $x i64) + ;; CHECK-NEXT: (i64.store + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-non-const_skip (param $ptr i32) (param $x i64) + (i64.store (local.get $ptr) (local.get $x)) + ) + ;; CHECK: (func $store-non-8-bytes_skip (param $ptr i32) + ;; CHECK-NEXT: (i64.store32 + ;; CHECK-NEXT: (local.get $ptr) + ;; CHECK-NEXT: (i64.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $store-non-8-bytes_skip (param $ptr i32) + (i64.store32 (local.get $ptr) (i64.const 2)) + ) ) diff --git a/test/wasm2js/unaligned.2asm.js.opt b/test/wasm2js/unaligned.2asm.js.opt index 1f0fd6f4c87..97ce21eee66 100644 --- a/test/wasm2js/unaligned.2asm.js.opt +++ b/test/wasm2js/unaligned.2asm.js.opt @@ -76,17 +76,6 @@ function asmFunc(env) { } function $5() { - HEAP8[0] = 0; - HEAP8[1] = 0; - HEAP8[2] = 0; - HEAP8[3] = 0; - HEAP8[4] = 0; - HEAP8[5] = 0; - HEAP8[6] = 0; - HEAP8[7] = 0; - } - - function $7() { var $0_1 = 0, $1 = 0; wasm2js_scratch_store_f64(0.0); $0_1 = wasm2js_scratch_load_i32(1) | 0; @@ -122,7 +111,7 @@ function asmFunc(env) { "i32_store": $4, "i64_store": $5, "f32_store": $4, - "f64_store": $7 + "f64_store": $5 }; }