From ca51365eb9ed4ecc5a1aea3d78fb6785965e4d7d Mon Sep 17 00:00:00 2001 From: suyue Date: Tue, 30 Jan 2024 04:13:47 +0000 Subject: [PATCH] [BiShengC]merge bishengc into litecg about local schedule Change-Id: Idb0dabd49d3db6cd08b88f47e960db88f2f200d3 Signed-off-by: suyuehhh --- .../compiler/codegen/maple/maple_be/BUILD.gn | 10 + .../maple_be/include/cg/aarch64/aarch64_cg.h | 7 + .../cg/aarch64/aarch64_data_dep_base.h | 62 + .../cg/aarch64/aarch64_global_schedule.h | 38 + .../cg/aarch64/aarch64_local_schedule.h | 33 + .../include/cg/aarch64/aarch64_phases.def | 2 +- .../maple/maple_be/include/cg/base_schedule.h | 72 + .../codegen/maple/maple_be/include/cg/cg.h | 13 + .../maple/maple_be/include/cg/cg_cdg.h | 864 ++++++++++++ .../maple/maple_be/include/cg/cg_dominance.h | 1 + .../maple/maple_be/include/cg/cg_option.h | 16 + .../codegen/maple/maple_be/include/cg/cgbb.h | 82 +- .../maple/maple_be/include/cg/cgfunc.h | 11 + .../include/cg/control_dep_analysis.h | 187 +++ .../maple_be/include/cg/data_dep_analysis.h | 64 + .../maple/maple_be/include/cg/data_dep_base.h | 137 ++ .../maple/maple_be/include/cg/dependence.h | 3 - .../codegen/maple/maple_be/include/cg/deps.h | 10 + .../maple_be/include/cg/global_schedule.h | 55 + .../maple_be/include/cg/list_scheduler.h | 273 ++++ .../maple_be/include/cg/local_schedule.h | 52 + .../codegen/maple/maple_be/include/cg/loop.h | 215 +++ .../include/cg/mplad_bypass_define.def | 45 +- .../maple_be/include/cg/schedule_heuristic.h | 277 ++++ .../codegen/maple/maple_be/src/ad/mad.cpp | 1 + .../src/cg/aarch64/aarch64_data_dep_base.cpp | 620 +++++++++ .../cg/aarch64/aarch64_global_schedule.cpp | 122 ++ .../src/cg/aarch64/aarch64_local_schedule.cpp | 65 + .../src/cg/aarch64/aarch64_schedule.cpp | 4 - .../maple/maple_be/src/cg/base_schedule.cpp | 228 ++++ .../maple/maple_be/src/cg/cg_dominance.cpp | 61 + .../maple/maple_be/src/cg/cg_option.cpp | 4 + .../maple_be/src/cg/control_dep_analysis.cpp | 1162 +++++++++++++++++ .../maple_be/src/cg/data_dep_analysis.cpp | 284 ++++ .../maple/maple_be/src/cg/data_dep_base.cpp | 496 +++++++ .../maple/maple_be/src/cg/global_schedule.cpp | 201 +++ .../maple/maple_be/src/cg/list_scheduler.cpp | 771 +++++++++++ .../maple/maple_be/src/cg/local_schedule.cpp | 123 ++ .../codegen/maple/maple_be/src/cg/loop.cpp | 123 ++ .../maple/maple_be/src/litecg/litecg.cpp | 11 + .../maple/maple_be/src/me_dominance.cpp | 54 + .../codegen/maple/maple_me/include/bb.h | 45 +- .../maple/maple_me/include/dominance.h | 509 ++++++-- .../maple/maple_me/include/me_dominance.h | 37 + .../maple/maple_me/src/meexpr_use_info.cpp | 2 +- .../compiler/codegen/maple/maple_pgo/BUILD.gn | 47 + .../codegen/maple/maple_pgo/include/cfg_mst.h | 77 ++ .../maple/maple_pgo/include/instrument.h | 259 ++++ .../codegen/maple/maple_pgo/src/cfg_mst.cpp | 136 ++ .../maple/maple_pgo/src/instrument.cpp | 151 +++ .../maple_util/include/base_graph_node.h | 40 + .../maple/mpl2mpl/include/call_graph.h | 35 +- .../codegen/maple/mpl2mpl/include/scc.h | 39 +- 53 files changed, 8050 insertions(+), 186 deletions(-) create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_data_dep_base.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_global_schedule.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_local_schedule.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/base_schedule.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_cdg.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/control_dep_analysis.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_analysis.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_base.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/global_schedule.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/list_scheduler.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/local_schedule.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/include/cg/schedule_heuristic.h create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_data_dep_base.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_global_schedule.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_local_schedule.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/base_schedule.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/control_dep_analysis.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_analysis.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_base.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/global_schedule.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/list_scheduler.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/cg/local_schedule.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_be/src/me_dominance.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_me/include/me_dominance.h create mode 100644 ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn create mode 100644 ecmascript/compiler/codegen/maple/maple_pgo/include/cfg_mst.h create mode 100644 ecmascript/compiler/codegen/maple/maple_pgo/include/instrument.h create mode 100644 ecmascript/compiler/codegen/maple/maple_pgo/src/cfg_mst.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_pgo/src/instrument.cpp create mode 100644 ecmascript/compiler/codegen/maple/maple_util/include/base_graph_node.h diff --git a/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn index 1d9653cec7..bc8ece60be 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn @@ -17,6 +17,7 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_be/include/cg", "${MAPLEALL_ROOT}/maple_be/include/litecg", "${MAPLEALL_ROOT}/maple_be/include/ad", + "${MAPLEALL_ROOT}/maple_pgo/include", "${MAPLEALL_ROOT}/maple_be/include/ad/target", "${MAPLEALL_ROOT}/maple_be/include/be", "${MAPLEALL_ROOT}/maple_driver/include", @@ -40,6 +41,7 @@ deps_libcg = [ "${MAPLEALL_ROOT}/maple_ir:libmplir", "${MAPLEALL_ROOT}/maple_util:libmplutil", "${MAPLEALL_ROOT}/maple_me:libmplme", + "${MAPLEALL_ROOT}/maple_pgo:libmplpgo", ] deps_libmplbe = [ ":libcglowerer" ] @@ -97,6 +99,7 @@ src_libcgaarch64 = [ "src/cg/aarch64/aarch64_cfi_generator.cpp", "src/cg/aarch64/aarch64_cgfunc.cpp", "src/cg/aarch64/aarch64_dependence.cpp", + "src/cg/aarch64/aarch64_data_dep_base.cpp", "src/cg/aarch64/aarch64_ebo.cpp", "src/cg/aarch64/aarch64_emitter.cpp", "src/cg/aarch64/aarch64_obj_emitter.cpp", @@ -132,6 +135,7 @@ src_libcgaarch64 = [ "src/cg/aarch64/aarch64_validbit_opt.cpp", "src/cg/aarch64/aarch64_cfgo.cpp", "src/cg/aarch64/aarch64_imm_valid.cpp", + "src/cg/aarch64/aarch64_local_schedule.cpp", ] src_libcgx86phases = [ @@ -230,6 +234,12 @@ src_libcgphases = [ "src/cg/alignment.cpp", "src/cg/cg_validbit_opt.cpp", "src/cg/cg_stackmap_computation.cpp", + "src/cg/control_dep_analysis.cpp", + "src/cg/data_dep_base.cpp", + "src/cg/data_dep_analysis.cpp", + "src/cg/base_schedule.cpp", + "src/cg/list_scheduler.cpp", + "src/cg/local_schedule.cpp", ] src_libcg = [ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cg.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cg.h index b0045867b7..b882f8b562 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cg.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cg.h @@ -32,6 +32,8 @@ #include "aarch64_peep.h" #include "aarch64_proepilog.h" +#include "aarch64_local_schedule.h" + namespace maplebe { constexpr int64 kShortBRDistance = (8 * 1024); constexpr int64 kNegativeImmLowerLimit = -4096; @@ -130,6 +132,11 @@ public: { return mp.New(f, ssaInfo); } + LocalSchedule *CreateLocalSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cda, + DataDepAnalysis &dda) const override + { + return mp.New(mp, f, cda, dda); + } CFGOptimizer *CreateCFGOptimizer(MemPool &mp, CGFunc &f) const override { return mp.New(f, mp); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_data_dep_base.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_data_dep_base.h new file mode 100644 index 0000000000..9f469d5cb2 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_data_dep_base.h @@ -0,0 +1,62 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_DATA_DEP_BASE_H +#define MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_DATA_DEP_BASE_H + +#include "aarch64_operand.h" +#include "cgfunc.h" +#include "data_dep_base.h" + +namespace maplebe { +class AArch64DataDepBase : public DataDepBase { +public: + AArch64DataDepBase(MemPool &mp, CGFunc &func, MAD &mad, bool isIntraAna) : DataDepBase(mp, func, mad, isIntraAna) {} + ~AArch64DataDepBase() override = default; + + void InitCDGNodeDataInfo(MemPool &mp, MapleAllocator &alloc, CDGNode &cdgNode) override; + bool IsFrameReg(const RegOperand &opnd) const override; + Insn *GetMemBaseDefInsn(const Insn &memInsn) const; + + void AnalysisAmbiInsns(BB &bb) override; + + void BuildDepsForMemDefCommon(Insn &insn, CDGNode &cdgNode); + void BuildDepsForMemUseCommon(Insn &insn, CDGNode &cdgNode); + void BuildDepsAccessStImmMem(Insn &insn) override; + void BuildCallerSavedDeps(Insn &insn) override; + void BuildDepsDirtyStack(Insn &insn) override; + void BuildDepsUseStack(Insn &insn) override; + void BuildDepsDirtyHeap(Insn &insn) override; + void BuildDepsMemBar(Insn &insn) override; + void BuildDepsUseMem(Insn &insn, MemOperand &memOpnd) override; + void BuildDepsDefMem(Insn &insn, MemOperand &memOpnd) override; + void BuildMemOpndDependency(Insn &insn, Operand &opnd, const OpndDesc ®Prop); + + void BuildOpndDependency(Insn &insn) override; + void BuildSpecialInsnDependency(Insn &insn, const MapleVector &nodes) override; + void BuildSpecialCallDeps(Insn &insn) override; + void BuildAsmInsnDependency(Insn &insn) override; + + void BuildInterBlockMemDefUseDependency(DepNode &depNode, bool isMemDef) override; + void BuildPredPathMemDefDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode) override; + void BuildPredPathMemUseDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode) override; + + void DumpNodeStyleInDot(std::ofstream &file, DepNode &depNode) override; + +protected: + void BuildSpecialBLDepsForJava(Insn &insn); +}; +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_DATA_DEP_BASE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_global_schedule.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_global_schedule.h new file mode 100644 index 0000000000..d52ded500f --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_global_schedule.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64_GLOBAL_SCHEDULE_H +#define MAPLEBE_INCLUDE_CG_AARCH64_GLOBAL_SCHEDULE_H + +#include "global_schedule.h" + +namespace maplebe { +class AArch64GlobalSchedule : public GlobalSchedule { +public: + AArch64GlobalSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cdAna, DataDepAnalysis &dda) + : GlobalSchedule(mp, f, cdAna, dda) + { + } + ~AArch64GlobalSchedule() override = default; + + /* Verify global scheduling */ + void VerifyingSchedule(CDGRegion ®ion) override; + +protected: + void FinishScheduling(CDGNode &cdgNode) override; +}; +} /* namespace maplebe */ + +#endif // MAPLEBE_INCLUDE_CG_AARCH64_GLOBAL_SCHEDULE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_local_schedule.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_local_schedule.h new file mode 100644 index 0000000000..97dd79a7ea --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_local_schedule.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_AARCH64_LOCAL_SCHEDULE_H +#define MAPLEBE_INCLUDE_CG_AARCH64_LOCAL_SCHEDULE_H + +#include "local_schedule.h" + +namespace maplebe { +class AArch64LocalSchedule : public LocalSchedule { +public: + AArch64LocalSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cdAna, DataDepAnalysis &dda) + : LocalSchedule(mp, f, cdAna, dda) + { + } + ~AArch64LocalSchedule() override = default; + + void FinishScheduling(CDGNode &cdgNode) override; +}; +} /* namespace maplebe */ + +#endif // MAPLEBE_INCLUDE_CG_AARCH64_LOCAL_SCHEDULE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def index 0e5d6e1e9d..772b461a2e 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def @@ -67,7 +67,7 @@ ADDTARGETPHASE("peephole", CGOptions::DoPeephole()) ADDTARGETPHASE("gencfi", !GetMIRModule()->IsCModule() || GetMIRModule()->IsWithDbgInfo()); ADDTARGETPHASE("yieldpoint", GetMIRModule()->IsJavaModule() && CGOptions::IsInsertYieldPoint()); - ADDTARGETPHASE("scheduling", CGOptions::DoSchedule()); + ADDTARGETPHASE("localschedule", CGOptions::DoLocalSchedule()); ADDTARGETPHASE("alignanalysis", GetMIRModule()->IsCModule() && CGOptions::DoAlignAnalysis()); ADDTARGETPHASE("fixshortbranch", true); ADDTARGETPHASE("cgirverify", CGOptions::DoCGIRVerify()); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/base_schedule.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/base_schedule.h new file mode 100644 index 0000000000..bb4cc35821 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/base_schedule.h @@ -0,0 +1,72 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_BASE_SCHEDULE_H +#define MAPLEBE_INCLUDE_CG_BASE_SCHEDULE_H + +#include "cgfunc.h" +#include "control_dep_analysis.h" +#include "data_dep_analysis.h" +#include "list_scheduler.h" + +namespace maplebe { +class BaseSchedule { +public: + BaseSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cdAna, bool doDelay = false) + : schedMP(mp), schedAlloc(&mp), cgFunc(f), cda(cdAna), doDelayHeu(doDelay) + { + } + virtual ~BaseSchedule() + { + listScheduler = nullptr; + } + + virtual void Run() = 0; + void InitInRegion(CDGRegion ®ion) const; + void DoLocalSchedule(CDGRegion ®ion); + bool DoDelayHeu() const + { + return doDelayHeu; + } + void SetDelayHeu() + { + doDelayHeu = true; + } + void SetUnitTest(bool flag) + { + isUnitTest = flag; + } + +protected: + void InitInsnIdAndLocInsn(); + // Using total number of machine instructions to control the end of the scheduling process + void InitMachineInsnNum(CDGNode &cdgNode) const; + uint32 CaculateOriginalCyclesOfBB(CDGNode &cdgNode) const; + void DumpRegionInfoBeforeSchedule(CDGRegion ®ion) const; + void DumpCDGNodeInfoBeforeSchedule(CDGNode &cdgNode) const; + void DumpCDGNodeInfoAfterSchedule(CDGNode &cdgNode) const; + void DumpInsnInfoByScheduledOrder(CDGNode &cdgNode) const; + + MemPool &schedMP; + MapleAllocator schedAlloc; + CGFunc &cgFunc; + ControlDepAnalysis &cda; + CommonScheduleInfo *commonSchedInfo = nullptr; + ListScheduler *listScheduler = nullptr; + bool doDelayHeu = false; + bool isUnitTest = false; +}; +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_BASE_SCHEDULE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg.h index 0bacc31734..4c554581a0 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg.h @@ -52,6 +52,9 @@ class ValidBitOpt; class CG; class LocalOpt; class CFGOptimizer; +class LocalSchedule; +class ControlDepAnalysis; +class DataDepAnalysis; class CGPeepHole; class GenProEpilog; @@ -90,6 +93,11 @@ public: return mad; } + void ClearMAD() + { + mad = nullptr; + } + const MAD *GetMAD() const { return mad; @@ -499,6 +507,11 @@ public: { return nullptr; }; + virtual LocalSchedule *CreateLocalSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cda, + DataDepAnalysis &dda) const + { + return nullptr; + } virtual LocalOpt *CreateLocalOpt(MemPool &mp, CGFunc &f, ReachingDefinition &) const { return nullptr; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_cdg.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_cdg.h new file mode 100644 index 0000000000..eba5d2f96c --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_cdg.h @@ -0,0 +1,864 @@ +/* + * 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. + */ + +/* + * The file defines the data structures of Control Dependence Graph(CDG). + */ +#ifndef MAPLEBE_INCLUDE_CG_CG_CDG_H +#define MAPLEBE_INCLUDE_CG_CG_CDG_H + +#include +#include "cgfunc.h" +#include "mpl_number.h" +#include "deps.h" +#include "mempool_allocator.h" + +namespace maplebe { +class CDGNode; +class CDGEdge; +class CDGRegion; +using CDGNodeId = utils::Index; +using CDGRegionId = utils::Index; + +// Encapsulation of BB +class CDGNode { +public: + CDGNode(CDGNodeId nId, BB &bb, MapleAllocator &alloc) + : id(nId), + bb(&bb), + outEdges(alloc.Adapter()), + inEdges(alloc.Adapter()), + lastComments(alloc.Adapter()), + dataNodes(alloc.Adapter()), + cfiInsns(alloc.Adapter()) + { + } + virtual ~CDGNode() + { + topoPredInRegion = nullptr; + lastFrameDef = nullptr; + bb = nullptr; + regUses = nullptr; + mayThrows = nullptr; + ehInRegs = nullptr; + heapDefs = nullptr; + ambiInsns = nullptr; + membarInsn = nullptr; + pseudoSepNodes = nullptr; + lastCallInsn = nullptr; + lastInlineAsmInsn = nullptr; + regDefs = nullptr; + stackDefs = nullptr; + region = nullptr; + heapUses = nullptr; + stackUses = nullptr; + } + + BB *GetBB() + { + return bb; + } + + const BB *GetBB() const + { + return bb; + } + + CDGNodeId GetNodeId() + { + return id; + } + + CDGNodeId GetNodeId() const + { + return id; + } + + void SetNodeId(CDGNodeId nId) + { + id = nId; + } + + CDGRegion *GetRegion() + { + return region; + } + + const CDGRegion *GetRegion() const + { + return region; + } + + void SetRegion(CDGRegion *cdgRegion) + { + region = cdgRegion; + } + + void ClearRegion() + { + region = nullptr; + } + + bool IsEntryNode() const + { + return isEntryNode; + } + + void SetEntryNode() + { + isEntryNode = true; + } + + bool IsExitNode() const + { + return isExitNode; + } + + void SetExitNode() + { + isExitNode = true; + } + + void AddOutEdges(CDGEdge *edge) + { + outEdges.emplace_back(edge); + } + + MapleVector &GetAllOutEdges() + { + return outEdges; + } + + void AddInEdges(CDGEdge *edge) + { + inEdges.emplace_back(edge); + } + + MapleVector &GetAllInEdges() + { + return inEdges; + } + + std::size_t GetOutEdgesNum() const + { + return outEdges.size(); + } + + std::size_t GetInEdgesNum() const + { + return inEdges.size(); + } + + void SetVisitedInTopoSort(bool isVisited) + { + isVisitedInTopoSort = isVisited; + } + + bool IsVisitedInTopoSort() const + { + return isVisitedInTopoSort; + } + + void SetVisitedInExtendedFind() + { + isVisitedInExtendedFind = true; + } + + bool IsVisitedInExtendedFind() const + { + return isVisitedInExtendedFind; + } + + uint32 GetInsnNum() const + { + return insnNum; + } + + void SetInsnNum(uint32 num) + { + insnNum = num; + } + + bool HasAmbiRegs() const + { + return hasAmbiRegs; + } + + void SetHasAmbiRegs(bool flag) + { + hasAmbiRegs = flag; + } + + Insn *GetMembarInsn() + { + return membarInsn; + } + + void SetMembarInsn(Insn *insn) + { + membarInsn = insn; + } + + Insn *GetLastCallInsn() + { + return lastCallInsn; + } + + void SetLastCallInsn(Insn *callInsn) + { + lastCallInsn = callInsn; + } + + Insn *GetLastFrameDefInsn() + { + return lastFrameDef; + } + + void SetLastFrameDefInsn(Insn *frameInsn) + { + lastFrameDef = frameInsn; + } + + Insn *GetLastInlineAsmInsn() + { + return lastInlineAsmInsn; + } + + void SetLastInlineAsmInsn(Insn *asmInsn) + { + lastInlineAsmInsn = asmInsn; + } + + void InitTopoInRegionInfo(MemPool &tmpMp, MapleAllocator &tmpAlloc) + { + topoPredInRegion = tmpMp.New>(tmpAlloc.Adapter()); + } + + void ClearTopoInRegionInfo() + { + topoPredInRegion = nullptr; + } + + void InitDataDepInfo(MemPool &tmpMp, MapleAllocator &tmpAlloc, uint32 maxRegNum) + { + regDefs = tmpMp.New>(tmpAlloc.Adapter()); + regUses = tmpMp.New>(tmpAlloc.Adapter()); + stackUses = tmpMp.New>(tmpAlloc.Adapter()); + stackDefs = tmpMp.New>(tmpAlloc.Adapter()); + heapUses = tmpMp.New>(tmpAlloc.Adapter()); + heapDefs = tmpMp.New>(tmpAlloc.Adapter()); + mayThrows = tmpMp.New>(tmpAlloc.Adapter()); + ambiInsns = tmpMp.New>(tmpAlloc.Adapter()); + pseudoSepNodes = tmpMp.New>(tmpAlloc.Adapter()); + ehInRegs = tmpMp.New>(tmpAlloc.Adapter()); + + regDefs->resize(maxRegNum); + regUses->resize(maxRegNum); + } + + void ClearDataDepInfo() + { + membarInsn = nullptr; + lastCallInsn = nullptr; + lastFrameDef = nullptr; + lastInlineAsmInsn = nullptr; + lastComments.clear(); + + regDefs = nullptr; + regUses = nullptr; + stackUses = nullptr; + stackDefs = nullptr; + heapUses = nullptr; + heapDefs = nullptr; + mayThrows = nullptr; + ambiInsns = nullptr; + pseudoSepNodes = nullptr; + ehInRegs = nullptr; + } + + void ClearDepDataVec() + { + membarInsn = nullptr; + lastCallInsn = nullptr; + lastFrameDef = nullptr; + lastInlineAsmInsn = nullptr; + + for (auto ®Def : *regDefs) { + regDef = nullptr; + } + for (auto ®Use : *regUses) { + regUse = nullptr; + } + + stackUses->clear(); + stackDefs->clear(); + heapUses->clear(); + heapDefs->clear(); + mayThrows->clear(); + ambiInsns->clear(); + } + + Insn *GetLatestDefInsn(regno_t regNO) + { + return (*regDefs)[regNO]; + } + + void SetLatestDefInsn(regno_t regNO, Insn *defInsn) + { + (*regDefs)[regNO] = defInsn; + } + + RegList *GetUseInsnChain(regno_t regNO) + { + return (*regUses)[regNO]; + } + + void AppendUseInsnChain(regno_t regNO, Insn *useInsn, MemPool &mp) + { + CHECK_FATAL(useInsn != nullptr, "invalid useInsn"); + auto *newUse = mp.New(); + newUse->insn = useInsn; + newUse->next = nullptr; + + RegList *headUse = (*regUses)[regNO]; + if (headUse == nullptr) { + (*regUses)[regNO] = newUse; + } else { + while (headUse->next != nullptr) { + headUse = headUse->next; + } + headUse->next = newUse; + } + } + + void ClearUseInsnChain(regno_t regNO) + { + (*regUses)[regNO] = nullptr; + } + + MapleVector &GetStackUseInsns() + { + return *stackUses; + } + + void AddStackUseInsn(Insn *stackInsn) + { + stackUses->emplace_back(stackInsn); + } + + MapleVector &GetStackDefInsns() + { + return *stackDefs; + } + + void AddStackDefInsn(Insn *stackInsn) + { + stackDefs->emplace_back(stackInsn); + } + + MapleVector &GetHeapUseInsns() + { + return *heapUses; + } + + void AddHeapUseInsn(Insn *heapInsn) const + { + heapUses->emplace_back(heapInsn); + } + + MapleVector &GetHeapDefInsns() + { + return *heapDefs; + } + + void AddHeapDefInsn(Insn *heapInsn) const + { + heapDefs->emplace_back(heapInsn); + } + + MapleVector &GetMayThrowInsns() + { + return *mayThrows; + } + + void AddMayThrowInsn(Insn *throwInsn) + { + mayThrows->emplace_back(throwInsn); + } + + MapleVector &GetAmbiguousInsns() + { + return *ambiInsns; + } + + void AddAmbiguousInsn(Insn *ambiInsn) const + { + ambiInsns->emplace_back(ambiInsn); + } + + MapleSet &GetTopoPredInRegion() + { + return *topoPredInRegion; + } + + void InsertVisitedTopoPredInRegion(CDGNodeId nodeId) const + { + topoPredInRegion->insert(nodeId); + } + + MapleVector &GetLastComments() + { + return lastComments; + } + + void AddCommentInsn(Insn *commentInsn) + { + lastComments.emplace_back(commentInsn); + } + + void CopyAndClearComments(MapleVector &comments) + { + lastComments = comments; + comments.clear(); + } + + void ClearLastComments() + { + lastComments.clear(); + } + + void AddPseudoSepNodes(DepNode *node) const + { + pseudoSepNodes->emplace_back(node); + } + + MapleSet &GetEhInRegs() + { + return *ehInRegs; + } + + MapleVector &GetAllDataNodes() + { + return dataNodes; + } + + void AddDataNode(DepNode *depNode) + { + (void)dataNodes.emplace_back(depNode); + } + + void ClearDataNodes() + { + dataNodes.clear(); + } + + MapleVector &GetCfiInsns() + { + return cfiInsns; + } + + void AddCfiInsn(Insn *cfiInsn) + { + (void)cfiInsns.emplace_back(cfiInsn); + } + + void RemoveDepNodeFromDataNodes(const DepNode &depNode) + { + for (auto iter = dataNodes.begin(); iter != dataNodes.end(); ++iter) { + if (*iter == &depNode) { + void(dataNodes.erase(iter)); + break; + } + } + } + + void InitPredNodeSumInRegion(int32 predSum) + { + CHECK_FATAL(predSum >= 0, "invalid predSum"); + predNodesInRegion = predSum; + } + + void DecPredNodeSumInRegion() + { + predNodesInRegion--; + } + + bool IsAllPredInRegionProcessed() const + { + return (predNodesInRegion == 0); + } + + uint32 &GetNodeSum() + { + return nodeSum; + } + + void AccNodeSum() + { + nodeSum++; + } + + void SetNodeSum(uint32 sum) + { + nodeSum = sum; + } + + bool operator!=(const CDGNode &node) + { + if (this != &node) { + return true; + } + if (this->id != node.GetNodeId() || this->bb != node.GetBB() || this->region != node.GetRegion()) { + return true; + } + if (this->GetInEdgesNum() != node.GetInEdgesNum() || this->GetOutEdgesNum() != node.GetOutEdgesNum()) { + return true; + } + return false; + } + +private: + CDGNodeId id; // same to bbId + BB *bb = nullptr; + CDGRegion *region = nullptr; + bool isEntryNode = false; + bool isExitNode = false; + MapleVector outEdges; + MapleVector inEdges; + bool isVisitedInTopoSort = false; // for sorting nodes in region by topological order + bool isVisitedInExtendedFind = false; // for finding a fallthrough path as a region + uint32 insnNum = 0; // record insn total num of BB + // The following structures are used to record data flow infos in building data dependence among insns + bool hasAmbiRegs = false; + Insn *membarInsn = nullptr; + Insn *lastCallInsn = nullptr; + Insn *lastFrameDef = nullptr; + Insn *lastInlineAsmInsn = nullptr; + MapleVector *regDefs = nullptr; // the index is regNO, record the latest defInsn in the curBB + MapleVector *regUses = nullptr; // the index is regNO + MapleVector *stackUses = nullptr; + MapleVector *stackDefs = nullptr; + MapleVector *heapUses = nullptr; + MapleVector *heapDefs = nullptr; + MapleVector *mayThrows = nullptr; + MapleVector *ambiInsns = nullptr; + MapleVector *pseudoSepNodes = nullptr; + MapleSet *ehInRegs = nullptr; + MapleSet *topoPredInRegion = nullptr; + MapleVector lastComments; + MapleVector dataNodes; + MapleVector cfiInsns; + // For computing topological order of cdgNodes in a region, + // which is initialized to the number of pred nodes in CFG at the beginning of processing the region, + // and change dynamically + int32 predNodesInRegion = -1; + // For intra-block dda: it accumulates from the first insn (nodeSum = 1) of bb + // For inter-block dda: it accumulates from the maximum of nodeSum in all the predecessor of cur cdgNode + uint32 nodeSum = 0; +}; + +class CDGEdge { +public: + CDGEdge(CDGNode &from, CDGNode &to, int32 cond) : fromNode(from), toNode(to), condition(cond) {} + virtual ~CDGEdge() = default; + + CDGNode &GetFromNode() + { + return fromNode; + } + + CDGNode &GetFromNode() const + { + return fromNode; + } + + void SetFromNode(const CDGNode &from) + { + fromNode = from; + } + + CDGNode &GetToNode() + { + return toNode; + } + + CDGNode &GetToNode() const + { + return toNode; + } + + void SetToNode(const CDGNode &to) + { + toNode = to; + } + + int32 GetCondition() const + { + return condition; + } + + void SetCondition(int32 cond) + { + condition = cond; + } + + // for checking same control dependence + bool operator==(const CDGEdge &edge) + { + if (this == &edge) { + return true; + } + if (this->fromNode != edge.GetFromNode()) { + return false; + } + if (this->toNode != edge.GetToNode()) { + return false; + } + if (this->condition != edge.GetCondition()) { + return false; + } + return true; + } + +private: + CDGNode &fromNode; + CDGNode &toNode; + // allocate different COND number to different succ edges of the same fromBB + // default value is -1 indicated no cond. + int32 condition; +}; + +// A region consists of nodes with the same control dependence sets +class CDGRegion { +public: + CDGRegion(CDGRegionId rId, MapleAllocator &alloc) : id(rId), memberNodes(alloc.Adapter()), cdEdges(alloc.Adapter()) + { + } + virtual ~CDGRegion() + { + root = nullptr; + } + + CDGRegionId GetRegionId() + { + return id; + } + + MapleVector &GetRegionNodes() + { + return memberNodes; + } + + std::size_t GetRegionNodeSize() const + { + return memberNodes.size(); + } + + // Ensure the node is unique + void AddCDGNode(CDGNode *node) + { + if (std::find(memberNodes.cbegin(), memberNodes.cend(), node) == memberNodes.cend()) { + memberNodes.emplace_back(node); + } + } + + void RemoveCDGNode(CDGNode *node) + { + auto it = std::find(memberNodes.begin(), memberNodes.end(), node); + if (it == memberNodes.end()) { + return; + } + (void)memberNodes.erase(it); + } + + CDGNode *GetCDGNodeById(CDGNodeId nodeId) + { + for (auto cdgNode : memberNodes) { + if (cdgNode->GetNodeId() == nodeId) { + return cdgNode; + } + } + return nullptr; + } + + MapleVector &GetCDEdges() + { + return cdEdges; + } + + void AddCDEdge(CDGEdge *edge) + { + cdEdges.emplace_back(edge); + } + + void AddCDEdgeSet(MapleVector &cds) + { + for (auto &cd : cds) { + cdEdges.emplace_back(cd); + } + } + + uint32 GetMaxBBIdInRegion() + { + uint32 maxId = 0; + for (auto node : memberNodes) { + maxId = (node->GetNodeId() > maxId ? static_cast(node->GetNodeId()) : maxId); + } + return maxId; + } + + void SetRegionRoot(CDGNode &node) + { + root = &node; + } + + CDGNode *GetRegionRoot() + { + return root; + } + + void SetBackBBId(BBID bbId) + { + backEdgeFromBBId = bbId; + } + + BBID GetBackBBId() const + { + return backEdgeFromBBId; + } + +private: + CDGRegionId id; + MapleVector memberNodes; // The nodes in CDGRegion by topological order + // The control dependence sets of the parent node. + // If it is a general non-linear region, the cdEdges is empty. + MapleVector cdEdges; + CDGNode *root = nullptr; + BBID backEdgeFromBBId = UINT32_MAX; // For loop region +}; + +// Forward Control Dependence Graph +// which does not compute the control dependence on the back edges +class FCDG { +public: + FCDG(const CGFunc &f, MapleAllocator &alloc) + : nodes(f.GetAllBBSize(), alloc.Adapter()), + fcds(alloc.Adapter()), + regions(f.GetAllBBSize() + 1, alloc.Adapter()) + { + } + virtual ~FCDG() = default; + + MapleVector &GetAllFCDGNodes() + { + return nodes; + } + + std::size_t GetFCDGNodeSize() const + { + return nodes.size(); + } + + CDGNode *GetCDGNodeFromId(CDGNodeId id) + { + return nodes[id]; + } + + MapleVector &GetAllFCDGEdges() + { + return fcds; + } + + MapleVector &GetAllRegions() + { + return regions; + } + + CDGRegion *GetRegionFromId(CDGRegionId id) + { + return regions[id]; + } + + // Ensure the node is unique + void AddFCDGNode(CDGNode &node) + { + if (nodes[node.GetNodeId()] == nullptr) { + nodes[node.GetNodeId()] = &node; + } + } + + void AddFCDGEdge(CDGEdge *edge) + { + fcds.emplace_back(edge); + } + + // Ensure the region is unique + void AddRegion(CDGRegion ®ion) + { + if (regions[region.GetRegionId()] == nullptr) { + regions[region.GetRegionId()] = ®ion; + } + } + + void RemoveRegionById(CDGRegionId id) + { + regions[id] = nullptr; + } + + // Provide interfaces for global scheduling + +private: + MapleVector nodes; // all CDGNodes in FCDG that use nodeId as the index + MapleVector fcds; // all forward-control-dependence in FCDG + MapleVector regions; // all regions in FCDG that use CDGRegionId as the index +}; + +struct CDGOutEdgeComparator { + bool operator()(const CDGEdge &outEdge1, const CDGEdge &outEdge2) const + { + const CDGNode &toNode1 = outEdge1.GetToNode(); + const CDGNode &toNode2 = outEdge2.GetToNode(); + return toNode1.GetNodeId() < toNode2.GetNodeId(); + } +}; + +struct CDGInEdgeComparator { + bool operator()(const CDGEdge &inEdge1, const CDGEdge &inEdge2) const + { + const CDGNode &fromNode1 = inEdge1.GetFromNode(); + const CDGNode &fromNode2 = inEdge2.GetToNode(); + return fromNode1.GetNodeId() < fromNode2.GetNodeId(); + } +}; +} // namespace maplebe + +namespace std { +template <> +struct hash { + size_t operator()(const maplebe::CDGNodeId &nId) const + { + return nId; + } +}; + +template <> +struct hash { + size_t operator()(const maplebe::CDGRegionId &rId) const + { + return rId; + } +}; +} // namespace std +#endif // MAPLEBE_INCLUDE_CG_CG_CDG_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_dominance.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_dominance.h index efa8c7fda9..779ff12b22 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_dominance.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_dominance.h @@ -211,6 +211,7 @@ public: uint32 ComputePdtPreorder(const BB &bb, uint32 &num); bool PostDominate(const BB &bb1, const BB &bb2); // true if bb1 postdominates bb2 void Dump(); + void GeneratePdomTreeDot(); auto &GetPdomFrontierItem(size_t idx) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h index 4e72e9e8cb..67b0151d80 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h @@ -813,6 +813,21 @@ public: return doCGSSA; } + static void DisableLocalSchedule() + { + doLocalSchedule = false; + } + + static void EnableLocalSchedule() + { + doLocalSchedule = true; + } + + static bool DoLocalSchedule() + { + return doLocalSchedule; + } + static bool DoCGRegCoalecse() { return doCGRegCoalesce; @@ -1651,6 +1666,7 @@ private: static bool cgBigEndian; static bool doEBO; static bool doCGSSA; + static bool doLocalSchedule; static bool doCGRegCoalesce; static bool doIPARA; static bool doCFGO; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h index 294c6a8764..c804b8ae5a 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h @@ -27,6 +27,7 @@ /* Maple MP header */ #include "mempool_allocator.h" #include "maple_phase_manager.h" +#include "base_graph_node.h" namespace maplebe { /* For get bb */ @@ -72,10 +73,11 @@ namespace maplebe { class CGFuncLoops; class CGFunc; +class CDGNode; using BBID = uint32; -class BB { +class BB : public maple::BaseGraphNode { public: static constexpr int32 kUnknownProb = -1; static constexpr uint32 kBBIfSuccsSize = 2; @@ -295,6 +297,10 @@ public: { return id; } + uint32 GetID() const + { + return id; + } uint32 GetLevel() const { return level; @@ -469,6 +475,59 @@ public: { return succs.size(); } + + // get curBB's all preds + std::vector GetAllPreds() const + { + std::vector allPreds; + for (auto *pred : preds) { + allPreds.push_back(pred); + } + for (auto *pred : ehPreds) { + allPreds.push_back(pred); + } + return allPreds; + } + + // get curBB's all succs + std::vector GetAllSuccs() const + { + std::vector allSuccs; + for (auto *suc : succs) { + allSuccs.push_back(suc); + } + for (auto *suc : ehSuccs) { + allSuccs.push_back(suc); + } + return allSuccs; + } + + // override interface of BaseGraphNode + const std::string GetIdentity() final + { + return "BBId: " + std::to_string(GetID()); + } + void GetOutNodes(std::vector &outNodes) const final + { + outNodes.resize(succs.size(), nullptr); + std::copy(succs.begin(), succs.end(), outNodes.begin()); + } + + void GetOutNodes(std::vector &outNodes) final + { + static_cast(this)->GetOutNodes(outNodes); + } + + void GetInNodes(std::vector &inNodes) const final + { + inNodes.resize(preds.size(), nullptr); + std::copy(preds.begin(), preds.end(), inNodes.begin()); + } + + void GetInNodes(std::vector &inNodes) final + { + static_cast(this)->GetInNodes(inNodes); + } const MapleList &GetEhPreds() const { return ehPreds; @@ -984,6 +1043,15 @@ public: return alignNopNum; } + CDGNode *GetCDGNode() + { + return cdgNode; + } + void SetCDGNode(CDGNode *node) + { + cdgNode = node; + } + // Check if a given BB mergee can be merged into this BB in the sense of control flow // The condition is looser than CanMerge, since we only need this for debug info. bool MayFoldInCfg(const BB &mergee) const @@ -1025,6 +1093,15 @@ public: isAdrpLabel = true; } + SCCNode *GetSCCNode() + { + return sccNode; + } + void SetSCCNode(SCCNode *scc) + { + sccNode = scc; + } + private: static const std::string bbNames[kBBLast]; uint32 id; @@ -1115,6 +1192,9 @@ private: uint32 alignPower = 0; uint32 alignNopNum = 0; + CDGNode *cdgNode = nullptr; + SCCNode *sccNode = nullptr; + bool isAdrpLabel = false; // Indicate whether the address of this BB is referenced by adrp_label insn }; /* class BB */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h index 7f3e61af59..0d99695d25 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h @@ -962,6 +962,12 @@ public: return commonExitBB; } + BB *GetCommonEntryBB() + { + DEBUG_ASSERT(bbVec[0]->GetId() == 0 && bbVec[0] != firstBB, "there is no commonEntryBB"); + return bbVec[0]; + } + LabelIdx GetFirstCGGenLabelIdx() const { return firstCGGenLabelIdx; @@ -1282,6 +1288,11 @@ public: return bbVec; } + std::size_t GetAllBBSize() const + { + return bbVec.size(); + } + BB *GetBBFromID(uint32 id) { return bbVec[id]; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/control_dep_analysis.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/control_dep_analysis.h new file mode 100644 index 0000000000..133877da9e --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/control_dep_analysis.h @@ -0,0 +1,187 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_PDG_ANALYSIS_H +#define MAPLEBE_INCLUDE_CG_PDG_ANALYSIS_H + +#include +#include "me_dominance.h" +#include "cfg_mst.h" +#include "instrument.h" +#include "cg_cdg.h" +#include "cg_dominance.h" +#include "data_dep_base.h" +#include "loop.h" + +namespace maplebe { +#define CONTROL_DEP_ANALYSIS_DUMP CG_DEBUG_FUNC(cgFunc) +// Analyze Control Dependence +class ControlDepAnalysis { +public: + ControlDepAnalysis(CGFunc &func, MemPool &memPool, MemPool &tmpPool, DomAnalysis &d, PostDomAnalysis &pd, + LoopAnalysis &lp, CFGMST, maplebe::BB> *cfgmst, std::string pName = "") + : cgFunc(func), + dom(&d), + pdom(&pd), + loop(&lp), + cfgMST(cfgmst), + cdgMemPool(memPool), + cdgAlloc(&memPool), + tmpAlloc(&tmpPool), + nonPdomEdges(tmpAlloc.Adapter()), + curCondNumOfBB(tmpAlloc.Adapter()), + phaseName(std::move(pName)) + { + } + ControlDepAnalysis(CGFunc &func, MemPool &memPool, std::string pName = "", bool isSingle = true) + : cgFunc(func), + cdgMemPool(memPool), + cdgAlloc(&memPool), + tmpAlloc(&memPool), + nonPdomEdges(cdgAlloc.Adapter()), + curCondNumOfBB(cdgAlloc.Adapter()), + phaseName(std::move(pName)), + isSingleBB(isSingle) + { + } + virtual ~ControlDepAnalysis() + { + dom = nullptr; + fcdg = nullptr; + cfgMST = nullptr; + pdom = nullptr; + loop = nullptr; + } + + std::string PhaseName() const + { + if (phaseName.empty()) { + return "controldepanalysis"; + } else { + return phaseName; + } + } + void SetIsSingleBB(bool isSingle) + { + isSingleBB = isSingle; + } + + // The entry of analysis + void Run(); + + // Provide scheduling-related interfaces + void ComputeSingleBBRegions(); // For local-scheduling in a single BB + void GetEquivalentNodesInRegion(CDGRegion ®ion, CDGNode &cdgNode, std::vector &equivalentNodes); + + // Interface for obtaining PDGAnalysis infos + FCDG *GetFCDG() + { + return fcdg; + } + CFGMST, maplebe::BB> *GetCFGMst() + { + return cfgMST; + } + + // Print forward-control-dependence-graph in dot syntax + void GenerateFCDGDot() const; + // Print control-flow-graph with condition at edges in dot syntax + void GenerateCFGDot() const; + // Print control-flow-graph with only bbId + void GenerateSimplifiedCFGDot() const; + // Print control-flow-graph of the region in dot syntax + void GenerateCFGInRegionDot(CDGRegion ®ion) const; + +protected: + void BuildCFGInfo(); + void ConstructFCDG(); + void ComputeRegions(bool doCDRegion); + void ComputeGeneralNonLinearRegions(); + void FindInnermostLoops(std::vector &innermostLoops, std::unordered_map &visited, + LoopDesc *lp); + void FindFallthroughPath(std::vector ®ionMembers, BB *curBB, bool isRoot); + void CreateRegionForSingleBB(); + bool AddRegionNodesInTopologicalOrder(CDGRegion ®ion, CDGNode &root, const MapleSet &members); + void ComputeSameCDRegions(bool considerNonDep); + void ComputeRegionForCurNode(uint32 curBBId, std::vector &visited); + void CreateAndDivideRegion(uint32 pBBId); + void ComputeRegionForNonDepNodes(); + CDGRegion *FindExistRegion(CDGNode &node) const; + bool IsISEqualToCDs(CDGNode &parent, CDGNode &child) const; + void MergeRegions(CDGNode &mergeNode, CDGNode &candiNode); + + CDGEdge *BuildControlDependence(const BB &fromBB, const BB &toBB, int32 condition); + CDGRegion *CreateFCDGRegion(CDGNode &curNode); + void CreateAllCDGNodes(); + Dominance *ComputePdomInRegion(CDGRegion ®ion, std::vector &nonUniformRegionCFG, uint32 &maxBBId); + bool IsInDifferentSCCNode(CDGRegion ®ion, std::vector ®ionCFG, uint32 maxBBId, const BB &curBB, + const BB &memberBB); + + void AddNonPdomEdges(BBEdge *bbEdge) + { + nonPdomEdges.emplace_back(bbEdge); + } + + uint32 GetAndAccSuccedCondNum(uint32 bbId) + { + auto pair = curCondNumOfBB.try_emplace(bbId, 0); + if (pair.second) { + return 0; + } else { + uint32 curNum = pair.first->second; + pair.first->second = curNum + 1; + return curNum; + } + } + + static bool IsSameControlDependence(const CDGEdge &edge1, const CDGEdge &edge2) + { + CDGNode &fromNode1 = edge1.GetFromNode(); + CDGNode &fromNode2 = edge2.GetFromNode(); + if (fromNode1.GetNodeId() != fromNode2.GetNodeId()) { + return false; + } + if (edge1.GetCondition() != edge2.GetCondition()) { + return false; + } + return true; + } + + CGFunc &cgFunc; + DomAnalysis *dom = nullptr; + PostDomAnalysis *pdom = nullptr; + LoopAnalysis *loop = nullptr; + CFGMST, maplebe::BB> *cfgMST = nullptr; + MemPool &cdgMemPool; + MapleAllocator cdgAlloc; + MapleAllocator tmpAlloc; + MapleVector *> nonPdomEdges; + MapleUnorderedMap curCondNumOfBB; // + FCDG *fcdg = nullptr; + uint32 lastRegionId = 0; + std::string phaseName; + bool isSingleBB = false; +}; + +MAPLE_FUNC_PHASE_DECLARE_BEGIN(CgControlDepAnalysis, maplebe::CGFunc); +ControlDepAnalysis *GetResult() +{ + return cda; +} +ControlDepAnalysis *cda = nullptr; +OVERRIDE_DEPENDENCE +MAPLE_FUNC_PHASE_DECLARE_END +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_PDG_ANALYSIS_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_analysis.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_analysis.h new file mode 100644 index 0000000000..da186cd6df --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_analysis.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +// Build intra/inter block data dependence graph. +// 1: Build data dependence nodes +// 2: Build edges between dependence nodes. Edges are: +// 2.1) True dependence +// 2.2) Anti dependence +// 2.3) Output dependence +// 2.4) Barrier dependence +#ifndef MAPLEBE_INCLUDE_CG_DATA_DEP_ANALYSIS_H +#define MAPLEBE_INCLUDE_CG_DATA_DEP_ANALYSIS_H + +#include "data_dep_base.h" +#include "mempool.h" +#include "cg_cdg.h" + +namespace maplebe { +constexpr uint32 kMaxDumpRegionNodeNum = 6; + +// Create data dependence of region, include: +// inter-data-dependence-analysis (cross-bb) and +// intra-data-dependence-analysis (in-bb) +class DataDepAnalysis { +public: + DataDepAnalysis(CGFunc &f, MemPool &memPool, DataDepBase &dataDepBase) + : cgFunc(f), interMp(memPool), interAlloc(&memPool), ddb(dataDepBase) + { + } + virtual ~DataDepAnalysis() = default; + + void Run(CDGRegion ®ion); + void GenerateDataDepGraphDotOfRegion(CDGRegion ®ion); + +protected: + void InitInfoInRegion(MemPool ®ionMp, MapleAllocator ®ionAlloc, CDGRegion ®ion); + void InitInfoInCDGNode(MemPool ®ionMp, MapleAllocator ®ionAlloc, BB &bb, CDGNode &cdgNode); + void ClearInfoInRegion(MemPool *regionMp, MapleAllocator *regionAlloc, CDGRegion ®ion) const; + void BuildDepsForPrevSeparator(CDGNode &cdgNode, DepNode &depNode, CDGRegion &curRegion); + void BuildSpecialInsnDependency(Insn &insn, CDGNode &cdgNode, CDGRegion ®ion, MapleAllocator &alloc); + void UpdateRegUseAndDef(Insn &insn, const DepNode &depNode, CDGNode &cdgNode); + void UpdateReadyNodesInfo(CDGNode &cdgNode, const CDGNode &root) const; + +private: + CGFunc &cgFunc; + MemPool &interMp; + MapleAllocator interAlloc; + DataDepBase &ddb; +}; +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_DATA_DEP_ANALYSIS_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_base.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_base.h new file mode 100644 index 0000000000..ce5b00fccf --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/data_dep_base.h @@ -0,0 +1,137 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_DATA_DEP_BASE_H +#define MAPLEBE_INCLUDE_CG_DATA_DEP_BASE_H + +#include "deps.h" +#include "cgbb.h" +#include "cg_cdg.h" + +namespace maplebe { +using namespace maple; +constexpr maple::uint32 kMaxDependenceNum = 200; +constexpr maple::uint32 kMaxInsnNum = 220; + +class DataDepBase { +public: + DataDepBase(MemPool &memPool, CGFunc &func, MAD &mad, bool isIntraAna) + : memPool(memPool), + alloc(&memPool), + cgFunc(func), + mad(mad), + beforeRA(!cgFunc.IsAfterRegAlloc()), + isIntra(isIntraAna) + { + } + virtual ~DataDepBase() + { + curRegion = nullptr; + curCDGNode = nullptr; + } + + enum DataFlowInfoType : uint8 { + kDataFlowUndef, + kMembar, + kLastCall, + kLastFrameDef, + kStackUses, + kStackDefs, + kHeapUses, + kHeapDefs, + kMayThrows, + kAmbiguous, + }; + + void SetCDGNode(CDGNode *cdgNode) + { + curCDGNode = cdgNode; + } + CDGNode *GetCDGNode() + { + return curCDGNode; + } + void SetCDGRegion(CDGRegion *region) + { + curRegion = region; + } + + void ProcessNonMachineInsn(Insn &insn, MapleVector &comments, MapleVector &dataNodes, + const Insn *&locInsn); + + void AddDependence4InsnInVectorByType(MapleVector &insns, Insn &insn, const DepType &type); + void AddDependence4InsnInVectorByTypeAndCmp(MapleVector &insns, Insn &insn, const DepType &type); + + const std::string &GetDepTypeName(DepType depType) const; + + bool IfInAmbiRegs(regno_t regNO) const; + void AddDependence(DepNode &fromNode, DepNode &toNode, DepType depType); + DepNode *GenerateDepNode(Insn &insn, MapleVector &nodes, uint32 &nodeSum, MapleVector &comments); + void RemoveSelfDeps(Insn &insn); + void BuildDepsUseReg(Insn &insn, regno_t regNO); + void BuildDepsDefReg(Insn &insn, regno_t regNO); + void BuildDepsAmbiInsn(Insn &insn); + void BuildAmbiInsnDependency(Insn &insn); + void BuildMayThrowInsnDependency(DepNode &depNode, Insn &insn, const Insn &locInsn); + void BuildDepsControlAll(Insn &insn, const MapleVector &nodes); + void BuildDepsBetweenControlRegAndCall(Insn &insn, bool isDest); + void BuildDepsLastCallInsn(Insn &insn); + void BuildInterBlockDefUseDependency(DepNode &curDepNode, regno_t regNO, DepType depType, bool isDef); + void BuildPredPathDefDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode, regno_t regNO, + DepType depType); + void BuildPredPathUseDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode, regno_t regNO, + DepType depType); + void BuildInterBlockSpecialDataInfoDependency(DepNode &curDepNode, bool needCmp, DepType depType, + DataDepBase::DataFlowInfoType infoType); + void BuildPredPathSpecialDataInfoDependencyDFS(BB &curBB, std::vector &visited, bool needCmp, + DepNode &depNode, DepType depType, + DataDepBase::DataFlowInfoType infoType); + + virtual void InitCDGNodeDataInfo(MemPool &mp, MapleAllocator &alloc, CDGNode &cdgNode) = 0; + virtual bool IsFrameReg(const RegOperand &) const = 0; + virtual void AnalysisAmbiInsns(BB &bb) = 0; + virtual void BuildDepsMemBar(Insn &insn) = 0; + virtual void BuildDepsUseMem(Insn &insn, MemOperand &memOpnd) = 0; + virtual void BuildDepsDefMem(Insn &insn, MemOperand &memOpnd) = 0; + virtual void BuildDepsAccessStImmMem(Insn &insn) = 0; + virtual void BuildCallerSavedDeps(Insn &insn) = 0; + virtual void BuildDepsDirtyStack(Insn &insn) = 0; + virtual void BuildDepsUseStack(Insn &insn) = 0; + virtual void BuildDepsDirtyHeap(Insn &insn) = 0; + virtual void BuildOpndDependency(Insn &insn) = 0; + virtual void BuildSpecialInsnDependency(Insn &insn, const MapleVector &nodes) = 0; + virtual void BuildSpecialCallDeps(Insn &insn) = 0; + virtual void BuildAsmInsnDependency(Insn &insn) = 0; + virtual void BuildInterBlockMemDefUseDependency(DepNode &depNode, bool isMemDef) = 0; + virtual void BuildPredPathMemDefDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode) = 0; + virtual void BuildPredPathMemUseDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode) = 0; + virtual void DumpNodeStyleInDot(std::ofstream &file, DepNode &depNode) = 0; + +private: + // only called by BuildPredPathSpecialDataInfoDependencyDFS + void BuildForStackHeapDefUseInfoData(bool needCmp, MapleVector &insns, DepNode &depNode, DepType depType); + +protected: + MemPool &memPool; + MapleAllocator alloc; + CGFunc &cgFunc; + MAD &mad; + bool beforeRA = false; + bool isIntra = false; + CDGNode *curCDGNode = nullptr; + CDGRegion *curRegion = nullptr; +}; +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_DATA_DEP_BASE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/dependence.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/dependence.h index bddf38a7f8..10967c32a8 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/dependence.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/dependence.h @@ -21,9 +21,6 @@ namespace maplebe { using namespace maple; -namespace { -constexpr maple::uint32 kMaxDependenceNum = 200; -}; class DepAnalysis { public: diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/deps.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/deps.h index 0deceebf9e..e961fba229 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/deps.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/deps.h @@ -25,6 +25,16 @@ namespace maplebe { #define PRINT_STR_VAL(STR, VAL) (LogInfo::MapleLogger() << std::left << std::setw(12) << (STR) << (VAL) << " | ") #define PRINT_VAL(VAL) (LogInfo::MapleLogger() << std::left << std::setw(12) << (VAL) << " | ") + +constexpr uint8 kNumOne = 1; +constexpr uint8 kNumTwo = 2; +constexpr uint8 kNumThree = 3; +constexpr uint8 kNumFour = 4; +constexpr uint8 kNumEight = 8; +constexpr uint8 kNumTen = 10; +constexpr uint8 kNumTwelve = 12; +constexpr uint8 kNumFifteen = 15; + enum DepType : uint8 { kDependenceTypeTrue, kDependenceTypeOutput, diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/global_schedule.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/global_schedule.h new file mode 100644 index 0000000000..fde1bdbd22 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/global_schedule.h @@ -0,0 +1,55 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_GLOBAL_SCHEDULE_H +#define MAPLEBE_INCLUDE_CG_GLOBAL_SCHEDULE_H + +#include "base_schedule.h" + +namespace maplebe { +#define GLOBAL_SCHEDULE_DUMP CG_DEBUG_FUNC(cgFunc) + +class GlobalSchedule : public BaseSchedule { +public: + GlobalSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cdAna, DataDepAnalysis &dda) + : BaseSchedule(mp, f, cdAna), interDDA(dda) + { + } + ~GlobalSchedule() override = default; + + std::string PhaseName() const + { + return "globalschedule"; + } + void Run() override; + bool CheckCondition(CDGRegion ®ion); + // Region-based global scheduling entry, using the list scheduling algorithm for scheduling insns in bb + void DoGlobalSchedule(CDGRegion ®ion); + + // Verifying the Correctness of Global Scheduling + virtual void VerifyingSchedule(CDGRegion ®ion) = 0; + +protected: + void InitInCDGNode(CDGRegion ®ion, CDGNode &cdgNode, MemPool &cdgNodeMp); + void PrepareCommonSchedInfo(CDGRegion ®ion, CDGNode &cdgNode, MemPool &cdgNodeMp); + virtual void FinishScheduling(CDGNode &cdgNode) = 0; + void ClearCDGNodeInfo(CDGRegion ®ion, CDGNode &cdgNode, MemPool *cdgNodeMp); + + DataDepAnalysis &interDDA; +}; + +MAPLE_FUNC_PHASE_DECLARE(CgGlobalSchedule, maplebe::CGFunc) +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_GLOBAL_SCHEDULE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/list_scheduler.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/list_scheduler.h new file mode 100644 index 0000000000..a22f1abe0c --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/list_scheduler.h @@ -0,0 +1,273 @@ +/* + * 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. + */ + +#ifndef MAPLEBE_INCLUDE_CG_LIST_SCHEDULER_H +#define MAPLEBE_INCLUDE_CG_LIST_SCHEDULER_H + +#include +#include "cg.h" +#include "deps.h" +#include "cg_cdg.h" +#include "schedule_heuristic.h" + +namespace maplebe { +#define LIST_SCHEDULE_DUMP CG_DEBUG_FUNC(cgFunc) +using SchedRankFunctor = bool (*)(const DepNode *node1, const DepNode *node2); + +constexpr uint32 kClinitAdvanceCycle = 12; +constexpr uint32 kAdrpLdrAdvanceCycle = 4; +constexpr uint32 kClinitTailAdvanceCycle = 6; + +class CommonScheduleInfo { +public: + explicit CommonScheduleInfo(MemPool &memPool) + : csiAlloc(&memPool), candidates(csiAlloc.Adapter()), schedResults(csiAlloc.Adapter()) + { + } + ~CommonScheduleInfo() = default; + + MapleVector &GetCandidates() + { + return candidates; + } + void AddCandidates(DepNode *depNode) + { + (void)candidates.emplace_back(depNode); + } + void EraseNodeFromCandidates(const DepNode *depNode) + { + for (auto iter = candidates.begin(); iter != candidates.end(); ++iter) { + if (*iter == depNode) { + (void)candidates.erase(iter); + return; + } + } + } + MapleVector::iterator EraseIterFromCandidates(MapleVector::iterator depIter) + { + return candidates.erase(depIter); + } + MapleVector &GetSchedResults() + { + return schedResults; + } + void AddSchedResults(DepNode *depNode) + { + (void)schedResults.emplace_back(depNode); + } + std::size_t GetSchedResultsSize() const + { + return schedResults.size(); + } + +private: + MapleAllocator csiAlloc; + // Candidate instructions list of current BB, + // by control flow sequence + MapleVector candidates; + // Scheduled results list of current BB + // for global-scheduler, it stored only to the last depNode of current BB + MapleVector schedResults; +}; + +class ListScheduler { +public: + ListScheduler(MemPool &memPool, CGFunc &func, SchedRankFunctor rankFunc, bool delayHeu = true, + std::string pName = "") + : listSchedMp(memPool), + listSchedAlloc(&memPool), + cgFunc(func), + rankScheduleInsns(rankFunc), + doDelayHeuristics(delayHeu), + phaseName(std::move(pName)), + waitingQueue(listSchedAlloc.Adapter()), + readyList(listSchedAlloc.Adapter()) + { + } + ListScheduler(MemPool &memPool, CGFunc &func, bool delayHeu = true, std::string pName = "") + : listSchedMp(memPool), + listSchedAlloc(&memPool), + cgFunc(func), + doDelayHeuristics(delayHeu), + phaseName(std::move(pName)), + waitingQueue(listSchedAlloc.Adapter()), + readyList(listSchedAlloc.Adapter()) + { + } + virtual ~ListScheduler() + { + mad = nullptr; + } + + std::string PhaseName() const + { + if (phaseName.empty()) { + return "listscheduler"; + } else { + return phaseName; + } + } + + // The entry of list-scheduler + // cdgNode: current scheduled BB + void DoListScheduling(); + void ComputeDelayPriority(); + // Compute the earliest start cycle, update maxEStart + void ComputeEStart(uint32 cycle); + // Compute the latest start cycle + void ComputeLStart(); + // Calculate the most used unitKind index + void CalculateMostUsedUnitKindCount(); + + void SetCommonSchedInfo(CommonScheduleInfo &csi) + { + commonSchedInfo = &csi; + } + void SetCDGRegion(CDGRegion &cdgRegion) + { + region = &cdgRegion; + } + void SetCDGNode(CDGNode &cdgNode) + { + curCDGNode = &cdgNode; + } + uint32 GetCurrCycle() const + { + return currCycle; + } + uint32 GetMaxLStart() const + { + return maxLStart; + } + uint32 GetMaxDelay() const + { + return maxDelay; + } + void SetUnitTest(bool flag) + { + isUnitTest = flag; + } + +protected: + void Init(); + void CandidateToWaitingQueue(); + void WaitingQueueToReadyList(); + void InitInfoBeforeCompEStart(uint32 cycle, std::vector &traversalList); + void InitInfoBeforeCompLStart(std::vector &traversalList); + void UpdateInfoBeforeSelectNode(); + void SortReadyList(); + void UpdateEStart(DepNode &schedNode); + void UpdateInfoAfterSelectNode(DepNode &schedNode); + void UpdateNodesInReadyList(); + void UpdateAdvanceCycle(const DepNode &schedNode); + void CountUnitKind(const DepNode &depNode, std::array &unitKindCount) const; + void DumpWaitingQueue() const; + void DumpReadyList() const; + void DumpScheduledResult() const; + void DumpDelay() const; + void DumpEStartLStartOfAllNodes(); + void DumpDepNodeInfo(const BB &curBB, MapleVector &nodes, const std::string state) const; + void DumpReservation(const DepNode &depNode) const; + + void EraseNodeFromReadyList(const DepNode *depNode) + { + for (auto iter = readyList.begin(); iter != readyList.end(); ++iter) { + if (*iter == depNode) { + (void)readyList.erase(iter); + return; + } + } + } + MapleVector::iterator EraseIterFromReadyList(MapleVector::iterator depIter) + { + return readyList.erase(depIter); + } + + MapleVector::iterator EraseIterFromWaitingQueue(MapleVector::iterator depIter) + { + return waitingQueue.erase(depIter); + } + + // Default rank readyList function by delay heuristic, + // which uses delay as algorithm of computing priority + static bool DelayRankScheduleInsns(const DepNode *node1, const DepNode *node2) + { + // p as an acronym for priority + CompareDelay compareDelay; + int p1 = compareDelay(*node1, *node2); + if (p1 != 0) { + return p1 > 0; + } + + CompareDataCache compareDataCache; + int p2 = compareDataCache(*node1, *node2); + if (p2 != 0) { + return p2 > 0; + } + + CompareClassOfLastScheduledNode compareClassOfLSN(lastSchedInsnId); + int p3 = compareClassOfLSN(*node1, *node2); + if (p3 != 0) { + return p3 > 0; + } + + CompareSuccNodeSize compareSuccNodeSize; + int p4 = compareSuccNodeSize(*node1, *node2); + if (p4 != 0) { + return p4 > 0; + } + + CompareInsnID compareInsnId; + int p6 = compareInsnId(*node1, *node2); + if (p6 != 0) { + return p6 > 0; + } + + // default + return true; + } + + static bool CriticalPathRankScheduleInsns(const DepNode *node1, const DepNode *node2); + + MemPool &listSchedMp; + MapleAllocator listSchedAlloc; + CGFunc &cgFunc; + MAD *mad = nullptr; // CPU resources + CDGRegion *region = nullptr; // the current region + CDGNode *curCDGNode = nullptr; // the current scheduled BB + CommonScheduleInfo *commonSchedInfo = nullptr; // common scheduling info that prepared by other scheduler + // The function ptr that computes instruction priority based on heuristic rules, + // list-scheduler provides default implementations and supports customization by other schedulers + SchedRankFunctor rankScheduleInsns = nullptr; + bool doDelayHeuristics = true; // true: compute delay; false: compute eStart & lStart + std::string phaseName; // for dumping log + // A node is moved from [candidates] to [waitingQueue] when it's all data dependency are met + MapleVector waitingQueue; + // A node is moved from [waitingQueue] to [readyList] when resources required by it are free and + // estart-cycle <= curr-cycle + MapleVector readyList; + uint32 currCycle = 0; // Simulates the CPU clock during scheduling + uint32 advancedCycle = 0; // Using after an instruction is scheduled, record its execution cycles + uint32 maxEStart = 0; // Update when the eStart of depNodes are recalculated + uint32 maxLStart = 0; // Ideal total cycles that is equivalent to critical path length + uint32 maxDelay = 0; // Ideal total cycles that is equivalent to max delay + uint32 scheduledNodeNum = 0; // The number of instructions that are scheduled + static uint32 lastSchedInsnId; // Last scheduled insnId, for heuristic function + DepNode *lastSchedNode = nullptr; // Last scheduled node + bool isUnitTest = false; +}; +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_LIST_SCHEDULER_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/local_schedule.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/local_schedule.h new file mode 100644 index 0000000000..684ad658fa --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/local_schedule.h @@ -0,0 +1,52 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_LOCAL_SCHEDULE_H +#define MAPLEBE_INCLUDE_CG_LOCAL_SCHEDULE_H + +#include "base_schedule.h" + +namespace maplebe { +#define LOCAL_SCHEDULE_DUMP CG_DEBUG_FUNC(cgFunc) + +class LocalSchedule : public BaseSchedule { +public: + LocalSchedule(MemPool &mp, CGFunc &f, ControlDepAnalysis &cdAna, DataDepAnalysis &dda) + : BaseSchedule(mp, f, cdAna), intraDDA(dda) + { + } + ~LocalSchedule() override = default; + + std::string PhaseName() const + { + return "localschedule"; + } + void Run() override; + bool CheckCondition(CDGRegion ®ion) const; + void DoLocalScheduleForRegion(CDGRegion ®ion); + using BaseSchedule::DoLocalSchedule; + void DoLocalSchedule(CDGNode &cdgNode); + +protected: + void InitInCDGNode(CDGNode &cdgNode); + virtual void FinishScheduling(CDGNode &cdgNode) = 0; + + DataDepAnalysis &intraDDA; +}; + +MAPLE_FUNC_PHASE_DECLARE_BEGIN(CgLocalSchedule, maplebe::CGFunc) +MAPLE_FUNC_PHASE_DECLARE_END +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_LOCAL_SCHEDULE_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/loop.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/loop.h index 7d28a4f2c3..a21a5b39c6 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/loop.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/loop.h @@ -16,12 +16,138 @@ #ifndef MAPLEBE_INCLUDE_CG_LOOP_H #define MAPLEBE_INCLUDE_CG_LOOP_H +#include "cgfunc.h" #include "cg_phase.h" +#include "cg_dominance.h" #include "cgbb.h" #include "insn.h" #include "maple_phase.h" namespace maplebe { +class LoopDesc { +public: + struct LoopDescCmp { + bool operator()(const LoopDesc *loop1, const LoopDesc *loop2) const + { + CHECK_NULL_FATAL(loop1); + CHECK_NULL_FATAL(loop2); + return (loop1->GetHeader().GetId() < loop2->GetHeader().GetId()); + } + }; + + LoopDesc(MapleAllocator &allocator, BB &head) + : alloc(allocator), + header(head), + loopBBs(alloc.Adapter()), + exitBBs(alloc.Adapter()), + backEdges(alloc.Adapter()), + childLoops(alloc.Adapter()) + { + } + + ~LoopDesc() = default; + + void Dump() const; + + BB &GetHeader() + { + return header; + } + + const BB &GetHeader() const + { + return header; + } + + // get all bbIds in the loop + const MapleSet &GetLoopBBs() const + { + return loopBBs; + } + + // check whether the BB exists in the current loop + bool Has(const BB &bb) const + { + return loopBBs.find(bb.GetId()) != loopBBs.end(); + } + + void InsertLoopBBs(const BB &bb) + { + (void)loopBBs.insert(bb.GetId()); + } + + const MapleSet &GetExitBBs() const + { + return exitBBs; + } + + void InsertExitBBs(const BB &bb) + { + (void)exitBBs.insert(bb.GetId()); + } + + void InsertBackEdges(const BB &bb) + { + (void)backEdges.insert(bb.GetId()); + } + + // check whether from->to is the back edge of the current loop + bool IsBackEdge(const BB &from, const BB &to) const + { + return (to.GetId() == header.GetId()) && (backEdges.find(from.GetId()) != backEdges.end()); + } + + // get the BBId of all back edges + const MapleSet &GetBackEdges() const + { + return backEdges; + } + + const LoopDesc *GetParentLoop() const + { + return parentLoop; + } + + LoopDesc *GetParentLoop() + { + return parentLoop; + } + + void SetParentLoop(LoopDesc &loop) + { + parentLoop = &loop; + } + + uint32 GetNestDepth() const + { + return nestDepth; + } + + void SetNestDepth(uint32 depth) + { + nestDepth = depth; + } + + const MapleSet &GetChildLoops() const + { + return childLoops; + } + + void InsertChildLoops(LoopDesc &loop) + { + (void)childLoops.insert(&loop); + } + +private: + MapleAllocator &alloc; + BB &header; // BB's header + MapleSet loopBBs; // BBs in loop + MapleSet exitBBs; // loop exit BBs + MapleSet backEdges; // loop back edges, backBB -> headBB + LoopDesc *parentLoop = nullptr; // points to its closest nesting loop + uint32 nestDepth = 1; // the nesting depth + MapleSet childLoops; +}; class LoopHierarchy { public: struct HeadIDCmp { @@ -286,7 +412,96 @@ struct CGFuncLoopCmp { } }; +class LoopAnalysis : public AnalysisResult { +public: + LoopAnalysis(CGFunc &func, MemPool &memPool, DomAnalysis &domInfo) + : AnalysisResult(&memPool), + alloc(&memPool), + cgFunc(func), + dom(domInfo), + loops(alloc.Adapter()), + bbLoopParent(cgFunc.GetAllBBSize(), nullptr, alloc.Adapter()) + { + } + + ~LoopAnalysis() override = default; + + const MapleVector &GetLoops() const + { + return loops; + } + + MapleVector &GetLoops() + { + return loops; + } + + // get the loop to which the BB belong, null -> not in loop. + LoopDesc *GetBBLoopParent(BBID bbID) const + { + if (bbID >= bbLoopParent.size()) { + return nullptr; + } + return bbLoopParent[bbID]; + } + + // check whether from->to is the back edge + bool IsBackEdge(const BB &from, const BB &to) const + { + auto *loop = GetBBLoopParent(to.GetId()); + if (loop && loop->IsBackEdge(from, to)) { + return true; + } + loop = GetBBLoopParent(from.GetId()); + return loop && loop->IsBackEdge(from, to); + } + + void Analysis(); + + void Dump() const + { + LogInfo::MapleLogger() << "Dump LoopAnalysis Result For Func " << cgFunc.GetName() << ":\n"; + for (const auto *loop : loops) { + loop->Dump(); + } + for (BBID bbId = 0; bbId < bbLoopParent.size(); ++bbId) { + if (bbLoopParent[bbId] == nullptr) { + continue; + } + LogInfo::MapleLogger() << "BB " << bbId << " in loop " << bbLoopParent[bbId]->GetHeader().GetId() << "\n"; + } + } + + bool IsLoopHeaderBB(const BB &bb) const + { + if (GetBBLoopParent(bb.GetId()) == nullptr) { + return false; + } else if (GetBBLoopParent(bb.GetId())->GetHeader().GetId() == bb.GetId()) { + return true; + } + return false; + } + +private: + MapleAllocator alloc; + CGFunc &cgFunc; + DomAnalysis &dom; + MapleVector loops; // all loops in func + MapleVector bbLoopParent; // gives closest nesting loop for each bb + + LoopDesc *GetOrCreateLoopDesc(BB &headBB); + void SetLoopParent4BB(const BB &bb, LoopDesc &loopDesc); + void SetExitBBs(LoopDesc &loop) const; + void ProcessBB(BB &bb); +}; + MAPLE_FUNC_PHASE_DECLARE_BEGIN(CgLoopAnalysis, maplebe::CGFunc); +LoopAnalysis *GetResult() +{ + return loop; +} +LoopAnalysis *loop = nullptr; +OVERRIDE_DEPENDENCE MAPLE_FUNC_PHASE_DECLARE_END } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/mplad_bypass_define.def b/ecmascript/compiler/codegen/maple/maple_be/include/cg/mplad_bypass_define.def index 1f6022e410..ea3ebcbdc3 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/mplad_bypass_define.def +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/mplad_bypass_define.def @@ -11,6 +11,7 @@ ADDBYPASS(kLtShiftReg, kLtAluShiftReg, 1); ADDBYPASS(kLtAlu, kLtAlu, 1); ADDBYPASS(kLtAluShift, kLtAlu, 1); ADDBYPASS(kLtAluShiftReg, kLtAlu, 1); +ADDBYPASS(kLtAluExtr, kLtAlu, 1); ADDALUSHIFTBYPASS(kLtAlu, kLtAluShift, 1); ADDALUSHIFTBYPASS(kLtAluShift, kLtAluShift, 1); ADDALUSHIFTBYPASS(kLtAluShiftReg, kLtAluShift, 1); @@ -19,14 +20,6 @@ ADDALUSHIFTBYPASS(kLtAlu, kLtAluShiftReg, 1); ADDALUSHIFTBYPASS(kLtAluShift, kLtAluShiftReg, 1); ADDALUSHIFTBYPASS(kLtAluShiftReg, kLtAluShiftReg, 1); ADDALUSHIFTBYPASS(kLtAluExtr, kLtAluShiftReg, 1); -ADDBYPASS(kLtAlu, kLtAluShift, 1); -ADDBYPASS(kLtAluShift, kLtAluShift, 1); -ADDBYPASS(kLtAluShiftReg, kLtAluShift, 1); -ADDBYPASS(kLtAluExtr, kLtAluShift, 1); -ADDBYPASS(kLtAlu, kLtAluShiftReg, 1); -ADDBYPASS(kLtAluShift, kLtAluShiftReg, 1); -ADDBYPASS(kLtAluShiftReg, kLtAluShiftReg, 1); -ADDBYPASS(kLtAluExtr, kLtAluShiftReg, 1); ADDBYPASS(kLtAlu, kLtAluExtr, 2); ADDBYPASS(kLtAluShift, kLtAluExtr, 2); ADDBYPASS(kLtAluShiftReg, kLtAluExtr, 2); @@ -52,7 +45,7 @@ ADDBYPASS(kLtLoad1, kLtAluShiftReg, 3); ADDBYPASS(kLtLoad1, kLtAluExtr, 3); ADDBYPASS(kLtLoad1, kLtShift, 3); ADDBYPASS(kLtLoad1, kLtShiftReg, 3); -ADDBYPASS(kLtLoad2, kLtAlu, 3); +ADDBYPASS(kLtLoad2, kLtAlu, 2); ADDSTOREADDRBYPASS(kLtAlu, kLtStore1, 0); ADDSTOREADDRBYPASS(kLtAlu, kLtStore2, 0); ADDSTOREADDRBYPASS(kLtAlu, kLtStore3plus, 0); @@ -107,12 +100,24 @@ ADDBYPASS(kLtShift, kLtBranch, 0); ADDBYPASS(kLtShiftReg, kLtBranch, 0); ADDACCUMULATORBYPASS(kLtFpalu, kLtFpmac, 1); ADDACCUMULATORBYPASS(kLtFpmul, kLtFpmac, 1); +ADDACCUMULATORBYPASS(kLtFpmac, kLtFpmac, 1); ADDACCUMULATORBYPASS(kLtR2f, kLtFpmac, 1); -ADDACCUMULATORBYPASS(kLtR2fCvt, kLtFpmac, 1); -ADDACCUMULATORBYPASS(kLtFconst, kLtFpmac, 1); -ADDBYPASS(kLtFLoad64, kLtFpmac, 1); -ADDBYPASS(kLtFLoadMany, kLtFpmac, 1); -ADDACCUMULATORBYPASS(kLtFpmac, kLtFpmac, 4); +ADDACCUMULATORBYPASS(kLtFLoad64, kLtFpmac, 1); +ADDACCUMULATORBYPASS(kLtFLoadMany, kLtFpmac, 1); +ADDBYPASS(kLtFpalu, kLtFpalu, 4); +ADDBYPASS(kLtFpalu, kLtFpmul, 4); +ADDBYPASS(kLtFpalu, kLtFpmac, 4); +ADDBYPASS(kLtFpalu, kLtAdvsimdDivS, 4); +ADDBYPASS(kLtFpalu, kLtAdvsimdDivD, 4); +ADDBYPASS(kLtFpalu, kLtAdvsimdDivSQ, 4); +ADDBYPASS(kLtFpalu, kLtAdvsimdDivdQ, 4); +ADDBYPASS(kLtFpmul, kLtFpalu, 4); +ADDBYPASS(kLtFpmul, kLtFpmul, 4); +ADDBYPASS(kLtFpmul, kLtFpmac, 4); +ADDBYPASS(kLtFpmul, kLtAdvsimdDivS, 4); +ADDBYPASS(kLtFpmul, kLtAdvsimdDivD, 4); +ADDBYPASS(kLtFpmul, kLtAdvsimdDivSQ, 4); +ADDBYPASS(kLtFpmul, kLtAdvsimdDivdQ, 4); ADDBYPASS(kLtCryptoAese, kLtCryptoAesmc, 0); ADDBYPASS(kLtShiftReg, kLtClinit, 1); ADDBYPASS(kLtAlu, kLtClinit, 2); @@ -121,8 +126,8 @@ ADDBYPASS(kLtAluExtr, kLtClinit, 2); ADDBYPASS(kLtMul, kLtClinit, 3); ADDBYPASS(kLtLoad1, kLtClinit, 3); ADDBYPASS(kLtAlu, kLtClinit, 13); -ADDSTOREADDRBYPASS(kLtClinit, kLtStore1, 11); -ADDSTOREADDRBYPASS(kLtClinit, kLtStore3plus, 11); +ADDBYPASS(kLtClinit, kLtStore1, 11); +ADDBYPASS(kLtClinit, kLtStore3plus, 11); ADDBYPASS(kLtClinit, kLtR2f, 11); ADDBYPASS(kLtClinit, kLtR2fCvt, 13); ADDBYPASS(kLtShiftReg, kLtAdrpLdr, 1); @@ -132,12 +137,12 @@ ADDBYPASS(kLtAluExtr, kLtAdrpLdr, 2); ADDBYPASS(kLtMul, kLtAdrpLdr, 3); ADDBYPASS(kLtLoad1, kLtAdrpLdr, 3); ADDBYPASS(kLtAdrpLdr, kLtAlu, 5); -ADDSTOREADDRBYPASS(kLtAdrpLdr, kLtStore1, 3); -ADDSTOREADDRBYPASS(kLtAdrpLdr, kLtStore3plus, 3); +ADDBYPASS(kLtAdrpLdr, kLtStore1, 3); +ADDBYPASS(kLtAdrpLdr, kLtStore3plus, 3); ADDBYPASS(kLtAdrpLdr, kLtR2f, 3); ADDBYPASS(kLtAdrpLdr, kLtR2fCvt, 5); ADDBYPASS(kLtClinitTail, kLtAlu, 7); -ADDSTOREADDRBYPASS(kLtClinitTail, kLtStore1, 5); -ADDSTOREADDRBYPASS(kLtClinitTail, kLtStore3plus, 5); +ADDBYPASS(kLtClinitTail, kLtStore1, 5); +ADDBYPASS(kLtClinitTail, kLtStore3plus, 5); ADDBYPASS(kLtClinitTail, kLtR2f, 5); ADDBYPASS(kLtClinitTail, kLtR2fCvt, 7); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/schedule_heuristic.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/schedule_heuristic.h new file mode 100644 index 0000000000..edf5a21e45 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/schedule_heuristic.h @@ -0,0 +1,277 @@ +/* + * 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. + */ +#ifndef MAPLEBE_INCLUDE_CG_SCHEDULE_HEURISTIC_H +#define MAPLEBE_INCLUDE_CG_SCHEDULE_HEURISTIC_H + +#include "deps.h" + +// Define a series of priority comparison function objects. +// @ReturnValue: +// - positive: node1 has higher priority +// - negative: node2 has higher priority +// - zero: node1 == node2 +// And ensure the sort is stable. +namespace maplebe { + +// Prefer max delay priority +class CompareDelay { +public: + int operator()(const DepNode &node1, const DepNode &node2) const + { + return static_cast(node1.GetDelay() - node2.GetDelay()); + } +}; + +// To make better use of cpu cache prefetch: +// (1) If both insns are memory operation and have same base address (same base register) and same access +// byte, prefer lowest offset. +// The following (2) and (3) are not implemented currently, and can be optimized in the future: +// (2) If one insn is store and the other is not memory operation, prefer non-memory-insn scheduled before store. +// (3) If one insn is load and the other is not memory operation, prefer load scheduled before non-memory-insn. +class CompareDataCache { +public: + int operator()(const DepNode &node1, const DepNode &node2) + { + Insn *insn1 = node1.GetInsn(); + ASSERT_NOT_NULL(insn1); + Insn *insn2 = node2.GetInsn(); + ASSERT_NOT_NULL(insn2); + // Exclude adrp + if (insn1->IsMemAccess() && insn2->IsMemAccess()) { + auto *memOpnd1 = static_cast(insn1->GetMemOpnd()); + auto *memOpnd2 = static_cast(insn2->GetMemOpnd()); + // Need the same access byte + if ((insn1->IsLoadStorePair() && !insn2->IsLoadStorePair()) || + (!insn1->IsLoadStorePair() && insn2->IsLoadStorePair())) { + return 0; + } + if (memOpnd1 != nullptr && memOpnd2 != nullptr) { // Exclude load address + if (memOpnd1->GetAddrMode() == MemOperand::kAddrModeBOi && + memOpnd2->GetAddrMode() == MemOperand::kAddrModeBOi) { + RegOperand *baseOpnd1 = memOpnd1->GetBaseRegister(); + ASSERT_NOT_NULL(baseOpnd1); + RegOperand *baseOpnd2 = memOpnd2->GetBaseRegister(); + ASSERT_NOT_NULL(baseOpnd2); + if (baseOpnd1->GetRegisterNumber() == baseOpnd2->GetRegisterNumber()) { + ImmOperand *ofstOpnd1 = memOpnd1->GetOffsetOperand(); + ImmOperand *ofstOpnd2 = memOpnd2->GetOffsetOperand(); + if (ofstOpnd1 == nullptr && ofstOpnd2 == nullptr) { + return 0; + } else if (ofstOpnd1 == nullptr) { + return 1; + } else if (ofstOpnd2 == nullptr) { + return -1; + } else { + return static_cast(ofstOpnd2->GetValue() - ofstOpnd1->GetValue()); + } + } + } else { + // Schedule load before store + if ((insn1->IsLoad() || insn1->IsLoadPair()) && (insn2->IsStore() || insn2->IsStorePair())) { + return 1; + } else if ((insn2->IsLoad() || insn2->IsLoadPair()) && (insn1->IsStore() || insn1->IsStorePair())) { + return -1; + } + } + } + } else if (enableIrrelevant && insn1->IsMemAccess()) { + return (insn1->IsLoad() || insn1->IsLoadPair()) ? 1 : -1; + } else if (enableIrrelevant && insn2->IsMemAccess()) { + return (insn2->IsLoad() || insn2->IsLoadPair()) ? -1 : 1; + } + return 0; + } + + bool enableIrrelevant = false; +}; + +// Prefer the class of the edges of two insn and last scheduled insn with the highest class number: +// 1. true dependency +// 2. anti/output dependency +// 3. the rest of the dependency +// 4. independent of last scheduled insn +class CompareClassOfLastScheduledNode { +public: + explicit CompareClassOfLastScheduledNode(uint32 lsid) : lastSchedInsnId(lsid) {} + ~CompareClassOfLastScheduledNode() = default; + + int operator()(const DepNode &node1, const DepNode &node2) const + { + DepType type1 = kDependenceTypeNone; + DepType type2 = kDependenceTypeNone; + for (auto *predLink : node1.GetPreds()) { + DepNode &predNode = predLink->GetFrom(); + if (lastSchedInsnId != 0 && predNode.GetInsn()->GetId() == lastSchedInsnId) { + type1 = predLink->GetDepType(); + } + } + for (auto *predLink : node2.GetPreds()) { + DepNode &predNode = predLink->GetFrom(); + if (lastSchedInsnId != 0 && predNode.GetInsn()->GetId() == lastSchedInsnId) { + type2 = predLink->GetDepType(); + } + } + CHECK_FATAL(type1 != kDependenceTypeSeparator && type2 != kDependenceTypeSeparator, "invalid dependency type"); + + uint32 typeClass1 = 0; + switch (type1) { + case kDependenceTypeTrue: + typeClass1 = kNumOne; + break; + case kDependenceTypeAnti: + case kDependenceTypeOutput: + typeClass1 = kNumTwo; + break; + case kDependenceTypeSeparator: + CHECK_FATAL(false, "invalid dependency type"); + break; + case kDependenceTypeNone: + typeClass1 = kNumFour; + break; + default: + typeClass1 = kNumThree; + break; + } + + uint32 typeClass2 = 0; + switch (type2) { + case kDependenceTypeTrue: + typeClass2 = kNumOne; + break; + case kDependenceTypeAnti: + case kDependenceTypeOutput: + typeClass2 = kNumTwo; + break; + case kDependenceTypeSeparator: + CHECK_FATAL(false, "invalid dependency type"); + case kDependenceTypeNone: + typeClass2 = kNumFour; + break; + default: + typeClass2 = kNumThree; + break; + } + + return static_cast(typeClass1 - typeClass2); + } + + uint32 lastSchedInsnId = 0; +}; + +// Prefer min eStart +class CompareEStart { +public: + int operator()(const DepNode &node1, const DepNode &node2) const + { + return static_cast(node2.GetEStart() - node1.GetEStart()); + } +}; + +// Prefer min lStart +class CompareLStart { +public: + int operator()(const DepNode &node1, const DepNode &node2) const + { + return static_cast(node2.GetLStart() - node1.GetLStart()); + } +}; + +// Prefer max cost of insn +class CompareCost { +public: + int operator()(const DepNode &node1, const DepNode &node2) + { + return (node1.GetReservation()->GetLatency() - node2.GetReservation()->GetLatency()); + } +}; + +// Prefer using more unit kind +class CompareUnitKindNum { +public: + explicit CompareUnitKindNum(uint32 maxUnitIndex) : maxUnitIdx(maxUnitIndex) {} + + int operator()(const DepNode &node1, const DepNode &node2) const + { + bool use1 = IsUseUnitKind(node1); + bool use2 = IsUseUnitKind(node2); + if ((use1 && use2) || (!use1 && !use2)) { + return 0; + } else if (!use2) { + return 1; + } else { + return -1; + } + } + +private: + // Check if a node use a specific unit kind + bool IsUseUnitKind(const DepNode &depNode) const + { + uint32 unitKind = depNode.GetUnitKind(); + auto idx = static_cast(__builtin_ffs(static_cast(unitKind))); + while (idx != 0) { + DEBUG_ASSERT(maxUnitIdx < kUnitKindLast, "invalid unit index"); + if (idx == maxUnitIdx) { + return true; + } + unitKind &= ~(1u << (idx - 1u)); + idx = static_cast(__builtin_ffs(static_cast(unitKind))); + } + return false; + } + + uint32 maxUnitIdx = 0; +}; + +// Prefer slot0 +class CompareSlotType { +public: + int operator()(const DepNode &node1, const DepNode &node2) + { + SlotType slotType1 = node1.GetReservation()->GetSlot(); + SlotType slotType2 = node2.GetReservation()->GetSlot(); + if (slotType1 == kSlots) { + slotType1 = kSlot0; + } + if (slotType2 == kSlots) { + slotType2 = kSlot0; + } + return (slotType2 - slotType1); + } +}; + +// Prefer more succNodes +class CompareSuccNodeSize { +public: + int operator()(const DepNode &node1, const DepNode &node2) const + { + return static_cast(node1.GetSuccs().size() - node2.GetSuccs().size()); + } +}; + +// Default order +class CompareInsnID { +public: + int operator()(const DepNode &node1, const DepNode &node2) + { + Insn *insn1 = node1.GetInsn(); + DEBUG_ASSERT(insn1 != nullptr, "get insn from depNode failed"); + Insn *insn2 = node2.GetInsn(); + DEBUG_ASSERT(insn2 != nullptr, "get insn from depNode failed"); + return static_cast(insn2->GetId() - insn1->GetId()); + } +}; +} // namespace maplebe +#endif // MAPLEBE_INCLUDE_CG_SCHEDULE_HEURISTIC_H diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/ad/mad.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/ad/mad.cpp index 35af78d546..a19d2b07b5 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/ad/mad.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/ad/mad.cpp @@ -165,6 +165,7 @@ MAD::~MAD() for (auto *bypass : bypassVector) { delete bypass; } + bypassVector.clear(); } } allUnits.clear(); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_data_dep_base.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_data_dep_base.cpp new file mode 100644 index 0000000000..ca661bede0 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_data_dep_base.cpp @@ -0,0 +1,620 @@ +/* + * 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. + */ +#include "aarch64_cg.h" +#ifndef ONLY_C +#include "pressure.h" +#endif +#include "cg_irbuilder.h" +#include "aarch64_mem_reference.h" +#include "aarch64_data_dep_base.h" + +namespace maplebe { +/** It is a yield point if loading from a dedicated + * register holding polling page address: + * ldr wzr, [RYP] + */ +static bool IsYieldPoint(const Insn &insn) +{ + if (insn.IsLoad() && !insn.IsLoadLabel()) { + auto mem = static_cast(insn.GetMemOpnd()); + return (mem != nullptr && mem->GetBaseRegister() != nullptr && + mem->GetBaseRegister()->GetRegisterNumber() == RYP); + } + return false; +} + +static bool IsLazyLoad(MOperator op) +{ + return (op == MOP_lazy_ldr) || (op == MOP_lazy_ldr_static) || (op == MOP_lazy_tail); +} + +bool AArch64DataDepBase::IsFrameReg(const RegOperand &opnd) const +{ + return (opnd.GetRegisterNumber() == RFP) || (opnd.GetRegisterNumber() == RSP); +} + +void AArch64DataDepBase::InitCDGNodeDataInfo(MemPool &mp, MapleAllocator &alloc, CDGNode &cdgNode) +{ + uint32 maxRegNum = (cgFunc.IsAfterRegAlloc() ? AArch64reg::kAllRegNum : cgFunc.GetMaxVReg()); + cdgNode.InitDataDepInfo(mp, alloc, maxRegNum); +} + +Insn *AArch64DataDepBase::GetMemBaseDefInsn(const Insn &memInsn) const +{ + auto *memOpnd = static_cast(memInsn.GetMemOpnd()); + if (memOpnd == nullptr) { + return nullptr; + } + RegOperand *baseOpnd = memOpnd->GetBaseRegister(); + if (baseOpnd == nullptr) { + return nullptr; + } + return curCDGNode->GetLatestDefInsn(baseOpnd->GetRegisterNumber()); +} + +void AArch64DataDepBase::BuildDepsForMemDefCommon(Insn &insn, CDGNode &cdgNode) +{ + // Stack memory + // Build anti dependency + MapleVector &stackUses = cdgNode.GetStackUseInsns(); + for (auto *stackUse : stackUses) { + // the insn may be stack memory or heap use memory + if (AArch64MemReference::NeedBuildMemoryDependency(*stackUse, insn, GetMemBaseDefInsn(*stackUse), + GetMemBaseDefInsn(insn), kDependenceTypeAnti)) { + AddDependence(*stackUse->GetDepNode(), *insn.GetDepNode(), kDependenceTypeAnti); + } + } + // Build output dependency + MapleVector &stackDefs = cdgNode.GetStackDefInsns(); + for (auto *stackDef : stackDefs) { + // the insn may be stack memory or heap use memory + if (AArch64MemReference::NeedBuildMemoryDependency(*stackDef, insn, GetMemBaseDefInsn(*stackDef), + GetMemBaseDefInsn(insn), kDependenceTypeOutput)) { + AddDependence(*stackDef->GetDepNode(), *insn.GetDepNode(), kDependenceTypeOutput); + } + } + // Heap memory + // Build anti dependency + MapleVector &heapUses = cdgNode.GetHeapUseInsns(); + for (auto *heapUse : heapUses) { + if (AArch64MemReference::NeedBuildMemoryDependency(*heapUse, insn, GetMemBaseDefInsn(*heapUse), + GetMemBaseDefInsn(insn), kDependenceTypeAnti)) { + AddDependence(*heapUse->GetDepNode(), *insn.GetDepNode(), kDependenceTypeAnti); + } + } + // Build output dependency + MapleVector &heapDefs = cdgNode.GetHeapDefInsns(); + for (auto *heapDef : heapDefs) { + if (AArch64MemReference::NeedBuildMemoryDependency(*heapDef, insn, GetMemBaseDefInsn(*heapDef), + GetMemBaseDefInsn(insn), kDependenceTypeOutput)) { + AddDependence(*heapDef->GetDepNode(), *insn.GetDepNode(), kDependenceTypeOutput); + } + } +} + +void AArch64DataDepBase::BuildDepsForMemUseCommon(Insn &insn, CDGNode &cdgNode) +{ + // Build dependency for stack memory access + MapleVector &stackDefs = cdgNode.GetStackDefInsns(); + for (auto *stackDef : stackDefs) { + // The insn may be stack memory or heap memory + if ((stackDef->IsCall() && stackDef->GetMachineOpcode() != MOP_tls_desc_call) || + AArch64MemReference::NeedBuildMemoryDependency(*stackDef, insn, GetMemBaseDefInsn(*stackDef), + GetMemBaseDefInsn(insn), kDependenceTypeTrue)) { + AddDependence(*stackDef->GetDepNode(), *insn.GetDepNode(), kDependenceTypeTrue); + } + } + // Build dependency for heap memory access + MapleVector &heapDefs = cdgNode.GetHeapDefInsns(); + for (auto *heapDef : heapDefs) { + if (AArch64MemReference::NeedBuildMemoryDependency(*heapDef, insn, GetMemBaseDefInsn(*heapDef), + GetMemBaseDefInsn(insn), kDependenceTypeTrue)) { + AddDependence(*heapDef->GetDepNode(), *insn.GetDepNode(), kDependenceTypeTrue); + } + } +} + +// Build data dependence of symbol memory access. +// Memory accesses with symbol must be a heap memory access. +void AArch64DataDepBase::BuildDepsAccessStImmMem(Insn &insn) +{ + for (auto *heapDef : curCDGNode->GetHeapDefInsns()) { + if (AArch64MemReference::NeedBuildMemoryDependency(*heapDef, insn, GetMemBaseDefInsn(*heapDef), + GetMemBaseDefInsn(insn), kDependenceTypeTrue)) { + AddDependence(*heapDef->GetDepNode(), *insn.GetDepNode(), kDependenceTypeMemAccess); + } + } + + curCDGNode->AddHeapUseInsn(&insn); + + // Build dependency for membar insn + Insn *membarInsn = curCDGNode->GetMembarInsn(); + if (membarInsn != nullptr) { + AddDependence(*membarInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeMembar); + } +} + +// Build data dependence of memory bars instructions +void AArch64DataDepBase::BuildDepsMemBar(Insn &insn) +{ + if (isIntra || curRegion->GetRegionNodeSize() == 1 || curRegion->GetRegionRoot() == curCDGNode) { + AddDependence4InsnInVectorByTypeAndCmp(curCDGNode->GetStackUseInsns(), insn, kDependenceTypeMembar); + AddDependence4InsnInVectorByTypeAndCmp(curCDGNode->GetHeapUseInsns(), insn, kDependenceTypeMembar); + AddDependence4InsnInVectorByTypeAndCmp(curCDGNode->GetStackDefInsns(), insn, kDependenceTypeMembar); + AddDependence4InsnInVectorByTypeAndCmp(curCDGNode->GetHeapDefInsns(), insn, kDependenceTypeMembar); + } else if (curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), true, kDependenceTypeMembar, kStackUses); + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), true, kDependenceTypeMembar, kHeapUses); + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), true, kDependenceTypeMembar, kStackDefs); + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), true, kDependenceTypeMembar, kHeapDefs); + } + curCDGNode->SetMembarInsn(&insn); +} + +// Build data dependence of stack memory and heap memory read: +// for memOpnd, do not build the true dependency, and identify it by a special mem dependency. +void AArch64DataDepBase::BuildDepsUseMem(Insn &insn, MemOperand &memOpnd) +{ + memOpnd.SetAccessSize(insn.GetMemoryByteSize()); + + if (isIntra || curRegion->GetRegionNodeSize() == 1 || curRegion->GetRegionRoot() == curCDGNode) { + BuildDepsForMemUseCommon(insn, *curCDGNode); + } else if (curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockMemDefUseDependency(*insn.GetDepNode(), false); + } + + // Record mem insn + RegOperand *baseRegister = memOpnd.GetBaseRegister(); + if ((baseRegister != nullptr && IsFrameReg(*baseRegister)) || memOpnd.IsStackMem()) { + curCDGNode->AddStackUseInsn(&insn); + } else { + curCDGNode->AddHeapUseInsn(&insn); + } + + // Build dependency for membar insn + Insn *membarInsn = curCDGNode->GetMembarInsn(); + if (membarInsn != nullptr) { + AddDependence(*membarInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeMembar); + } else if (!isIntra && curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeMembar, kMembar); + } +} + +// Build data dependency of stack memory and heap memory definitions +// We do not need build output dependence for write-write, because of transitivity: +// e.g. +// write1 [mem1] --- +// | access | +// read [mem1] X (transitivity) +// | anti | +// write2 [mem1] --- +void AArch64DataDepBase::BuildDepsDefMem(Insn &insn, MemOperand &memOpnd) +{ + RegOperand *baseRegister = memOpnd.GetBaseRegister(); + ASSERT_NOT_NULL(baseRegister); + memOpnd.SetAccessSize(insn.GetMemoryByteSize()); + + if (isIntra || curRegion->GetRegionNodeSize() == 1 || curRegion->GetRegionRoot() == curCDGNode) { + BuildDepsForMemDefCommon(insn, *curCDGNode); + + // Memory definition can not across may-throw insns for java + if (cgFunc.GetMirModule().IsJavaModule()) { + MapleVector &mayThrows = curCDGNode->GetMayThrowInsns(); + AddDependence4InsnInVectorByType(mayThrows, insn, kDependenceTypeThrow); + } + } else if (curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockMemDefUseDependency(*insn.GetDepNode(), true); + + if (cgFunc.GetMirModule().IsJavaModule()) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeThrow, kMayThrows); + } + } + + if (baseRegister->GetRegisterNumber() == RSP) { + Insn *lastCallInsn = curCDGNode->GetLastCallInsn(); + if (lastCallInsn != nullptr && lastCallInsn->GetMachineOpcode() != MOP_tls_desc_call) { + // Build a dependence between stack passed arguments and call + AddDependence(*lastCallInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeControl); + } else if (!isIntra && curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeControl, kLastCall); + } + } + + // Build membar dependence + Insn *membarInsn = curCDGNode->GetMembarInsn(); + if (membarInsn != nullptr) { + AddDependence(*membarInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeMembar); + } else if (!isIntra && curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeMembar, kMembar); + } + + // Update cur cdgNode info of def-memory insn + if (IsFrameReg(*baseRegister) || memOpnd.IsStackMem()) { + curCDGNode->AddStackDefInsn(&insn); + } else { + curCDGNode->AddHeapDefInsn(&insn); + } +} + +// Build dependence of call instructions. +// caller-saved physical registers will be defined by a call instruction. +// also a conditional register may be modified by a call. +void AArch64DataDepBase::BuildCallerSavedDeps(Insn &insn) +{ + // Build anti dependence and output dependence + for (uint32 i = R0; i <= R9; ++i) { + BuildDepsDefReg(insn, i); + } + for (uint32 i = V0; i <= V7; ++i) { + BuildDepsDefReg(insn, i); + } + if (!beforeRA) { + for (uint32 i = R9; i <= R18; ++i) { + BuildDepsDefReg(insn, i); + } + for (uint32 i = RLR; i <= RSP; ++i) { + BuildDepsUseReg(insn, i); + } + for (uint32 i = V16; i <= V31; ++i) { + BuildDepsDefReg(insn, i); + } + } + /* For condition operand, such as NE, EQ, and so on. */ + if (cgFunc.GetRflag() != nullptr) { + BuildDepsDefReg(insn, kRFLAG); + } +} + +// Some insns may dirty all stack memory, such as "bl MCC_InitializeLocalStackRef" +void AArch64DataDepBase::BuildDepsDirtyStack(Insn &insn) +{ + /* Build anti dependence */ + MapleVector &stackUses = curCDGNode->GetStackUseInsns(); + AddDependence4InsnInVectorByType(stackUses, insn, kDependenceTypeAnti); + /* Build output dependence */ + MapleVector &stackDefs = curCDGNode->GetStackDefInsns(); + AddDependence4InsnInVectorByType(stackDefs, insn, kDependenceTypeOutput); + curCDGNode->AddStackDefInsn(&insn); +} + +// Some call insns may use all stack memory, such as "bl MCC_CleanupLocalStackRef_NaiveRCFast" +void AArch64DataDepBase::BuildDepsUseStack(Insn &insn) +{ + /* Build true dependence */ + MapleVector &stackDefs = curCDGNode->GetStackDefInsns(); + AddDependence4InsnInVectorByType(stackDefs, insn, kDependenceTypeTrue); +} + +// Some insns may dirty all heap memory, such as a call insn +void AArch64DataDepBase::BuildDepsDirtyHeap(Insn &insn) +{ + // Build anti dependence + MapleVector &heapUses = curCDGNode->GetHeapUseInsns(); + AddDependence4InsnInVectorByType(heapUses, insn, kDependenceTypeAnti); + // Build output dependence + MapleVector &heapDefs = curCDGNode->GetHeapDefInsns(); + AddDependence4InsnInVectorByType(heapDefs, insn, kDependenceTypeOutput); + + Insn *membarInsn = curCDGNode->GetMembarInsn(); + if (membarInsn != nullptr) { + AddDependence(*membarInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeMembar); + } + curCDGNode->AddHeapDefInsn(&insn); +} + +// Analysis live-in registers in catch bb and cleanup bb +void AArch64DataDepBase::AnalysisAmbiInsns(BB &bb) +{ + curCDGNode->SetHasAmbiRegs(false); + if (bb.GetEhSuccs().empty()) { + return; + } + MapleSet &ehInRegs = curCDGNode->GetEhInRegs(); + + // Union all catch bb + for (auto succBB : bb.GetEhSuccs()) { + const MapleSet &liveInRegSet = succBB->GetLiveInRegNO(); + (void)set_union(liveInRegSet.begin(), liveInRegSet.end(), ehInRegs.begin(), ehInRegs.end(), + inserter(ehInRegs, ehInRegs.begin())); + } + + // Union cleanup entry bb + const MapleSet ®NOSet = cgFunc.GetCleanupBB()->GetLiveInRegNO(); + (void)std::set_union(regNOSet.begin(), regNOSet.end(), ehInRegs.begin(), ehInRegs.end(), + inserter(ehInRegs, ehInRegs.begin())); + + // Subtract R0 and R1, that is defined by eh runtime + (void)ehInRegs.erase(R0); + (void)ehInRegs.erase(R1); + if (ehInRegs.empty()) { + return; + } + curCDGNode->SetHasAmbiRegs(true); +} + +// Build data dependence of memory operand. +// insn : an instruction with the memory access operand. +// opnd : the memory access operand. +// regProp : operand property of the memory access operand. +void AArch64DataDepBase::BuildMemOpndDependency(Insn &insn, Operand &opnd, const OpndDesc ®Prop) +{ + DEBUG_ASSERT(opnd.IsMemoryAccessOperand(), "opnd must be memory Operand"); + auto *memOpnd = static_cast(&opnd); + + // Build dependency for register of memOpnd + RegOperand *baseRegister = memOpnd->GetBaseRegister(); + if (baseRegister != nullptr) { + regno_t regNO = baseRegister->GetRegisterNumber(); + BuildDepsUseReg(insn, regNO); + if (memOpnd->IsPostIndexed() || memOpnd->IsPreIndexed()) { + // Base operand has redefined + BuildDepsDefReg(insn, regNO); + } + } + RegOperand *indexRegister = memOpnd->GetIndexRegister(); + if (indexRegister != nullptr) { + regno_t regNO = indexRegister->GetRegisterNumber(); + BuildDepsUseReg(insn, regNO); + } + + // Build dependency for mem access + if (regProp.IsUse()) { + BuildDepsUseMem(insn, *memOpnd); + } else { + BuildDepsDefMem(insn, *memOpnd); + BuildDepsAmbiInsn(insn); + } + + // Build dependency for yield point in java + if (cgFunc.GetMirModule().IsJavaModule() && IsYieldPoint(insn)) { + BuildDepsMemBar(insn); + BuildDepsDefReg(insn, kRFLAG); + } +} + +// Build Dependency for each operand of insn +void AArch64DataDepBase::BuildOpndDependency(Insn &insn) +{ + const InsnDesc *md = insn.GetDesc(); + MOperator mOp = insn.GetMachineOpcode(); + uint32 opndNum = insn.GetOperandSize(); + for (uint32 i = 0; i < opndNum; ++i) { + Operand &opnd = insn.GetOperand(i); + const OpndDesc *regProp = md->opndMD[i]; + if (opnd.IsMemoryAccessOperand()) { + BuildMemOpndDependency(insn, opnd, *regProp); + } else if (opnd.IsStImmediate() && mOp != MOP_xadrpl12) { + BuildDepsAccessStImmMem(insn); + } else if (opnd.IsRegister()) { + auto ®Opnd = static_cast(opnd); + regno_t regNO = regOpnd.GetRegisterNumber(); + if (regProp->IsUse()) { + BuildDepsUseReg(insn, regNO); + } + if (regProp->IsDef()) { + BuildDepsDefReg(insn, regNO); + } + } else if (opnd.IsConditionCode()) { + // For condition operand, such as NE, EQ, and so on. + if (regProp->IsUse()) { + BuildDepsUseReg(insn, kRFLAG); + BuildDepsBetweenControlRegAndCall(insn, false); + } + if (regProp->IsDef()) { + BuildDepsDefReg(insn, kRFLAG); + BuildDepsBetweenControlRegAndCall(insn, true); + } + } else if (opnd.IsList()) { + auto &listOpnd = static_cast(opnd); + for (auto &lst : listOpnd.GetOperands()) { + regno_t regNO = lst->GetRegisterNumber(); + BuildDepsUseReg(insn, regNO); + } + } + } +} + +// Build dependencies in some special cases for MOP_xbl +void AArch64DataDepBase::BuildSpecialBLDepsForJava(Insn &insn) +{ + DEBUG_ASSERT(insn.GetMachineOpcode() == MOP_xbl, "invalid insn"); + auto &target = static_cast(insn.GetOperand(0)); + if ((target.GetName() == "MCC_InitializeLocalStackRef") || (target.GetName() == "MCC_ClearLocalStackRef") || + (target.GetName() == "MCC_DecRefResetPair")) { + // Write stack memory + BuildDepsDirtyStack(insn); + } else if ((target.GetName() == "MCC_CleanupLocalStackRef_NaiveRCFast") || + (target.GetName() == "MCC_CleanupLocalStackRefSkip_NaiveRCFast") || + (target.GetName() == "MCC_CleanupLocalStackRefSkip")) { + // Use Stack Memory + BuildDepsUseStack(insn); + } +} + +// Build dependencies for call insns which do not obey standard call procedure +void AArch64DataDepBase::BuildSpecialCallDeps(Insn &insn) +{ + if (insn.IsSpecialCall()) { + // The runtime model uses to implement this originates in the IA-64 processor-specific ABI + // It is not available everywhere !!! + // for tls_desc_call, which clobber r0, r1, cc reg according to call convention rules, + // and the blr will write the LR reg. + if (insn.GetMachineOpcode() == MOP_tls_desc_call) { + BuildDepsDefReg(insn, RLR); + BuildDepsDefReg(insn, kRFLAG); + } + } +} + +// Build dependencies in some special cases (stack/heap/throw/clinit/lazy binding/control flow) +void AArch64DataDepBase::BuildSpecialInsnDependency(Insn &insn, const MapleVector &nodes) +{ + const InsnDesc *md = insn.GetDesc(); + MOperator mOp = insn.GetMachineOpcode(); + if (insn.IsCall() || insn.IsTailCall()) { + // Build caller saved registers dependency + BuildCallerSavedDeps(insn); + BuildDepsDirtyStack(insn); + BuildDepsDirtyHeap(insn); + BuildDepsAmbiInsn(insn); + if (mOp == MOP_xbl) { + BuildSpecialBLDepsForJava(insn); + } + BuildDepsLastCallInsn(insn); + } else if (insn.IsClinit() || IsLazyLoad(insn.GetMachineOpcode()) || + insn.GetMachineOpcode() == MOP_arrayclass_cache_ldr) { + BuildDepsDirtyHeap(insn); + BuildDepsDefReg(insn, kRFLAG); + if (insn.GetMachineOpcode() != MOP_adrp_ldr) { + BuildDepsDefReg(insn, R16); + BuildDepsDefReg(insn, R17); + } + } else if (mOp == MOP_xret || md->IsBranch()) { + BuildDepsControlAll(insn, nodes); + } else if (insn.IsMemAccessBar()) { + BuildDepsMemBar(insn); + } else if (insn.IsSpecialIntrinsic()) { + BuildDepsDirtyHeap(insn); + } +} + +void AArch64DataDepBase::BuildAsmInsnDependency(Insn &insn) +{ + Insn *asmInsn = curCDGNode->GetLastInlineAsmInsn(); + if (asmInsn != nullptr) { + // Due to the possible undefined behavior of users, we conservatively restrict + // the instructions under the asm-insn to be moved above this instruction, + // by building dependency edges on asm-insn and all subsequent instructions. + // e.g. + // asm volatile ( "mov x2, %[a]\n\t" + // "sub x2, x2, %[a]\n\t" + // "orr x3, x2, %[a]\n\t" + // : + // : [a] "I" (1) + // : "x2" + // It only identifies that clobber x2. + AddDependence(*asmInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeControl); + } + + if (insn.IsAsmInsn()) { + DEBUG_ASSERT(insn.GetOperand(kInsnSecondOpnd).IsList(), "invalid opnd of asm insn"); + DEBUG_ASSERT(insn.GetOperand(kInsnThirdOpnd).IsList(), "invalid opnd of asm insn"); + DEBUG_ASSERT(insn.GetOperand(kInsnFourthOpnd).IsList(), "invalid opnd of asm insn"); + auto &outputList = static_cast(insn.GetOperand(kInsnSecondOpnd)); + auto &clobberList = static_cast(insn.GetOperand(kInsnThirdOpnd)); + auto &inputList = static_cast(insn.GetOperand(kInsnFourthOpnd)); + for (auto *defOpnd : outputList.GetOperands()) { + if (defOpnd == nullptr) { + continue; + } + BuildDepsDefReg(insn, defOpnd->GetRegisterNumber()); + } + for (auto *defOpnd : clobberList.GetOperands()) { + if (defOpnd == nullptr) { + continue; + } + BuildDepsDefReg(insn, defOpnd->GetRegisterNumber()); + } + for (auto *useOpnd : inputList.GetOperands()) { + if (useOpnd == nullptr) { + continue; + } + BuildDepsUseReg(insn, useOpnd->GetRegisterNumber()); + } + curCDGNode->SetLastInlineAsmInsn(&insn); + } +} + +void AArch64DataDepBase::BuildInterBlockMemDefUseDependency(DepNode &depNode, bool isMemDef) +{ + CHECK_FATAL(!isIntra, "must be inter block data dependence analysis"); + CHECK_FATAL(curRegion->GetRegionRoot() != curCDGNode, "for the root node, cross-BB search is not required"); + BB *curBB = curCDGNode->GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + std::vector visited(curRegion->GetMaxBBIdInRegion() + 1, false); + if (isMemDef) { + BuildPredPathMemDefDependencyDFS(*curBB, visited, depNode); + } else { + BuildPredPathMemUseDependencyDFS(*curBB, visited, depNode); + } +} + +void AArch64DataDepBase::BuildPredPathMemDefDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode) +{ + if (visited[curBB.GetId()]) { + return; + } + CDGNode *cdgNode = curBB.GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + CDGRegion *region = cdgNode->GetRegion(); + CHECK_FATAL(region != nullptr, "get region from cdgNode failed"); + if (region->GetRegionId() != curRegion->GetRegionId()) { + return; + } + + visited[curBB.GetId()] = true; + + BuildDepsForMemDefCommon(*depNode.GetInsn(), *cdgNode); + + // Ignore back-edge + if (cdgNode == curRegion->GetRegionRoot()) { + return; + } + + for (auto predIt = curBB.GetPredsBegin(); predIt != curBB.GetPredsEnd(); ++predIt) { + // Ignore back-edge of self-loop + if (*predIt != &curBB) { + BuildPredPathMemDefDependencyDFS(**predIt, visited, depNode); + } + } +} + +void AArch64DataDepBase::BuildPredPathMemUseDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode) +{ + if (visited[curBB.GetId()]) { + return; + } + CDGNode *cdgNode = curBB.GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + CDGRegion *region = cdgNode->GetRegion(); + CHECK_FATAL(region != nullptr, "get region from cdgNode failed"); + if (region->GetRegionId() != curRegion->GetRegionId()) { + return; + } + visited[curBB.GetId()] = true; + + BuildDepsForMemUseCommon(*depNode.GetInsn(), *cdgNode); + + // Ignore back-edge + if (cdgNode == curRegion->GetRegionRoot()) { + return; + } + for (auto predIt = curBB.GetPredsBegin(); predIt != curBB.GetPredsEnd(); ++predIt) { + // Ignore back-edge of self-loop + if (*predIt != &curBB) { + BuildPredPathMemUseDependencyDFS(**predIt, visited, depNode); + } + } +} + +void AArch64DataDepBase::DumpNodeStyleInDot(std::ofstream &file, DepNode &depNode) +{ + MOperator mOp = depNode.GetInsn()->GetMachineOpcode(); + const InsnDesc *md = &AArch64CG::kMd[mOp]; + file << " insn_" << depNode.GetInsn() << "["; + file << "label = \"" << depNode.GetInsn()->GetId() << ":\n"; + file << "{ " << md->name << "}\"];\n"; +} +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_global_schedule.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_global_schedule.cpp new file mode 100644 index 0000000000..2dc77e14df --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_global_schedule.cpp @@ -0,0 +1,122 @@ +/* + * 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. + */ +#include "aarch64_global_schedule.h" +#include "aarch64_cg.h" + +namespace maplebe { +/* + * To verify the correctness of the dependency graph, + * by only scheduling the instructions of nodes in the region based on the inter-block data dependency information. + */ +void AArch64GlobalSchedule::VerifyingSchedule(CDGRegion ®ion) +{ + for (auto cdgNode : region.GetRegionNodes()) { + MemPool *cdgNodeMp = memPoolCtrler.NewMemPool("global-scheduler cdgNode memPool", true); + + InitInCDGNode(region, *cdgNode, *cdgNodeMp); + uint32 scheduledNodeNum = 0; + + /* Schedule independent instructions sequentially */ + MapleVector candidates = commonSchedInfo->GetCandidates(); + MapleVector schedResults = commonSchedInfo->GetSchedResults(); + auto depIter = candidates.begin(); + while (!candidates.empty()) { + DepNode *depNode = *depIter; + // the depNode can be scheduled + if (depNode->GetValidPredsSize() == 0) { + Insn *insn = depNode->GetInsn(); + depNode->SetState(kScheduled); + schedResults.emplace_back(depNode); + for (auto succLink : depNode->GetSuccs()) { + DepNode &succNode = succLink->GetTo(); + succNode.DecreaseValidPredsSize(); + } + depIter = commonSchedInfo->EraseIterFromCandidates(depIter); + if (insn->GetBB()->GetId() == cdgNode->GetBB()->GetId()) { + scheduledNodeNum++; + } + } else { + ++depIter; + } + if (depIter == candidates.end()) { + depIter = candidates.begin(); + } + // When all instructions in the cdgNode are scheduled, the scheduling ends + if (scheduledNodeNum == cdgNode->GetInsnNum()) { + break; + } + } + + /* Reorder the instructions of BB based on the scheduling result */ + FinishScheduling(*cdgNode); + ClearCDGNodeInfo(region, *cdgNode, cdgNodeMp); + } +} + +void AArch64GlobalSchedule::FinishScheduling(CDGNode &cdgNode) +{ + BB *curBB = cdgNode.GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + curBB->ClearInsns(); + + MapleVector schedResults = commonSchedInfo->GetSchedResults(); + for (auto depNode : schedResults) { + CHECK_FATAL(depNode->GetInsn() != nullptr, "get insn from depNode failed"); + if (!depNode->GetClinitInsns().empty()) { + for (auto clinitInsn : depNode->GetClinitInsns()) { + curBB->AppendInsn(*clinitInsn); + } + } + + BB *bb = depNode->GetInsn()->GetBB(); + if (bb->GetId() != curBB->GetId()) { + CDGNode *node = bb->GetCDGNode(); + CHECK_FATAL(node != nullptr, "get cdgNode from bb failed"); + node->RemoveDepNodeFromDataNodes(*depNode); + if (curBB->MayFoldInCfg(*bb)) { + // move dbg line with insn if two bb is close in cfg + Insn *prev = depNode->GetInsn()->GetPrev(); + if (prev != nullptr && prev->IsDbgLine()) { + bb->RemoveInsn(*prev); + curBB->AppendOtherBBInsn(*prev); + } + } + // Remove the instruction & depNode from the candidate BB + bb->RemoveInsn(*depNode->GetInsn()); + // Append the instruction of candidateBB + curBB->AppendOtherBBInsn(*depNode->GetInsn()); + } else { + // Append debug & comment infos of curBB + for (auto commentInsn : depNode->GetComments()) { + if (commentInsn->GetPrev() != nullptr && commentInsn->GetPrev()->IsDbgInsn()) { + curBB->AppendInsn(*commentInsn->GetPrev()); + } + curBB->AppendInsn(*commentInsn); + } + if (depNode->GetInsn()->GetPrev() != nullptr && depNode->GetInsn()->GetPrev()->IsDbgInsn()) { + curBB->AppendInsn(*depNode->GetInsn()->GetPrev()); + } + // Append the instruction of curBB + curBB->AppendInsn(*depNode->GetInsn()); + } + } + for (auto lastComment : cdgNode.GetLastComments()) { + curBB->AppendInsn(*lastComment); + } + cdgNode.ClearLastComments(); + ASSERT(curBB->NumInsn() >= static_cast(cdgNode.GetInsnNum()), + "The number of instructions after global-scheduling is unexpected"); +} +} /* namespace maplebe */ \ No newline at end of file diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_local_schedule.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_local_schedule.cpp new file mode 100644 index 0000000000..2f957ee31b --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_local_schedule.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#include "aarch64_local_schedule.h" +#include "aarch64_cg.h" + +namespace maplebe { +void AArch64LocalSchedule::FinishScheduling(CDGNode &cdgNode) +{ + BB *curBB = cdgNode.GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + curBB->ClearInsns(); + + const Insn *prevLocInsn = (curBB->GetPrev() != nullptr ? curBB->GetPrev()->GetLastLoc() : nullptr); + MapleVector schedResults = commonSchedInfo->GetSchedResults(); + for (auto depNode : schedResults) { + Insn *curInsn = depNode->GetInsn(); + CHECK_FATAL(curInsn != nullptr, "get insn from depNode failed"); + + // Append comments + for (auto comment : depNode->GetComments()) { + if (comment->GetPrev() != nullptr && comment->GetPrev()->IsDbgInsn()) { + curBB->AppendInsn(*comment->GetPrev()); + } + curBB->AppendInsn(*comment); + } + + // Append clinit insns + if (!depNode->GetClinitInsns().empty()) { + for (auto clinitInsn : depNode->GetClinitInsns()) { + curBB->AppendInsn(*clinitInsn); + } + } else { + // Append debug insns + if (curInsn->GetPrev() != nullptr && curInsn->GetPrev()->IsDbgInsn()) { + curBB->AppendInsn(*curInsn->GetPrev()); + } + // Append insn + curBB->AppendInsn(*curInsn); + } + } + + curBB->SetLastLoc(prevLocInsn); + for (auto lastComment : cdgNode.GetLastComments()) { + curBB->AppendInsn(*lastComment); + } + cdgNode.ClearLastComments(); + DEBUG_ASSERT(curBB->NumInsn() >= static_cast(cdgNode.GetInsnNum()), + "The number of instructions after local-scheduling is unexpected"); + + commonSchedInfo = nullptr; +} +} /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_schedule.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_schedule.cpp index 9be3d3ef5f..081e6d3a97 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_schedule.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_schedule.cpp @@ -35,10 +35,6 @@ namespace { constexpr uint32 kSecondToLastNode = 2; } // namespace -constexpr uint32 kClinitAdvanceCycle = 12; -constexpr uint32 kAdrpLdrAdvanceCycle = 4; -constexpr uint32 kClinitTailAdvanceCycle = 6; - uint32 AArch64Schedule::maxUnitIndex = 0; /* reserve two register for special purpose */ int AArch64Schedule::intRegPressureThreshold = static_cast(R27 - R0); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/base_schedule.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/base_schedule.cpp new file mode 100644 index 0000000000..0113251798 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/base_schedule.cpp @@ -0,0 +1,228 @@ +/* + * 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. + */ + +#include "base_schedule.h" +#ifdef TARGAARCH64 +#include "aarch64_cg.h" +#endif + +namespace maplebe { +// Set insnId to guarantee default priority, +// Set locInsn to maintain debug info +void BaseSchedule::InitInsnIdAndLocInsn() +{ + uint32 id = 0; + FOR_ALL_BB(bb, &cgFunc) + { + bb->SetLastLoc(bb->GetPrev() ? bb->GetPrev()->GetLastLoc() : nullptr); + FOR_BB_INSNS(insn, bb) + { + if (insn->IsMachineInstruction()) { + insn->SetId(id++); + } +#if defined(DEBUG) && DEBUG + insn->AppendComment(" Insn id: " + std::to_string(insn->GetId())); +#endif + if (insn->IsImmaterialInsn() && !insn->IsComment()) { + bb->SetLastLoc(insn); + } else if (!bb->GetFirstLoc() && insn->IsMachineInstruction()) { + bb->SetFirstLoc(*bb->GetLastLoc()); + } + } + } +} + +void BaseSchedule::InitMachineInsnNum(CDGNode &cdgNode) const +{ + uint32 insnNum = 0; + BB *curBB = cdgNode.GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + FOR_BB_INSNS_CONST(insn, curBB) + { + if (insn->IsMachineInstruction()) { + insnNum++; + } + } + cdgNode.SetInsnNum(insnNum); +} + +void BaseSchedule::InitInRegion(CDGRegion ®ion) const +{ + // Init valid dependency size for scheduling + for (auto *cdgNode : region.GetRegionNodes()) { + for (auto *depNode : cdgNode->GetAllDataNodes()) { + depNode->SetState(kNormal); + depNode->SetValidPredsSize(static_cast(depNode->GetPreds().size())); + depNode->SetValidSuccsSize(static_cast(depNode->GetSuccs().size())); + } + } +} + +uint32 BaseSchedule::CaculateOriginalCyclesOfBB(CDGNode &cdgNode) const +{ + BB *bb = cdgNode.GetBB(); + DEBUG_ASSERT(bb != nullptr, "get bb from cdgNode failed"); + + FOR_BB_INSNS(insn, bb) + { + if (!insn->IsMachineInstruction()) { + continue; + } + DepNode *depNode = insn->GetDepNode(); + DEBUG_ASSERT(depNode != nullptr, "get depNode from insn failed"); + // init + depNode->SetSimulateState(kStateUndef); + depNode->SetSimulateIssueCycle(0); + } + + MAD *mad = Globals::GetInstance()->GetMAD(); + std::vector runningList; + uint32 curCycle = 0; + FOR_BB_INSNS(insn, bb) + { + if (!insn->IsMachineInstruction()) { + continue; + } + DepNode *depNode = insn->GetDepNode(); + ASSERT_NOT_NULL(depNode); + // Currently, do not consider the conflicts of resource + if (depNode->GetPreds().empty()) { + depNode->SetSimulateState(kRunning); + depNode->SetSimulateIssueCycle(curCycle); + (void)runningList.emplace_back(depNode); + continue; + } + // Update depNode info on curCycle + for (auto *runningNode : runningList) { + if (runningNode->GetSimulateState() == kRunning && + (static_cast(curCycle) - static_cast(runningNode->GetSimulateIssueCycle()) >= + runningNode->GetReservation()->GetLatency())) { + runningNode->SetSimulateState(kRetired); + } + } + // Update curCycle by curDepNode + uint32 maxWaitTime = 0; + for (auto *predLink : depNode->GetPreds()) { + ASSERT_NOT_NULL(predLink); + DepNode &predNode = predLink->GetFrom(); + Insn *predInsn = predNode.GetInsn(); + ASSERT_NOT_NULL(predInsn); + // Only calculate latency of true dependency in local BB + if (predLink->GetDepType() == kDependenceTypeTrue && predInsn->GetBB() == bb && + predNode.GetSimulateState() == kRunning) { + DEBUG_ASSERT(curCycle >= predNode.GetSimulateIssueCycle(), "the state of dependency node is wrong"); + if ((static_cast(curCycle) - static_cast(predNode.GetSimulateIssueCycle())) < + mad->GetLatency(*predInsn, *insn)) { + int actualLatency = + mad->GetLatency(*predInsn, *insn) - + (static_cast(curCycle) - static_cast(predNode.GetSimulateIssueCycle())); + maxWaitTime = std::max(maxWaitTime, static_cast(actualLatency)); + } + } + } + curCycle += maxWaitTime; + depNode->SetSimulateState(kRunning); + depNode->SetSimulateIssueCycle(curCycle); + } + return curCycle; +} + +void BaseSchedule::DumpRegionInfoBeforeSchedule(CDGRegion ®ion) const +{ + LogInfo::MapleLogger() << "---------------- Schedule Region_" << region.GetRegionId() << " ----------------\n\n"; + LogInfo::MapleLogger() << "## total number of blocks: " << region.GetRegionNodeSize() << "\n\n"; + LogInfo::MapleLogger() << "## topological order of blocks in region: {"; + for (uint32 i = 0; i < region.GetRegionNodeSize(); ++i) { + BB *bb = region.GetRegionNodes()[i]->GetBB(); + DEBUG_ASSERT(bb != nullptr, "get bb from cdgNode failed"); + LogInfo::MapleLogger() << "bb_" << bb->GetId(); + if (i != region.GetRegionNodeSize() - 1) { + LogInfo::MapleLogger() << ", "; + } else { + LogInfo::MapleLogger() << "}\n\n"; + } + } +} + +void BaseSchedule::DumpCDGNodeInfoBeforeSchedule(CDGNode &cdgNode) const +{ + BB *curBB = cdgNode.GetBB(); + DEBUG_ASSERT(curBB != nullptr, "get bb from cdgNode failed"); + LogInfo::MapleLogger() << "= = = = = = = = = = = = = = = = = = = = = = = = = = = =\n\n"; + LogInfo::MapleLogger() << "## -- bb_" << curBB->GetId() << " before schedule --\n\n"; + LogInfo::MapleLogger() << " >> candidates info of bb_" << curBB->GetId() << " <<\n\n"; + curBB->Dump(); + LogInfo::MapleLogger() << "\n"; + DumpInsnInfoByScheduledOrder(cdgNode); +} + +void BaseSchedule::DumpCDGNodeInfoAfterSchedule(CDGNode &cdgNode) const +{ + BB *curBB = cdgNode.GetBB(); + DEBUG_ASSERT(curBB != nullptr, "get bb from cdgNode failed"); + LogInfo::MapleLogger() << "\n"; + LogInfo::MapleLogger() << "## -- bb_" << curBB->GetId() << " after schedule --\n"; + LogInfo::MapleLogger() << " ideal total cycles: " + << (doDelayHeu ? listScheduler->GetMaxDelay() : listScheduler->GetMaxLStart()) << "\n"; + LogInfo::MapleLogger() << " sched total cycles: " << listScheduler->GetCurrCycle() << "\n\n"; + curBB->Dump(); + LogInfo::MapleLogger() << " = = = = = = = = = = = = = = = = = = = = = = = = = = =\n\n\n"; +} + +void BaseSchedule::DumpInsnInfoByScheduledOrder(CDGNode &cdgNode) const +{ + // For print table log with unequal widths + int printWidth1 = 6; + int printWidth2 = 8; + int printWidth3 = 14; + LogInfo::MapleLogger() << " ------------------------------------------------\n"; + (void)LogInfo::MapleLogger().fill(' '); + LogInfo::MapleLogger() << " " << std::setiosflags(std::ios::left) << std::setw(printWidth1) << "insn" + << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right) + << std::setw(printWidth2) << "mop" << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(printWidth2) << "bb" + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(printWidth3) << "succs(latency)" << std::resetiosflags(std::ios::right) << "\n"; + LogInfo::MapleLogger() << " ------------------------------------------------\n"; + BB *curBB = cdgNode.GetBB(); + DEBUG_ASSERT(curBB != nullptr, "get bb from cdgNode failed"); + FOR_BB_INSNS_CONST(insn, curBB) + { + if (!insn->IsMachineInstruction()) { + continue; + } + LogInfo::MapleLogger() << " " << std::setiosflags(std::ios::left) << std::setw(printWidth1) + << insn->GetId() << std::resetiosflags(std::ios::left) + << std::setiosflags(std::ios::right) << std::setw(printWidth2); + const InsnDesc *md = nullptr; + if (Globals::GetInstance()->GetTarget()->GetTargetMachine()->isAArch64()) { + md = &AArch64CG::kMd[insn->GetMachineOpcode()]; + } + CHECK_NULL_FATAL(md); + LogInfo::MapleLogger() << md->name << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(printWidth2) << curBB->GetId() << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(printWidth3); + const DepNode *depNode = insn->GetDepNode(); + DEBUG_ASSERT(depNode != nullptr, "get depNode from insn failed"); + for (auto succLink : depNode->GetSuccs()) { + DepNode &succNode = succLink->GetTo(); + LogInfo::MapleLogger() << succNode.GetInsn()->GetId() << "(" << succLink->GetLatency() << "), "; + } + LogInfo::MapleLogger() << std::resetiosflags(std::ios::right) << "\n"; + } + LogInfo::MapleLogger() << " ------------------------------------------------\n"; + LogInfo::MapleLogger() << "\n"; +} +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_dominance.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_dominance.cpp index 9f2f6b7789..1a5b872a2f 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_dominance.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_dominance.cpp @@ -474,6 +474,67 @@ void PostDomAnalysis::Dump() LogInfo::MapleLogger() << "\n\n"; } +void PostDomAnalysis::GeneratePdomTreeDot() +{ + std::streambuf *coutBuf = std::cout.rdbuf(); + std::ofstream pdomFile; + std::streambuf *fileBuf = pdomFile.rdbuf(); + (void)std::cout.rdbuf(fileBuf); + + std::string fileName; + (void)fileName.append("pdom_tree_"); + (void)fileName.append(cgFunc.GetName()); + (void)fileName.append(".dot"); + + pdomFile.open(fileName.c_str(), std::ios::trunc); + if (!pdomFile.is_open()) { + LogInfo::MapleLogger(kLlWarn) << "fileName:" << fileName << " open failed.\n"; + return; + } + pdomFile << "digraph Pdom_" << cgFunc.GetName() << " {\n\n"; + pdomFile << " node [shape=box];\n\n"; + + FOR_ALL_BB_CONST(bb, &cgFunc) + { + if (bb->IsUnreachable()) { + continue; + } + pdomFile << " BB_" << bb->GetId(); + pdomFile << "[label= \""; + if (bb == cgFunc.GetCommonEntryBB()) { + pdomFile << "ENTRY\n"; + } + pdomFile << "BB_" << bb->GetId() << "\"];\n"; + } + BB *exitBB = cgFunc.GetCommonExitBB(); + pdomFile << " BB_" << exitBB->GetId(); + pdomFile << "[label= \"EXIT\n"; + pdomFile << "BB_" << exitBB->GetId() << "\"];\n"; + pdomFile << "\n"; + + for (uint32 bbId = 0; bbId < pdomChildren.size(); ++bbId) { + if (pdomChildren[bbId].empty()) { + continue; + } + BB *parent = cgFunc.GetBBFromID(bbId); + CHECK_FATAL(parent != nullptr, "get pdom parent-node failed"); + for (auto childId : pdomChildren[bbId]) { + BB *child = cgFunc.GetBBFromID(childId); + CHECK_FATAL(child != nullptr, "get pdom child-node failed"); + pdomFile << " BB_" << parent->GetId() << " -> " + << "BB_" << child->GetId(); + pdomFile << " [dir=none]" + << ";\n"; + } + } + pdomFile << "\n"; + + pdomFile << "}\n"; + (void)pdomFile.flush(); + pdomFile.close(); + (void)std::cout.rdbuf(coutBuf); +} + void PostDomAnalysis::Compute() { PdomGenPostOrderID(); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp index 96490552af..047dc49cd8 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp @@ -72,6 +72,7 @@ bool CGOptions::useBarriersForVolatile = true; bool CGOptions::exclusiveEH = false; bool CGOptions::doEBO = false; bool CGOptions::doCGSSA = false; +bool CGOptions::doLocalSchedule = false; bool CGOptions::doCGRegCoalesce = false; bool CGOptions::doIPARA = true; bool CGOptions::doCFGO = false; @@ -706,6 +707,7 @@ void CGOptions::EnableO0() optimizeLevel = kLevel0; doEBO = false; doCGSSA = false; + doLocalSchedule = false; doCFGO = false; doICO = false; doPrePeephole = false; @@ -751,6 +753,7 @@ void CGOptions::EnableO2() optimizeLevel = kLevel2; doEBO = true; doCGSSA = true; + doLocalSchedule = true; doCFGO = true; doICO = true; doPrePeephole = true; @@ -785,6 +788,7 @@ void CGOptions::EnableLiteCG() optimizeLevel = kLevelLiteCG; doEBO = false; doCGSSA = false; + doLocalSchedule = false; doCGRegCoalesce = false; doCFGO = true; doICO = false; diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/control_dep_analysis.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/control_dep_analysis.cpp new file mode 100644 index 0000000000..29532949c7 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/control_dep_analysis.cpp @@ -0,0 +1,1162 @@ +/* + * 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. + */ + +#include "control_dep_analysis.h" +#include "mpl_logging.h" + +namespace maplebe { +static BB *GetExistBB(std::vector &bbVec, BBID bbId) +{ + for (auto *bb : bbVec) { + if (bb->GetId() == bbId) { + return bb; + } + } + return nullptr; +} + +void ControlDepAnalysis::Run() +{ + // Local-scheduler(after RA) does not need pdom-analysis + if (CONTROL_DEP_ANALYSIS_DUMP && phaseName != "localschedule") { + pdom->GeneratePdomTreeDot(); + } + if (cgFunc.IsAfterRegAlloc() || isSingleBB) { + // For local scheduling + ComputeSingleBBRegions(); + } else { + // For global scheduling based on regions + BuildCFGInfo(); + ConstructFCDG(); + ComputeRegions(false); + } +} + +// Augment CFG info +void ControlDepAnalysis::BuildCFGInfo() +{ + CHECK_FATAL(cgFunc.GetCommonExitBB() != nullptr, "there must be a virtual ExitBB in cfg"); + cfgMST->BuildEdges(cgFunc.GetFirstBB(), cgFunc.GetCommonExitBB()); + // denote back-edge on CFGEdge + for (auto cfgEdge : cfgMST->GetAllEdges()) { + BB *srcBB = cfgEdge->GetSrcBB(); + BB *destBB = cfgEdge->GetDestBB(); + (void)*srcBB; + (void)*destBB; + if (loop->IsBackEdge(*srcBB, *destBB)) { + cfgEdge->SetIsBackEdge(); + } + } + // denote the condition on CFGEdge except for back-edge + for (auto &cfgEdge : cfgMST->GetAllEdges()) { + if (cfgEdge->IsBackEdge()) { + continue; + } + BB *srcBB = cfgEdge->GetSrcBB(); + BB *destBB = cfgEdge->GetDestBB(); + CHECK_FATAL(srcBB != nullptr, "get srcBB of cfgEdge failed"); + if (srcBB == cgFunc.GetFirstBB()) { + cfgEdge->SetCondition(0); + continue; + } else if (srcBB == cgFunc.GetCommonExitBB()) { + continue; + } + BB::BBKind srcKind = srcBB->GetKind(); + switch (srcKind) { + case BB::kBBFallthru: + case BB::kBBGoto: + case BB::kBBIgoto: + case BB::kBBReturn: + cfgEdge->SetCondition(0); + break; + case BB::kBBIntrinsic: + ASSERT_NOT_NULL(srcBB->GetLastMachineInsn()); + if (!srcBB->GetLastMachineInsn()->IsBranch()) { + // set default cond number + cfgEdge->SetCondition(0); + } + // else fall through + [[clang::fallthrough]]; + case BB::kBBIf: { + Insn *branchInsn = srcBB->GetLastMachineInsn(); + CHECK_FATAL(branchInsn != nullptr, "ifBB must have a machine insn at the end"); + DEBUG_ASSERT(branchInsn->IsCondBranch(), "ifBB must have a conditional branch insn at the end"); + int lastOpndIdx = static_cast(branchInsn->GetOperandSize()) - 1; + DEBUG_ASSERT(lastOpndIdx > -1, "lastOpndIdx must greater than -1"); + Operand &lastOpnd = branchInsn->GetOperand(static_cast(lastOpndIdx)); + DEBUG_ASSERT(lastOpnd.IsLabelOpnd(), "lastOpnd must be labelOpnd in branchInsn"); + BB *jumpBB = cgFunc.GetBBFromLab2BBMap(static_cast(lastOpnd).GetLabelIndex()); + if (jumpBB == destBB) { + cfgEdge->SetCondition(0); + } else { + cfgEdge->SetCondition(1); + } + break; + } + case BB::kBBRangeGoto: { + // Each successor cfgEdge is assigned a different cond number + cfgEdge->SetCondition(static_cast(GetAndAccSuccedCondNum(srcBB->GetId()))); + break; + } + default: + // these kindBBs set default cond number [kBBNoReturn kBBThrow kBBLast] + cfgEdge->SetCondition(0); + break; + } + } +} + +// Construct forward control dependence graph +void ControlDepAnalysis::ConstructFCDG() +{ + CreateAllCDGNodes(); + // 1. Collect all edges(A, B) in CFG that B does not post-dom A + for (auto cfgEdge : cfgMST->GetAllEdges()) { + if (cfgEdge->IsBackEdge()) { + continue; + } + BB *srcBB = cfgEdge->GetSrcBB(); + BB *destBB = cfgEdge->GetDestBB(); + CHECK_FATAL(srcBB != nullptr && destBB != nullptr, "get edge-connected nodes in cfg failed"); + if (srcBB == cgFunc.GetCommonExitBB()) { + continue; + } + if (!pdom->PostDominate(*destBB, *srcBB)) { + AddNonPdomEdges(cfgEdge); + } + } + + // 2. Determine control dependence by traversal backward in the post-dom tree for every bbEdge in nonPdomEdges + for (auto candiEdge : nonPdomEdges) { + BB *srcBB = candiEdge->GetSrcBB(); + BB *destBB = candiEdge->GetDestBB(); + CHECK_FATAL(srcBB != nullptr && destBB != nullptr, "get edge-connected nodes in nonPdomEdges failed"); + // Find the nearest common ancestor (L) of srcBB and destBB in the pdom-tree : + // (1) L == parent of srcBB in the pdom-tree (immediate dominator of srcBB) + // (2) L == srcBB + BB *ancestor = (pdom->GetPdom(destBB->GetId()) == srcBB) ? srcBB : pdom->GetPdom(srcBB->GetId()); + BB *curBB = destBB; + while (curBB != nullptr && curBB != ancestor && curBB != cgFunc.GetCommonExitBB()) { + (void)BuildControlDependence(*srcBB, *curBB, candiEdge->GetCondition()); + curBB = pdom->GetPdom(curBB->GetId()); + } + } +} + +/** Divide regions for the CDGNodes : + * Traverse the post-dominator tree by means of a post-order to + * assure that all children in the post-dominator tree are visited before their parent. + */ +void ControlDepAnalysis::ComputeRegions(bool doCDRegion) +{ + if (doCDRegion) { + ComputeSameCDRegions(false); + } else { + ComputeGeneralNonLinearRegions(); + } +} + +// This algorithm computes the general non-linear region, including: +// 1). A reducible loops which have a single-in edge +// 2). A fallthrough path not in any regions +// 3). A single-bb not in other regions as a region +void ControlDepAnalysis::ComputeGeneralNonLinearRegions() +{ + // If ebo phase was removed, must recalculate loop info + // 1. Find all innermost loops + std::vector innermostLoops; + std::unordered_map visited; + + for (auto lp : loop->GetLoops()) { + FindInnermostLoops(innermostLoops, visited, lp); + } + + // 2. Find reducible loops as a region + for (auto innerLoop : innermostLoops) { + // Avoid the case as following: + // | + // | + // ----- BB4 ---------- + // | / \ | + // | / \ | + // BB3 BB5 | + // / \ | + // / \ | + // BB6 BB10 - + // | + // | + // EXIT + // By the current loop analysis, {BB4, BB3, BB5, BB10} are in the same loop, which the headerBB is BB4 + // By the dom and pdom analysis, {BB4 dom BB5} and {BB5 pdom BB4}, BB4 and BB5 are EQUIVALENT, + // but they cannot schedule in parallel. + // + // The above case may cause loop-carried dependency instructions to be scheduled, and currently this + // dependency is not considered. + if (innerLoop->GetBackEdges().size() > 1) { + continue; + } + + bool isReducible = true; + auto &header = innerLoop->GetHeader(); + for (auto memberId : innerLoop->GetLoopBBs()) { + if (!dom->Dominate(header, *cgFunc.GetBBFromID(memberId))) { + isReducible = false; + } + } + if (isReducible) { + auto *region = cdgMemPool.New(CDGRegionId(lastRegionId++), cdgAlloc); + CDGNode *headerNode = header.GetCDGNode(); + CHECK_FATAL(headerNode != nullptr, "get cdgNode from bb failed"); + region->SetRegionRoot(*headerNode); + region->SetBackBBId(*innerLoop->GetBackEdges().begin()); + for (auto memberId : innerLoop->GetLoopBBs()) { + CDGNode *memberNode = cgFunc.GetBBFromID(memberId)->GetCDGNode(); + CHECK_FATAL(memberNode != nullptr, "get cdgNode from bb failed"); + memberNode->SetRegion(region); + } + if (AddRegionNodesInTopologicalOrder(*region, *headerNode, innerLoop->GetLoopBBs())) { + fcdg->AddRegion(*region); + } + } + } + + // 3. Find fallthrough path not in any regions as a region + FOR_ALL_BB(bb, &cgFunc) + { + if (bb->IsUnreachable()) { + continue; + } + std::vector regionMembers; + CDGNode *cdgNode = bb->GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + if (!cdgNode->IsVisitedInExtendedFind() && bb->GetSuccsSize() == 1 && cdgNode->GetRegion() == nullptr) { + // Nodes in the region are in the order of topology in this way + FindFallthroughPath(regionMembers, bb, true); + auto *region = cdgMemPool.New(CDGRegionId(lastRegionId++), cdgAlloc); + region->SetRegionRoot(*cdgNode); + for (auto memberNode : regionMembers) { + region->AddCDGNode(memberNode); + memberNode->SetRegion(region); + } + fcdg->AddRegion(*region); + regionMembers.clear(); + } + } + + // 4. Create region for the remaining BBs that are not in any region + CreateRegionForSingleBB(); +} + +void ControlDepAnalysis::FindFallthroughPath(std::vector ®ionMembers, BB *curBB, bool isRoot) +{ + CHECK_FATAL(curBB != nullptr, "invalid bb"); + CDGNode *curNode = curBB->GetCDGNode(); + CHECK_FATAL(curNode != nullptr, "get cdgNode from bb failed"); + if (curNode->IsVisitedInExtendedFind()) { + return; + } + curNode->SetVisitedInExtendedFind(); + if (isRoot) { + if (curBB->GetSuccsSize() == 1 && curNode->GetRegion() == nullptr) { + regionMembers.emplace_back(curNode); + } else { + return; + } + } else { + if (curBB->GetPreds().size() == 1 && curBB->GetSuccsSize() == 1 && curNode->GetRegion() == nullptr) { + regionMembers.emplace_back(curNode); + } else { + return; + } + } + FindFallthroughPath(regionMembers, *curBB->GetSuccsBegin(), false); +} + +void ControlDepAnalysis::CreateRegionForSingleBB() +{ + FOR_ALL_BB(bb, &cgFunc) + { + if (bb->IsUnreachable()) { + continue; + } + CDGNode *cdgNode = bb->GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + if (cdgNode->GetRegion() == nullptr) { + auto *region = cdgMemPool.New(CDGRegionId(lastRegionId++), cdgAlloc); + region->AddCDGNode(cdgNode); + cdgNode->SetRegion(region); + region->SetRegionRoot(*cdgNode); + fcdg->AddRegion(*region); + } + } +} + +// Recursive search for innermost loop +void ControlDepAnalysis::FindInnermostLoops(std::vector &innermostLoops, + std::unordered_map &visited, LoopDesc *lp) +{ + if (lp == nullptr) { + return; + } + auto it = visited.find(lp); + if (it != visited.end() && it->second) { + return; + } + visited.emplace(lp, true); + const auto &innerLoops = lp->GetChildLoops(); + if (innerLoops.empty()) { + innermostLoops.emplace_back(lp); + } else { + for (auto innerLoop : innerLoops) { + FindInnermostLoops(innermostLoops, visited, innerLoop); + } + } +} + +bool ControlDepAnalysis::AddRegionNodesInTopologicalOrder(CDGRegion ®ion, CDGNode &root, + const MapleSet &members) +{ + // Init predSum for memberNode except for root in region + for (auto bbId : members) { + auto *bb = cgFunc.GetBBFromID(bbId); + CDGNode *cdgNode = bb->GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + if (cdgNode == &root) { + continue; + } + int32 predSumInRegion = 0; + for (auto predIt = bb->GetPredsBegin(); predIt != bb->GetPredsEnd(); ++predIt) { + CDGNode *predNode = (*predIt)->GetCDGNode(); + CHECK_FATAL(predNode != nullptr, "get CDGNode from bb failed"); + if (predNode->GetRegion() == ®ion) { + predSumInRegion++; + } + } + cdgNode->InitPredNodeSumInRegion(predSumInRegion); + cdgNode->SetVisitedInTopoSort(false); + } + + // Topological sort + std::queue topoQueue; + topoQueue.push(&root); + while (!topoQueue.empty()) { + CDGNode *curNode = topoQueue.front(); + topoQueue.pop(); + region.AddCDGNode(curNode); + + for (auto bbId : members) { + auto *bb = cgFunc.GetBBFromID(bbId); + CDGNode *memberNode = bb->GetCDGNode(); + CHECK_FATAL(memberNode != nullptr, "get cdgNode from bb failed"); + if (memberNode == &root || memberNode->IsVisitedInTopoSort()) { + continue; + } + for (auto predIt = bb->GetPredsBegin(); predIt != bb->GetPredsEnd(); ++predIt) { + CDGNode *predNode = (*predIt)->GetCDGNode(); + CHECK_FATAL(predNode != nullptr, "get cdgNode from bb failed"); + if (predNode == curNode) { + memberNode->DecPredNodeSumInRegion(); + } + } + if (memberNode->IsAllPredInRegionProcessed()) { + topoQueue.push(memberNode); + memberNode->SetVisitedInTopoSort(true); + } + } + } + // To avoid irreducible loops in reducible loops, need to modify the loop analysis algorithm in the future. + if (region.GetRegionNodeSize() != members.size()) { + return false; + } + return true; +} + +/** This region computing algorithm is based on this paper: + * The Program Dependence Graph and Its Use in Optimization + * It traverses the post-dominator tree by means of a post-order to assure that + * all children in the post-dominator tree are visited before their parent. + * The region is non-linear too. + * If cdgNodes that do not have any control dependency are divided into a region, the region is multi-root, + * which is not supported in inter-block data dependence analysis + */ +void ControlDepAnalysis::ComputeSameCDRegions(bool considerNonDep) +{ + // The default bbId starts from 1 + std::vector visited(fcdg->GetFCDGNodeSize(), false); + for (uint32 bbId = 1; bbId < fcdg->GetFCDGNodeSize(); ++bbId) { + if (!visited[bbId]) { + ComputeRegionForCurNode(bbId, visited); + } + } + if (considerNonDep) { + ComputeRegionForNonDepNodes(); + } +} + +// Nodes that don't have any control dependency are divided into a region +void ControlDepAnalysis::ComputeRegionForNonDepNodes() +{ + CDGRegion *curRegion = nullptr; + CDGNode *mergeNode = nullptr; + for (auto node : fcdg->GetAllFCDGNodes()) { + if (node == nullptr) { + continue; + } + if (node->GetInEdgesNum() != 0) { + continue; + } + if (curRegion == nullptr) { + curRegion = node->GetRegion(); + CHECK_FATAL(curRegion != nullptr, "each CDGNode must be in a region"); + mergeNode = node; + } else if (node->GetRegion() != curRegion) { + // Merge Region + CHECK_FATAL(mergeNode != nullptr, "invalid non-dep cdgNode"); + MergeRegions(*mergeNode, *node); + } + } +} + +// Recursively computes the region of each node +void ControlDepAnalysis::ComputeRegionForCurNode(uint32 curBBId, std::vector &visited) +{ + if (visited[curBBId]) { + return; + } + visited[curBBId] = true; + MapleVector children = pdom->GetPdomChildrenItem(curBBId); + if (!children.empty()) { + // Check that each child of the node has been computed + for (auto childId : children) { + if (!visited[childId]) { + ComputeRegionForCurNode(childId, visited); + } + } + } + // Leaf nodes and the nodes whose children have been computed in the pdom-tree that can be merged region + CreateAndDivideRegion(curBBId); +} + +void ControlDepAnalysis::CreateAndDivideRegion(uint32 pBBId) +{ + // 1. Visit every CDGNode:N, Get and Create the region of the control dependence set + CDGNode *parentNode = fcdg->GetCDGNodeFromId(CDGNodeId(pBBId)); + CHECK_FATAL(parentNode != nullptr, "get CDGNode failed"); + CDGRegion *region = FindExistRegion(*parentNode); + if (region == nullptr) { + region = CreateFCDGRegion(*parentNode); + } else { + region->AddCDGNode(parentNode); + parentNode->SetRegion(region); + } + MapleVector ®ionNodes = region->GetRegionNodes(); + // 2. Visit each immediate child of N in the post-dom tree, compute the intersection of CDs + BB *curBB = parentNode->GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb of CDGNode failed"); + for (auto childBBId : pdom->GetPdomChildrenItem(curBB->GetId())) { + CDGNode *childNode = fcdg->GetCDGNodeFromId(CDGNodeId(childBBId)); + if (std::find(regionNodes.begin(), regionNodes.end(), childNode) != regionNodes.end()) { + continue; + } + if (IsISEqualToCDs(*parentNode, *childNode)) { + MergeRegions(*parentNode, *childNode); + } + } +} + +// Check whether the region corresponding to the control dependence set exists +CDGRegion *ControlDepAnalysis::FindExistRegion(CDGNode &node) const +{ + MapleVector &allRegions = fcdg->GetAllRegions(); + MapleVector &curCDs = node.GetAllInEdges(); + // Nodes that don't have control dependencies are processed in a unified method at last + if (curCDs.empty()) { + return nullptr; + } + for (auto region : allRegions) { + if (region == nullptr) { + continue; + } + MapleVector ®ionCDs = region->GetCDEdges(); + if (regionCDs.size() != curCDs.size()) { + continue; + } + bool isAllCDExist = true; + for (auto curCD : curCDs) { + CHECK_FATAL(curCD != nullptr, "invalid control dependence edge"); + bool isOneCDExist = false; + for (auto regionCD : regionCDs) { + CHECK_FATAL(regionCD != nullptr, "invalid control dependence edge"); + if (IsSameControlDependence(*curCD, *regionCD)) { + isOneCDExist = true; + break; + } + } + if (!isOneCDExist) { + isAllCDExist = false; + break; + } + } + if (isAllCDExist) { + return region; + } + } + return nullptr; +} + +// Check whether the intersection(IS) of the control dependency set of the parent node (CDs) +// and the child node is equal to the control dependency set of the parent node +bool ControlDepAnalysis::IsISEqualToCDs(CDGNode &parent, CDGNode &child) const +{ + MapleVector &parentCDs = parent.GetAllInEdges(); + MapleVector &childCDs = child.GetAllInEdges(); + // Nodes that don't have control dependencies are processed in a unified method at last + if (parentCDs.empty() || childCDs.empty()) { + return false; + } + bool equal = true; + for (auto parentCD : parentCDs) { + CHECK_FATAL(parentCD != nullptr, "invalid CDGEdge in parentCDs"); + for (auto childCD : childCDs) { + if (!IsSameControlDependence(*parentCD, *childCD)) { + equal = false; + continue; + } + } + if (!equal) { + return false; + } + } + return true; +} + +// Merge regions of parentNode and childNode +void ControlDepAnalysis::MergeRegions(CDGNode &mergeNode, CDGNode &candiNode) +{ + CDGRegion *oldRegion = candiNode.GetRegion(); + CHECK_FATAL(oldRegion != nullptr, "get child's CDGRegion failed"); + + // Set newRegion of all memberNodes in oldRegion of child + CDGRegion *mergeRegion = mergeNode.GetRegion(); + CHECK_FATAL(mergeRegion != nullptr, "get parent's CDGRegion failed"); + for (auto node : oldRegion->GetRegionNodes()) { + node->SetRegion(mergeRegion); + mergeRegion->AddCDGNode(node); + oldRegion->RemoveCDGNode(node); + } + + if (oldRegion->GetRegionNodeSize() == 0) { + fcdg->RemoveRegionById(oldRegion->GetRegionId()); + } +} + +CDGEdge *ControlDepAnalysis::BuildControlDependence(const BB &fromBB, const BB &toBB, int32 condition) +{ + auto *fromNode = fcdg->GetCDGNodeFromId(CDGNodeId(fromBB.GetId())); + auto *toNode = fcdg->GetCDGNodeFromId(CDGNodeId(toBB.GetId())); + CHECK_FATAL(fromNode != nullptr && toNode != nullptr, "get CDGNode failed"); + auto *cdgEdge = cdgMemPool.New(*fromNode, *toNode, condition); + + fromNode->AddOutEdges(cdgEdge); + toNode->AddInEdges(cdgEdge); + fcdg->AddFCDGEdge(cdgEdge); + return cdgEdge; +} + +CDGRegion *ControlDepAnalysis::CreateFCDGRegion(CDGNode &curNode) +{ + MapleVector cdEdges = curNode.GetAllInEdges(); + auto *region = cdgMemPool.New(CDGRegionId(lastRegionId++), cdgAlloc); + region->AddCDEdgeSet(cdEdges); + region->AddCDGNode(&curNode); + fcdg->AddRegion(*region); + curNode.SetRegion(region); + return region; +} + +void ControlDepAnalysis::ComputeSingleBBRegions() +{ + CreateAllCDGNodes(); + CreateRegionForSingleBB(); +} + +// Create CDGNode for every BB +void ControlDepAnalysis::CreateAllCDGNodes() +{ + fcdg = cdgMemPool.New(cgFunc, cdgAlloc); + FOR_ALL_BB(bb, &cgFunc) + { + if (bb->IsUnreachable()) { + continue; + } + auto *node = cdgMemPool.New(CDGNodeId(bb->GetId()), *bb, cdgAlloc); + if (bb == cgFunc.GetFirstBB()) { + node->SetEntryNode(); + } + bb->SetCDGNode(node); + fcdg->AddFCDGNode(*node); + } + // Create CDGNode for exitBB + BB *exitBB = cgFunc.GetCommonExitBB(); + auto *exitNode = cdgMemPool.New(CDGNodeId(exitBB->GetId()), *exitBB, cdgAlloc); + exitNode->SetExitNode(); + exitBB->SetCDGNode(exitNode); + fcdg->AddFCDGNode(*exitNode); +} + +// Compute the pdom info only in the CDGRegion: +// we copy the cfg of the CDGRegion and perform pdom analysis on the tmp cfg. +// Currently, only for the innermost reducible loops. +// e.g. +// tmpCommonEntry +// | +// .... +// | (regionInEdge) +// \|/ +// |--|--->BB9 +// | | \ +// | | BB10 +// | | / \ +// | | BB11 BB16 +// | | \ / +// | | BB12 +// | | / \ (regionOutEdge) +// | | BB13 _\/ +// | | / .... --------- +// |--|--->BB14 | +// \ | +// _\/ (regionOutEdge) | +// .... | +// \ | +// tmpCommonExit ------ +// based on the global cfg, the BB12 pdom BB9; +// but based on the region cfg, the BB12 not pdom BB9. +Dominance *ControlDepAnalysis::ComputePdomInRegion(CDGRegion ®ion, std::vector &nonUniformRegionCFG, + uint32 &maxBBId) +{ + if (region.GetRegionNodeSize() <= 1) { + return nullptr; + } + // Copy the cfg of the CDGRegion + std::set regionInBBs; + std::set regionOutBBs; + maxBBId = 0; + BB *startBB = nullptr; + BB *endBB = nullptr; + for (auto *memberNode : region.GetRegionNodes()) { + BB *memberBB = memberNode->GetBB(); + ASSERT_NOT_NULL(memberBB); + BB *tmpBB = GetExistBB(nonUniformRegionCFG, memberBB->GetId()); + if (tmpBB == nullptr) { + tmpBB = cdgMemPool.New(memberBB->GetId(), cdgAlloc); + nonUniformRegionCFG.emplace_back(tmpBB); + } + if (memberNode == region.GetRegionRoot()) { + startBB = tmpBB; + } else if (memberNode == region.GetRegionNodes().back()) { + endBB = tmpBB; + } + maxBBId = (tmpBB->GetId() > maxBBId ? tmpBB->GetId() : maxBBId); + bool hasOutSidePred = false; + for (auto *predBB : memberBB->GetPreds()) { + if (predBB == nullptr) { + continue; + } + ASSERT_NOT_NULL(predBB->GetCDGNode()); + BB *existBB = GetExistBB(nonUniformRegionCFG, predBB->GetId()); + if (existBB != nullptr) { + tmpBB->PushBackPreds(*existBB); + existBB->PushBackSuccs(*tmpBB); + } else { + auto *tmpPredBB = cdgMemPool.New(predBB->GetId(), cdgAlloc); + if (predBB->GetCDGNode()->GetRegion() == ®ion) { + tmpBB->PushBackPreds(*tmpPredBB); + tmpPredBB->PushBackSuccs(*tmpBB); + } else if (!hasOutSidePred) { + tmpBB->PushBackPreds(*tmpPredBB); + tmpPredBB->PushBackSuccs(*tmpBB); + regionInBBs.insert(tmpPredBB); + hasOutSidePred = true; + } else { + continue; + } + nonUniformRegionCFG.emplace_back(tmpPredBB); + maxBBId = (tmpPredBB->GetId() > maxBBId ? tmpPredBB->GetId() : maxBBId); + } + } + bool hasOutSideSucc = false; + for (auto *succBB : memberBB->GetSuccs()) { + if (succBB == nullptr) { + continue; + } + ASSERT_NOT_NULL(succBB->GetCDGNode()); + BB *existBB = GetExistBB(nonUniformRegionCFG, succBB->GetId()); + if (existBB != nullptr) { + tmpBB->PushBackSuccs(*existBB); + existBB->PushBackPreds(*tmpBB); + } else { + auto *tmpSuccBB = cdgMemPool.New(succBB->GetId(), cdgAlloc); + if (succBB->GetCDGNode()->GetRegion() == ®ion) { + tmpBB->PushBackSuccs(*tmpSuccBB); + tmpSuccBB->PushBackPreds(*tmpBB); + } else if (!hasOutSideSucc) { + tmpBB->PushBackSuccs(*tmpSuccBB); + tmpSuccBB->PushBackPreds(*tmpBB); + regionOutBBs.insert(tmpSuccBB); + hasOutSideSucc = true; + } else { + continue; + } + nonUniformRegionCFG.emplace_back(tmpSuccBB); + maxBBId = (tmpSuccBB->GetId() > maxBBId ? tmpSuccBB->GetId() : maxBBId); + } + } + } + // Create temp commonEntry + maxBBId++; + BB *tmpEntry = cdgMemPool.New(maxBBId, cdgAlloc); + if (!regionInBBs.empty()) { + for (auto *regionIn : regionInBBs) { + tmpEntry->PushBackSuccs(*regionIn); + } + } else { + CHECK_NULL_FATAL(startBB); + tmpEntry->PushBackSuccs(*startBB); + } + nonUniformRegionCFG.emplace_back(tmpEntry); + // Create temp CommonExit + maxBBId++; + BB *tmpExit = cdgMemPool.New(maxBBId, cdgAlloc); + if (!regionOutBBs.empty()) { + for (auto *regionOut : regionOutBBs) { + tmpExit->PushBackPreds(*regionOut); + } + } else { + CHECK_NULL_FATAL(endBB); + tmpExit->PushBackPreds(*endBB); + } + nonUniformRegionCFG.emplace_back(tmpExit); + // Uniform region bb vector: + MapleVector regionCFG(maxBBId + 1, cdgAlloc.Adapter()); + for (auto *bb : nonUniformRegionCFG) { + regionCFG[bb->GetId()] = bb; + } + // For pdom analysis, the commonEntry and commonExit need to be reversed + auto *regionPdom = cdgMemPool.New(cdgMemPool, regionCFG, *tmpExit, *tmpEntry, true); + regionPdom->Init(); + return regionPdom; +} + +bool ControlDepAnalysis::IsInDifferentSCCNode(CDGRegion ®ion, std::vector ®ionCFG, uint32 maxBBId, + const BB &curBB, const BB &memberBB) +{ + // For fallthrough region, we do not need to check this + if (region.GetBackBBId() == UINT32_MAX) { + return false; + } + // Before pdom analysis, uniform region bb vector: + MapleVector uniformedRegionCFG(maxBBId + 1, cdgAlloc.Adapter()); + for (auto *bb : regionCFG) { + uniformedRegionCFG[bb->GetId()] = bb; + } + // 1. Check SCC + // Before buildSCC, record regionCFG, but not record commonEntry and commonExit + regionCFG.erase(regionCFG.end() - kNumOne); + regionCFG.erase(regionCFG.end() - kNumTwo); + MapleVector *> sccs(cdgAlloc.Adapter()); + (void)BuildSCC(cdgAlloc, maxBBId, regionCFG, false, sccs, true); + for (auto *scc : sccs) { + if (!scc->HasRecursion()) { + continue; + } + uint32 count = 0; + for (BB *bb : scc->GetNodes()) { + if (bb->GetId() == curBB.GetId() || bb->GetId() == memberBB.GetId()) { + count++; + } + } + // The two equivalent candidate BBs are not in the same SCC, + // we can not thin they are equivalent. + if (count == 1) { + return true; + } + } + // 2. Check pdom analysis for cfg of region that removes the back edge. + // Region construction ensures that there is only one back edge in the region. + bool allSuccOfBackBBInRegion = true; + for (auto *succ : cgFunc.GetBBFromID(region.GetBackBBId())->GetSuccs()) { + CDGNode *cdgNode = succ->GetCDGNode(); + ASSERT_NOT_NULL(cdgNode); + if (cdgNode->GetRegion() != ®ion) { + allSuccOfBackBBInRegion = false; + break; + } + } + if (allSuccOfBackBBInRegion) { + BB *commonEntryBB = static_cast(uniformedRegionCFG[uniformedRegionCFG.size() - 2]); + BB *commonExitBB = static_cast(uniformedRegionCFG[uniformedRegionCFG.size() - 1]); + ASSERT_NOT_NULL(region.GetRegionRoot()); + ASSERT_NOT_NULL(region.GetRegionRoot()->GetBB()); + BB *headerBB = static_cast(uniformedRegionCFG[region.GetRegionRoot()->GetBB()->GetId()]); + BB *backBB = static_cast(uniformedRegionCFG[region.GetBackBBId()]); + backBB->RemoveSuccs(*headerBB); + headerBB->RemovePreds(*backBB); + commonExitBB->PushBackPreds(*backBB); + auto *pruneRegionPdom = + cdgMemPool.New(cdgMemPool, uniformedRegionCFG, *commonExitBB, *commonEntryBB, true); + pruneRegionPdom->Init(); + if (!pruneRegionPdom->Dominate(memberBB.GetId(), curBB.GetId())) { + return true; + } + } + return false; +} + +/** Find equivalent candidate nodes of current cdgNode: + * A and B are equivalent if and only if A dominates B and B post-dominates A + * And it must be behind the current cdgNode in the topology order + */ +void ControlDepAnalysis::GetEquivalentNodesInRegion(CDGRegion ®ion, CDGNode &cdgNode, + std::vector &equivalentNodes) +{ + BB *curBB = cdgNode.GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + MapleVector &memberNodes = region.GetRegionNodes(); + bool isBehind = false; + for (auto member : memberNodes) { + if (member == &cdgNode) { + isBehind = true; + continue; + } + BB *memberBB = member->GetBB(); + CHECK_FATAL(memberBB != nullptr, "get bb from cdgNode failed"); + std::vector nonUniformRegionCFG; + uint32 maxBBId = 0; + Dominance *regionPdom = ComputePdomInRegion(region, nonUniformRegionCFG, maxBBId); + if (dom->Dominate(*curBB, *memberBB) && + (regionPdom != nullptr && regionPdom->Dominate(memberBB->GetId(), curBB->GetId())) && isBehind) { + // To avoid the loop-carried instructions are scheduled + bool isInPartialCycle = false; + for (auto predBB : memberBB->GetPreds()) { + if (predBB->GetCDGNode()->GetRegion() == ®ion && predBB->GetSuccsSize() > 1) { + isInPartialCycle = true; + break; + } + } + if (!isInPartialCycle && !IsInDifferentSCCNode(region, nonUniformRegionCFG, maxBBId, *curBB, *memberBB)) { + equivalentNodes.emplace_back(member); + } + } + } +} + +void ControlDepAnalysis::GenerateFCDGDot() const +{ + CHECK_FATAL(fcdg != nullptr, "construct FCDG failed"); + MapleVector &allNodes = fcdg->GetAllFCDGNodes(); + MapleVector &allEdges = fcdg->GetAllFCDGEdges(); + MapleVector &allRegions = fcdg->GetAllRegions(); + + std::streambuf *coutBuf = std::cout.rdbuf(); + std::ofstream fcdgFile; + std::streambuf *fileBuf = fcdgFile.rdbuf(); + (void)std::cout.rdbuf(fileBuf); + + // Define the output file name + std::string fileName; + (void)fileName.append("fcdg_"); + (void)fileName.append(cgFunc.GetName()); + (void)fileName.append(".dot"); + + fcdgFile.open(fileName, std::ios::trunc); + if (!fcdgFile.is_open()) { + LogInfo::MapleLogger(kLlWarn) << "fileName:" << fileName << " open failed.\n"; + return; + } + fcdgFile << "digraph FCDG_" << cgFunc.GetName() << " {\n\n"; + fcdgFile << " node [shape=box,style=filled,color=lightgrey];\n\n"; + + // Dump nodes style + for (auto node : allNodes) { + if (node == nullptr) { + continue; + } + BB *bb = node->GetBB(); + CHECK_FATAL(bb != nullptr, "get bb of CDGNode failed"); + fcdgFile << " BB_" << bb->GetId(); + fcdgFile << "[label= \""; + if (node->IsEntryNode()) { + fcdgFile << "ENTRY\n"; + } else if (node->IsExitNode()) { + fcdgFile << "EXIT\n"; + } + fcdgFile << "BB_" << bb->GetId() << " Label_" << bb->GetLabIdx() << ":\n"; + fcdgFile << " { " << bb->GetKindName() << " }\"];\n"; + } + fcdgFile << "\n"; + + // Dump edges style + for (auto edge : allEdges) { + CDGNode &fromNode = edge->GetFromNode(); + CDGNode &toNode = edge->GetToNode(); + fcdgFile << " BB_" << fromNode.GetBB()->GetId() << " -> " + << "BB_" << toNode.GetBB()->GetId(); + fcdgFile << " [label = \""; + fcdgFile << edge->GetCondition() << "\"];\n"; + } + fcdgFile << "\n"; + + // Dump region style using cluster in dot language + for (auto region : allRegions) { + if (region == nullptr) { + continue; + } + CHECK_FATAL(region->GetRegionNodeSize() != 0, "invalid region"); + fcdgFile << " subgraph cluster_" << region->GetRegionId() << " {\n"; + fcdgFile << " color=red;\n"; + fcdgFile << " label = \"region #" << region->GetRegionId() << "\";\n"; + MapleVector &memberNodes = region->GetRegionNodes(); + for (auto node : memberNodes) { + fcdgFile << " BB_" << node->GetBB()->GetId() << ";\n"; + } + fcdgFile << "}\n\n"; + } + + fcdgFile << "}\n"; + (void)fcdgFile.flush(); + fcdgFile.close(); + (void)std::cout.rdbuf(coutBuf); +} + +void ControlDepAnalysis::GenerateCFGDot() const +{ + std::streambuf *coutBuf = std::cout.rdbuf(); + std::ofstream cfgFile; + std::streambuf *fileBuf = cfgFile.rdbuf(); + (void)std::cout.rdbuf(fileBuf); + + // Define the output file name + std::string fileName; + (void)fileName.append("cfg_after_cdg_"); + (void)fileName.append(cgFunc.GetName()); + (void)fileName.append(".dot"); + + cfgFile.open(fileName, std::ios::trunc); + if (!cfgFile.is_open()) { + LogInfo::MapleLogger(kLlWarn) << "fileName:" << fileName << " open failed.\n"; + return; + } + + cfgFile << "digraph CFG_" << cgFunc.GetName() << " {\n\n"; + cfgFile << " node [shape=box];\n\n"; + + // Dump nodes style + FOR_ALL_BB_CONST(bb, &cgFunc) + { + if (bb->IsUnreachable()) { + continue; + } + cfgFile << " BB_" << bb->GetId(); + cfgFile << "[label= \""; + if (bb == cgFunc.GetFirstBB()) { + cfgFile << "ENTRY\n"; + } + cfgFile << "BB_" << bb->GetId() << " Label_" << bb->GetLabIdx() << ":\n"; + cfgFile << " { " << bb->GetKindName() << " }\"];\n"; + } + BB *exitBB = cgFunc.GetCommonExitBB(); + cfgFile << " BB_" << exitBB->GetId(); + cfgFile << "[label= \"EXIT\n"; + cfgFile << "BB_" << exitBB->GetId() << "\"];\n"; + cfgFile << "\n"; + + // Dump edges style + for (auto cfgEdge : cfgMST->GetAllEdges()) { + BB *srcBB = cfgEdge->GetSrcBB(); + BB *destBB = cfgEdge->GetDestBB(); + CHECK_FATAL(srcBB != nullptr && destBB != nullptr, "get wrong cfg-edge"); + if (srcBB == cgFunc.GetCommonExitBB()) { + continue; + } + cfgFile << " BB_" << srcBB->GetId() << " -> " + << "BB_" << destBB->GetId(); + cfgFile << " [label = \""; + cfgFile << cfgEdge->GetCondition() << "\""; + if (cfgEdge->IsBackEdge()) { + cfgFile << ",color=darkorchid1"; + } + cfgFile << "];\n"; + } + cfgFile << "\n"; + + // Dump region style using cluster in dot language + for (auto region : fcdg->GetAllRegions()) { + if (region == nullptr) { + continue; + } + CHECK_FATAL(region->GetRegionNodeSize() != 0, "invalid region"); + cfgFile << " subgraph cluster_" << region->GetRegionId() << " {\n"; + cfgFile << " color=red;\n"; + cfgFile << " label = \"region #" << region->GetRegionId() << "\";\n"; + for (auto cdgNode : region->GetRegionNodes()) { + BB *bb = cdgNode->GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + cfgFile << " BB_" << bb->GetId() << ";\n"; + } + cfgFile << "}\n\n"; + } + + cfgFile << "}\n"; + (void)cfgFile.flush(); + cfgFile.close(); + (void)std::cout.rdbuf(coutBuf); +} + +void ControlDepAnalysis::GenerateSimplifiedCFGDot() const +{ + std::streambuf *coutBuf = std::cout.rdbuf(); + std::ofstream cfgFile; + std::streambuf *fileBuf = cfgFile.rdbuf(); + (void)std::cout.rdbuf(fileBuf); + + // Define the output file name + std::string fileName; + (void)fileName.append("cfg_simplify_"); + (void)fileName.append(cgFunc.GetName()); + (void)fileName.append(".dot"); + + cfgFile.open(fileName.c_str(), std::ios::trunc); + if (!cfgFile.is_open()) { + LogInfo::MapleLogger(kLlWarn) << "fileName:" << fileName << " open failed.\n"; + return; + } + + cfgFile << "digraph CFG_SIMPLE" << cgFunc.GetName() << " {\n\n"; + cfgFile << " node [shape=box];\n\n"; + + // Dump nodes style + FOR_ALL_BB_CONST(bb, &cgFunc) + { + if (bb->IsUnreachable()) { + continue; + } + cfgFile << " BB_" << bb->GetId(); + cfgFile << "[label= \""; + if (bb == cgFunc.GetFirstBB()) { + cfgFile << "ENTRY\n"; + } + cfgFile << bb->GetId() << "\"];\n"; + } + BB *exitBB = cgFunc.GetCommonExitBB(); + cfgFile << " BB_" << exitBB->GetId(); + cfgFile << "[label= \"EXIT\n"; + cfgFile << exitBB->GetId() << "\"];\n"; + cfgFile << "\n"; + + // Dump edges style + for (auto cfgEdge : cfgMST->GetAllEdges()) { + BB *srcBB = cfgEdge->GetSrcBB(); + BB *destBB = cfgEdge->GetDestBB(); + CHECK_FATAL(srcBB != nullptr && destBB != nullptr, "get wrong cfg-edge"); + if (srcBB == cgFunc.GetCommonExitBB()) { + continue; + } + cfgFile << " BB_" << srcBB->GetId() << " -> " + << "BB_" << destBB->GetId(); + cfgFile << " [label = \""; + cfgFile << cfgEdge->GetCondition() << "\""; + if (cfgEdge->IsBackEdge()) { + cfgFile << ",color=darkorchid1"; + } + cfgFile << "];\n"; + } + + cfgFile << "}\n"; + (void)cfgFile.flush(); + cfgFile.close(); + (void)std::cout.rdbuf(coutBuf); +} + +void ControlDepAnalysis::GenerateCFGInRegionDot(CDGRegion ®ion) const +{ + std::streambuf *coutBuf = std::cout.rdbuf(); + std::ofstream cfgOfRFile; + std::streambuf *fileBuf = cfgOfRFile.rdbuf(); + (void)std::cout.rdbuf(fileBuf); + + // Define the output file name + std::string fileName; + (void)fileName.append("cfg_region"); + (void)fileName.append(std::to_string(region.GetRegionId())); + (void)fileName.append("_"); + (void)fileName.append(cgFunc.GetName()); + (void)fileName.append(".dot"); + + cfgOfRFile.open(fileName.c_str(), std::ios::trunc); + if (!cfgOfRFile.is_open()) { + LogInfo::MapleLogger(kLlWarn) << "fileName:" << fileName << " open failed.\n"; + return; + } + + cfgOfRFile << "digraph CFG_REGION" << region.GetRegionId() << " {\n\n"; + cfgOfRFile << " node [shape=box];\n\n"; + + for (auto cdgNode : region.GetRegionNodes()) { + BB *bb = cdgNode->GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + + for (auto succ = bb->GetSuccsBegin(); succ != bb->GetSuccsEnd(); ++succ) { + CDGNode *node = (*succ)->GetCDGNode(); + CHECK_FATAL(node != nullptr, "get cdgNode from bb failed"); + if (node->GetRegion() == ®ion) { + cfgOfRFile << "\tbb_" << bb->GetId() << " -> " + << "bb_" << (*succ)->GetId() << "\n"; + } + } + } + cfgOfRFile << "}\n"; + (void)cfgOfRFile.flush(); + cfgOfRFile.close(); + (void)std::cout.rdbuf(coutBuf); +} + +void CgControlDepAnalysis::GetAnalysisDependence(maple::AnalysisDep &aDep) const +{ + aDep.AddRequired(); + aDep.AddRequired(); + aDep.AddRequired(); + aDep.SetPreservedAll(); +} + +bool CgControlDepAnalysis::PhaseRun(maplebe::CGFunc &f) +{ + MemPool *cdgMemPool = GetPhaseMemPool(); + MemPool *tmpMemPool = ApplyTempMemPool(); + CHECK_FATAL(cdgMemPool != nullptr && tmpMemPool != nullptr, "get memPool failed"); + DomAnalysis *domInfo = GET_ANALYSIS(CgDomAnalysis, f); + CHECK_FATAL(domInfo != nullptr, "get result of DomAnalysis failed"); + PostDomAnalysis *pdomInfo = GET_ANALYSIS(CgPostDomAnalysis, f); + CHECK_FATAL(pdomInfo != nullptr, "get result of PostDomAnalysis failed"); + LoopAnalysis *loopInfo = GET_ANALYSIS(CgLoopAnalysis, f); + CHECK_FATAL(loopInfo != nullptr, "get result of LoopAnalysis failed"); + auto *cfgMST = cdgMemPool->New, maplebe::BB>>(*cdgMemPool); + cda = f.IsAfterRegAlloc() ? cdgMemPool->New(f, *cdgMemPool, "localschedule", true) + : cdgMemPool->New(f, *cdgMemPool, *tmpMemPool, *domInfo, *pdomInfo, + *loopInfo, cfgMST, "globalschedule"); + cda->Run(); + return true; +} +MAPLE_ANALYSIS_PHASE_REGISTER(CgControlDepAnalysis, cgcontroldepanalysis) +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_analysis.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_analysis.cpp new file mode 100644 index 0000000000..3dc43f4bfc --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_analysis.cpp @@ -0,0 +1,284 @@ +/* + * 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. + */ + +#include "data_dep_analysis.h" +#include "control_dep_analysis.h" +#include "aarch64_cg.h" + +namespace maplebe { +void DataDepAnalysis::Run(CDGRegion ®ion) +{ + MemPool *regionMp = memPoolCtrler.NewMemPool("inter-block dda mempool", true); + auto *regionAlloc = new MapleAllocator(regionMp); + + MapleVector comments(interAlloc.Adapter()); + CDGNode *root = region.GetRegionRoot(); + CHECK_FATAL(root != nullptr, "the root of region must be computed first"); + InitInfoInRegion(*regionMp, *regionAlloc, region); + + // Visit CDGNodes in the region follow the topological order of CFG + for (auto cdgNode : region.GetRegionNodes()) { + BB *curBB = cdgNode->GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from CDGNode failed"); + // Init data dependence info for cur cdgNode + InitInfoInCDGNode(*regionMp, *regionAlloc, *curBB, *cdgNode); + const Insn *locInsn = curBB->GetFirstLoc(); + FOR_BB_INSNS(insn, curBB) + { + if (!insn->IsMachineInstruction()) { + ddb.ProcessNonMachineInsn(*insn, comments, cdgNode->GetAllDataNodes(), locInsn); + continue; + } + cdgNode->AccNodeSum(); + DepNode *ddgNode = ddb.GenerateDepNode(*insn, cdgNode->GetAllDataNodes(), cdgNode->GetNodeSum(), comments); + ddb.BuildMayThrowInsnDependency(*ddgNode, *insn, *locInsn); + ddb.BuildOpndDependency(*insn); + BuildSpecialInsnDependency(*insn, *cdgNode, region, *regionAlloc); + ddb.BuildAmbiInsnDependency(*insn); + ddb.BuildAsmInsnDependency(*insn); + ddb.BuildSpecialCallDeps(*insn); + // For global schedule before RA, do not move the instruction before the call, + // avoid unnecessary callee allocation and callee save instructions. + if (!cgFunc.IsAfterRegAlloc()) { + ddb.BuildDepsLastCallInsn(*insn); + } + if (insn->IsFrameDef()) { + cdgNode->SetLastFrameDefInsn(insn); + } + UpdateRegUseAndDef(*insn, *ddgNode, *cdgNode); + } + cdgNode->CopyAndClearComments(comments); + UpdateReadyNodesInfo(*cdgNode, *root); + } + ClearInfoInRegion(regionMp, regionAlloc, region); +} + +void DataDepAnalysis::InitInfoInRegion(MemPool ®ionMp, MapleAllocator ®ionAlloc, CDGRegion ®ion) +{ + ddb.SetCDGRegion(®ion); + for (auto cdgNode : region.GetRegionNodes()) { + cdgNode->InitTopoInRegionInfo(regionMp, regionAlloc); + } +} + +void DataDepAnalysis::InitInfoInCDGNode(MemPool ®ionMp, MapleAllocator ®ionAlloc, BB &bb, CDGNode &cdgNode) +{ + ddb.SetCDGNode(&cdgNode); + ddb.InitCDGNodeDataInfo(regionMp, regionAlloc, cdgNode); + if (cgFunc.GetMirModule().IsJavaModule()) { + // Analysis live-in registers in catch BB + ddb.AnalysisAmbiInsns(bb); + } +} + +void DataDepAnalysis::BuildDepsForPrevSeparator(CDGNode &cdgNode, DepNode &depNode, CDGRegion &curRegion) +{ + if (cdgNode.GetRegion() != &curRegion) { + return; + } + DepNode *prevSepNode = nullptr; + MapleVector &dataNodes = cdgNode.GetAllDataNodes(); + for (auto i = static_cast(dataNodes.size() - 1); i >= 0; --i) { + if (dataNodes[static_cast(i)]->GetType() == kNodeTypeSeparator) { + prevSepNode = dataNodes[static_cast(i)]; + break; + } + } + if (prevSepNode != nullptr) { + ddb.AddDependence(*prevSepNode, depNode, kDependenceTypeSeparator); + return; + } + BB *bb = cdgNode.GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + for (auto predIt = bb->GetPredsBegin(); predIt != bb->GetPredsEnd(); ++predIt) { + CDGNode *predNode = (*predIt)->GetCDGNode(); + CHECK_FATAL(predNode != nullptr, "get cdgNode from bb failed"); + BuildDepsForPrevSeparator(*predNode, depNode, curRegion); + } +} + +void DataDepAnalysis::BuildSpecialInsnDependency(Insn &insn, CDGNode &cdgNode, CDGRegion ®ion, MapleAllocator &alloc) +{ + MapleVector dataNodes(alloc.Adapter()); + for (auto nodeId : cdgNode.GetTopoPredInRegion()) { + CDGNode *predNode = region.GetCDGNodeById(nodeId); + CHECK_FATAL(predNode != nullptr, "get cdgNode from region by id failed"); + for (auto depNode : predNode->GetAllDataNodes()) { + dataNodes.emplace_back(depNode); + } + } + for (auto depNode : cdgNode.GetAllDataNodes()) { + if (depNode != insn.GetDepNode()) { + dataNodes.emplace_back(depNode); + } + } + ddb.BuildSpecialInsnDependency(insn, dataNodes); +} + +void DataDepAnalysis::UpdateRegUseAndDef(Insn &insn, const DepNode &depNode, CDGNode &cdgNode) +{ + // Update reg use + const auto &useRegNos = depNode.GetUseRegnos(); + for (auto regNO : useRegNos) { + cdgNode.AppendUseInsnChain(regNO, &insn, interMp); + } + + // Update reg def + const auto &defRegNos = depNode.GetDefRegnos(); + for (const auto regNO : defRegNos) { + // Update reg def for cur depInfo + cdgNode.SetLatestDefInsn(regNO, &insn); + cdgNode.ClearUseInsnChain(regNO); + } +} + +void DataDepAnalysis::UpdateReadyNodesInfo(CDGNode &cdgNode, const CDGNode &root) const +{ + BB *bb = cdgNode.GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + for (auto succIt = bb->GetSuccsBegin(); succIt != bb->GetSuccsEnd(); ++succIt) { + CDGNode *succNode = (*succIt)->GetCDGNode(); + CHECK_FATAL(succNode != nullptr, "get cdgNode from bb failed"); + if (succNode != &root && succNode->GetRegion() == cdgNode.GetRegion()) { + succNode->SetNodeSum(std::max(cdgNode.GetNodeSum(), succNode->GetNodeSum())); + // Successor nodes in region record nodeIds that have been visited in topology order + for (const auto &nodeId : cdgNode.GetTopoPredInRegion()) { + succNode->InsertVisitedTopoPredInRegion(nodeId); + } + succNode->InsertVisitedTopoPredInRegion(cdgNode.GetNodeId()); + } + } +} + +void DataDepAnalysis::ClearInfoInRegion(MemPool *regionMp, MapleAllocator *regionAlloc, CDGRegion ®ion) const +{ + delete regionAlloc; + memPoolCtrler.DeleteMemPool(regionMp); + for (auto cdgNode : region.GetRegionNodes()) { + cdgNode->ClearDataDepInfo(); + cdgNode->ClearTopoInRegionInfo(); + } +} + +void DataDepAnalysis::GenerateDataDepGraphDotOfRegion(CDGRegion ®ion) +{ + bool hasExceedMaximum = (region.GetRegionNodes().size() > kMaxDumpRegionNodeNum); + std::streambuf *coutBuf = std::cout.rdbuf(); + std::ofstream iddgFile; + std::streambuf *fileBuf = iddgFile.rdbuf(); + (void)std::cout.rdbuf(fileBuf); + + // Define the output file name + std::string fileName; + (void)fileName.append("interDDG_"); + (void)fileName.append(cgFunc.GetName()); + (void)fileName.append("_region"); + (void)fileName.append(std::to_string(region.GetRegionId())); + (void)fileName.append(".dot"); + + iddgFile.open(fileName, std::ios::trunc); + if (!iddgFile.is_open()) { + LogInfo::MapleLogger(kLlWarn) << "fileName:" << fileName << " open failed.\n"; + return; + } + iddgFile << "digraph InterDDG_" << cgFunc.GetName() << " {\n\n"; + if (hasExceedMaximum) { + iddgFile << "newrank = true;\n"; + } + iddgFile << " node [shape=box];\n\n"; + + for (auto cdgNode : region.GetRegionNodes()) { + // Dump nodes style + for (auto depNode : cdgNode->GetAllDataNodes()) { + ddb.DumpNodeStyleInDot(iddgFile, *depNode); + } + iddgFile << "\n"; + + /* Dump edges style */ + for (auto depNode : cdgNode->GetAllDataNodes()) { + for (auto succ : depNode->GetSuccs()) { + // Avoid overly complex data dependency graphs + if (hasExceedMaximum && succ->GetDepType() == kDependenceTypeSeparator) { + continue; + } + iddgFile << " insn_" << depNode->GetInsn() << " -> " + << "insn_" << succ->GetTo().GetInsn(); + iddgFile << " ["; + switch (succ->GetDepType()) { + case kDependenceTypeTrue: + iddgFile << "color=red,"; + iddgFile << "label= \"" << succ->GetLatency() << "\""; + break; + case kDependenceTypeOutput: + iddgFile << "label= \"" + << "output" + << "\""; + break; + case kDependenceTypeAnti: + iddgFile << "label= \"" + << "anti" + << "\""; + break; + case kDependenceTypeControl: + iddgFile << "label= \"" + << "control" + << "\""; + break; + case kDependenceTypeMembar: + iddgFile << "label= \"" + << "membar" + << "\""; + break; + case kDependenceTypeThrow: + iddgFile << "label= \"" + << "throw" + << "\""; + break; + case kDependenceTypeSeparator: + iddgFile << "label= \"" + << "separator" + << "\""; + break; + case kDependenceTypeMemAccess: + iddgFile << "label= \"" + << "memAccess" + << "\""; + break; + default: + CHECK_FATAL(false, "invalid depType"); + } + iddgFile << "];\n"; + } + } + iddgFile << "\n"; + + // Dump BB cluster + BB *bb = cdgNode->GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + iddgFile << " subgraph cluster_" << bb->GetId() << " {\n"; + iddgFile << " color=blue;\n"; + iddgFile << " label = \"bb #" << bb->GetId() << "\";\n"; + for (auto depNode : cdgNode->GetAllDataNodes()) { + iddgFile << " insn_" << depNode->GetInsn() << ";\n"; + } + iddgFile << "}\n\n"; + } + + iddgFile << "}\n"; + (void)iddgFile.flush(); + iddgFile.close(); + (void)std::cout.rdbuf(coutBuf); +} +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_base.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_base.cpp new file mode 100644 index 0000000000..466f82194c --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/data_dep_base.cpp @@ -0,0 +1,496 @@ +/* + * 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. + */ + +#include "data_dep_base.h" + +namespace maplebe { +void DataDepBase::ProcessNonMachineInsn(Insn &insn, MapleVector &comments, MapleVector &dataNodes, + const Insn *&locInsn) +{ + CHECK_FATAL(!insn.IsMachineInstruction(), "need non-machine-instruction"); + if (insn.IsImmaterialInsn()) { + if (!insn.IsComment()) { + locInsn = &insn; + } else { + (void)comments.emplace_back(&insn); + } + } else if (insn.IsCfiInsn()) { + if (!dataNodes.empty()) { + dataNodes.back()->AddCfiInsn(insn); + } + } +} + +void DataDepBase::BuildDepsLastCallInsn(Insn &insn) +{ + Insn *lastCallInsn = curCDGNode->GetLastCallInsn(); + if (lastCallInsn != nullptr && !lastCallInsn->IsSpecialCall()) { + AddDependence(*lastCallInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeControl); + } + if (insn.IsCall() || insn.IsTailCall()) { + curCDGNode->SetLastCallInsn(&insn); + } +} + +// Build dependency for may throw insn +void DataDepBase::BuildMayThrowInsnDependency(DepNode &depNode, Insn &insn, const Insn &locInsn) +{ + if (!insn.MayThrow() || !cgFunc.GetMirModule().IsJavaModule()) { + return; + } + + depNode.SetLocInsn(locInsn); + curCDGNode->AddMayThrowInsn(&insn); + // Build dependency in local BB + if (isIntra || curRegion->GetRegionNodeSize() == 1 || curRegion->GetRegionRoot() == curCDGNode) { + // Build dependency between may-throw-insn and ambiguous-insn + AddDependence4InsnInVectorByType(curCDGNode->GetAmbiguousInsns(), insn, kDependenceTypeThrow); + // Build dependency between may-throw-insn and stack-def-insn + AddDependence4InsnInVectorByType(curCDGNode->GetStackDefInsns(), insn, kDependenceTypeThrow); + // Build dependency between may-throw-insn and heap-def-insn + AddDependence4InsnInVectorByType(curCDGNode->GetHeapDefInsns(), insn, kDependenceTypeThrow); + } else if (curRegion->GetRegionRoot() != curCDGNode) { + // Build dependency across BB + // Build dependency between may-throw-insn and ambiguous-insn + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeThrow, kAmbiguous); + // Build dependency between may-throw-insn and stack-def-insn + BuildInterBlockSpecialDataInfoDependency(depNode, false, kDependenceTypeThrow, kStackDefs); + // Build dependency between may-throw-insn and heap-def-insn + BuildInterBlockSpecialDataInfoDependency(depNode, false, kDependenceTypeThrow, kHeapDefs); + } + // Build dependency between may-throw-insn and last-frame-def-insn + Insn *lastFrameDef = curCDGNode->GetLastFrameDefInsn(); + if (lastFrameDef != nullptr) { + AddDependence(*lastFrameDef->GetDepNode(), *insn.GetDepNode(), kDependenceTypeThrow); + } else if (!isIntra && curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeThrow, kLastFrameDef); + } +} + +void DataDepBase::BuildAmbiInsnDependency(Insn &insn) +{ + const auto &defRegnos = insn.GetDepNode()->GetDefRegnos(); + for (const auto ®NO : defRegnos) { + if (IfInAmbiRegs(regNO)) { + BuildDepsAmbiInsn(insn); + break; + } + } +} + +// Build data dependence between control register and last call instruction. +// insn : instruction that with control register operand. +// isDest : if the control register operand is a destination operand. +void DataDepBase::BuildDepsBetweenControlRegAndCall(Insn &insn, bool isDest) +{ + Insn *lastCallInsn = curCDGNode->GetLastCallInsn(); + if (lastCallInsn == nullptr) { + return; + } + if (isDest) { + AddDependence(*lastCallInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeOutput); + return; + } + AddDependence(*lastCallInsn->GetDepNode(), *insn.GetDepNode(), kDependenceTypeAnti); +} + +// Build control data dependence for branch/ret instructions +void DataDepBase::BuildDepsControlAll(Insn &insn, const MapleVector &nodes) +{ + DepNode *depNode = insn.GetDepNode(); + // For rest instructions, we build control dependency + for (auto *dataNode : nodes) { + AddDependence(*dataNode, *depNode, kDependenceTypeControl); + } +} + +// Build data dependence of ambiguous instruction. +// ambiguous instruction: instructions that can not across may throw instructions +void DataDepBase::BuildDepsAmbiInsn(Insn &insn) +{ + if (!cgFunc.GetMirModule().IsJavaModule()) { + return; + } + if (isIntra || curRegion->GetRegionNodeSize() == 1 || curRegion->GetRegionRoot() == curCDGNode) { + MapleVector &mayThrows = curCDGNode->GetMayThrowInsns(); + AddDependence4InsnInVectorByType(mayThrows, insn, kDependenceTypeThrow); + } else if (curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockSpecialDataInfoDependency(*insn.GetDepNode(), false, kDependenceTypeThrow, kMayThrows); + } + curCDGNode->AddAmbiguousInsn(&insn); +} + +// Build data dependence of destination register operand +void DataDepBase::BuildDepsDefReg(Insn &insn, regno_t regNO) +{ + DepNode *node = insn.GetDepNode(); + node->AddDefReg(regNO); + // 1. For building intra-block data dependence, only require the data flow info of the curBB(cur CDGNode) + // 2. For building inter-block data dependence, require the data flow info of all BBs on the pred path in CFG + // Build anti dependence + if (isIntra || curRegion->GetRegionNodeSize() == 1 || curRegion->GetRegionRoot() == curCDGNode) { + RegList *regList = curCDGNode->GetUseInsnChain(regNO); + while (regList != nullptr) { + CHECK_NULL_FATAL(regList->insn); + AddDependence(*regList->insn->GetDepNode(), *node, kDependenceTypeAnti); + regList = regList->next; + } + } else if (curRegion->GetRegionRoot() != curCDGNode) { + BuildInterBlockDefUseDependency(*node, regNO, kDependenceTypeAnti, false); + } + + // Build output dependence + // Build intra block data dependence + Insn *defInsn = curCDGNode->GetLatestDefInsn(regNO); + if (defInsn != nullptr) { + AddDependence(*defInsn->GetDepNode(), *node, kDependenceTypeOutput); + } else if (!isIntra && curRegion->GetRegionRoot() != curCDGNode) { + // Build inter block data dependence + BuildInterBlockDefUseDependency(*node, regNO, kDependenceTypeOutput, true); + } +} + +// Build data dependence of source register operand +void DataDepBase::BuildDepsUseReg(Insn &insn, regno_t regNO) +{ + DepNode *node = insn.GetDepNode(); + node->AddUseReg(regNO); + + // Build intra block data dependence + Insn *defInsn = curCDGNode->GetLatestDefInsn(regNO); + if (defInsn != nullptr) { + AddDependence(*defInsn->GetDepNode(), *node, kDependenceTypeTrue); + } else if (!isIntra && curRegion->GetRegionRoot() != curCDGNode) { + // Build inter block data dependence + BuildInterBlockDefUseDependency(*node, regNO, kDependenceTypeTrue, true); + } +} + +// For inter data dependence analysis +void DataDepBase::BuildInterBlockDefUseDependency(DepNode &curDepNode, regno_t regNO, DepType depType, bool isDef) +{ + CHECK_FATAL(!isIntra, "must be inter block data dependence analysis"); + CHECK_FATAL(curRegion->GetRegionRoot() != curCDGNode, "for the root node, cross-BB search is not required"); + BB *curBB = curCDGNode->GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + std::vector visited(curRegion->GetMaxBBIdInRegion() + 1, false); + if (isDef) { + BuildPredPathDefDependencyDFS(*curBB, visited, curDepNode, regNO, depType); + } else { + BuildPredPathUseDependencyDFS(*curBB, visited, curDepNode, regNO, depType); + } +} + +void DataDepBase::BuildPredPathDefDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode, regno_t regNO, + DepType depType) +{ + if (visited[curBB.GetId()]) { + return; + } + CDGNode *cdgNode = curBB.GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + CDGRegion *region = cdgNode->GetRegion(); + CHECK_FATAL(region != nullptr, "get region from cdgNode failed"); + if (region->GetRegionId() != curRegion->GetRegionId()) { + return; + } + Insn *curDefInsn = cdgNode->GetLatestDefInsn(regNO); + if (curDefInsn != nullptr) { + visited[curBB.GetId()] = true; + AddDependence(*curDefInsn->GetDepNode(), depNode, depType); + return; + } + // Ignore back-edge + if (cdgNode == curRegion->GetRegionRoot()) { + return; + } + for (auto predIt = curBB.GetPredsBegin(); predIt != curBB.GetPredsEnd(); ++predIt) { + // Ignore back-edge of self-loop + if (*predIt != &curBB) { + BuildPredPathDefDependencyDFS(**predIt, visited, depNode, regNO, depType); + } + } +} + +void DataDepBase::BuildPredPathUseDependencyDFS(BB &curBB, std::vector &visited, DepNode &depNode, regno_t regNO, + DepType depType) +{ + if (visited[curBB.GetId()]) { + return; + } + CDGNode *cdgNode = curBB.GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + CDGRegion *region = cdgNode->GetRegion(); + CHECK_FATAL(region != nullptr, "get region from cdgNode failed"); + if (region->GetRegionId() != curRegion->GetRegionId()) { + return; + } + visited[curBB.GetId()] = true; + RegList *useChain = cdgNode->GetUseInsnChain(regNO); + while (useChain != nullptr) { + Insn *useInsn = useChain->insn; + CHECK_FATAL(useInsn != nullptr, "get useInsn failed"); + AddDependence(*useInsn->GetDepNode(), depNode, depType); + useChain = useChain->next; + } + // Ignore back-edge + if (cdgNode == curRegion->GetRegionRoot()) { + return; + } + for (auto predIt = curBB.GetPredsBegin(); predIt != curBB.GetPredsEnd(); ++predIt) { + // Ignore back-edge of self-loop + if (*predIt != &curBB) { + BuildPredPathUseDependencyDFS(**predIt, visited, depNode, regNO, depType); + } + } +} + +void DataDepBase::BuildInterBlockSpecialDataInfoDependency(DepNode &curDepNode, bool needCmp, DepType depType, + DataDepBase::DataFlowInfoType infoType) +{ + CHECK_FATAL(!isIntra, "must be inter block data dependence analysis"); + CHECK_FATAL(curRegion->GetRegionRoot() != curCDGNode, "for the root node, cross-BB search is not required"); + BB *curBB = curCDGNode->GetBB(); + CHECK_FATAL(curBB != nullptr, "get bb from cdgNode failed"); + std::vector visited(curRegion->GetMaxBBIdInRegion() + 1, false); + BuildPredPathSpecialDataInfoDependencyDFS(*curBB, visited, needCmp, curDepNode, depType, infoType); +} + +// Generate a data depNode. +// insn : create depNode for the instruction. +// nodes : a vector to store depNode. +// nodeSum : the new depNode's index. +// comments : those comment insn between last no-comment's insn and insn. +DepNode *DataDepBase::GenerateDepNode(Insn &insn, MapleVector &nodes, uint32 &nodeSum, + MapleVector &comments) +{ + Reservation *rev = mad.FindReservation(insn); + DEBUG_ASSERT(rev != nullptr, "get reservation of insn failed"); + auto *depNode = memPool.New(insn, alloc, rev->GetUnit(), rev->GetUnitNum(), *rev); + depNode->SetIndex(nodeSum++); + (void)nodes.emplace_back(depNode); + insn.SetDepNode(*depNode); + + constexpr size_t vectorSize = 5; + depNode->ReservePreds(vectorSize); + depNode->ReserveSuccs(vectorSize); + + if (!comments.empty()) { + depNode->SetComments(comments); + comments.clear(); + } + return depNode; +} + +void DataDepBase::BuildPredPathSpecialDataInfoDependencyDFS(BB &curBB, std::vector &visited, bool needCmp, + DepNode &depNode, DepType depType, + DataDepBase::DataFlowInfoType infoType) +{ + if (visited[curBB.GetId()]) { + return; + } + CDGNode *cdgNode = curBB.GetCDGNode(); + CHECK_FATAL(cdgNode != nullptr, "get cdgNode from bb failed"); + CDGRegion *region = cdgNode->GetRegion(); + CHECK_FATAL(region != nullptr, "get region from cdgNode failed"); + if (region != curCDGNode->GetRegion()) { + return; + } + + switch (infoType) { + case kMembar: { + Insn *membarInsn = cdgNode->GetMembarInsn(); + if (membarInsn != nullptr) { + visited[curBB.GetId()] = true; + AddDependence(*membarInsn->GetDepNode(), depNode, depType); + } + break; + } + case kLastCall: { + Insn *lastCallInsn = cdgNode->GetLastCallInsn(); + if (lastCallInsn != nullptr) { + visited[curBB.GetId()] = true; + AddDependence(*lastCallInsn->GetDepNode(), depNode, depType); + } + break; + } + case kLastFrameDef: { + Insn *lastFrameDef = cdgNode->GetLastFrameDefInsn(); + if (lastFrameDef != nullptr) { + visited[curBB.GetId()] = true; + AddDependence(*lastFrameDef->GetDepNode(), depNode, depType); + } + break; + } + case kStackUses: { + visited[curBB.GetId()] = true; + MapleVector stackUses = cdgNode->GetStackUseInsns(); + BuildForStackHeapDefUseInfoData(needCmp, stackUses, depNode, depType); + break; + } + case kStackDefs: { + visited[curBB.GetId()] = true; + MapleVector stackDefs = cdgNode->GetStackDefInsns(); + BuildForStackHeapDefUseInfoData(needCmp, stackDefs, depNode, depType); + break; + } + case kHeapUses: { + visited[curBB.GetId()] = true; + MapleVector &heapUses = cdgNode->GetHeapUseInsns(); + BuildForStackHeapDefUseInfoData(needCmp, heapUses, depNode, depType); + break; + } + case kHeapDefs: { + visited[curBB.GetId()] = true; + MapleVector &heapDefs = cdgNode->GetHeapDefInsns(); + BuildForStackHeapDefUseInfoData(needCmp, heapDefs, depNode, depType); + break; + } + case kMayThrows: { + CHECK_FATAL(cgFunc.GetMirModule().IsJavaModule(), "do not need build dependency for throw"); + visited[curBB.GetId()] = true; + MapleVector &mayThrows = cdgNode->GetMayThrowInsns(); + AddDependence4InsnInVectorByType(mayThrows, *depNode.GetInsn(), depType); + break; + } + case kAmbiguous: { + CHECK_FATAL(cgFunc.GetMirModule().IsJavaModule(), "do not need build dependency for ambiguous"); + visited[curBB.GetId()] = true; + MapleVector &ambiInsns = cdgNode->GetAmbiguousInsns(); + AddDependence4InsnInVectorByType(ambiInsns, *depNode.GetInsn(), depType); + break; + } + default: { + visited[curBB.GetId()] = true; + break; + } + } + // Ignore back-edge + if (cdgNode == curRegion->GetRegionRoot()) { + return; + } + for (auto predIt = curBB.GetPredsBegin(); predIt != curBB.GetPredsEnd(); ++predIt) { + // Ignore back-edge of self-loop + if (*predIt != &curBB) { + BuildPredPathSpecialDataInfoDependencyDFS(**predIt, visited, needCmp, depNode, depType, infoType); + } + } +} + +void DataDepBase::BuildForStackHeapDefUseInfoData(bool needCmp, MapleVector &insns, DepNode &depNode, + DepType depType) +{ + if (needCmp) { + AddDependence4InsnInVectorByTypeAndCmp(insns, *depNode.GetInsn(), depType); + } else { + AddDependence4InsnInVectorByType(insns, *depNode.GetInsn(), depType); + } +} + +// Build data dependency edge from FromNode to ToNode: +// Two data dependency node has a unique edge. +// These two dependencies will set the latency on the dependency edge: +// 1. True data dependency overwrites other dependency; +// 2. Output data dependency overwrites other dependency except true dependency; +// The latency of the other dependencies is 0. +void DataDepBase::AddDependence(DepNode &fromNode, DepNode &toNode, DepType depType) +{ + // Can not build a self loop dependence + if (&fromNode == &toNode) { + return; + } + // Check if exist edge between the two node + if (!fromNode.GetSuccs().empty()) { + DepLink *depLink = fromNode.GetSuccs().back(); + if (&(depLink->GetTo()) == &toNode) { + // If there exists edges, only replace with the true or output dependency + if (depLink->GetDepType() != kDependenceTypeTrue && depType == kDependenceTypeTrue) { + depLink->SetDepType(kDependenceTypeTrue); + // Set latency on true dependency edge: + // 1. if there exists bypass between defInsn and useInsn, the latency of dependency is bypass default; + // 2. otherwise, the latency of dependency is cost of defInsn + depLink->SetLatency(static_cast(mad.GetLatency(*fromNode.GetInsn(), *toNode.GetInsn()))); + } else if (depLink->GetDepType() != kDependenceTypeOutput && depType == kDependenceTypeOutput) { + depLink->SetDepType(kDependenceTypeOutput); + // Set latency on output dependency edge: + // 1. set (fromInsn_default_latency - toInsn_default_latency), if it greater than 0; + // 2. set 1 by default. + int latency = (fromNode.GetReservation()->GetLatency() - toNode.GetReservation()->GetLatency()) > 0 + ? fromNode.GetReservation()->GetLatency() - toNode.GetReservation()->GetLatency() + : 1; + depLink->SetLatency(static_cast(latency)); + } + return; + } + } + auto *depLink = memPool.New(fromNode, toNode, depType); + if (depType == kDependenceTypeTrue) { + depLink->SetLatency(static_cast(mad.GetLatency(*fromNode.GetInsn(), *toNode.GetInsn()))); + } else if (depType == kDependenceTypeOutput) { + int latency = (fromNode.GetReservation()->GetLatency() - toNode.GetReservation()->GetLatency()) > 0 + ? fromNode.GetReservation()->GetLatency() - toNode.GetReservation()->GetLatency() + : 1; + depLink->SetLatency(static_cast(latency)); + } + fromNode.AddSucc(*depLink); + toNode.AddPred(*depLink); +} + +void DataDepBase::AddDependence4InsnInVectorByType(MapleVector &insns, Insn &insn, const DepType &type) +{ + for (auto anyInsn : insns) { + AddDependence(*anyInsn->GetDepNode(), *insn.GetDepNode(), type); + } +} + +void DataDepBase::AddDependence4InsnInVectorByTypeAndCmp(MapleVector &insns, Insn &insn, const DepType &type) +{ + for (auto anyInsn : insns) { + if (anyInsn != &insn) { + AddDependence(*anyInsn->GetDepNode(), *insn.GetDepNode(), type); + } + } +} + +// Remove self data dependence (self loop) in data dependence graph. +void DataDepBase::RemoveSelfDeps(Insn &insn) +{ + DepNode *node = insn.GetDepNode(); + DEBUG_ASSERT(node->GetSuccs().back()->GetTo().GetInsn() == &insn, "Is not a self dependence."); + DEBUG_ASSERT(node->GetPreds().back()->GetFrom().GetInsn() == &insn, "Is not a self dependence."); + node->RemoveSucc(); + node->RemovePred(); +} + +// Check if regNO is in ehInRegs. +bool DataDepBase::IfInAmbiRegs(regno_t regNO) const +{ + if (!curCDGNode->HasAmbiRegs() || !cgFunc.GetMirModule().IsJavaModule()) { + return false; + } + MapleSet &ehInRegs = curCDGNode->GetEhInRegs(); + if (ehInRegs.find(regNO) != ehInRegs.end()) { + return true; + } + return false; +} + +// Return data dependence type name +const std::string &DataDepBase::GetDepTypeName(DepType depType) const +{ + DEBUG_ASSERT(depType <= kDependenceTypeNone, "array boundary check failed"); + return kDepTypeName[depType]; +} +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/global_schedule.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/global_schedule.cpp new file mode 100644 index 0000000000..62ce224837 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/global_schedule.cpp @@ -0,0 +1,201 @@ +/* + * 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. + */ + +#include "global_schedule.h" +#include "optimize_common.h" +#include "aarch64_data_dep_base.h" +#include "cg.h" + +namespace maplebe { +void GlobalSchedule::Run() +{ + FCDG *fcdg = cda.GetFCDG(); + CHECK_FATAL(fcdg != nullptr, "control dependence analysis failed"); + if (GLOBAL_SCHEDULE_DUMP) { + cda.GenerateSimplifiedCFGDot(); + cda.GenerateCFGDot(); + cda.GenerateFCDGDot(); + DotGenerator::GenerateDot("globalsched", cgFunc, cgFunc.GetMirModule(), true, cgFunc.GetName()); + } + InitInsnIdAndLocInsn(); + + uint32 times = 0; + for (auto region : fcdg->GetAllRegions()) { + if (times++ >= CGOptions::GetGlobalScheduleLimit()) { + break; + } + if (region == nullptr || !CheckCondition(*region)) { + continue; + } + interDDA.Run(*region); + if (GLOBAL_SCHEDULE_DUMP) { + cda.GenerateCFGInRegionDot(*region); + interDDA.GenerateDataDepGraphDotOfRegion(*region); + } + InitInRegion(*region); + if (CGOptions::DoVerifySchedule()) { + VerifyingSchedule(*region); + continue; + } + DoGlobalSchedule(*region); + } +} + +bool GlobalSchedule::CheckCondition(CDGRegion ®ion) +{ + uint32 insnSum = 0; + for (auto cdgNode : region.GetRegionNodes()) { + BB *bb = cdgNode->GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + FOR_BB_INSNS_CONST(insn, bb) + { + if (!insn->IsMachineInstruction()) { + continue; + } + insnSum++; + } + } + return insnSum <= kMaxInsnNum; +} + +// The entry of global scheduling +void GlobalSchedule::DoGlobalSchedule(CDGRegion ®ion) +{ + if (GLOBAL_SCHEDULE_DUMP) { + DumpRegionInfoBeforeSchedule(region); + } + listScheduler = schedMP.New(schedMP, cgFunc, true, "globalschedule"); + // Process nodes in a region by the topology sequence + for (auto cdgNode : region.GetRegionNodes()) { + BB *bb = cdgNode->GetBB(); + ASSERT(bb != nullptr, "get bb from cdgNode failed"); + if (bb->IsAtomicBuiltInBB()) { + for (auto depNode : cdgNode->GetAllDataNodes()) { + for (auto succLink : depNode->GetSuccs()) { + DepNode &succNode = succLink->GetTo(); + succNode.DecreaseValidPredsSize(); + } + } + continue; + } + + MemPool *cdgNodeMp = memPoolCtrler.NewMemPool("global-scheduler cdgNode memPool", true); + // Collect candidate instructions of current cdgNode + InitInCDGNode(region, *cdgNode, *cdgNodeMp); + + // Execute list scheduling + listScheduler->SetCDGRegion(region); + listScheduler->SetCDGNode(*cdgNode); + listScheduler->DoListScheduling(); + + // Reorder instructions in the current BB based on the scheduling result + FinishScheduling(*cdgNode); + + if (GLOBAL_SCHEDULE_DUMP) { + DumpCDGNodeInfoAfterSchedule(*cdgNode); + } + + ClearCDGNodeInfo(region, *cdgNode, cdgNodeMp); + } +} + +void GlobalSchedule::InitInCDGNode(CDGRegion ®ion, CDGNode &cdgNode, MemPool &cdgNodeMp) +{ + PrepareCommonSchedInfo(region, cdgNode, cdgNodeMp); + + // Init insnNum of curCDGNode + InitMachineInsnNum(cdgNode); + + if (GLOBAL_SCHEDULE_DUMP) { + DumpCDGNodeInfoBeforeSchedule(cdgNode); + } +} + +void GlobalSchedule::PrepareCommonSchedInfo(CDGRegion ®ion, CDGNode &cdgNode, MemPool &cdgNodeMp) +{ + commonSchedInfo = cdgNodeMp.New(cdgNodeMp); + // 1. The instructions of the current node + MapleVector &curDataNodes = cdgNode.GetAllDataNodes(); + // For verify, the node is stored in reverse order and for global, the node is stored in sequence + for (auto *depNode : curDataNodes) { + commonSchedInfo->AddCandidates(depNode); + depNode->SetState(kCandidate); + } + // 2. The instructions of the equivalent candidate nodes of the current node + std::vector equivalentNodes; + cda.GetEquivalentNodesInRegion(region, cdgNode, equivalentNodes); + if (GLOBAL_SCHEDULE_DUMP && !equivalentNodes.empty()) { + LogInfo::MapleLogger() << "BB_" << cdgNode.GetBB()->GetId() << "'s " + << "Equivalent BBs: {"; + } + for (auto *equivNode : equivalentNodes) { + BB *equivBB = equivNode->GetBB(); + ASSERT(equivBB != nullptr, "get bb from cdgNode failed"); + if (GLOBAL_SCHEDULE_DUMP) { + LogInfo::MapleLogger() << "BB_" << equivBB->GetId() << ", "; + } + if (equivBB->IsAtomicBuiltInBB()) { + continue; + } + for (auto *depNode : equivNode->GetAllDataNodes()) { + Insn *insn = depNode->GetInsn(); + CHECK_FATAL(insn != nullptr, "get insn from depNode failed"); + // call & branch insns cannot be moved across BB + if (insn->IsBranch() || insn->IsCall()) { + continue; + } + commonSchedInfo->AddCandidates(depNode); + depNode->SetState(kCandidate); + } + } + if (GLOBAL_SCHEDULE_DUMP && !equivalentNodes.empty()) { + LogInfo::MapleLogger() << "}\n"; + } + listScheduler->SetCommonSchedInfo(*commonSchedInfo); +} + +void GlobalSchedule::ClearCDGNodeInfo(CDGRegion ®ion, CDGNode &cdgNode, MemPool *cdgNodeMp) +{ + std::vector equivalentNodes; + cda.GetEquivalentNodesInRegion(region, cdgNode, equivalentNodes); + for (auto *equivNode : equivalentNodes) { + for (auto *depNode : equivNode->GetAllDataNodes()) { + ASSERT(depNode->GetState() != kScheduled, "update state of depNode failed in finishScheduling"); + depNode->SetState(kNormal); + } + } + + memPoolCtrler.DeleteMemPool(cdgNodeMp); + commonSchedInfo = nullptr; +} + +void CgGlobalSchedule::GetAnalysisDependence(maple::AnalysisDep &aDep) const +{ + aDep.AddRequired(); +} + +bool CgGlobalSchedule::PhaseRun(maplebe::CGFunc &f) +{ + MemPool *memPool = GetPhaseMemPool(); + ControlDepAnalysis *cda = GET_ANALYSIS(CgControlDepAnalysis, f); + MAD *mad = Globals::GetInstance()->GetMAD(); + auto *ddb = memPool->New(*memPool, f, *mad, false); + auto *dda = memPool->New(f, *memPool, *ddb); + auto *globalScheduler = f.GetCG()->CreateGlobalSchedule(*memPool, f, *cda, *dda); + globalScheduler->Run(); + return true; +} +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgGlobalSchedule, globalschedule) +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/list_scheduler.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/list_scheduler.cpp new file mode 100644 index 0000000000..037ee090d7 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/list_scheduler.cpp @@ -0,0 +1,771 @@ +/* + * 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. + */ + +#include "list_scheduler.h" + +namespace maplebe { +uint32 ListScheduler::lastSchedInsnId = 0; + +void ListScheduler::DoListScheduling() +{ + Init(); + + if (doDelayHeuristics) { + /* Compute delay priority of all candidates */ + ComputeDelayPriority(); + } + + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << "## --- schedule bb_" << curCDGNode->GetBB()->GetId() << " ---\n\n"; + if (doDelayHeuristics) { + DumpDelay(); + } + LogInfo::MapleLogger() << " >> dependencies resolved: "; + } + + // Push depNodes whose dependencies resolved into waitingQueue + CandidateToWaitingQueue(); + + ComputeEStart(currCycle); + + // Iterate until the instructions in the current BB are scheduled + while (scheduledNodeNum < curCDGNode->GetInsnNum()) { + UpdateInfoBeforeSelectNode(); + + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << "\n\n '' current cycle: " << currCycle << "\n\n"; + DumpWaitingQueue(); + } + + // Push depNodes whose resources are free from waitingQueue into readyList + WaitingQueueToReadyList(); + + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << " >> After waitingQueue to readyList: {"; + DumpReadyList(); + } + + // If there are no ready insns, stall until one is ready + if (readyList.empty()) { + advancedCycle = 1; + continue; + } + + CalculateMostUsedUnitKindCount(); + + if (!doDelayHeuristics) { + // Update LStart + ComputeLStart(); + if (LIST_SCHEDULE_DUMP || isUnitTest) { + DumpEStartLStartOfAllNodes(); + } + } + + // Sort the readyList by priority from highest to lowest + SortReadyList(); + + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << " >> ReadyList after sort: {"; + DumpReadyList(); + } + + // Select the ready node with the highest priority + DepNode *schedNode = *readyList.begin(); + CHECK_FATAL(schedNode != nullptr, "select readyNode failed"); + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << " >> Select node: insn_" << schedNode->GetInsn()->GetId() << "\n\n"; + } + + if (schedNode->GetInsn()->GetBB()->GetId() == curCDGNode->GetBB()->GetId()) { + scheduledNodeNum++; + } + UpdateInfoAfterSelectNode(*schedNode); + } + commonSchedInfo = nullptr; +} + +void ListScheduler::Init() +{ + DEBUG_ASSERT(region != nullptr, "invalid region"); + DEBUG_ASSERT(curCDGNode != nullptr, "invalid cdgNode"); + DEBUG_ASSERT(commonSchedInfo != nullptr, "invalid common scheduling info"); + + mad = Globals::GetInstance()->GetMAD(); + + waitingQueue.clear(); + readyList.clear(); + + mad->ReleaseAllUnits(); + currCycle = 0; + advancedCycle = 0; + scheduledNodeNum = 0; + + MapleVector &candidates = commonSchedInfo->GetCandidates(); + // Set the initial earliest time of all nodes to 0 + for (auto *depNode : candidates) { + depNode->SetEStart(0); + } + + lastSchedInsnId = 0; +} + +void ListScheduler::CandidateToWaitingQueue() +{ + MapleVector &candidates = commonSchedInfo->GetCandidates(); + auto candiIter = candidates.begin(); + while (candiIter != candidates.end()) { + DepNode *candiNode = *candiIter; + // dependencies resolved + if (candiNode->GetValidPredsSize() == 0) { + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << "insn_" << candiNode->GetInsn()->GetId() << ", "; + } + (void)waitingQueue.emplace_back(candiNode); + candiNode->SetState(kWaiting); + candiIter = commonSchedInfo->EraseIterFromCandidates(candiIter); + } else { + ++candiIter; + } + } +} + +void ListScheduler::WaitingQueueToReadyList() +{ + auto waitingIter = waitingQueue.begin(); + while (waitingIter != waitingQueue.end()) { + DepNode *waitingNode = *waitingIter; + // Just check whether the current cycle is free, because + // the rightmost bit of occupyTable always indicates curCycle + if (((cgFunc.IsAfterRegAlloc() && waitingNode->IsResourceIdle()) || !cgFunc.IsAfterRegAlloc()) && + waitingNode->GetEStart() <= currCycle) { + (void)readyList.emplace_back(waitingNode); + waitingNode->SetState(kReady); + waitingIter = EraseIterFromWaitingQueue(waitingIter); + } else { + ++waitingIter; + } + } +} + +static uint32 kMaxUnitIdx = 0; +// Sort by priority in descending order, which use LStart as algorithm of computing priority, +// that is the first node in list has the highest priority +bool ListScheduler::CriticalPathRankScheduleInsns(const DepNode *node1, const DepNode *node2) +{ + // p as an acronym for priority + CompareLStart compareLStart; + int p1 = compareLStart(*node1, *node2); + if (p1 != 0) { + return p1 > 0; + } + + CompareCost compareCost; + int p2 = compareCost(*node1, *node2); + if (p2 != 0) { + return p2 > 0; + } + + CompareEStart compareEStart; + int p3 = compareEStart(*node1, *node2); + if (p3 != 0) { + return p3 > 0; + } + + CompareSuccNodeSize compareSuccNodeSize; + int p4 = compareSuccNodeSize(*node1, *node2); + if (p4 != 0) { + return p4 > 0; + } + + CompareUnitKindNum compareUnitKindNum(kMaxUnitIdx); + int p5 = compareUnitKindNum(*node1, *node2); + if (p5 != 0) { + return p5 > 0; + } + + CompareSlotType compareSlotType; + int p6 = compareSlotType(*node1, *node2); + if (p6 != 0) { + return p6 > 0; + } + + CompareInsnID compareInsnId; + int p7 = compareInsnId(*node1, *node2); + if (p7 != 0) { + return p7 > 0; + } + + // default + return true; +} + +void ListScheduler::UpdateInfoBeforeSelectNode() +{ + while (advancedCycle > 0) { + currCycle++; + // Update the occupation of cpu units + mad->AdvanceOneCycleForAll(); + advancedCycle--; + } + // Fall back to the waitingQueue if the depNode in readyList has resources conflict + UpdateNodesInReadyList(); +} + +void ListScheduler::SortReadyList() +{ + // Use default rank rules + if (rankScheduleInsns == nullptr) { + if (doDelayHeuristics) { + std::sort(readyList.begin(), readyList.end(), DelayRankScheduleInsns); + } else { + std::sort(readyList.begin(), readyList.end(), CriticalPathRankScheduleInsns); + } + } else { + // Use custom rank rules + std::sort(readyList.begin(), readyList.end(), rankScheduleInsns); + } +} + +void ListScheduler::UpdateEStart(DepNode &schedNode) +{ + std::vector traversalList; + (void)traversalList.emplace_back(&schedNode); + + while (!traversalList.empty()) { + DepNode *curNode = traversalList.front(); + traversalList.erase(traversalList.begin()); + + for (auto succLink : curNode->GetSuccs()) { + DepNode &succNode = succLink->GetTo(); + DEBUG_ASSERT(succNode.GetState() != kScheduled, "invalid state of depNode"); + succNode.SetEStart(std::max(succNode.GetEStart(), schedNode.GetSchedCycle() + succLink->GetLatency())); + maxEStart = std::max(maxEStart, succNode.GetEStart()); + if (!succNode.GetSuccs().empty() && + std::find(traversalList.begin(), traversalList.end(), &succNode) == traversalList.end()) { + (void)traversalList.emplace_back(&succNode); + } + } + } +} + +void ListScheduler::UpdateInfoAfterSelectNode(DepNode &schedNode) +{ + schedNode.SetState(kScheduled); + schedNode.SetSchedCycle(currCycle); + if (cgFunc.IsAfterRegAlloc()) { + schedNode.OccupyRequiredUnits(); + } + schedNode.SetEStart(currCycle); + commonSchedInfo->AddSchedResults(&schedNode); + lastSchedInsnId = schedNode.GetInsn()->GetId(); + lastSchedNode = &schedNode; + EraseNodeFromReadyList(&schedNode); + UpdateAdvanceCycle(schedNode); + + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << " >> dependencies resolved: {"; + } + for (auto succLink : schedNode.GetSuccs()) { + DepNode &succNode = succLink->GetTo(); + succNode.DecreaseValidPredsSize(); + // Push depNodes whose dependencies resolved from candidates into waitingQueue + if (succNode.GetValidPredsSize() == 0 && succNode.GetState() == kCandidate) { + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << "insn_" << succNode.GetInsn()->GetId() << ", "; + } + (void)waitingQueue.emplace_back(&succNode); + commonSchedInfo->EraseNodeFromCandidates(&succNode); + succNode.SetState(kWaiting); + } + } + + UpdateEStart(schedNode); + + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << "}\n\n"; + DumpScheduledResult(); + LogInfo::MapleLogger() << "'' issue insn_" << schedNode.GetInsn()->GetId() << " [ "; + schedNode.GetInsn()->Dump(); + LogInfo::MapleLogger() << " ] " + << " at cycle " << currCycle << "\n\n"; + } + + // Add comment + Insn *schedInsn = schedNode.GetInsn(); + DEBUG_ASSERT(schedInsn != nullptr, "get schedInsn from schedNode failed"); + Reservation *res = schedNode.GetReservation(); + DEBUG_ASSERT(res != nullptr, "get reservation of insn failed"); + schedInsn->AppendComment(std::string("run on cycle: ") + .append(std::to_string(schedNode.GetSchedCycle())) + .append("; ") + .append(std::string("cost: ")) + .append(std::to_string(res->GetLatency())) + .append("; ")); + schedInsn->AppendComment(std::string("from bb: ").append(std::to_string(schedInsn->GetBB()->GetId()))); +} + +void ListScheduler::UpdateNodesInReadyList() +{ + auto readyIter = readyList.begin(); + while (readyIter != readyList.end()) { + DepNode *readyNode = *readyIter; + CHECK_NULL_FATAL(lastSchedNode); + // In globalSchedule before RA, we do not consider resource conflict in pipeline + if ((cgFunc.IsAfterRegAlloc() && !readyNode->IsResourceIdle()) || readyNode->GetEStart() > currCycle) { + if (LIST_SCHEDULE_DUMP || isUnitTest) { + LogInfo::MapleLogger() << " >> ReadyList -> WaitingQueue: insn_" << readyNode->GetInsn()->GetId() + << " (resource conflict)\n\n"; + } + (void)waitingQueue.emplace_back(readyNode); + readyNode->SetState(kWaiting); + readyIter = EraseIterFromReadyList(readyIter); + } else { + ++readyIter; + } + } +} + +void ListScheduler::UpdateAdvanceCycle(const DepNode &schedNode) +{ + switch (schedNode.GetInsn()->GetLatencyType()) { + case kLtClinit: + advancedCycle = kClinitAdvanceCycle; + break; + case kLtAdrpLdr: + advancedCycle = kAdrpLdrAdvanceCycle; + break; + case kLtClinitTail: + advancedCycle = kClinitTailAdvanceCycle; + break; + default: + break; + } + + if (advancedCycle == 0 && mad->IsFullIssued()) { + advancedCycle = 1; + } +} + +// Compute the delay of the depNode by postorder, which is calculated only once before scheduling, +// and the delay of the leaf node is initially set to 0 or execTime +void ListScheduler::ComputeDelayPriority() +{ + std::vector traversalList; + MapleVector &candidates = commonSchedInfo->GetCandidates(); + for (auto *depNode : candidates) { + if (depNode->GetSuccs().empty()) { // Leaf node + depNode->SetDelay(static_cast(depNode->GetReservation()->GetLatency())); + (void)traversalList.emplace_back(depNode); + } else { + depNode->SetDelay(0); + } + } + + // Compute delay from leaf node to root node + while (!traversalList.empty()) { + DepNode *depNode = traversalList.front(); + traversalList.erase(traversalList.begin()); + + for (const auto *predLink : depNode->GetPreds()) { + DepNode &predNode = predLink->GetFrom(); + // Consider the cumulative effect of nodes on the critical path + predNode.SetDelay(std::max(predLink->GetLatency() + depNode->GetDelay(), predNode.GetDelay())); + maxDelay = std::max(maxDelay, predNode.GetDelay()); + predNode.DecreaseValidSuccsSize(); + if (predNode.GetValidSuccsSize() == 0) { + (void)traversalList.emplace_back(&predNode); + } + } + } +} + +void ListScheduler::InitInfoBeforeCompEStart(uint32 cycle, std::vector &traversalList) +{ + for (CDGNode *cdgNode : region->GetRegionNodes()) { + for (auto *depNode : cdgNode->GetAllDataNodes()) { + depNode->SetTopoPredsSize(static_cast(depNode->GetPreds().size())); + if (depNode->GetState() != kScheduled) { + depNode->SetEStart(cycle); + } + if (depNode->GetTopoPredsSize() == 0) { + (void)traversalList.emplace_back(depNode); + } + } + } +} + +// Compute the earliest start cycle of the instruction. +// Regardless of whether the LStart heuristic is used, EStart always needs to be calculated, +// which indicates the cycles required for an insn to wait because of the resource conflict. +void ListScheduler::ComputeEStart(uint32 cycle) +{ + std::vector traversalList; + InitInfoBeforeCompEStart(cycle, traversalList); + + // Compute the eStart of each depNode in the topology sequence + while (!traversalList.empty()) { + DepNode *depNode = traversalList.front(); + traversalList.erase(traversalList.begin()); + + for (const auto *succLink : depNode->GetSuccs()) { + DepNode &succNode = succLink->GetTo(); + succNode.DecreaseTopoPredsSize(); + + if (succNode.GetState() != kScheduled) { + succNode.SetEStart(std::max(depNode->GetEStart() + succLink->GetLatency(), succNode.GetEStart())); + } + maxEStart = std::max(succNode.GetEStart(), maxEStart); + + if (succNode.GetTopoPredsSize() == 0) { + (void)traversalList.emplace_back(&succNode); + } + } + } + if (maxEStart < cycle) { + maxEStart = cycle; + } +} + +void ListScheduler::InitInfoBeforeCompLStart(std::vector &traversalList) +{ + for (CDGNode *cdgNode : region->GetRegionNodes()) { + for (auto *depNode : cdgNode->GetAllDataNodes()) { + if (depNode->GetState() != kScheduled) { + depNode->SetLStart(maxEStart); + } + depNode->SetValidSuccsSize(static_cast(depNode->GetSuccs().size())); + if (depNode->GetSuccs().empty()) { + (void)traversalList.emplace_back(depNode); + } + } + } +} + +// Compute the latest start cycle of the instruction, which +// is dynamically recalculated based on the current maxEStart during scheduling. +void ListScheduler::ComputeLStart() +{ + maxLStart = maxEStart; + + MapleVector &candidates = commonSchedInfo->GetCandidates(); + if (candidates.empty() && waitingQueue.empty()) { + return; + } + + // Push leaf nodes into traversalList + std::vector traversalList; + InitInfoBeforeCompLStart(traversalList); + + // Compute the lStart of all nodes in the topology sequence + while (!traversalList.empty()) { + DepNode *depNode = traversalList.front(); + traversalList.erase(traversalList.begin()); + + for (const auto predLink : depNode->GetPreds()) { + DepNode &predNode = predLink->GetFrom(); + + if (predNode.GetState() != kScheduled) { + predNode.SetLStart(std::min(depNode->GetLStart() - predLink->GetLatency(), predNode.GetLStart())); + } + maxLStart = std::max(maxLStart, predNode.GetLStart()); + + predNode.DecreaseValidSuccsSize(); + if (predNode.GetValidSuccsSize() == 0) { + traversalList.emplace_back(&predNode); + } + } + } +} + +// Calculate the most used unitKind index +void ListScheduler::CalculateMostUsedUnitKindCount() +{ + std::array unitKindCount = {0}; + for (auto *depNode : readyList) { + CountUnitKind(*depNode, unitKindCount); + } + + uint32 maxCount = 0; + kMaxUnitIdx = 0; + for (uint32 i = 1; i < kUnitKindLast; ++i) { + if (maxCount < unitKindCount[i]) { + maxCount = unitKindCount[i]; + kMaxUnitIdx = i; + } + } +} + +// The index of unitKindCount is unitKind, the element of unitKindCount is count of the unitKind +void ListScheduler::CountUnitKind(const DepNode &depNode, std::array &unitKindCount) const +{ + uint32 unitKind = depNode.GetUnitKind(); + auto index = static_cast(__builtin_ffs(static_cast(unitKind))); + while (index != 0) { + DEBUG_ASSERT(index < kUnitKindLast, "invalid unitKind index"); + ++unitKindCount[index]; + unitKind &= ~(1u << (index - 1u)); + index = static_cast(__builtin_ffs(static_cast(unitKind))); + } +} + +void ListScheduler::DumpWaitingQueue() const +{ + LogInfo::MapleLogger() << " >> waitingQueue: {"; + for (uint32 i = 0; i < waitingQueue.size(); ++i) { + Insn *waitInsn = waitingQueue[i]->GetInsn(); + DEBUG_ASSERT(waitInsn != nullptr, "get insn from depNode failed"); + LogInfo::MapleLogger() << "insn_" << waitInsn->GetId(); + if (i != waitingQueue.size() - 1) { + LogInfo::MapleLogger() << ", "; + } + } + LogInfo::MapleLogger() << "}\n\n"; +} + +void ListScheduler::DumpReadyList() const +{ + for (uint32 i = 0; i < readyList.size(); ++i) { + Insn *readyInsn = readyList[i]->GetInsn(); + DEBUG_ASSERT(readyInsn != nullptr, "get insn from depNode failed"); + if (doDelayHeuristics) { + LogInfo::MapleLogger() << "insn_" << readyInsn->GetId() << "(Delay = " << readyList[i]->GetDelay() << ")"; + } else { + LogInfo::MapleLogger() << "insn_" << readyInsn->GetId() << "(EStart = " << readyList[i]->GetEStart() + << ", LStart = " << readyList[i]->GetLStart() << ")"; + } + if (i != readyList.size() - 1) { + LogInfo::MapleLogger() << ", "; + } + } + LogInfo::MapleLogger() << "}\n\n"; +} + +void ListScheduler::DumpScheduledResult() const +{ + LogInfo::MapleLogger() << " >> scheduledResult: {"; + for (uint32 i = 0; i < commonSchedInfo->GetSchedResultsSize(); ++i) { + Insn *schedInsn = commonSchedInfo->GetSchedResults()[i]->GetInsn(); + DEBUG_ASSERT(schedInsn != nullptr, "get insn from depNode failed"); + LogInfo::MapleLogger() << "insn_" << schedInsn->GetId(); + if (i != commonSchedInfo->GetSchedResultsSize() - 1) { + LogInfo::MapleLogger() << ", "; + } + } + LogInfo::MapleLogger() << "}\n\n"; +} + +void ListScheduler::DumpDelay() const +{ + BB *curBB = curCDGNode->GetBB(); + DEBUG_ASSERT(curBB != nullptr, "get bb from cdgNode failed"); + LogInfo::MapleLogger() << " >> Delay priority of readyList in bb_" << curBB->GetId() << "\n"; + LogInfo::MapleLogger() << " --------------------------------------------------------\n"; + (void)LogInfo::MapleLogger().fill(' '); + LogInfo::MapleLogger() << " " << std::setiosflags(std::ios::left) << std::setw(kNumEight) << "insn" + << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right) + << std::setw(kNumFour) << "bb" << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumTen) << "predDepSize" + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumTen) << "delay" << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumEight) << "cost" + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumFifteen) << "reservation" << std::resetiosflags(std::ios::right) << "\n"; + LogInfo::MapleLogger() << " --------------------------------------------------------\n"; + for (auto depNode : commonSchedInfo->GetCandidates()) { + Insn *insn = depNode->GetInsn(); + ASSERT_NOT_NULL(insn); + uint32 predSize = depNode->GetValidPredsSize(); + uint32 delay = depNode->GetDelay(); + ASSERT_NOT_NULL(mad); + ASSERT_NOT_NULL(mad->FindReservation(*insn)); + int latency = mad->FindReservation(*insn)->GetLatency(); + LogInfo::MapleLogger() << " " << std::setiosflags(std::ios::left) << std::setw(kNumEight) << insn->GetId() + << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right) + << std::setw(kNumFour) << curBB->GetId() << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumTen) << predSize + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumTen) << delay << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumEight) << latency + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumFifteen); + DumpReservation(*depNode); + LogInfo::MapleLogger() << std::resetiosflags(std::ios::right) << "\n"; + } + LogInfo::MapleLogger() << " --------------------------------------------------------\n\n"; +} + +void ListScheduler::DumpEStartLStartOfAllNodes() +{ + BB *curBB = curCDGNode->GetBB(); + DEBUG_ASSERT(curBB != nullptr, "get bb from cdgNode failed"); + LogInfo::MapleLogger() << " >> max EStart: " << maxEStart << "\n\n"; + LogInfo::MapleLogger() << " >> CP priority of readyList in bb_" << curBB->GetId() << "\n"; + LogInfo::MapleLogger() << " --------------------------------------------------------------------------\n"; + (void)LogInfo::MapleLogger().fill(' '); + LogInfo::MapleLogger() << " " << std::setiosflags(std::ios::left) << std::setw(kNumEight) << "insn" + << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right) + << std::setw(kNumFour) << "bb" << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumEight) << "state" + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumTwelve) << "predDepSize" << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumTen) << "EStart" + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumTen) << "LStart" << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumEight) << "cost" + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumFifteen) << "reservation" << std::resetiosflags(std::ios::right) << "\n"; + LogInfo::MapleLogger() << " --------------------------------------------------------------------------\n"; + DumpDepNodeInfo(*curBB, commonSchedInfo->GetCandidates(), "candi"); + DumpDepNodeInfo(*curBB, waitingQueue, "wait"); + DumpDepNodeInfo(*curBB, readyList, "ready"); + LogInfo::MapleLogger() << " --------------------------------------------------------------------------\n\n"; +} + +void ListScheduler::DumpDepNodeInfo(const BB &curBB, MapleVector &nodes, const std::string state) const +{ + for (auto depNode : nodes) { + Insn *insn = depNode->GetInsn(); + DEBUG_ASSERT(insn != nullptr, "get insn from depNode failed"); + uint32 predSize = depNode->GetValidPredsSize(); + uint32 eStart = depNode->GetEStart(); + uint32 lStart = depNode->GetLStart(); + ASSERT_NOT_NULL(mad->FindReservation(*insn)); + int latency = mad->FindReservation(*insn)->GetLatency(); + (void)LogInfo::MapleLogger().fill(' '); + LogInfo::MapleLogger() << " " << std::setiosflags(std::ios::left) << std::setw(kNumEight) << insn->GetId() + << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right) + << std::setw(kNumFour) << curBB.GetId() << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumEight) << state + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumTwelve) << predSize << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumTen) << eStart + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumTen) << lStart << std::resetiosflags(std::ios::right) + << std::setiosflags(std::ios::right) << std::setw(kNumEight) << latency + << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::right) + << std::setw(kNumFour) << " "; + DumpReservation(*depNode); + LogInfo::MapleLogger() << std::resetiosflags(std::ios::right) << "\n"; + } +} + +void ListScheduler::DumpReservation(const DepNode &depNode) const +{ + for (uint32 i = 0; i < depNode.GetUnitNum(); ++i) { + UnitId unitId = depNode.GetUnitByIndex(i)->GetUnitId(); + switch (unitId) { + case kUnitIdSlot0: + LogInfo::MapleLogger() << "slot0"; + break; + case kUnitIdSlot1: + LogInfo::MapleLogger() << "slot1"; + break; + case kUnitIdAgen: + LogInfo::MapleLogger() << "agen"; + break; + case kUnitIdHazard: + LogInfo::MapleLogger() << "hazard"; + break; + case kUnitIdCrypto: + LogInfo::MapleLogger() << "crypto"; + break; + case kUnitIdMul: + LogInfo::MapleLogger() << "mul"; + break; + case kUnitIdDiv: + LogInfo::MapleLogger() << "div"; + break; + case kUnitIdBranch: + LogInfo::MapleLogger() << "branch"; + break; + case kUnitIdStAgu: + LogInfo::MapleLogger() << "stAgu"; + break; + case kUnitIdLdAgu: + LogInfo::MapleLogger() << "ldAgu"; + break; + case kUnitIdFpAluLo: + LogInfo::MapleLogger() << "fpAluLo"; + break; + case kUnitIdFpAluHi: + LogInfo::MapleLogger() << "fpAluHi"; + break; + case kUnitIdFpMulLo: + LogInfo::MapleLogger() << "fpMulLo"; + break; + case kUnitIdFpMulHi: + LogInfo::MapleLogger() << "fpMulHi"; + break; + case kUnitIdFpDivLo: + LogInfo::MapleLogger() << "fpDivLo"; + break; + case kUnitIdFpDivHi: + LogInfo::MapleLogger() << "fpDivHi"; + break; + case kUnitIdSlotS: + LogInfo::MapleLogger() << "slot0 | slot1"; + break; + case kUnitIdFpAluS: + LogInfo::MapleLogger() << "fpAluLo | fpAluHi"; + break; + case kUnitIdFpMulS: + LogInfo::MapleLogger() << "fpMulLo | fpMulHi"; + break; + case kUnitIdFpDivS: + LogInfo::MapleLogger() << "fpDivLo | fpDivHi"; + break; + case kUnitIdSlotD: + LogInfo::MapleLogger() << "slot0 & slot1"; + break; + case kUnitIdFpAluD: + LogInfo::MapleLogger() << "fpAluLo & fpAluHi"; + break; + case kUnitIdFpMulD: + LogInfo::MapleLogger() << "fpMulLo & fpMulHi"; + break; + case kUnitIdFpDivD: + LogInfo::MapleLogger() << "fpMulLo & fpMulHi"; + break; + case kUnitIdSlotSHazard: + LogInfo::MapleLogger() << "(slot0 | slot1) & hazard"; + break; + case kUnitIdSlotSMul: + LogInfo::MapleLogger() << "(slot0 | slot1) & mul"; + break; + case kUnitIdSlotSBranch: + LogInfo::MapleLogger() << "(slot0 | slot1) & branch"; + break; + case kUnitIdSlotSAgen: + LogInfo::MapleLogger() << "(slot0 | slot1) & agen"; + break; + case kUnitIdSlotDAgen: + LogInfo::MapleLogger() << "slot0 & slot1 & agen"; + break; + case kUnitIdSlot0LdAgu: + LogInfo::MapleLogger() << "slot0 & ldAgu"; + break; + case kUnitIdSlot0StAgu: + LogInfo::MapleLogger() << "slot0 & stAgu"; + break; + default: + LogInfo::MapleLogger() << "unknown"; + break; + } + if (i != depNode.GetUnitNum() - 1) { + LogInfo::MapleLogger() << ", "; + } + } +} +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/local_schedule.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/local_schedule.cpp new file mode 100644 index 0000000000..1befbb183b --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/local_schedule.cpp @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#include "local_schedule.h" +#include "data_dep_base.h" +#include "aarch64_data_dep_base.h" +#include "cg.h" +#include "optimize_common.h" + +namespace maplebe { +void LocalSchedule::Run() +{ + FCDG *fcdg = cda.GetFCDG(); + CHECK_FATAL(fcdg != nullptr, "control dependence analysis failed"); + if (LOCAL_SCHEDULE_DUMP) { + DotGenerator::GenerateDot("localsched", cgFunc, cgFunc.GetMirModule(), true, cgFunc.GetName()); + } + InitInsnIdAndLocInsn(); + for (auto region : fcdg->GetAllRegions()) { + if (region == nullptr || !CheckCondition(*region)) { + continue; + } + DoLocalScheduleForRegion(*region); + } +} + +bool LocalSchedule::CheckCondition(CDGRegion ®ion) const +{ + CHECK_FATAL(region.GetRegionNodeSize() == 1 && region.GetRegionRoot() != nullptr, + "invalid region in local scheduling"); + uint32 insnSum = 0; + for (auto cdgNode : region.GetRegionNodes()) { + BB *bb = cdgNode->GetBB(); + CHECK_FATAL(bb != nullptr, "get bb from cdgNode failed"); + FOR_BB_INSNS_CONST(insn, bb) + { + if (!insn->IsMachineInstruction()) { + continue; + } + insnSum++; + } + } + if (insnSum > kMaxInsnNum) { + return false; + } + return true; +} + +void LocalSchedule::DoLocalScheduleForRegion(CDGRegion ®ion) +{ + CDGNode *cdgNode = region.GetRegionRoot(); + BB *bb = cdgNode->GetBB(); + DEBUG_ASSERT(bb != nullptr, "get bb from cdgNode failed"); + if (bb->IsAtomicBuiltInBB()) { + return; + } + intraDDA.Run(region); + if (LOCAL_SCHEDULE_DUMP) { + intraDDA.GenerateDataDepGraphDotOfRegion(region); + } + InitInRegion(region); + if (LOCAL_SCHEDULE_DUMP || isUnitTest) { + DumpRegionInfoBeforeSchedule(region); + } + DoLocalSchedule(*cdgNode); +} + +void LocalSchedule::DoLocalSchedule(CDGNode &cdgNode) +{ + listScheduler = schedMP.New(schedMP, cgFunc, true, "localschedule"); + InitInCDGNode(cdgNode); + listScheduler->SetCDGRegion(*cdgNode.GetRegion()); + listScheduler->SetCDGNode(cdgNode); + listScheduler->SetUnitTest(isUnitTest); + listScheduler->DoListScheduling(); + FinishScheduling(cdgNode); + if (LOCAL_SCHEDULE_DUMP || isUnitTest) { + DumpCDGNodeInfoAfterSchedule(cdgNode); + } +} + +void LocalSchedule::InitInCDGNode(CDGNode &cdgNode) +{ + commonSchedInfo = schedMP.New(schedMP); + for (auto *depNode : cdgNode.GetAllDataNodes()) { + commonSchedInfo->AddCandidates(depNode); + depNode->SetState(kCandidate); + } + listScheduler->SetCommonSchedInfo(*commonSchedInfo); + + InitMachineInsnNum(cdgNode); + + if (LOCAL_SCHEDULE_DUMP || isUnitTest) { + DumpCDGNodeInfoBeforeSchedule(cdgNode); + } +} + +bool CgLocalSchedule::PhaseRun(maplebe::CGFunc &f) +{ + MemPool *memPool = GetPhaseMemPool(); + auto *cda = memPool->New(f, *memPool, "localschedule", true); + cda->Run(); + MAD *mad = Globals::GetInstance()->GetMAD(); + auto *ddb = memPool->New(*memPool, f, *mad, true); + auto *dda = memPool->New(f, *memPool, *ddb); + auto *localScheduler = f.GetCG()->CreateLocalSchedule(*memPool, f, *cda, *dda); + localScheduler->Run(); + return true; +} +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(CgLocalSchedule, localschedule) +} // namespace maplebe diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp index 30e17a6d6a..8b59fdeb6f 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp @@ -69,6 +69,33 @@ void LoopHierarchy::PrintLoops(const std::string &name) const } } +void LoopDesc::Dump() const +{ + LogInfo::MapleLogger() << "LoopDesc:" << header.GetId() << ", nest depth:" << nestDepth; + if (parentLoop != nullptr) { + LogInfo::MapleLogger() << ", parent:" << parentLoop->GetHeader().GetId(); + } + LogInfo::MapleLogger() << "\n\tbackedge:"; + for (auto bbId : backEdges) { + LogInfo::MapleLogger() << bbId << " "; + } + LogInfo::MapleLogger() << "\n\tmembers:"; + for (auto bbId : loopBBs) { + LogInfo::MapleLogger() << bbId << " "; + } + LogInfo::MapleLogger() << "\n\texitBB:"; + for (auto bbId : exitBBs) { + LogInfo::MapleLogger() << bbId << " "; + } + if (!childLoops.empty()) { + LogInfo::MapleLogger() << "\n\tchild loops:"; + for (auto *childLoop : childLoops) { + LogInfo::MapleLogger() << childLoop->GetHeader().GetId() << " "; + } + } + LogInfo::MapleLogger() << "\n\n"; +} + bool CGFuncLoops::IsBBLoopMember(const BB *bb) { return (*(std::find(loopMembers.begin(), loopMembers.end(), bb)) == bb); @@ -678,6 +705,102 @@ void LoopFinder::FormLoopHierarchy() UpdateCGFunc(); } +LoopDesc *LoopAnalysis::GetOrCreateLoopDesc(BB &headBB) +{ + auto *loop = bbLoopParent[headBB.GetId()]; + if (loop == nullptr || loop->GetHeader().GetId() != headBB.GetId()) { + // If the headBB is not in loop or loop's header is not the headBB, create a new loop. + loop = alloc.New(alloc, headBB); + loops.push_back(loop); + } + return loop; +} + +void LoopAnalysis::SetLoopParent4BB(const BB &bb, LoopDesc &loopDesc) +{ + if (bbLoopParent[bb.GetId()] != nullptr && bbLoopParent[bb.GetId()] != &loopDesc) { + if (loopDesc.GetParentLoop() == nullptr) { + loopDesc.SetParentLoop(*bbLoopParent[bb.GetId()]); + ASSERT_NOT_NULL(loopDesc.GetParentLoop()); + loopDesc.GetParentLoop()->InsertChildLoops(loopDesc); + loopDesc.SetNestDepth(loopDesc.GetParentLoop()->GetNestDepth() + 1); + } + } + loopDesc.InsertLoopBBs(bb); + bbLoopParent[bb.GetId()] = &loopDesc; +} + +void LoopAnalysis::SetExitBBs(LoopDesc &loop) const +{ + // if loopBBs succs not in the loop, the succs is the loop's exitBB + for (auto bbId : loop.GetLoopBBs()) { + auto *bb = cgFunc.GetBBFromID(bbId); + for (auto *succ : bb->GetAllSuccs()) { + if (loop.Has(*succ)) { + continue; + } + loop.InsertExitBBs(*succ); + } + } +} + +void LoopAnalysis::ProcessBB(BB &bb) +{ + if (&bb == cgFunc.GetCommonExitBB()) { + return; + } + + // generate loop based on the dom information + for (auto *pred : bb.GetAllPreds()) { + if (!dom.Dominate(bb, *pred)) { + continue; + } + auto *loop = GetOrCreateLoopDesc(bb); + loop->InsertBackEdges(*pred); + std::list bodyList; + bodyList.push_back(pred); + while (!bodyList.empty()) { + auto *curBB = bodyList.front(); + bodyList.pop_front(); + // skip bb or if it has already been dealt with + if (curBB == &bb || loop->Has(*curBB)) { + continue; + } + SetLoopParent4BB(*curBB, *loop); + for (auto *curPred : curBB->GetAllPreds()) { + bodyList.push_back(curPred); + } + } + SetLoopParent4BB(bb, *loop); + SetExitBBs(*loop); + } + + // process dom tree + for (auto domChildBBId : dom.GetDomChildren(bb.GetId())) { + ProcessBB(*cgFunc.GetBBFromID(domChildBBId)); + } +} + +void LoopAnalysis::Analysis() +{ + std::vector entryBBs; + FOR_ALL_BB(bb, (&cgFunc)) + { + if (bb->GetAllPreds().size() == 0) { + entryBBs.push_back(bb); + } + } + + for (auto *bb : entryBBs) { + ProcessBB(*bb); + } +} + +void CgLoopAnalysis::GetAnalysisDependence(AnalysisDep &aDep) const +{ + aDep.AddRequired(); + aDep.SetPreservedAll(); +} bool CgLoopAnalysis::PhaseRun(maplebe::CGFunc &f) { f.ClearLoopInfo(); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/litecg/litecg.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/litecg/litecg.cpp index a7d3111826..24b166305f 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/litecg/litecg.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/litecg/litecg.cpp @@ -119,6 +119,12 @@ void LiteCG::DoCG() Globals::GetInstance()->SetOptimLevel(cgOptions->GetOptimizeLevel()); + MAD *mad; + if (cgOptions->DoLocalSchedule()) { + mad = new MAD(); + Globals::GetInstance()->SetMAD(*mad); + } + // not sure how to do this. auto cgPhaseManager = std::make_unique(memPoolCtrler, "cg function phasemanager"); const MaplePhaseInfo *cgPMInfo = MaplePhaseRegister::GetMaplePhaseRegister()->GetPhaseByID(&CgFuncPM::id); @@ -138,6 +144,11 @@ void LiteCG::DoCG() timer.Stop(); LogInfo::MapleLogger() << "Mplcg consumed " << timer.ElapsedMilliseconds() << "ms" << '\n'; } + + if (cgOptions->DoLocalSchedule()) { + Globals::GetInstance()->ClearMAD(); + delete mad; + } } } // namespace litecg diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/me_dominance.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/me_dominance.cpp new file mode 100644 index 0000000000..70fef8ddcb --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_be/src/me_dominance.cpp @@ -0,0 +1,54 @@ +/* + * 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. + */ +#include "me_dominance.h" +#include +#include "me_option.h" +#include "me_cfg.h" +#include "base_graph_node.h" +// This phase analyses the CFG of the given MeFunction, generates the dominator tree, +// and the dominance frontiers of each basic block using Keith Cooper's algorithm. +// For some backward data-flow problems, such as LiveOut, +// the reverse CFG(The CFG with its edges reversed) is always useful, +// so we also generates the above two structures on the reverse CFG. +namespace maple { +void MEDominance::GetAnalysisDependence(maple::AnalysisDep &aDep) const +{ + aDep.AddRequired(); + aDep.SetPreservedAll(); +} + +bool MEDominance::PhaseRun(maple::MeFunction &f) +{ + MeCFG *cfg = f.GetCfg(); + ASSERT_NOT_NULL(cfg); + MemPool *memPool = GetPhaseMemPool(); + auto alloc = MapleAllocator(memPool); + auto nodeVec = memPool->New>(alloc.Adapter()); + CHECK_NULL_FATAL(nodeVec); + ConvertToVectorOfBasePtr(cfg->GetAllBBs(), *nodeVec); + dom = memPool->New(*memPool, *nodeVec, *cfg->GetCommonEntryBB(), *cfg->GetCommonExitBB(), false); + CHECK_NULL_FATAL(dom); + pdom = memPool->New(*memPool, *nodeVec, *cfg->GetCommonExitBB(), *cfg->GetCommonEntryBB(), true); + CHECK_NULL_FATAL(pdom); + dom->Init(); + pdom->Init(); + if (DEBUGFUNC_NEWPM(f)) { + LogInfo::MapleLogger() << "-----------------Dump dominance info and postdominance info---------\n"; + dom->DumpDoms(); + pdom->DumpDoms(); + } + return false; +} +} // namespace maple diff --git a/ecmascript/compiler/codegen/maple/maple_me/include/bb.h b/ecmascript/compiler/codegen/maple/maple_me/include/bb.h index 2f22ab46b2..65ffae4d5e 100644 --- a/ecmascript/compiler/codegen/maple/maple_me/include/bb.h +++ b/ecmascript/compiler/codegen/maple/maple_me/include/bb.h @@ -21,6 +21,8 @@ #include "orig_symbol.h" #include "ver_symbol.h" #include "ssa.h" +#include "scc.h" +#include "base_graph_node.h" namespace maple { class MeStmt; // circular dependency exists, no other choice @@ -59,7 +61,7 @@ constexpr uint32 kBBVectorInitialSize = 2; using StmtNodes = PtrListRef; using MeStmts = PtrListRef; -class BB { +class BB : public BaseGraphNode { public: using BBId = utils::Index; @@ -97,6 +99,41 @@ public: } virtual ~BB() = default; + SCCNode *GetSCCNode() + { + return sccNode; + } + void SetSCCNode(SCCNode *scc) + { + sccNode = scc; + } + + const std::string GetIdentity() + { + return "BBId: " + std::to_string(GetID()); + } + + void GetOutNodes(std::vector &outNodes) const final + { + outNodes.resize(succ.size(), nullptr); + std::copy(succ.begin(), succ.end(), outNodes.begin()); + } + + void GetOutNodes(std::vector &outNodes) final + { + static_cast(this)->GetOutNodes(outNodes); + } + + void GetInNodes(std::vector &inNodes) const final + { + inNodes.resize(pred.size(), nullptr); + std::copy(pred.begin(), pred.end(), inNodes.begin()); + } + + void GetInNodes(std::vector &inNodes) final + { + static_cast(this)->GetInNodes(inNodes); + } bool GetAttributes(uint32 attrKind) const { @@ -170,6 +207,11 @@ public: return static_cast(id); } + uint32 GetID() const + { + return static_cast(id); + } + bool IsEmpty() const { return stmtNodeList.empty(); @@ -514,6 +556,7 @@ public: private: MeStmts meStmtList; BB *group; + SCCNode *sccNode = nullptr; }; using BBId = BB::BBId; diff --git a/ecmascript/compiler/codegen/maple/maple_me/include/dominance.h b/ecmascript/compiler/codegen/maple/maple_me/include/dominance.h index fdbd7233c4..e8e2e3de2b 100644 --- a/ecmascript/compiler/codegen/maple/maple_me/include/dominance.h +++ b/ecmascript/compiler/codegen/maple/maple_me/include/dominance.h @@ -15,127 +15,157 @@ #ifndef MAPLE_ME_INCLUDE_DOMINANCE_H #define MAPLE_ME_INCLUDE_DOMINANCE_H -#include "bb.h" - +#include "mpl_number.h" +#include "mempool.h" +#include "mempool_allocator.h" +#include "types_def.h" +#include "base_graph_node.h" namespace maple { -class Dominance : public AnalysisResult { +class Dominance { public: - Dominance(MemPool &memPool, MemPool &tmpPool, MapleVector &bbVec, BB &commonEntryBB, BB &commonExitBB) - : AnalysisResult(&memPool), - domAllocator(&memPool), - tmpAllocator(&tmpPool), - bbVec(bbVec), - commonEntryBB(commonEntryBB), - commonExitBB(commonExitBB), - postOrderIDVec(bbVec.size(), -1, domAllocator.Adapter()), + using NodeId = uint32; + + Dominance(MemPool &memPool, MapleVector &nodeVec, BaseGraphNode &commonEntryNode, + BaseGraphNode &commonExitNode, bool isPdom) + : domAllocator(&memPool), + nodeVec(nodeVec), + commonEntryNode(commonEntryNode), + commonExitNode(commonExitNode), + isPdom(isPdom), + postOrderIDVec(nodeVec.size(), -1, domAllocator.Adapter()), reversePostOrder(domAllocator.Adapter()), reversePostOrderId(domAllocator.Adapter()), doms(domAllocator.Adapter()), - pdomPostOrderIDVec(bbVec.size(), -1, domAllocator.Adapter()), - pdomReversePostOrder(domAllocator.Adapter()), - pdoms(domAllocator.Adapter()), - domFrontier(bbVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), - domChildren(bbVec.size(), MapleVector(domAllocator.Adapter()), domAllocator.Adapter()), - iterDomFrontier(bbVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), - dtPreOrder(bbVec.size(), BBId(0), domAllocator.Adapter()), - dtDfn(bbVec.size(), -1, domAllocator.Adapter()), - pdomFrontier(bbVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), - pdomChildren(bbVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), - iterPdomFrontier(bbVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), - pdtPreOrder(bbVec.size(), BBId(0), domAllocator.Adapter()), - pdtDfn(bbVec.size(), -1, domAllocator.Adapter()) + domFrontier(nodeVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), + domChildren(nodeVec.size(), MapleVector(domAllocator.Adapter()), domAllocator.Adapter()), + iterDomFrontier(nodeVec.size(), MapleSet(domAllocator.Adapter()), domAllocator.Adapter()), + dtPreOrder(nodeVec.size(), NodeId(0), domAllocator.Adapter()), + dtDfn(nodeVec.size(), -1, domAllocator.Adapter()) { } - ~Dominance() override = default; + ~Dominance() = default; - void GenPostOrderID(); - void ComputeDominance(); - void ComputeDomFrontiers(); - void ComputeDomChildren(); - void GetIterDomFrontier(const BB *bb, MapleSet *dfset, BBId bbidMarker, std::vector &visitedMap); - void ComputeIterDomFrontiers(); - void ComputeDtPreorder(const BB &bb, size_t &num); - void ComputeDtDfn(); - bool Dominate(const BB &bb1, const BB &bb2); // true if bb1 dominates bb2 - void DumpDoms(); - void PdomGenPostOrderID(); - void ComputePostDominance(); - void ComputePdomFrontiers(); - void ComputePdomChildren(); - void GetIterPdomFrontier(const BB *bb, MapleSet *dfset, BBId bbidMarker, std::vector &visitedMap); - void ComputeIterPdomFrontiers(); - void ComputePdtPreorder(const BB &bb, size_t &num); - void ComputePdtDfn(); - bool PostDominate(const BB &bb1, const BB &bb2); // true if bb1 postdominates bb2 - void DumpPdoms(); + const MapleVector &GetNodeVec() const + { + return nodeVec; + } - const MapleVector &GetBBVec() const + bool IsNodeVecEmpty() const { - return bbVec; + return nodeVec.empty(); } - bool IsBBVecEmpty() const + size_t GetNodeVecSize() const { - return bbVec.empty(); + return nodeVec.size(); } - size_t GetBBVecSize() const + BaseGraphNode *GetNodeAt(size_t i) const { - return bbVec.size(); + return nodeVec.at(i); } - BB *GetBBAt(size_t i) const + const BaseGraphNode &GetCommonEntryNode() const { - return bbVec[i]; + return commonEntryNode; } - BB &GetCommonEntryBB() const + const BaseGraphNode &GetCommonExitNode() const { - return commonEntryBB; + return commonExitNode; } - BB &GetCommonExitBB() const + const BaseGraphNode *GetReversePostOrder(size_t idx) const { - return commonExitBB; + return reversePostOrder[idx]; } - const MapleVector &GetPostOrderIDVec() const + const MapleVector &GetReversePostOrder() const { - return postOrderIDVec; + return reversePostOrder; } - MapleVector &GetReversePostOrder() + MapleVector &GetReversePostOrder() { return reversePostOrder; } - MapleVector &GetReversePostOrderId() + const MapleVector &GetReversePostOrderId() { if (reversePostOrderId.empty()) { - reversePostOrderId.resize(bbVec.size(), 0); + reversePostOrderId.resize(nodeVec.size(), 0); for (size_t id = 0; id < reversePostOrder.size(); ++id) { - reversePostOrderId[reversePostOrder[id]->GetBBId()] = static_cast(id); + reversePostOrderId[reversePostOrder[id]->GetID()] = static_cast(id); } } return reversePostOrderId; } - const MapleUnorderedMap &GetDoms() const + BaseGraphNode *GetDom(NodeId id) { - return doms; + auto it = doms.find(id); + if (it == doms.end()) { + return nullptr; + } + return it->second; } - MapleVector &GetDtPreOrder() + MapleSet &GetDomFrontier(size_t idx) { - return dtPreOrder; + return domFrontier[idx]; + } + + const MapleSet &GetDomFrontier(size_t idx) const + { + return domFrontier.at(idx); + } + + size_t GetDomFrontierSize() const + { + return domFrontier.size(); + } + + const MapleSet &GetIterDomFrontier(const NodeId &idx) const + { + return iterDomFrontier[idx]; + } + + MapleSet &GetIterDomFrontier(const NodeId &idx) + { + return iterDomFrontier[idx]; + } + + size_t GetIterDomFrontierSize() const + { + return iterDomFrontier.size(); + } + + const MapleVector &GetDomChildren(const NodeId &idx) const + { + return domChildren[idx]; } - BBId GetDtPreOrderItem(size_t idx) const + MapleVector &GetDomChildren(const NodeId &idx) + { + return domChildren[idx]; + } + + size_t GetDomChildrenSize() const + { + return domChildren.size(); + } + + const NodeId &GetDtPreOrderItem(size_t idx) const { return dtPreOrder[idx]; } + const MapleVector &GetDtPreOrder() const + { + return dtPreOrder; + } + size_t GetDtPreOrderSize() const { return dtPreOrder.size(); @@ -151,132 +181,327 @@ public: return dtDfn.size(); } - MapleSet &GetPdomFrontierItem(size_t idx) + void DumpDoms() const { - return pdomFrontier[idx]; + const std::string tag = isPdom ? "pdom" : "dom"; + for (auto &node : reversePostOrder) { + auto nodeId = node->GetID(); + LogInfo::MapleLogger() << tag << "_postorder no " << postOrderIDVec[nodeId]; + LogInfo::MapleLogger() << " is node:" << nodeId; + LogInfo::MapleLogger() << " im_" << tag << " is node:" << doms.at(nodeId)->GetID(); + LogInfo::MapleLogger() << " " << tag << "frontier: ["; + for (auto &id : domFrontier[nodeId]) { + LogInfo::MapleLogger() << id << " "; + } + LogInfo::MapleLogger() << "] iter" << tag << "Frontier: ["; + for (auto &id : iterDomFrontier[nodeId]) { + LogInfo::MapleLogger() << id << " "; + } + LogInfo::MapleLogger() << "] " << tag << "children: ["; + for (auto &id : domChildren[nodeId]) { + LogInfo::MapleLogger() << id << " "; + } + LogInfo::MapleLogger() << "]\n"; + } + LogInfo::MapleLogger() << "\npreorder traversal of " << tag << " tree:"; + for (auto &id : dtPreOrder) { + LogInfo::MapleLogger() << id << " "; + } + LogInfo::MapleLogger() << "\n\n"; } - size_t GetPdomFrontierSize() const + void Init() { - return pdomFrontier.size(); + GenPostOrderID(); + ComputeDominance(); + ComputeDomFrontiers(); + ComputeDomChildren(); + ComputeIterDomFrontiers(); + size_t num = 0; + ComputeDtPreorder(num); + dtPreOrder.resize(num); + ComputeDtDfn(); } - MapleSet &GetPdomChildrenItem(size_t idx) + // true if b1 dominates b2 + bool Dominate(const BaseGraphNode &node1, const BaseGraphNode &node2) const { - return pdomChildren[idx]; + if (&node1 == &node2) { + return true; + } + const auto *iDom = &node2; + while (iDom != &commonEntryNode) { + auto it = doms.find(iDom->GetID()); + if (it == doms.end() || it->second == nullptr) { + return false; + } + iDom = it->second; + if (iDom == &node1) { + return true; + } + } + return false; } - void ResizePdtPreOrder(size_t n) + // true if b1 dominates b2 + bool Dominate(const uint32 nodeId1, const uint32 nodeId2) const { - pdtPreOrder.resize(n); + if (nodeId1 == nodeId2) { + return true; + } + uint32 curId = nodeId2; + while (curId != commonEntryNode.GetID()) { + auto it = doms.find(curId); + if (it == doms.end() || it->second == nullptr) { + return false; + } + curId = it->second->GetID(); + if (curId == nodeId1) { + return true; + } + } + return false; } - BBId GetPdtPreOrderItem(size_t idx) const - { - return pdtPreOrder[idx]; +private: + void GenPostOrderID() + { + DEBUG_ASSERT(!nodeVec.empty(), "size to be allocated is 0"); + std::vector visitedMap(nodeVec.size(), false); + size_t postOrderID = 0; + PostOrderWalk(commonEntryNode, postOrderID, visitedMap); + // initialize reversePostOrder + reversePostOrder.resize(postOrderID); + auto maxPostOrderID = postOrderID - 1; + for (size_t i = 0; i < postOrderIDVec.size(); ++i) { + auto postOrderNo = postOrderIDVec[i]; + if (postOrderNo == -1) { + continue; + } + reversePostOrder[maxPostOrderID - static_cast(postOrderNo)] = nodeVec[i]; + } } - uint32 GetPdtDfnItem(size_t idx) const + // Figure 5 in "A Simple, Fast Dominance Algorithm" by Keith Cooper et al. + void ComputeDomFrontiers() { - return pdtDfn[idx]; + constexpr uint32 kNodeVectorInitialSize = 2; + for (const auto node : nodeVec) { + if (node == nullptr || node == &commonExitNode) { + continue; + } + std::vector prevNodes; + GetPrevNodesToVisit(*node, prevNodes); + + if (prevNodes.size() < kNodeVectorInitialSize) { + continue; + } + for (auto *pre : prevNodes) { + auto runner = pre; + while (runner != doms.at(node->GetID()) && runner != &commonEntryNode) { + (void)domFrontier[runner->GetID()].insert(node->GetID()); + runner = doms.at(runner->GetID()); + } + } + } } - BB *GetDom(BBId id) + void ComputeDomChildren() { - return doms[id]; + for (const auto node : reversePostOrder) { + if (node == nullptr) { + continue; + } + auto *parent = doms.at(node->GetID()); + if (parent == nullptr || parent == node) { + continue; + } + domChildren[parent->GetID()].push_back(node->GetID()); + } } - size_t GetDomsSize() const + void ComputeIterDomFrontiers() { - return doms.size(); + for (auto &node : nodeVec) { + if (node == nullptr || node == &commonExitNode) { + continue; + } + std::vector visitedMap(nodeVec.size(), false); + GetIterDomFrontier(*node, iterDomFrontier[node->GetID()], node->GetID(), visitedMap); + } } - int32 GetPdomPostOrderIDVec(size_t idx) const + void ComputeDtPreorder(size_t &num) { - return pdomPostOrderIDVec[idx]; + ComputeDtPreorder(commonEntryNode, num); } - BB *GetPdomReversePostOrder(size_t idx) + void ComputeDtDfn() { - return pdomReversePostOrder[idx]; + for (size_t i = 0; i < dtPreOrder.size(); ++i) { + dtDfn[dtPreOrder[i]] = static_cast(i); + } } - MapleVector &GetPdomReversePostOrder() - { - return pdomReversePostOrder; + // Figure 3 in "A Simple, Fast Dominance Algorithm" by Keith Cooper et al. + void ComputeDominance() + { + doms[commonEntryNode.GetID()] = &commonEntryNode; + bool changed; + do { + changed = false; + for (size_t i = 1; i < reversePostOrder.size(); ++i) { + auto node = reversePostOrder[i]; + BaseGraphNode *pre = nullptr; + std::vector prevNodes; + GetPrevNodesToVisit(*node, prevNodes); + auto numOfPrevNodes = prevNodes.size(); + if (InitNodeIsPred(*node) || numOfPrevNodes == 0) { + pre = &commonEntryNode; + } else { + pre = prevNodes[0]; + } + size_t j = 1; + while ((doms[pre->GetID()] == nullptr || pre == node) && j < numOfPrevNodes) { + pre = prevNodes[j]; + ++j; + } + BaseGraphNode *newIDom = pre; + for (; j < numOfPrevNodes; ++j) { + pre = prevNodes[j]; + if (doms[pre->GetID()] != nullptr && pre != node) { + newIDom = Intersect(*pre, *newIDom); + } + } + if (doms[node->GetID()] != newIDom) { + doms[node->GetID()] = newIDom; + changed = true; + } + } + } while (changed); } - size_t GetPdomReversePostOrderSize() const + BaseGraphNode *Intersect(BaseGraphNode &node1, const BaseGraphNode &node2) const { - return pdomReversePostOrder.size(); + auto *ptrNode1 = &node1; + auto *ptrNode2 = &node2; + while (ptrNode1 != ptrNode2) { + while (postOrderIDVec[ptrNode1->GetID()] < postOrderIDVec[ptrNode2->GetID()]) { + ptrNode1 = doms.at(ptrNode1->GetID()); + } + while (postOrderIDVec[ptrNode2->GetID()] < postOrderIDVec[ptrNode1->GetID()]) { + ptrNode2 = doms.at(ptrNode2->GetID()); + } + } + return ptrNode1; } - MapleSet &GetDomFrontier(size_t idx) + bool InitNodeIsPred(const BaseGraphNode &node) const { - return domFrontier[idx]; + std::vector succNodes; + GetNextNodesToVisit(commonEntryNode, succNodes); + for (const auto &suc : succNodes) { + if (suc == &node) { + return true; + } + } + return false; } - size_t GetDomFrontierSize() const + void PostOrderWalk(const BaseGraphNode &root, size_t &pid, std::vector &visitedMap) { - return domFrontier.size(); + std::stack s; + s.push(&root); + visitedMap[root.GetID()] = true; + while (!s.empty()) { + auto node = s.top(); + auto nodeId = node->GetID(); + if (nodeVec[nodeId] == nullptr) { + s.pop(); + continue; + } + DEBUG_ASSERT(nodeId < visitedMap.size() && nodeId < postOrderIDVec.size(), "index out of range"); + bool tail = true; + std::vector succNodes; + GetNextNodesToVisit(*node, succNodes); + for (auto succ : succNodes) { + if (!visitedMap[succ->GetID()]) { + tail = false; + visitedMap[succ->GetID()] = true; + s.push(succ); + break; + } + } + if (tail) { + s.pop(); + postOrderIDVec[nodeId] = static_cast(pid++); + } + } } - MapleVector> &GetDomChildren() + void ComputeDtPreorder(const BaseGraphNode &node, size_t &num) { - return domChildren; + CHECK_FATAL(num < dtPreOrder.size(), "index out of range"); + dtPreOrder[num++] = node.GetID(); + for (auto &k : domChildren[node.GetID()]) { + ComputeDtPreorder(*nodeVec[k], num); + } } - MapleVector &GetDomChildren(size_t idx) + void GetNextNodesToVisit(const BaseGraphNode &node, std::vector &nodesToVisit) const { - return domChildren[idx]; + if (isPdom) { + node.GetInNodes(nodesToVisit); + } else { + node.GetOutNodes(nodesToVisit); + } } - size_t GetDomChildrenSize() const + void GetPrevNodesToVisit(const BaseGraphNode &node, std::vector &nodesToVisit) const { - return domChildren.size(); + if (isPdom) { + node.GetOutNodes(nodesToVisit); + } else { + node.GetInNodes(nodesToVisit); + } } - BB *GetPdom(BBId id) + // nodeIdMarker indicates that the iterDomFrontier results for nodeId < nodeIdMarker have been computed + void GetIterDomFrontier(const BaseGraphNode &node, MapleSet &dfSet, const NodeId &nodeIdMarker, + std::vector &visitedMap) { - return pdoms[id]; + if (visitedMap[node.GetID()]) { + return; + } + visitedMap[node.GetID()] = true; + for (auto frontierNodeId : domFrontier[node.GetID()]) { + (void)dfSet.insert(frontierNodeId); + if (frontierNodeId < nodeIdMarker) { // union with its computed result + dfSet.insert(iterDomFrontier[frontierNodeId].cbegin(), iterDomFrontier[frontierNodeId].cend()); + } else { // recursive call + auto frontierNode = nodeVec[frontierNodeId]; + if (frontierNode == nullptr) { + continue; + } + GetIterDomFrontier(*frontierNode, dfSet, nodeIdMarker, visitedMap); + } + } } -protected: - void PostOrderWalk(const BB &bb, int32 &pid, std::vector &visitedMap); - BB *Intersect(BB &bb1, const BB &bb2) const; - bool CommonEntryBBIsPred(const BB &bb) const; - void PdomPostOrderWalk(const BB &bb, int32 &pid, std::vector &visitedMap); - BB *PdomIntersect(BB &bb1, const BB &bb2); - MapleAllocator domAllocator; // stores the analysis results - -private: - MapleAllocator tmpAllocator; // can be freed after dominator computation - MapleVector &bbVec; - BB &commonEntryBB; - BB &commonExitBB; - MapleVector postOrderIDVec; // index is bb id - MapleVector reversePostOrder; // an ordering of the BB in reverse postorder - MapleVector reversePostOrderId; // gives position of each BB in reversePostOrder - MapleUnorderedMap doms; // index is bb id; immediate dominator for each BB - // following is for post-dominance - MapleVector pdomPostOrderIDVec; // index is bb id - MapleVector pdomReversePostOrder; // an ordering of the BB in reverse postorder - MapleUnorderedMap pdoms; // index is bb id; immediate dominator for each BB - MapleVector> domFrontier; // index is bb id -public: - MapleVector> domChildren; // index is bb id; for dom tree - MapleVector> iterDomFrontier; // index is bb id -private: - MapleVector dtPreOrder; // ordering of the BBs in a preorder traversal of the dominator tree - MapleVector dtDfn; // gives position of each BB in dt_preorder - MapleVector> pdomFrontier; // index is bb id -public: - MapleVector> pdomChildren; // index is bb id; for pdom tree - MapleVector> iterPdomFrontier; // index is bb id -private: - MapleVector pdtPreOrder; // ordering of the BBs in a preorder traversal of the post-dominator tree - MapleVector pdtDfn; // gives position of each BB in pdt_preorder + MapleVector &nodeVec; + BaseGraphNode &commonEntryNode; + BaseGraphNode &commonExitNode; + bool isPdom; + MapleVector postOrderIDVec; // index is node id + MapleVector reversePostOrder; // an ordering of the node in reverse postorder + MapleVector reversePostOrderId; // gives position of each node in reversePostOrder + MapleUnorderedMap doms; // index is node id; immediate dominator for each node + MapleVector> domFrontier; // index is node id + MapleVector> domChildren; // index is node id; for dom tree + MapleVector> iterDomFrontier; // index is node id + MapleVector dtPreOrder; // ordering of the nodes in a preorder traversal of the dominator tree + MapleVector dtDfn; // gives position of each node in dt_preorder }; } // namespace maple -#endif // MAPLE_ME_INCLUDE_DOMINANCE_H +#endif // MAPLE_UTIL_INCLUDE_DOMINANCE_H diff --git a/ecmascript/compiler/codegen/maple/maple_me/include/me_dominance.h b/ecmascript/compiler/codegen/maple/maple_me/include/me_dominance.h new file mode 100644 index 0000000000..cb19f19847 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_me/include/me_dominance.h @@ -0,0 +1,37 @@ +/* + * 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. + */ +#ifndef MAPLE_ME_INCLUDE_ME_DOMINANCE_H +#define MAPLE_ME_INCLUDE_ME_DOMINANCE_H +#include "dominance.h" +#include "me_function.h" +#include "maple_phase.h" + +namespace maple { +MAPLE_FUNC_PHASE_DECLARE_BEGIN(MEDominance, MeFunction) +Dominance *GetDomResult() +{ + return dom; +} + +Dominance *GetPdomResult() +{ + return pdom; +} +OVERRIDE_DEPENDENCE +Dominance *dom = nullptr; +Dominance *pdom = nullptr; +MAPLE_MODULE_PHASE_DECLARE_END +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_DOMINANCE_H diff --git a/ecmascript/compiler/codegen/maple/maple_me/src/meexpr_use_info.cpp b/ecmascript/compiler/codegen/maple/maple_me/src/meexpr_use_info.cpp index eea7aa7dd2..5cd75e5ac0 100644 --- a/ecmascript/compiler/codegen/maple/maple_me/src/meexpr_use_info.cpp +++ b/ecmascript/compiler/codegen/maple/maple_me/src/meexpr_use_info.cpp @@ -147,7 +147,7 @@ void MeExprUseInfo::CollectUseInfoInFunc(IRMap *irMap, Dominance *domTree, MeExp useInfoState = state; for (auto bb : domTree->GetReversePostOrder()) { - CollectUseInfoInBB(bb); + CollectUseInfoInBB(irMap->GetBB(BBId(bb->GetID()))); } } } // namespace maple diff --git a/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn new file mode 100644 index 0000000000..1b53744178 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn @@ -0,0 +1,47 @@ +# 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. + +import("//arkcompiler/ets_runtime/js_runtime_config.gni") + +include_libmplpgo = [ + "${MAPLEALL_ROOT}/maple_me/include", + "${MAPLEALL_ROOT}/maple_pgo/include", + "${MAPLEALL_ROOT}/maple_ipa/include", + "${MAPLEALL_ROOT}/maple_ipa/include/old", + "${MAPLEALL_ROOT}/maple_util/include", + "${MAPLEALL_ROOT}/mempool/include", + "${MAPLEALL_ROOT}/maple_ir/include", + "${MAPLEALL_ROOT}/mpl2mpl/include", + "${MAPLEALL_ROOT}/maple_be/include/cg", + "${MAPLEALL_ROOT}/maple_be/include/be", + "${MAPLEALL_ROOT}/maple_be/include/ad", + "${MAPLEALL_ROOT}/maple_be/include/ad/target", + "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", + "${MAPLEALL_ROOT}/maple_driver/include", + "${MAPLEALL_ROOT}/maple_phase/include", +] + +src_libmplpgo = [ + "src/cfg_mst.cpp", + "src/instrument.cpp", +] + +ohos_static_library("libmplpgo") { + stack_protector_ret = false + configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] + sources = src_libmplpgo + include_dirs = include_libmplpgo + output_dir = "${root_out_dir}/lib/${HOST_ARCH}" + part_name = "ets_runtime" + subsystem_name = "arkcompiler" +} diff --git a/ecmascript/compiler/codegen/maple/maple_pgo/include/cfg_mst.h b/ecmascript/compiler/codegen/maple/maple_pgo/include/cfg_mst.h new file mode 100644 index 0000000000..972636e91c --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_pgo/include/cfg_mst.h @@ -0,0 +1,77 @@ +/* + * 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. + */ +#ifndef MAPLE_PGO_INCLUDE_CFG_MST_H +#define MAPLE_PGO_INCLUDE_CFG_MST_H + +#include "types_def.h" +#include "mempool_allocator.h" + +namespace maple { +template +class CFGMST { +public: + explicit CFGMST(MemPool &mp) : mp(&mp), alloc(&mp), allEdges(alloc.Adapter()), bbGroups(alloc.Adapter()) {} + virtual ~CFGMST() + { + mp = nullptr; + } + void ComputeMST(BB *commonEntry, BB *commonExit); + void BuildEdges(BB *commonEntry, BB *commonExit); + void SortEdges(); + void AddEdge(BB *src, BB *dest, uint64 w, bool isCritical = false, bool isFake = false); + bool IsCritialEdge(const BB *src, const BB *dest) const + { + return src->GetSuccs().size() > 1 && dest->GetPreds().size() > 1; + } + const MapleVector &GetAllEdges() const + { + return allEdges; + } + + size_t GetAllEdgesSize() const + { + return allEdges.size(); + } + + uint32 GetAllBBs() const + { + return totalBB; + } + + void GetInstrumentEdges(std::vector &instrumentEdges) const + { + for (const auto &e : allEdges) { + if (!e->IsInMST()) { + instrumentEdges.push_back(e); + } + } + } + void DumpEdgesInfo() const; + +private: + uint32 FindGroup(uint32 bbId); + bool UnionGroups(uint32 srcId, uint32 destId); + static constexpr int kNormalEdgeWeight = 2; + static constexpr int kExitEdgeWeight = 3; + static constexpr int kFakeExitEdgeWeight = 4; + static constexpr int kCriticalEdgeWeight = 4; + MemPool *mp; + MapleAllocator alloc; + MapleVector allEdges; + MapleMap bbGroups; // bbId - gourpId + uint32 totalBB = 0; +}; +} /* namespace maple */ +#endif // MAPLE_PGO_INCLUDE_CFG_MST_H diff --git a/ecmascript/compiler/codegen/maple/maple_pgo/include/instrument.h b/ecmascript/compiler/codegen/maple/maple_pgo/include/instrument.h new file mode 100644 index 0000000000..d041f8eba6 --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_pgo/include/instrument.h @@ -0,0 +1,259 @@ +/* + * 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. + */ +#ifndef MAPLE_PGO_INCLUDE_INSTRUMENT_H +#define MAPLE_PGO_INCLUDE_INSTRUMENT_H + +#include "types_def.h" +#include "cfg_mst.h" +#include "mir_function.h" + +namespace maple { +MIRSymbol *GetOrCreateFuncCounter(MIRFunction &func, uint32 elemCnt, uint32 cfgHash); + +template +class BBEdge { +public: + BBEdge(BB *src, BB *dest, uint64 w = 1, bool isCritical = false, bool isFake = false) + : srcBB(src), destBB(dest), weight(w), inMST(false), isCritical(isCritical), isFake(isFake) + { + } + + ~BBEdge() = default; + + BB *GetSrcBB() + { + return srcBB; + } + + BB *GetDestBB() + { + return destBB; + } + + uint64 GetWeight() const + { + return weight; + } + + void SetWeight(uint64 w) + { + weight = w; + } + + bool IsCritical() const + { + return isCritical; + } + + bool IsFake() const + { + return isFake; + } + + bool IsInMST() const + { + return inMST; + } + + void SetInMST() + { + inMST = true; + } + + int32 GetCondition() const + { + return condition; + } + + void SetCondition(int32 cond) + { + condition = cond; + } + + bool IsBackEdge() const + { + return isBackEdge; + } + + void SetIsBackEdge() + { + isBackEdge = true; + } + +private: + BB *srcBB; + BB *destBB; + uint64 weight; + bool inMST; + bool isCritical; + bool isFake; + int32 condition = -1; + bool isBackEdge = false; +}; + +template +class BBUseEdge : public BBEdge { +public: + BBUseEdge(BB *src, BB *dest, uint64 w = 1, bool isCritical = false, bool isFake = false) + : BBEdge(src, dest, w, isCritical, isFake) + { + } + virtual ~BBUseEdge() = default; + void SetCount(uint64 value) + { + countValue = value; + valid = true; + } + + uint64 GetCount() const + { + return countValue; + } + + bool GetStatus() const + { + return valid; + } + +private: + bool valid = false; + uint64 countValue = 0; +}; + +template +class PGOInstrumentTemplate { +public: + explicit PGOInstrumentTemplate(MemPool &mp) : mst(mp) {} + + void GetInstrumentBBs(std::vector &bbs, IRBB *commonEntry) const; + void PrepareInstrumentInfo(IRBB *commonEntry, IRBB *commmonExit) + { + mst.ComputeMST(commonEntry, commmonExit); + } + const MapleVector &GetAllEdges() + { + return mst.GetAllEdges(); + } + +private: + CFGMST mst; +}; + +template +class BBUseInfo { +public: + explicit BBUseInfo(MemPool &tmpPool) + : innerAlloc(&tmpPool), inEdges(innerAlloc.Adapter()), outEdges(innerAlloc.Adapter()) + { + } + virtual ~BBUseInfo() = default; + void SetCount(uint64 value) + { + countValue = value; + valid = true; + } + uint64 GetCount() const + { + return countValue; + } + + bool GetStatus() const + { + return valid; + } + + void AddOutEdge(BBUseEdge *e) + { + outEdges.push_back(e); + if (!e->GetStatus()) { + unknownOutEdges++; + } + } + + void AddInEdge(BBUseEdge *e) + { + inEdges.push_back(e); + if (!e->GetStatus()) { + unknownInEdges++; + } + } + + const MapleVector *> &GetInEdges() const + { + return inEdges; + } + + MapleVector *> &GetInEdges() + { + return inEdges; + } + + size_t GetInEdgeSize() const + { + return inEdges.size(); + } + + const MapleVector *> &GetOutEdges() const + { + return outEdges; + } + + MapleVector *> &GetOutEdges() + { + return outEdges; + } + + size_t GetOutEdgeSize() const + { + return outEdges.size(); + } + + void DecreaseUnKnownOutEdges() + { + unknownOutEdges--; + } + + void DecreaseUnKnownInEdges() + { + unknownInEdges--; + } + + uint32 GetUnknownOutEdges() const + { + return unknownOutEdges; + } + + BBUseEdge *GetOnlyUnknownOutEdges(); + + uint32 GetUnknownInEdges() const + { + return unknownInEdges; + } + + BBUseEdge *GetOnlyUnknownInEdges(); + + void Dump(); + +private: + bool valid = false; + uint64 countValue = 0; + uint32 unknownInEdges = 0; + uint32 unknownOutEdges = 0; + MapleAllocator innerAlloc; + MapleVector *> inEdges; + MapleVector *> outEdges; +}; +} /* namespace maple */ +#endif // MAPLE_PGO_INCLUDE_INSTRUMENT_H diff --git a/ecmascript/compiler/codegen/maple/maple_pgo/src/cfg_mst.cpp b/ecmascript/compiler/codegen/maple/maple_pgo/src/cfg_mst.cpp new file mode 100644 index 0000000000..7c72f2ab4b --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_pgo/src/cfg_mst.cpp @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#include "cfg_mst.h" +#include "cgbb.h" +#include "instrument.h" +namespace maple { +template +void CFGMST::BuildEdges(BB *commonEntry, BB *commonExit) +{ + for (auto *curbb = commonEntry; curbb != nullptr; curbb = curbb->GetNext()) { + bbGroups[curbb->GetId()] = curbb->GetId(); + if (curbb == commonExit) { + continue; + } + totalBB++; + for (auto *succBB : curbb->GetSuccs()) { + // exitBB incoming edge allocate high weight + if (succBB->GetKind() == BB::BBKind::kBBReturn) { + AddEdge(curbb, succBB, kExitEdgeWeight); + continue; + } + if (IsCritialEdge(curbb, succBB)) { + AddEdge(curbb, succBB, kCriticalEdgeWeight, true); + continue; + } + AddEdge(curbb, succBB, kNormalEdgeWeight); + } + } + + for (BB *bb : commonExit->GetPreds()) { + AddEdge(bb, commonExit, kFakeExitEdgeWeight, false, true); + } + bbGroups[commonExit->GetId()] = commonExit->GetId(); + // insert fake edge to keep consistent + AddEdge(commonExit, commonEntry, UINT64_MAX, false, true); +} + +template +void CFGMST::ComputeMST(BB *commonEntry, BB *commonExit) +{ + BuildEdges(commonEntry, commonExit); + SortEdges(); + /* only one edge means only one bb */ + if (allEdges.size() == 1) { + LogInfo::MapleLogger() << "only one edge find " << std::endl; + return; + } + // first,put all critial edge,with destBB is eh-handle + // in mst,because current doesn't support split that edge + for (auto &e : allEdges) { + if (UnionGroups(e->GetSrcBB()->GetId(), e->GetDestBB()->GetId())) { + e->SetInMST(); + } + } +} + +template +void CFGMST::AddEdge(BB *src, BB *dest, uint64 w, bool isCritical, bool isFake) +{ + if (src == nullptr || dest == nullptr) { + return; + } + bool found = false; + for (auto &edge : allEdges) { + if (edge->GetSrcBB() == src && edge->GetDestBB() == dest) { + uint64 weight = edge->GetWeight(); + weight++; + edge->SetWeight(weight); + found = true; + } + } + if (!found) { + (void)allEdges.emplace_back(mp->New(src, dest, w, isCritical, isFake)); + } +} + +template +void CFGMST::SortEdges() +{ + std::stable_sort(allEdges.begin(), allEdges.end(), + [](const Edge *edge1, const Edge *edge2) { return edge1->GetWeight() > edge2->GetWeight(); }); +} + +template +uint32 CFGMST::FindGroup(uint32 bbId) +{ + CHECK_FATAL(bbGroups.count(bbId) != 0, "unRegister bb"); + if (bbGroups[bbId] != bbId) { + bbGroups[bbId] = FindGroup(bbGroups[bbId]); + } + return bbGroups[bbId]; +} + +template +bool CFGMST::UnionGroups(uint32 srcId, uint32 destId) +{ + uint32 srcGroupId = FindGroup(srcId); + uint32 destGroupId = FindGroup(destId); + if (srcGroupId == destGroupId) { + return false; + } + bbGroups[srcGroupId] = destGroupId; + return true; +} +template +void CFGMST::DumpEdgesInfo() const +{ + for (auto &edge : allEdges) { + BB *src = edge->GetSrcBB(); + BB *dest = edge->GetDestBB(); + LogInfo::MapleLogger() << "BB" << src->GetId() << "->" + << "BB" << dest->GetId() << " weight " << edge->GetWeight(); + if (edge->IsInMST()) { + LogInfo::MapleLogger() << " in Mst\n"; + } else { + LogInfo::MapleLogger() << " not in Mst\n"; + } + } +} + +template class CFGMST, maplebe::BB>; +template class CFGMST, maplebe::BB>; +} // namespace maple diff --git a/ecmascript/compiler/codegen/maple/maple_pgo/src/instrument.cpp b/ecmascript/compiler/codegen/maple/maple_pgo/src/instrument.cpp new file mode 100644 index 0000000000..176b02f15f --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_pgo/src/instrument.cpp @@ -0,0 +1,151 @@ +/* + * 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. + */ + +#include "instrument.h" +#include "cgbb.h" +#include "mir_builder.h" +#include "mpl_logging.h" + +namespace maple { +std::string GetProfCntSymbolName(const std::string &funcName) +{ + return funcName + "_counter"; +} + +static inline void RegisterInFuncInfo(MIRFunction &func, const MIRSymbol &counter, uint64 elemCnt, uint32 cfgHash) +{ + if (elemCnt == 0) { + return; + } + auto funcStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(namemangler::kprefixProfFuncDesc + func.GetName()); + MIRSymbol *sym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(funcStrIdx); + CHECK_FATAL(sym, "function have not generated, please check in CreateFuncInfo"); + auto *funcInfoMirConst = static_cast(sym->GetKonst()); + MIRType *u32Ty = GlobalTables::GetTypeTable().GetUInt32(); + MIRIntConst *cfgHashConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(cfgHash, *u32Ty); + MIRIntConst *eleCntMirConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(elemCnt, *u32Ty); + auto *counterConst = func.GetModule()->GetMemPool()->New(counter.GetStIdx(), 0, + *GlobalTables::GetTypeTable().GetPtr()); + int num1 = 1; + int num2 = 2; + int num3 = 3; + int num4 = 4; + funcInfoMirConst->SetItem(num1, cfgHashConst, num2); + funcInfoMirConst->SetItem(num2, eleCntMirConst, num3); + funcInfoMirConst->SetItem(num3, counterConst, num4); +} + +MIRSymbol *GetOrCreateFuncCounter(MIRFunction &func, uint32 elemCnt, uint32 cfgHash) +{ + auto *mirModule = func.GetModule(); + std::string name = GetProfCntSymbolName(func.GetName()); + auto nameStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(name); + MIRSymbol *sym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(nameStrIdx); + if (sym != nullptr) { + return sym; + } + auto *elemType = GlobalTables::GetTypeTable().GetUInt64(); + MIRArrayType &arrayType = *GlobalTables::GetTypeTable().GetOrCreateArrayType(*elemType, elemCnt); + sym = mirModule->GetMIRBuilder()->CreateGlobalDecl(name.c_str(), arrayType, kScFstatic); + auto *profTab = mirModule->GetMemPool()->New(*mirModule, arrayType); + MIRIntConst *indexConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, *elemType); + for (uint32 i = 0; i < elemCnt; ++i) { + profTab->AddItem(indexConst, i); + } + sym->SetKonst(profTab); + sym->SetStorageClass(kScFstatic); + sym->sectionAttr = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName("mpl_counter"); + RegisterInFuncInfo(func, *sym, elemCnt, cfgHash); + return sym; +} + +template +void PGOInstrumentTemplate::GetInstrumentBBs(std::vector &bbs, IRBB *commonEntry) const +{ + std::vector iEdges; + mst.GetInstrumentEdges(iEdges); + std::unordered_set visitedBBs; + for (auto &edge : iEdges) { + IRBB *src = edge->GetSrcBB(); + IRBB *dest = edge->GetDestBB(); + if (src->GetSuccs().size() <= 1) { + if (src == commonEntry) { + bbs.push_back(dest); + } else { + bbs.push_back(src); + } + } else if (!edge->IsCritical()) { + bbs.push_back(dest); + } else { + if (src->GetKind() == IRBB::kBBIgoto) { + if (visitedBBs.find(dest) == visitedBBs.end()) { + // In this case, we have to instrument it anyway + bbs.push_back(dest); + (void)visitedBBs.insert(dest); + } + } else { + CHECK_FATAL(false, "Unexpected case %d -> %d", src->GetId(), dest->GetId()); + } + } + } +} + +template +BBUseEdge *BBUseInfo::GetOnlyUnknownOutEdges() +{ + BBUseEdge *ouEdge = nullptr; + for (auto *e : outEdges) { + if (!e->GetStatus()) { + CHECK_FATAL(!ouEdge, "have multiple unknown out edges"); + ouEdge = e; + } + } + return ouEdge; +} + +template +BBUseEdge *BBUseInfo::GetOnlyUnknownInEdges() +{ + BBUseEdge *ouEdge = nullptr; + for (auto *e : inEdges) { + if (!e->GetStatus()) { + CHECK_FATAL(!ouEdge, "have multiple unknown in edges"); + ouEdge = e; + } + } + return ouEdge; +} + +template +void BBUseInfo::Dump() +{ + for (const auto &inE : inEdges) { + if (inE->GetStatus()) { + LogInfo::MapleLogger() << inE->GetSrcBB()->GetId() << "->" << inE->GetDestBB()->GetId() + << " c : " << inE->GetCount() << "\n"; + } + } + for (const auto &outE : outEdges) { + if (outE->GetStatus()) { + LogInfo::MapleLogger() << outE->GetSrcBB()->GetId() << "->" << outE->GetDestBB()->GetId() + << " c : " << outE->GetCount() << "\n"; + } + } +} + +template class PGOInstrumentTemplate>; +template class PGOInstrumentTemplate>; +template class BBUseInfo; +} /* namespace maple */ diff --git a/ecmascript/compiler/codegen/maple/maple_util/include/base_graph_node.h b/ecmascript/compiler/codegen/maple/maple_util/include/base_graph_node.h new file mode 100644 index 0000000000..dd8fb35c6e --- /dev/null +++ b/ecmascript/compiler/codegen/maple/maple_util/include/base_graph_node.h @@ -0,0 +1,40 @@ +/* + * 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. + */ +#ifndef MAPLE_UTIL_INCLUDE_BASE_GRAPH_NODE_H +#define MAPLE_UTIL_INCLUDE_BASE_GRAPH_NODE_H +#include "types_def.h" +#include "mempool_allocator.h" +namespace maple { + +class BaseGraphNode { +public: + virtual void GetOutNodes(std::vector &outNodes) = 0; + virtual void GetOutNodes(std::vector &outNodes) const = 0; + virtual void GetInNodes(std::vector &outNodes) = 0; + virtual void GetInNodes(std::vector &outNodes) const = 0; + virtual const std::string GetIdentity() = 0; + virtual uint32 GetID() const = 0; +}; + +// BaseGraphNode needs to be the base class of T +template ::value, bool> = true> +void ConvertToVectorOfBasePtr(const MapleVector &originVec, MapleVector &targetVec) +{ + for (auto &item : originVec) { + targetVec.emplace_back(item); + } +} +} // namespace maple +#endif /* MAPLE_UTIL_INCLUDE_BASE_GRAPH_NODE_H */ diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/include/call_graph.h b/ecmascript/compiler/codegen/maple/mpl2mpl/include/call_graph.h index 9edb1bae4f..13eb40d986 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/include/call_graph.h +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/include/call_graph.h @@ -19,6 +19,7 @@ #include "mir_builder.h" #include "mir_nodes.h" #include "scc.h" +#include "base_graph_node.h" namespace maple { enum CallType { kCallTypeInvalid, @@ -116,14 +117,6 @@ private: uint32 id; }; -class BaseGraphNode { -public: - virtual void GetOutNodes(std::vector &outNodes) = 0; - virtual void GetInNodes(std::vector &outNodes) = 0; - virtual const std::string GetIdentity() = 0; - virtual uint32 GetID() const = 0; -}; - // Node in callgraph class CGNode : public BaseGraphNode { public: @@ -369,9 +362,9 @@ public: addrTaken = true; } - void GetOutNodes(std::vector &outNodes) override + void GetOutNodes(std::vector &outNodes) final { - for (auto &callSite : GetCallee()) { + for (auto &callSite : std::as_const(GetCallee())) { for (auto &cgIt : *callSite.second) { CGNode *calleeNode = cgIt; outNodes.emplace_back(calleeNode); @@ -379,9 +372,27 @@ public: } } - void GetInNodes(std::vector &inNodes) override + void GetOutNodes(std::vector &outNodes) const final + { + for (auto &callSite : std::as_const(GetCallee())) { + for (auto &cgIt : *callSite.second) { + CGNode *calleeNode = cgIt; + outNodes.emplace_back(calleeNode); + } + } + } + + void GetInNodes(std::vector &inNodes) final + { + for (auto pair : std::as_const(GetCaller())) { + CGNode *callerNode = pair.first; + inNodes.emplace_back(callerNode); + } + } + + void GetInNodes(std::vector &inNodes) const final { - for (auto pair : GetCaller()) { + for (auto pair : std::as_const(GetCaller())) { CGNode *callerNode = pair.first; inNodes.emplace_back(callerNode); } diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/include/scc.h b/ecmascript/compiler/codegen/maple/mpl2mpl/include/scc.h index 2096e2e209..93f7aa5e76 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/include/scc.h +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/include/scc.h @@ -15,7 +15,7 @@ #ifndef MPL2MPL_INCLUDE_SCC_H #define MPL2MPL_INCLUDE_SCC_H -#include "call_graph.h" +#include "base_graph_node.h" namespace maple { class BaseGraphNode; @@ -287,5 +287,42 @@ void VerifySCC(std::vector nodes) } } } + +template +uint32 BuildSCC(MapleAllocator &cgAlloc, uint32 numOfNodes, std::vector &allNodes, bool debugScc, + MapleVector *> &topologicalVec, bool clearOld = false) +{ + // This is the mapping between cg_id to node. + std::vector id2NodeMap(numOfNodes, nullptr); + std::vector visitedOrder(numOfNodes, 0); + std::vector lowestOrder(numOfNodes, 0); + std::vector inStack(numOfNodes, false); + std::vector visitStack; + uint32 visitIndex = 1; + uint32 numOfSccs = 0; + if (clearOld) { + // clear old scc before computing + for (auto node : allNodes) { + node->SetSCCNode(nullptr); + } + } + // However, not all SCC can be reached from roots. + // E.g. foo()->foo(), foo is not considered as a root. + for (auto node : allNodes) { + if (node->GetSCCNode() == nullptr) { + BuildSCCDFS(*node, visitIndex, topologicalVec, id2NodeMap, visitedOrder, lowestOrder, inStack, visitStack, + numOfSccs, cgAlloc); + } + } + for (auto scc : topologicalVec) { + scc->Verify(); + scc->Setup(); // fix caller and callee info. + if (debugScc && scc->HasRecursion()) { + scc->Dump(); + } + } + std::reverse(topologicalVec.begin(), topologicalVec.end()); + return numOfSccs; +} } // namespace maple #endif // MPL2MPL_INCLUDE_SCC_H \ No newline at end of file -- Gitee