From ec4265b3e474abd4bd5e025a15e0e1104662db1e Mon Sep 17 00:00:00 2001 From: Andrey Efremov Date: Wed, 28 Dec 2022 21:18:54 +0300 Subject: [PATCH] Replace Intrinsic.DynCallCheck by inst DynamicCallCheck Signed-off-by: Andrey Efremov --- compiler/codegen_intrinsics_ecmascript.cpp | 14 -- .../code_generator/compiler_base_types.cpp | 19 ++ .../code_generator/compiler_base_types.h | 1 + .../ir_builder/ecmascript_inst_builder.cpp | 14 +- ecmascript_plugin_options.yaml | 1 + runtime/ecma_runtime.yaml | 12 -- tests/checked/ecma_call_profile_clear.js | 2 +- tests/checked/ecma_inlining.js | 10 + .../compiler/checks_elimination_ecma_test.cpp | 190 ++++++++++++++++++ 9 files changed, 226 insertions(+), 37 deletions(-) diff --git a/compiler/codegen_intrinsics_ecmascript.cpp b/compiler/codegen_intrinsics_ecmascript.cpp index c26eeb35c..426ac75dc 100644 --- a/compiler/codegen_intrinsics_ecmascript.cpp +++ b/compiler/codegen_intrinsics_ecmascript.cpp @@ -323,20 +323,6 @@ void Codegen::CreateDynObjectSetClass(IntrinsicInst *inst, [[maybe_unused]] Reg } } -void Codegen::CreateDynCallCheck([[maybe_unused]] IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src) -{ - auto exit_label = CreateSlowPath(inst, DeoptimizeType::ANY_TYPE_CHECK)->GetLabel(); - - ScopedTmpReg tmp(GetEncoder(), ConvertDataType(DataType::UINT64, GetArch())); - - LoadClassFromObject(tmp, src[0]); - GetEncoder()->EncodeLdr(tmp, false, - MemRef(tmp, -cross_values::GetJshclassHclassOffset(GetArch()) + - cross_values::GetJshclassBitfieldOffset(GetArch()))); - GetEncoder()->EncodeBitTestAndBranch(exit_label, tmp, - cross_values::GetJshclassBitfieldClassConstructorStartBit(GetArch()), true); -} - void Codegen::CreateDynClassNumberOfProps([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src) { ScopedTmpReg tmp_reg(GetEncoder(), ConvertDataType(DataType::UINT64, GetArch())); diff --git a/compiler/optimizer/code_generator/compiler_base_types.cpp b/compiler/optimizer/code_generator/compiler_base_types.cpp index 7cb21fb5c..4820fdfda 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.cpp +++ b/compiler/optimizer/code_generator/compiler_base_types.cpp @@ -496,4 +496,23 @@ bool ecmascript::AnyTypeCheckGen(AnyTypeCheckInst *check_inst, EncodeVisitor *en return false; } +bool ecmascript::DynamicCallCheckGen(FixedInputsInst2 *check_inst, EncodeVisitor *enc_v) +{ + auto enc = enc_v->GetEncoder(); + auto codegen = enc_v->GetCodegen(); + auto arch = codegen->GetArch(); + auto src = codegen->ConvertRegister(check_inst->GetSrcReg(0), DataType::Type::ANY); + auto exit_label = + codegen->CreateSlowPath(check_inst, DeoptimizeType::ANY_TYPE_CHECK)->GetLabel(); + + ScopedTmpReg tmp(enc, codegen->ConvertDataType(DataType::UINT64, arch)); + + codegen->LoadClassFromObject(tmp, src); + enc->EncodeLdr( + tmp, false, + MemRef(tmp, -cross_values::GetJshclassHclassOffset(arch) + cross_values::GetJshclassBitfieldOffset(arch))); + enc->EncodeBitTestAndBranch(exit_label, tmp, cross_values::GetJshclassBitfieldClassConstructorStartBit(arch), true); + return true; +} + } // namespace panda::compiler diff --git a/compiler/optimizer/code_generator/compiler_base_types.h b/compiler/optimizer/code_generator/compiler_base_types.h index c76c24376..b228e37c4 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.h +++ b/compiler/optimizer/code_generator/compiler_base_types.h @@ -33,6 +33,7 @@ bool CastAnyTypeValueGen(const CastAnyTypeValueInst *cati, EncodeVisitor *enc_v) bool CastValueToAnyTypeGen(const CastValueToAnyTypeInst *cvai, EncodeVisitor *enc_v); bool AnyTypeCheckGen(AnyTypeCheckInst *check_inst, EncodeVisitor *enc_v); bool ObjByIndexCheckGen(const FixedInputsInst2 *check_inst, EncodeVisitor *enc_v, LabelHolder::LabelId id); +bool DynamicCallCheckGen(FixedInputsInst2 *check_inst, EncodeVisitor *enc_v); } // namespace ecmascript } // namespace panda::compiler diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp index b73ec2297..94505581d 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp @@ -59,17 +59,11 @@ void InstBuilder::BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_ra } { // Check callee is suitable to call (!IsConstructor) - auto fn_class_check = GetGraph()->CreateInstIntrinsic(DataType::ANY, bc_pc); - fn_class_check->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_DYN_CALL_CHECK); - AdjustFlags(fn_class_check->GetIntrinsicId(), fn_class_check); - fn_class_check->SetFlag(inst_flags::CAN_DEOPTIMIZE); - fn_class_check->ReserveInputs(1); - fn_class_check->AllocateInputTypes(GetGraph()->GetAllocator(), 1); - fn_class_check->AppendInput(callee); - fn_class_check->AddInputType(DataType::ANY); - fn_class_check->AppendInput(save_state); - fn_class_check->AddInputType(DataType::NO_TYPE); + auto fn_class_check = GetGraph()->CreateInstDynamicCallCheck(DataType::ANY, bc_pc); + fn_class_check->SetInput(0, callee); + fn_class_check->SetInput(1, save_state); AddInstruction(fn_class_check); + callee = fn_class_check; } auto call_inst = GetGraph()->CreateInstCallDynamic(DataType::ANY, bc_pc); diff --git a/ecmascript_plugin_options.yaml b/ecmascript_plugin_options.yaml index 95b1cd8a6..c11fc3339 100644 --- a/ecmascript_plugin_options.yaml +++ b/ecmascript_plugin_options.yaml @@ -41,6 +41,7 @@ func_cast_implementation_codegen: panda::compiler::ecmascript::CastAnyTypeValueGen func_cast_to_any_implementation_codegen: panda::compiler::ecmascript::CastValueToAnyTypeGen func_any_type_check_implementation_codegen: panda::compiler::ecmascript::AnyTypeCheckGen + func_dynamic_call_check_implementation_codegen: panda::compiler::ecmascript::DynamicCallCheckGen func_obj_by_index_check_implementation_codegen: panda::compiler::ecmascript::ObjByIndexCheckGen func_resolve_numeric_type: panda::compiler::ecmascript::NumericDataTypeToAnyType func_resolve_string_type: panda::compiler::ecmascript::GetAnyStringType diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 9e733b931..532961830 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -2226,18 +2226,6 @@ intrinsics: use_thread: false clear_flags: [require_state, runtime_call] -- name: DynCallCheck - space: ecmascript - class_name: Ecmascript.Intrinsics - method_name: CreateDynCallCheck - static: true - signature: - ret: void - args: [any] - codegen_func: CreateDynCallCheck - use_thread: false - clear_flags: [] - - name: DynClassNumberOfProps space: ecmascript class_name: Ecmascript.Intrinsics diff --git a/tests/checked/ecma_call_profile_clear.js b/tests/checked/ecma_call_profile_clear.js index 3cea1b9df..0cfa7ecf4 100644 --- a/tests/checked/ecma_call_profile_clear.js +++ b/tests/checked/ecma_call_profile_clear.js @@ -17,7 +17,7 @@ //! CHECKER Clear call profile after deoptimize. Deoptimize happend with PC for DynamicCall. //! RUN_PAOC options: "" //! RUN options: "--compiler-enable-jit=false", entry: "_GLOBAL::func_main_0" -//! EVENT /DeoptimizationReason,_GLOBAL::.*test.*,NOT_SMALL_INT/ +//! EVENT /DeoptimizationReason,_GLOBAL::.*test.*,DOUBLE_WITH_INT/ //! EVENT /Deoptimization,_GLOBAL::.*test.*,.*,CFRAME/ function construct(len) { diff --git a/tests/checked/ecma_inlining.js b/tests/checked/ecma_inlining.js index 3526aaf15..7e026efd3 100644 --- a/tests/checked/ecma_inlining.js +++ b/tests/checked/ecma_inlining.js @@ -18,6 +18,16 @@ //! EVENT /Inline,_GLOBAL::test,_GLOBAL::one,.*DYNAMIC_MONOMORPHIC,SUCCESS/ //! EVENT /Compilation,_GLOBAL::test,.*,COMPILED/ //! EVENT_NOT /Deoptimization,_GLOBAL::.*test.*,.*,IFRAME/ + +//! CHECKER Remove DynamicCallCheck for inlined ecma method +//! RUN options: "--no-async-jit --compiler-hotness-threshold=10 --compiler-regex _GLOBAL::test", entry: "_GLOBAL::func_main_0" +//! METHOD "test" +//! PASS_AFTER "IrBuilder" +//! INST "DynamicCallCheck" +//! PASS_AFTER "ChecksElimination" +//! INST "CallDynamic" +//! INST_NOT "DynamicCallCheck" + function one() { return 1; } diff --git a/tests/compiler/checks_elimination_ecma_test.cpp b/tests/compiler/checks_elimination_ecma_test.cpp index 6413ed98e..5f86e7a91 100644 --- a/tests/compiler/checks_elimination_ecma_test.cpp +++ b/tests/compiler/checks_elimination_ecma_test.cpp @@ -562,6 +562,196 @@ TEST_F(CheckEliminationEcmaTest, EliminateAnyTypeCheckWithUndefinedType) EXPECT_TRUE(GraphComparator().Compare(graph, graph_opt)); } + +TEST_F(CheckEliminationEcmaTest, EliminateDuplicateDynamicCallCheck) +{ + auto graph = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + PARAMETER(1, 1).any(); + CONSTANT(10, 0xa).any(); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); + + INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_FUNCTION_TYPE).Inputs(0, 2); + INST(4, Opcode::DynamicCallCheck).any().Inputs(3, 2); + INST(5, Opcode::CallDynamic).any().InputsAutoType(4, 10, 10, 1, 2); + + INST(6, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_FUNCTION_TYPE).Inputs(0, 2); + INST(7, Opcode::DynamicCallCheck).any().Inputs(6, 2); + INST(8, Opcode::CallDynamic).any().InputsAutoType(7, 10, 10, 5, 2); + + INST(9, Opcode::Return).any().Inputs(8); + } + } + + ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynWithDefaultRuntime(); + + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + PARAMETER(1, 1).any(); + CONSTANT(10, 0xa).any(); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); + + INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_FUNCTION_TYPE).Inputs(0, 2); + INST(4, Opcode::DynamicCallCheck).any().Inputs(3, 2); + INST(5, Opcode::CallDynamic).any().InputsAutoType(4, 10, 10, 1, 2); + + INST(8, Opcode::CallDynamic).any().InputsAutoType(4, 10, 10, 5, 2); + + INST(9, Opcode::Return).any().Inputs(8); + } + } + + EXPECT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} + +TEST_F(CheckEliminationEcmaTest, EliminateDynamicCallCheckInlined) +{ + auto graph = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + PARAMETER(1, 1).any(); + CONSTANT(10, 0xa).any(); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); + + INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_FUNCTION_TYPE).Inputs(0, 2); + INST(4, Opcode::DynamicCallCheck).any().Inputs(3, 2); + INST(5, Opcode::CallDynamic).any().Inlined().InputsAutoType(4, 10, 10, 1, 2); + INST(6, Opcode::ReturnInlined).Inputs(2); + + INST(9, Opcode::Return).any().Inputs(5); + } + } + + ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynWithDefaultRuntime(); + + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + PARAMETER(1, 1).any(); + CONSTANT(10, 0xa).any(); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); + + INST(5, Opcode::CallDynamic).any().Inlined().InputsAutoType(0, 10, 10, 1, 2); + INST(6, Opcode::ReturnInlined).Inputs(2); + + INST(9, Opcode::Return).any().Inputs(5); + } + } + + EXPECT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} + +TEST_F(CheckEliminationEcmaTest, MoveDynamicCallCheckFromLoop) +{ + auto graph = CreateGraphDynWithDefaultRuntime(); + GRAPH(graph) + { + CONSTANT(0, 0); // initial + CONSTANT(1, 1); // increment + CONSTANT(2, 10); + + BASIC_BLOCK(2, 3, 5) + { + INST(3, Opcode::SaveState).Inputs(0, 1, 2).SrcVregs({0, 1, 2}); + INST(4, Opcode::Intrinsic) + .any() + .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN) + .Inputs({{compiler::DataType::NO_TYPE, 3}}); + INST(5, Opcode::Intrinsic) + .any() + .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_DEFINEFUNC_DYN) + .Inputs({{compiler::DataType::ANY, 4}, {compiler::DataType::NO_TYPE, 3}}); + INST(20, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5}); + INST(6, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0, 2); // 0 < 10 + INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6); + } + BASIC_BLOCK(3, 3, 5) + { + INST(8, Opcode::Phi).s32().Inputs(0, 13); + INST(9, Opcode::SaveState).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5}); + INST(10, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_FUNCTION_TYPE).Inputs(5, 9); + INST(11, Opcode::DynamicCallCheck).any().Inputs(10, 9); + INST(12, Opcode::CallDynamic).any().InputsAutoType(11, 2, 2, 8, 9); + + INST(13, Opcode::Add).s32().Inputs(8, 1); // i++ + INST(14, Opcode::Compare).CC(CC_LT).b().Inputs(13, 2); // i < 10 + INST(15, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(14); + } + BASIC_BLOCK(5, 1) + { + INST(16, Opcode::ReturnVoid).v0id(); + } + } + + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynWithDefaultRuntime(); + + GRAPH(graph_opt) + { + CONSTANT(0, 0); // initial + CONSTANT(1, 1); // increment + CONSTANT(2, 10); + + BASIC_BLOCK(2, 3, 5) + { + INST(3, Opcode::SaveState).Inputs(0, 1, 2).SrcVregs({0, 1, 2}); + INST(4, Opcode::Intrinsic) + .any() + .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN) + .Inputs({{compiler::DataType::NO_TYPE, 3}}); + INST(5, Opcode::Intrinsic) + .any() + .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_DEFINEFUNC_DYN) + .Inputs({{compiler::DataType::ANY, 4}, {compiler::DataType::NO_TYPE, 3}}); + INST(20, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5}); + INST(10, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_FUNCTION_TYPE).Inputs(5, 20); + INST(11, Opcode::DynamicCallCheck).any().Inputs(10, 20); + INST(6, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0, 2); // 0 < 10 + INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6); + } + BASIC_BLOCK(3, 3, 5) + { + INST(8, Opcode::Phi).s32().Inputs(0, 13); + INST(9, Opcode::SaveState).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5}); + INST(12, Opcode::CallDynamic).any().InputsAutoType(11, 2, 2, 8, 9); + + INST(13, Opcode::Add).s32().Inputs(8, 1); // i++ + INST(14, Opcode::Compare).CC(CC_LT).b().Inputs(13, 2); // i < 10 + INST(15, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(14); + } + BASIC_BLOCK(5, 1) + { + INST(16, Opcode::ReturnVoid).v0id(); + } + } + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} // NOLINTEND(readability-magic-numbers) } // namespace panda::compiler -- Gitee