From 7be8d27b81cc6894ea6f7f0890ffbb9bfd1455d2 Mon Sep 17 00:00:00 2001 From: Ishin Pavel Date: Mon, 10 Jul 2023 13:06:50 +0300 Subject: [PATCH] Support Mod for integer types Signed-off-by: Ishin Pavel --- irtoc_scripts/interpreter_handlers.irt | 4 ++- runtime/ecma_profiling.h | 37 ++++++++++++++++++++ runtime/interpreter/ecma-interpreter-inl.h | 19 +++++++++-- tests/checked/inline_intrinsics.js | 39 +++++++++++++++++++++- 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index fb36ab847..cd20cd9c8 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -439,7 +439,9 @@ function(:EcmaMod2dyn, params: {'a'=>'any', 'b'=>'any'}, mode: [:Interpreter, :D end macro(:mod2dyn_smi_smi) do |l, r| - f64toany(Mod(i32tof64(anytoi32(l.any)), i32tof64(anytoi32(r.any))).f64) + il := anytoi32(l) + ir := anytoi32(r) + i32toany(Mod(NegativeCheck(il).SetFlag("panda::compiler::inst_flags::Flags::CAN_DEOPTIMIZE").u32, NotPositiveCheck(ir).SetFlag("panda::compiler::inst_flags::Flags::CAN_DEOPTIMIZE").u32).u32) end macro(:mod2dyn_smi_double) do |l, r| diff --git a/runtime/ecma_profiling.h b/runtime/ecma_profiling.h index 7426ac7c1..d7be07149 100644 --- a/runtime/ecma_profiling.h +++ b/runtime/ecma_profiling.h @@ -243,6 +243,32 @@ inline ProfilingTypeBits::Type GetTypeFromValue(JSTaggedValue value) return ProfilingTypeBits::OBJECT; } +inline ProfilingTypeBits::Type GetTypeFromValueForMod(JSTaggedValue value) +{ + if (value.IsInt()) { + if (value.GetInt() < 0) { + return ProfilingTypeBits::DOUBLE_INTEGER; + } + return ProfilingTypeBits::INTEGER; + } + // IsDouble() is encoded as `!IsInt() && !IsObject()`, IsInt() we already tested, so check only it is not an object + if (!value.IsObject()) { + return ProfilingTypeBits::DOUBLE; + } + if (value.IsBoolean()) { + return ProfilingTypeBits::BOOLEAN; + } + if (value.IsString()) { + return ProfilingTypeBits::STRING; + } + if (value.IsUndefined()) { + return ProfilingTypeBits::SPECIAL_DOUBLE; + } + if (value.IsNull()) { + return ProfilingTypeBits::SPECIAL_INT; + } + return ProfilingTypeBits::OBJECT; +} inline ProfilingTypeOfBits::Type GetTypeOfFromValue(JSTaggedValue value) { if (value.IsInt()) { @@ -455,6 +481,17 @@ public: std::memory_order_release); } + // NOLINTNEXTLINE(readability-non-const-parameter) + static void UpdateMod(Base::ValueType *data, JSTaggedValue lhs, JSTaggedValue rhs) + { + auto ltype = GetTypeFromValueForMod(lhs); + auto rtype = GetTypeFromValueForMod(rhs); + // Atomic with release order reason: profile data may be updated while the compiler thread loads it + reinterpret_cast *>(reinterpret_cast(data)) + ->store(*data | LeftOperandType::Encode(ltype) | RightOperandType::Encode(rtype), + std::memory_order_release); + } + protected: using LeftOperandType = BitField; using RightOperandType = diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index 3610678d1..42aeb1092 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -95,6 +95,15 @@ namespace panda::ecmascript { UNUSED_VAR(rhs); \ } +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define UPDATE_MOD_PROFILE(lhs, rhs) \ + if constexpr (IS_PROFILE_ENABLED) { \ + UpdateBinaryArithProfile(lhs, rhs); \ + } else { \ + UNUSED_VAR(lhs); \ + UNUSED_VAR(rhs); \ + } + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define UPDATE_TYPE_OF_PROFILE(lhs) \ if constexpr (IS_PROFILE_ENABLED) { \ @@ -1272,7 +1281,7 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - UPDATE_BINARY_ARITH_PROFILE(left, right); + UPDATE_MOD_PROFILE(left, right); INTRINSIC_CALL_CHECK_SETACC(intrinsics::Mod2Dyn(this->GetJSThread(), left, right)); this->template MoveToNextInst(); @@ -2929,6 +2938,7 @@ public: UnaryOperationProfile::Update(prof_value, JSTaggedValue(value)); } + template void UpdateBinaryArithProfile(coretypes::TaggedType lhs, coretypes::TaggedType rhs) { auto left = JSTaggedValue(lhs); @@ -2944,7 +2954,12 @@ public: ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto prof_value = reinterpret_cast(&prof_data[prof_id]); - BinaryOperationProfile::Update(prof_value, left, right); + // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon) + if constexpr (IS_MOD) { + BinaryOperationProfile::UpdateMod(prof_value, left, right); + } else { + BinaryOperationProfile::Update(prof_value, left, right); + } } void UpdateCallProfile(ECMAObject *func) diff --git a/tests/checked/inline_intrinsics.js b/tests/checked/inline_intrinsics.js index 8ba4dc1fc..702d8414d 100644 --- a/tests/checked/inline_intrinsics.js +++ b/tests/checked/inline_intrinsics.js @@ -60,7 +60,7 @@ //! check_aot.call(:Div, 'Div2Dyn', 'i_f', /f64 +Div /) //! check_aot.call(:Div, 'Div2Dyn', 'f_i', /f64 +Div /) //! check_aot.call(:Div, 'Div2Dyn', 'f_f', /f64 +Div /) -//! check_aot.call(:Mod, 'Mod2Dyn', 'i_i', /f64 +Mod /) +//! check_aot.call(:Mod, 'Mod2Dyn', 'i_i', /u32 +Mod /) //! check_aot.call(:Mod, 'Mod2Dyn', 'i_f', /f64 +Mod /) //! check_aot.call(:Mod, 'Mod2Dyn', 'f_i', /f64 +Mod /) //! check_aot.call(:Mod, 'Mod2Dyn', 'f_f', /f64 +Mod /) @@ -154,6 +154,27 @@ //! RUN options: "--interpreter-type irtoc", entry: "_GLOBAL::func_main_0", force_jit: false //! EVENT_NOT /AotEntrypointFound.*/ +//! CHECKER Test mod instruction +//! RUN options: "--no-async-jit --compiler-hotness-threshold=1 --compiler-regex _GLOBAL::test_mod_with_.*_int", entry: "_GLOBAL::func_main_0" +//! EVENT_NOT /AotEntrypointFound.*/ +//! METHOD "test_mod_with_neg_int" +//! PASS_BEFORE "InlineIntrinsics" +//! INST "Intrinsic.Mod2Dyn" +//! PASS_AFTER "InlineIntrinsics" +//! INST_NOT /Intrinsic.*Mod2Dyn/ +//! INST "f64 Mod" +//! METHOD "test_mod_with_pos_int" +//! PASS_BEFORE "InlineIntrinsics" +//! INST "Intrinsic.Mod2Dyn" +//! PASS_AFTER "InlineIntrinsics" +//! INST_NOT /Intrinsic.*Mod2Dyn/ +//! INST "NegativeCheck" +//! INST_NEXT "NotPositiveCheck" +//! INST_NEXT "u32 Mod" +//! EVENT /Compilation,_GLOBAL::test_mod_with_pos_int,.*,COMPILED/ +//! TRUE EVENT_COUNT(/DeoptimizationReason,.*test_mod_with_pos_int.*NEGATIVE_CHECK.*/) == 2 + + function test_add_i_i() { let a = 1; let b = 2; @@ -774,6 +795,14 @@ function test_compare_diff_types() { } } +function test_mod_with_neg_int(a, b) { + return a % b; +} + +function test_mod_with_pos_int(a, b) { + return (a % b) + 1; +} + test_add(); test_sub(); test_and(); @@ -794,3 +823,11 @@ NO_COMPILE_test_ldconst(); test_string(); test_strict_compare_diff_types(); test_compare_diff_types(); + +test_mod_with_neg_int(-3, 4); +test_mod_with_neg_int(-3, 4); +test_mod_with_pos_int(3, 4); +test_mod_with_pos_int(3, 4); +test_mod_with_pos_int(3, 0); +test_mod_with_pos_int(0, 3); +test_mod_with_pos_int(-1, 3); -- Gitee