diff --git a/compiler/intrinsics_inline_ecmascript.inl b/compiler/intrinsics_inline_ecmascript.inl index e1df2811732ae485f3e1789c9e2d15766a31f484..24194eb2e48dc1bcafcd12cf0abd4457e4b1b16c 100644 --- a/compiler/intrinsics_inline_ecmascript.inl +++ b/compiler/intrinsics_inline_ecmascript.inl @@ -110,7 +110,8 @@ case RuntimeInterface::IntrinsicId::INTRINSIC_TOBOOLEAN: { } case RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER: { ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineToNumberDyn(intrinsic, types_[0]); + auto special_allowed = (GetAllowedTypeForInput(intrinsic, 0) & profiling::AnyInputType::SPECIAL) != 0; + return panda::compiler::IrtocInlineToNumberDyn(intrinsic, types_[0], special_allowed); } case RuntimeInterface::IntrinsicId::INTRINSIC_IS_FALSE: { ASSERT(types_.size() == 1); diff --git a/compiler/intrinsics_type_resolving_ecmascript.cpp b/compiler/intrinsics_type_resolving_ecmascript.cpp index 03741c3c7ce8f2f73e5a8eff999a3e9a6e72cd0f..0301b6d0c517e43876ba730443d279c5a92c240e 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.cpp +++ b/compiler/intrinsics_type_resolving_ecmascript.cpp @@ -19,18 +19,6 @@ #include "runtime/include/coretypes/tagged_value.h" namespace panda::compiler { -bool TypesResolving::InlineToNumberDyn(IntrinsicInst *intrinsic, AnyBaseType type) -{ - ASSERT(type != AnyBaseType::UNDEFINED_TYPE); - if (type != AnyBaseType::ECMASCRIPT_INT_TYPE && type != AnyBaseType::ECMASCRIPT_DOUBLE_TYPE) { - return false; - } - intrinsic->ReplaceUsers(intrinsic->GetInput(0).GetInst()); - intrinsic->SetInlined(false); - intrinsic->ClearFlag(compiler::inst_flags::NO_DCE); - return true; -} - template bool InlineLdConstant(IntrinsicInst *intrinsic, AnyBaseType any_type, T value) { @@ -769,6 +757,15 @@ bool TypesResolving::InlineResolveAllocResult(IntrinsicInst *intrinsic) return true; } +profiling::AnyInputType TypesResolving::GetAllowedTypeForInput(IntrinsicInst *intrinsic, size_t index) +{ + auto input = intrinsic->GetInput(index).GetInst(); + if (input->GetOpcode() == Opcode::AnyTypeCheck) { + return input->CastToAnyTypeCheck()->GetAllowedInputType(); + } + return profiling::AnyInputType::DEFAULT; +} + bool TypesResolving::InlineStrictCompareDifferentTypes(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) { ASSERT(intrinsic->GetIntrinsicId() == RuntimeInterface::IntrinsicId::INTRINSIC_STRICT_EQ_DYN || diff --git a/compiler/intrinsics_type_resolving_ecmascript.inl.h b/compiler/intrinsics_type_resolving_ecmascript.inl.h index a6095fc85859315bef36cfca0ce0783e1e1f1e18..c7d6068f918cfd458636834caeb7044935397e1c 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.inl.h +++ b/compiler/intrinsics_type_resolving_ecmascript.inl.h @@ -16,7 +16,6 @@ #ifndef PLUGINS_ECMASCRIPT_COMPILER_INTRINSICS_TYPE_RESOLVING_ECMASCRIPT_INL_H #define PLUGINS_ECMASCRIPT_COMPILER_INTRINSICS_TYPE_RESOLVING_ECMASCRIPT_INL_H -bool InlineToNumberDyn(IntrinsicInst *intrinsic, AnyBaseType type); bool InlineLdTrue(IntrinsicInst *intrinsic); bool InlineLdFalse(IntrinsicInst *intrinsic); bool InlineLdHole(IntrinsicInst *intrinsic); @@ -55,6 +54,7 @@ void CreateCompareClass(uint32_t pc, Inst *get_cls_inst, RuntimeInterface::Class Inst *CreateCompareClassWithDeopt(uint32_t pc, Inst *get_cls_inst, RuntimeInterface::ClassPtr receiver, Inst *save_state); +profiling::AnyInputType GetAllowedTypeForInput(IntrinsicInst *intrinsic, size_t index); bool InlineStrictCompareDifferentTypes(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); bool InlineCompareWithNull(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index f2aafae6f25254db3cb9667741e2fdb7d893f71e..dbcad22282c9339dd74d30380b338ca2817898d6 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -589,17 +589,36 @@ macro(:tonumberdyn_double) do |v| v end +# v here will be AnyTypeCheck, and CastValueToAnyType will copy its allowed types +# (int as double / null / boolean / undefined) +macro(:tonumberdyn_smi_special) do |v| + i32toany(anytoi32(v)) +end + +macro(:tonumberdyn_double_special) do |v| + f64toany(anytof64(v)) +end + cpp_function(:"IrtocInlineToNumberDyn") do params type1: 'any' + cpp_params special: 'bool' return_type 'bool' variant(:tonumberdyn_smi) { - condition "type1 == AnyBaseType::ECMASCRIPT_INT_TYPE" + condition "type1 == AnyBaseType::ECMASCRIPT_INT_TYPE && !special" code { Return(tonumberdyn_smi(type1)) } } variant(:tonumberdyn_double) { - condition "type1 == AnyBaseType::ECMASCRIPT_DOUBLE_TYPE" + condition "type1 == AnyBaseType::ECMASCRIPT_DOUBLE_TYPE && !special" code { Return(tonumberdyn_double(type1)) } } + variant(:tonumberdyn_smi_special) { + condition "type1 == AnyBaseType::ECMASCRIPT_INT_TYPE && special" + code { Return(tonumberdyn_smi_special(type1)) } + } + variant(:tonumberdyn_double_special) { + condition "type1 == AnyBaseType::ECMASCRIPT_DOUBLE_TYPE && special" + code { Return(tonumberdyn_double_special(type1)) } + } end #################################################################### diff --git a/tests/compiler/types_resolving_ecma_tests.cpp b/tests/compiler/types_resolving_ecma_tests.cpp index 19498349c6dd3f35f1672a0cbe785f1cd05c891e..906128e7b6827ae753f19fe97d59ccc689bb0d6a 100644 --- a/tests/compiler/types_resolving_ecma_tests.cpp +++ b/tests/compiler/types_resolving_ecma_tests.cpp @@ -27,7 +27,8 @@ public: TypeResolvingTest() = default; Graph *ConstructGraphWithIntrinsic(RuntimeInterface::IntrinsicId id); - Graph *ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeInterface::IntrinsicId id); + Graph *ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeInterface::IntrinsicId id, + profiling::AnyInputType allowed_type = profiling::AnyInputType::DEFAULT); Graph *ConstructGraphWithIntrinsic(AnyBaseType type1, AnyBaseType type2, RuntimeInterface::IntrinsicId id); Graph *ConstructGraphWithOpcode1(AnyBaseType type, Opcode opcode); Graph *ConstructGraphWithOpcode2(AnyBaseType type, Opcode opcode); @@ -108,7 +109,8 @@ Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(RuntimeInterface::Intrinsi return graph; } -Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeInterface::IntrinsicId id) +Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeInterface::IntrinsicId id, + profiling::AnyInputType allowed_type) { auto graph = CreateGraphDynWithDefaultRuntime(); GRAPH(graph) @@ -119,7 +121,7 @@ Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeI BASIC_BLOCK(2, -1) { INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); - INST(4, Opcode::AnyTypeCheck).any().AnyType(type).Inputs(0, 2); + INST(4, Opcode::AnyTypeCheck).any().AnyType(type).AllowedInputType(allowed_type).Inputs(0, 2); INST(5, Opcode::Intrinsic) .any() .IntrinsicId(id) @@ -261,10 +263,42 @@ TEST_F(TypeResolvingTest, ToNumber) ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); } - // Case with Double + // Case with Int when boolean and null inputs are allowed { + auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_INT_TYPE, + RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER, + profiling::AnyInputType::SPECIAL); + ASSERT_TRUE(graph->RunPass()); + graph->RunPass(); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + PARAMETER(1, 1).any(); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); + INST(3, Opcode::AnyTypeCheck) + .any() + .AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE) + .AllowedInputType(profiling::AnyInputType::SPECIAL) + .Inputs(0, 2); + INST(4, Opcode::CastAnyTypeValue).s32().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(3); + INST(5, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(4); + INST(9, Opcode::Return).any().Inputs(5); + } + } + + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + } + + // Case with Double + for (auto allowed_type : {profiling::AnyInputType::DEFAULT, profiling::AnyInputType::INTEGER}) { auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, - RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER); + RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER, allowed_type); ASSERT_TRUE(graph->RunPass()); graph->RunPass(); GraphChecker(graph).Check(); @@ -286,6 +320,38 @@ TEST_F(TypeResolvingTest, ToNumber) ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); } + // Case with Double when boolean, undefined and null inputs are allowed + { + auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, + RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER, + profiling::AnyInputType::SPECIAL); + ASSERT_TRUE(graph->RunPass()); + graph->RunPass(); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + PARAMETER(1, 1).any(); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); + INST(3, Opcode::AnyTypeCheck) + .any() + .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE) + .AllowedInputType(profiling::AnyInputType::SPECIAL) + .Inputs(0, 2); + INST(4, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3); + INST(5, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(4); + INST(9, Opcode::Return).any().Inputs(5); + } + } + + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + } + // Case with Object { auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_OBJECT_TYPE,