diff --git a/compiler/optimizer/analysis/alias_analysis.cpp b/compiler/optimizer/analysis/alias_analysis.cpp index 096002234f7eef0c3d6ca9a64d7f49fd3c3a0ef5..754fa468092f05f8298957cbaf58b71ede159e7e 100644 --- a/compiler/optimizer/analysis/alias_analysis.cpp +++ b/compiler/optimizer/analysis/alias_analysis.cpp @@ -13,11 +13,13 @@ * limitations under the License. */ +#include #include "optimizer/ir/analysis.h" #include "optimizer/ir/basicblock.h" #include "optimizer/ir/graph.h" #include "optimizer/analysis/alias_analysis.h" #include "compiler_logger.h" +#include "optimizer/ir/inst.h" /** * See "Efficient Field-sensitive pointer analysis for C" by "David J. Pearce @@ -586,7 +588,8 @@ bool AliasAnalysis::ParseInstruction(Inst *inst, Pointer *pointer) if (base->GetOpcode() == Opcode::LoadArrayPair || base->GetOpcode() == Opcode::LoadArrayPairI || base->GetOpcode() == Opcode::LoadPairPart || base->GetOpcode() == Opcode::CatchPhi || base->GetOpcode() == Opcode::Load || base->GetOpcode() == Opcode::LoadI || - base->GetOpcode() == Opcode::Store || base->GetOpcode() == Opcode::StoreI) { + base->GetOpcode() == Opcode::Store || base->GetOpcode() == Opcode::StoreI || + base->GetOpcode() == Opcode::LoadObjectPair || base->GetOpcode() == Opcode::StoreObjectPair) { return false; } } @@ -1108,6 +1111,84 @@ void AliasAnalysis::VisitStoreArrayPair(GraphVisitor *v, Inst *inst) visitor->AddCopyEdge(val_snd, el_snd); } +void AliasAnalysis::VisitLoadObjectPair(GraphVisitor *v, Inst *inst) +{ + if (!inst->IsReferenceOrAny()) { + return; + } + auto visitor = static_cast(v); + auto typed_inst = inst->CastToLoadObjectPair(); + uint32_t type_id = typed_inst->GetTypeId(); + if (typed_inst->GetObjectType() == ObjectType::MEM_STATIC) { + Pointer sfield0 = Pointer::CreateStaticField(type_id, typed_inst->GetObjField0()); + Pointer sfield1 = Pointer::CreateStaticField(type_id, typed_inst->GetObjField1()); + + sfield0.SetVolatile(typed_inst->GetVolatile()); + sfield1.SetVolatile(typed_inst->GetVolatile()); + + visitor->AddDirectEdge(sfield0); + visitor->AddCopyEdge(sfield0, Pointer::CreateObject(inst)); + visitor->AddDirectEdge(sfield1); + visitor->AddCopyEdge(sfield1, Pointer::CreateObject(inst)); + } else { + Inst *dfobj0 = inst->GetDataFlowInput(1); + Pointer obj0 = Pointer::CreateObject(dfobj0); + Pointer ifield0 = Pointer::CreateObjectField(dfobj0, type_id, typed_inst->GetObjField0()); + Inst *dfobj1 = inst->GetDataFlowInput(2); + Pointer obj1 = Pointer::CreateObject(dfobj1); + Pointer ifield1 = Pointer::CreateObjectField(dfobj1, type_id, typed_inst->GetObjField1()); + + Pointer to = Pointer::CreateObject(inst); + + ifield0.SetVolatile(typed_inst->GetVolatile()); + ifield1.SetVolatile(typed_inst->GetVolatile()); + + visitor->AddCopyEdge(obj0, ifield0); + visitor->AddCopyEdge(ifield0, to); + visitor->AddCopyEdge(obj1, ifield1); + visitor->AddCopyEdge(ifield1, to); + } +} + +void AliasAnalysis::VisitStoreObjectPair(GraphVisitor *v, Inst *inst) +{ + if (!inst->IsReferenceOrAny()) { + return; + } + auto visitor = static_cast(v); + auto typed_inst = inst->CastToStoreObjectPair(); + uint32_t type_id = typed_inst->GetTypeId(); + if (typed_inst->GetObjectType() == ObjectType::MEM_STATIC) { + Pointer sfield0 = Pointer::CreateStaticField(typed_id, typed_inst->GetObjField0()); + Pointer sfield1 = Pointer::CreateStaticField(typed_id, typed_inst->GetObjField1()); + + sfield0.SetVolatile(typed_inst->GetVolatile()); + sfield1.SetVolatile(typed_inst->GetVolatile()); + + visitor->AddDirectEdge(sfield0); + visitor->AddDirectEdge(sfield1); + visitor->AddCopyEdge(Pointer::CreateObject(inst->GetDataFlowInput(1)), sfield0); + visitor->AddCopyEdge(Pointer::CreateObject(inst->GetDataFlowInput(2)), sfield1); + } else { + Inst *dfobj0 = inst->GetDataFlowInput(1); + Pointer obj0 = Pointer::CreateObject(dfobj0); + Pointer ifield0 = Pointer::CreateObjectField(dfobj0, type_id, typed_inst->GetObjField0()); + Pointer val0 = Pointer::CreateObject(inst->GetDataFlowInput(1)); + Inst *dfobj1 = inst->GetDataFlowInput(2); + Pointer obj1 = Pointer::CreateObject(dfobj1); + Pointer ifield1 = Pointer::CreateObjectField(dfobj1, type_id, typed_inst->GetObjField1()); + Pointer val1 = Pointer::CreateObject(inst->GetDataFlowInput(2)); + + ifield0.SetVolatile(typed_inst->GetVolatile()); + ifield1.SetVolatile(typed_inst->GetVolatile()); + + visitor->AddCopyEdge(obj0, ifield0); + visitor->AddCopyEdge(val0, ifield0); + visitor->AddCopyEdge(obj1, ifield1); + visitor->AddCopyEdge(val1, ifield1); + } +} + void AliasAnalysis::VisitLoadArrayPairI(GraphVisitor *v, Inst *inst) { if (!inst->IsReferenceOrAny()) { diff --git a/compiler/optimizer/analysis/alias_analysis.h b/compiler/optimizer/analysis/alias_analysis.h index d2a1c2945a5d54cec38687dba9037df3fd91771a..9905291a1f5e7a1a84d5f7c7104ae3b76dc7f0e2 100644 --- a/compiler/optimizer/analysis/alias_analysis.h +++ b/compiler/optimizer/analysis/alias_analysis.h @@ -364,6 +364,8 @@ public: static void VisitGetAnyTypeName(GraphVisitor *v, Inst *inst); static void VisitLoadConstantPool(GraphVisitor *v, Inst *inst); static void VisitLoadLexicalEnv(GraphVisitor *v, Inst *inst); + static void VisitLoadObjectPair(GraphVisitor *v, Inst *inst); + static void VisitStoreObjectPair(GraphVisitor *v, Inst *inst); /// Dynamic instructions static void VisitLoadObjectDynamic(GraphVisitor *v, Inst *inst); diff --git a/compiler/optimizer/code_generator/codegen.cpp b/compiler/optimizer/code_generator/codegen.cpp index 2816515b3c1c622f0c1ce97693e6471d916eb606..c6a9c8628d93711bf15191eeb4c483c0013a1ee3 100644 --- a/compiler/optimizer/code_generator/codegen.cpp +++ b/compiler/optimizer/code_generator/codegen.cpp @@ -3287,36 +3287,6 @@ void EncodeVisitor::VisitLoadString(GraphVisitor *visitor, Inst *inst) } } -static size_t GetObjectOffset(Graph *graph, ObjectType obj_type, RuntimeInterface::FieldPtr field, uint32_t type_id) -{ - switch (obj_type) { - case ObjectType::MEM_DYN_GLOBAL: - return graph->GetRuntime()->GetPropertyBoxOffset(graph->GetArch()); - case ObjectType::MEM_DYN_ELEMENTS: - return graph->GetRuntime()->GetElementsOffset(graph->GetArch()); - case ObjectType::MEM_DYN_PROPS: - return graph->GetRuntime()->GetPropertiesOffset(graph->GetArch()); - case ObjectType::MEM_DYN_PROTO_HOLDER: - return graph->GetRuntime()->GetPrototypeHolderOffset(graph->GetArch()); - case ObjectType::MEM_DYN_PROTO_CELL: - return graph->GetRuntime()->GetPrototypeCellOffset(graph->GetArch()); - case ObjectType::MEM_DYN_CHANGE_FIELD: - return graph->GetRuntime()->GetIsChangeFieldOffset(graph->GetArch()); - case ObjectType::MEM_DYN_ARRAY_LENGTH: - return graph->GetRuntime()->GetDynArrayLenthOffset(graph->GetArch()); - case ObjectType::MEM_DYN_INLINED: - return type_id; - case ObjectType::MEM_DYN_CLASS: - return graph->GetRuntime()->GetObjClassOffset(graph->GetArch()); - case ObjectType::MEM_DYN_METHOD: - return graph->GetRuntime()->GetFunctionTargetOffset(graph->GetArch()); - case ObjectType::MEM_DYN_HCLASS: - return graph->GetRuntime()->GetHClassOffset(graph->GetArch()); - default: - return graph->GetRuntime()->GetFieldOffset(field); - } -} - void EncodeVisitor::VisitLoadObject(GraphVisitor *visitor, Inst *inst) { auto *enc = static_cast(visitor); @@ -5091,6 +5061,28 @@ void EncodeVisitor::VisitLoadArrayPair(GraphVisitor *visitor, Inst *inst) enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prev_offset); } +void EncodeVisitor::VisitLoadObjectPair(GraphVisitor *visitor, Inst *inst) +{ + auto *enc = static_cast(visitor); + auto load_obj = inst->CastToLoadObjectPair(); + if (load_obj->GetNeedBarrier()) { + // Consider inserting barriers for GC + } + auto type = inst->GetType(); + auto type_input = inst->GetInput(0).GetInst()->GetType(); + auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type_input); // obj + auto dst0 = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(0), type); + auto dst1 = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(1), type); + + auto graph = enc->cg_->GetGraph(); + auto field0 = load_obj->GetObjField0(); + size_t offset0 = GetObjectOffset(graph, load_obj->GetObjectType(), field0, load_obj->GetTypeId()); + auto mem = MemRef(src, offset0); + auto prev_offset = enc->GetEncoder()->GetCursorOffset(); + enc->GetEncoder()->EncodeLdp(dst0, dst1, IsTypeSigned(type), mem); + enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prev_offset); +} + void EncodeVisitor::VisitLoadArrayPairI(GraphVisitor *visitor, Inst *inst) { auto *enc = static_cast(visitor); @@ -5149,6 +5141,48 @@ void EncodeVisitor::VisitStoreArrayPair(GraphVisitor *visitor, Inst *inst) } } +void EncodeVisitor::VisitStoreObjectPair(GraphVisitor *visitor, Inst *inst) +{ + auto *enc = static_cast(visitor); + auto encoder = enc->GetEncoder(); + auto store_obj = inst->CastToStoreObjectPair(); + auto codegen = enc->GetCodegen(); + auto type = inst->GetType(); + auto src0 = codegen->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE); // obj + auto src1 = codegen->ConvertRegister(inst->GetSrcReg(1), type); // store value 1 + auto src2 = codegen->ConvertRegister(inst->GetSrcReg(2), type); // store value 2 + + auto graph = enc->cg_->GetGraph(); + auto field0 = store_obj->GetObjField0(); + auto field1 = store_obj->GetObjField1(); + size_t offset0 = GetObjectOffset(graph, store_obj->GetObjectType(), field0, store_obj->GetTypeId()); + size_t offset1 = GetObjectOffset(graph, store_obj->GetObjectType(), field1, store_obj->GetTypeId()); + if (!(codegen->OffsetFitReferenceTypeSize(offset0) && codegen->OffsetFitReferenceTypeSize(offset1))) { + // such code should not be executed + encoder->EncodeAbort(); + } + auto mem = MemRef(src0, offset0); + if (store_obj->GetNeedBarrier()) { + if (store_obj->GetObjectType() == ObjectType::MEM_DYN_CLASS) { + codegen->CreatePreWRB(inst, mem, MakeMask(src0.GetId(), src1.GetId())); + } else { + codegen->CreatePreWRB(inst, mem, MakeMask(src0.GetId(), src1.GetId())); + } + } + auto prev_offset = encoder->GetCursorOffset(); + encoder->EncodeStp(src1, src2, mem); + codegen->TryInsertImplicitNullCheck(inst, prev_offset); + if (store_obj->GetNeedBarrier()) { + ScopedTmpRegLazy tmp(encoder); + if (store_obj->GetObjectType() == ObjectType::MEM_DYN_CLASS) { + tmp.AcquireIfInvalid(); + encoder->EncodeLdr(tmp, false, MemRef(src1, graph->GetRuntime()->GetManagedClassOffset(graph->GetArch()))); + src1 = tmp; + } + codegen->CreatePostWRB(inst, mem, src0, src1); + } +} + void EncodeVisitor::VisitStoreArrayPairI(GraphVisitor *visitor, Inst *inst) { auto *enc = static_cast(visitor); diff --git a/compiler/optimizer/code_generator/codegen.h b/compiler/optimizer/code_generator/codegen.h index 060d64e00d2fff0ef016fda530e3ee24b2727f8d..141f20d962d13a851ce3c694294aff75dc0293d3 100644 --- a/compiler/optimizer/code_generator/codegen.h +++ b/compiler/optimizer/code_generator/codegen.h @@ -1055,10 +1055,14 @@ protected: static void VisitLoadPairPart(GraphVisitor *visitor, Inst *inst); + static void VisitLoadObjectPair(GraphVisitor *visitor, Inst *inst); + static void VisitStoreArrayPair(GraphVisitor *visitor, Inst *inst); static void VisitStoreArrayPairI(GraphVisitor *visitor, Inst *inst); + static void VisitStoreObjectPair(GraphVisitor *visitor, Inst *inst); + static void VisitLoadExclusive(GraphVisitor *visitor, Inst *inst); static void VisitStoreExclusive(GraphVisitor *visitor, Inst *inst); diff --git a/compiler/optimizer/ir/analysis.cpp b/compiler/optimizer/ir/analysis.cpp index 9812293fa2dbb3c837ae214d8e0c8760af751d49..41bdf9047739c36c12b963fffab9667ddbc128ed 100644 --- a/compiler/optimizer/ir/analysis.cpp +++ b/compiler/optimizer/ir/analysis.cpp @@ -142,6 +142,12 @@ Inst *InstStoredValue(Inst *inst, Inst **second_value) *second_value = inst->GetDataFlowInput(second_inst); break; } + case Opcode::StoreObjectPair: { + val = inst->GetInput(1).GetInst(); + auto second_inst = inst->GetInput(2).GetInst(); + *second_value = inst->GetDataFlowInput(second_inst); + break; + } case Opcode::FillConstArray: { return nullptr; } @@ -189,6 +195,8 @@ bool IsSuitableForImplicitNullCheck(const Inst *inst) case Opcode::StoreArrayPair: case Opcode::LoadArrayPairI: case Opcode::StoreArrayPairI: + case Opcode::LoadObjectPair: + case Opcode::StoreObjectPair: // These instructions access nullptr and produce a signal in place // Note that CallVirtual is not in the list return true; diff --git a/compiler/optimizer/ir/dump.cpp b/compiler/optimizer/ir/dump.cpp index 6b9a001bd3cbb80f242b6c56b2111d4b138337ee..8675f0c1136e3002c2c372215680d4595b6f855a 100644 --- a/compiler/optimizer/ir/dump.cpp +++ b/compiler/optimizer/ir/dump.cpp @@ -594,6 +594,78 @@ void LoadObjectInst::DumpOpcode(std::ostream *out) const DumpTypedFieldOpcode(out, GetOpcode(), GetTypeId(), field_name, graph->GetLocalAllocator()); } +void LoadObjectPairInst::DumpOpcode(std::ostream *out) const +{ + auto graph = GetBasicBlock()->GetGraph(); + auto runtime = graph->GetRuntime(); + auto *allocator = graph->GetLocalAllocator(); + auto obj_type = GetObjectType(); + const auto &adapter = allocator->Adapter(); + ArenaString space(" ", adapter); + ArenaString dot(".", adapter); + auto field0 = GetObjField0(); + auto field1 = GetObjField1(); + + ArenaString cls_name("", adapter); + ArenaString field_name0("", adapter), field_name1("", adapter); + + if (obj_type != ObjectType::MEM_STATIC && obj_type != ObjectType::MEM_OBJECT) { + cls_name = ArenaString(" ", adapter); + field_name0 = dot + ArenaString(ObjectTypeToString(obj_type), adapter) + space; + field_name1 = dot + ArenaString(ObjectTypeToString(obj_type), adapter) + space; + } else if (!runtime->HasFieldMetadata(field0)) { + cls_name = ArenaString("Unknown ", adapter); + auto offset0 = runtime->GetFieldOffset(field0); + auto offset1 = runtime->GetFieldOffset(field1); + field_name0 = dot + ArenaString(".Unknown", adapter) + ArenaString(std::to_string(offset0), adapter) + space; + field_name1 = dot + ArenaString(".Unknown", adapter) + ArenaString(std::to_string(offset1), adapter) + space; + } else { + cls_name = ArenaString(runtime->GetClassName(runtime->GetClassForField(field0)), adapter) + space; + field_name0 = dot + ArenaString(runtime->GetFieldName(field0), adapter) + space; + field_name1 = dot + ArenaString(runtime->GetFieldName(field1), adapter) + space; + } + + ArenaString opc(GetOpcodeString(GetOpcode()), adapter); + ArenaString id(IdToString(GetTypeId(), allocator), adapter); + (*out) << std::setw(INDENT_OPCODE) << opc + space + id + space + cls_name + field_name0 + field_name1 << std::endl; +} + +void StoreObjectPairInst::DumpOpcode(std::ostream *out) const +{ + auto graph = GetBasicBlock()->GetGraph(); + auto runtime = graph->GetRuntime(); + auto *allocator = graph->GetLocalAllocator(); + auto obj_type = GetObjectType(); + const auto &adapter = allocator->Adapter(); + ArenaString space(" ", adapter); + ArenaString dot(".", adapter); + auto field0 = GetObjField0(); + auto field1 = GetObjField1(); + + ArenaString cls_name("", adapter); + ArenaString field_name0("", adapter), field_name1("", adapter); + + if (obj_type != ObjectType::MEM_STATIC && obj_type != ObjectType::MEM_OBJECT) { + cls_name = ArenaString(" ", adapter); + field_name0 = dot + ArenaString(ObjectTypeToString(obj_type), adapter) + space; + field_name1 = dot + ArenaString(ObjectTypeToString(obj_type), adapter) + space; + } else if (!runtime->HasFieldMetadata(field0)) { + cls_name = ArenaString("Unknown ", adapter); + auto offset0 = runtime->GetFieldOffset(field0); + auto offset1 = runtime->GetFieldOffset(field1); + field_name0 = dot + ArenaString(".Unknown", adapter) + ArenaString(std::to_string(offset0), adapter) + space; + field_name1 = dot + ArenaString(".Unknown", adapter) + ArenaString(std::to_string(offset1), adapter) + space; + } else { + cls_name = ArenaString(runtime->GetClassName(runtime->GetClassForField(field0)), adapter) + space; + field_name0 = dot + ArenaString(runtime->GetFieldName(field0), adapter) + space; + field_name1 = dot + ArenaString(runtime->GetFieldName(field1), adapter) + space; + } + + ArenaString opc(GetOpcodeString(GetOpcode()), adapter); + ArenaString id(IdToString(GetTypeId(), allocator), adapter); + (*out) << std::setw(INDENT_OPCODE) << opc + space + id + space + cls_name + field_name0 + field_name1 << std::endl; +} + void LoadMemInst::DumpOpcode(std::ostream *out) const { DumpTypedOpcode(out, GetOpcode(), GetType(), GetBasicBlock()->GetGraph()->GetLocalAllocator()); diff --git a/compiler/optimizer/ir/graph.cpp b/compiler/optimizer/ir/graph.cpp index c5ed3b973203243f9e95fcc24b3ccf10ae841e64..542f93077a66917ea6022e384a0a691b9db7ac29 100644 --- a/compiler/optimizer/ir/graph.cpp +++ b/compiler/optimizer/ir/graph.cpp @@ -843,4 +843,34 @@ void GraphMode::Dump(std::ostream &stm) DUMP_MODE(InterpreterEntry); } +size_t GetObjectOffset(Graph *graph, ObjectType obj_type, RuntimeInterface::FieldPtr field, uint32_t type_id) +{ + switch (obj_type) { + case ObjectType::MEM_DYN_GLOBAL: + return graph->GetRuntime()->GetPropertyBoxOffset(graph->GetArch()); + case ObjectType::MEM_DYN_ELEMENTS: + return graph->GetRuntime()->GetElementsOffset(graph->GetArch()); + case ObjectType::MEM_DYN_PROPS: + return graph->GetRuntime()->GetPropertiesOffset(graph->GetArch()); + case ObjectType::MEM_DYN_PROTO_HOLDER: + return graph->GetRuntime()->GetPrototypeHolderOffset(graph->GetArch()); + case ObjectType::MEM_DYN_PROTO_CELL: + return graph->GetRuntime()->GetPrototypeCellOffset(graph->GetArch()); + case ObjectType::MEM_DYN_CHANGE_FIELD: + return graph->GetRuntime()->GetIsChangeFieldOffset(graph->GetArch()); + case ObjectType::MEM_DYN_ARRAY_LENGTH: + return graph->GetRuntime()->GetDynArrayLenthOffset(graph->GetArch()); + case ObjectType::MEM_DYN_INLINED: + return type_id; + case ObjectType::MEM_DYN_CLASS: + return graph->GetRuntime()->GetObjClassOffset(graph->GetArch()); + case ObjectType::MEM_DYN_METHOD: + return graph->GetRuntime()->GetFunctionTargetOffset(graph->GetArch()); + case ObjectType::MEM_DYN_HCLASS: + return graph->GetRuntime()->GetHClassOffset(graph->GetArch()); + default: + return graph->GetRuntime()->GetFieldOffset(field); + } +} + } // namespace panda::compiler diff --git a/compiler/optimizer/ir/graph.h b/compiler/optimizer/ir/graph.h index 2ef14eaaefe3e7718f3b91c3ecfec07132ad96fb..8afef1745843c80768cd10e0bbe6f2252fd840e5 100644 --- a/compiler/optimizer/ir/graph.h +++ b/compiler/optimizer/ir/graph.h @@ -1359,5 +1359,7 @@ void InvalidateBlocksOrderAnalyzes(Graph *graph); void MarkLoopExits(const Graph *graph, Marker marker); void RemovePredecessorUpdateDF(BasicBlock *block, BasicBlock *rm_pred); std::string GetMethodFullName(const Graph *graph, RuntimeInterface::MethodPtr method); +size_t GetObjectOffset(Graph *graph, ObjectType obj_type, RuntimeInterface::FieldPtr field, uint32_t type_id); + } // namespace panda::compiler #endif // COMPILER_OPTIMIZER_IR_GRAPH_H_ diff --git a/compiler/optimizer/ir/graph_checker.cpp b/compiler/optimizer/ir/graph_checker.cpp index 95204fce7a15675bfba77dd905755013b002f5f8..5cfe8646bc8dedd04f652a88257d743bf50f8bf1 100644 --- a/compiler/optimizer/ir/graph_checker.cpp +++ b/compiler/optimizer/ir/graph_checker.cpp @@ -1319,6 +1319,12 @@ void GraphChecker::VisitLoadArrayPair([[maybe_unused]] GraphVisitor *v, Inst *in (std::cerr << "Unallowed type of coalesced load\n", inst->Dump(&std::cerr))); CheckMemoryInstruction(inst); } +void GraphChecker::VisitLoadObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst) +{ + ASSERT_DO_EXT_VISITOR(MemoryCoalescing::AcceptedType(inst->GetType()) || DataType::IsReference(inst->GetType()), + (std::cerr << "Unallowed type of coalesced load\n", inst->Dump(&std::cerr))); + CheckMemoryInstruction(inst); +} void GraphChecker::VisitLoadArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst) { ASSERT_DO_EXT_VISITOR(MemoryCoalescing::AcceptedType(inst->GetType()) || DataType::IsReference(inst->GetType()), @@ -1333,14 +1339,17 @@ void GraphChecker::VisitLoadPairPart([[maybe_unused]] GraphVisitor *v, Inst *ins CheckMemoryInstruction(inst); [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst(); [[maybe_unused]] auto idx = inst->CastToLoadPairPart()->GetImm(); - ASSERT_DO_EXT_VISITOR(op1->GetOpcode() == Opcode::LoadArrayPair || op1->GetOpcode() == Opcode::LoadArrayPairI, + ASSERT_DO_EXT_VISITOR(op1->GetOpcode() == Opcode::LoadArrayPair || op1->GetOpcode() == Opcode::LoadArrayPairI || + op1->GetOpcode() == Opcode::LoadObjectPair, (std::cerr << "Input instruction is not a Pair\n", inst->Dump(&std::cerr))); if (op1->GetOpcode() == Opcode::LoadArrayPairI) { ASSERT_DO_EXT_VISITOR(idx < op1->CastToLoadArrayPairI()->GetDstCount(), (std::cerr << "Pair index is out of bounds\n", inst->Dump(&std::cerr))); - } else { + } else if (op1->GetOpcode() == Opcode::LoadArrayPair) { ASSERT_DO_EXT_VISITOR(idx < op1->CastToLoadArrayPair()->GetDstCount(), (std::cerr << "Pair index is out of bounds\n", inst->Dump(&std::cerr))); + } else { + ASSERT(op1->GetOpcode() == Opcode::LoadObjectPair); } ASSERT_DO_EXT_VISITOR( CheckCommonTypes(inst, inst->GetInputs()[0].GetInst()), @@ -1377,6 +1386,21 @@ void GraphChecker::VisitStoreArrayPair([[maybe_unused]] GraphVisitor *v, Inst *i (std::cerr << "StoreArrayPair has incorrect value NeedBarrier", inst->Dump(&std::cerr))); } +void GraphChecker::VisitStoreObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst) +{ + bool need_barrier = inst->CastToStoreObjectPair()->GetNeedBarrier(); + CheckMemoryInstruction(inst, need_barrier); + ASSERT_DO_EXT_VISITOR( + CheckCommonTypes(inst, inst->GetInputs()[1].GetInst()), + (std::cerr << "Types of store and the first store input are not compatible\n", inst->Dump(&std::cerr))); + ASSERT_DO_EXT_VISITOR( + CheckCommonTypes(inst, inst->GetInputs()[2].GetInst()), + (std::cerr << "Types of store and the second store input are not compatible\n", inst->Dump(&std::cerr))); + ASSERT_DO_EXT_VISITOR(need_barrier == (inst->GetType() == DataType::REFERENCE) || inst->GetType() == DataType::ANY, + (std::cerr << "StoreObjectPair has incorrect value NeedBarrier", inst->Dump(&std::cerr))); + CheckObjectType(inst, inst->CastToStoreObjectPair()->GetObjectType(), inst->CastToStoreObjectPair()->GetTypeId()); +} + void GraphChecker::VisitStoreArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst) { bool need_barrier = inst->CastToStoreArrayPairI()->GetNeedBarrier(); diff --git a/compiler/optimizer/ir/graph_checker.h b/compiler/optimizer/ir/graph_checker.h index ff75858efbd97585b9381ed3d941df7c582d2089..8e3d68bda5624e9dabea802bd2d3cdb42efe04c9 100644 --- a/compiler/optimizer/ir/graph_checker.h +++ b/compiler/optimizer/ir/graph_checker.h @@ -172,11 +172,13 @@ private: static void VisitLoadArray([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitLoadArrayI([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitLoadArrayPair([[maybe_unused]] GraphVisitor *v, Inst *inst); + static void VisitLoadObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitLoadArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitLoadPairPart([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitStore([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitStoreI([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitStoreArrayPair([[maybe_unused]] GraphVisitor *v, Inst *inst); + static void VisitStoreObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitStoreArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitStoreArray([[maybe_unused]] GraphVisitor *v, Inst *inst); static void VisitStoreArrayI([[maybe_unused]] GraphVisitor *v, Inst *inst); diff --git a/compiler/optimizer/ir/inst.cpp b/compiler/optimizer/ir/inst.cpp index 3482810de943cb819caa52e80226be79cf3190a7..b2d7377bf511aa39a74b2a6e2952c45b86420818 100644 --- a/compiler/optimizer/ir/inst.cpp +++ b/compiler/optimizer/ir/inst.cpp @@ -317,8 +317,8 @@ Inst *SkipInstructions(Inst *input_inst) } /* * For instructions LoadArray, StoreArray, LoadArrayPair, StoreArrayPair, LoadArrayI, StoreArrayI, LoadArrayPairI, - * StoreArrayPairI, LenArray, LoadObject, StoreObject, CallVirtual, Monitor with NullCheck input the dataflow user - * is object, which is the first input of NullCheck instruction. + * StoreArrayPairI, LenArray, LoadObject, StoreObject, CallVirtual, Monitor, LoadObjectPair, StoreObjectPair with + * NullCheck input the dataflow user is object, which is the first input of NullCheck instruction. * For instructions LoadArray, StoreArray, LoadArrayPair, StoreArrayPair with BoundsCheck input the dataflow user is * array index, which is the second input of BoundsCheck instruction * For instructions Div and Mod with ZeroCheck input the dataflow user is the first input of ZeroCheck diff --git a/compiler/optimizer/ir/inst.h b/compiler/optimizer/ir/inst.h index d8df2419baf195b97fd329fa13c5fc337daaa8ef..d647044fdb121abba491041ea0e818cc9b895c6a 100644 --- a/compiler/optimizer/ir/inst.h +++ b/compiler/optimizer/ir/inst.h @@ -2140,6 +2140,41 @@ private: RuntimeInterface::FieldPtr field_ {nullptr}; }; +/// This mixin aims to implement 2 field accessors. +class FieldMixin2 { +public: + explicit FieldMixin2(RuntimeInterface::FieldPtr field0, RuntimeInterface::FieldPtr field1) + : field0_(field0), field1_(field1) + { + } + + FieldMixin2() = default; + NO_COPY_SEMANTIC(FieldMixin2); + NO_MOVE_SEMANTIC(FieldMixin2); + virtual ~FieldMixin2() = default; + + void SetObjField0(RuntimeInterface::FieldPtr field) + { + field0_ = field; + } + auto GetObjField0() const + { + return field0_; + } + void SetObjField1(RuntimeInterface::FieldPtr field) + { + field1_ = field; + } + auto GetObjField1() const + { + return field1_; + } + +private: + RuntimeInterface::FieldPtr field0_ {nullptr}; + RuntimeInterface::FieldPtr field1_ {nullptr}; +}; + /// This mixin aims to implement volatile accessors. template class VolatileMixin : public T { @@ -6723,6 +6758,61 @@ public: } }; +/// Load a pair of consecutive values from object +// NOLINTNEXTLINE(fuchsia-multiple-inheritance) +class LoadObjectPairInst + : public ObjectTypeMixin>>>, + public TypeIdMixin, + public FieldMixin2 { +public: + DECLARE_INST(LoadObjectPairInst); + using Base = ObjectTypeMixin>>>; + using Base::Base; + + LoadObjectPairInst(Opcode opcode, DataType::Type type, uint32_t pc, Inst *input, bool is_volatile = false, + bool need_barrier = false) + : Base(opcode, type, pc) + { + SetField(INPUT_COUNT); + SetInput(0, input); + SetVolatile(is_volatile); + SetNeedBarrier(need_barrier); + } + + DataType::Type GetInputType([[maybe_unused]] size_t index) const override + { + ASSERT(index < GetInputsCount()); + ASSERT(GetInputsCount() == 1); + auto input_type = GetInput(0).GetInst()->GetType(); + ASSERT(input_type == DataType::NO_TYPE || input_type == DataType::REFERENCE || input_type == DataType::ANY); + return input_type; + } + + bool IsBarrier() const override + { + return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile(); + } + + Inst *Clone(const Graph *target_graph) const override + { + auto clone = FixedInputsInst::Clone(target_graph); + clone->CastToLoadObjectPair()->SetTypeId(GetTypeId()); + clone->CastToLoadObjectPair()->SetMethod(GetMethod()); + clone->CastToLoadObjectPair()->SetObjField0(GetObjField0()); + clone->CastToLoadObjectPair()->SetObjField1(GetObjField1()); + ASSERT(clone->CastToLoadObjectPair()->GetVolatile() == GetVolatile()); + ASSERT(clone->CastToLoadObjectPair()->GetObjectType() == GetObjectType()); + return clone; + } + + uint32_t Latency() const override + { + return OPTIONS.GetCompilerSchedLatencyLong(); + } + + void DumpOpcode(std::ostream *out) const override; +}; + /// Store a pair of consecutive values to array // NOLINTNEXTLINE(fuchsia-multiple-inheritance) class StoreArrayPairInst : public NeedBarrierMixin> { @@ -6783,6 +6873,63 @@ public: } }; +/// Store a pair of consecutive values to object +// NOLINTNEXTLINE(fuchsia-multiple-inheritance) +class StoreObjectPairInst : public ObjectTypeMixin>>, + public TypeIdMixin, + public FieldMixin2 { +public: + DECLARE_INST(StoreObjectPairInst); + using Base = ObjectTypeMixin>>; + using Base::Base; + static constexpr size_t STORED_INPUT_INDEX = 2; + + StoreObjectPairInst(Opcode opcode, DataType::Type type, uint32_t pc, Inst *input0, Inst *input1, Inst *input2, + uint32_t type_id, RuntimeInterface::MethodPtr method, bool is_volatile = false, + bool need_barrier = false) + : Base(opcode, type, pc), TypeIdMixin(type_id, method) + { + SetField(INPUT_COUNT); + SetInput(0, input0); + SetInput(1, input1); + SetInput(2, input2); + SetVolatile(is_volatile); + SetNeedBarrier(need_barrier); + } + + bool IsBarrier() const override + { + return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile(); + } + + DataType::Type GetInputType(size_t index) const override + { + ASSERT(index < GetInputsCount()); + ASSERT(GetInputsCount() == 3U); + return index == 0 ? DataType::REFERENCE : GetType(); + } + + Inst *Clone(const Graph *target_graph) const override + { + auto clone = FixedInputsInst::Clone(target_graph); + clone->CastToStoreObjectPair()->SetTypeId(GetTypeId()); + clone->CastToStoreObjectPair()->SetMethod(GetMethod()); + clone->CastToStoreObjectPair()->SetObjField0(GetObjField0()); + clone->CastToStoreObjectPair()->SetObjField1(GetObjField1()); + ASSERT(clone->CastToStoreObjectPair()->GetVolatile() == GetVolatile()); + ASSERT(clone->CastToStoreObjectPair()->GetObjectType() == GetObjectType()); + return clone; + } + + // StoreObject call barriers twice,so we need to save input register for second call + bool IsPropagateLiveness() const override + { + return GetType() == DataType::REFERENCE; + } + + void DumpOpcode(std::ostream *out) const override; +}; + /// Load a pair of consecutive values from array, using array index as immediate // NOLINTNEXTLINE(fuchsia-multiple-inheritance) class LoadArrayPairInstI : public NeedBarrierMixin>, public ImmediateMixin { @@ -7315,8 +7462,12 @@ inline bool IsVolatileMemInst(Inst *inst) switch (inst->GetOpcode()) { case Opcode::LoadObject: return inst->CastToLoadObject()->GetVolatile(); + case Opcode::LoadObjectPair: + return inst->CastToLoadObjectPair()->GetVolatile(); case Opcode::StoreObject: return inst->CastToStoreObject()->GetVolatile(); + case Opcode::StoreObjectPair: + return inst->CastToStoreObjectPair()->GetVolatile(); case Opcode::LoadStatic: return inst->CastToLoadStatic()->GetVolatile(); case Opcode::StoreStatic: diff --git a/compiler/optimizer/ir/instructions.yaml b/compiler/optimizer/ir/instructions.yaml index b676afcbb26ec6cb20279b193c46a76fd792b179..0cb99e34e33cc355df70c663b88d0da1221b33a2 100644 --- a/compiler/optimizer/ir/instructions.yaml +++ b/compiler/optimizer/ir/instructions.yaml @@ -1062,6 +1062,13 @@ instructions: modes: [jit_aot, irtoc] description: Load element from vector. + - opcode: LoadObjectPair + base: LoadObjectPairInst + signature: [d-real-any, ref-any-nc] + flags: [load, no_hoist, no_cse, low_level, acc_write] + modes: [jit_aot, irtoc] + description: Load several values at a time from object. + - opcode: StoreArrayPair base: StoreArrayPairInst signature: [ref-nc, int-bc, real-any, real-any] @@ -1076,6 +1083,13 @@ instructions: modes: [jit_aot, irtoc] description: Store several values at a time to array at immediate index. + - opcode: StoreObjectPair + base: StoreObjectPairInst + signature: [ref-nc, real-any, real-any] + flags: [store, no_dce, no_hoist, no_cse, low_level, acc_read, require_tmp] + modes: [jit_aot, irtoc] + description: Store several values at a time to object. + - opcode: ReturnI base: ReturnInstI signature: [] diff --git a/compiler/optimizer/optimizations/memory_barriers.cpp b/compiler/optimizer/optimizations/memory_barriers.cpp index 6cc01b7906be4ec3d2add41e6f629dad051007c9..3fd4c58e47a4ccad2e702667153294e73cf35f7f 100644 --- a/compiler/optimizer/optimizations/memory_barriers.cpp +++ b/compiler/optimizer/optimizations/memory_barriers.cpp @@ -157,6 +157,11 @@ void OptimizeMemoryBarriers::VisitStoreObject(GraphVisitor *v, Inst *inst) static_cast(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst()); } +void OptimizeMemoryBarriers::VisitStoreObjectPair(GraphVisitor *v, Inst *inst) +{ + static_cast(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst()); +} + void OptimizeMemoryBarriers::VisitStoreObjectDynamic(GraphVisitor *v, Inst *inst) { static_cast(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst()); diff --git a/compiler/optimizer/optimizations/memory_barriers.h b/compiler/optimizer/optimizations/memory_barriers.h index 3a7842aa5e5ec154986678bc9500350d7eded31c..71833879f681171d6ed89d547340d9fec7238d41 100644 --- a/compiler/optimizer/optimizations/memory_barriers.h +++ b/compiler/optimizer/optimizations/memory_barriers.h @@ -80,6 +80,7 @@ private: static void VisitStoreArray(GraphVisitor *v, Inst *inst); static void VisitStoreArrayI(GraphVisitor *v, Inst *inst); static void VisitStoreObject(GraphVisitor *v, Inst *inst); + static void VisitStoreObjectPair(GraphVisitor *v, Inst *inst); static void VisitStoreObjectDynamic(GraphVisitor *v, Inst *inst); static void VisitStoreStatic(GraphVisitor *v, Inst *inst); static void VisitStore(GraphVisitor *v, Inst *inst); diff --git a/compiler/optimizer/optimizations/memory_coalescing.cpp b/compiler/optimizer/optimizations/memory_coalescing.cpp index 2c3a9a34ca63c173dc9c6b49e5191d76caba0d08..3400234cb4fac772332c41b1fb6636bb656ec1a2 100644 --- a/compiler/optimizer/optimizations/memory_coalescing.cpp +++ b/compiler/optimizer/optimizations/memory_coalescing.cpp @@ -227,6 +227,16 @@ public: static_cast(v)->HandleArrayAccessI(inst); } + static void VisitLoadObject(GraphVisitor *v, Inst *inst) + { + static_cast(v)->HandleObjectAccess(inst); + } + + static void VisitStoreObject(GraphVisitor *v, Inst *inst) + { + static_cast(v)->HandleObjectAccess(inst); + } + static bool IsNotAcceptableForStore(Inst *inst) { if (inst->GetOpcode() == Opcode::SaveState) { @@ -302,6 +312,8 @@ private: case Opcode::LoadArrayPairI: case Opcode::StoreArrayPair: case Opcode::StoreArrayPairI: + case Opcode::LoadObjectPair: + case Opcode::StoreObjectPair: return true; default: return false; @@ -562,6 +574,51 @@ private: candidates_.push_back(inst); } + void HandleObjectAccess(Inst *inst) + { + if (!MemoryCoalescing::AcceptedType(inst->GetType())) { + candidates_.push_back(inst); + return; + } + + bool isload = inst->GetOpcode() == Opcode::LoadObject; + auto load_obj = isload ? inst->CastToLoadObject() : nullptr; + auto store_obj = isload ? nullptr : inst->CastToStoreObject(); + + Inst *obj = inst->GetDataFlowInput(inst->GetInput(0).GetInst()); + auto field = isload ? load_obj->GetObjField() : store_obj->GetObjField(); + auto field_size = GetTypeSize(inst->GetType(), graph_->GetArch()) >> 3; + size_t field_offset = GetObjectOffset(graph_, isload ? load_obj->GetObjectType() : store_obj->GetObjectType(), + field, isload ? load_obj->GetTypeId() : store_obj->GetTypeId()); + + /* Last candidates more likely to be coalesced */ + for (auto iter = candidates_.rbegin(); iter != candidates_.rend(); iter++) { + auto cand = *iter; + /* Skip not interesting candidates */ + Inst *cand_obj = cand->GetDataFlowInput(cand->GetInput(0).GetInst()); + if (cand->IsMarked(mrk_invalid_) || cand->GetOpcode() != inst->GetOpcode() || obj != cand_obj || + cand->GetType() != inst->GetType()) { + continue; + } + + auto cand_load_obj = isload ? cand->CastToLoadObject() : nullptr; + auto cand_store_obj = isload ? nullptr : cand->CastToStoreObject(); + auto cand_field = isload ? cand_load_obj->GetObjField() : cand_store_obj->GetObjField(); + auto cand_field_size = GetTypeSize(cand->GetType(), graph_->GetArch()) >> 3; + size_t cand_field_offset = + GetObjectOffset(graph_, isload ? cand_load_obj->GetObjectType() : cand_store_obj->GetObjectType(), + cand_field, isload ? cand_load_obj->GetTypeId() : cand_store_obj->GetTypeId()); + + if (field_offset + field_size == cand_field_offset && TryAddCoalescedPair(inst, 0, cand, 1)) { + break; + } else if (cand_field_offset + cand_field_size == field_offset && TryAddCoalescedPair(inst, 1, cand, 0)) { + break; + } + } + + candidates_.push_back(inst); + } + void InsertPair(Inst *first, Inst *second, Inst *insert_after) { COMPILER_LOG(DEBUG, MEMORY_COALESCING) @@ -582,12 +639,18 @@ private: case Opcode::StoreArrayI: paired = ReplaceStoreArrayI(first, second, insert_after); break; + case Opcode::LoadObject: + paired = ReplaceLoadObject(first, second, insert_after); + break; + case Opcode::StoreObject: + paired = ReplaceStoreObject(first, second, insert_after); + break; default: UNREACHABLE(); } - COMPILER_LOG(DEBUG, MEMORY_COALESCING) - << "Coalescing of {v" << first->GetId() << " v" << second->GetId() << "} is successful"; + COMPILER_LOG(DEBUG, MEMORY_COALESCING) << "Coalescing of {v" << first->GetId() << " v" << second->GetId() + << "} by " << paired->GetId() << " is successful"; graph_->GetEventWriter().EventMemoryCoalescing(first->GetId(), first->GetPc(), second->GetId(), second->GetPc(), paired->GetId(), paired->IsStore() ? "Store" : "Load"); @@ -616,6 +679,26 @@ private: return pload; } + Inst *ReplaceLoadObject(Inst *first, Inst *second, Inst *insert_after) + { + ASSERT(first->GetOpcode() == Opcode::LoadObject); + ASSERT(second->GetOpcode() == Opcode::LoadObject); + + auto pload = graph_->CreateInstLoadObjectPair(first->GetType(), INVALID_PC); + pload->SetInput(0, first->GetInput(0).GetInst()); + pload->SetType(first->GetType()); + pload->SetObjField0(first->CastToLoadObject()->GetObjField()); + pload->SetObjField1(second->CastToLoadObject()->GetObjField()); + pload->CastToLoadObjectPair()->SetNeedBarrier(first->CastToLoadObject()->GetNeedBarrier() || + second->CastToLoadObject()->GetNeedBarrier()); + if (first->CanThrow() || second->CanThrow()) { + pload->SetFlag(compiler::inst_flags::CAN_THROW); + } + insert_after->InsertAfter(pload); + + return pload; + } + Inst *ReplaceLoadArrayI(Inst *first, Inst *second, Inst *insert_after) { ASSERT(first->GetOpcode() == Opcode::LoadArrayI); @@ -651,6 +734,28 @@ private: return pstore; } + Inst *ReplaceStoreObject(Inst *first, Inst *second, Inst *insert_after) + { + ASSERT(first->GetOpcode() == Opcode::StoreObject); + ASSERT(second->GetOpcode() == Opcode::StoreObject); + + auto pstore = graph_->CreateInstStoreObjectPair(); + pstore->SetInput(0, first->GetInput(0).GetInst()); + pstore->SetType(first->GetType()); + pstore->SetInput(1, first->GetInput(1).GetInst()); + pstore->SetInput(2, second->GetInput(1).GetInst()); + pstore->SetObjField0(first->CastToStoreObject()->GetObjField()); + pstore->SetObjField1(second->CastToStoreObject()->GetObjField()); + pstore->CastToStoreObjectPair()->SetNeedBarrier(first->CastToStoreObject()->GetNeedBarrier() || + second->CastToStoreObject()->GetNeedBarrier()); + if (first->CanThrow() || second->CanThrow()) { + pstore->SetFlag(compiler::inst_flags::CAN_THROW); + } + insert_after->InsertAfter(pstore); + + return pstore; + } + Inst *ReplaceStoreArrayI(Inst *first, Inst *second, Inst *insert_after) { ASSERT(first->GetOpcode() == Opcode::StoreArrayI); @@ -716,6 +821,8 @@ bool MemoryCoalescing::RunImpl() return false; } + COMPILER_LOG(DEBUG, MEMORY_COALESCING) << "Memory Coalescing running"; + GetGraph()->RunPass(); GetGraph()->RunPass(); GetGraph()->RunPass(); diff --git a/compiler/optimizer/optimizations/memory_coalescing.h b/compiler/optimizer/optimizations/memory_coalescing.h index f1acd147080fb8450c63a2d82ce928585a84fca7..9da0e972a17c1a0acbd7cd381d546cea8eccec27 100644 --- a/compiler/optimizer/optimizations/memory_coalescing.h +++ b/compiler/optimizer/optimizations/memory_coalescing.h @@ -73,8 +73,10 @@ private: Inst *ReplaceLoadArray(Inst *first, Inst *second, Inst *insert_after); Inst *ReplaceLoadArrayI(Inst *first, Inst *second, Inst *insert_after); + Inst *ReplaceLoadObject(Inst *first, Inst *second, Inst *insert_after); Inst *ReplaceStoreArray(Inst *first, Inst *second, Inst *insert_after); Inst *ReplaceStoreArrayI(Inst *first, Inst *second, Inst *insert_after); + Inst *ReplaceStoreObject(Inst *first, Inst *second, Inst *insert_after); private: bool aligned_only_; diff --git a/compiler/optimizer/optimizations/scheduler.cpp b/compiler/optimizer/optimizations/scheduler.cpp index 6036a082d824958d34844832c9f3f1b19996a45d..08db0bc8e5085bd2a08b6013cf6f3890625b017c 100644 --- a/compiler/optimizer/optimizations/scheduler.cpp +++ b/compiler/optimizer/optimizations/scheduler.cpp @@ -407,7 +407,8 @@ uint32_t Scheduler::SchedWithGlued(Inst *inst, SchedulerPriorityQueue *waiting, now.push(inst); // Add glued instructions into 'now' - if (inst->GetOpcode() == Opcode::LoadArrayPair || inst->GetOpcode() == Opcode::LoadArrayPairI) { + if (inst->GetOpcode() == Opcode::LoadArrayPair || inst->GetOpcode() == Opcode::LoadArrayPairI || + inst->GetOpcode() == Opcode::LoadObjectPair) { for (auto &user_item : inst->GetUsers()) { auto user = user_item.GetInst(); ASSERT(user->GetOpcode() == Opcode::LoadPairPart); diff --git a/plugins/ets/compiler/tools/paoc_compile_stdlib.sh b/plugins/ets/compiler/tools/paoc_compile_stdlib.sh index b12ca42cd17646c1f70d1eb8be1b4af405a4f2fc..2834c43247c6cfa9543f5b4441e82d302bf5dedf 100755 --- a/plugins/ets/compiler/tools/paoc_compile_stdlib.sh +++ b/plugins/ets/compiler/tools/paoc_compile_stdlib.sh @@ -44,6 +44,11 @@ if [ -z "$PANDA_BINARY_ROOT" ]; then exit 1 fi +echo ${PANDA_BINARY_ROOT}/bin/ark_aot --boot-panda-files=${PANDA_BINARY_ROOT}/plugins/ets/etsstdlib.abc \ + --paoc-panda-files=${PANDA_BINARY_ROOT}/plugins/ets/etsstdlib.abc \ + --compiler-ignore-failures=false $PAOC_MODE --load-runtimes="ets" \ + $TARGET_ARCH ${OPTIONS} --paoc-output=${PAOC_OUTPUT} + ${PANDA_BINARY_ROOT}/bin/ark_aot --boot-panda-files=${PANDA_BINARY_ROOT}/plugins/ets/etsstdlib.abc \ --paoc-panda-files=${PANDA_BINARY_ROOT}/plugins/ets/etsstdlib.abc \ --compiler-ignore-failures=false $PAOC_MODE --load-runtimes="ets" \ diff --git a/plugins/ets/tests/checked/memory_coalescing1.ets b/plugins/ets/tests/checked/memory_coalescing1.ets new file mode 100644 index 0000000000000000000000000000000000000000..3923f7aeb306f097c85992bcf8f01d1d1ea2f399 --- /dev/null +++ b/plugins/ets/tests/checked/memory_coalescing1.ets @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 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. + */