diff --git a/compiler/intrinsics_inline_ecmascript.inl b/compiler/intrinsics_inline_ecmascript.inl index e65c094d0a89727c7debac65ef83a719c4e6f881..0378534eb426571bded007912d52339455136603 100644 --- a/compiler/intrinsics_inline_ecmascript.inl +++ b/compiler/intrinsics_inline_ecmascript.inl @@ -97,3 +97,31 @@ case RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER: { ASSERT(types_.size() == 1); return InlineToNumberDyn(intrinsic, types_[0]); } +case RuntimeInterface::IntrinsicId::INTRINSIC_LDTRUE: { + ASSERT(types_.size() == 0); + return InlineLdTrue(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_LDFALSE: { + ASSERT(types_.size() == 0); + return InlineLdFalse(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_LDHOLE: { + ASSERT(types_.size() == 0); + return InlineLdHole(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_LDNULL: { + ASSERT(types_.size() == 0); + return InlineLdNull(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_LDUNDEFINED: { + ASSERT(types_.size() == 0); + return InlineLdUndefined(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_LDINFINITY: { + ASSERT(types_.size() == 0); + return InlineLdInfinity(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_LDNAN: { + ASSERT(types_.size() == 0); + return InlineLdNan(intrinsic); +} \ No newline at end of file diff --git a/compiler/intrinsics_type_resolving_ecmascript.cpp b/compiler/intrinsics_type_resolving_ecmascript.cpp index ac119fda9611b250ca020d2463afe7ac31dd44d4..836ccbdb4db303102f4266a507605c310eef8da0 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.cpp +++ b/compiler/intrinsics_type_resolving_ecmascript.cpp @@ -14,6 +14,7 @@ */ #include "compiler/optimizer/optimizations/types_resolving.h" +#include "runtime/include/coretypes/tagged_value.h" namespace panda::compiler { template @@ -501,4 +502,59 @@ bool TypesResolving::InlineToNumberDyn(IntrinsicInst *intrinsics, AnyBaseType ty intrinsics->ClearFlag(compiler::inst_flags::NO_DCE); return true; } + +template +bool InlineLdConstant(IntrinsicInst *intrinsics, AnyBaseType any_type, T value) +{ + auto current_block = intrinsics->GetBasicBlock(); + auto graph = current_block->GetGraph(); + auto cnst = graph->FindOrCreateConstant(value); + + auto cast_to_any_inst = graph->CreateInstCastValueToAnyType(DataType::ANY, intrinsics->GetPc()); + current_block->InsertAfter(cast_to_any_inst, intrinsics); + cast_to_any_inst->SetAnyType(any_type); + cast_to_any_inst->SetInput(0, cnst); + + intrinsics->ReplaceUsers(cast_to_any_inst); + intrinsics->SetInlined(false); + current_block->RemoveInst(intrinsics); + return true; +} + +using TaggedValue = panda::coretypes::TaggedValue; + +bool TypesResolving::InlineLdTrue(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 1U); +} + +bool TypesResolving::InlineLdFalse(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 0U); +} + +bool TypesResolving::InlineLdHole(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_HOLE_TYPE, TaggedValue::VALUE_HOLE); +} + +bool TypesResolving::InlineLdNull(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_NULL_TYPE, TaggedValue::VALUE_NULL); +} + +bool TypesResolving::InlineLdUndefined(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE, TaggedValue::VALUE_UNDEFINED); +} + +bool TypesResolving::InlineLdInfinity(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, TaggedValue::VALUE_INFINITY); +} + +bool TypesResolving::InlineLdNan(IntrinsicInst *intrinsics) +{ + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, TaggedValue::VALUE_NAN); +} } // namespace panda::compiler diff --git a/compiler/intrinsics_type_resolving_ecmascript.inl.h b/compiler/intrinsics_type_resolving_ecmascript.inl.h index 2299286989635811b9cf33744ab737fcb8d555d3..12e0edc264da020a075eef61494f2e442cf4a94a 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.inl.h +++ b/compiler/intrinsics_type_resolving_ecmascript.inl.h @@ -29,5 +29,12 @@ bool InlineNotDyn(IntrinsicInst *intrinsics, AnyBaseType type); bool InlineNegDyn(IntrinsicInst *intrinsics, AnyBaseType type); bool InlineToBooleanDyn(IntrinsicInst *intrinsics, AnyBaseType type); bool InlineToNumberDyn(IntrinsicInst *intrinsics, AnyBaseType type); +bool InlineLdTrue(IntrinsicInst *intrinsics); +bool InlineLdFalse(IntrinsicInst *intrinsics); +bool InlineLdHole(IntrinsicInst *intrinsics); +bool InlineLdNull(IntrinsicInst *intrinsics); +bool InlineLdUndefined(IntrinsicInst *intrinsics); +bool InlineLdInfinity(IntrinsicInst *intrinsics); +bool InlineLdNan(IntrinsicInst *intrinsics); #endif // PLUGINS_ECMASCRIPT_COMPILER_INTRINSICS_TYPE_RESOLVING_ECMASCRIPT_INL_H \ No newline at end of file diff --git a/irtoc_scripts/common.irt b/irtoc_scripts/common.irt index b6cf45fa9becc36ba6d3e0760b39a0a348ef70ca..a7599aa0754447c31f5d343c05d4ccee580ebea1 100644 --- a/irtoc_scripts/common.irt +++ b/irtoc_scripts/common.irt @@ -29,8 +29,8 @@ module Constants TAGGED_HOLE = "DataType::Any(coretypes::TaggedValue::VALUE_HOLE)" TAGGED_NULL = "DataType::Any(coretypes::TaggedValue::VALUE_NULL)" TAGGED_UNDEFINED = "DataType::Any(coretypes::TaggedValue::VALUE_UNDEFINED)" - TAGGED_INFINITY = "DataType::Any(panda::coretypes::TaggedValue(std::numeric_limits::infinity()).GetRawData())" #panda::ecmascript::base::POSITIVE_INFINITY - TAGGED_NAN_VALUE = "DataType::Any(panda::coretypes::TaggedValue(std::numeric_limits::quiet_NaN()).GetRawData())" #panda::ecmascript::base::NAN_VALUE + TAGGED_INFINITY = "DataType::Any(panda::coretypes::TaggedValue(coretypes::TaggedValue::VALUE_INFINITY).GetRawData())" + TAGGED_NAN_VALUE = "DataType::Any(panda::coretypes::TaggedValue(coretypes::TaggedValue::VALUE_NAN).GetRawData())" ECMASTRING_JSTYPE_STRING = "JSTYPE_STRING" ECMASTRING_MIX_LENGTH_FIELD = "runtime->GetFieldByOffset(cross_values::GetEcmastringMixLengthOffset(graph->GetArch()))" diff --git a/runtime/base/number_helper.h b/runtime/base/number_helper.h index 61c544dff4ffb03b69ce706c069e2d360ed0220b..f997bbe7ac83b2ba3bfd69c617656f3365ded415 100644 --- a/runtime/base/number_helper.h +++ b/runtime/base/number_helper.h @@ -20,6 +20,7 @@ #include "plugins/ecmascript/runtime/ecma_string.h" #include "plugins/ecmascript/runtime/js_tagged_value.h" +#include "include/coretypes/tagged_value.h" namespace panda::ecmascript::base { // NOLINTNEXTLINE(modernize-avoid-c-arrays) @@ -50,8 +51,8 @@ static constexpr double EPSILON = std::numeric_limits::epsilon(); static constexpr double MAX_SAFE_INTEGER = 9007199254740991; static constexpr double MAX_VALUE = std::numeric_limits::max(); static constexpr double MIN_VALUE = std::numeric_limits::min(); -static constexpr double POSITIVE_INFINITY = std::numeric_limits::infinity(); -static constexpr double NAN_VALUE = std::numeric_limits::quiet_NaN(); +static constexpr double POSITIVE_INFINITY = coretypes::TaggedValue::VALUE_INFINITY; +static constexpr double NAN_VALUE = coretypes::TaggedValue::VALUE_NAN; // Helper defines for double static constexpr int DOUBLE_MAX_PRECISION = 15; diff --git a/tests/checked/type_resolving.js b/tests/checked/type_resolving.js index e6ffed9af80d5b000ec691cd550b52d2e2e34d8e..00f429ac1292741f42f74f813b4bc2913b73d33c 100644 --- a/tests/checked/type_resolving.js +++ b/tests/checked/type_resolving.js @@ -14,7 +14,7 @@ */ //! CHECKER Test arithmetic aot -//! RUN_PAOC options: "--compiler-regex '_GLOBAL::test_(\\w+_[if](_[if]|)|toboolean)'" +//! RUN_PAOC options: "--compiler-regex '_GLOBAL::test_(\\w+_[if](_[if]|)|toboolean|ld.*)'" //! check_aot = lambda do |op, intrinsic, form, inst| //! METHOD "test_#{op.downcase}_#{form}" //! PASS_BEFORE "TypesResolving" @@ -68,6 +68,12 @@ //! check_aot.call(:Inc, 'IncDyn', 'f', /f64 +Add/) //! check_aot.call(:Dec, 'DecDyn', 'i', /SubOverflowCheck/) //! check_aot.call(:Dec, 'DecDyn', 'f', /f64 +Sub/) +//! check_aot.call(:Ldtrue, 'Ldtrue', '', /i64 +Constant +0x1/) +//! check_aot.call(:Ldfalse, 'Ldfalse', '', /i64 +Constant +0x0/) +//! check_aot.call(:Ldnull, 'Ldnull', '', /i64 +Constant +0x2/) +//! check_aot.call(:Ldundefined, 'Ldundefined', '', /i64 +Constant +0xa/) +//! check_aot.call(:Ldinfinity, 'Ldinfinity', '', /f64 +Constant +inf/) +//! check_aot.call(:Ldnan, 'Ldnan', '', /f64 +Constant +nan/) //! //! forms = [['i_i', 'i32'], ['i_f', 'f64'], ['f_i', 'f64'], ['f_f', 'f64']] //! insts = [['eq', 'Eq'], ['ne', 'NotEq'], ['ge', 'GreaterEq'], ['le', 'LessEq'], ['gt', 'Greater'], ['lt', 'Less']] @@ -575,6 +581,44 @@ function test_toboolean() { } } +function test_ldtrue() { + return true; +} + +function test_ldfalse() { + return false; +} + +function test_ldnull() { + return null; +} + +function test_ldundefined() { + return undefined; +} + +function test_ldinfinity() { + return Infinity; +} + +function test_ldnan() { + return NaN; +} + +// For correct check we do not need to compile this method. +function NO_COMPILE_test_ldconst() { + let res = 0; + if (test_ldtrue() == true) res += 1; + if (test_ldfalse() == false) res += 2; + if (test_ldnull() == null) res += 3; + if (test_ldundefined() == undefined) res += 4; + if (test_ldinfinity() == Infinity) res += 5; + if (isNaN(test_ldnan())) res += 6; + if (res != 21) { + throw "NO_COMPILE_test_ldconst is failed"; + } +} + test_add(); test_sub(); test_and(); @@ -590,3 +634,4 @@ test_inc(); test_dec(); test_cmp(); test_toboolean(); +NO_COMPILE_test_ldconst(); \ No newline at end of file diff --git a/tests/compiler/types_resolving_ecma_tests.cpp b/tests/compiler/types_resolving_ecma_tests.cpp index 1f51194d00a435c68f225d69616bb45d903dc218..9f7d78175b443d4e02b9d497dd652b871ba2dbf9 100644 --- a/tests/compiler/types_resolving_ecma_tests.cpp +++ b/tests/compiler/types_resolving_ecma_tests.cpp @@ -18,18 +18,73 @@ #include "optimizer/ir/graph_cloner.h" #include "optimizer/optimizations/cleanup.h" #include "optimizer/optimizations/types_resolving.h" +#include "runtime/include/coretypes/tagged_value.h" namespace panda::compiler { class TypeResolvingTest : public AsmTest { public: TypeResolvingTest() {} + Graph *ConstructGraphWithIntrinsic(RuntimeInterface::IntrinsicId id); Graph *ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeInterface::IntrinsicId id); Graph *ConstructGraphWithIntrinsic(AnyBaseType type1, AnyBaseType type2, RuntimeInterface::IntrinsicId id); Graph *ConstructGraphWithOpcode1(AnyBaseType type, Opcode opcode); Graph *ConstructGraphWithOpcode2(AnyBaseType type, Opcode opcode); + + template + using TestArray = std::array, N>; + + template + Graph *ConstructGraphWithConst(AnyBaseType any_type, T cnst); + + template + void TestLdConsts(TestArray tests); }; +template +Graph *TypeResolvingTest::ConstructGraphWithConst(AnyBaseType any_type, T cnst) +{ + auto graph = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph) + { + CONSTANT(0, cnst); + BASIC_BLOCK(2, -1) + { + INST(3, Opcode::CastValueToAnyType).any().AnyType(any_type).Inputs(0); + INST(4, Opcode::Return).any().Inputs(3); + } + } + return graph; +} + +template +void TypeResolvingTest::TestLdConsts(TestArray tests) +{ + for (auto [id, any_type, cnst] : tests) { + auto graph = ConstructGraphWithIntrinsic(id); + ASSERT_TRUE(graph->template RunPass()); + ASSERT_TRUE(graph->template RunPass()); + GraphChecker(graph).Check(); + auto graph_opt = ConstructGraphWithConst(any_type, cnst); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + } +} + +Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(RuntimeInterface::IntrinsicId id) +{ + auto graph = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph) + { + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs().SrcVregs({}); + INST(3, Opcode::Intrinsic).any().IntrinsicId(id).Inlined().Inputs({{DataType::NO_TYPE, 2}}); + INST(4, Opcode::Return).any().Inputs(3); + } + } + return graph; +} + Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeInterface::IntrinsicId id) { auto graph = CreateGraphDynWithDefaultRuntime(); @@ -124,6 +179,33 @@ Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type1, AnyBase return graph; } +TEST_F(TypeResolvingTest, LdConst) +{ + using TaggedValue = panda::coretypes::TaggedValue; + { + TestArray tests = {{ + {RuntimeInterface::IntrinsicId::INTRINSIC_LDTRUE, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 1U}, + {RuntimeInterface::IntrinsicId::INTRINSIC_LDFALSE, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 0U}, + {RuntimeInterface::IntrinsicId::INTRINSIC_LDHOLE, AnyBaseType::ECMASCRIPT_HOLE_TYPE, + TaggedValue::VALUE_HOLE}, + {RuntimeInterface::IntrinsicId::INTRINSIC_LDNULL, AnyBaseType::ECMASCRIPT_NULL_TYPE, + TaggedValue::VALUE_NULL}, + {RuntimeInterface::IntrinsicId::INTRINSIC_LDUNDEFINED, AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE, + TaggedValue::VALUE_UNDEFINED}, + }}; + TestLdConsts(tests); + } + { + TestArray tests = {{ + {RuntimeInterface::IntrinsicId::INTRINSIC_LDINFINITY, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, + TaggedValue::VALUE_INFINITY}, + {RuntimeInterface::IntrinsicId::INTRINSIC_LDNAN, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, + TaggedValue::VALUE_NAN}, + }}; + TestLdConsts(tests); + } +} + TEST_F(TypeResolvingTest, ToNumber) { // Case with Int