diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index e89452af8fb0e3aac2853f848c8ca58ece129621..9e59179f867732bf6a69ee233ffbbc0e575a1422 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -411,9 +411,17 @@ end # NEG # macro(:negdyn_smi) do |v| - # We can't use Neg with INT type, because it doesn't work for -0 and INT::MIN values. Thus, we cast it to the float - # and use as float Neg. - f64toany(Neg(i32tof64(anytoi32(v))).f64) + if self.mode.include? :IrInline + i32toany(NegOverflowAndZeroCheck(anytoi32(v)).i32) + else + value := And(anytoi32(v), 0x7fffffff).i32 + If(value, 0).EQ { + res_float := f64toany(Neg(i32tof64(anytoi32(v))).f64) + } Else { + res_int := i32toany(Neg(anytoi32(v)).i32) + } + Phi(res_float, res_int).any + end end macro(:negdyn_double) do |v| diff --git a/runtime/intrinsics-inl.h b/runtime/intrinsics-inl.h index c1f17946262851dad5da9a63a8d483873e06e739..247692b0f5a8ce1939b1c7c1520b32797eefdf0e 100644 --- a/runtime/intrinsics-inl.h +++ b/runtime/intrinsics-inl.h @@ -16,6 +16,7 @@ #ifndef PLUGINS_ECMASCRIPT_RUNTIME_INTRINSICS_INL_H #define PLUGINS_ECMASCRIPT_RUNTIME_INTRINSICS_INL_H +#include #include "intrinsics.h" #include "runtime/include/method-inl.h" @@ -452,6 +453,9 @@ INLINE_ECMA_INTRINSICS uint64_t NegDyn(JSThread *thread, uint64_t val) if (value.GetInt() == 0) { return JSTaggedValue(-0.0).GetRawData(); } + if (value.GetInt() == std::numeric_limits::min()) { + return JSTaggedValue(std::numeric_limits::max() + 1.0).GetRawData(); + } return JSTaggedValue(-value.GetInt()).GetRawData(); } if (value.IsDouble()) { diff --git a/tests/checked/type_resolving.js b/tests/checked/type_resolving.js index 00f429ac1292741f42f74f813b4bc2913b73d33c..8db6aa56e3d4e79e29691ead85d1724fdaa3a7c2 100644 --- a/tests/checked/type_resolving.js +++ b/tests/checked/type_resolving.js @@ -62,7 +62,7 @@ //! check_aot.call(:Div, 'Div2Dyn', 'f_f', /f64 +Div /) //! check_aot.call(:Not, 'NotDyn', 'i', /i32 +Not/) //! check_aot.call(:Not, 'NotDyn', 'f', /i32 +Not/) -//! check_aot.call(:Neg, 'NegDyn', 'i', /f64 +Neg/) +//! check_aot.call(:Neg, 'NegDyn', 'i', /NegOverflowAndZeroCheck/) //! check_aot.call(:Neg, 'NegDyn', 'f', /f64 +Neg/) //! check_aot.call(:Inc, 'IncDyn', 'i', /AddOverflowCheck/) //! check_aot.call(:Inc, 'IncDyn', 'f', /f64 +Add/) @@ -451,19 +451,33 @@ function test_not() { function test_neg_i() { let a = 1; - return -a; + return -a; // -1 } function test_neg_f() { let a = -3.5; - return -a; + return -a; // 3.5 +} + +function test_neg_i_overflow() { + let a = -2147483648; + return -a; // 2147483648 +} + +function test_neg_i_zero() { + let a = 0; + return 1/(-a); // -Infinity } function test_neg() { let res = 0; res += test_neg_i(); res += test_neg_f(); - if (res != 2.5) { + res += test_neg_i_overflow(); + if (res != 2147483650.5) { + throw "test_neg is failed"; + } + if (test_neg_i_zero() != -Infinity) { throw "test_neg is failed"; } } diff --git a/tests/runtime/irtoc/advanced/advanced.js b/tests/runtime/irtoc/advanced/advanced.js index 27ec082dc612d18ea8ecc9112b923f89ff0ce9e6..d3e6c47f4a039ea0468303a89074348bf13bde9f 100644 --- a/tests/runtime/irtoc/advanced/advanced.js +++ b/tests/runtime/irtoc/advanced/advanced.js @@ -67,6 +67,19 @@ expected = 12345678987654321; if (res != expected) throw "res = " + res + ", expected = " + expected +res = 0; +res = 1 / -res; +expected = -Infinity; + +if (res != expected) + throw "res = " + res + ", expected = " + expected + +res = -2147483648; +res = -res; +expected = 2147483648; + +if (res != expected) + throw "res = " + res + ", expected = " + expected res = 0; res = -res;