diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index e0b1d8120e4aa61549fe58334c3dcea57489dacc..63a9faea2c0f37339a27c798cc02fcd6708d4fa3 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -32,11 +32,11 @@ add_dependencies(arkcompiler runtime_options_gen) set(COMPILER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/optimizer/code_generator/compiler_base_types.cpp ${CMAKE_CURRENT_SOURCE_DIR}/optimizer/optimizations/ecma_inlining.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/intrinsics_type_resolving_ecmascript.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/inline_intrinsics_ecmascript.cpp ${CMAKE_CURRENT_SOURCE_DIR}/codegen_intrinsics_ecmascript.cpp ${CMAKE_CURRENT_SOURCE_DIR}/optimizer/ir_builder/ecmascript_inst_builder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/optimizer/ecma_pipeline.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/optimizer/optimizations/expand_intrinsics.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/optimizer/optimizations/inline_call_intrinsics.cpp ) target_sources(arkcompiler PRIVATE ${COMPILER_SOURCES}) diff --git a/compiler/ecma_compiler.yaml b/compiler/ecma_compiler.yaml index 042e401cb5a1cf10623536765443034fd549b289..8e91aa4232c7a3e72b8a7156e763e523ff1f7b6a 100644 --- a/compiler/ecma_compiler.yaml +++ b/compiler/ecma_compiler.yaml @@ -19,10 +19,10 @@ options: recommended_values: [50,8000] tags: [perf] -- name: compiler-ecma-expand-intrinsics +- name: compiler-ecma-inline-call-intrinsics type: bool default: true - description: Expand intrinsics into several IR instructions when applicable + description: Expand intrinsics into several IR instructions including dynamic call when applicable tags: [perf] - name: compiler-ecma-newobj-profiling diff --git a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h index a72ab4192deccf398364934b569f0a198fa7e35a..61280c095868fa0af76d298393f71ad69566fbf7 100644 --- a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h +++ b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h @@ -107,6 +107,12 @@ virtual GlobalVarInfo GetGlobalVarInfo([[maybe_unused]] MethodPtr method, [[mayb return {GlobalVarInfo::Type::DEFAULT, 0}; } +virtual GlobalVarInfo GetGlobalVarInfo([[maybe_unused]] MethodPtr method, [[maybe_unused]] uintptr_t func, + [[maybe_unused]] size_t id, [[maybe_unused]] uintptr_t slot_id) const +{ + return {GlobalVarInfo::Type::DEFAULT, 0}; +} + virtual uintptr_t GetGlobalConstStringOffsetForAnyType([[maybe_unused]] compiler::AnyBaseType type, [[maybe_unused]] Arch arch) const { diff --git a/compiler/intrinsics_type_resolving_ecmascript.cpp b/compiler/inline_intrinsics_ecmascript.cpp similarity index 66% rename from compiler/intrinsics_type_resolving_ecmascript.cpp rename to compiler/inline_intrinsics_ecmascript.cpp index d4dbf82b45c14258b46654fa92543f1ba950a7fe..77c8d4c4eab02bee9adfe9885d5a8b8d41eee892 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.cpp +++ b/compiler/inline_intrinsics_ecmascript.cpp @@ -13,10 +13,11 @@ * limitations under the License. */ -#include "compiler/optimizer/optimizations/types_resolving.h" +#include "compiler/optimizer/optimizations/inline_intrinsics.h" #include "optimizer/analysis/loop_analyzer.h" #include "compiler/optimizer/ir/analysis.h" #include "runtime/include/coretypes/tagged_value.h" +#include "irtoc_ir_inline.h" namespace panda::compiler { template @@ -32,7 +33,6 @@ bool InlineLdConstant(IntrinsicInst *intrinsic, AnyBaseType any_type, T value) cast_to_any_inst->SetInput(0, cnst); intrinsic->ReplaceUsers(cast_to_any_inst); - intrinsic->SetInlined(false); current_block->RemoveInst(intrinsic); return true; } @@ -45,49 +45,48 @@ bool InlineLdConstant(IntrinsicInst *intrinsic, DataType::Any value) intrinsic->ReplaceUsers(cnst); - intrinsic->SetInlined(false); current_block->RemoveInst(intrinsic); return true; } using TaggedValue = panda::coretypes::TaggedValue; -bool TypesResolving::InlineLdTrue(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdTrue(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 1U); } -bool TypesResolving::InlineLdFalse(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdFalse(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 0U); } -bool TypesResolving::InlineLdHole(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdHole(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, DataType::Any(TaggedValue::VALUE_HOLE)); } -bool TypesResolving::InlineLdNull(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdNull(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, DataType::Any(TaggedValue::VALUE_NULL)); } -bool TypesResolving::InlineLdUndefined(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdUndefined(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, DataType::Any(TaggedValue::VALUE_UNDEFINED)); } -bool TypesResolving::InlineLdInfinity(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdInfinity(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, TaggedValue::VALUE_INFINITY); } -bool TypesResolving::InlineLdNan(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdNan(IntrinsicInst *intrinsic) { return InlineLdConstant(intrinsic, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, TaggedValue::VALUE_NAN); } -bool TypesResolving::InlineTypeOf(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineTypeOf(IntrinsicInst *intrinsic) { auto any_type = intrinsic->GetInput(0).GetInst(); if (any_type->GetOpcode() != Opcode::AnyTypeCheck) { @@ -105,8 +104,8 @@ bool TypesResolving::InlineTypeOf(IntrinsicInst *intrinsic) return true; } -void TypesResolving::CreateCompareClass(uint32_t pc, Inst *get_cls_inst, RuntimeInterface::ClassPtr receiver, - BasicBlock *load_bb) +void InlineIntrinsics::CreateCompareClass(uint32_t pc, Inst *get_cls_inst, RuntimeInterface::ClassPtr receiver, + BasicBlock *load_bb) { auto load_cls_inst = GetGraph()->CreateInstClassImmediate(DataType::REFERENCE, pc, receiver); auto cmp_inst = GetGraph()->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_EQ); @@ -122,8 +121,8 @@ void TypesResolving::CreateCompareClass(uint32_t pc, Inst *get_cls_inst, Runtime load_bb->AppendInst(if_inst); } -Inst *TypesResolving::CreateCompareClassWithDeopt(uint32_t pc, Inst *get_cls_inst, RuntimeInterface::ClassPtr receiver, - Inst *save_state) +Inst *InlineIntrinsics::CreateCompareClassWithDeopt(uint32_t pc, Inst *get_cls_inst, + RuntimeInterface::ClassPtr receiver, Inst *save_state) { auto load_cls_inst = GetGraph()->CreateInstClassImmediate(DataType::REFERENCE, pc, receiver); auto cmp_inst = GetGraph()->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_NE); @@ -395,27 +394,27 @@ void InsertDeoptimizeInst(uint32_t pc, SaveStateInst *ss, BasicBlock *load_bb) load_bb->AppendInst(deopt_inst); } -bool TypesResolving::InlineLdObjByName(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdObjByName(IntrinsicInst *intrinsic) { return InlineObjByName(intrinsic); } -bool TypesResolving::InlineStObjByName(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineStObjByName(IntrinsicInst *intrinsic) { return InlineObjByName(intrinsic); } -bool TypesResolving::InlineLdObjByValue(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineLdObjByValue(IntrinsicInst *intrinsic) { return InlineObjByValue(intrinsic); } -bool TypesResolving::InlineStObjByValue(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineStObjByValue(IntrinsicInst *intrinsic) { return InlineObjByValue(intrinsic); } -bool TypesResolving::GetICForMemNamedAccess(IntrinsicInst *intrinsic) +bool InlineIntrinsics::GetICForMemNamedAccess(IntrinsicInst *intrinsic) { auto pc = intrinsic->GetPc(); auto runtime = GetGraph()->GetRuntime(); @@ -426,19 +425,14 @@ bool TypesResolving::GetICForMemNamedAccess(IntrinsicInst *intrinsic) ASSERT(caller_inst->IsInlined()); auto func = caller_inst->GetFunctionObject(); if (func != 0) { - if (!runtime->GetProfileDataForNamedAccess(GetGraph()->GetMethod(), func, pc, &named_access_profile_)) { - return false; - } - } else if (!runtime->GetProfileDataForNamedAccess(caller_inst->GetCallMethod(), pc, &named_access_profile_)) { - return false; + return runtime->GetProfileDataForNamedAccess(GetGraph()->GetMethod(), func, pc, &named_access_profile_); } - } else if (!runtime->GetProfileDataForNamedAccess(GetGraph()->GetMethod(), pc, &named_access_profile_)) { - return false; + return runtime->GetProfileDataForNamedAccess(caller_inst->GetCallMethod(), pc, &named_access_profile_); } - return true; + return runtime->GetProfileDataForNamedAccess(GetGraph()->GetMethod(), pc, &named_access_profile_); } -bool TypesResolving::GetICForMemValueAccess(IntrinsicInst *intrinsic) +bool InlineIntrinsics::GetICForMemValueAccess(IntrinsicInst *intrinsic) { auto pc = intrinsic->GetPc(); auto runtime = GetGraph()->GetRuntime(); @@ -449,19 +443,14 @@ bool TypesResolving::GetICForMemValueAccess(IntrinsicInst *intrinsic) ASSERT(caller_inst->IsInlined()); auto func = caller_inst->GetFunctionObject(); if (func != 0) { - if (!runtime->GetProfileDataForValueAccess(GetGraph()->GetMethod(), func, pc, &named_access_profile_)) { - return false; - } - } else if (!runtime->GetProfileDataForValueAccess(caller_inst->GetCallMethod(), pc, &named_access_profile_)) { - return false; + return runtime->GetProfileDataForValueAccess(GetGraph()->GetMethod(), func, pc, &named_access_profile_); } - } else if (!runtime->GetProfileDataForValueAccess(GetGraph()->GetMethod(), pc, &named_access_profile_)) { - return false; + return runtime->GetProfileDataForValueAccess(caller_inst->GetCallMethod(), pc, &named_access_profile_); } - return true; + return runtime->GetProfileDataForValueAccess(GetGraph()->GetMethod(), pc, &named_access_profile_); } -Inst *TypesResolving::InsertCheckAndCastInstructions(IntrinsicInst *intrinsic) +Inst *InlineIntrinsics::InsertCheckAndCastInstructions(IntrinsicInst *intrinsic) { auto pc = intrinsic->GetPc(); auto save_state = intrinsic->GetSaveState(); @@ -484,7 +473,7 @@ Inst *TypesResolving::InsertCheckAndCastInstructions(IntrinsicInst *intrinsic) } template -void TypesResolving::InlineObjByNameMonomorphic(IntrinsicInst *intrinsic, Inst *get_cls_inst, Inst *obj_inst) +void InlineIntrinsics::InlineObjByNameMonomorphic(IntrinsicInst *intrinsic, Inst *get_cls_inst, Inst *obj_inst) { auto pc = intrinsic->GetPc(); auto save_state = intrinsic->GetSaveState(); @@ -501,12 +490,11 @@ void TypesResolving::InlineObjByNameMonomorphic(IntrinsicInst *intrinsic, Inst * intrinsic->ReplaceUsers(load_inst); } - intrinsic->SetInlined(false); intrinsic->GetBasicBlock()->RemoveInst(intrinsic); } template -void TypesResolving::InlineObjByNamePolymorphic(IntrinsicInst *intrinsic, Inst *get_cls_inst, Inst *obj_inst) +void InlineIntrinsics::InlineObjByNamePolymorphic(IntrinsicInst *intrinsic, Inst *get_cls_inst, Inst *obj_inst) { auto pc = intrinsic->GetPc(); auto save_state = intrinsic->GetSaveState(); @@ -559,7 +547,6 @@ void TypesResolving::InlineObjByNamePolymorphic(IntrinsicInst *intrinsic, Inst * intrinsic->ReplaceUsers(phi_inst); } - intrinsic->SetInlined(false); intrinsic->GetBasicBlock()->RemoveInst(intrinsic); } @@ -583,7 +570,7 @@ void InsertCheckKeyInstructions(IntrinsicInst *intrinsic, uintptr_t key_mem) } template -void TypesResolving::InlineObjByValueWithKey(IntrinsicInst *intrinsic) +void InlineIntrinsics::InlineObjByValueWithKey(IntrinsicInst *intrinsic) { auto pc = intrinsic->GetPc(); auto save_state = intrinsic->GetSaveState(); @@ -606,12 +593,11 @@ void TypesResolving::InlineObjByValueWithKey(IntrinsicInst *intrinsic) intrinsic->ReplaceUsers(load_inst); } - intrinsic->SetInlined(false); intrinsic->GetBasicBlock()->RemoveInst(intrinsic); } template -void TypesResolving::InlineObjByValueFromElements(IntrinsicInst *intrinsic) +void InlineIntrinsics::InlineObjByValueFromElements(IntrinsicInst *intrinsic) { auto pc = intrinsic->GetPc(); auto save_state = intrinsic->GetSaveState(); @@ -707,12 +693,11 @@ void TypesResolving::InlineObjByValueFromElements(IntrinsicInst *intrinsic) InsertCheckJSArrayLength(cast_value, cast_value_int, bounds_check, save_state->GetMethod(), pc); } } - intrinsic->SetInlined(false); intrinsic->GetBasicBlock()->RemoveInst(intrinsic); } template -bool TypesResolving::InlineObjByValue(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineObjByValue(IntrinsicInst *intrinsic) { if (GetGraph()->IsAotMode()) { return false; @@ -736,7 +721,7 @@ bool TypesResolving::InlineObjByValue(IntrinsicInst *intrinsic) } template -bool TypesResolving::InlineObjByName(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineObjByName(IntrinsicInst *intrinsic) { if (GetGraph()->IsAotMode()) { return false; @@ -762,7 +747,7 @@ bool TypesResolving::InlineObjByName(IntrinsicInst *intrinsic) return true; } -bool TypesResolving::InlineResolveAllocResult(IntrinsicInst *intrinsic) +bool InlineIntrinsics::InlineResolveAllocResult(IntrinsicInst *intrinsic) { auto ctor_res = intrinsic->GetInput(2U).GetInst(); if (ctor_res->GetOpcode() != Opcode::CastValueToAnyType) { @@ -774,12 +759,11 @@ bool TypesResolving::InlineResolveAllocResult(IntrinsicInst *intrinsic) auto alloc_inst = intrinsic->GetInput(1U).GetInst(); intrinsic->ReplaceUsers(alloc_inst); - intrinsic->SetInlined(false); intrinsic->GetBasicBlock()->RemoveInst(intrinsic); return true; } -profiling::AnyInputType TypesResolving::GetAllowedTypeForInput(IntrinsicInst *intrinsic, size_t index) +profiling::AnyInputType InlineIntrinsics::GetAllowedTypeForInput(IntrinsicInst *intrinsic, size_t index) { auto input = intrinsic->GetInput(index).GetInst(); if (input->GetOpcode() == Opcode::AnyTypeCheck) { @@ -788,7 +772,7 @@ profiling::AnyInputType TypesResolving::GetAllowedTypeForInput(IntrinsicInst *in return profiling::AnyInputType::DEFAULT; } -bool TypesResolving::InlineStrictCompareDifferentTypes(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) +bool InlineIntrinsics::InlineStrictCompareDifferentTypes(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) { ASSERT(intrinsic->GetIntrinsicId() == RuntimeInterface::IntrinsicId::INTRINSIC_STRICT_EQ_DYN || intrinsic->GetIntrinsicId() == RuntimeInterface::IntrinsicId::INTRINSIC_STRICT_NOT_EQ_DYN); @@ -813,7 +797,19 @@ bool TypesResolving::InlineStrictCompareDifferentTypes(IntrinsicInst *intrinsic, return false; } -bool TypesResolving::InlineCompareWithNull(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) +bool InlineIntrinsics::InlineStrictEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) +{ + return InlineStrictCompareDifferentTypes(intrinsic, type1, type2) || + IrtocInlineCompareStrictEqDyn(intrinsic, type1, type2); +} + +bool InlineIntrinsics::InlineStrictNotEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) +{ + return InlineStrictCompareDifferentTypes(intrinsic, type1, type2) || + IrtocInlineCompareStrictNotEqDyn(intrinsic, type1, type2); +} + +bool InlineIntrinsics::InlineCompareWithNull(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) { ASSERT(intrinsic->GetIntrinsicId() == RuntimeInterface::IntrinsicId::INTRINSIC_EQ_DYN || intrinsic->GetIntrinsicId() == RuntimeInterface::IntrinsicId::INTRINSIC_NOT_EQ_DYN); @@ -840,4 +836,327 @@ bool TypesResolving::InlineCompareWithNull(IntrinsicInst *intrinsic, AnyBaseType return InlineLdConstant(intrinsic, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 1 - eq_result); } +bool InlineIntrinsics::InlineEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) +{ + return InlineCompareWithNull(intrinsic, type1, type2) || IrtocInlineCompareEqDyn(intrinsic, type1, type2); +} + +bool InlineIntrinsics::InlineNotEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2) +{ + return InlineCompareWithNull(intrinsic, type1, type2) || IrtocInlineCompareNeDyn(intrinsic, type1, type2); +} + +bool InlineIntrinsics::InlineToNumber(IntrinsicInst *intrinsic, AnyBaseType type1) +{ + auto special_allowed = (GetAllowedTypeForInput(intrinsic, 0) & profiling::AnyInputType::SPECIAL) != 0; + return panda::compiler::IrtocInlineToNumber(intrinsic, type1, special_allowed); +} + +bool InlineIntrinsics::InlineLdLexDyn(IntrinsicInst *intrinsic) +{ + auto *save_state = intrinsic->GetSaveState(); + ASSERT(save_state != nullptr); + + ASSERT(intrinsic->GetImms().size() == 3U); + // ConstPool, LexEnv, SaveState + ASSERT(intrinsic->GetInputsCount() == 3U); + auto *load_lex_var = intrinsic; + load_lex_var->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN); + load_lex_var->SetImm(0U, load_lex_var->GetImm(1U)); // level + load_lex_var->SetImm(1U, load_lex_var->GetImm(2U)); // slot + load_lex_var->GetImms().pop_back(); // the last is not needed + ASSERT(load_lex_var->GetInput(2U).GetInst()->GetOpcode() == Opcode::SaveState); + load_lex_var->RemoveInput(2U); + load_lex_var->RemoveInput(0U); + load_lex_var->ClearFlag(inst_flags::REQUIRE_STATE); + InstAppender appender(load_lex_var->GetBasicBlock(), load_lex_var); + + auto pc = intrinsic->GetPc(); + auto *hole = GetGraph()->FindOrCreateConstant(DataType::Any(panda::coretypes::TaggedValue::VALUE_HOLE)); + auto *compare = GetGraph()->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_EQ); + compare->SetOperandsType(DataType::ANY); + compare->SetInput(0U, load_lex_var); + compare->SetInput(1U, hole); + appender.Append(compare); + + auto *deopt_if = GetGraph()->CreateInstDeoptimizeIf(DataType::NO_TYPE, pc); + deopt_if->SetDeoptimizeType(DeoptimizeType::HOLE); + deopt_if->SetInput(0, compare); + deopt_if->SetSaveState(save_state); + appender.Append(deopt_if); + + InlineLdLexVarDyn(load_lex_var); + return true; +} + +Inst *InlineIntrinsics::GetParentLexEnv(InstAppender *appender, Inst *current_lex_env, uint32_t level, uint32_t pc) +{ + auto *runtime = GetGraph()->GetRuntime(); + for (; level > 0U; --level) { + auto *load_parent = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); + load_parent->SetInput(0U, current_lex_env); + load_parent->SetInput(1U, GetGraph()->FindOrCreateConstant(runtime->GetLexicalEnvParentEnvIndex())); + appender->Append(load_parent); + + auto *parent_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); + parent_ref->SetInput(0U, load_parent); + parent_ref->SetFlag(inst_flags::NO_HOIST); + appender->Append(parent_ref); + current_lex_env = parent_ref; + } + return current_lex_env; +} + +bool InlineIntrinsics::InlineStLexDyn(IntrinsicInst *intrinsic) +{ + ASSERT(intrinsic->GetImms().size() == 3U); + // Acc, ConstPool, LexEnv, SaveState + ASSERT(intrinsic->GetInputsCount() == 4U); + + auto level = intrinsic->GetImms()[1U]; + if (level > GetLdStLexVarDynLevelThreshold()) { + return false; + } + + auto slot = intrinsic->GetImms()[2U]; + + auto *store_acc_val = intrinsic->GetInput(0U).GetInst(); + auto *store_lex_env = intrinsic->GetInput(2U).GetInst(); + + InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); + + auto pc = intrinsic->GetPc(); + auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); + env_ref->SetInput(0U, store_lex_env); + env_ref->SetFlag(inst_flags::NO_HOIST); + appender.Append(env_ref); + + Inst *current_lex_env = env_ref; + current_lex_env = GetParentLexEnv(&appender, current_lex_env, level, pc); + + auto start = GetGraph()->GetRuntime()->GetLexicalEnvStartDataIndex(); + auto elem_offset = start + slot; + + auto save_state = intrinsic->GetSaveState(); + ASSERT(save_state != nullptr); + + auto *get_prop = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); + get_prop->SetInput(0U, current_lex_env); + get_prop->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); + appender.Append(get_prop); + + auto *hole = GetGraph()->FindOrCreateConstant(DataType::Any(panda::coretypes::TaggedValue::VALUE_HOLE)); + auto *compare = GetGraph()->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_EQ); + compare->SetOperandsType(DataType::ANY); + compare->SetInput(0U, get_prop); + compare->SetInput(1U, hole); + appender.Append(compare); + + auto *deopt_if = GetGraph()->CreateInstDeoptimizeIf(DataType::NO_TYPE, pc); + deopt_if->SetDeoptimizeType(DeoptimizeType::HOLE); + deopt_if->SetInput(0, compare); + deopt_if->SetSaveState(save_state); + appender.Append(deopt_if); + + auto *store_lex_var = GetGraph()->CreateInstStoreArray(DataType::ANY, pc); + store_lex_var->SetNeedBarrier(true); + store_lex_var->SetInput(0U, current_lex_env); + store_lex_var->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); + store_lex_var->SetInput(2U, store_acc_val); + appender.Append(store_lex_var); + + if (intrinsic->HasUsers()) { + intrinsic->ReplaceUsers(store_acc_val); + } + intrinsic->GetBasicBlock()->RemoveInst(intrinsic); + return true; +} + +bool InlineIntrinsics::InlineLdLexVarDyn(IntrinsicInst *intrinsic) +{ + auto level = intrinsic->GetImms()[0U]; + if (level > GetLdStLexVarDynLevelThreshold()) { + return false; + } + + auto slot = intrinsic->GetImms()[1U]; + + auto *load_lex_env = intrinsic->GetInput(0U).GetInst(); + + InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); + + auto pc = intrinsic->GetPc(); + auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); + env_ref->SetInput(0U, load_lex_env); + env_ref->SetFlag(inst_flags::NO_HOIST); + appender.Append(env_ref); + + Inst *current_lex_env = env_ref; + current_lex_env = GetParentLexEnv(&appender, current_lex_env, level, pc); + + auto start = GetGraph()->GetRuntime()->GetLexicalEnvStartDataIndex(); + auto elem_offset = start + slot; + auto *load_lex_var = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); + load_lex_var->SetInput(0U, current_lex_env); + load_lex_var->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); + appender.Append(load_lex_var); + + intrinsic->ReplaceUsers(load_lex_var); + intrinsic->GetBasicBlock()->RemoveInst(intrinsic); + return true; +} + +bool InlineIntrinsics::InlineLdlexenvDyn([[maybe_unused]] IntrinsicInst *intrinsic) +{ + auto pc = intrinsic->GetPc(); + auto load_lexical_env = GetGraph()->CreateInstLoadLexicalEnv(DataType::ANY, pc); + auto func_obj = intrinsic->GetInput(0).GetInst(); + load_lexical_env->SetInput(0, func_obj); + intrinsic->InsertBefore(load_lexical_env); + intrinsic->ReplaceUsers(load_lexical_env); + intrinsic->GetBasicBlock()->RemoveInst(intrinsic); + return true; +} + +bool InlineIntrinsics::InlineStLexVarDyn(IntrinsicInst *intrinsic) +{ + auto level = intrinsic->GetImms()[0U]; + if (level > GetLdStLexVarDynLevelThreshold()) { + return false; + } + + auto slot = intrinsic->GetImms()[1U]; + + auto *store_acc_val = intrinsic->GetInput(0U).GetInst(); + auto *store_lex_env = intrinsic->GetInput(1U).GetInst(); + + InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); + + auto pc = intrinsic->GetPc(); + auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); + env_ref->SetInput(0U, store_lex_env); + env_ref->SetFlag(inst_flags::NO_HOIST); + appender.Append(env_ref); + + Inst *current_lex_env = env_ref; + current_lex_env = GetParentLexEnv(&appender, current_lex_env, level, pc); + + auto start = GetGraph()->GetRuntime()->GetLexicalEnvStartDataIndex(); + auto elem_offset = start + slot; + + auto *store_lex_var = GetGraph()->CreateInstStoreArray(DataType::ANY, pc); + store_lex_var->SetNeedBarrier(true); + store_lex_var->SetInput(0U, current_lex_env); + store_lex_var->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); + store_lex_var->SetInput(2U, store_acc_val); + appender.Append(store_lex_var); + + if (intrinsic->HasUsers()) { + intrinsic->ReplaceUsers(store_acc_val); + } + intrinsic->GetBasicBlock()->RemoveInst(intrinsic); + return true; +} + +bool InlineIntrinsics::InlinePopLexenvDyn(IntrinsicInst *intrinsic) +{ + InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); + + auto pc = intrinsic->GetPc(); + auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); + env_ref->SetInput(0U, intrinsic->GetInput(0).GetInst()); + env_ref->SetFlag(inst_flags::NO_HOIST); + appender.Append(env_ref); + + auto *load_parent = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); + load_parent->SetInput(0U, env_ref); + load_parent->SetInput(1U, + GetGraph()->FindOrCreateConstant(GetGraph()->GetRuntime()->GetLexicalEnvParentEnvIndex())); + appender.Append(load_parent); + + intrinsic->ReplaceUsers(load_parent); + intrinsic->GetBasicBlock()->RemoveInst(intrinsic); + return true; +} + +bool InlineIntrinsics::InlineTryLdGlobalByName(IntrinsicInst *inst) +{ + if (GetGraph()->IsAotMode()) { + return false; + } + ASSERT(inst->GetSaveState() != nullptr); + auto runtime = GetGraph()->GetRuntime(); + auto type_id = inst->GetImms()[0]; + auto pc = inst->GetPc(); + auto save_state = inst->GetSaveState(); + ASSERT(save_state != nullptr); + auto caller_inst = save_state->GetCallerInst(); + RuntimeInterface::GlobalVarInfo inline_info; + if (caller_inst != nullptr) { + ASSERT(caller_inst->IsInlined()); + auto func = caller_inst->GetFunctionObject(); + if (func != 0) { + inline_info = runtime->GetGlobalVarInfo(GetGraph()->GetMethod(), func, type_id, pc); + } else { + inline_info = runtime->GetGlobalVarInfo(caller_inst->GetCallMethod(), type_id, pc); + } + } else { + inline_info = runtime->GetGlobalVarInfo(GetGraph()->GetMethod(), type_id, pc); + } + switch (inline_info.type) { + case RuntimeInterface::GlobalVarInfo::Type::CONSTANT: { + auto constant = GetGraph()->FindOrCreateConstant(DataType::Any(inline_info.value)); + inst->ReplaceUsers(constant); + inst->GetBasicBlock()->RemoveInst(inst); + return true; + } + case RuntimeInterface::GlobalVarInfo::Type::NON_CONFIGURABLE: + InlineTryLdGlobalField(inst, static_cast(inline_info.value)); + return true; + case RuntimeInterface::GlobalVarInfo::Type::FIELD: + InlineTryLdGlobalField(inst, static_cast(inline_info.value)); + return true; + default: + return false; + } +} + +template +void InlineIntrinsics::InlineTryLdGlobalField(IntrinsicInst *inst, uintptr_t address) +{ + auto pc = inst->GetPc(); + auto save_state = inst->GetSaveState(); + auto type_id = inst->GetImms()[0]; + + auto get_address = GetGraph()->CreateInstGetGlobalVarAddress(DataType::REFERENCE, pc, address); + get_address->SetTypeId(type_id); + get_address->SetMethod(GetGraph()->GetMethod()); + get_address->SetInput(0, inst->GetInput(2).GetInst()); + get_address->SetInput(1, save_state); + inst->InsertBefore(get_address); + + auto load_object = GetGraph()->CreateInstLoadObject(DataType::ANY, pc); + load_object->SetTypeId(TypeIdMixin::MEM_DYN_GLOBAL_ID); + load_object->SetMethod(GetGraph()->GetMethod()); + load_object->SetObjField(nullptr); + load_object->SetObjectType(ObjectType::MEM_DYN_GLOBAL); + load_object->SetInput(0, get_address); + inst->InsertBefore(load_object); + + if constexpr (NEED_GUARD) { + auto cmp = GetGraph()->CreateInstCompareAnyType(DataType::BOOL, pc); + cmp->SetAnyType(AnyBaseType::ECMASCRIPT_HOLE_TYPE); + cmp->SetInput(0, load_object); + auto deopt = GetGraph()->CreateInstDeoptimizeIf(DataType::BOOL, pc); + deopt->SetInput(0, cmp); + deopt->SetInput(1, save_state); + deopt->SetDeoptimizeType(DeoptimizeType::INLINE_IC); + inst->InsertBefore(cmp); + inst->InsertBefore(deopt); + } + + inst->ReplaceUsers(load_object); + inst->GetBasicBlock()->RemoveInst(inst); +} + } // namespace panda::compiler diff --git a/compiler/intrinsics_inline_ecmascript.inl b/compiler/intrinsics_inline_ecmascript.inl deleted file mode 100644 index 24194eb2e48dc1bcafcd12cf0abd4457e4b1b16c..0000000000000000000000000000000000000000 --- a/compiler/intrinsics_inline_ecmascript.inl +++ /dev/null @@ -1,170 +0,0 @@ - /* - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -case RuntimeInterface::IntrinsicId::INTRINSIC_ADD2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineAddDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_INC_DYN: { - ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineIncDyn(intrinsic, types_[0]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_DEC_DYN: { - ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineDecDyn(intrinsic, types_[0]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_SUB2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineSubDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_EQ_DYN: { - ASSERT(types_.size() == 2); - return InlineCompareWithNull(intrinsic, types_[0], types_[1]) || - panda::compiler::IrtocInlineCompareEqDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_NOT_EQ_DYN: { - ASSERT(types_.size() == 2); - return InlineCompareWithNull(intrinsic, types_[0], types_[1]) || - panda::compiler::IrtocInlineCompareNeDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_STRICT_EQ_DYN: { - ASSERT(types_.size() == 2); - return InlineStrictCompareDifferentTypes(intrinsic, types_[0], types_[1]) || - panda::compiler::IrtocInlineCompareStrictEqDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_STRICT_NOT_EQ_DYN: { - ASSERT(types_.size() == 2); - return InlineStrictCompareDifferentTypes(intrinsic, types_[0], types_[1]) || - panda::compiler::IrtocInlineCompareStrictNotEqDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_LESS_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineCompareLtDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_LESS_EQ_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineCompareLeDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_GREATER_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineCompareGtDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_GREATER_EQ_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineCompareGeDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_SHL2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineShlDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_SHR2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineShrDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_AND2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineAndDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_OR2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineOrDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_XOR2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineXorDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_MUL2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineMulDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_DIV2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineDivDyn(intrinsic, types_[0], types_[1]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_MOD2_DYN: { - ASSERT(types_.size() == 2); - return panda::compiler::IrtocInlineModDyn(intrinsic, types_[0], types_[1]); -} case RuntimeInterface::IntrinsicId::INTRINSIC_NOT_DYN: { - ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineNotDyn(intrinsic, types_[0]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_NEG_DYN: { - ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineNegDyn(intrinsic, types_[0]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_TOBOOLEAN: { - ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineToBooleanDyn(intrinsic, types_[0]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER: { - ASSERT(types_.size() == 1); - 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); - return panda::compiler::IrtocInlineIsFalseDyn(intrinsic, types_[0]); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_IS_TRUE: { - ASSERT(types_.size() == 1); - return panda::compiler::IrtocInlineIsTrueDyn(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); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_LD_OBJ_BY_NAME: { - return InlineLdObjByName(intrinsic); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_ST_OBJ_BY_NAME: { - return InlineStObjByName(intrinsic); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_LD_OBJ_BY_VALUE: { - return InlineLdObjByValue(intrinsic); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_ST_OBJ_BY_VALUE: { - return InlineStObjByValue(intrinsic); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_RESOLVE_ALLOC_RESULT: { - return InlineResolveAllocResult(intrinsic); -} -case RuntimeInterface::IntrinsicId::INTRINSIC_TYPEOF_DYN: { - ASSERT(types_.size() == 1); - return InlineTypeOf(intrinsic); -} \ No newline at end of file diff --git a/compiler/intrinsics_type_resolving_ecmascript.inl.h b/compiler/intrinsics_inline_ecmascript.inl.h similarity index 66% rename from compiler/intrinsics_type_resolving_ecmascript.inl.h rename to compiler/intrinsics_inline_ecmascript.inl.h index c7d6068f918cfd458636834caeb7044935397e1c..b7f40549b91040ad8dba32f72c8a4a784c15b2c6 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.inl.h +++ b/compiler/intrinsics_inline_ecmascript.inl.h @@ -13,9 +13,16 @@ * limitations under the License. */ -#ifndef PLUGINS_ECMASCRIPT_COMPILER_INTRINSICS_TYPE_RESOLVING_ECMASCRIPT_INL_H -#define PLUGINS_ECMASCRIPT_COMPILER_INTRINSICS_TYPE_RESOLVING_ECMASCRIPT_INL_H +#ifndef PLUGINS_ECMASCRIPT_COMPILER_INLINE_INTRINSICS_ECMASCRIPT_INL_H +#define PLUGINS_ECMASCRIPT_COMPILER_INLINE_INTRINSICS_ECMASCRIPT_INL_H +static constexpr size_t GetLdStLexVarDynLevelThreshold() +{ + constexpr size_t MAX_LEVEL = 2U; + return MAX_LEVEL; +} + +private: bool InlineLdTrue(IntrinsicInst *intrinsic); bool InlineLdFalse(IntrinsicInst *intrinsic); bool InlineLdHole(IntrinsicInst *intrinsic); @@ -29,8 +36,6 @@ bool InlineLdObjByValue(IntrinsicInst *intrinsic); bool InlineStObjByValue(IntrinsicInst *intrinsic); bool InlineResolveAllocResult(IntrinsicInst *intrinsic); bool InlineTypeOf(IntrinsicInst *intrinsic); - -private: template bool InlineObjByName(IntrinsicInst *intrinsic); template @@ -56,6 +61,22 @@ Inst *CreateCompareClassWithDeopt(uint32_t pc, Inst *get_cls_inst, RuntimeInterf profiling::AnyInputType GetAllowedTypeForInput(IntrinsicInst *intrinsic, size_t index); bool InlineStrictCompareDifferentTypes(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); +bool InlineStrictEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); +bool InlineStrictNotEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); bool InlineCompareWithNull(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); +bool InlineEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); +bool InlineNotEqDyn(IntrinsicInst *intrinsic, AnyBaseType type1, AnyBaseType type2); +bool InlineToNumber(IntrinsicInst *intrinsic, AnyBaseType type1); +Inst *GetParentLexEnv(InstAppender *appender, Inst *current_lex_env, uint32_t level, uint32_t pc); +bool InlineLdLexDyn(IntrinsicInst *intrinsic); +bool InlineStLexDyn(IntrinsicInst *intrinsic); +bool InlineLdLexVarDyn(IntrinsicInst *intrinsic); +bool InlineLdlexenvDyn(IntrinsicInst *intrinsic); +bool InlineStLexVarDyn(IntrinsicInst *intrinsic); +bool InlinePopLexenvDyn(IntrinsicInst *intrinsic); + +bool InlineTryLdGlobalByName(IntrinsicInst *inst); +template +void InlineTryLdGlobalField(IntrinsicInst *inst, uintptr_t address); -#endif // PLUGINS_ECMASCRIPT_COMPILER_INTRINSICS_TYPE_RESOLVING_ECMASCRIPT_INL_H \ No newline at end of file +#endif // PLUGINS_ECMASCRIPT_COMPILER_INLINE_INTRINSICS_ECMASCRIPT_INL_H \ No newline at end of file diff --git a/compiler/optimizer/ecma_pipeline.cpp b/compiler/optimizer/ecma_pipeline.cpp index 5c9c1af342a72234dbcdd21cedeb9931b46f6038..b12404668eea2e0064567e917b1ac7c6c5927554 100644 --- a/compiler/optimizer/ecma_pipeline.cpp +++ b/compiler/optimizer/ecma_pipeline.cpp @@ -42,19 +42,19 @@ #include "optimizer/optimizations/regalloc/reg_alloc.h" #include "optimizer/optimizations/scheduler.h" #include "optimizer/optimizations/try_catch_resolving.h" -#include "optimizer/optimizations/types_resolving.h" +#include "optimizer/optimizations/inline_intrinsics.h" #include "optimizer/optimizations/vn.h" #include "optimizer/optimizations/cse.h" #include "optimizer/optimizations/move_constants.h" #include "optimizer/optimizations/adjust_arefs.h" -#include "plugins/ecmascript/compiler/optimizer/optimizations/expand_intrinsics.h" +#include "plugins/ecmascript/compiler/optimizer/optimizations/inline_call_intrinsics.h" namespace panda::compiler::ecmascript { bool EcmaPipeline::RunOptimizations() { auto graph = GetGraph(); - graph->RunPass(); + graph->RunPass(); // TODO(schernykh): Find way to inline in AOT and OSR mode if (!graph->IsAotMode() && !graph->IsOsrMode()) { graph->RunPass(); @@ -71,7 +71,7 @@ bool EcmaPipeline::RunOptimizations() if (graph->IsAotMode()) { graph->RunPass(); } - graph->RunPass(); + graph->RunPass(); graph->RunPass(); graph->RunPass(); graph->RunPass(); diff --git a/compiler/optimizer/optimizations/ecma_inlining.cpp b/compiler/optimizer/optimizations/ecma_inlining.cpp index 7da0b8a163cbf8f8a2e6b71be1e43fcd478addf0..b4a0223eb4f8725daceee8bb7a2319ab200eec85 100644 --- a/compiler/optimizer/optimizations/ecma_inlining.cpp +++ b/compiler/optimizer/optimizations/ecma_inlining.cpp @@ -14,7 +14,7 @@ */ #include "ecma_inlining.h" -#include "expand_intrinsics.h" +#include "inline_call_intrinsics.h" #include "events/events.h" #include "optimizer/ir/graph.h" #include "optimizer/analysis/loop_analyzer.h" @@ -34,7 +34,7 @@ EcmaInlining::EcmaInlining(Graph *graph, uint32_t instructions_count, uint32_t i void EcmaInlining::RunOptimizations() const { - if (GetGraph()->RunPass()) { + if (GetGraph()->RunPass()) { GetGraph()->RunPass(); } if (GetGraph()->RunPass()) { @@ -122,7 +122,7 @@ Graph *EcmaInlining::BuildGraph(InlineContext *ctx, CallInst *call_inst, CallIns } // Run basic optimizations - graph_inl->RunPass(); + graph_inl->RunPass(); graph_inl->RunPass(false); if (graph_inl->RunPass()) { graph_inl->RunPass(); diff --git a/compiler/optimizer/optimizations/expand_intrinsics.cpp b/compiler/optimizer/optimizations/inline_call_intrinsics.cpp similarity index 46% rename from compiler/optimizer/optimizations/expand_intrinsics.cpp rename to compiler/optimizer/optimizations/inline_call_intrinsics.cpp index 4b85ebc334ce1bfbf89b1b2afdf7fbc4b3fd3f8b..ef42b16275cb737a1956fa4f877fcb22b4b17ec6 100644 --- a/compiler/optimizer/optimizations/expand_intrinsics.cpp +++ b/compiler/optimizer/optimizations/inline_call_intrinsics.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "expand_intrinsics.h" +#include "inline_call_intrinsics.h" #include "plugins/ecmascript/runtime/js_tagged_value.h" #include "optimizer/ir/basicblock.h" #include "optimizer/analysis/dominators_tree.h" @@ -22,7 +22,7 @@ namespace panda::compiler { -bool ExpandIntrinsics::RunImpl() +bool InlineCallIntrinsics::RunImpl() { bool success = false; for (auto *bb : GetGraph()->GetVectorBlocks()) { @@ -41,50 +41,19 @@ bool ExpandIntrinsics::RunImpl() return success; } -bool ExpandIntrinsics::Expand(IntrinsicInst *inst) +bool InlineCallIntrinsics::Expand(IntrinsicInst *inst) { auto id = inst->GetIntrinsicId(); switch (id) { case RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE: case RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE_HANDLED: return ExpandNewObjDynRange(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_DYN: - return ExpandLdLexDyn(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_DYN: - return ExpandStLexDyn(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN: - return ExpandLdLexVarDyn(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN: - return ExpandStLexVarDyn(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_TRY_LD_GLOBAL_BY_NAME: - return ExpandTryLdGlobalByName(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN: - return ExpandLdlexenvDyn(inst); - case RuntimeInterface::IntrinsicId::INTRINSIC_POP_LEXENV_DYN: - return ExpandPopLexenvDyn(inst); default: return false; } } -void ExpandIntrinsics::InstAppender::Append(Inst *inst) -{ - if (prev_ == nullptr) { - block_->AppendInst(inst); - } else { - block_->InsertAfter(inst, prev_); - } - prev_ = inst; -} - -void ExpandIntrinsics::InstAppender::Append(std::initializer_list instructions) -{ - for (auto *inst : instructions) { - Append(inst); - } -} - -Inst *ExpandIntrinsics::CreateAllocDynObjIntrinsic(Inst *ctor, SaveStateInst *ss, uint32_t pc) +Inst *InlineCallIntrinsics::CreateAllocDynObjIntrinsic(Inst *ctor, SaveStateInst *ss, uint32_t pc) { auto alloc_obj = GetGraph()->CreateInstIntrinsic(DataType::ANY, pc, RuntimeInterface::IntrinsicId::INTRINSIC_ALLOC_DYN_OBJECT); @@ -97,7 +66,8 @@ Inst *ExpandIntrinsics::CreateAllocDynObjIntrinsic(Inst *ctor, SaveStateInst *ss return alloc_obj; } -Inst *ExpandIntrinsics::NewObjCreateConstructorCall(Inst *orig_call, Inst *alloc_obj, SaveStateInst *ss, uint32_t pc) +Inst *InlineCallIntrinsics::NewObjCreateConstructorCall(Inst *orig_call, Inst *alloc_obj, SaveStateInst *ss, + uint32_t pc) { auto call_ctor = GetGraph()->CreateInstCallDynamic(DataType::ANY, pc); call_ctor->ReserveInputs(orig_call->GetInputsCount() + 1); @@ -117,7 +87,7 @@ Inst *ExpandIntrinsics::NewObjCreateConstructorCall(Inst *orig_call, Inst *alloc return call_ctor; } -void ExpandIntrinsics::NewObjFillCurrBlock(InstAppender *appender, Inst *alloc_obj, uint32_t pc) +void InlineCallIntrinsics::NewObjFillCurrBlock(InstAppender *appender, Inst *alloc_obj, uint32_t pc) { auto cmp = GetGraph()->CreateInstCompareAnyType(DataType::BOOL, pc); cmp->SetAnyType(AnyBaseType::ECMASCRIPT_NULL_TYPE); @@ -130,7 +100,7 @@ void ExpandIntrinsics::NewObjFillCurrBlock(InstAppender *appender, Inst *alloc_o appender->Append({cmp, ifimm}); } -void ExpandIntrinsics::NewObjFillSlowPathBlock(InstAppender *appender, Inst *orig_alloc) +void InlineCallIntrinsics::NewObjFillSlowPathBlock(InstAppender *appender, Inst *orig_alloc) { auto curr_block = orig_alloc->GetBasicBlock(); auto ss = orig_alloc->CastToIntrinsic()->GetSaveState(); @@ -145,8 +115,8 @@ void ExpandIntrinsics::NewObjFillSlowPathBlock(InstAppender *appender, Inst *ori appender->Append({ss_copy, orig_alloc}); } -Inst *ExpandIntrinsics::NewObjFillCallConstructorBlock(InstAppender *appender, Inst *orig_alloc, Inst *alloc_obj, - uint32_t pc) +Inst *InlineCallIntrinsics::NewObjFillCallConstructorBlock(InstAppender *appender, Inst *orig_alloc, Inst *alloc_obj, + uint32_t pc) { auto ss = orig_alloc->GetSaveState(); auto ss_copy = static_cast(ss->Clone(GetGraph())); @@ -164,8 +134,8 @@ Inst *ExpandIntrinsics::NewObjFillCallConstructorBlock(InstAppender *appender, I return call_ctor; } -Inst *ExpandIntrinsics::NewObjResolveCtorResult(InstAppender *appender, Inst *orig_alloc, Inst *alloc_obj, - Inst *call_ctor, uint32_t pc) +Inst *InlineCallIntrinsics::NewObjResolveCtorResult(InstAppender *appender, Inst *orig_alloc, Inst *alloc_obj, + Inst *call_ctor, uint32_t pc) { auto ss = call_ctor->GetSaveState(); auto ss_copy_2 = static_cast(ss->Clone(GetGraph())); @@ -189,7 +159,6 @@ Inst *ExpandIntrinsics::NewObjResolveCtorResult(InstAppender *appender, Inst *or resolve_result->AddInputType(DataType::ANY); resolve_result->AppendInput(ss_copy_2); resolve_result->AddInputType(DataType::NO_TYPE); - resolve_result->SetInlined(true); appender->Append({ss_copy_2, resolve_result}); @@ -221,7 +190,7 @@ Inst *ExpandIntrinsics::NewObjResolveCtorResult(InstAppender *appender, Inst *or * * Depending on profiling info shape of the emitted IR may change by pruning one of the branches. */ -bool ExpandIntrinsics::ExpandNewObjDynRange(IntrinsicInst *inst) +bool InlineCallIntrinsics::ExpandNewObjDynRange(IntrinsicInst *inst) { Inst *ctor_inst = inst->GetInput(1).GetInst(); Inst *new_target_inst = inst->GetInput(2).GetInst(); @@ -265,7 +234,7 @@ bool ExpandIntrinsics::ExpandNewObjDynRange(IntrinsicInst *inst) return false; } -void ExpandIntrinsics::ExpandNewObjDynDefault(Inst *inst) +void InlineCallIntrinsics::ExpandNewObjDynDefault(Inst *inst) { auto curr_block = inst->GetBasicBlock(); auto succ_block = curr_block->SplitBlockAfterInstruction(inst, false); @@ -302,7 +271,7 @@ void ExpandIntrinsics::ExpandNewObjDynDefault(Inst *inst) InvalidateBlocksOrderAnalyzes(GetGraph()); } -void ExpandIntrinsics::ExpandNewObjDynFastPath(Inst *inst, RuntimeInterface::NewObjDynInfo info, uintptr_t target) +void InlineCallIntrinsics::ExpandNewObjDynFastPath(Inst *inst, RuntimeInterface::NewObjDynInfo info, uintptr_t target) { auto curr_block = inst->GetBasicBlock(); auto pc = inst->GetPc(); @@ -331,7 +300,7 @@ void ExpandIntrinsics::ExpandNewObjDynFastPath(Inst *inst, RuntimeInterface::New curr_block->RemoveInst(inst); } -void ExpandIntrinsics::BuildGuard(Inst *inst, uintptr_t target) +void InlineCallIntrinsics::BuildGuard(Inst *inst, uintptr_t target) { auto pc = inst->GetPc(); auto load_function = GetGraph()->CreateInstFunctionImmediate(DataType::ANY, pc, target); @@ -355,297 +324,4 @@ void ExpandIntrinsics::BuildGuard(Inst *inst, uintptr_t target) inst->InsertBefore(deopt_inst); } -bool ExpandIntrinsics::ExpandLdLexDyn(IntrinsicInst *intrinsic) -{ - auto *save_state = intrinsic->GetSaveState(); - ASSERT(save_state != nullptr); - - ASSERT(intrinsic->GetImms().size() == 3U); - // ConstPool, LexEnv, SaveState - ASSERT(intrinsic->GetInputsCount() == 3U); - auto *load_lex_var = intrinsic; - load_lex_var->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN); - load_lex_var->SetImm(0U, load_lex_var->GetImm(1U)); // level - load_lex_var->SetImm(1U, load_lex_var->GetImm(2U)); // slot - load_lex_var->GetImms().pop_back(); // the last is not needed - ASSERT(load_lex_var->GetInput(2U).GetInst()->GetOpcode() == Opcode::SaveState); - load_lex_var->RemoveInput(2U); - load_lex_var->RemoveInput(0U); - load_lex_var->ClearFlag(inst_flags::REQUIRE_STATE); - InstAppender appender(load_lex_var->GetBasicBlock(), load_lex_var); - - auto pc = intrinsic->GetPc(); - auto *hole = GetGraph()->FindOrCreateConstant(DataType::Any(panda::coretypes::TaggedValue::VALUE_HOLE)); - auto *compare = GetGraph()->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_EQ); - compare->SetOperandsType(DataType::ANY); - compare->SetInput(0U, load_lex_var); - compare->SetInput(1U, hole); - appender.Append(compare); - - auto *deopt_if = GetGraph()->CreateInstDeoptimizeIf(DataType::NO_TYPE, pc); - deopt_if->SetDeoptimizeType(DeoptimizeType::HOLE); - deopt_if->SetInput(0, compare); - deopt_if->SetSaveState(save_state); - appender.Append(deopt_if); - - ExpandLdLexVarDyn(load_lex_var); - return true; -} - -Inst *ExpandIntrinsics::GetParentLexEnv(InstAppender *appender, Inst *current_lex_env, uint32_t level, uint32_t pc) -{ - auto *runtime = GetGraph()->GetRuntime(); - for (; level > 0U; --level) { - auto *load_parent = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); - load_parent->SetInput(0U, current_lex_env); - load_parent->SetInput(1U, GetGraph()->FindOrCreateConstant(runtime->GetLexicalEnvParentEnvIndex())); - appender->Append(load_parent); - - auto *parent_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); - parent_ref->SetInput(0U, load_parent); - parent_ref->SetFlag(inst_flags::NO_HOIST); - appender->Append(parent_ref); - current_lex_env = parent_ref; - } - return current_lex_env; -} - -bool ExpandIntrinsics::ExpandStLexDyn(IntrinsicInst *intrinsic) -{ - ASSERT(intrinsic->GetImms().size() == 3U); - // Acc, ConstPool, LexEnv, SaveState - ASSERT(intrinsic->GetInputsCount() == 4U); - - auto level = intrinsic->GetImms()[1U]; - if (level > GetLdStLexVarDynLevelThreshold()) { - return false; - } - - auto slot = intrinsic->GetImms()[2U]; - - auto *store_acc_val = intrinsic->GetInput(0U).GetInst(); - auto *store_lex_env = intrinsic->GetInput(2U).GetInst(); - - InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); - - auto pc = intrinsic->GetPc(); - auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); - env_ref->SetInput(0U, store_lex_env); - env_ref->SetFlag(inst_flags::NO_HOIST); - appender.Append(env_ref); - - Inst *current_lex_env = env_ref; - current_lex_env = GetParentLexEnv(&appender, current_lex_env, level, pc); - - auto start = GetGraph()->GetRuntime()->GetLexicalEnvStartDataIndex(); - auto elem_offset = start + slot; - - auto save_state = intrinsic->GetSaveState(); - ASSERT(save_state != nullptr); - - auto *get_prop = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); - get_prop->SetInput(0U, current_lex_env); - get_prop->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); - appender.Append(get_prop); - - auto *hole = GetGraph()->FindOrCreateConstant(DataType::Any(panda::coretypes::TaggedValue::VALUE_HOLE)); - auto *compare = GetGraph()->CreateInstCompare(DataType::BOOL, pc, ConditionCode::CC_EQ); - compare->SetOperandsType(DataType::ANY); - compare->SetInput(0U, get_prop); - compare->SetInput(1U, hole); - appender.Append(compare); - - auto *deopt_if = GetGraph()->CreateInstDeoptimizeIf(DataType::NO_TYPE, pc); - deopt_if->SetDeoptimizeType(DeoptimizeType::HOLE); - deopt_if->SetInput(0, compare); - deopt_if->SetSaveState(save_state); - appender.Append(deopt_if); - - auto *store_lex_var = GetGraph()->CreateInstStoreArray(DataType::ANY, pc); - store_lex_var->SetNeedBarrier(true); - store_lex_var->SetInput(0U, current_lex_env); - store_lex_var->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); - store_lex_var->SetInput(2U, store_acc_val); - appender.Append(store_lex_var); - - if (intrinsic->HasUsers()) { - intrinsic->ReplaceUsers(store_acc_val); - } - intrinsic->GetBasicBlock()->RemoveInst(intrinsic); - return true; -} - -bool ExpandIntrinsics::ExpandLdLexVarDyn(IntrinsicInst *intrinsic) -{ - auto level = intrinsic->GetImms()[0U]; - if (level > GetLdStLexVarDynLevelThreshold()) { - return false; - } - - auto slot = intrinsic->GetImms()[1U]; - - auto *load_lex_env = intrinsic->GetInput(0U).GetInst(); - - InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); - - auto pc = intrinsic->GetPc(); - auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); - env_ref->SetInput(0U, load_lex_env); - env_ref->SetFlag(inst_flags::NO_HOIST); - appender.Append(env_ref); - - Inst *current_lex_env = env_ref; - current_lex_env = GetParentLexEnv(&appender, current_lex_env, level, pc); - - auto start = GetGraph()->GetRuntime()->GetLexicalEnvStartDataIndex(); - auto elem_offset = start + slot; - auto *load_lex_var = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); - load_lex_var->SetInput(0U, current_lex_env); - load_lex_var->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); - appender.Append(load_lex_var); - - intrinsic->ReplaceUsers(load_lex_var); - intrinsic->GetBasicBlock()->RemoveInst(intrinsic); - return true; -} - -bool ExpandIntrinsics::ExpandLdlexenvDyn([[maybe_unused]] IntrinsicInst *intrinsic) -{ - auto pc = intrinsic->GetPc(); - auto load_lexical_env = GetGraph()->CreateInstLoadLexicalEnv(DataType::ANY, pc); - auto func_obj = intrinsic->GetInput(0).GetInst(); - load_lexical_env->SetInput(0, func_obj); - intrinsic->InsertBefore(load_lexical_env); - intrinsic->ReplaceUsers(load_lexical_env); - intrinsic->GetBasicBlock()->RemoveInst(intrinsic); - return true; -} - -bool ExpandIntrinsics::ExpandStLexVarDyn(IntrinsicInst *intrinsic) -{ - auto level = intrinsic->GetImms()[0U]; - if (level > GetLdStLexVarDynLevelThreshold()) { - return false; - } - - auto slot = intrinsic->GetImms()[1U]; - - auto *store_acc_val = intrinsic->GetInput(0U).GetInst(); - auto *store_lex_env = intrinsic->GetInput(1U).GetInst(); - - InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); - - auto pc = intrinsic->GetPc(); - auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); - env_ref->SetInput(0U, store_lex_env); - env_ref->SetFlag(inst_flags::NO_HOIST); - appender.Append(env_ref); - - Inst *current_lex_env = env_ref; - current_lex_env = GetParentLexEnv(&appender, current_lex_env, level, pc); - - auto start = GetGraph()->GetRuntime()->GetLexicalEnvStartDataIndex(); - auto elem_offset = start + slot; - - auto *store_lex_var = GetGraph()->CreateInstStoreArray(DataType::ANY, pc); - store_lex_var->SetNeedBarrier(true); - store_lex_var->SetInput(0U, current_lex_env); - store_lex_var->SetInput(1U, GetGraph()->FindOrCreateConstant(elem_offset)); - store_lex_var->SetInput(2U, store_acc_val); - appender.Append(store_lex_var); - - if (intrinsic->HasUsers()) { - intrinsic->ReplaceUsers(store_acc_val); - } - intrinsic->GetBasicBlock()->RemoveInst(intrinsic); - return true; -} - -bool ExpandIntrinsics::ExpandPopLexenvDyn(IntrinsicInst *intrinsic) -{ - InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); - - auto pc = intrinsic->GetPc(); - auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); - env_ref->SetInput(0U, intrinsic->GetInput(0).GetInst()); - env_ref->SetFlag(inst_flags::NO_HOIST); - appender.Append(env_ref); - - auto *load_parent = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); - load_parent->SetInput(0U, env_ref); - load_parent->SetInput(1U, - GetGraph()->FindOrCreateConstant(GetGraph()->GetRuntime()->GetLexicalEnvParentEnvIndex())); - appender.Append(load_parent); - - intrinsic->ReplaceUsers(load_parent); - intrinsic->GetBasicBlock()->RemoveInst(intrinsic); - return true; -} - -bool ExpandIntrinsics::ExpandTryLdGlobalByName(IntrinsicInst *inst) -{ - if (GetGraph()->IsAotMode()) { - return false; - } - ASSERT(inst->GetSaveState() != nullptr); - auto runtime = GetGraph()->GetRuntime(); - auto type_id = inst->GetImms()[0]; - auto pc = inst->GetPc(); - auto inline_info = runtime->GetGlobalVarInfo(GetGraph()->GetMethod(), type_id, pc); - switch (inline_info.type) { - case RuntimeInterface::GlobalVarInfo::Type::CONSTANT: { - auto constant = GetGraph()->FindOrCreateConstant(DataType::Any(inline_info.value)); - inst->ReplaceUsers(constant); - inst->GetBasicBlock()->RemoveInst(inst); - return true; - } - case RuntimeInterface::GlobalVarInfo::Type::NON_CONFIGURABLE: - ExpandTryLdGlobalField(inst, static_cast(inline_info.value)); - return true; - case RuntimeInterface::GlobalVarInfo::Type::FIELD: - ExpandTryLdGlobalField(inst, static_cast(inline_info.value)); - return true; - default: - return false; - } -} - -template -void ExpandIntrinsics::ExpandTryLdGlobalField(IntrinsicInst *inst, uintptr_t address) -{ - auto pc = inst->GetPc(); - auto save_state = inst->GetSaveState(); - auto type_id = inst->GetImms()[0]; - - auto get_address = GetGraph()->CreateInstGetGlobalVarAddress(DataType::REFERENCE, pc, address); - get_address->SetTypeId(type_id); - get_address->SetMethod(GetGraph()->GetMethod()); - get_address->SetInput(0, inst->GetInput(2).GetInst()); - get_address->SetInput(1, save_state); - inst->InsertBefore(get_address); - - auto load_object = GetGraph()->CreateInstLoadObject(DataType::ANY, pc); - load_object->SetTypeId(TypeIdMixin::MEM_DYN_GLOBAL_ID); - load_object->SetMethod(GetGraph()->GetMethod()); - load_object->SetObjField(nullptr); - load_object->SetObjectType(ObjectType::MEM_DYN_GLOBAL); - load_object->SetInput(0, get_address); - inst->InsertBefore(load_object); - - if constexpr (NEED_GUARD) { - auto cmp = GetGraph()->CreateInstCompareAnyType(DataType::BOOL, pc); - cmp->SetAnyType(AnyBaseType::ECMASCRIPT_HOLE_TYPE); - cmp->SetInput(0, load_object); - auto deopt = GetGraph()->CreateInstDeoptimizeIf(DataType::BOOL, pc); - deopt->SetInput(0, cmp); - deopt->SetInput(1, save_state); - deopt->SetDeoptimizeType(DeoptimizeType::INLINE_IC); - inst->InsertBefore(cmp); - inst->InsertBefore(deopt); - } - - inst->ReplaceUsers(load_object); - inst->GetBasicBlock()->RemoveInst(inst); -} - } // namespace panda::compiler diff --git a/compiler/optimizer/optimizations/expand_intrinsics.h b/compiler/optimizer/optimizations/inline_call_intrinsics.h similarity index 52% rename from compiler/optimizer/optimizations/expand_intrinsics.h rename to compiler/optimizer/optimizations/inline_call_intrinsics.h index 9538d4d01644f4ab4ee100c45356b66e7d0c976d..e7db5c4335709c6a510325c8300c5973aeeba085 100644 --- a/compiler/optimizer/optimizations/expand_intrinsics.h +++ b/compiler/optimizer/optimizations/inline_call_intrinsics.h @@ -13,54 +13,37 @@ * limitations under the License. */ -#ifndef _COMPILER_OPTIMIZER_OPTIMIZATIONS_EXPAND_INTRINSICS_H -#define _COMPILER_OPTIMIZER_OPTIMIZATIONS_EXPAND_INTRINSICS_H +#ifndef _COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINE_CALL_INTRINSICS_H +#define _COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINE_CALL_INTRINSICS_H +#include "optimizer/ir/analysis.h" #include "optimizer/ir/graph.h" #include "optimizer/pass.h" #include "utils/arena_containers.h" namespace panda::compiler { -// Pass aimed to expand various intrinsics into some IR -class ExpandIntrinsics : public Optimization { +// Pass aimed to expand intrinsics into some IR involving CallDynamic, +// and allow calls to be processed in EcmaInlining pass afterwards +// Intrinsics that do not produce calls after inlining should be inlined +// in InlineIntrinsics pass for consistency +class InlineCallIntrinsics : public Optimization { public: - explicit ExpandIntrinsics(Graph *graph) : Optimization(graph), functions_(graph->GetAllocator()->Adapter()) {} + explicit InlineCallIntrinsics(Graph *graph) : Optimization(graph), functions_(graph->GetAllocator()->Adapter()) {} const char *GetPassName() const override { - return "ExpandIntrinsics"; + return "InlineCallIntrinsics"; } bool RunImpl() override; bool IsEnable() const override { - return OPTIONS.IsCompilerEcmaExpandIntrinsics(); - } - - static constexpr size_t GetLdStLexVarDynLevelThreshold() - { - constexpr size_t MAX_LEVEL = 2U; - return MAX_LEVEL; + return OPTIONS.IsCompilerEcmaInlineCallIntrinsics(); } private: - class InstAppender { - public: - explicit InstAppender(BasicBlock *block, Inst *insert_after = nullptr) : block_(block), prev_(insert_after) {} - ~InstAppender() = default; - DEFAULT_MOVE_SEMANTIC(InstAppender); - NO_COPY_SEMANTIC(InstAppender); - - void Append(Inst *inst); - void Append(std::initializer_list instructions); - - private: - BasicBlock *block_; - Inst *prev_ {nullptr}; - }; - bool Expand(IntrinsicInst *inst); bool ExpandNewObjDynRange(IntrinsicInst *inst); void ExpandNewObjDynDefault(Inst *inst); @@ -73,21 +56,10 @@ private: Inst *NewObjResolveCtorResult(InstAppender *appender, Inst *orig_alloc, Inst *alloc_obj, Inst *call_ctor, uint32_t pc); void BuildGuard(Inst *inst, uintptr_t target); - Inst *GetParentLexEnv(InstAppender *appender, Inst *current_lex_env, uint32_t level, uint32_t pc); - bool ExpandLdLexDyn(IntrinsicInst *intrinsic); - bool ExpandStLexDyn(IntrinsicInst *intrinsic); - bool ExpandLdLexVarDyn(IntrinsicInst *intrinsic); - bool ExpandLdlexenvDyn(IntrinsicInst *intrinsic); - bool ExpandStLexVarDyn(IntrinsicInst *intrinsic); - bool ExpandPopLexenvDyn(IntrinsicInst *intrinsic); - - bool ExpandTryLdGlobalByName(IntrinsicInst *inst); - template - void ExpandTryLdGlobalField(IntrinsicInst *inst, uintptr_t address); ArenaVector functions_; }; } // namespace panda::compiler -#endif // _COMPILER_OPTIMIZER_OPTIMIZATIONS_EXPAND_INTRINSICS_H +#endif // _COMPILER_OPTIMIZER_OPTIMIZATIONS_INLINE_CALL_INTRINSICS_H diff --git a/compiler/templates/ecmascript_inst_builder_gen.cpp.erb b/compiler/templates/ecmascript_inst_builder_gen.cpp.erb index e8d76012d9a387b1e4bef7ec9eff21533f609127..23e4a6ae98a641f3a29ef4d1cd1666f71f188c7c 100644 --- a/compiler/templates/ecmascript_inst_builder_gen.cpp.erb +++ b/compiler/templates/ecmascript_inst_builder_gen.cpp.erb @@ -147,10 +147,6 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N % end inst->ReserveInputs(args_count); inst->AllocateInputTypes(GetGraph()->GetAllocator(), args_count); - // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) - if constexpr (WITH_SPECULATIVE) { - inst->SetInlined(true); - } % imm_index = 0 % vreg_index = 0 diff --git a/ecmascript_plugin_options.yaml b/ecmascript_plugin_options.yaml index 72cdf9c8a9747e1bed1c0dfd9672e7a690c0596d..b51485b57fc41097c812c6542e71703d25c7f19a 100644 --- a/ecmascript_plugin_options.yaml +++ b/ecmascript_plugin_options.yaml @@ -71,8 +71,7 @@ CALLABLE_TYPE: panda::compiler::DataType::Type::REFERENCE BIGINT_TYPE: panda::compiler::DataType::Type::REFERENCE Intrinsics: - intrinsic_inline_inl: plugins/ecmascript/compiler/intrinsics_inline_ecmascript.inl - intrinsic_type_resolving_inl_h: plugins/ecmascript/compiler/intrinsics_type_resolving_ecmascript.inl.h + intrinsics_inline_inl_h: plugins/ecmascript/compiler/intrinsics_inline_ecmascript.inl.h intrinsics_graph_checker_inl: plugins/ecmascript/compiler/intrinsics_graph_checker.h Metadatas: - RecordMetadata: diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index dbcad22282c9339dd74d30380b338ca2817898d6..fb36ab847e756762e9a44ad53d5c325370423b07 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -599,7 +599,7 @@ macro(:tonumberdyn_double_special) do |v| f64toany(anytof64(v)) end -cpp_function(:"IrtocInlineToNumberDyn") do +cpp_function(:"IrtocInlineToNumber") do params type1: 'any' cpp_params special: 'bool' return_type 'bool' diff --git a/runtime/compiler/ecmascript_runtime_interface.cpp b/runtime/compiler/ecmascript_runtime_interface.cpp index 6871d4ec31683047cd4bb4a7332c24cab89170ca..54d5ceb11cd495116d9ab49e45c275e4faecea66 100644 --- a/runtime/compiler/ecmascript_runtime_interface.cpp +++ b/runtime/compiler/ecmascript_runtime_interface.cpp @@ -535,7 +535,7 @@ bool EcmaRuntimeInterface::AddProfileValueInfo(PandaRuntimeInterface::MethodPtr } inline ProfileTypeInfo *EcmaRuntimeInterface::GetProfileTypeInfo(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, - uint8_t *slot) + uint8_t *slot) const { // ProfileTypeInfo is manage object // We need to have lock in caller method, because we return ProfileTypeInfo @@ -556,8 +556,9 @@ inline ProfileTypeInfo *EcmaRuntimeInterface::GetProfileTypeInfo(PandaRuntimeInt } inline ProfileTypeInfo *EcmaRuntimeInterface::GetProfileTypeInfo(uintptr_t func_address, uintptr_t slot_id, - uint8_t *slot) + uint8_t *slot) const { + ASSERT(func_address != 0); // ProfileTypeInfo is manage object // We need to have lock in caller method, because we return ProfileTypeInfo ASSERT(ecma_vm_->GetMutatorLock()->HasLock()); @@ -581,8 +582,10 @@ inline ProfileTypeInfo *EcmaRuntimeInterface::GetProfileTypeInfo(uintptr_t func_ return ProfileTypeInfo::Cast(profile_info_obj.GetTaggedObject()); } -bool EcmaRuntimeInterface::GetProfileDataForNamedAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, - ArenaVector *profile) +template +bool EcmaRuntimeInterface::GetProfileDataForNamedAccessImpl(PandaRuntimeInterface::MethodPtr m, Func func, + uintptr_t slot_id, + ArenaVector *profile) { if (profile == nullptr) { return false; @@ -590,7 +593,7 @@ bool EcmaRuntimeInterface::GetProfileDataForNamedAccess(PandaRuntimeInterface::M profile->clear(); ScopedMutatorLock lock; uint8_t slot; - ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(m, slot_id, &slot); + ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(func, slot_id, &slot); if (profile_type_info == nullptr) { return false; } @@ -601,57 +604,18 @@ bool EcmaRuntimeInterface::GetProfileDataForNamedAccess(PandaRuntimeInterface::M return false; } -bool EcmaRuntimeInterface::GetProfileDataForNamedAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t func_address, - uintptr_t slot_id, ArenaVector *profile) -{ - if (profile == nullptr) { - return false; - } - profile->clear(); - ASSERT(func_address != 0); - ScopedMutatorLock lock; - - uint8_t slot; - ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(func_address, slot_id, &slot); - if (profile_type_info == nullptr) { - return false; - } - if (AddProfileInfo(m, profile, profile_type_info, slot)) { - AddProfileInfo(m, profile, profile_type_info, slot + 2); - return true; - } - return false; -} - -bool EcmaRuntimeInterface::GetProfileDataForValueAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, - ArenaVector *profile) -{ - if (profile == nullptr) { - return false; - } - profile->clear(); - ScopedMutatorLock lock; - uint8_t slot; - ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(m, slot_id, &slot); - if (profile_type_info == nullptr) { - return false; - } - - return AddProfileValueInfo(m, profile, profile_type_info, slot); -} - -bool EcmaRuntimeInterface::GetProfileDataForValueAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t func_address, - uintptr_t slot_id, ArenaVector *profile) +template +bool EcmaRuntimeInterface::GetProfileDataForValueAccessImpl(PandaRuntimeInterface::MethodPtr m, Func func, + uintptr_t slot_id, + ArenaVector *profile) { if (profile == nullptr) { return false; } profile->clear(); - ASSERT(func_address != 0); ScopedMutatorLock lock; - uint8_t slot; - ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(func_address, slot_id, &slot); + ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(func, slot_id, &slot); if (profile_type_info == nullptr) { return false; } @@ -760,8 +724,10 @@ uintptr_t EcmaRuntimeInterface::AddFixedObjectHandle(Method *method, ObjectHeade return gos->GetAddressForRef(func_ref); } -PandaRuntimeInterface::GlobalVarInfo EcmaRuntimeInterface::GetGlobalVarInfo(PandaRuntimeInterface::MethodPtr method, - size_t id, uintptr_t slot_id) const +template +PandaRuntimeInterface::GlobalVarInfo EcmaRuntimeInterface::GetGlobalVarInfoImpl(PandaRuntimeInterface::MethodPtr method, + Func func, size_t id, + uintptr_t slot_id) const { auto thread = TryGetJSThread(); if (thread == nullptr) { @@ -793,22 +759,11 @@ PandaRuntimeInterface::GlobalVarInfo EcmaRuntimeInterface::GetGlobalVarInfo(Pand return {GlobalVarInfo::Type::NON_CONFIGURABLE, address}; } - uint8_t *mapping = JsMethodCast(method)->GetICMapping(); - if (mapping == nullptr) { - return {}; - } - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - auto slot = mapping[slot_id]; - auto func = GetJSFunctionByMethod(method); - if (func == nullptr) { - return {}; - } - auto pti = func->GetProfileTypeInfo(); - if (!pti.IsHeapObject()) { + uint8_t slot; + ProfileTypeInfo *profile_type_info = GetProfileTypeInfo(func, slot_id, &slot); + if (profile_type_info == nullptr) { return {}; } - ProfileTypeInfo *profile_type_info = ProfileTypeInfo::Cast(pti.GetTaggedObject()); - JSTaggedValue handler = profile_type_info->Get(slot); if (!handler.IsHeapObject()) { return {}; diff --git a/runtime/compiler/ecmascript_runtime_interface.h b/runtime/compiler/ecmascript_runtime_interface.h index d6fefb599a8655828eff6e714c03c94f324b11fe..26b9ccf2b6203a7e7e9a16f0923f0ffb34bf1782 100644 --- a/runtime/compiler/ecmascript_runtime_interface.h +++ b/runtime/compiler/ecmascript_runtime_interface.h @@ -158,13 +158,34 @@ public: NewObjDynInfo GetNewObjDynInfo(uintptr_t ctor) const override; bool GetProfileDataForNamedAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, - ArenaVector *profile) override; + ArenaVector *profile) override + { + return GetProfileDataForNamedAccessImpl(m, m, slot_id, profile); + } bool GetProfileDataForNamedAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t func_address, uintptr_t slot_id, - ArenaVector *profile) override; + ArenaVector *profile) override + { + return GetProfileDataForNamedAccessImpl(m, func_address, slot_id, profile); + } bool GetProfileDataForValueAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, - ArenaVector *profile) override; + ArenaVector *profile) override + { + return GetProfileDataForValueAccessImpl(m, m, slot_id, profile); + } bool GetProfileDataForValueAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t func_address, uintptr_t slot_id, - ArenaVector *profile) override; + ArenaVector *profile) override + { + return GetProfileDataForValueAccessImpl(m, func_address, slot_id, profile); + } + GlobalVarInfo GetGlobalVarInfo(MethodPtr method, uintptr_t id, uintptr_t slot_id) const override + { + return GetGlobalVarInfoImpl(method, method, id, slot_id); + } + GlobalVarInfo GetGlobalVarInfo(MethodPtr method, uintptr_t func_address, uintptr_t id, + uintptr_t slot_id) const override + { + return GetGlobalVarInfoImpl(method, func_address, id, slot_id); + } void CleanFunction(Method *method); @@ -200,8 +221,16 @@ private: bool AddProfileValueInfo(PandaRuntimeInterface::MethodPtr m, ArenaVector *profile, ProfileTypeInfo *profile_type_info, uint8_t slot); bool AddElementInfo(ArenaVector *profile, ProfileTypeInfo *profile_type_info, uint8_t slot); - ProfileTypeInfo *GetProfileTypeInfo(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, uint8_t *slot); - ProfileTypeInfo *GetProfileTypeInfo(uintptr_t func_address, uintptr_t slot_id, uint8_t *slot); + ProfileTypeInfo *GetProfileTypeInfo(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, uint8_t *slot) const; + ProfileTypeInfo *GetProfileTypeInfo(uintptr_t func_address, uintptr_t slot_id, uint8_t *slot) const; + template + bool GetProfileDataForNamedAccessImpl(PandaRuntimeInterface::MethodPtr m, Func func, uintptr_t slot_id, + ArenaVector *profile); + template + bool GetProfileDataForValueAccessImpl(PandaRuntimeInterface::MethodPtr m, Func func, uintptr_t slot_id, + ArenaVector *profile); + template + GlobalVarInfo GetGlobalVarInfoImpl(MethodPtr method, Func func, uintptr_t id, uintptr_t slot_id) const; size_t GetLexicalEnvParentEnvIndex() const override; @@ -209,7 +238,6 @@ private: size_t GetTaggedArrayElementSize() const override; - GlobalVarInfo GetGlobalVarInfo(MethodPtr method, uintptr_t id, uintptr_t slot_id) const override; JSThread *TryGetJSThread() const; std::pair GetGlobalDictionaryEntry(JSThread *thread, MethodPtr method, size_t id) const; diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 026452f41a80d195c12166661661f95977200122..20c7aa2c9bee3e7708ea29151a81720e0368ac2b 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -25,6 +25,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::Ldnan clear_flags: [no_dce] use_thread: false + inline_func: InlineLdNan - name: Ldinfinity space: ecmascript @@ -37,6 +38,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::Ldinfinity clear_flags: [no_dce] use_thread: false + inline_func: InlineLdInfinity - name: Ldglobalthis space: ecmascript @@ -60,6 +62,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::Ldundefined clear_flags: [no_dce] use_thread: false + inline_func: InlineLdUndefined - name: Ldboolean space: ecmascript @@ -112,6 +115,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::Ldnull clear_flags: [no_dce] use_thread: false + inline_func: InlineLdNull - name: Ldsymbol space: ecmascript @@ -166,6 +170,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::Ldtrue clear_flags: [no_dce] use_thread: false + inline_func: InlineLdTrue - name: Ldfalse space: ecmascript @@ -178,6 +183,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::Ldfalse clear_flags: [no_dce] use_thread: false + inline_func: InlineLdFalse - name: Add2Dyn space: ecmascript @@ -191,6 +197,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Add2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaAdd + inline_func: IrtocInlineAddDyn + inline_need_types: true - name: Sub2Dyn space: ecmascript @@ -204,6 +212,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Sub2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaSub + inline_func: IrtocInlineSubDyn + inline_need_types: true - name: Mul2Dyn space: ecmascript @@ -217,6 +227,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Mul2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaMul + inline_func: IrtocInlineMulDyn + inline_need_types: true - name: Div2Dyn space: ecmascript @@ -230,6 +242,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Div2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaDiv + inline_func: IrtocInlineDivDyn + inline_need_types: true - name: Mod2Dyn space: ecmascript @@ -242,6 +256,8 @@ intrinsics: args: [any, acc] impl: panda::ecmascript::intrinsics::Mod2Dyn set_flags: [heap_inv] + inline_func: IrtocInlineModDyn + inline_need_types: true - name: EqDyn space: ecmascript @@ -254,6 +270,8 @@ intrinsics: args: [any, acc] impl: panda::ecmascript::intrinsics::EqDyn set_flags: [heap_inv] + inline_func: InlineEqDyn + inline_need_types: true - name: NotEqDyn space: ecmascript @@ -266,6 +284,8 @@ intrinsics: args: [any, acc] impl: panda::ecmascript::intrinsics::NotEqDyn set_flags: [heap_inv] + inline_func: InlineNotEqDyn + inline_need_types: true - name: LessDyn space: ecmascript @@ -279,6 +299,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::LessDyn set_flags: [heap_inv] fast_path: FastPathEcmaLt + inline_func: IrtocInlineCompareLtDyn + inline_need_types: true - name: LessEqDyn space: ecmascript @@ -292,6 +314,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::LessEqDyn set_flags: [heap_inv] fast_path: FastPathEcmaLe + inline_func: IrtocInlineCompareLeDyn + inline_need_types: true - name: GreaterDyn space: ecmascript @@ -305,6 +329,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::GreaterDyn set_flags: [heap_inv] fast_path: FastPathEcmaGt + inline_func: IrtocInlineCompareGtDyn + inline_need_types: true - name: GreaterEqDyn space: ecmascript @@ -318,6 +344,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::GreaterEqDyn set_flags: [heap_inv] fast_path: FastPathEcmaGe + inline_func: IrtocInlineCompareGeDyn + inline_need_types: true - name: LdObjByValue space: ecmascript @@ -331,6 +359,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::LdObjByValue fast_path: FastPathLdObjByValue set_flags: [heap_inv] + inline_func: InlineLdObjByValue - name: TryLdGlobalByValue space: ecmascript @@ -356,6 +385,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::StObjByValue fast_path: FastPathStObjByValue set_flags: [heap_inv] + inline_func: InlineStObjByValue - name: Shl2Dyn space: ecmascript @@ -369,6 +399,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Shl2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaShl + inline_func: IrtocInlineShlDyn + inline_need_types: true - name: Shr2Dyn space: ecmascript @@ -382,6 +414,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Shr2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaShr + inline_func: IrtocInlineShrDyn + inline_need_types: true - name: Ashr2Dyn space: ecmascript @@ -407,6 +441,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::And2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaAnd + inline_func: IrtocInlineAndDyn + inline_need_types: true - name: Or2Dyn space: ecmascript @@ -420,6 +456,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Or2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaOr + inline_func: IrtocInlineOrDyn + inline_need_types: true - name: Xor2Dyn space: ecmascript @@ -433,6 +471,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::Xor2Dyn set_flags: [heap_inv] fast_path: FastPathEcmaXor + inline_func: IrtocInlineXorDyn + inline_need_types: true - name: Tonumber space: ecmascript @@ -445,6 +485,8 @@ intrinsics: args: [any] impl: panda::ecmascript::intrinsics::Tonumber set_flags: [heap_inv] + inline_func: InlineToNumber + inline_need_types: true - name: NegDyn space: ecmascript @@ -458,6 +500,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::NegDyn set_flags: [heap_inv] fast_path: FastPathEcmaNeg + inline_func: IrtocInlineNegDyn + inline_need_types: true - name: NotDyn space: ecmascript @@ -471,6 +515,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::NotDyn set_flags: [heap_inv] fast_path: FastPathEcmaNot + inline_func: IrtocInlineNotDyn + inline_need_types: true - name: IncDyn space: ecmascript @@ -484,6 +530,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::IncDyn set_flags: [heap_inv] fast_path: FastPathEcmaInc + inline_func: IrtocInlineIncDyn + inline_need_types: true - name: DecDyn space: ecmascript @@ -497,6 +545,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::DecDyn set_flags: [heap_inv] fast_path: FastPathEcmaDec + inline_func: IrtocInlineDecDyn + inline_need_types: true - name: RethrowDyn space: ecmascript @@ -656,6 +706,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::TypeofDyn clear_flags: [no_dce] fast_path: FastTypeOfDyn + inline_func: InlineTypeOf - name: Callruntimerange space: ecmascript @@ -703,6 +754,8 @@ intrinsics: set_flags: [heap_inv] clear_flags: [no_dce] codegen_func: CreateFastPathStrictNotEq + inline_func: InlineStrictNotEqDyn + inline_need_types: true - name: StrictEqDyn space: ecmascript @@ -715,6 +768,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::StrictEqDyn set_flags: [heap_inv] codegen_func: CreateFastPathStrictEq + inline_func: InlineStrictEqDyn + inline_need_types: true - name: NewobjspreadDyn space: ecmascript @@ -803,6 +858,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::StLexVarDyn set_flags: [heap_inv] codegen_func: StLexVarDyn + inline_func: InlineStLexVarDyn - name: StLexDyn space: ecmascript @@ -816,6 +872,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::StLexDyn set_flags: [heap_inv] codegen_func: StLexDyn + inline_func: InlineStLexDyn - name: LdLexVarDyn space: ecmascript @@ -828,6 +885,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::LdLexVarDyn clear_flags: [no_dce, runtime_call, require_state] codegen_func: LdLexVarDyn + inline_func: InlineLdLexVarDyn - name: LdLexDyn space: ecmascript @@ -839,6 +897,7 @@ intrinsics: ret: any args: [string_id, u16, u16, any, any] impl: panda::ecmascript::intrinsics::LdLexDyn + inline_func: InlineLdLexDyn - name: LdlexenvDyn space: ecmascript @@ -851,6 +910,7 @@ intrinsics: impl: panda::ecmascript::intrinsics::LdlexenvDyn clear_flags: [no_dce, runtime_call] codegen_func: LdlexenvDyn + inline_func: InlineLdlexenvDyn - name: PopLexenvDyn space: ecmascript @@ -861,6 +921,7 @@ intrinsics: ret: any args: [any] impl: panda::ecmascript::intrinsics::PopLexenvDyn + inline_func: InlinePopLexenvDyn - name: GetUnmappedArgs space: ecmascript @@ -898,6 +959,8 @@ intrinsics: set_flags: [heap_inv] clear_flags: [no_dce] use_thread: false + inline_func: IrtocInlineToBooleanDyn + inline_need_types: true - name: Negate space: ecmascript @@ -937,6 +1000,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::IsTrue clear_flags: [no_dce] use_thread: false + inline_func: IrtocInlineIsTrueDyn + inline_need_types: true - name: IsFalse space: ecmascript @@ -950,6 +1015,8 @@ intrinsics: impl: panda::ecmascript::intrinsics::IsFalse clear_flags: [no_dce] use_thread: false + inline_func: IrtocInlineIsFalseDyn + inline_need_types: true - name: IsCoercible space: ecmascript @@ -1259,6 +1326,7 @@ intrinsics: clear_flags: [no_dce] impl: panda::ecmascript::intrinsics::Ldhole use_thread: false + inline_func: InlineLdHole - name: TryStGlobalByValue space: ecmascript @@ -1306,6 +1374,7 @@ intrinsics: ret: any args: [string_id, u16, any, any] impl: panda::ecmascript::intrinsics::TryLdGlobalByName + inline_func: InlineTryLdGlobalByName set_flags: [heap_inv] - name: TryStGlobalByName @@ -1357,6 +1426,7 @@ intrinsics: args: [string_id, acc, u16, any, any] impl: panda::ecmascript::intrinsics::LdObjByName fast_path: FastPathLdObjByName + inline_func: InlineLdObjByName set_flags: [heap_inv] - name: StObjByName @@ -1370,6 +1440,7 @@ intrinsics: args: [string_id, any, acc, u16, any, any] impl: panda::ecmascript::intrinsics::StObjByName fast_path: FastPathStObjByName + inline_func: InlineStObjByName set_flags: [heap_inv] - name: LdObjByIndex @@ -2277,6 +2348,7 @@ intrinsics: args: [any, any, any] codegen_func: CreateResolveAllocResult set_flags: [can_throw] + inline_func: InlineResolveAllocResult - name: EcmaStringEquals space: ecmascript diff --git a/subproject_sources.gn b/subproject_sources.gn index 1c75a77bcece720d7708ab3161234fc5053c3514..36a28119e1a2d810318376a4f9ce398e253f4d28 100644 --- a/subproject_sources.gn +++ b/subproject_sources.gn @@ -22,7 +22,7 @@ srcs_isa = [ "isa/isa.yaml" ] srcs_compiler = [ "compiler/optimizer/code_generator/compiler_base_types.cpp", "compiler/ecmascript_extensions/ecmascript_codegen_extensions.cpp", - "compiler/intrinsics_type_resolving_ecmascript.cpp", + "compiler/inline_intrinsics_ecmascript.cpp", "compiler/codegen_intrinsics_ecmascript.cpp", "compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp", ] diff --git a/tests/checked/CMakeLists.txt b/tests/checked/CMakeLists.txt index 18421ae91694394703eb4bec36f3f3b00343c929..edcfc078615b90e69b2385c774cd1837263f568d 100644 --- a/tests/checked/CMakeLists.txt +++ b/tests/checked/CMakeLists.txt @@ -92,7 +92,7 @@ endfunction() if (NOT PANDA_TARGET_ARM32) # Disable checked tests with sanitizers for arm64, since it takes too long time running. if (PANDA_TARGET_AMD64 OR NOT PANDA_ARM64_TESTS_WITH_SANITIZER) - panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/type_resolving.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/inline_intrinsics.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/getunmappedargs_test.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/global_var.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/try_load_global_by_name.js SUPPORT_RELEASE true) diff --git a/tests/checked/type_resolving.js b/tests/checked/inline_intrinsics.js similarity index 95% rename from tests/checked/type_resolving.js rename to tests/checked/inline_intrinsics.js index d101925c430c733d1f1409a55baa5e910aeec24d..8ba4dc1fcbb924908a8ffccdde105ba281b174e7 100644 --- a/tests/checked/type_resolving.js +++ b/tests/checked/inline_intrinsics.js @@ -17,10 +17,10 @@ //! RUN_PAOC options: "--compiler-regex '_GLOBAL::test_(\\w+_[if](_[if]|)|toboolean|ld.*|string|.*compare.*)'" //! check_aot = lambda do |op, intrinsic, form, inst| //! METHOD "test_#{op.downcase}_#{form}" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST "Intrinsic.#{intrinsic}" //! INST_NOT inst -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT "Intrinsic.#{intrinsic}" //! INST inst //! end @@ -83,11 +83,11 @@ //! insts = [['eq', 'Eq'], ['ne', 'NotEq'], ['ge', 'GreaterEq'], ['le', 'LessEq'], ['gt', 'Greater'], ['lt', 'Less'], ['eq', 'StrictEq'], ['ne', 'StrictNotEq']] //! forms.each do |form, type| //! METHOD "test_cmp_#{form}" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! insts.each do |op, intrinsic| //! INST "Intrinsic.#{intrinsic}Dyn" //! end -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! insts.each do |op, intrinsic| //! INST_NOT "Intrinsic.#{intrinsic}Dyn" //! if (['ge', 'le', 'gt', 'lt'].include? op) && type == 'f64' @@ -101,36 +101,36 @@ //! end //! //! METHOD "test_toboolean" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST_COUNT "Intrinsic.Toboolean", 5 -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_COUNT "Intrinsic.Toboolean", 2 //! //! METHOD "test_string" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST "Intrinsic.EqDyn" //! INST_NEXT "Intrinsic.NotEqDyn" //! INST_NEXT "Intrinsic.StrictEqDyn" //! INST_NEXT "Intrinsic.StrictNotEqDyn" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.*EqDyn/ //! INST_COUNT "Intrinsic.EcmaStringEquals", 4 //! //! METHOD "test_strict_compare_diff_types" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST_COUNT "Intrinsic.StrictNotEqDyn", 4 //! INST_COUNT "Intrinsic.StrictEqDyn", 2 //! INST_COUNT "Compare", 7 -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.*EqDyn/ //! INST_COUNT "Compare", 9 //! //! METHOD "test_compare_diff_types" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST_COUNT "Intrinsic.EqDyn", 8 //! INST_COUNT "Intrinsic.NotEqDyn", 3 //! INST_COUNT "Compare", 11 -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_COUNT "Intrinsic.EqDyn", 1 //! INST_NOT "Intrinsic.NotEqDyn" //! INST_COUNT "Compare", 13 @@ -735,7 +735,7 @@ function test_string() { } } -// Only two new Compare instructions should be created after types_resolving, +// Only two new Compare instructions should be created after inline_intrinsics, // other comparisons should be replaced with true/false based on input types function test_strict_compare_diff_types() { let a = "abcde"; @@ -746,13 +746,13 @@ function test_strict_compare_diff_types() { if (false !== null) res += 3; if (a === undefined) res += 7; if (b !== true) res += 8; - if (b === 0) res += 9; // Compare EQ after types_resolving - if (res != 14) { // Compare NE after types_resolving + if (b === 0) res += 9; // Compare EQ after inline_intrinsics + if (res != 14) { // Compare NE after inline_intrinsics throw "test_strict_compare_diff_types is failed" } } -// Only one new Compare instruction should be created after types_resolving, +// Only one new Compare instruction should be created after inline_intrinsics, // other comparisons should be replaced with true/false or not inlined function test_compare_diff_types() { let a = "1"; @@ -769,7 +769,7 @@ function test_compare_diff_types() { if (null == c) res += 11; // false if (b == c) res += 12; // false, create Compare EQ if (undefined != null) res += 13; // false - if (res != 25) { // Compare NE after types_resolving + if (res != 25) { // Compare NE after inline_intrinsics throw "test_compare_diff_types is failed: " + res } } diff --git a/tests/checked/ldlex.js b/tests/checked/ldlex.js index e6a5c28a1d26ac9f1285af88179ed6e7b09fa02f..1214343e9569919b87a517fc071144255e104201 100644 --- a/tests/checked/ldlex.js +++ b/tests/checked/ldlex.js @@ -59,30 +59,30 @@ function get_level3() { }; } -//! CHECKER Expand LdLexDyn/LdLexVarDyn intrinsics +//! CHECKER Inline LdLexDyn/LdLexVarDyn intrinsics //! RUN options: "--compiler-hotness-threshold=0 --no-async-jit=true --compiler-regex='_GLOBAL::compile_.*'", entry: "_GLOBAL::func_main_0" //! METHOD "compile_level0" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.LdLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.LdLexDyn.*/ //! INST_NOT /Intrinsic.LdLexVarDyn.*/ //! METHOD "compile_level1" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.LdLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.LdLexDyn.*/ //! INST_NOT /Intrinsic.LdLexVarDyn.*/ //! METHOD "compile_level2" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.LdLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.LdLexDyn.*/ //! INST_NOT /Intrinsic.LdLexVarDyn.*/ //! METHOD "compile_level3" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.LdLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.LdLexDyn.*/ //! INST /Intrinsic.LdLexVarDyn.*/ get_level0()(); diff --git a/tests/checked/new_obj_profiling.js b/tests/checked/new_obj_profiling.js index 2406056bcfb240096ec83983fd8a37c4f93b1d84..80a6d2ba49a1bde9d5b369f79dc6a73397b999ed 100644 --- a/tests/checked/new_obj_profiling.js +++ b/tests/checked/new_obj_profiling.js @@ -61,11 +61,11 @@ function monomorphic_call_site_derived_ctor() { //! INST /Intrinsic.ResolveAllocResult.*/ //! INST /Intrinsic.NewobjDynrangeHandled*/ //! METHOD "monomorphic_call_site_simple_ctor" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST /Intrinsic.AllocDynObject.*/ //! INST /Intrinsic.ResolveAllocResult.*/ //! INST_NOT /Intrinsic.NewobjDynrangeHandled*/ -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST /Intrinsic.AllocDynObject.*/ //! INST_NOT /Intrinsic.ResolveAllocResult.*/ //! INST_NOT /Intrinsic.NewobjDynrangeHandled*/ diff --git a/tests/checked/obj_by_name.js b/tests/checked/obj_by_name.js index e9913df18c3f6665fc75c0c3d2959d637ac310c2..fc4920917a25349963cc82bd471aa80c392ad617 100644 --- a/tests/checked/obj_by_name.js +++ b/tests/checked/obj_by_name.js @@ -16,7 +16,7 @@ //! CHECKER Test check store and load by name //! RUN options: "--no-async-jit --compiler-hotness-threshold=10 --compiler-regex _GLOBAL::test_load_store_by_name.*", entry: "_GLOBAL::func_main_0" //! METHOD "test_load_store_by_name_single_field_inlined" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" //! INST_NEXT "CastAnyTypeValue" //! INST_NEXT /LoadObject.*Class/ @@ -29,7 +29,7 @@ //! INST_NOT "StoreArray" //! EVENT /Compilation,_GLOBAL::test_load_store_by_name_single_field_inlined,.*,COMPILED/ //! METHOD "test_load_store_by_name_single_field_properties" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" //! INST_NEXT "CastAnyTypeValue" //! INST_NEXT /LoadObject.*Class/ @@ -42,7 +42,7 @@ //! INST_NOT "StoreObject" //! EVENT /Compilation,_GLOBAL::test_load_store_by_name_single_field_properties,.*,COMPILED/ //! METHOD "test_load_store_by_name_single_transition_inlined" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" //! INST_NEXT "CastAnyTypeValue" //! INST_NEXT /LoadObject.*Class/ @@ -57,7 +57,7 @@ //! INST_NOT "StoreArray" //! EVENT /Compilation,_GLOBAL::test_load_store_by_name_single_transition_inlined,.*,COMPILED/ //! METHOD "test_load_store_by_name_single_transition_properties" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" //! INST_NEXT "CastAnyTypeValue" //! INST_NEXT /LoadObject.*Class/ @@ -72,7 +72,7 @@ //! INST_NEXT "StoreArray" //! EVENT /Compilation,_GLOBAL::test_load_store_by_name_single_transition_properties,.*,COMPILED/ //! METHOD "test_load_store_by_name_single_prototype_inlined" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" //! INST_NEXT "CastAnyTypeValue" //! INST_NEXT /LoadObject.*Class/ @@ -86,7 +86,7 @@ //! INST_NEXT "DeoptimizeIf" //! EVENT /Compilation,_GLOBAL::test_load_store_by_name_single_prototype_inlined,.*,COMPILED/ //! METHOD "test_load_store_by_name_polymorphic" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" //! INST_NEXT "CastAnyTypeValue" //! INST_NEXT /LoadObject.*Class/ diff --git a/tests/checked/peephole_negoverflowandzerocheck.js b/tests/checked/peephole_negoverflowandzerocheck.js index 361515fa2dba1d846e4f50e5b0b55bc34e566d1d..00e1c49e2821d88f9df5b9602e2a71517b00b38e 100644 --- a/tests/checked/peephole_negoverflowandzerocheck.js +++ b/tests/checked/peephole_negoverflowandzerocheck.js @@ -16,21 +16,21 @@ //! CHECKER Peephole for NegOverflowAndZeroCheck //! RUN options: "--no-async-jit --compiler-hotness-threshold=10", entry: "_GLOBAL::func_main_0" //! METHOD "__noinline__test_peephole_success_shl" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST /NegOverflowAndZeroCheck / //! INST_NOT /Neg / //! PASS_BEFORE "Lowering" //! INST_NOT /NegOverflowAndZeroCheck / //! INST /Neg / //! METHOD "__noinline__test_peephole_success_and" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST /NegOverflowAndZeroCheck / //! INST_NOT /Neg / //! PASS_BEFORE "Lowering" //! INST_NOT /NegOverflowAndZeroCheck / //! INST /Neg / //! METHOD "__noinline__test_peephole_reject_add" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Neg / //! INST /NegOverflowAndZeroCheck / //! PASS_BEFORE "Lowering" diff --git a/tests/checked/poplexenv.js b/tests/checked/poplexenv.js index 147b65dbb025439ed51ed91f1a778a90bd54cb20..e6c4318dbcaf5dcc234654ae11afcb6548c0a476 100644 --- a/tests/checked/poplexenv.js +++ b/tests/checked/poplexenv.js @@ -13,13 +13,13 @@ * limitations under the License. */ -//! CHECKER Expand PopLexenvDyn intrinsic +//! CHECKER Inline PopLexenvDyn intrinsic //! RUN options: "--compiler-hotness-threshold=0 --no-async-jit=true --compiler-regex='_GLOBAL::level1'", entry: "_GLOBAL::func_main_0" //! METHOD "level1" //! PASS_AFTER "IrBuilder" //! INST "Intrinsic.PopLexenvDyn" //! INST_NEXT "Intrinsic.LdLexDyn" -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT "Intrinsic.PopLexenvDyn" //! INST "CastAnyTypeValue ECMASCRIPT_ARRAY_TYPE" //! INST_NEXT "LoadArray" diff --git a/tests/checked/stlex.js b/tests/checked/stlex.js index f59d9917093042158d34d4ce85da52f39d1fbc2c..eaa6f79ac356d1237bc8ec8bb90978c27f8c3f66 100644 --- a/tests/checked/stlex.js +++ b/tests/checked/stlex.js @@ -55,48 +55,48 @@ function testfn_level0(x) { } } -//! CHECKER Expand StLexDyn/StLexVarDyn intrinsics +//! CHECKER Inline StLexDyn/StLexVarDyn intrinsics //! RUN options: "--compiler-hotness-threshold=0 --no-async-jit=true --compiler-regex='_GLOBAL::testfn.*'", entry: "_GLOBAL::func_main_0" //! METHOD "testfn" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexVarDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.StLexDyn.*/ //! INST_NOT /Intrinsic.StLexVarDyn.*/ //! METHOD "testfn_l0" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexVarDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.StLexDyn.*/ //! INST_NOT /Intrinsic.StLexVarDyn.*/ //! METHOD "testfn_in" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.StLexDyn.*/ //! INST_NOT /Intrinsic.StLexVarDyn.*/ //! METHOD "testfn_level0" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexVarDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.StLexDyn.*/ //! INST_NOT /Intrinsic.StLexVarDyn.*/ //! METHOD "testfn_level1" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.StLexDyn.*/ //! INST_NOT /Intrinsic.StLexVarDyn.*/ //! METHOD "testfn_level2" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.StLexDyn.*/ //! INST_NOT /Intrinsic.StLexVarDyn.*/ //! METHOD "testfn_level3" //! PASS_AFTER "IrBuilder" //! INST /Intrinsic.StLexDyn.*/ -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST /Intrinsic.StLexDyn.*/ testfn(); diff --git a/tests/checked/string_equals.js b/tests/checked/string_equals.js index 2fc7186d7b49b29cca0516eae9565610b10c8b40..479ac8fa4ac3fdf04797520d32c01b4209d08d13 100644 --- a/tests/checked/string_equals.js +++ b/tests/checked/string_equals.js @@ -17,12 +17,12 @@ //! RUN options: "--no-async-jit --compiler-hotness-threshold=1 --compiler-ecma-replace-intrinsics-to-deopt=false --compiler-regex _GLOBAL::test_.*", entry: "_GLOBAL::func_main_0" //! EVENT_NOT /Deoptimization.*/ //! METHOD "test_eq" -//! PASS_BEFORE "TypesResolving" +//! PASS_BEFORE "InlineIntrinsics" //! INST "Intrinsic.EqDyn" //! INST_NEXT "Intrinsic.NotEqDyn" //! INST_NEXT "Intrinsic.StrictEqDyn" //! INST_NEXT "Intrinsic.StrictNotEqDyn" -//! PASS_AFTER "TypesResolving" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT /Intrinsic.*EqDyn/ //! INST_COUNT "Intrinsic.EcmaStringEquals", 4 //! PASS_AFTER "Codegen" diff --git a/tests/checked/try_load_global_by_name.js b/tests/checked/try_load_global_by_name.js index 7db1d66f489d4602cb72cff1bc0ac6c2e2903a3d..f598fc358554a3e1103dd2ee29efd1de34e6ec8a 100644 --- a/tests/checked/try_load_global_by_name.js +++ b/tests/checked/try_load_global_by_name.js @@ -22,7 +22,7 @@ //! METHOD "get_x" //! PASS_AFTER "IrBuilder" //! INST "Intrinsic.TryLdGlobalByName" -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT "Intrinsic.TryLdGlobalByName" //! INST "GetGlobalVarAddress" //! INST_NEXT "LoadObject" @@ -31,7 +31,7 @@ //! METHOD "get_y" //! PASS_AFTER "IrBuilder" //! INST "Intrinsic.TryLdGlobalByName" -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT "Intrinsic.TryLdGlobalByName" //! INST "GetGlobalVarAddress" //! INST_NEXT "LoadObject" @@ -40,16 +40,26 @@ //! METHOD "get_non_conf" //! PASS_AFTER "IrBuilder" //! INST "Intrinsic.TryLdGlobalByName" -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT "Intrinsic.TryLdGlobalByName" //! INST_NOT "DeoptimizeIf" //! INST "GetGlobalVarAddress" //! INST_NEXT "LoadObject" +//! METHOD "get_non_conf_twice" +//! PASS_AFTER "IrBuilder" +//! INST_NOT "Intrinsic.TryLdGlobalByName" +//! PASS_AFTER "Inline." +//! INST "Intrinsic.TryLdGlobalByName" +//! PASS_AFTER "InlineIntrinsics" +//! INST_NOT "Intrinsic.TryLdGlobalByName" +//! INST_NOT "DeoptimizeIf INLINE_IC" +//! INST "GetGlobalVarAddress" +//! INST_NEXT "LoadObject" //! METHOD "get_const" //! PASS_AFTER "IrBuilder" //! INST "Intrinsic.TryLdGlobalByName" //! INST_COUNT "Constant", 2 -//! PASS_AFTER "ExpandIntrinsics" +//! PASS_AFTER "InlineIntrinsics" //! INST_NOT "Intrinsic.TryLdGlobalByName" //! INST_NOT "DeoptimizeIf" //! INST_NOT "GetGlobalVarAddress" @@ -67,6 +77,12 @@ function get_y() { function get_non_conf() { return non_conf_var; } +function inlined_get_non_conf() { + return non_conf_var; +} +function get_non_conf_twice() { + return inlined_get_non_conf() + inlined_get_non_conf(); +} function get_const() { return const_var; } @@ -145,6 +161,14 @@ if (sum != 0) { throw "Wrong result after write to non-configurable global var: " + sum; } +sum = 0; +for (var i = 0; i < 15; i++) { + sum += get_non_conf_twice(); +} +if (sum != -30) { + throw "Wrong result for loading non-configurable global var from inlined function: " + sum; +} + Object.defineProperty(globalThis, "const_var", {value: 4, writable: false, configurable: false}); sum = 0; for (var i = 0; i < 20; i++) { diff --git a/tests/compiler/CMakeLists.txt b/tests/compiler/CMakeLists.txt index 5ff302f25dd5ccbc4a904e61713005f731650f30..5f3f5dc1630171d534e3ed9f6b11cc76876b23ee 100644 --- a/tests/compiler/CMakeLists.txt +++ b/tests/compiler/CMakeLists.txt @@ -23,11 +23,11 @@ set(PANDA_COMPILER_ECMA_TESTS_SOURCES unit_ecma_test.cpp branch_elimination_ecma_test.cpp checks_elimination_ecma_test.cpp - expand_intrinsics_ecma_test.cpp + inline_call_intrinsics_ecma_test.cpp ir_builder_ecma_test.cpp lowering_ecma_test.cpp peepholes_ecma_test.cpp - types_resolving_ecma_tests.cpp + inline_intrinsics_ecma_test.cpp phi_type_resolving_ecma_test.cpp vn_test_ecma.cpp ) diff --git a/tests/compiler/expand_intrinsics_ecma_test.cpp b/tests/compiler/expand_intrinsics_ecma_test.cpp deleted file mode 100644 index eea116f26f5a3323a597bc6a7c1835d1f3d4763e..0000000000000000000000000000000000000000 --- a/tests/compiler/expand_intrinsics_ecma_test.cpp +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "unit_ecma_test.h" -#include "optimizer/ir/datatype.h" -#include "optimizer/optimizations/cleanup.h" -#include "plugins/ecmascript/compiler/optimizer/optimizations/expand_intrinsics.h" - -namespace panda::compiler { -class ExpandIntrinsicsTest : public AsmTest { -public: - ExpandIntrinsicsTest() = default; -}; - -// NOLINTBEGIN(readability-magic-numbers) -TEST_F(ExpandIntrinsicsTest, LdLexVarDynApply) -{ - constexpr uint32_t SLOT = 10U; - - for (size_t level = 0U; level <= ExpandIntrinsics::GetLdStLexVarDynLevelThreshold(); ++level) { - auto graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(2, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) - .any() - .Inputs({{DataType::ANY, 1}}) - .AddImm(level) - .AddImm(SLOT); - INST(3, Opcode::Return).any().Inputs(2); - } - } - - ASSERT_TRUE(graph->RunPass()); - ASSERT_FALSE(graph->RunPass()); - GraphChecker(graph).Check(); - - auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(11, 0).any(); - CONSTANT(0, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); - CONSTANT(1, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); - - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(11); - INST(3, Opcode::CastAnyTypeValue) - .ref() - .Inputs(2) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - int last_index = 3; - for (auto cur_level = level; cur_level > 0U; --cur_level) { - INST(last_index + 1, Opcode::LoadArray).any().Inputs(last_index, 0); - INST(last_index + 2, Opcode::CastAnyTypeValue) - .ref() - .Inputs(last_index + 1) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - last_index += 2; - } - INST(last_index + 1, Opcode::LoadArray).any().Inputs(last_index, 1); - INST(last_index + 2, Opcode::Return).any().Inputs(last_index + 1); - } - } - - graph_opt->RunPass(); - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); - } -} - -TEST_F(ExpandIntrinsicsTest, LdLexVarDynSkip) -{ - constexpr uint32_t LEVEL = ExpandIntrinsics::GetLdStLexVarDynLevelThreshold() + 1U; - constexpr uint32_t SLOT = 10U; - - auto graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(2, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) - .any() - .Inputs({{DataType::ANY, 1}}) - .AddImm(LEVEL) - .AddImm(SLOT); - INST(3, Opcode::Return).any().Inputs(2); - } - } - - ASSERT_FALSE(graph->RunPass()); - ASSERT_FALSE(graph->RunPass()); - GraphChecker(graph).Check(); - - auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(2, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) - .any() - .Inputs({{DataType::ANY, 1}}) - .AddImm(LEVEL) - .AddImm(SLOT); - INST(3, Opcode::Return).any().Inputs(2); - } - } - - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); -} - -TEST_F(ExpandIntrinsicsTest, LdLexDyn) -{ - constexpr uint32_t STRING_ID = 0xABCDU; - constexpr uint32_t LEVEL = ExpandIntrinsics::GetLdStLexVarDynLevelThreshold() + 1U; - constexpr uint32_t SLOT = 10U; - - auto graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadConstantPool).any().Inputs(0); - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::SaveState).NoVregs(); - INST(4, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_DYN) - .any() - .Inputs({{DataType::ANY, 1}, {DataType::ANY, 2}, {DataType::NO_TYPE, 3}}) - .AddImm(STRING_ID) - .AddImm(LEVEL) - .AddImm(SLOT); - INST(5, Opcode::Return).any().Inputs(4); - } - } - - ASSERT_TRUE(graph->RunPass()); - ASSERT_TRUE(graph->RunPass()); - GraphChecker(graph).Check(); - - auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - CONSTANT(1, DataType::Any(panda::coretypes::TaggedValue::VALUE_HOLE)); - BASIC_BLOCK(2, -1) - { - INST(3, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(4, Opcode::SaveState).NoVregs(); - // We do not check LdLexVarDyn expansion in this test! - INST(5, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) - .any() - .Inputs({{DataType::ANY, 3}}) - .AddImm(LEVEL) - .AddImm(SLOT) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(6, Opcode::Compare).b().Inputs(5, 1).SrcType(DataType::ANY).CC(ConditionCode::CC_EQ); - INST(7, Opcode::DeoptimizeIf).Inputs(6, 4).DeoptimizeType(DeoptimizeType::HOLE); - INST(8, Opcode::Return).any().Inputs(5); - } - } - - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); -} - -TEST_F(ExpandIntrinsicsTest, ExpandLdlexenvDyn) -{ - auto graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(4, Opcode::SaveState).NoVregs(); - INST(1, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN) - .any() - .Inputs({{DataType::ANY, 0}}) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(2, Opcode::Return).any().Inputs(1); - } - } - ASSERT_TRUE(graph->RunPass()); - ASSERT_TRUE(graph->RunPass()); - GraphChecker(graph).Check(); - auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(2, Opcode::Return).any().Inputs(1); - } - } - GraphChecker(graph_opt).Check(); - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); -} - -TEST_F(ExpandIntrinsicsTest, StLexVarDyn) -{ - constexpr uint32_t SLOT = 10U; - - size_t level = 0U; - auto graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) - .any() - .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) - .AddImm(level) - .AddImm(SLOT) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - ASSERT_TRUE(graph->RunPass()); - ASSERT_FALSE(graph->RunPass()); - GraphChecker(graph).Check(); - auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - CONSTANT(7, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); - - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::CastAnyTypeValue) - .ref() - .Inputs(2) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(5, Opcode::StoreArray).any().Inputs(3).Inputs(7).Inputs(1).SetNeedBarrier(true); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - graph_opt->RunPass(); - GraphChecker(graph_opt).Check(); - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); - - level = 1U; - graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) - .any() - .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) - .AddImm(level) - .AddImm(SLOT) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - ASSERT_TRUE(graph->RunPass()); - ASSERT_FALSE(graph->RunPass()); - GraphChecker(graph).Check(); - - graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - CONSTANT(7, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); - CONSTANT(10, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); - - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(5, Opcode::CastAnyTypeValue) - .ref() - .Inputs(2) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(6, Opcode::LoadArray).any().Inputs(5, 7); - INST(8, Opcode::CastAnyTypeValue) - .ref() - .Inputs(6) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(9, Opcode::StoreArray).any().Inputs(8).Inputs(10).Inputs(1).SetNeedBarrier(true); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - graph_opt->RunPass(); - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); - - level = 2U; - graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) - .any() - .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) - .AddImm(level) - .AddImm(SLOT) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - ASSERT_TRUE(graph->RunPass()); - ASSERT_FALSE(graph->RunPass()); - GraphChecker(graph).Check(); - - graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - CONSTANT(7, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); - CONSTANT(12, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); - - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(5, Opcode::CastAnyTypeValue) - .ref() - .Inputs(2) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(6, Opcode::LoadArray).any().Inputs(5, 7); - INST(8, Opcode::CastAnyTypeValue) - .ref() - .Inputs(6) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(9, Opcode::LoadArray).any().Inputs(8, 7); - INST(10, Opcode::CastAnyTypeValue) - .ref() - .Inputs(9) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(11, Opcode::StoreArray).any().Inputs(10).Inputs(12).Inputs(1).SetNeedBarrier(true); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - graph_opt->RunPass(); - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); - - level = 3U; - graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) - .any() - .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) - .AddImm(level) - .AddImm(SLOT) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - ASSERT_FALSE(graph->RunPass()); - ASSERT_FALSE(graph->RunPass()); - GraphChecker(graph).Check(); - - graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - CONSTANT(1, 1); - BASIC_BLOCK(2, -1) - { - INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(3, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) - .any() - .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) - .AddImm(level) - .AddImm(SLOT) - .ClearFlag(inst_flags::REQUIRE_STATE); - INST(4, Opcode::ReturnVoid).v0id(); - } - } - graph_opt->RunPass(); - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); -} - -TEST_F(ExpandIntrinsicsTest, PopLexenvDyn) -{ - auto graph = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph) - { - PARAMETER(0, 0).any(); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(2, Opcode::SaveState).NoVregs(); - INST(3, Opcode::Intrinsic) - .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_POP_LEXENV_DYN) - .any() - .Inputs({{DataType::ANY, 1}, {DataType::NO_TYPE, 2}}); - INST(4, Opcode::Return).any().Inputs(3); - } - } - - ASSERT_TRUE(graph->RunPass()); - GraphChecker(graph).Check(); - - auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); - GRAPH(graph_opt) - { - PARAMETER(0, 0).any(); - CONSTANT(5, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); - BASIC_BLOCK(2, -1) - { - INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); - INST(2, Opcode::SaveState).NoVregs(); - INST(4, Opcode::CastAnyTypeValue) - .ref() - .Inputs(1) - .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) - .SetFlag(inst_flags::NO_HOIST); - INST(6, Opcode::LoadArray).any().Inputs(4, 5); - INST(3, Opcode::Return).any().Inputs(6); - } - } - - ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); -} -// NOLINTEND(readability-magic-numbers) -} // namespace panda::compiler diff --git a/tests/compiler/inline_call_intrinsics_ecma_test.cpp b/tests/compiler/inline_call_intrinsics_ecma_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a81968cbfda3aaafebc43cb5a1c7873e418d61cd --- /dev/null +++ b/tests/compiler/inline_call_intrinsics_ecma_test.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unit_ecma_test.h" +#include "optimizer/ir/datatype.h" +#include "optimizer/optimizations/cleanup.h" +#include "plugins/ecmascript/compiler/optimizer/optimizations/inline_call_intrinsics.h" + +namespace panda::compiler { +class InlineCallIntrinsicsTest : public AsmTest { +public: + InlineCallIntrinsicsTest() = default; +}; +} // namespace panda::compiler diff --git a/tests/compiler/types_resolving_ecma_tests.cpp b/tests/compiler/inline_intrinsics_ecma_test.cpp similarity index 49% rename from tests/compiler/types_resolving_ecma_tests.cpp rename to tests/compiler/inline_intrinsics_ecma_test.cpp index 906128e7b6827ae753f19fe97d59ccc689bb0d6a..724dba1939b7083733dab7cfe9cae4ea3f377192 100644 --- a/tests/compiler/types_resolving_ecma_tests.cpp +++ b/tests/compiler/inline_intrinsics_ecma_test.cpp @@ -18,7 +18,7 @@ #include "optimizer/ir/graph_cloner.h" #include "optimizer/optimizations/cleanup.h" #include "optimizer/optimizations/phi_type_resolving.h" -#include "optimizer/optimizations/types_resolving.h" +#include "optimizer/optimizations/inline_intrinsics.h" #include "runtime/include/coretypes/tagged_value.h" namespace panda::compiler { @@ -81,7 +81,7 @@ 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()); ASSERT_TRUE(graph->template RunPass()); GraphChecker(graph).Check(); Graph *graph_opt = nullptr; @@ -102,7 +102,7 @@ Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(RuntimeInterface::Intrinsi BASIC_BLOCK(2, -1) { INST(2, Opcode::SaveState).Inputs().SrcVregs({}); - INST(3, Opcode::Intrinsic).any().IntrinsicId(id).Inlined().Inputs({{DataType::NO_TYPE, 2}}); + INST(3, Opcode::Intrinsic).any().IntrinsicId(id).Inputs({{DataType::NO_TYPE, 2}}); INST(4, Opcode::Return).any().Inputs(3); } } @@ -122,11 +122,7 @@ Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type, RuntimeI { INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}); INST(4, Opcode::AnyTypeCheck).any().AnyType(type).AllowedInputType(allowed_type).Inputs(0, 2); - INST(5, Opcode::Intrinsic) - .any() - .IntrinsicId(id) - .Inlined() - .Inputs({{DataType::ANY, 4}, {DataType::NO_TYPE, 2}}); + INST(5, Opcode::Intrinsic).any().IntrinsicId(id).Inputs({{DataType::ANY, 4}, {DataType::NO_TYPE, 2}}); INST(6, Opcode::Return).any().Inputs(5); } } @@ -196,7 +192,6 @@ Graph *TypeResolvingTest::ConstructGraphWithIntrinsic(AnyBaseType type1, AnyBase INST(5, Opcode::Intrinsic) .any() .IntrinsicId(id) - .Inlined() .Inputs({{DataType::ANY, 3}, {DataType::ANY, 4}, {DataType::NO_TYPE, 2}}); INST(6, Opcode::Return).any().Inputs(5); } @@ -242,7 +237,7 @@ TEST_F(TypeResolvingTest, ToNumber) { auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_INT_TYPE, RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER); - ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); graph->RunPass(); GraphChecker(graph).Check(); @@ -268,7 +263,7 @@ TEST_F(TypeResolvingTest, ToNumber) auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_INT_TYPE, RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER, profiling::AnyInputType::SPECIAL); - ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); graph->RunPass(); GraphChecker(graph).Check(); @@ -299,7 +294,7 @@ TEST_F(TypeResolvingTest, ToNumber) for (auto allowed_type : {profiling::AnyInputType::DEFAULT, profiling::AnyInputType::INTEGER}) { auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER, allowed_type); - ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); graph->RunPass(); GraphChecker(graph).Check(); @@ -325,7 +320,7 @@ TEST_F(TypeResolvingTest, ToNumber) auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER, profiling::AnyInputType::SPECIAL); - ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); graph->RunPass(); GraphChecker(graph).Check(); @@ -357,7 +352,7 @@ TEST_F(TypeResolvingTest, ToNumber) auto graph = ConstructGraphWithIntrinsic(AnyBaseType::ECMASCRIPT_OBJECT_TYPE, RuntimeInterface::IntrinsicId::INTRINSIC_TONUMBER); auto clone = GraphCloner(graph, graph->GetAllocator(), graph->GetLocalAllocator()).CloneGraph(); - ASSERT_FALSE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); ASSERT_FALSE(graph->RunPass()); GraphChecker(graph).Check(); @@ -421,12 +416,11 @@ TEST_F(TypeResolvingTest, ResolveLoopPhi) INST(18, Opcode::SaveState).NoVregs(); INST(19, Opcode::Intrinsic) .any() - .Inlined() .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_INC_DYN) .Inputs({{DataType::ANY, 4}, {DataType::NO_TYPE, 18}}); } } - ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); ASSERT_TRUE(graph->RunPass()); ASSERT_TRUE(graph->RunPass(false)); GraphChecker(graph).Check(); @@ -435,6 +429,450 @@ TEST_F(TypeResolvingTest, ResolveLoopPhi) ASSERT_EQ(phi.GetType(), DataType::INT32); ASSERT_EQ(phi.GetInput(1U).GetInst(), &phi); } + +TEST_F(TypeResolvingTest, LdLexVarDynApply) +{ + constexpr uint32_t SLOT = 10U; + + for (size_t level = 0U; level <= InlineIntrinsics::GetLdStLexVarDynLevelThreshold(); ++level) { + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) + .any() + .Inputs({{DataType::ANY, 1}}) + .AddImm(level) + .AddImm(SLOT); + INST(3, Opcode::Return).any().Inputs(2); + } + } + + ASSERT_TRUE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(11, 0).any(); + CONSTANT(0, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); + CONSTANT(1, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(11); + INST(3, Opcode::CastAnyTypeValue) + .ref() + .Inputs(2) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + int last_index = 3; + for (auto cur_level = level; cur_level > 0U; --cur_level) { + INST(last_index + 1, Opcode::LoadArray).any().Inputs(last_index, 0); + INST(last_index + 2, Opcode::CastAnyTypeValue) + .ref() + .Inputs(last_index + 1) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + last_index += 2; + } + INST(last_index + 1, Opcode::LoadArray).any().Inputs(last_index, 1); + INST(last_index + 2, Opcode::Return).any().Inputs(last_index + 1); + } + } + + graph_opt->RunPass(); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + } +} + +TEST_F(TypeResolvingTest, LdLexVarDynSkip) +{ + constexpr uint32_t LEVEL = InlineIntrinsics::GetLdStLexVarDynLevelThreshold() + 1U; + constexpr uint32_t SLOT = 10U; + + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) + .any() + .Inputs({{DataType::ANY, 1}}) + .AddImm(LEVEL) + .AddImm(SLOT); + INST(3, Opcode::Return).any().Inputs(2); + } + } + + ASSERT_FALSE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) + .any() + .Inputs({{DataType::ANY, 1}}) + .AddImm(LEVEL) + .AddImm(SLOT); + INST(3, Opcode::Return).any().Inputs(2); + } + } + + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} + +TEST_F(TypeResolvingTest, LdLexDyn) +{ + constexpr uint32_t STRING_ID = 0xABCDU; + constexpr uint32_t LEVEL = InlineIntrinsics::GetLdStLexVarDynLevelThreshold() + 1U; + constexpr uint32_t SLOT = 10U; + + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadConstantPool).any().Inputs(0); + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::SaveState).NoVregs(); + INST(4, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_DYN) + .any() + .Inputs({{DataType::ANY, 1}, {DataType::ANY, 2}, {DataType::NO_TYPE, 3}}) + .AddImm(STRING_ID) + .AddImm(LEVEL) + .AddImm(SLOT); + INST(5, Opcode::Return).any().Inputs(4); + } + } + + ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(1, DataType::Any(panda::coretypes::TaggedValue::VALUE_HOLE)); + BASIC_BLOCK(2, -1) + { + INST(3, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(4, Opcode::SaveState).NoVregs(); + // We do not check LdLexVarDyn expansion in this test! + INST(5, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LD_LEX_VAR_DYN) + .any() + .Inputs({{DataType::ANY, 3}}) + .AddImm(LEVEL) + .AddImm(SLOT) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(6, Opcode::Compare).b().Inputs(5, 1).SrcType(DataType::ANY).CC(ConditionCode::CC_EQ); + INST(7, Opcode::DeoptimizeIf).Inputs(6, 4).DeoptimizeType(DeoptimizeType::HOLE); + INST(8, Opcode::Return).any().Inputs(5); + } + } + + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} + +TEST_F(TypeResolvingTest, InlineLdlexenvDyn) +{ + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(4, Opcode::SaveState).NoVregs(); + INST(1, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN) + .any() + .Inputs({{DataType::ANY, 0}}) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(2, Opcode::Return).any().Inputs(1); + } + } + ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::Return).any().Inputs(1); + } + } + GraphChecker(graph_opt).Check(); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} + +TEST_F(TypeResolvingTest, StLexVarDyn) +{ + constexpr uint32_t SLOT = 10U; + + size_t level = 0U; + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) + .any() + .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) + .AddImm(level) + .AddImm(SLOT) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + ASSERT_TRUE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); + GraphChecker(graph).Check(); + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + CONSTANT(7, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::CastAnyTypeValue) + .ref() + .Inputs(2) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(5, Opcode::StoreArray).any().Inputs(3).Inputs(7).Inputs(1).SetNeedBarrier(true); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + graph_opt->RunPass(); + GraphChecker(graph_opt).Check(); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + + level = 1U; + graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) + .any() + .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) + .AddImm(level) + .AddImm(SLOT) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + ASSERT_TRUE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); + GraphChecker(graph).Check(); + + graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + CONSTANT(7, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); + CONSTANT(10, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(5, Opcode::CastAnyTypeValue) + .ref() + .Inputs(2) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(6, Opcode::LoadArray).any().Inputs(5, 7); + INST(8, Opcode::CastAnyTypeValue) + .ref() + .Inputs(6) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(9, Opcode::StoreArray).any().Inputs(8).Inputs(10).Inputs(1).SetNeedBarrier(true); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + graph_opt->RunPass(); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + + level = 2U; + graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) + .any() + .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) + .AddImm(level) + .AddImm(SLOT) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + ASSERT_TRUE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); + GraphChecker(graph).Check(); + + graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + CONSTANT(7, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); + CONSTANT(12, graph_opt->GetRuntime()->GetLexicalEnvStartDataIndex() + SLOT); + + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(5, Opcode::CastAnyTypeValue) + .ref() + .Inputs(2) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(6, Opcode::LoadArray).any().Inputs(5, 7); + INST(8, Opcode::CastAnyTypeValue) + .ref() + .Inputs(6) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(9, Opcode::LoadArray).any().Inputs(8, 7); + INST(10, Opcode::CastAnyTypeValue) + .ref() + .Inputs(9) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(11, Opcode::StoreArray).any().Inputs(10).Inputs(12).Inputs(1).SetNeedBarrier(true); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + graph_opt->RunPass(); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); + + level = 3U; + graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) + .any() + .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) + .AddImm(level) + .AddImm(SLOT) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + ASSERT_FALSE(graph->RunPass()); + ASSERT_FALSE(graph->RunPass()); + GraphChecker(graph).Check(); + + graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(1, 1); + BASIC_BLOCK(2, -1) + { + INST(2, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_ST_LEX_VAR_DYN) + .any() + .Inputs({{DataType::INT32, 1}, {DataType::ANY, 2}}) + .AddImm(level) + .AddImm(SLOT) + .ClearFlag(inst_flags::REQUIRE_STATE); + INST(4, Opcode::ReturnVoid).v0id(); + } + } + graph_opt->RunPass(); + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} + +TEST_F(TypeResolvingTest, PopLexenvDyn) +{ + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::SaveState).NoVregs(); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_POP_LEXENV_DYN) + .any() + .Inputs({{DataType::ANY, 1}, {DataType::NO_TYPE, 2}}); + INST(4, Opcode::Return).any().Inputs(3); + } + } + + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(5, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::SaveState).NoVregs(); + INST(4, Opcode::CastAnyTypeValue) + .ref() + .Inputs(1) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(6, Opcode::LoadArray).any().Inputs(4, 5); + INST(3, Opcode::Return).any().Inputs(6); + } + } + + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} // NOLINTEND(readability-magic-numbers) } // namespace panda::compiler