diff --git a/src/bin/jbc2mpl b/src/bin/jbc2mpl index 486d303897764f83aa44f7d0d064f8775c476b4a..596797e42164357831497ebfc1b0f5986f239612 100755 Binary files a/src/bin/jbc2mpl and b/src/bin/jbc2mpl differ diff --git a/src/bin/maple b/src/bin/maple index a2fa7707ed662a61f741e18022677da2ab80196f..fac7f78d602a237ec545d117e8a640c83773e7f6 100755 Binary files a/src/bin/maple and b/src/bin/maple differ diff --git a/src/deplibs/libmplphase.a b/src/deplibs/libmplphase.a index 129c7d577b4c51496661e1037ce41fc8b6c5f603..9fb5d414f01a31a2840ab5a1147d3bf7ad04bccf 100644 Binary files a/src/deplibs/libmplphase.a and b/src/deplibs/libmplphase.a differ diff --git a/src/maple_driver/include/usages.h b/src/maple_driver/include/usages.h index 6a948fdce9db7ff158ebbb33fa8aa1c1ff3fa3d0..42cf81cb28ecd25fa4cdeeebb526df2514ccc7eb 100644 --- a/src/maple_driver/include/usages.h +++ b/src/maple_driver/include/usages.h @@ -43,15 +43,42 @@ enum OptionIndex : uint64 { kMeDumpFunc, kMeQuiet, kMeNoDot, + kMeSkipFrom, + kMeSkipAfter, kSetCalleeHasSideEffect, kNoSteensgaard, kNoTBAA, kAliasAnalysisLevel, kStmtNum, + kRcLower, + kNoRcLower, + kMeDumpBefore, kMeDumpAfter, + kMeOptL1, + kMeOptL2, kMeRange, + kEpreLimit, + kEprepuLimit, + kStmtPrepuLimit, + kLpreLimit, + kLprepulLimit, + kDelrcpuLimit, + kEpreIncludeRef, + kNoEpreIncludeRef, + kEpreLocalRefVar, + kNoEpreLocalRefVar, + kEprelhSivar, kLessThrowAlias, + kNodeLegateRc, + kNocondBasedRc, + kNullcheckPre, + kClinitPre, + kDassignPre, + kAssign2finalPre, kRegReadAtReturn, + kLpreSpeculate, + kNoLpreSpeculate, + kSpillatCatch, // ----------mpl2mpl begin--------- kMpl2MplHelp, kMpl2MplDumpPhase, diff --git a/src/maple_driver/src/maple_comb_compiler.cpp b/src/maple_driver/src/maple_comb_compiler.cpp index b407f79283abce45edb106cd58af4e5ccb2fa742..d74263fc376b2c5649608a61803733df3a8903be 100644 --- a/src/maple_driver/src/maple_comb_compiler.cpp +++ b/src/maple_driver/src/maple_comb_compiler.cpp @@ -91,6 +91,12 @@ MeOption *MapleCombCompiler::MakeMeOptions(const MplOptions &options, MemPool &o case kMeSkipPhases: meOption->SplitSkipPhases(opt.Args()); break; + case kMeOptL1: + // Already handled above in DecideMeRealLevel + break; + case kMeOptL2: + // Already handled above in DecideMeRealLevel + break; case kMeRange: meOption->useRange = true; meOption->GetRange(opt.Args()); @@ -152,18 +158,72 @@ MeOption *MapleCombCompiler::MakeMeOptions(const MplOptions &options, MemPool &o LogInfo::MapleLogger() << "--sub options: noTBAA " << meOption->noTBAA << '\n'; } break; + case kRcLower: + meOption->rcLowering = (opt.Type() == kEnable); + break; case kMeNoDot: meOption->noDot = (opt.Type() == kEnable); break; case kStmtNum: meOption->stmtNum = (opt.Type() == kEnable); break; + case kEpreLimit: + meOption->epreLimit = std::stoul(opt.Args(), nullptr); + break; + case kEprepuLimit: + meOption->eprePULimit = std::stoul(opt.Args(), nullptr); + break; + case kStmtPrepuLimit: + meOption->stmtprePULimit = std::stoul(opt.Args(), nullptr); + break; + case kLpreLimit: + meOption->lpreLimit = std::stoul(opt.Args(), nullptr); + break; + case kLprepulLimit: + meOption->lprePULimit = std::stoul(opt.Args(), nullptr); + break; + case kDelrcpuLimit: + meOption->delRcPULimit = std::stoul(opt.Args(), nullptr); + break; + case kEpreIncludeRef: + meOption->epreIncludeRef = (opt.Type() == kEnable); + break; + case kEpreLocalRefVar: + meOption->epreLocalRefVar = (opt.Type() == kEnable); + break; + case kEprelhSivar: + meOption->epreLHSIvar = (opt.Type() == kEnable); + break; case kLessThrowAlias: meOption->lessThrowAlias = (opt.Type() == kEnable); break; + case kNodeLegateRc: + meOption->noDelegateRC = (opt.Type() == kEnable); + break; + case kNocondBasedRc: + meOption->noCondBasedRC = (opt.Type() == kEnable); + break; + case kNullcheckPre: + meOption->nullCheckPre = (opt.Type() == kEnable); + break; + case kClinitPre: + meOption->clinitPre = (opt.Type() == kEnable); + break; + case kDassignPre: + meOption->dassignPre = (opt.Type() == kEnable); + break; + case kAssign2finalPre: + meOption->assign2FinalPre = (opt.Type() == kEnable); + break; case kRegReadAtReturn: meOption->regreadAtReturn = (opt.Type() == kEnable); break; + case kLpreSpeculate: + meOption->lpreSpeculate = (opt.Type() == kEnable); + break; + case kSpillatCatch: + meOption->spillAtCatch = (opt.Type() == kEnable); + break; default: WARN(kLncWarn, "input invalid key for me " + opt.OptionKey()); break; diff --git a/src/maple_driver/src/mpl_options.cpp b/src/maple_driver/src/mpl_options.cpp index 6f5a0ffe80090a69fee9494c81f93c6a7d7363b4..a1082cac4f6e574e9afdff143795709a86ecbd49 100644 --- a/src/maple_driver/src/mpl_options.cpp +++ b/src/maple_driver/src/mpl_options.cpp @@ -421,6 +421,32 @@ const mapleOption::Descriptor USAGES[] = { " --no-stmtnum \tDon't print MeStmt index number in IR dump\n", "me", { { nullptr, nullptr, nullptr, nullptr } } }, + { kRcLower, + kEnable, + nullptr, + "rclower", + nullptr, + false, + nullptr, + mapleOption::BuildType::kBuildTypeAll, + mapleOption::ArgCheckPolicy::kArgCheckPolicyBool, + " --rclower \tEnable rc lowering\n" + " --no-rclower \tDisable rc lowering\n", + "me", + { { nullptr, nullptr, nullptr, nullptr } } }, + { kMeDumpBefore, + kEnable, + nullptr, + "dump-before", + nullptr, + false, + nullptr, + mapleOption::BuildType::kBuildTypeAll, + mapleOption::ArgCheckPolicy::kArgCheckPolicyBool, + " --dump-before \tDo extra IR dump before the specified phase in me\n" + " --no-dump-before \tDon't extra IR dump before the specified phase in me\n", + "me", + { { nullptr, nullptr, nullptr, nullptr } } }, { kMeDumpAfter, kEnable, nullptr, @@ -447,6 +473,33 @@ const mapleOption::Descriptor USAGES[] = { " --no-lessthrowalias \tDisable lessthrowalias\n", "me", { { nullptr, nullptr, nullptr, nullptr } } }, + { kNodeLegateRc, + kEnable, + nullptr, + "nodelegaterc", + nullptr, + false, + nullptr, + mapleOption::BuildType::kBuildTypeAll, + mapleOption::ArgCheckPolicy::kArgCheckPolicyBool, + " --nodelegateerc \tDo not apply RC delegation to local object reference pointers\n" + " --no-nodelegateerc \tDisable nodelegateerc\n", + "me", + { { nullptr, nullptr, nullptr, nullptr } } }, + { kNocondBasedRc, + kEnable, + nullptr, + "nocondbasedrc", + nullptr, + false, + nullptr, + mapleOption::BuildType::kBuildTypeAll, + mapleOption::ArgCheckPolicy::kArgCheckPolicyBool, + " --nocondbasedrc \tDo not apply condition-based RC optimization to\n" + " \tlocal object reference pointers\n" + " --no-nocondbasedrc \tDisable nocondbasedrc\n", + "me", + { { nullptr, nullptr, nullptr, nullptr } } }, { kRegReadAtReturn, kEnable, nullptr, @@ -1285,7 +1338,12 @@ ErrorCode MplOptions::UpdatePhaseOption(const std::string &args, const std::stri ErrorCode MplOptions::UpdateExtraOptionOpt(const std::string &args) { std::vector temp; +#ifdef _WIN32 + // Paths on windows may contain such string like "C:/", then it would be confused with the split symbol ":" + StringUtils::Split(args, temp, ';'); +#else StringUtils::Split(args, temp, ':'); +#endif if (temp.size() != runningExes.size()) { // parameter not match ignore LogInfo::MapleLogger(kLlErr) << "The --run and --option are not matched, please check them." diff --git a/src/maple_ir/include/mir_nodes.h b/src/maple_ir/include/mir_nodes.h index 1e491385421d4cc938d78899ecf96209ef52e370..de31dea95f6d4b5657d7a2f65181b4e33cf03028 100644 --- a/src/maple_ir/include/mir_nodes.h +++ b/src/maple_ir/include/mir_nodes.h @@ -1450,11 +1450,20 @@ class StmtNode : public BaseNode, public PtrListNodeBase { return nullptr; } + bool GetIsLive() const { + return isLive; + } + + void SetIsLive(bool live) const { + isLive = live; + } protected: SrcPosition srcPosition; private: uint32 stmtID; // a unique ID assigned to it + mutable bool isLive = false; // only used for dse to save compile time + // mutable to keep const-ness at most situation }; class IassignNode : public StmtNode { diff --git a/src/maple_me/BUILD.gn b/src/maple_me/BUILD.gn index bc4cb522cedabde327339ff39b27443db110a8ec..33658c3e3d6601e569f33596558676ec1ca53c2b 100644 --- a/src/maple_me/BUILD.gn +++ b/src/maple_me/BUILD.gn @@ -29,11 +29,22 @@ src_libmplme = [ "src/me_option.cpp", "src/me_phase_manager.cpp", "src/me_prop.cpp", + "src/me_cond_based_opt.cpp", "src/me_rc_lowering.cpp", + "src/me_lower_globals.cpp", "src/me_rename2preg.cpp", "src/me_ssa.cpp", "src/me_ssa_tab.cpp", "src/me_ssa_update.cpp", + "src/me_stmt_fre.cpp", + "src/me_stmt_pre.cpp", + "src/me_store_pre.cpp", + "src/me_ssa_epre.cpp", + "src/me_ssa_lpre.cpp", + "src/me_ssu_pre.cpp", + "src/ssa_epre.cpp", + "src/ssa_pre.cpp", + "src/occur.cpp", ] src_libmplmewpo = [ diff --git a/src/maple_me/include/dse.h b/src/maple_me/include/dse.h index 1a74163bd47e5ac53288c3754c7f43fe0dfe654f..9c3744a3e75439504abcf17f8c6dede14a793145 100644 --- a/src/maple_me/include/dse.h +++ b/src/maple_me/include/dse.h @@ -31,7 +31,8 @@ class DSE { : enableDebug(enableDebug), bbVec(bbVec), commonEntryBB(commonEntryBB), commonExitBB(commonExitBB), ssaTab(ssaTab), - postDom(postDom), bbRequired(bbVec.size(), false) {} + postDom(postDom), bbRequired(bbVec.size(), false), + exprRequired(ssaTab.GetVersionStTableSize(), false) {} ~DSE() = default; @@ -42,8 +43,8 @@ class DSE { protected: bool enableDebug = false; - bool IsSymbolLived(const utils::SafePtr &symbol) const { - return exprRequired.find(symbol) != exprRequired.end(); + bool IsSymbolLived(const VersionSt &symbol) const { + return exprRequired[symbol.GetIndex()]; } private: @@ -87,15 +88,15 @@ class DSE { void OnRemoveBranchStmt(BB &bb, const StmtNode &stmt); void CheckRemoveCallAssignedReturn(StmtNode &stmt); - bool IsStmtRequired(const utils::SafePtr &stmt) const { - return stmtRequired.find(stmt) != stmtRequired.end(); + bool IsStmtRequired(const StmtNode &stmt) const { + return stmt.GetIsLive(); } - void SetStmtRequired(const utils::SafePtr &stmt) { - stmtRequired.insert(stmt); + void SetStmtRequired(const StmtNode &stmt) const { + stmt.SetIsLive(true); } - void SetSymbolLived(const utils::SafePtr &symbol) { - exprRequired.insert(symbol); + void SetSymbolLived(const VersionSt &symbol) { + exprRequired[symbol.GetIndex()] = true; } void AddToWorkList(const utils::SafePtr &symbol) { @@ -113,8 +114,7 @@ class DSE { SSATab &ssaTab; Dominance &postDom; std::vector bbRequired; - std::unordered_set> stmtRequired{}; - std::unordered_set> exprRequired{}; + std::vector exprRequired; std::forward_list> workList{}; bool cfgUpdated = false; }; diff --git a/src/maple_me/include/irmap.h b/src/maple_me/include/irmap.h index 5d45b76073bac58d96a2d965638170c8bad34e34..7c81727c39d55b5e023e3fbf787503e2062b2f5f 100644 --- a/src/maple_me/include/irmap.h +++ b/src/maple_me/include/irmap.h @@ -35,6 +35,8 @@ class IRMap : public AnalysisResult { hashTable(mapHashLength, nullptr, irMapAlloc.Adapter()), vst2MeExprTable(ssaTab.GetVersionStTableSize(), nullptr, irMapAlloc.Adapter()), regMeExprTable(irMapAlloc.Adapter()), + lpreTmps(irMapAlloc.Adapter()), + vst2Decrefs(irMapAlloc.Adapter()), meBuilder(irMapAlloc) { InitMeStmtFactory(); } @@ -50,6 +52,7 @@ class IRMap : public AnalysisResult { MeExpr *HashMeExpr(MeExpr &meExpr); void BuildBB(BB &bb, std::vector &bbIRMapProcessed); MeExpr *BuildExpr(BaseNode&); + IvarMeExpr *BuildIvarFromOpMeExpr(OpMeExpr &opMeExpr); IvarMeExpr *BuildLHSIvarFromIassMeStmt(IassignMeStmt &iassignMeStmt); IvarMeExpr *BuildLHSIvar(MeExpr &baseAddr, IassignMeStmt &iassignMeStmt, FieldID fieldID); RegMeExpr *CreateRegRefMeExpr(MeExpr&); @@ -85,6 +88,7 @@ class IRMap : public AnalysisResult { VarMeExpr *CreateNewGlobalTmp(GStrIdx strIdx, PrimType pType); VarMeExpr *CreateNewLocalRefVarTmp(GStrIdx strIdx, TyIdx tIdx); DassignMeStmt *CreateDassignMeStmt(MeExpr&, MeExpr&, BB&); + IassignMeStmt *CreateIassignMeStmt(TyIdx, IvarMeExpr&, MeExpr&, const MapleMap&); RegassignMeStmt *CreateRegassignMeStmt(MeExpr&, MeExpr&, BB&); void InsertMeStmtBefore(BB&, MeStmt&, MeStmt&); MeRegPhiNode *CreateMeRegPhi(RegMeExpr&); @@ -164,6 +168,33 @@ class IRMap : public AnalysisResult { return regMeExprTable; } + MapleUnorderedMap::iterator GetLpreTmpsEnd() { + return lpreTmps.end(); + } + + MapleUnorderedMap::iterator FindLpreTmpsItem(OStIdx idx) { + return lpreTmps.find(idx); + } + + void SetLpreTmps(OStIdx idx, RegMeExpr &expr) { + lpreTmps[idx] = &expr; + } + + MapleUnorderedMap*> &GetVerst2DecrefsMap() { + return vst2Decrefs; + } + + MapleUnorderedMap*>::iterator GetDecrefsEnd() { + return vst2Decrefs.end(); + } + + MapleUnorderedMap*>::iterator FindDecrefItem(VarMeExpr &var) { + return vst2Decrefs.find(&var); + } + + void SetDecrefs(VarMeExpr &var, MapleSet &set) { + vst2Decrefs[&var] = &set; + } void SetNeedAnotherPass(bool need) { needAnotherPass = need; @@ -192,6 +223,8 @@ class IRMap : public AnalysisResult { MapleVector hashTable; // the value number hash table MapleVector vst2MeExprTable; // map versionst to MeExpr. MapleVector regMeExprTable; // record all the regmeexpr created by ssa_pre + MapleUnorderedMap lpreTmps; // for passing LPRE's temp usage to SPRE + MapleUnorderedMap*> vst2Decrefs; // map versionst to decrefreset. bool needAnotherPass = false; // set to true if CFG has changed bool dumpStmtNum = false; BB *curBB = nullptr; // current maple_me::BB being visited diff --git a/src/maple_me/include/me_cond_based.h b/src/maple_me/include/me_cond_based.h new file mode 100644 index 0000000000000000000000000000000000000000..26e00d8d63461f7d06fa71f934b1fad7c767e482 --- /dev/null +++ b/src/maple_me/include/me_cond_based.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MECONDBASED_H +#define MAPLE_ME_INCLUDE_MECONDBASED_H + +#include "me_function.h" +#include "me_phase.h" +#include "me_irmap.h" + +namespace maple { +class MeCondBased { + public: + MeCondBased(MeFunction *func, Dominance *dom) : func(func), dominance(dom) {} + + ~MeCondBased() = default; + bool NullValueFromTestCond(VarMeExpr&, BB&, bool); + bool IsNotNullValue(VarMeExpr&, UnaryMeStmt&, BB*); + + MeFunction *GetFunc() const { + return func; + } + + private: + bool NullValueFromOneTestCond(VarMeExpr&, BB&, BB&, bool); + bool PointerWasDereferencedBefore(VarMeExpr&, UnaryMeStmt&, BB*); + bool PointerWasDereferencedRightAfter(VarMeExpr&, UnaryMeStmt&); + bool IsIreadWithTheBase(VarMeExpr&, MeExpr&); + bool StmtHasDereferencedBase(MeStmt&, VarMeExpr&); + + MeFunction *func; + Dominance *dominance; +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MECONDBASED_H diff --git a/src/maple_me/include/me_cond_based_npc.h b/src/maple_me/include/me_cond_based_npc.h new file mode 100644 index 0000000000000000000000000000000000000000..b7a7c46f63f2896a9c3b124d66bb711df5cb4588 --- /dev/null +++ b/src/maple_me/include/me_cond_based_npc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MECONDBASEDNPC_H +#define MAPLE_ME_INCLUDE_MECONDBASEDNPC_H +#include "me_cond_based.h" + +namespace maple { +class CondBasedNPC : public MeCondBased { + public: + CondBasedNPC(MeFunction *func, Dominance *dom) : MeCondBased(func, dom) {} + + ~CondBasedNPC() = default; + void DoCondBasedNPC(); +}; + +class MeDoCondBasedNPC : public MeFuncPhase { + public: + explicit MeDoCondBasedNPC(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoCondBasedNPC() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "condbasednpc"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MECONDBASEDNPC_H diff --git a/src/maple_me/include/me_cond_based_rc.h b/src/maple_me/include/me_cond_based_rc.h new file mode 100644 index 0000000000000000000000000000000000000000..0f640bc6e05959b387e02fb34273afc6d4f813cd --- /dev/null +++ b/src/maple_me/include/me_cond_based_rc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MECONDBASEDRC_H +#define MAPLE_ME_INCLUDE_MECONDBASEDRC_H +#include "me_cond_based.h" + +namespace maple { +class CondBasedRC : public MeCondBased { + public: + CondBasedRC(MeFunction *f, Dominance *dom) : MeCondBased(f, dom) {} + + virtual ~CondBasedRC() = default; +}; +class MeDoCondBasedRC : public MeFuncPhase { + public: + explicit MeDoCondBasedRC(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoCondBasedRC() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "condbasedrc"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MECONDBASEDRC_H diff --git a/src/maple_me/include/me_function.h b/src/maple_me/include/me_function.h index c13a152e7bf0e9056ae3d3485686e83258f1c16e..c3077c3dc3e1d76ffa27b7b72f3cec982c22679b 100644 --- a/src/maple_me/include/me_function.h +++ b/src/maple_me/include/me_function.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. * * OpenArkCompiler is licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. @@ -139,7 +139,6 @@ bool FilterNullPtr(Iterator it, Iterator endIt) { enum MeFuncHint { kReserved = 0x00, // reserved - kPlacementRCed = 0x01, // method processed by placementrc kAnalyzeRCed = 0x02, // method processed by analyzerc kRcLowered = 0x04, // method lowered by rclowering }; diff --git a/src/maple_me/include/me_ir.h b/src/maple_me/include/me_ir.h index 3085fb603669e780794b1923a92861a55dc6cd32..a3e4076bae89f29fdd79dc1b9add122197229254 100644 --- a/src/maple_me/include/me_ir.h +++ b/src/maple_me/include/me_ir.h @@ -284,6 +284,14 @@ class VarMeExpr final : public MeExpr { maybeNull = maybeNullVal; } + bool GetNoDelegateRC() const { + return noDelegateRC; + } + + void SetNoDelegateRC(bool noDelegateRCVal) { + noDelegateRC = noDelegateRCVal; + } + MeStmt *GetDefStmt() const { return def.defStmt; } @@ -320,6 +328,7 @@ class VarMeExpr final : public MeExpr { bool IsDefByPhi() const { return defBy == kDefByPhi; } + bool noDelegateRC = false; // true if this cannot be optimized by delegaterc union { MeStmt *defStmt = nullptr; // definition stmt of this var MeVarPhiNode *defPhi; diff --git a/src/maple_me/include/me_lower_globals.h b/src/maple_me/include/me_lower_globals.h new file mode 100644 index 0000000000000000000000000000000000000000..35ecf1923b80072b70cbcb405ec31b5c80723862 --- /dev/null +++ b/src/maple_me/include/me_lower_globals.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MELOWERGLOBALS_H +#define MAPLE_ME_INCLUDE_MELOWERGLOBALS_H +#include "me_function.h" +#include "me_irmap.h" + +namespace maple { +class MeLowerGlobals { + public: + MeLowerGlobals(MeFunction *func, SSATab *ssaTab) : func(func), irMap(func->GetIRMap()), ssaTable(ssaTab) {} + MeLowerGlobals(const MeLowerGlobals &p) = default; + + ~MeLowerGlobals() = default; + MeLowerGlobals &operator=(const MeLowerGlobals &p) = default; + + void Run(); + + private: + MeFunction *func; + IRMap *irMap; + SSATab *ssaTable; + void LowerGlobalDreads(MeStmt &stmt, MeExpr *x); +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MELOWERGLOBALS_H diff --git a/src/maple_me/include/me_option.h b/src/maple_me/include/me_option.h index 55788e0e565bf0af5814b3f33bef3044c86be6ba..968631706eb231bcb0263d91cabbe6882dd35d4a 100644 --- a/src/maple_me/include/me_option.h +++ b/src/maple_me/include/me_option.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. * * OpenArkCompiler is licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. @@ -48,11 +48,14 @@ class MeOption { static bool DumpPhase(const std::string &phase); static std::unordered_set dumpPhases; + static bool dumpBefore; static bool dumpAfter; static constexpr int kRangeArrayLen = 2; static unsigned long range[kRangeArrayLen]; static bool useRange; static std::string dumpFunc; + static std::string skipFrom; + static std::string skipAfter; static bool quiet; static bool setCalleeHasSideEffect; static bool noSteensgaard; @@ -60,10 +63,26 @@ class MeOption { static uint8 aliasAnalysisLevel; static bool noDot; static bool stmtNum; + static bool rcLowering; static uint8 optLevel; + static uint32 stmtprePULimit; + static uint32 epreLimit; + static uint32 eprePULimit; + static uint32 lpreLimit; + static uint32 lprePULimit; + static uint32 delRcPULimit; static bool ignoreIPA; + static bool epreIncludeRef; + static bool epreLocalRefVar; + static bool epreLHSIvar; static bool dseKeepRef; static bool lessThrowAlias; + static bool noDelegateRC; + static bool noCondBasedRC; + static bool nullCheckPre; + static bool assign2FinalPre; + static bool clinitPre; + static bool dassignPre; static bool regreadAtReturn; static bool propBase; static bool propIloadRef; @@ -71,6 +90,9 @@ class MeOption { static bool propFinaliLoadRef; static bool propIloadRefNonParm; static bool propAtPhi; + static bool lpreSpeculate; + static bool spillAtCatch; + static bool optDirectCall; private: std::unordered_set skipPhases; MapleAllocator optionAlloc; diff --git a/src/maple_me/include/me_phases.def b/src/maple_me/include/me_phases.def index 5fd60cbdff6b05b5f1cd9090dc3c532fd8dae080..8e889e481d6616467765a1496aeb77ac999eecca 100644 --- a/src/maple_me/include/me_phases.def +++ b/src/maple_me/include/me_phases.def @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. * * OpenArkCompiler is licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. @@ -18,5 +18,10 @@ FUNCAPHASE(MeFuncPhase_ALIASCLASS, MeDoAliasClass) FUNCAPHASE(MeFuncPhase_SSA, MeDoSSA) FUNCAPHASE(MeFuncPhase_IRMAP, MeDoIRMap) FUNCAPHASE(MeFuncPhase_BBLAYOUT, MeDoBBLayout) -FUNCTPHASE(MeFuncPhase_EMIT, MeDoEmit) +FUNCAPHASE(MeFuncPhase_MELOOP, MeDoMeLoop) +FUNCTPHASE(MeFuncPhase_SSAEPRE, MeDoSSAEPre) +FUNCTPHASE(MeFuncPhase_SSALPRE, MeDoSSALPre) +FUNCTPHASE(MeFuncPhase_STOREPRE, MeDoStorePre) +FUNCTPHASE(MeFuncPhase_STMTPRE, MeDoStmtPre) FUNCTPHASE(MeFuncPhase_RCLOWERING, MeDoRCLowering) +FUNCTPHASE(MeFuncPhase_EMIT, MeDoEmit) diff --git a/src/maple_me/include/me_rc_lowering.h b/src/maple_me/include/me_rc_lowering.h index 3f33574e2886b4640fe81b05432c0570bbb3445b..6a58eae885f524576b3912362bc4a1939c1119d1 100644 --- a/src/maple_me/include/me_rc_lowering.h +++ b/src/maple_me/include/me_rc_lowering.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. * * OpenArkCompiler is licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. @@ -23,12 +23,11 @@ namespace maple { class RCLowering { public: - RCLowering(MeFunction &f, KlassHierarchy &kh, bool enabledDebug) + RCLowering(MeFunction &f, bool enabledDebug) : func(f), mirModule(f.GetMIRModule()), irMap(*f.GetIRMap()), ssaTab(*f.GetMeSSATab()), - klassHierarchy(kh), enabledDebug(enabledDebug) {} virtual ~RCLowering() = default; @@ -38,7 +37,9 @@ class RCLowering { void RCLower(); void PostRCLower(); void Finish(); - void FastBBLower(BB &bb); + bool GetIsAnalyzed() const { + return isAnalyzed; + } private: void MarkLocalRefVar(); @@ -46,6 +47,11 @@ class RCLowering { void BBLower(BB &bb); void CreateCleanupIntrinsics(); void HandleArguments(); + void CompactRC(BB &bb); + void CompactIncAndDec(MeStmt &incStmt, MeStmt &decStmt); + void CompactIncAndDecReset(MeStmt &incStmt, MeStmt &resetStmt); + void ReplaceDecResetWithDec(MeStmt &prevStmt, MeStmt &stmt); + void CompactAdjacentDecReset(MeStmt &prevStmt, MeStmt &stmt); // create new symbol from name and return its ost OriginalSt *RetrieveOSt(const std::string &name, bool isLocalrefvar) const; // create new symbol from temp name and return its VarMeExpr @@ -59,6 +65,7 @@ class RCLowering { MIRIntrinsicID PrepareVolatileCall(const MeStmt &stmt, MIRIntrinsicID index = INTRN_UNDEFINED); IntrinsiccallMeStmt *CreateRCIntrinsic(MIRIntrinsicID intrnID, const MeStmt &stmt, std::vector &opnds, bool assigned = false); + MeExpr *HandleIncRefAndDecRefStmt(MeStmt &stmt); void InitializedObjectFields(MeStmt &stmt); bool IsInitialized(IvarMeExpr &ivar); void PreprocessAssignMeStmt(MeStmt &stmt); @@ -86,10 +93,10 @@ class RCLowering { MIRModule &mirModule; IRMap &irMap; SSATab &ssaTab; - KlassHierarchy &klassHierarchy; std::vector rets{}; // std::vector of return statement unsigned int tmpCount = 0; bool needSpecialHandleException = false; + bool isAnalyzed = false; std::set assignedPtrSym; std::set tmpLocalRefVars; std::set gcMallocObjects{}; @@ -98,9 +105,6 @@ class RCLowering { // used to store initialized map, help to optimize dec ref in first assignment std::unordered_map*> initializedFields{}; bool enabledDebug; - bool checkRefFormal = false; - bool checkRefAssign = false; - bool checkRefReturn = false; }; class MeDoRCLowering : public MeFuncPhase { diff --git a/src/maple_me/include/me_ssa_epre.h b/src/maple_me/include/me_ssa_epre.h new file mode 100644 index 0000000000000000000000000000000000000000..1c4e8490cbccc1dfaae1d4f7f2cba9d4e869c3db --- /dev/null +++ b/src/maple_me/include/me_ssa_epre.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MESSAEPRE_H +#define MAPLE_ME_INCLUDE_MESSAEPRE_H + +#include "me_function.h" +#include "me_irmap.h" +#include "me_cfg.h" +#include "ssa_epre.h" + +namespace maple { +class MeSSAEPre : public SSAEPre { + public: + // a symbol is a candidate for ssaupdate if its ostidx key exists in the map; + // the mapped set gives bbs where dassign's are inserted by ssa_epre for the symbol + explicit MeSSAEPre(MeFunction *func, IRMap &map, Dominance &dom, MemPool &memPool, MemPool &mp2, uint32 limit, + bool includeRef, bool epreLocalRefVar, bool lhsIvar) + : SSAEPre(map, dom, memPool, mp2, kExprPre, limit, includeRef, lhsIvar), + candsForSSAUpdate(std::less(), ssaPreAllocator.Adapter()), + func(func), + epreLocalRefVar(epreLocalRefVar) {} + + virtual ~MeSSAEPre() = default; + void GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) override; + bool ScreenPhiBB(BBId) const override { + return true; + } + + MapleMap*> &GetCandsForSSAUpdate() { + return candsForSSAUpdate; + } + + protected: + MapleMap*> candsForSSAUpdate; + MeFunction *func; + bool epreLocalRefVar; + + private: + void BuildWorkList() override; + BB *GetBB(BBId id) override { + return func->GetBBFromID(id); + } + + PUIdx GetPUIdx() const override { + return func->GetMirFunc()->GetPuidx(); + } + + bool CfgHasDoWhile() override { + return func->GetTheCfg()->GetHasDoWhile(); + } + + bool EpreLocalRefVar() override { + return epreLocalRefVar; + } + + void EnterCandsForSSAUpdate(OStIdx ostIdx, BB *bb) override { + if (candsForSSAUpdate.find(ostIdx) == candsForSSAUpdate.end()) { + MapleSet *bbSet = ssaPreMemPool->New>(std::less(), ssaPreAllocator.Adapter()); + bbSet->insert(bb->GetBBId()); + candsForSSAUpdate[ostIdx] = bbSet; + } else { + candsForSSAUpdate[ostIdx]->insert(bb->GetBBId()); + } + } +}; + +class MeDoSSAEPre : public MeFuncPhase { + public: + explicit MeDoSSAEPre(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoSSAEPre() = default; + AnalysisResult *Run(MeFunction *ir, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "epre"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MESSAEPRE_H diff --git a/src/maple_me/include/me_ssa_lpre.h b/src/maple_me/include/me_ssa_lpre.h new file mode 100644 index 0000000000000000000000000000000000000000..9b67eeaf7feb07f72fb3a6970b35b7849f5da0dc --- /dev/null +++ b/src/maple_me/include/me_ssa_lpre.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_SSA_LPRE_H +#define MAPLE_ME_INCLUDE_ME_SSA_LPRE_H +#include "me_irmap.h" +#include "ssa_pre.h" +#include "me_loop_analysis.h" + +namespace maple { +constexpr size_t kDoLpreBBsLimit = 0x7fffff; +class MeSSALPre : public SSAPre { + public: + MeSSALPre(MeFunction *f, MeIRMap &hMap, Dominance &dom, MemPool &memPool, MemPool &mp2, PreKind kind, uint32 limit) + : SSAPre(hMap, dom, memPool, mp2, kind, limit), + irMap(&hMap), + func(f), + assignedFormals(ssaPreAllocator.Adapter()), + loopHeadBBs(ssaPreAllocator.Adapter()) {} + + virtual ~MeSSALPre() = default; + void FindLoopHeadBBs(IdentifyLoops *identLoops); + + private: + void GenerateSaveRealOcc(MeRealOcc*) override; + void GenerateReloadRealOcc(MeRealOcc*) override; + MeExpr *PhiOpndFromRes(MeRealOcc*, size_t) override; + void GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) override; + void ComputeVarAndDfPhis() override; + bool ScreenPhiBB(BBId) const override { + return true; + } + + void CollectVarForMeExpr(MeExpr *meExpr, std::vector &varVec) override { + if (meExpr->GetMeOp() == kMeOpAddrof || meExpr->GetMeOp() == kMeOpAddroffunc) { + return; + } + varVec.push_back(meExpr); + } + + void CollectVarForCand(MeRealOcc *realOcc, std::vector &varVec) override { + if (realOcc->GetMeExpr()->GetMeOp() == kMeOpAddrof || realOcc->GetMeExpr()->GetMeOp() == kMeOpAddroffunc) { + return; + } + varVec.push_back(realOcc->GetMeExpr()); + } + + void BuildEntryLHSOcc4Formals() override; + void BuildWorkListLHSOcc(MeStmt *meStmt, int32 seqStmt) override; + void CreateMembarOccAtCatch(BB &bb) override; + void BuildWorkListExpr(MeStmt*, int32, MeExpr*, bool, MeExpr*, bool isRootExpr) override; + void BuildWorkList() override; + BB *GetBB(BBId id) override { + return func->GetBBFromID(id); + } + + PUIdx GetPUIdx() const override { + return func->GetMirFunc()->GetPuidx(); + } + + bool IsLoopHeadBB(BBId bbId) const override { + return loopHeadBBs.find(bbId) != loopHeadBBs.end(); + } + + MeIRMap *irMap; + MeFunction *func; + MapleSet assignedFormals; // set of formals that are assigned + MapleSet loopHeadBBs; +}; + +class MeDoSSALPre : public MeFuncPhase { + public: + explicit MeDoSSALPre(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoSSALPre() = default; + AnalysisResult *Run(MeFunction *irFunc, MeFuncResultMgr *funcMgr, ModuleResultMgr *moduleMgr) override; + std::string PhaseName() const override { + return "lpre"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_SSA_LPRE_H diff --git a/src/maple_me/include/me_ssu_pre.h b/src/maple_me/include/me_ssu_pre.h new file mode 100644 index 0000000000000000000000000000000000000000..80d1480a12c2ed0ff6b2a318143b146f566cf5ab --- /dev/null +++ b/src/maple_me/include/me_ssu_pre.h @@ -0,0 +1,409 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MESSUPRE_H +#define MAPLE_ME_INCLUDE_MESSUPRE_H +#include "me_function.h" +#include "me_irmap.h" +#include "me_dominance.h" +namespace maple { +enum SOccType { + kSOccUndef, + kSOccReal, + kSOccLambda, + kSOccLambdaRes, + kSOccEntry, + kSOccUse, + kSOccPhi +}; +class SOcc { + public: + SOcc(SOccType ty, BB *bb) : occTy(ty), classId(0), mirBB(bb), use(nullptr) {} + + virtual void Dump() = 0; + bool IsPostDominate(Dominance *dom, SOcc *occ) { + CHECK_NULL_FATAL(occ); + CHECK_NULL_FATAL(dom); + return dom->PostDominate(*mirBB, *occ->mirBB); + } + + SOccType GetOccTy() { + return occTy; + } + + void SetOccTy(SOccType occTy) { + this->occTy = occTy; + } + + uint32 GetClassId() { + return classId; + } + + void SetClassId(uint32 classId) { + this->classId = classId; + } + + BB *GetBB() { + return mirBB; + } + + const BB *GetBB() const { + return mirBB; + } + + void SetBB(BB *mirBB) { + this->mirBB = mirBB; + } + + SOcc *GetUse() { + return use; + } + + void SetUse(SOcc *use) { + this->use = use; + } + private: + SOccType occTy; + uint32 classId; + BB *mirBB; // the BB it occurs in + SOcc *use; // points to its single use +}; +class SRealOcc : public SOcc { + public: + SRealOcc() + : SOcc(kSOccReal, nullptr), meStmt(nullptr), vMeExpr(nullptr), realFromDef(false), redundant(true) {} + SRealOcc(MeStmt *s) + : SOcc(kSOccReal, s->GetBB()), meStmt(s), vMeExpr(nullptr), realFromDef(false), redundant(true) {} + SRealOcc(MeStmt *s, VarMeExpr *v) + : SOcc(kSOccReal, s->GetBB()), meStmt(s), vMeExpr(v), realFromDef(false), redundant(true) {} + SRealOcc(BB *bb, VarMeExpr *v) + : SOcc(kSOccReal, bb), meStmt(nullptr), vMeExpr(v), realFromDef(false), redundant(true) {} + virtual ~SRealOcc() = default; + void Dump() { + LogInfo::MapleLogger() << "RealOcc at bb" << GetBB()->GetBBId(); + if (realFromDef) { + LogInfo::MapleLogger() << "(from-def)"; + } + LogInfo::MapleLogger() << " classId" << GetClassId(); + } + + MeStmt *GetStmt() { + return meStmt; + } + + VarMeExpr *GetVar() { + return vMeExpr; + } + + bool GetRealFromDef() { + return realFromDef; + } + + void SetRealFromDef(bool realFromDef) { + this->realFromDef = realFromDef; + } + + bool GetRedundant() { + return redundant; + } + + void SetRedundant(bool redundant) { + this->redundant = redundant; + } + private: + MeStmt *meStmt; // the stmt of this real occurrence; null for formal at entry + VarMeExpr *vMeExpr; // the varmeexpr of this real occurrence + bool realFromDef; // used only by placementRC + bool redundant; +}; +class SLambdaOcc; +class SLambdaResOcc : public SOcc { + public: + SLambdaResOcc(BB *bb) : SOcc(kSOccLambdaRes, bb), useLambdaOcc(nullptr), hasRealUse(false), insertHere(false) {} + + virtual ~SLambdaResOcc() = default; + void Dump() { + LogInfo::MapleLogger() << "LambdaResOcc at bb" << GetBB()->GetBBId() << " classId" << GetClassId(); + } + + SLambdaOcc *GetUseLambdaOcc() { + return useLambdaOcc; + } + + void SetUseLambdaOcc(SLambdaOcc *useLambdaOcc) { + this->useLambdaOcc = useLambdaOcc; + } + + bool GetHasRealUse() { + return hasRealUse; + } + + void SetHasRealUse(bool hasRealUse) { + this->hasRealUse = hasRealUse; + } + + bool GetInsertHere() { + return insertHere; + } + + void SetInsertHere(bool insertHere) { + this->insertHere = insertHere; + } + private: + SLambdaOcc *useLambdaOcc; // its rhs use + bool hasRealUse; + bool insertHere; +}; +class SLambdaOcc : public SOcc { + public: + SLambdaOcc(BB *bb, MapleAllocator *alloc) + : SOcc(kSOccLambda, bb), isUpsafe(true), isCanBeAnt(true), isEarlier(true), lambdaRes(alloc->Adapter()) {} + + virtual ~SLambdaOcc() = default; + bool WillBeAnt() const { + return isCanBeAnt && !isEarlier; + } + + void Dump() { + LogInfo::MapleLogger() << "LambdaOcc at bb" << GetBB()->GetBBId() << " classId" << GetClassId() << " Lambda["; + for (size_t i = 0; i < lambdaRes.size(); i++) { + lambdaRes[i]->Dump(); + if (i != lambdaRes.size() - 1) { + LogInfo::MapleLogger() << ", "; + } + } + LogInfo::MapleLogger() << "]"; + } + + bool GetIsUpsafe() { + return isUpsafe; + } + + void SetIsUpsafe(bool isUpsafe) { + this->isUpsafe = isUpsafe; + } + + bool GetIsCanBeAnt() { + return isCanBeAnt; + } + + void SetIsCanBeAnt(bool isCanBeAnt) { + this->isCanBeAnt = isCanBeAnt; + } + + bool GetIsEarlier() { + return isEarlier; + } + + void SetIsEarlier(bool isEarlier) { + this->isEarlier = isEarlier; + } + + MapleVector &GetLambdaRes() { + return lambdaRes; + } + private: + bool isUpsafe; + bool isCanBeAnt; + bool isEarlier; + MapleVector lambdaRes; +}; +class SEntryOcc : public SOcc { + public: + explicit SEntryOcc(BB *bb) : SOcc(kSOccEntry, bb) {} + + virtual ~SEntryOcc() = default; + void Dump() { + LogInfo::MapleLogger() << "EntryOcc at bb" << GetBB()->GetBBId(); + } +}; +class SUseOcc : public SOcc { + public: + explicit SUseOcc(BB *bb) : SOcc(kSOccUse, bb) {} + + virtual ~SUseOcc() = default; + void Dump() { + LogInfo::MapleLogger() << "UseOcc at bb" << GetBB()->GetBBId(); + } +}; +class SPhiOcc : public SOcc { + public: + SPhiOcc(BB *bb, MeVarPhiNode *p, VarMeExpr *v) : SOcc(kSOccPhi, bb), phi(p), vMeExpr(v) {}; + + virtual ~SPhiOcc() = default; + + MeVarPhiNode *GetPhiNode() { + return phi; + } + + const MeVarPhiNode *GetPhiNode() const { + return phi; + } + + VarMeExpr *GetVar() { + return vMeExpr; + } + + const VarMeExpr *GetVar() const { + return vMeExpr; + } + + void Dump() { + LogInfo::MapleLogger() << "PhiOcc at bb" << GetBB()->GetBBId(); + } + private: + MeVarPhiNode *phi; // the phinode of this real occurrence; + VarMeExpr *vMeExpr; // the varmeexpr of this real occurrence +}; +class SpreWorkCand { + public: + SpreWorkCand(MapleAllocator *alloc, const OriginalSt *ost) + : next(nullptr), + theOst(ost), + theVar(nullptr), + realOccs(alloc->Adapter()), + hasStoreOcc(false), + hasCriticalEdge(false) {} + + ~SpreWorkCand() = default; + + SpreWorkCand *GetNext() { + return next; + } + + const OriginalSt *GetOst() const { + return theOst; + } + + VarMeExpr *GetTheVar() { + return theVar; + } + + void SetTheVar(VarMeExpr *theVar) { + this->theVar = theVar; + } + + MapleVector &GetRealOccs() { + return realOccs; + } + + bool GetHasStoreOcc() { + return hasStoreOcc; + } + + void SetHasStoreOcc(bool hasStoreOcc) { + this->hasStoreOcc = hasStoreOcc; + } + + bool GetHasCriticalEdge() { + return hasCriticalEdge; + } + + void SetHasCriticalEdge(bool hasCriticalEdge) { + this->hasCriticalEdge = hasCriticalEdge; + } + + private: + SpreWorkCand *next; + const OriginalSt *theOst; // the stored symbol of this workcand + VarMeExpr *theVar; // any existing node of the lhs var + MapleVector realOccs; // maintained in order of pdt_preorder + bool hasStoreOcc; // true if there is any store occurrence + bool hasCriticalEdge; // determined by Finalize step +}; +class MeSSUPre { + public: + enum PreKind { + kStorePre, + kDecrefPre, + kSecondDecrefPre, + kSubsumePre + } preKind; + MeSSUPre(MeFunction *f, Dominance *dom, MemPool *memPool, PreKind kind, bool enabledDebug) + : preKind(kind), + func(f), + ssaTab(f->GetMeSSATab()), + irMap(f->GetIRMap()), + mirModule(&f->GetMeSSATab()->GetModule()), + dom(dom), + spreMp(memPool), + spreAllocator(memPool), + workCandMap(std::less(), spreAllocator.Adapter()), + workCand(nullptr), + lambdaDfns(std::less(), spreAllocator.Adapter()), + classCount(0), + allOccs(spreAllocator.Adapter()), + lambdaOccs(spreAllocator.Adapter()), + entryOccs(spreAllocator.Adapter()), + catchBlocks2Insert(spreAllocator.Adapter()), + enabledDebug(enabledDebug) {} + + void ApplySSUPre(); + + protected: + MeFunction *func; + SSATab *ssaTab; + MeIRMap *irMap; + MIRModule *mirModule; + Dominance *dom; + MemPool *spreMp; + MapleAllocator spreAllocator; + MapleMap workCandMap; + SpreWorkCand *workCand; // current SpreWorkCand + // step 1 lambda insertion data structures: + // following are set of BBs in terms of their dfn's; index into + // dominance->pdt_preorder to get their bbid's + MapleSet lambdaDfns; // set by FormLambdas() + // step 2 renaming + uint32 classCount; // for assigning new class id + // the following 3 lists are all maintained in order of pdt_preorder + MapleVector allOccs; // cleared at start of each workcand + MapleVector lambdaOccs; // cleared at start of each workcand + MapleVector entryOccs; // this is shared by all workcands + // used in steps 5 and 6 + MapleSet catchBlocks2Insert; // need insertions at entries to these catch blocks + bool enabledDebug; + // step 6 methods + virtual void CodeMotion() = 0; + // step 5 methods + void Finalize(); + // step 4 methods + void ResetCanBeAnt(SLambdaOcc *lambda); + void ComputeCanBeAnt(); + void ResetEarlier(SLambdaOcc *lambda); + void ComputeEarlier(); + void ResetCanBeFullyAnt(SLambdaOcc *lambda); + void ComputeCanBeFullyAnt(); + // step 3 methods + void ResetUpsafe(SLambdaResOcc *lambdaRes); + void ComputeUpsafe(); + // step 2 methods + void Rename(); + // step 1 methods + void GetIterPdomFrontier(const BB *bb, MapleSet *pdfSet, std::vector &visitedMap); + void FormLambdas(); + void FormLambdaRes(); + void CreateSortedOccs(); + // step 0 methods + void CreateEntryOcc(BB *bb) { + SEntryOcc *entryOcc = spreMp->New(bb); + entryOccs.push_back(entryOcc); + } + + virtual void BuildWorkListBB(BB *bb) = 0; + virtual void PerCandInit() = 0; + virtual void CreateEmptyCleanupIntrinsics() {} +}; +}; // namespace maple +#endif // MAPLE_ME_INCLUDE_MESSUPRE_H diff --git a/src/maple_me/include/me_stmt_pre.h b/src/maple_me/include/me_stmt_pre.h new file mode 100644 index 0000000000000000000000000000000000000000..41b568136e0ce3875dc610603ca9693bbb51d06b --- /dev/null +++ b/src/maple_me/include/me_stmt_pre.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MESTMTPRE_H +#define MAPLE_ME_INCLUDE_MESTMTPRE_H + +#include "me_function.h" +#include "me_irmap.h" +#include "ssa_epre.h" + +namespace maple { +class MeStmtPre : public SSAEPre { + public: + // a symbol is a candidate for ssaupdate if its ostidx key exists in the map; + // the mapped set gives bbs where dassign's are inserted by stmtpre for the symbol + MeStmtPre(MeFunction *func, IRMap &map, Dominance &dom, MemPool &memPool, MemPool &mp2, uint32 limit) + : SSAEPre(map, dom, memPool, mp2, kStmtPre, limit, true, false), + candsForSSAUpdate(std::less(), ssaPreAllocator.Adapter()), + func(func), + versionStackVec(ssaTab->GetOriginalStTable().GetOriginalStVector().size(), nullptr, ssaPreAllocator.Adapter()), + useOccurMap(std::less(), ssaPreAllocator.Adapter()) {} + + virtual ~MeStmtPre() = default; + void GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) override; + bool ScreenPhiBB(BBId) const override { + return true; + } + + MapleMap*> &GetCandsForSSAUpdate() { + return candsForSSAUpdate; + } + + protected: + MapleMap*> candsForSSAUpdate; + MeFunction *func; + MapleVector*> versionStackVec; // top of stack gives last version during BuildWorkList() + MapleMap*> useOccurMap; // give the set of BBs (in dfn) that contain uses of the symbol + + private: + // code motion phase + void CodeMotion() override; + // finalize phase + void Finalize1() override; + void Finalize2() override {}; + // fully available (replaces downsafety, canbeavail and later under SSAFRE) + void ResetFullyAvail(MePhiOcc *occg); + void ComputeFullyAvail(); + // rename phase + bool AllVarsSameVersion(MeRealOcc *realOcc1, MeRealOcc *realOcc2) override; + bool AllVarsSameVersionStmtFre(MeRealOcc *topOcc, MeRealOcc *curOcc) const; + void CollectVarForMeStmt(MeStmt *meStmt, MeExpr *meExpr, std::vector &varVec); + void CollectVarForCand(MeRealOcc *realOcc, std::vector &varVec) override; + MeStmt *CopyMeStmt(MeStmt &meStmt) override; + MeStmt *PhiOpndFromRes4Stmt(MeRealOcc *realZ, size_t j, MeExpr *&lhsVar); + void Rename1StmtFre(); + void Rename2() override; + // phi insertion phase + void ComputeVarAndDfPhis() override; + void CreateSortedOccs() override; + void ConstructUseOccurMapExpr(uint32 bbDfn, MeExpr *x); + void ConstructUseOccurMap() override; // build useOccurMap for dassign candidates + PreStmtWorkCand *CreateStmtRealOcc(MeStmt &meStmt, int seqStmt); + void VersionStackChiListUpdate(const MapleMap &chiList); + void BuildWorkListBB(BB *bb) override; + void BuildWorkList() override; + void RemoveUnnecessaryDassign(DassignMeStmt *dssMeStmt); + void DoSSAFRE() override; + BB *GetBB(BBId id) override { + return func->GetBBFromID(id); + } + + PUIdx GetPUIdx() const override { + return func->GetMirFunc()->GetPuidx(); + } +}; + +class MeDoStmtPre : public MeFuncPhase { + public: + MeDoStmtPre(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoStmtPre() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "stmtpre"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MESTMTPRE_H diff --git a/src/maple_me/include/me_store_pre.h b/src/maple_me/include/me_store_pre.h new file mode 100644 index 0000000000000000000000000000000000000000..29f67663932cab738647d8a1fe71248ff2c687d8 --- /dev/null +++ b/src/maple_me/include/me_store_pre.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MESTOREPRE_H +#define MAPLE_ME_INCLUDE_MESTOREPRE_H +#include "me_ssu_pre.h" +#include "me_alias_class.h" +namespace maple { +class MeStorePre : public MeSSUPre { + public: + MeStorePre(MeFunction *f, Dominance *dom, AliasClass *ac, MemPool *memPool, bool enabledDebug) + : MeSSUPre(f, dom, memPool, kStorePre, enabledDebug), aliasClass(ac), curTemp(nullptr), + bbCurTempMap(spreAllocator.Adapter()) {} + + virtual ~MeStorePre() = default; + + private: + AliasClass *aliasClass; + // step 6 code motion + RegMeExpr *curTemp; // the preg for the RHS of inserted stores + MapleUnorderedMap bbCurTempMap; // map bb to curTemp version + // step 6 methods + void CheckCreateCurTemp(); + RegMeExpr *EnsureRHSInCurTemp(BB *bb); + void CodeMotion(); + // step 0 methods + void CreateRealOcc(OStIdx ostIdx, MeStmt *meStmt); + void CreateUseOcc(OStIdx ostIdx, BB *bb); + void CreateSpreUseOccsThruAliasing(const OriginalSt *muOst, BB *bb); + void FindAndCreateSpreUseOccs(MeExpr *x, BB *bb); + void CreateSpreUseOccsForAll(BB *bb); + void BuildWorkListBB(BB *bb); + void PerCandInit() { + curTemp = nullptr; + bbCurTempMap.clear(); + } +}; + +class MeDoStorePre : public MeFuncPhase { + public: + explicit MeDoStorePre(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoStorePre() = default; + AnalysisResult *Run(MeFunction *ir, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "storepre"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MESTOREPRE_H diff --git a/src/maple_me/include/occur.h b/src/maple_me/include/occur.h new file mode 100644 index 0000000000000000000000000000000000000000..8cabbe83a85fea49654060cbb654dde25410d52c --- /dev/null +++ b/src/maple_me/include/occur.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_OCCUR_H +#define MAPLE_ME_INCLUDE_OCCUR_H +// the data structures that represent occurrences and work candidates for SSAPRE +#include "me_function.h" +#include "irmap.h" +const int kWorkCandHashLength = 229; +namespace maple { +enum OccType { + kOccUndef, + kOccReal, + kOccPhiocc, + kOccPhiopnd, + kOccExit, + kOccInserted, + kOccGcmalloc, + kOccUse, // for use appearances when candidate is dassign + kOccMembar, // for representing occurrence of memory barriers (use MeRealOcc) +}; + +class MePhiOcc; +class MeOccur { + public: + MeOccur(OccType ty, int cId, MeOccur *df) : occTy(ty), classID(cId), mirBB(nullptr), def(df) {} + MeOccur(OccType ty, int cId, BB *bb, MeOccur *df) : occTy(ty), classID(cId), mirBB(bb), def(df) {} + virtual ~MeOccur() = default; + virtual void Dump(IRMap&); + void DumpOccur(IRMap&); + bool IsDominate(Dominance *dom, MeOccur*); + const BB *GetBB() const { + return mirBB; + } + + BB *GetBB() { + return mirBB; + } + + void SetBB(BB &bb) { + mirBB = &bb; + } + + OccType GetOccType() const { + return occTy; + } + + void SetOccType(OccType occType) { + occTy = occType; + } + + int GetClassID() const { + return classID; + } + + void SetClassID(int id) { + classID = id; + } + + const MeOccur *GetDef() const { + return def; + } + + MeOccur *GetDef() { + return def; + } + + void SetDef(MeOccur *define) { + def = define; + } + MeExpr *GetSavedExpr(); + private: + OccType occTy; // kinds of occ + int classID; // class id + BB *mirBB; // the BB it occurs in + MeOccur *def; +}; + +class MeRealOcc : public MeOccur { + public: + MeRealOcc(MeStmt *stmt, int sq, MeExpr *expr) + : MeOccur(kOccReal, 0, nullptr), + meStmt(stmt), + meExpr(expr), + savedExpr(nullptr), + seq(sq), + position(0), + isReload(false), + isSave(false), + isLHS(false), + isFormalAtEntry(false) { + if (stmt != nullptr) { + SetBB(*stmt->GetBB()); + } + } + + ~MeRealOcc() = default; + void Dump(IRMap&); + const MeStmt *GetMeStmt() const { + return meStmt; + } + + MeStmt *GetMeStmt() { + return meStmt; + } + + void SetMeStmt(MeStmt &stmt) { + meStmt = &stmt; + } + + Opcode GetOpcodeOfMeStmt() const { + return meStmt->GetOp(); + } + + const MeExpr *GetMeExpr() const { + return meExpr; + } + + MeExpr *GetMeExpr() { + return meExpr; + } + + void SetMeExpr(MeExpr &expr) { + meExpr = &expr; + } + + const MeExpr *GetSavedExpr() const { + return savedExpr; + } + + MeExpr *GetSavedExpr() { + return savedExpr; + } + + void SetSavedExpr(MeExpr &expr) { + savedExpr = &expr; + } + + int GetSequence() const { + return seq; + } + + void SetSequence(int sequence) { + seq = sequence; + } + + size_t GetPosition() const { + return position; + } + + void SetPosition(size_t pos) { + position = pos; + } + + bool IsReload() const { + return isReload; + } + + void SetIsReload(bool reload) { + isReload = reload; + } + + bool IsSave() const { + return isSave; + } + + void SetIsSave(bool save) { + isSave = save; + } + + bool IsLHS() const { + return isLHS; + } + + void SetIsLHS(bool lhs) { + isLHS = lhs; + } + + bool IsFormalAtEntry() const { + return isFormalAtEntry; + } + + void SetIsFormalAtEntry(bool isFormal) { + isFormalAtEntry = isFormal; + } + private: + MeStmt *meStmt; // the stmt that has this occ + MeExpr *meExpr; // the expr it's corresponding to + MeExpr *savedExpr; // the reall occ saved to, must be a VarMeExpr/RegMeExpr + int seq; // meStmt sequence number in the bb + size_t position; // the position in the workCand->GetRealOccs() vector + bool isReload; + bool isSave; + bool isLHS; + bool isFormalAtEntry; // the fake lhs occurrence at entry for formals +}; + +class MeInsertedOcc : public MeOccur { + public: + MeInsertedOcc(MeExpr *expr, MeStmt *stmt, BB *bb) + : MeOccur(kOccInserted, 0, bb, nullptr), meExpr(expr), meStmt(stmt), savedExpr(nullptr) {} + + ~MeInsertedOcc() = default; + void Dump(IRMap&); + const MeStmt *GetMeStmt() const { + return meStmt; + } + + MeStmt *GetMeStmt() { + return meStmt; + } + + void SetMeStmt(MeStmt &stmt) { + meStmt = &stmt; + } + + Opcode GetOpcodeOfMeStmt() const { + return meStmt->GetOp(); + } + + const MeExpr *GetMeExpr() const { + return meExpr; + } + + MeExpr *GetMeExpr() { + return meExpr; + } + + void SetMeExpr(MeExpr &expr) { + meExpr = &expr; + } + + const MeExpr *GetSavedExpr() const { + return savedExpr; + } + + MeExpr *GetSavedExpr() { + return savedExpr; + } + + void SetSavedExpr(MeExpr &expr) { + savedExpr = &expr; + } + private: + MeExpr *meExpr; + MeStmt *meStmt; + MeExpr *savedExpr; +}; + +class MePhiOpndOcc : public MeOccur { + public: + MePhiOpndOcc(BB *dbb) + : MeOccur(kOccPhiopnd, 0, dbb, nullptr), + isProcessed(false), + hasRealUse(false), + isInsertedOcc(false), + isPhiOpndReload(false), + defPhiOcc(nullptr) { + currentExpr.meStmt = nullptr; + } + + ~MePhiOpndOcc() = default; + bool IsOkToInsert(); + void Dump(IRMap&); + bool IsProcessed() const { + return isProcessed; + } + + void SetIsProcessed(bool processed) { + isProcessed = processed; + } + + bool HasRealUse() const { + return hasRealUse; + } + + void SetHasRealUse(bool realUse) { + hasRealUse = realUse; + } + + bool IsInsertedOcc() const { + return isInsertedOcc; + } + + void SetIsInsertedOcc(bool inserted) { + isInsertedOcc = inserted; + } + + bool IsPhiOpndReload() const { + return isPhiOpndReload; + } + + void SetIsPhiOpndReload(bool phiOpndReload) { + isPhiOpndReload = phiOpndReload; + } + + const MePhiOcc *GetDefPhiOcc() const { + return defPhiOcc; + } + + MePhiOcc *GetDefPhiOcc() { + return defPhiOcc; + } + + void SetDefPhiOcc(MePhiOcc &occ) { + defPhiOcc = &occ; + } + + const MeExpr *GetCurrentMeExpr() const { + return currentExpr.meExpr; + } + + MeExpr *GetCurrentMeExpr() { + return currentExpr.meExpr; + } + + void SetCurrentMeExpr(MeExpr &expr) { + currentExpr.meExpr = &expr; + } + + const MeStmt *GetCurrentMeStmt() const { + return currentExpr.meStmt; + } + + MeStmt *GetCurrentMeStmt() { + return currentExpr.meStmt; + } + + void SetCurrentMeStmt(MeStmt &stmt) { + currentExpr.meStmt = &stmt; + } + private: + bool isProcessed; + bool hasRealUse; + bool isInsertedOcc; // the phi operand was inserted by inserted occ + bool isPhiOpndReload; // if insertedocc and redefined the def, set this flag + MePhiOcc *defPhiOcc; // its lhs + union { + MeExpr *meExpr; // the current expression at the end of the block containing this PhiOpnd + MeStmt *meStmt; // which will be inserted during finalize + } currentExpr; +}; + +class MePhiOcc : public MeOccur { + public: + MePhiOcc(BB *bb, MapleAllocator *alloc) + : MeOccur(kOccPhiocc, 0, bb, nullptr), + isDownSafe(!bb->GetAttributes(kBBAttrIsCatch)), + speculativeDownSafe(false), + isCanBeAvail(true), + isLater(true), + isExtraneous(false), + isRemoved(false), + phiOpnds(alloc->Adapter()), + regPhi(nullptr), + varPhi(nullptr) {} + + virtual ~MePhiOcc() = default; + bool IsWillBeAvail() const { + return isCanBeAvail && !isLater; + } + + bool IsDownSafe() const { + return isDownSafe; + } + + void SetIsDownSafe(bool downSafe) { + isDownSafe = downSafe; + } + + bool SpeculativeDownSafe() const { + return speculativeDownSafe; + } + + void SetSpeculativeDownSafe(bool downSafe) { + speculativeDownSafe = downSafe; + } + + bool IsCanBeAvail() const { + return isCanBeAvail; + } + + void SetIsCanBeAvail(bool canBeAvail) { + isCanBeAvail = canBeAvail; + } + + bool IsLater() const { + return isLater; + } + + void SetIsLater(bool later) { + isLater = later; + } + + bool IsExtraneous() const { + return isExtraneous; + } + + void SetIsExtraneous(bool extra) { + isExtraneous = extra; + } + + bool IsRemoved() const { + return isRemoved; + } + + void SetIsRemoved(bool removed) { + isRemoved = removed; + } + + const MapleVector &GetPhiOpnds() const { + return phiOpnds; + } + + MapleVector &GetPhiOpnds() { + return phiOpnds; + } + + MePhiOpndOcc *GetPhiOpnd(size_t idx) { + ASSERT(idx < phiOpnds.size(), "out of range in MePhiOcc::GetPhiOpnd"); + return phiOpnds.at(idx); + } + + const MePhiOpndOcc *GetPhiOpnd(size_t idx) const { + ASSERT(idx < phiOpnds.size(), "out of range in MePhiOcc::GetPhiOpnd"); + return phiOpnds.at(idx); + } + + void AddPhiOpnd(MePhiOpndOcc &opnd) { + phiOpnds.push_back(&opnd); + } + + const MeRegPhiNode *GetRegPhi() const { + return regPhi; + } + + MeRegPhiNode *GetRegPhi() { + return regPhi; + } + + void SetRegPhi(MeRegPhiNode &phi) { + regPhi = φ + } + + const MeVarPhiNode *GetVarPhi() const { + return varPhi; + } + + MeVarPhiNode *GetVarPhi() { + return varPhi; + } + + void SetVarPhi(MeVarPhiNode &phi) { + varPhi = φ + } + bool IsOpndDefByRealOrInserted(); + void Dump(IRMap&); + private: + bool isDownSafe; // default is true + bool speculativeDownSafe; // is downsafe due to speculation + bool isCanBeAvail; + bool isLater; + bool isExtraneous; + bool isRemoved; // during finalize2, marked this phiocc is removed or not + MapleVector phiOpnds; + MeRegPhiNode *regPhi; // the reg phi being inserted. TODO: maybe can delete it later + MeVarPhiNode *varPhi; // the Var phi being inserted. TODO: maybe can delete it later +}; + +// each singly linked list repersents each bucket in workCandHashTable +class PreWorkCand { + public: + PreWorkCand(MapleAllocator *alloc, int32 idx, MeExpr *meExpr, PUIdx pIdx) + : next(nullptr), + index(idx), + realOccs(alloc->Adapter()), + theMeExpr(meExpr), + puIdx(pIdx), + hasLocalOpnd(false), + redo2HandleCritEdges(false), + needLocalRefVar(false) { + ASSERT(pIdx != 0, "PreWorkCand: initial puIdx cannot be 0"); + } + + virtual ~PreWorkCand() = default; + void Dump(IRMap *irMap) { + irMap->GetSSATab().GetModule().GetOut() << "========index: " << index << " has the following occ\n"; + for (MeOccur *occ : realOccs) { + occ->Dump(*irMap); + } + } + + void AddRealOccAsLast(MeRealOcc &occ, PUIdx pIdx) { + realOccs.push_back(&occ); // add as last + ASSERT(pIdx != 0, "puIdx of realocc cannot be 0"); + if (pIdx != puIdx) { + ASSERT(!hasLocalOpnd, "candidate with local opnd cannot have real occurrences in more than one PU"); + puIdx = 0; + } + } + + void AddRealOccSorted(Dominance &dom, MeRealOcc &occ, PUIdx pIdx); + PrimType GetPrimType() const { + PrimType pTyp = theMeExpr->GetPrimType(); + CHECK_FATAL(pTyp != kPtyInvalid, "invalid primtype"); + return pTyp; + } + + static uint32 ComputeWorkCandHashIndex(MeExpr &meExpr); + virtual void DumpCand(IRMap &irMap) { + theMeExpr->Dump(&irMap); + } + + const PreWorkCand *GetNext() const { + return next; + } + + PreWorkCand *GetNext() { + return next; + } + + void SetNext(PreWorkCand &workCand) { + next = &workCand; + } + + int32 GetIndex() const { + return index; + } + + void SetIndex(int idx) { + index = idx; + } + + const MapleVector &GetRealOccs() const { + return realOccs; + } + + MapleVector &GetRealOccs() { + return realOccs; + } + + const MeRealOcc *GetRealOcc(size_t idx) const { + ASSERT(idx < realOccs.size(), "out of range in PreWorkCand::GetRealOccAt"); + return realOccs.at(idx); + } + + MeRealOcc *GetRealOcc(size_t idx) { + ASSERT(idx < realOccs.size(), "out of range in PreWorkCand::GetRealOccAt"); + return realOccs.at(idx); + } + + const MeExpr *GetTheMeExpr() const { + return theMeExpr; + } + + MeExpr *GetTheMeExpr() { + return theMeExpr; + } + + void SetTheMeExpr(MeExpr &expr) { + theMeExpr = &expr; + } + + PUIdx GetPUIdx() const { + return puIdx; + } + + void SetPUIdx(PUIdx idx) { + puIdx = idx; + } + + bool HasLocalOpnd() const { + return hasLocalOpnd; + } + + void SetHasLocalOpnd(bool has) { + hasLocalOpnd = has; + } + + bool Redo2HandleCritEdges() const { + return redo2HandleCritEdges; + } + + void SetRedo2HandleCritEdges(bool redo) { + redo2HandleCritEdges = redo; + } + + bool NeedLocalRefVar() const { + return needLocalRefVar; + } + + void SetNeedLocalRefVar(bool need) { + needLocalRefVar = need; + } + + static std::array &GetWorkcandHashTable() { + return workCandHashTable; + } + + static PreWorkCand *GetWorkcandFromIndex(size_t idx) { + return workCandHashTable[idx]; + } + + static void SetWorkCandAt(size_t idx, PreWorkCand &workCand) { + workCandHashTable[idx] = &workCand; + } + private: + PreWorkCand *next; + int32 index; + MapleVector realOccs; // maintained in order of dt_preorder + MeExpr *theMeExpr; // the expression of this workcand + PUIdx puIdx; // if 0, its occ span multiple PUs; initial value must + // not be 0; if set to 0, will be stuck at 0 + bool hasLocalOpnd : 1; // true if any opnd in the expression is local + // puIdx cannot be 0 if hasLocalOpnd is true + bool redo2HandleCritEdges : 1; // redo to make critical edges affect canbevail + bool needLocalRefVar : 1; // for the candidate, if necessary to introduce + // localrefvar in addition to the temp register to for saving the value + static std::array workCandHashTable; + void InsertRealOccAt(MeRealOcc &occ, MapleVector::iterator it, PUIdx pIdx); +}; + +class PreStmtWorkCand : public PreWorkCand { + public: + PreStmtWorkCand(MapleAllocator *alloc, int32 idx, MeStmt *meStmt, PUIdx pIdx) + : PreWorkCand(alloc, idx, nullptr, pIdx), theMeStmt(meStmt), lhsIsFinal(false) {} + + virtual ~PreStmtWorkCand() = default; + static uint32 ComputeStmtWorkCandHashIndex(MeStmt &stmt); + void DumpCand(IRMap &irMap) { + theMeStmt->Dump(&irMap); + } + + const MeStmt *GetTheMeStmt() const { + return theMeStmt; + } + + MeStmt *GetTheMeStmt() { + return theMeStmt; + } + + void SetTheMeStmt(MeStmt &stmt) { + theMeStmt = &stmt; + } + + bool LHSIsFinal() { + return lhsIsFinal; + } + + void SetLHSIsFinal(bool isFinal) { + lhsIsFinal = isFinal; + } + private: + MeStmt *theMeStmt; // the statement of this workcand + bool lhsIsFinal; // used only if candidate is an assignment +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_OCCUR_H diff --git a/src/maple_me/include/ssa_epre.h b/src/maple_me/include/ssa_epre.h new file mode 100644 index 0000000000000000000000000000000000000000..4cdbff5c638b954b3f27ef7cf157da6745169aba --- /dev/null +++ b/src/maple_me/include/ssa_epre.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_SSAEPRE_H +#define MAPLE_ME_INCLUDE_SSAEPRE_H +#include "ssa_pre.h" +namespace maple { +class SSAEPre : public SSAPre { + public: + SSAEPre(IRMap &map, Dominance &dom, MemPool &memPool, MemPool &mp2, PreKind kind, + uint32 limit, bool includeRef, bool lhsIvar) + : SSAPre(map, dom, memPool, mp2, kind, limit), epreIncludeRef(includeRef), enableLHSIvar(lhsIvar) {} + + virtual ~SSAEPre() = default; + + private: + bool epreIncludeRef; + bool enableLHSIvar; + void GenerateSaveLHSRealocc(MeRealOcc *realOcc, MeExpr *regOrVar); + void GenerateSaveRealOcc(MeRealOcc *realOcc); + void GenerateReloadRealOcc(MeRealOcc *realOcc); + MeExpr *PhiOpndFromRes(MeRealOcc *realZ, size_t j); + void ComputeVarAndDfPhis(); + void BuildWorkListExpr(MeStmt *meStmt, int32 seqStmt, MeExpr*, bool isReBuild, MeExpr *tempVar, bool isRootExpr); + void BuildWorkListIvarLHSOcc(MeStmt *meStmt, int32 seqStmt, bool isReBuild, MeExpr *tempVar); + void CollectVarForMeExpr(MeExpr *meExpr, std::vector &varVec); + void CollectVarForCand(MeRealOcc *realOcc, std::vector &varVec); + bool LeafIsVolatile(MeExpr *x) { + VarMeExpr *v = safe_cast(x); + return v != nullptr && v->IsVolatile(irMap->GetSSATab()); + } + + virtual bool CfgHasDoWhile() { + return false; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_SSAEPRE_H diff --git a/src/maple_me/include/ssa_pre.h b/src/maple_me/include/ssa_pre.h new file mode 100644 index 0000000000000000000000000000000000000000..49615b49746f8dc348fc1ed6ead6ae434b746ed5 --- /dev/null +++ b/src/maple_me/include/ssa_pre.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_SSAPRE_H +#define MAPLE_ME_INCLUDE_SSAPRE_H +#include "irmap.h" +#include "occur.h" +#include "securec.h" +namespace maple { +enum PreKind { + kExprPre, + kStmtPre, + kLoadPre, + kAddrPre +}; + +class SSAPre { + public: + SSAPre(IRMap &hMap, Dominance &currDom, MemPool &memPool, MemPool &mp2, PreKind kind, uint32 limit) + : irMap(&hMap), + ssaTab(&hMap.GetSSATab()), + mirModule(&hMap.GetSSATab().GetModule()), + dom(&currDom), + ssaPreMemPool(&memPool), + ssaPreAllocator(&memPool), + perCandMemPool(&mp2), + perCandAllocator(&mp2), + workList(ssaPreAllocator.Adapter()), + preKind(kind), + allOccs(ssaPreAllocator.Adapter()), + phiOccs(ssaPreAllocator.Adapter()), + exitOccs(ssaPreAllocator.Adapter()), + preLimit(limit), + dfPhiDfns(std::less(), ssaPreAllocator.Adapter()), + varPhiDfns(std::less(), ssaPreAllocator.Adapter()), + rename2Set(std::less(), ssaPreAllocator.Adapter()), + temp2LocalRefVarMap(ssaPreAllocator.Adapter()) { + PreWorkCand::GetWorkcandHashTable().fill(nullptr); + } + + void ApplySSAPRE(); + bool DefVarDominateOcc(MeExpr *meExpr, MeOccur *meOcc); + virtual void CollectVarForMeExpr(MeExpr *meExpr, std::vector &varVec) = 0; + virtual void CollectVarForCand(MeRealOcc *realOcc, std::vector &varVec) = 0; + const MapleVector &GetRealOccList() const { + return workCand->GetRealOccs(); + } + + virtual MeExpr *CopyMeExpr(MeExpr &expr); + virtual MeStmt *CopyMeStmt(MeStmt &meStmt); + virtual IassignMeStmt *CopyIassignMeStmt(const IassignMeStmt &iaStmt); + void IncTreeid() { + curTreeId += 2; + } + + virtual void DumpWorkList(); + virtual void DumpWorkListWrap(); + GStrIdx NewTempStrIdx(); + virtual BB *GetBB(BBId id) = 0; + virtual PUIdx GetPUIdx() const = 0; + virtual void SetCurFunction(PUIdx) {} + + virtual void GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) = 0; + void SetSpillAtCatch(bool status) { + spillAtCatch = status; + } + + bool GetSpillAtCatch() const { + return spillAtCatch; + } + + PreWorkCand* GetWorkCand() const { + return workCand; + } + + void SetAddedNewLocalRefVars(bool status) { + addedNewLocalRefVars = status; + } + + bool GetAddedNewLocalRefVars() const { + return addedNewLocalRefVars; + } + + void SetSSAPreDebug(bool status) { + enableDebug = status; + } + + bool GetSSAPreDebug() const { + return enableDebug; + } + + void SetPlacementRC(bool status) { + placementRCEnabled = status; + } + + bool GetPlacementRCOn() const { + return placementRCEnabled; + } + + void SetRcLoweringOn(bool status) { + rcLoweringEnabled = status; + } + + bool GetRcLoweringOn() const { + return rcLoweringEnabled; + } + + void SetRegReadAtReturn(bool status) { + regReadAtReturn = status; + } + + bool GetRegReadAtReturn() const { + return regReadAtReturn; + } + + protected: + IRMap *irMap; + SSATab *ssaTab; + MIRModule *mirModule; + Dominance *dom; + MemPool *ssaPreMemPool; + MapleAllocator ssaPreAllocator; + MemPool *perCandMemPool; + MapleAllocator perCandAllocator; + MapleVector workList; + PreWorkCand *workCand = nullptr; // the current PreWorkCand + PreKind preKind; + + uint32 curTreeId = 0; // based on number of rooted trees processed in collecting + // PRE work candidates; incremented by 2 for each tree; + // purpose is to avoid processing a node the third time + // inside a tree (which is a DAG) + // the following 3 lists are all maintained in order of dt_preorder + MapleVector allOccs; // cleared at start of each workcand + MapleVector phiOccs; // cleared at start of each workcand + MapleVector exitOccs; // this is shared by all workcands + uint32 preLimit; // set by command-line option to limit the number of candidates optimized (for debugging purpose) + // step 1 phi insertion data structures + // following are set of BBs in terms of their dfn's; index into + // dominance->pdt_preorder to get their bbid's + MapleSet dfPhiDfns; // phis inserted due to dominance frontiers + MapleSet varPhiDfns; // phis inserted due to the var operands + // step 2 renaming data structures + uint32 classCount = 0; // count class created during renaming + MapleSet rename2Set; // set created by rename1 for use rename2; value + // is index into workCand->realOccs + // step 6 codemotion data structures + MeExpr *curTemp = nullptr; // the created temp for current workCand + VarMeExpr *curLocalRefVar = nullptr; // the created localrefvar for ref-type iread + MapleMap temp2LocalRefVarMap; + int32 reBuiltOccIndex = -1; // stores the size of worklist every time when try to add new worklist, update before each + // code motion + uint32 strIdxCount = 0; // ssapre will create a lot of temp variables if using var to store redundances, start from 0 + // step 6 codemotion methods + MeExpr *CreateNewCurTemp(MeExpr *meExpr); + VarMeExpr *CreateNewCurLocalRefVar(); + virtual void GenerateSaveRealOcc(MeRealOcc *realOcc) = 0; + virtual void GenerateReloadRealOcc(MeRealOcc *realOcc) = 0; + void GenerateSaveInsertedOcc(MeInsertedOcc *insertedOcc); + void GenerateSavePhiOcc(MePhiOcc *phiOcc); + void UpdateInsertedPhiOccOpnd(); + virtual void CodeMotion(); + // step 5 Finalize methods + virtual void Finalize1(); + void SetSave(MeOccur *defx); + void SetReplacement(MePhiOcc *occg, MeOccur *repDef); + virtual void Finalize2(); + // step 4 willbevail methods + void ComputeCanBeAvail(); + void ResetCanBeAvail(MePhiOcc *occg); + void ComputeLater(); + void ResetLater(MePhiOcc *occg); + // step 3 downsafety methods + void ResetDS(MePhiOpndOcc *phiOpnd); + void ComputeDS(); + // step 2 renaming methods + virtual bool AllVarsSameVersion(MeRealOcc *realOcc1, MeRealOcc *realOcc2) { + return realOcc1->GetMeExpr() == realOcc2->GetMeExpr(); + } + + void Rename1(); + MeExpr *GetReplaceMeExpr(MeExpr *opnd, const BB *ePhiBB, size_t j); + virtual MeExpr *PhiOpndFromRes(MeRealOcc *realOcc, size_t i) = 0; + virtual void Rename2(); + // step 1 phi insertion methods + void SetVarPhis(MeExpr *meExpr); + virtual void ComputeVarAndDfPhis() = 0; + virtual void CreateSortedOccs(); + // phi insertion methods end + virtual void BuildWorkList() = 0; + virtual void BuildEntryLHSOcc4Formals() {} + + virtual void BuildWorkListLHSOcc(MeStmt*, int32) {} + + virtual void BuildWorkListIvarLHSOcc(MeStmt*, int32, bool, MeExpr*) {} + + virtual void BuildWorkListExpr(MeStmt *meStmt, int32 seqStmt, MeExpr *meExpr, bool isRebuilt, MeExpr *tempVar, + bool isRootExpr) = 0; + virtual void BuildWorkListStmt(MeStmt* meStmt, uint32 seqStmt, bool isRebuilt, MeExpr *tempVar = nullptr); + virtual void BuildWorkListBB(BB *bb); + virtual void ConstructUseOccurMap() {} + + void CreateMembarOcc(MeStmt &meStmt, int seqStmt); + virtual void CreateMembarOccAtCatch(BB &bb); + void CreateExitOcc(BB *bb) { + MeOccur *exitOcc = ssaPreMemPool->New(kOccExit, 0, bb, nullptr); + exitOccs.push_back(exitOcc); + } + + bool CheckIfAnyLocalOpnd(MeExpr *x); + MeRealOcc *CreateRealOcc(MeStmt &meStmt, int32 seqStmt, MeExpr &meExpr, bool isRebuilt, bool isLHS = false); + virtual bool ScreenPhiBB(BBId bbId) const = 0; + virtual bool EpreLocalRefVar() { + return false; + } + + virtual void EnterCandsForSSAUpdate(OStIdx, BB*) {} + + virtual bool IsLoopHeadBB(BBId) const { + return false; + } + + private: + bool enableDebug = false; + bool rcLoweringEnabled = false; + bool regReadAtReturn = false; + bool spillAtCatch = false; + bool placementRCEnabled = false; + bool addedNewLocalRefVars = false; + virtual void DoSSAFRE() {}; +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_SSAPRE_H diff --git a/src/maple_me/src/dse.cpp b/src/maple_me/src/dse.cpp index d8e75afa623f380be93486d53ba11f47387d4399..5a0fbfd54dde917941925d7521f9baac4c84e882 100644 --- a/src/maple_me/src/dse.cpp +++ b/src/maple_me/src/dse.cpp @@ -325,7 +325,7 @@ void DSE::MarkStmtRequired(const StmtNode &stmt, const BB &bb) { // save only one line comment StmtNode *prev = stmt.GetPrev(); if (prev != nullptr && prev->GetOpCode() == OP_comment) { - SetStmtRequired(prev); + SetStmtRequired(*prev); } MarkStmtUseLive(stmt); @@ -339,15 +339,9 @@ void DSE::MarkSpecialStmtRequired() { if (bb == nullptr) { continue; } - auto &stmtNodes = bb->GetStmtNodes(); - for (auto itStmt = stmtNodes.rbegin(); itStmt != stmtNodes.rend(); ++itStmt) { - StmtNode *pStmt = to_ptr(itStmt); - if (IsStmtRequired(pStmt)) { - continue; - } - - if (StmtMustRequired(*itStmt, ToRef(bb))) { - MarkStmtRequired(*itStmt, ToRef(bb)); + for (auto itStmt = bb->GetStmtNodes().rbegin(); itStmt != bb->GetStmtNodes().rend(); ++itStmt) { + if (StmtMustRequired(*itStmt, *bb)) { + MarkStmtRequired(*itStmt, *bb); continue; } } diff --git a/src/maple_me/src/irmap.cpp b/src/maple_me/src/irmap.cpp index eb2e59e627285b1d1c861453a04e3bf0a2270f25..7d4d4489020624e73d8bc7514688e8d56af5704f 100644 --- a/src/maple_me/src/irmap.cpp +++ b/src/maple_me/src/irmap.cpp @@ -361,6 +361,14 @@ IvarMeExpr *IRMap::BuildLHSIvar(MeExpr &baseAddr, IassignMeStmt &iassignMeStmt, return meDef; } +IvarMeExpr *IRMap::BuildIvarFromOpMeExpr(OpMeExpr &opMeExpr) { + IvarMeExpr *ivar = New(exprID++); + ivar->SetFieldID(opMeExpr.GetFieldID()); + ivar->SetTyIdx(opMeExpr.GetTyIdx()); + ivar->SetBase(opMeExpr.GetOpnd(0)); + return ivar; +} + IvarMeExpr *IRMap::BuildLHSIvarFromIassMeStmt(IassignMeStmt &iassignMeStmt) { return BuildLHSIvar(*iassignMeStmt.GetLHSVal()->GetBase(), iassignMeStmt, iassignMeStmt.GetLHSVal()->GetFieldID()); } @@ -816,6 +824,11 @@ DassignMeStmt *IRMap::CreateDassignMeStmt(MeExpr &lhs, MeExpr &rhs, BB &currBB) return meStmt; } +IassignMeStmt *IRMap::CreateIassignMeStmt(TyIdx tyIdx, IvarMeExpr &lhs, MeExpr &rhs, + const MapleMap &clist) { + return NewInPool(tyIdx, &lhs, &rhs, &clist); +} + RegassignMeStmt *IRMap::CreateRegassignMeStmt(MeExpr &lhs, MeExpr &rhs, BB &currBB) { auto *meStmt = New(); ASSERT(lhs.GetMeOp() == kMeOpReg, "Create regassign without lhs == regread"); diff --git a/src/maple_me/src/me_bb_layout.cpp b/src/maple_me/src/me_bb_layout.cpp index e53e9994701fa4793d4939bc8c4957db27c52198..c0aa0c7cf7164af28d2a52031b7444931fc73a51 100644 --- a/src/maple_me/src/me_bb_layout.cpp +++ b/src/maple_me/src/me_bb_layout.cpp @@ -385,7 +385,7 @@ void BBLayout::RemoveUnreachable(BB &bb) { } MapleVector succBBs = bb.GetSucc(); for (BB *succ : succBBs) { - MapleVector preds = succ->GetPred(); + MapleVector &preds = succ->GetPred(); bb.RemoveBBFromVector(preds); if (preds.empty()) { RemoveUnreachable(*succ); diff --git a/src/maple_me/src/me_cond_based_opt.cpp b/src/maple_me/src/me_cond_based_opt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..69342e23bce8c651ef485bd9a52aff8e7ae7368e --- /dev/null +++ b/src/maple_me/src/me_cond_based_opt.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_cond_based_rc.h" +#include "me_cond_based_npc.h" +#include "me_const.h" + +// We do two types of condition based optimization here: +// 1. condition based null pointer check(NPC) elimination +// 2. condition based RC elimination +// both use post dominance data to see if the symbol they are dealing with is +// zero or not. To be specific, retrieve every stmt of all the bbs', if the stmt +// is an assertnonnull/MCC_DecRef_NaiveRCFast, then retrieve the enclosing bb's +// every post dominance frontiers in a backward order, if a frontier is found of +// conditional branch, and the `expr` it compared is the same as that of +// the assertnonnull/MCC_DecRef_NaiveRCFast, then the value of the symbol can be +// known. If it's not zero, condbasednpc could remove the assertnonnull +// statement; if it is a zero, then MCC_DecRef_NaiveRCFast could be removed. +// +// There are other conditions that the assertnonnull can be removed, e.g. if +// the statement next to assertnonnull is an iread and the base is the +// symbol assertnonnull is dealing with, then the assertnonnull can be removed, +// because the exception will be thrown at this same place by iread, as the +// symbol's value is zero. +namespace maple { +// check if varmeexpr is under the condition varmeexpr == 0 when expectedEq0 is true, +// or varmeexpr != 0 if expectedEq0 is false +bool MeCondBased::NullValueFromOneTestCond(VarMeExpr &varMeExpr, BB &cdBB, BB &bb, bool expectedEq0) { + auto &meStmts = cdBB.GetMeStmts(); + if (meStmts.empty()) { + return false; + } + if (!meStmts.back().IsCondBr()) { + return false; + } + auto &condBrMeStmt = static_cast(meStmts.back()); + bool isTrueBr = condBrMeStmt.GetOp() == OP_brtrue; + MeExpr *testMeExpr = condBrMeStmt.GetOpnd(); + if (testMeExpr->GetOp() != OP_eq && testMeExpr->GetOp() != OP_ne) { + return false; + } + bool isEq = testMeExpr->GetOp() == OP_eq; + auto *cmpMeExpr = static_cast(testMeExpr); + if (cmpMeExpr->GetOpnd(0)->GetMeOp() != kMeOpVar || cmpMeExpr->GetOpnd(1)->GetOp() != OP_constval) { + return false; + } + auto *constMeExpr = static_cast(cmpMeExpr->GetOpnd(1)); + if (!constMeExpr->IsZero()) { + return false; + } + if (!cmpMeExpr->GetOpnd(0)->IsSameVariableValue(varMeExpr)) { + return false; + } + BB *sucDomBB = nullptr; + for (size_t i = 0; i < cdBB.GetSucc().size(); ++i) { + BB *sucBB = cdBB.GetSucc(i); + if (dominance->Dominate(*sucBB, bb)) { + sucDomBB = sucBB; + break; + } + } + if (sucDomBB == nullptr) { + return false; + } + bool isJumptoBB = sucDomBB->GetBBLabel() == condBrMeStmt.GetOffset(); + if (expectedEq0) { + isEq = !isEq; + } + return isJumptoBB ? ((isTrueBr && !isEq) || (!isTrueBr && isEq)) : ((isTrueBr && isEq) || (!isTrueBr && !isEq)); +} + +bool MeCondBased::NullValueFromTestCond(VarMeExpr &varMeExpr, BB &bb, bool expectedEq0) { + MapleSet *pdomFrt = &dominance->GetPdomFrontierItem(bb.GetBBId()); + size_t bbSize = dominance->GetBBVecSize(); + std::vector visitedMap(bbSize, false); + bool provenNull = false; + while (pdomFrt->size() == 1) { + BB &cdBB = *func->GetAllBBs().at(*(pdomFrt->begin())); + if (visitedMap[cdBB.GetBBId()]) { + break; + } + visitedMap[cdBB.GetBBId()] = true; + if (NullValueFromOneTestCond(varMeExpr, cdBB, bb, expectedEq0)) { + provenNull = true; + break; + } + pdomFrt = &dominance->GetPdomFrontierItem(cdBB.GetBBId()); + } + return provenNull; +} + +bool MeCondBased::IsIreadWithTheBase(VarMeExpr &var, MeExpr &meExpr) { + if (meExpr.GetOp() == OP_iread) { + auto &ivarMeExpr = static_cast(meExpr); + if (ivarMeExpr.GetBase()->GetExprID() == var.GetExprID()) { + return true; + } + } + for (uint8 i = 0; i < meExpr.GetNumOpnds(); ++i) { + if (IsIreadWithTheBase(var, *meExpr.GetOpnd(i))) { + return true; + } + } + return false; +} + +bool MeCondBased::StmtHasDereferencedBase(MeStmt &stmt, VarMeExpr &var) { + if (stmt.GetOp() == OP_iassign) { + auto &iassStmt = static_cast(stmt); + if (iassStmt.GetLHSVal()->GetBase()->GetExprID() == var.GetExprID()) { + return true; + } + } + if (stmt.GetOp() == OP_syncenter || stmt.GetOp() == OP_syncexit) { + auto &syncMeStmt = static_cast(stmt); + MapleVector &opnds = syncMeStmt.GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); ++it) { + if ((*it)->GetExprID() == var.GetExprID()) { + return true; + } + } + } + for (size_t i = 0; i < stmt.NumMeStmtOpnds(); ++i) { + MeExpr *meExpr = stmt.GetOpnd(i); + if (IsIreadWithTheBase(var, *meExpr)) { + return true; + } + } + return false; +} + +bool MeCondBased::PointerWasDereferencedBefore(VarMeExpr &var, UnaryMeStmt &assertMeStmt, BB *bb) { + // If var is defined in the function, let BBx be the BB that defines var. + // If var is not defined, then let BBx be the function entry BB. + // Let BBy be the current BB that contains the assertnonnull. + // Search backward along the path in the dominator tree from BBy to BBx. + // If it sees an iread or iassign whose base is var, then the assertnonnull can be deleted. + MeStmt *defMeStmt = nullptr; + BB *bbx = var.GetDefByBBMeStmt(*dominance, defMeStmt); + if (bbx == nullptr) { + return false; + } + CHECK_FATAL(dominance->Dominate(*bbx, *bb), "bbx should dominate bb at this point"); + for (MeStmt *stmt = assertMeStmt.GetPrev(); stmt != nullptr; stmt = stmt->GetPrev()) { + if (StmtHasDereferencedBase(*stmt, var)) { + return true; + } + } + if (bbx == bb) { + return false; + } + BB *itBB = dominance->GetDom(bb->GetBBId()); + while (itBB != bbx) { + // check if there is an iread or iassign in itbb whose base is var + auto &meStmts = itBB->GetMeStmts(); + for (auto itStmt = meStmts.rbegin(); itStmt != meStmts.rend(); ++itStmt) { + if (StmtHasDereferencedBase(*to_ptr(itStmt), var)) { + return true; + } + } + itBB = dominance->GetDom(itBB->GetBBId()); + } + auto &meStmts = bbx->GetMeStmts(); + for (auto itStmt = meStmts.rbegin(); to_ptr(itStmt) != defMeStmt; ++itStmt) { + if (StmtHasDereferencedBase(*to_ptr(itStmt), var)) { + return true; + } + } + return false; +} + +bool MeCondBased::PointerWasDereferencedRightAfter(VarMeExpr &var, UnaryMeStmt &assertMeStmt) { + // assertnonnull(var) + // t = iread(var, 0) + // we can safely delete assertnonnull(var) + // if we got + // assertnonnull(var) + // t2 <- + // t = iread (var) + // we can't remove assertnonnull(var) safely, because if var is null, then the position of throwing exception is + // not the same. + MeStmt *nextMeStmt = assertMeStmt.GetNextMeStmt(); + return nextMeStmt && StmtHasDereferencedBase(*nextMeStmt, var); +} + +bool MeCondBased::IsNotNullValue(VarMeExpr &varMeExpr, UnaryMeStmt &assertMeStmt, BB *bb) { + const OriginalSt *varOst = func->GetMeSSATab()->GetSymbolOriginalStFromID(varMeExpr.GetOStIdx()); + if (varOst->IsFormal() && varOst->GetMIRSymbol()->GetName() == kStrThisPointer) { + return true; + } + if (varMeExpr.GetDefBy() == kDefByStmt && varMeExpr.GetDefStmt()->GetOp() == OP_dassign) { + MeExpr *rhs = static_cast(varMeExpr.GetDefStmt())->GetRHS(); + if (rhs->GetOp() == OP_gcmalloc || rhs->GetOp() == OP_gcmallocjarray) { + return true; + } + if (rhs->GetMeOp() == kMeOpVar) { + auto *rhsVar = static_cast(rhs); + const OriginalSt *ost = func->GetMeSSATab()->GetSymbolOriginalStFromID(rhsVar->GetOStIdx()); + if (ost->IsFormal() && ost->GetMIRSymbol()->GetName() == kStrThisPointer) { + return true; + } + } + } + if (PointerWasDereferencedBefore(varMeExpr, assertMeStmt, bb)) { + return true; + } + if (PointerWasDereferencedRightAfter(varMeExpr, assertMeStmt)) { + return true; + } + return false; +} + +void CondBasedNPC::DoCondBasedNPC() { + auto eIt = GetFunc()->valid_end(); + for (auto bIt = GetFunc()->valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + for (auto &stmt : bb->GetMeStmts()) { + if (stmt.GetOp() != OP_assertnonnull) { + continue; + } + auto &assertMeStmt = static_cast(stmt); + if (assertMeStmt.GetOpnd()->GetMeOp() != kMeOpVar) { + continue; + } + auto *varMeExpr = static_cast(assertMeStmt.GetOpnd()); + if (NullValueFromTestCond(*varMeExpr, *bb, false) || IsNotNullValue(*varMeExpr, assertMeStmt, bb)) { + bb->RemoveMeStmt(&stmt); + } + } + } +} + +AnalysisResult *MeDoCondBasedRC::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom != nullptr, "dominance phase has problem"); + CondBasedRC condBasedRC(func, dom); + auto eIt = func->valid_end(); + for (auto bIt = func->valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + for (auto &stmt : bb->GetMeStmts()) { + if (stmt.GetOp() != OP_decref) { + continue; + } + auto &decref = static_cast(stmt); + if (decref.GetOpnd()->GetMeOp() != kMeOpVar) { + continue; + } + auto *varMeExpr = static_cast(decref.GetOpnd()); + const OriginalSt *ost = func->GetMeSSATab()->GetSymbolOriginalStFromID(varMeExpr->GetOStIdx()); + if (!ost->IsLocal() && ost->IsVolatile()) { + // global volatile cannot be optimized + continue; + } + MeStmt *refAssign = stmt.GetNext(); + if (condBasedRC.NullValueFromTestCond(*varMeExpr, *bb, true)) { + bb->RemoveMeStmt(&stmt); // delete the decref + if (refAssign != nullptr) { + refAssign->DisableNeedDecref(); + } else { + break; + } + stmt = *refAssign; // next iteration will process the stmt after refassign + } + } + } + return nullptr; +} + +AnalysisResult *MeDoCondBasedNPC::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom, "dominance phase has problem"); + CondBasedNPC condBasedNPC(func, dom); + condBasedNPC.DoCondBasedNPC(); + return nullptr; +} +} // namespace maple diff --git a/src/maple_me/src/me_lower_globals.cpp b/src/maple_me/src/me_lower_globals.cpp new file mode 100644 index 0000000000000000000000000000000000000000..469edf548f424f5b4a69bdeaddc63315011dcdaa --- /dev/null +++ b/src/maple_me/src/me_lower_globals.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_lower_globals.h" + +// the dassign/dread of global or static variables are lowered into +// iassign/iread to expose the addrof. The inserted addrof is always of fieldID +// 0 to reduce the number of registers needed for storing addresses after the +// addrof's are allocated to pregs. The fieldID's thus reside in the iassign's +// and iread's. +// +// By the same token, an addrof with non-zero field id is also lowered into +// iaddrof with same field id whose operand is addrof with 0 field id. +// +// call and callassigned are lowered into icall/icallassigned and addroffunc. +// The addroffunc is inserted as the extra first operand and the +// call/callassinged is renamed to icall/icallassigned. +namespace maple { +void MeLowerGlobals::LowerGlobalDreads(MeStmt &stmt, MeExpr *x) { + switch (x->GetMeOp()) { + case kMeOpOp: { + auto *meOpExpr = static_cast(x); + for (size_t i = 0; i < kOperandNumTernary; ++i) { + MeExpr *opnd = meOpExpr->GetOpnd(i); + if (opnd != nullptr) { + LowerGlobalDreads(stmt, opnd); + } + } + break; + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(x); + MapleVector &opnds = naryMeExpr->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); ++it) { + LowerGlobalDreads(stmt, *it); + } + break; + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(x); + LowerGlobalDreads(stmt, ivarMeExpr->GetBase()); + break; + } + case kMeOpVar: { + auto *varExpr = static_cast(x); + OriginalSt *ost = ssaTable->GetSymbolOriginalStFromID(varExpr->GetOStIdx()); + if (ost->IsLocal()) { + break; + } + // lower to ivar to expose addrof + OriginalSt *baseOst = ost; + if (ost->GetFieldID() != 0) { + PUIdx puIdx = func->GetMirFunc()->GetPuidx(); + baseOst = ssaTable->FindOrCreateSymbolOriginalSt(*ost->GetMIRSymbol(), puIdx, 0); + } + auto *addrofExpr = static_cast(irMap->CreateAddrofMeExpr(*varExpr)); + MIRPtrType ptrType(baseOst->GetTyIdx(), PTY_ptr); + TyIdx addrTyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(&ptrType); + auto *ivarExpr = static_cast(irMap->CreateIvarMeExpr(*varExpr, addrTyIdx, *addrofExpr)); + irMap->ReplaceMeExprStmt(stmt, *varExpr, *ivarExpr); + break; + } + case kMeOpAddrof: { + auto *addrofExpr = static_cast(x); + if (addrofExpr->GetFieldID() == 0) { + break; + } + OriginalSt *ost = ssaTable->GetSymbolOriginalStFromID(addrofExpr->GetOstIdx()); + if (ost->IsLocal()) { + break; + } + // lower to iaddrof to expose addrof with 0 fieldID + PUIdx puIdx = func->GetMirFunc()->GetPuidx(); + OriginalSt *baseOst = ssaTable->FindOrCreateSymbolOriginalSt(*ost->GetMIRSymbol(), + func->GetMirFunc()->GetPuidx(), 0); + MeExpr *newAddrofExpr = irMap->CreateAddrofMeExprFromSymbol(*ost->GetMIRSymbol(), puIdx); + MIRPtrType ptrType(baseOst->GetTyIdx(), PTY_ptr); + TyIdx addrTyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(&ptrType); + MeExpr *iaddrofExpr = irMap->CreateIaddrofMeExpr(*addrofExpr, addrTyIdx, *newAddrofExpr); + irMap->ReplaceMeExprStmt(stmt, *addrofExpr, *iaddrofExpr); + break; + } + default: + break; + } +} + +void MeLowerGlobals::Run() { + auto eIt = func->valid_end(); + for (auto bIt = func->valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + for (auto &stmt : bb->GetMeStmts()) { + for (size_t i = 0; i < stmt.NumMeStmtOpnds(); ++i) { + LowerGlobalDreads(stmt, stmt.GetOpnd(i)); + } + if (stmt.GetOp() == OP_dassign) { + auto &dass = static_cast(stmt); + OriginalSt *ost = ssaTable->GetSymbolOriginalStFromID(dass.GetVarLHS()->GetOStIdx()); + if (ost->IsLocal()) { + continue; + } + // lower to iassign to expose addrof + OriginalSt *baseOst = ost; + if (ost->GetFieldID() != 0) { + baseOst = ssaTable->FindOrCreateSymbolOriginalSt(*ost->GetMIRSymbol(), + func->GetMirFunc()->GetPuidx(), 0); + } + MeExpr *addrof = irMap->CreateAddrofMeExpr(baseOst->GetIndex()); + MIRPtrType ptrType(baseOst->GetTyIdx(), PTY_ptr); + TyIdx addrTyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(&ptrType); + auto *lhsIvar = static_cast(irMap->CreateIvarMeExpr(*dass.GetLHS(), addrTyIdx, *addrof)); + IassignMeStmt *iass = irMap->NewInPool(addrTyIdx, lhsIvar, dass.GetRHS(), &*dass.GetChiList()); + iass->SetBB(bb); + iass->SetSrcPos(dass.GetSrcPosition()); + iass->SetIsLive(true); + bb->ReplaceMeStmt(&stmt, iass); + } else if (stmt.GetOp() == OP_call || stmt.GetOp() == OP_callassigned) { + // don't do this if current function is in libcore-all + if (!MeOption::optDirectCall) { + continue; + } + if (GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName( + NameMangler::GetInternalNameLiteral(NameMangler::kJavaLangObjectStr))) != nullptr) { + continue; + } + auto &callStmt = static_cast(stmt); + MIRFunction &callee = callStmt.GetTargetFunction(); + if (!callee.IsJava() && callee.GetBaseClassName().empty()) { + continue; // not a java callee + } + MeExpr *addroffuncExpr = irMap->CreateAddroffuncMeExpr(callee.GetPuidx()); + auto insertpos = callStmt.GetOpnds().begin(); + callStmt.GetOpnds().insert(insertpos, addroffuncExpr); + IcallMeStmt *icallStmt = irMap->NewInPool(stmt.GetOp() == OP_call ? OP_icall : OP_icallassigned); + icallStmt->SetIsLive(callStmt.GetIsLive()); + icallStmt->SetSrcPos(callStmt.GetSrcPosition()); + for (MeExpr *o : callStmt.GetOpnds()) { + icallStmt->GetOpnds().push_back(o); + } + icallStmt->GetMuList()->insert(callStmt.GetMuList()->begin(), callStmt.GetMuList()->end()); + icallStmt->GetChiList()->insert(callStmt.GetChiList()->begin(), callStmt.GetChiList()->end()); + icallStmt->SetRetTyIdx(callee.GetReturnTyIdx()); + if (stmt.GetOp() != OP_call) { + if (callStmt.NeedDecref()) { + icallStmt->EnableNeedDecref(); + } else { + icallStmt->DisableNeedDecref(); + } + if (callStmt.NeedIncref()) { + icallStmt->EnableNeedIncref(); + } else { + icallStmt->DisableNeedIncref(); + } + icallStmt->GetMustDefList()->assign(callStmt.GetMustDefList()->begin(), callStmt.GetMustDefList()->end()); + } + bb->ReplaceMeStmt(&stmt, icallStmt); + } + } + } +} +} // namespace maple diff --git a/src/maple_me/src/me_option.cpp b/src/maple_me/src/me_option.cpp index ceee728b0a1d6f220c7f4b23750eaf3f50221987..6e121ff963269f3a2d2882ec9e1cc45e5037e407 100644 --- a/src/maple_me/src/me_option.cpp +++ b/src/maple_me/src/me_option.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. * * OpenArkCompiler is licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. @@ -43,6 +43,25 @@ bool MeOption::propIloadRef = false; bool MeOption::propGlobalRef = false; bool MeOption::propFinaliLoadRef = true; bool MeOption::propIloadRefNonParm = false; +uint32 MeOption::delRcPULimit = UINT32_MAX; +uint32 MeOption::stmtprePULimit = UINT32_MAX; +uint32 MeOption::epreLimit = UINT32_MAX; +uint32 MeOption::eprePULimit = UINT32_MAX; +uint32 MeOption::lpreLimit = UINT32_MAX; +uint32 MeOption::lprePULimit = UINT32_MAX; +bool MeOption::noDelegateRC = false; +bool MeOption::noCondBasedRC = false; +bool MeOption::clinitPre = true; +bool MeOption::dassignPre = true; +bool MeOption::nullCheckPre = false; +bool MeOption::assign2FinalPre = false; +bool MeOption::epreIncludeRef = false; +bool MeOption::epreLocalRefVar = true; +bool MeOption::epreLHSIvar = true; +bool MeOption::lpreSpeculate = false; +bool MeOption::spillAtCatch = false; +bool MeOption::rcLowering = true; +bool MeOption::optDirectCall = false; void MeOption::SplitPhases(const std::string &str, std::unordered_set &set) const { std::string s{ str }; diff --git a/src/maple_me/src/me_phase_manager.cpp b/src/maple_me/src/me_phase_manager.cpp index 8250159e9f8a1e52b6d37786725a616cb06c4af0..53437b15485ecba9a4a5cbcdb11f65e310f906aa 100644 --- a/src/maple_me/src/me_phase_manager.cpp +++ b/src/maple_me/src/me_phase_manager.cpp @@ -20,6 +20,12 @@ #include "me_phase.h" #include "me_cfg.h" #include "me_alias_class.h" +#include "me_ssa_lpre.h" +#include "me_ssa_epre.h" +#include "me_stmt_pre.h" +#include "me_store_pre.h" +#include "me_cond_based_rc.h" +#include "me_cond_based_npc.h" #include "me_ssa.h" #include "me_irmap.h" #include "me_bb_layout.h" diff --git a/src/maple_me/src/me_rc_lowering.cpp b/src/maple_me/src/me_rc_lowering.cpp index d74e86858f8333f650aca0f1a3ea6f681a7c6f09..d5467bab225bf3c72b68b75159bfd6aebc41eab1 100644 --- a/src/maple_me/src/me_rc_lowering.cpp +++ b/src/maple_me/src/me_rc_lowering.cpp @@ -14,6 +14,7 @@ */ #include "me_rc_lowering.h" #include +#include "me_option.h" // RCLowering phase generate RC intrinsic for reference assignment // based on previous analyze results. RC intrinsic will later be lowered @@ -38,12 +39,19 @@ void RCLowering::Prepare() { if (enabledDebug) { LogInfo::MapleLogger() << "Handling function " << mirFunction->GetName() << '\n'; } + func.SetHints(func.GetHints() | kRcLowered); + isAnalyzed = (func.GetHints() & kAnalyzeRCed) != 0; } void RCLowering::PreRCLower() { // preparation steps before going through basicblocks MarkLocalRefVar(); + // if analyze rc phase has run, skip this + if (isAnalyzed) { + return; + } + MarkAllRefOpnds(); CreateCleanupIntrinsics(); } @@ -144,8 +152,10 @@ IntrinsiccallMeStmt *RCLowering::GetVarRHSHandleStmt(const MeStmt &stmt) { // load global into temp and update rhs to temp std::vector opnds; bool isVolatile = var->IsVolatile(ssaTab); - MIRIntrinsicID rcCallID = isVolatile ? PrepareVolatileCall(stmt, INTRN_MCCLoadRefSVol) : INTRN_MCCLoadRefS; + MIRIntrinsicID rcCallID = INTRN_UNDEFINED; + rcCallID = isVolatile ? PrepareVolatileCall(stmt, INTRN_MCCLoadRefSVol) : INTRN_MCCLoadRefS; opnds.push_back(irMap.CreateAddrofMeExpr(*var)); + // rhs is not special, skip if (rcCallID == INTRN_UNDEFINED) { return nullptr; @@ -487,6 +497,32 @@ void RCLowering::RCLower() { } } +MeExpr *RCLowering::HandleIncRefAndDecRefStmt(MeStmt &stmt) { + Opcode opCode = stmt.GetOp(); + MIRIntrinsicID rcCallID = INTRN_UNDEFINED; + + if (opCode == OP_incref) { + rcCallID = INTRN_MCCIncRef; + } else if (opCode == OP_decref) { + rcCallID = INTRN_MCCDecRef; + } else if (opCode == OP_decrefreset) { + rcCallID = INTRN_MCCDecRefReset; + } + + if (rcCallID == INTRN_UNDEFINED) { + return nullptr; + } + + auto &unaryMeStmt = static_cast(stmt); + if (opCode == OP_decref && !unaryMeStmt.GetDecrefBeforeExit()) { + stmt.GetBB()->RemoveMeStmt(&stmt); + return unaryMeStmt.GetOpnd(); + } + std::vector opnds = { unaryMeStmt.GetOpnd() }; + IntrinsiccallMeStmt *rcCall = CreateRCIntrinsic(rcCallID, stmt, opnds); + stmt.GetBB()->ReplaceMeStmt(&stmt, rcCall); + return nullptr; +} // if a var me expr is initialized by constructor, record it's initialized map // if a field id is not in initialized map, means the field has not been assigned a value @@ -533,7 +569,8 @@ void RCLowering::BBLower(BB &bb) { } else if (stmt.IsAssign()) { HandleAssignMeStmt(stmt, pendingDec); } else { - // handling is not necessary + MeExpr *ret = HandleIncRefAndDecRefStmt(stmt); + pendingDec = ret == nullptr ? pendingDec : ret; } } // there is no any statement exist whose opnd is the throw value, handle it @@ -571,6 +608,11 @@ void RCLowering::HandleReturnVar(RetMeStmt &ret) { if (sym != nullptr && sym->IgnoreRC()) { return; } + // if dread is local assigned var, no need inc because we will skip its dec + // unless we are change it to regread in later optimization + if (assignedPtrSym.count(sym) > 0 && sym->GetStorageClass() == kScAuto && !MeOption::regreadAtReturn) { + return; + } if (sym != nullptr && sym->IsGlobal() && !sym->IsFinal()) { HandleReturnGlobal(ret); } else if (assignedPtrSym.count(sym) > 0 && sym->GetStorageClass() == kScAuto && sym->GetAttr(ATTR_localrefvar)) { @@ -578,7 +620,6 @@ void RCLowering::HandleReturnVar(RetMeStmt &ret) { // checking localrefvar because some objects are meta HandleReturnRegread(ret); } else { - // if returning formal, incref unless placementRC is used and formal is NOT reassigned HandleReturnFormal(ret); } } @@ -592,6 +633,7 @@ void RCLowering::HandleReturnGlobal(RetMeStmt &ret) { IntrinsiccallMeStmt *loadCall = CreateRCIntrinsic(INTRN_MCCLoadRefS, ret, opnds, true); bb->InsertMeStmtBefore(&ret, loadCall); ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); + } void RCLowering::HandleReturnRegread(RetMeStmt &ret) { @@ -608,7 +650,7 @@ void RCLowering::HandleReturnRegread(RetMeStmt &ret) { // remove argument from intrinsiccall MPL_CLEANUP_LOCALREFVARS (dread ref %Reg1_R5678, ... MapleVector *opnds = &cleanup->GetOpnds(); for (auto iter = opnds->begin(); iter != opnds->end(); ++iter) { - if (*iter == retVar || static_cast(*iter)->GetOStIdx() == retVar->GetOStIdx()) { + if (*iter == retVar || (!isAnalyzed && static_cast(*iter)->GetOStIdx() == retVar->GetOStIdx())) { opnds->erase(iter); opnds->push_back(retVar); // pin it to end of std::vector cleanup->SetIntrinsic(INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP); @@ -647,6 +689,7 @@ void RCLowering::HandleReturnIvar(RetMeStmt &ret) { MeStmt *loadCall = CreateRCIntrinsic(INTRN_MCCLoadRef, ret, opnds, true); ret.GetBB()->InsertMeStmtBefore(&ret, loadCall); ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); + } } @@ -771,6 +814,11 @@ void RCLowering::PostRCLower() { HandleArguments(); // handle ret stmts HandleReturnStmt(); + // compact RC + // to prevent valid_end from being called repeatedly, don't modify the definition of eIt + for (auto bIt = func.valid_begin(), eIt = func.valid_end(); bIt != eIt; ++bIt) { + CompactRC(**bIt); + } } void RCLowering::Finish() { @@ -780,6 +828,99 @@ void RCLowering::Finish() { } } + +static inline bool CheckIntrinsicID(MeStmt *stmt, MIRIntrinsicID id) { + if (!CheckOp(stmt, OP_intrinsiccall)) { + return false; + } + auto *intrinsicCall = static_cast(stmt); + return intrinsicCall->GetIntrinsic() == id; +} + +static inline MeStmt *GetPrevMeStmt(const MeStmt &stmt) { + MeStmt *prevStmt = stmt.GetPrev(); + while (CheckOp(prevStmt, OP_comment)) { + prevStmt = prevStmt->GetPrev(); + } + return prevStmt; +} + +// iterate over stmts and find back-to-back incref/decref +// and merge them into one intrinsic if needed +void RCLowering::CompactRC(BB &bb) { + for (auto &stmt : bb.GetMeStmts()) { + if (CheckIntrinsicID(&stmt, INTRN_MCCIncRef)) { + MeStmt *prevStmt = GetPrevMeStmt(stmt); + if (CheckIntrinsicID(prevStmt, INTRN_MCCDecRef)) { + CompactIncAndDec(stmt, *prevStmt); + } + } + if (CheckIntrinsicID(&stmt, INTRN_MCCDecRef)) { + MeStmt *prevStmt = GetPrevMeStmt(stmt); + if (CheckIntrinsicID(prevStmt, INTRN_MCCIncRef)) { + CompactIncAndDec(*prevStmt, stmt); + } + } + } +} + +void RCLowering::CompactIncAndDec(MeStmt &incStmt, MeStmt &decStmt) { + BB *bb = incStmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb nullptr check"); + MeExpr *incOpnd = incStmt.GetOpnd(0); + MeExpr *decOpnd = decStmt.GetOpnd(0); + if (incOpnd == decOpnd) { + bb->RemoveMeStmt(&incStmt); + } else { + std::vector opnds = { incOpnd, decOpnd }; + IntrinsiccallMeStmt *incDecCall = CreateRCIntrinsic(INTRN_MCCIncDecRef, incStmt, opnds); + bb->ReplaceMeStmt(&incStmt, incDecCall); + } + bb->RemoveMeStmt(&decStmt); +} + +void RCLowering::CompactIncAndDecReset(MeStmt &incStmt, MeStmt &resetStmt) { + BB *bb = incStmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb nullptr check"); + MeExpr *incOpnd = incStmt.GetOpnd(0); + MeExpr *resetOpnd = resetStmt.GetOpnd(0); + if (incOpnd == resetOpnd) { + bb->RemoveMeStmt(&resetStmt); + } else { + std::vector opnds = { incOpnd, resetOpnd }; + IntrinsiccallMeStmt *incDecReset = CreateRCIntrinsic(INTRN_MCCIncDecRefReset, resetStmt, opnds); + bb->ReplaceMeStmt(&resetStmt, incDecReset); + } + bb->RemoveMeStmt(&incStmt); +} + +void RCLowering::ReplaceDecResetWithDec(MeStmt &prevStmt, MeStmt &stmt) { + auto *addrofMeExpr = static_cast(stmt.GetOpnd(0)); + ASSERT_NOT_NULL(addrofMeExpr); + auto *dass = static_cast(&prevStmt); + if (dass->GetRHS()->GetMeOp() != kMeOpReg || dass->GetVarLHS()->GetOStIdx() != addrofMeExpr->GetOstIdx()) { + return; + } + BB *bb = stmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb nullptr check"); + std::vector opnds = { dass->GetRHS() }; + IntrinsiccallMeStmt *decRefCall = CreateRCIntrinsic(INTRN_MCCDecRef, stmt, opnds); + bb->ReplaceMeStmt(&stmt, decRefCall); + bb->RemoveMeStmt(&prevStmt); +} + +void RCLowering::CompactAdjacentDecReset(MeStmt &prevStmt, MeStmt &stmt) { + MeExpr *prevOpnd = prevStmt.GetOpnd(0); + MeExpr *curOpnd = stmt.GetOpnd(0); + BB *bb = stmt.GetBB(); + if (prevOpnd != curOpnd) { + std::vector opnds = { prevOpnd, curOpnd }; + IntrinsiccallMeStmt *decRefCall = CreateRCIntrinsic(INTRN_MCCDecRefResetPair, stmt, opnds); + bb->ReplaceMeStmt(&stmt, decRefCall); + } + bb->RemoveMeStmt(&prevStmt); +} + OriginalSt *RCLowering::RetrieveOSt(const std::string &name, bool isLocalRefVar) const { MIRSymbol *backupSym = mirModule.GetMIRBuilder()->GetOrCreateLocalDecl( name, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_ptr))); // use PTY_ptr for temp @@ -808,15 +949,13 @@ VarMeExpr *RCLowering::CreateNewTmpVarMeExpr(bool isLocalRefVar) { } AnalysisResult *MeDoRCLowering::Run(MeFunction *func, MeFuncResultMgr *funcResMgr, ModuleResultMgr *moduleResMgr) { - auto *kh = static_cast(moduleResMgr->GetAnalysisResult(MoPhase_CHA, &func->GetMIRModule())); - ASSERT_NOT_NULL(kh); if (func->GetIRMap() == nullptr) { auto *hmap = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_IRMAP, func)); CHECK_FATAL(hmap != nullptr, "hssamap has problem"); func->SetIRMap(hmap); } CHECK_FATAL(func->GetMeSSATab() != nullptr, "ssatab has problem"); - RCLowering rcLowering(*func, *kh, DEBUGFUNC(func)); + RCLowering rcLowering(*func, DEBUGFUNC(func)); rcLowering.Prepare(); rcLowering.PreRCLower(); diff --git a/src/maple_me/src/me_ssa_epre.cpp b/src/maple_me/src/me_ssa_epre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..951b63b8b5cdff4ba8a10ea4d82beafe41751bfa --- /dev/null +++ b/src/maple_me/src/me_ssa_epre.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_ssa_epre.h" +#include "me_dominance.h" +#include "me_ssa_update.h" + + +// accumulate the BBs that are in the iterated dominance frontiers of bb in +// the set dfSet, visiting each BB only once +namespace maple { +void MeSSAEPre::GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) { + CHECK_FATAL(bb.GetBBId() < visitedMap.size(), "index out of range in MeSSAEPre::GetIterDomFrontier"); + if (visitedMap[bb.GetBBId()]) { + return; + } + visitedMap[bb.GetBBId()] = true; + for (BBId frontierBBId : dom->GetDomFrontier(bb.GetBBId())) { + dfSet.insert(dom->GetDtDfnItem(frontierBBId)); + BB *frontierBB = GetBB(frontierBBId); + GetIterDomFrontier(*frontierBB, dfSet, visitedMap); + } +} + +void MeSSAEPre::BuildWorkList() { + const MapleVector &preOrderDt = dom->GetDtPreOrder(); + for (auto &bbID : preOrderDt) { + BB *bb = func->GetAllBBs().at(bbID); + BuildWorkListBB(bb); + } +} + +AnalysisResult *MeDoSSAEPre::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + static uint32 puCount = 0; // count PU to support the eprePULimit option + if (puCount > MeOption::eprePULimit) { + ++puCount; + return nullptr; + } + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom != nullptr, "dominance phase has problem"); + auto *irMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAP, func)); + ASSERT(irMap != nullptr, "irMap phase has problem"); + bool eprePULimitSpecified = MeOption::eprePULimit != UINT32_MAX; + uint32 epreLimitUsed = + (eprePULimitSpecified && puCount != MeOption::eprePULimit) ? UINT32_MAX : MeOption::epreLimit; + MemPool *ssaPreMemPool = NewMemPool(); + bool epreIncludeRef = MeOption::epreIncludeRef; + MeSSAEPre ssaPre(func, *irMap, *dom, *ssaPreMemPool, *NewMemPool(), epreLimitUsed, epreIncludeRef, + MeOption::epreLocalRefVar, MeOption::epreLHSIvar); + ssaPre.SetSpillAtCatch(MeOption::spillAtCatch); + if (eprePULimitSpecified && puCount == MeOption::eprePULimit && epreLimitUsed != UINT32_MAX) { + LogInfo::MapleLogger() << "applying EPRE limit " << epreLimitUsed << " in function " << + func->GetMirFunc()->GetName() << "\n"; + } + if (DEBUGFUNC(func)) { + ssaPre.SetSSAPreDebug(true); + } + ssaPre.ApplySSAPRE(); + if (!ssaPre.GetCandsForSSAUpdate().empty()) { + MemPool *tmp = memPoolCtrler.NewMemPool("MeSSAUpdate"); + MeSSAUpdate ssaUpdate(*func, *func->GetMeSSATab(), *dom, ssaPre.GetCandsForSSAUpdate(), *tmp); + ssaUpdate.Run(); + } + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "\n============== EPRE =============" << "\n"; + func->Dump(false); + } + ++puCount; + return nullptr; +} +} // namespace maple diff --git a/src/maple_me/src/me_ssa_lpre.cpp b/src/maple_me/src/me_ssa_lpre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd23187e23bf94be3239f111a3a2763aafe4a448 --- /dev/null +++ b/src/maple_me/src/me_ssa_lpre.cpp @@ -0,0 +1,406 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_ssa_lpre.h" +#include "mir_builder.h" +#include "me_lower_globals.h" + +namespace maple { +void MeSSALPre::GenerateSaveRealOcc(MeRealOcc *realOcc) { + ASSERT(GetPUIdx() == workCand->GetPUIdx() || workCand->GetPUIdx() == 0, + "GenerateSaveRealOcc: inconsistent puIdx"); + MeExpr *regOrVar = CreateNewCurTemp(realOcc->GetMeExpr()); + if (!realOcc->IsLHS()) { + // create a new meStmt before realOcc->GetMeStmt() + MeStmt *newMeStmt = irMap->CreateRegassignMeStmt(*regOrVar, *realOcc->GetMeExpr(), *realOcc->GetMeStmt()->GetBB()); + regOrVar->SetDefByStmt(*newMeStmt); + realOcc->GetMeStmt()->GetBB()->InsertMeStmtBefore(realOcc->GetMeStmt(), newMeStmt); + // replace realOcc->GetMeStmt()'s occ with regOrVar + irMap->ReplaceMeExprStmt(*realOcc->GetMeStmt(), *realOcc->GetMeExpr(), *regOrVar); + } else if (realOcc->IsFormalAtEntry()) { + // no need generate any code, but change formal declaration to preg + CHECK_FATAL(regOrVar->GetMeOp() == kMeOpReg, "formals not promoted to register"); + auto *varMeExpr = static_cast(realOcc->GetMeExpr()); + const MIRSymbol *oldFormalSt = ssaTab->GetMIRSymbolFromID(varMeExpr->GetOStIdx()); + auto *regFormal = static_cast(regOrVar); + MIRSymbol *newFormalSt = mirModule->GetMIRBuilder()->CreatePregFormalSymbol(oldFormalSt->GetTyIdx(), + regFormal->GetRegIdx(), + *func->GetMirFunc()); + size_t i = 0; + for (; i < func->GetMirFunc()->GetFormalCount(); ++i) { + if (func->GetMirFunc()->GetFormal(i) == oldFormalSt) { + func->GetMirFunc()->SetFormal(i, newFormalSt); + break; + } + } + CHECK_FATAL(i < func->GetMirFunc()->GetFormalCount(), "Cannot replace promoted formal"); + } else if (realOcc->GetOpcodeOfMeStmt() == OP_dassign || realOcc->GetOpcodeOfMeStmt() == OP_maydassign) { + VarMeExpr *theLHS = realOcc->GetMeStmt()->GetVarLHS(); + MeExpr *savedRHS = realOcc->GetMeStmt()->GetRHS(); + CHECK_NULL_FATAL(theLHS); + CHECK_NULL_FATAL(savedRHS); + CHECK_NULL_FATAL(realOcc->GetMeStmt()->GetChiList()); + realOcc->GetMeStmt()->GetChiList()->clear(); + SrcPosition savedSrcPos = realOcc->GetMeStmt()->GetSrcPosition(); + BB *savedBB = realOcc->GetMeStmt()->GetBB(); + MeStmt *savedPrev = realOcc->GetMeStmt()->GetPrev(); + MeStmt *savedNext = realOcc->GetMeStmt()->GetNext(); + // change original dassign/maydassign to regassign; + // use placement new to modify in place, because other occ nodes are pointing + // to this statement in order to get to the rhs expression; + // this assume RegassignMeStmt has smaller size then DassignMeStmt and + // MaydassignMeStmt + RegassignMeStmt *rass = new (realOcc->GetMeStmt()) RegassignMeStmt(); + rass->SetLHS(static_cast(regOrVar)); + rass->SetRHS(savedRHS); + rass->SetSrcPos(savedSrcPos); + rass->SetBB(savedBB); + rass->SetPrev(savedPrev); + rass->SetNext(savedNext); + regOrVar->SetDefByStmt(*rass); + // create new dassign for original lhs + MeStmt *newDassign = irMap->CreateDassignMeStmt(*theLHS, *regOrVar, *savedBB); + theLHS->SetDefByStmt(*newDassign); + savedBB->InsertMeStmtAfter(realOcc->GetMeStmt(), newDassign); + } else { + CHECK_FATAL(kOpcodeInfo.IsCallAssigned(realOcc->GetOpcodeOfMeStmt()), + "LHS real occurrence has unrecognized stmt type"); + MapleVector *mustDefList = realOcc->GetMeStmt()->GetMustDefList(); + CHECK_NULL_FATAL(mustDefList); + ASSERT(!mustDefList->empty(), "empty mustdef in callassigned stmt"); + MustDefMeNode *mustDefMeNode = &mustDefList->front(); + if (regOrVar->GetMeOp() == kMeOpReg) { + auto *theLHS = static_cast(mustDefMeNode->GetLHS()); + // change mustDef lhs to regOrVar + mustDefMeNode->UpdateLHS(*regOrVar); + // create new dassign for original lhs + MeStmt *newDassign = irMap->CreateDassignMeStmt(*theLHS, *regOrVar, *realOcc->GetMeStmt()->GetBB()); + theLHS->SetDefByStmt(*newDassign); + realOcc->GetMeStmt()->GetBB()->InsertMeStmtAfter(realOcc->GetMeStmt(), newDassign); + } else { + CHECK_FATAL(false, "GenerateSaveRealOcc: non-reg temp for callassigned LHS occurrence NYI"); + } + } + realOcc->SetSavedExpr(*regOrVar); +} + +void MeSSALPre::GenerateReloadRealOcc(MeRealOcc *realOcc) { + CHECK_FATAL(!realOcc->IsLHS(), "GenerateReloadRealOcc: cannot be LHS occurrence"); + MeExpr *regOrVar = nullptr; + MeOccur *defOcc = realOcc->GetDef(); + if (defOcc->GetOccType() == kOccReal) { + auto *defRealOcc = static_cast(defOcc); + regOrVar = defRealOcc->GetSavedExpr(); + } else if (defOcc->GetOccType() == kOccPhiocc) { + auto *defPhiOcc = static_cast(defOcc); + MeRegPhiNode *regPhi = defPhiOcc->GetRegPhi(); + regOrVar = regPhi->GetLHS(); + } else if (defOcc->GetOccType() == kOccInserted) { + auto *defInsertedOcc = static_cast(defOcc); + regOrVar = defInsertedOcc->GetSavedExpr(); + } else { + CHECK_FATAL(false, "NYI"); + } + CHECK_NULL_FATAL(regOrVar); + // replace realOcc->GetMeStmt()'s occ with regOrVar + irMap->ReplaceMeExprStmt(*realOcc->GetMeStmt(), *realOcc->GetMeExpr(), *regOrVar); +} + +// the variable in realZ is defined by a phi; replace it by the jth phi opnd +MeExpr *MeSSALPre::PhiOpndFromRes(MeRealOcc *realZ, size_t j) { + MeOccur *defZ = realZ->GetDef(); + CHECK_NULL_FATAL(defZ); + CHECK_FATAL(defZ->GetOccType() == kOccPhiocc, "must be def by phiocc"); + MeExpr *meExprZ = realZ->GetMeExpr(); + BB *ePhiBB = static_cast(defZ)->GetBB(); + MeExpr *retVar = GetReplaceMeExpr(meExprZ, ePhiBB, j); + return (retVar != nullptr) ? retVar : meExprZ; +} + +// accumulate the BBs that are in the iterated dominance frontiers of bb in +// the set dfSet, visiting each BB only once +void MeSSALPre::GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) { + CHECK_FATAL(bb.GetBBId() < visitedMap.size(), "index out of range in MeSSALPre::GetIterDomFrontier"); + if (visitedMap[bb.GetBBId()]) { + return; + } + visitedMap[bb.GetBBId()] = true; + CHECK_FATAL(bb.GetBBId() < dom->GetDomFrontierSize(), "index out of range in MeSSALPre::GetIterDomFrontier"); + for (BBId frontierBBId : dom->GetDomFrontier(bb.GetBBId())) { + dfSet.insert(dom->GetDtDfnItem(frontierBBId)); + BB *frontierBB = GetBB(frontierBBId); + GetIterDomFrontier(*frontierBB, dfSet, visitedMap); + } +} + +void MeSSALPre::ComputeVarAndDfPhis() { + varPhiDfns.clear(); + dfPhiDfns.clear(); + PreWorkCand *workCand = GetWorkCand(); + const MapleVector &realOccList = workCand->GetRealOccs(); + CHECK_FATAL(!dom->IsBBVecEmpty(), "size to be allocated is 0"); + for (auto it = realOccList.begin(); it != realOccList.end(); ++it) { + std::vector visitedMap(dom->GetBBVecSize(), false); + MeRealOcc *realOcc = *it; + BB *defBB = realOcc->GetBB(); + GetIterDomFrontier(*defBB, dfPhiDfns, visitedMap); + MeExpr *meExpr = realOcc->GetMeExpr(); + if (meExpr->GetMeOp() == kMeOpVar) { + SetVarPhis(meExpr); + } + } +} + +void MeSSALPre::BuildEntryLHSOcc4Formals() { + if (preKind == kAddrPre) { + return; + } + PreWorkCand *workCand = GetWorkCand(); + auto *varMeExpr = static_cast(workCand->GetTheMeExpr()); + const OriginalSt *ost = ssaTab->GetSymbolOriginalStFromID(varMeExpr->GetOStIdx()); + if (!ost->IsFormal()) { + return; + } + if (assignedFormals.find(ost->GetIndex()) != assignedFormals.end()) { + return; // the formal's memory location has to be preserved + } + // Avoid promoting formals if it has been marked localrefvar + if (ost->HasAttr(ATTR_localrefvar)) { + return; + } + // get the zero version VarMeExpr node + VarMeExpr *zeroVersion = irMap->GetOrCreateZeroVersionVarMeExpr(*ost); + MeRealOcc *occ = ssaPreMemPool->New(nullptr, 0, zeroVersion); + auto occIt = workCand->GetRealOccs().begin(); + workCand->GetRealOccs().insert(occIt, occ); // insert at beginning + occ->SetIsLHS(true); + occ->SetIsFormalAtEntry(true); + occ->SetBB(*func->GetFirstBB()); +} + +void MeSSALPre::BuildWorkListLHSOcc(MeStmt *meStmt, int32 seqStmt) { + if (preKind == kAddrPre) { + return; + } + if (meStmt->GetOp() == OP_dassign || meStmt->GetOp() == OP_maydassign) { + VarMeExpr *lhs = meStmt->GetVarLHS(); + CHECK_NULL_FATAL(lhs); + const OriginalSt *ost = ssaTab->GetSymbolOriginalStFromID(lhs->GetOStIdx()); + if (ost->IsFormal()) { + assignedFormals.insert(ost->GetIndex()); + } + CHECK_NULL_FATAL(meStmt->GetRHS()); + if (ost->IsVolatile()) { + return; + } + if (lhs->GetPrimType() == PTY_agg) { + return; + } + CreateRealOcc(*meStmt, seqStmt, *lhs, false, true); + } else if (kOpcodeInfo.IsCallAssigned(meStmt->GetOp())) { + MapleVector *mustDefList = meStmt->GetMustDefList(); + if (mustDefList->empty()) { + return; + } + if (mustDefList->front().GetLHS()->GetMeOp() != kMeOpVar) { + return; + } + auto *theLHS = static_cast(mustDefList->front().GetLHS()); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(theLHS->GetOStIdx()); + if (ost->IsFormal()) { + assignedFormals.insert(ost->GetIndex()); + } + if (theLHS->GetPrimType() == PTY_ref && !MeOption::rcLowering) { + return; + } + if (ost->IsVolatile()) { + return; + } + if (theLHS->GetPrimType() == PTY_agg) { + return; + } + CreateRealOcc(*meStmt, seqStmt, *theLHS, false, true); + } +} + +void MeSSALPre::CreateMembarOccAtCatch(BB &bb) { + // go thru all workcands and insert a membar occurrence for each of them + for (size_t i = 0; i < workList.size() && i <= preLimit; ++i) { + PreWorkCand *workCand = workList[i]; + MeRealOcc *newOcc = ssaPreMemPool->New(nullptr, 0, workCand->GetTheMeExpr()); + newOcc->SetOccType(kOccMembar); + newOcc->SetBB(bb); + workCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + if (preKind == kAddrPre) { + continue; + } + auto *varMeExpr = static_cast(workCand->GetTheMeExpr()); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varMeExpr->GetOStIdx()); + if (ost->IsFormal()) { + assignedFormals.insert(ost->GetIndex()); + } + } +} + +// only handle the leaf of load, because all other expressions has been done by +// previous SSAPre +void MeSSALPre::BuildWorkListExpr(MeStmt *meStmt, int32 seqStmt, MeExpr *meExpr, bool, MeExpr*, bool) { + MeExprOp meOp = meExpr->GetMeOp(); + switch (meOp) { + case kMeOpVar: { + if (preKind != kLoadPre) { + break; + } + auto *varMeExpr = static_cast(meExpr); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varMeExpr->GetOStIdx()); + if (ost->IsVolatile()) { + break; + } + const MIRSymbol *sym = ost->GetMIRSymbol(); + if (sym->IsInstrumented()) { + // not doing because its SSA form is not complete + break; + } + if (meExpr->GetPrimType() == PTY_agg) { + break; + } + CreateRealOcc(*meStmt, seqStmt, *meExpr, false); + break; + } + case kMeOpAddrof: { + if (preKind != kAddrPre) { + break; + } + auto *addrOfMeExpr = static_cast(meExpr); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(addrOfMeExpr->GetOstIdx()); + if (ost->IsLocal()) { // skip lpre for stack addresses as they are cheap + break; + } + CreateRealOcc(*meStmt, seqStmt, *meExpr, false); + break; + } + case kMeOpAddroffunc: { + if (preKind != kAddrPre) { + break; + } + CreateRealOcc(*meStmt, seqStmt, *meExpr, false); + break; + } + case kMeOpOp: { + auto *meOpExpr = static_cast(meExpr); + for (size_t i = 0; i < kOperandNumTernary; ++i) { + MeExpr *opnd = meOpExpr->GetOpnd(i); + if (opnd != nullptr) { + BuildWorkListExpr(meStmt, seqStmt, opnd, false, nullptr, false); + } + } + break; + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(meExpr); + MapleVector &opnds = naryMeExpr->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); ++it) { + MeExpr *opnd = *it; + BuildWorkListExpr(meStmt, seqStmt, opnd, false, nullptr, false); + } + break; + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(meExpr); + BuildWorkListExpr(meStmt, seqStmt, ivarMeExpr->GetBase(), false, nullptr, false); + break; + } + default: + break; + } +} + +void MeSSALPre::BuildWorkList() { + MeFunction &tmpFunc = irMap->GetFunc(); + size_t numBBs = dom->GetDtPreOrderSize(); + if (numBBs > kDoLpreBBsLimit) { + return; + } + const MapleVector &preOrderDt = dom->GetDtPreOrder(); + for (size_t i = 0; i < numBBs; ++i) { + BB *bb = tmpFunc.GetBBFromID(preOrderDt[i]); + BuildWorkListBB(bb); + } +} + +void MeSSALPre::FindLoopHeadBBs(IdentifyLoops *identLoops) { + for (LoopDesc *mapleLoop : identLoops->GetMeLoops()) { + if (mapleLoop->head != nullptr) { + loopHeadBBs.insert(mapleLoop->head->GetBBId()); + } + } +} + +AnalysisResult *MeDoSSALPre::Run(MeFunction *irFunc, MeFuncResultMgr *funcMgr, ModuleResultMgr*) { + static uint32 puCount = 0; // count PU to support the lprePULimit option + if (puCount > MeOption::lprePULimit) { + ++puCount; + return nullptr; + } + auto *dom = static_cast(funcMgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, irFunc)); + CHECK_NULL_FATAL(dom); + auto *irMap = static_cast(funcMgr->GetAnalysisResult(MeFuncPhase_IRMAP, irFunc)); + CHECK_NULL_FATAL(irMap); + auto *identLoops = static_cast(funcMgr->GetAnalysisResult(MeFuncPhase_MELOOP, irFunc)); + CHECK_NULL_FATAL(identLoops); + bool lprePULimitSpecified = MeOption::lprePULimit != UINT32_MAX; + uint32 lpreLimitUsed = + (lprePULimitSpecified && puCount != MeOption::lprePULimit) ? UINT32_MAX : MeOption::lpreLimit; + { + MeSSALPre ssaLpre(irFunc, *irMap, *dom, *NewMemPool(), *NewMemPool(), kLoadPre, lpreLimitUsed); + ssaLpre.SetRcLoweringOn(MeOption::rcLowering); + ssaLpre.SetRegReadAtReturn(MeOption::regreadAtReturn); + ssaLpre.SetSpillAtCatch(MeOption::spillAtCatch); + if (lprePULimitSpecified && puCount == MeOption::lprePULimit && lpreLimitUsed != UINT32_MAX) { + LogInfo::MapleLogger() << "applying LPRE limit " << lpreLimitUsed << " in function " << + irFunc->GetMirFunc()->GetName() << '\n'; + } + if (DEBUGFUNC(irFunc)) { + ssaLpre.SetSSAPreDebug(true); + } + if (MeOption::lpreSpeculate && !irFunc->HasException()) { + ssaLpre.FindLoopHeadBBs(identLoops); + } + ssaLpre.ApplySSAPRE(); + if (DEBUGFUNC(irFunc)) { + LogInfo::MapleLogger() << "\n==============after LoadPre =============" << '\n'; + irFunc->Dump(false); + } + } + MeLowerGlobals lowerGlobals(irFunc, irFunc->GetMeSSATab()); + lowerGlobals.Run(); + { + MeSSALPre ssaLpre(irFunc, *irMap, *dom, *NewMemPool(), *NewMemPool(), kAddrPre, lpreLimitUsed); + ssaLpre.SetSpillAtCatch(MeOption::spillAtCatch); + if (DEBUGFUNC(irFunc)) { + ssaLpre.SetSSAPreDebug(true); + } + if (MeOption::lpreSpeculate && !irFunc->HasException()) { + ssaLpre.FindLoopHeadBBs(identLoops); + } + ssaLpre.ApplySSAPRE(); + if (DEBUGFUNC(irFunc)) { + LogInfo::MapleLogger() << "\n==============after AddrPre =============" << '\n'; + irFunc->Dump(false); + } + } + ++puCount; + return nullptr; +} +} // namespace maple diff --git a/src/maple_me/src/me_ssu_pre.cpp b/src/maple_me/src/me_ssu_pre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17f12ed2355ae9b61d2b7a629e950ac11ee23870 --- /dev/null +++ b/src/maple_me/src/me_ssu_pre.cpp @@ -0,0 +1,581 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_ssu_pre.h" + +namespace maple { +#define JAVALANG (mirmodule->IsJavaModule()) + +// ================ Step 5: Finalize ================ +void MeSSUPre::Finalize() { + std::vector anticipatedDefVec(classCount + 1, nullptr); + // preorder traversal of post-dominator tree + for (SOcc *occ : allOccs) { + size_t classx = static_cast(occ->GetClassId()); + switch (occ->GetOccTy()) { + case kSOccLambda: { + auto *lambdaOcc = static_cast(occ); + if (lambdaOcc->WillBeAnt()) { + anticipatedDefVec[classx] = lambdaOcc; + } + break; + } + case kSOccReal: { + auto *realocc = static_cast(occ); + if (anticipatedDefVec[classx] == nullptr || !anticipatedDefVec[classx]->IsPostDominate(dom, occ)) { + realocc->SetRedundant(false); + anticipatedDefVec[classx] = realocc; + } else { + realocc->SetRedundant(true); + } + break; + } + case kSOccLambdaRes: { + auto *lambdaResOcc = static_cast(occ); + SLambdaOcc *lambdaOcc = lambdaResOcc->GetUseLambdaOcc(); + if (lambdaOcc->WillBeAnt()) { + if (lambdaResOcc->GetUse() == nullptr || (!lambdaResOcc->GetHasRealUse() && + lambdaResOcc->GetUse()->GetOccTy() == kSOccLambda && + !static_cast(lambdaResOcc->GetUse())->WillBeAnt())) { + // insert a store + BB *insertBB = lambdaResOcc->GetBB(); + if (insertBB->GetAttributes(kBBAttrIsCatch)) { + if (preKind == kDecrefPre) { + catchBlocks2Insert.insert(insertBB->GetBBId()); + } // else { kStorePre: omit insertion at entry of catch blocks } + break; + } + if (lambdaResOcc->GetBB()->GetPred().size() != 1) { // critical edge + if (preKind != kDecrefPre && preKind != kSecondDecrefPre) { + CHECK_FATAL(false, "MeSSUPre::Finalize: insertion at critical edge"); + workCand->SetHasCriticalEdge(true); + return; + } + } + if (insertBB->GetAttributes(kBBAttrArtificial) && insertBB->GetAttributes(kBBAttrIsExit)) { + // do not insert at fake BBs created due to infinite loops + break; + } + lambdaResOcc->SetInsertHere(true); + } else { + lambdaResOcc->SetUse(anticipatedDefVec[classx]); + } + } + break; + } + case kSOccEntry: + case kSOccUse: + case kSOccPhi: + break; + default: + ASSERT(false, "Finalize: unexpected occ type"); + } + } + if (enabledDebug) { + LogInfo::MapleLogger() << " _______ after finalize _______" << '\n'; + for (SOcc *occ : allOccs) { + if (occ->GetOccTy() == kSOccReal) { + auto *realocc = static_cast(occ); + if (realocc->GetRedundant()) { + occ->Dump(); + LogInfo::MapleLogger() << " deleted" << '\n'; + } + } else if (occ->GetOccTy() == kSOccLambdaRes) { + auto *lambdaResOcc = static_cast(occ); + if (lambdaResOcc->GetInsertHere()) { + occ->Dump(); + LogInfo::MapleLogger() << " insertHere" << '\n'; + } + } + } + } +} + +// ================ Step 4: WillBeAnt Computation ================ +void MeSSUPre::ResetCanBeFullyAnt(SLambdaOcc *lambda) { + CHECK_NULL_FATAL(lambda); + lambda->SetIsCanBeAnt(false); + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + if (lambdaResOcc->GetUse() && lambdaResOcc->GetUse() == lambda && + !lambdaResOcc->GetHasRealUse() && lambdaOcc->GetIsCanBeAnt()) { + ResetCanBeFullyAnt(lambdaOcc); + } + } + } +} + +void MeSSUPre::ComputeCanBeFullyAnt() { + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + bool existNullUse = false; + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + if (lambdaResOcc->GetUse() == nullptr) { + existNullUse = true; + break; + } + } + if (existNullUse) { + ResetCanBeFullyAnt(lambdaOcc); + } + } +} + +void MeSSUPre::ResetCanBeAnt(SLambdaOcc *lambda) { + CHECK_NULL_FATAL(lambda); + lambda->SetIsCanBeAnt(false); + // the following loop finds lambda's defs and reset them + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + if (lambdaResOcc->GetUse() && lambdaResOcc->GetUse() == lambda) { + if (!lambdaResOcc->GetHasRealUse() && !lambdaOcc->GetIsUpsafe() && lambdaOcc->GetIsCanBeAnt()) { + ResetCanBeAnt(lambdaOcc); + } + } + } + } +} + +void MeSSUPre::ComputeCanBeAnt() { + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + if (!lambdaOcc->GetIsUpsafe() && lambdaOcc->GetIsCanBeAnt()) { + bool existNullUse = false; + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + if (lambdaResOcc->GetUse() == nullptr) { + existNullUse = true; + break; + } + } + if (existNullUse) { + ResetCanBeAnt(lambdaOcc); + } + } + } +} + +void MeSSUPre::ResetEarlier(SLambdaOcc *lambda) { + CHECK_NULL_FATAL(lambda); + lambda->SetIsEarlier(false); + // the following loop finds lambda's defs and reset them + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + if (lambdaResOcc->GetUse() && lambdaResOcc->GetUse() == lambda) { + if (lambdaOcc->GetIsEarlier()) { + ResetEarlier(lambdaOcc); + } + } + } + } +} + +void MeSSUPre::ComputeEarlier() { + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + lambdaOcc->SetIsEarlier(lambdaOcc->GetIsCanBeAnt()); + } + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + if (lambdaOcc->GetIsEarlier()) { + bool existNonNullUse = false; + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + if (lambdaResOcc->GetUse() && lambdaResOcc->GetHasRealUse()) { + existNonNullUse = true; + break; + } + } + if (existNonNullUse) { + ResetEarlier(lambdaOcc); + } + } + } + if (enabledDebug) { + LogInfo::MapleLogger() << " _______ after earlier computation _______" << '\n'; + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + lambdaOcc->Dump(); + if (lambdaOcc->GetIsCanBeAnt()) { + LogInfo::MapleLogger() << " canbeant"; + } + if (lambdaOcc->GetIsEarlier()) { + LogInfo::MapleLogger() << " earlier"; + } + if (lambdaOcc->GetIsCanBeAnt() && !lambdaOcc->GetIsEarlier()) { + LogInfo::MapleLogger() << " will be ant"; + } + LogInfo::MapleLogger() << '\n'; + } + } +} + +// ================ Step 3: Upsafe Computation ================ +void MeSSUPre::ResetUpsafe(SLambdaResOcc *lambdaRes) { + CHECK_NULL_FATAL(lambdaRes); + if (lambdaRes->GetHasRealUse()) { + return; + } + SOcc *useOcc = lambdaRes->GetUse(); + if (useOcc == nullptr || useOcc->GetOccTy() != kSOccLambda) { + return; + } + auto *useLambdaOcc = static_cast(useOcc); + if (!useLambdaOcc->GetIsUpsafe()) { + return; + } + useLambdaOcc->SetIsUpsafe(false); + for (SLambdaResOcc *lambdaResOcc : useLambdaOcc->GetLambdaRes()) { + ResetUpsafe(lambdaResOcc); + } +} + +void MeSSUPre::ComputeUpsafe() { + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + if (!lambdaOcc->GetIsUpsafe()) { + // propagate not-upsafe forward along def-use edges + for (SLambdaResOcc *lambdaResOcc : lambdaOcc->GetLambdaRes()) { + ResetUpsafe(lambdaResOcc); + } + } + } + if (enabledDebug) { + LogInfo::MapleLogger() << " _______ after upsafe computation _______" << '\n'; + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + lambdaOcc->Dump(); + if (lambdaOcc->GetIsUpsafe()) { + LogInfo::MapleLogger() << " upsafe"; + } + LogInfo::MapleLogger() << '\n'; + } + } +} + +// ================ Step 2: rename ================ +void MeSSUPre::Rename() { + std::stack occStack; + classCount = 0; + // iterate thru the occurrences in order of preorder traversal of + // post-dominator tree + for (SOcc *occ : allOccs) { + while (!occStack.empty() && !occStack.top()->IsPostDominate(dom, occ)) { + occStack.pop(); + } + switch (occ->GetOccTy()) { + case kSOccUse: + if (!occStack.empty()) { + SOcc *topOcc = occStack.top(); + if (topOcc->GetOccTy() == kSOccLambda) { + static_cast(topOcc)->SetIsUpsafe(false); + } + } + occStack.push(occ); + break; + case kSOccEntry: + if (!occStack.empty()) { + SOcc *topOcc = occStack.top(); + if (topOcc->GetOccTy() == kSOccLambda) { + // make sure this lambda is dominated by at least one kill occurrence + for (SOcc *realocc : workCand->GetRealOccs()) { + if (realocc->GetOccTy() == kSOccUse || realocc->GetOccTy() == kSOccPhi) { + continue; + } + CHECK_FATAL(realocc->GetOccTy() == kSOccReal, "just check"); + if ((preKind == kDecrefPre || preKind == kSecondDecrefPre) && + !static_cast(realocc)->GetRealFromDef()) { + continue; + } + CHECK_NULL_FATAL(dom); + if (!dom->Dominate(*realocc->GetBB(), *topOcc->GetBB())) { + continue; + } + static_cast(topOcc)->SetIsUpsafe(false); + break; + } + } + } + break; + case kSOccLambda: + // assign new class + occ->SetClassId(++classCount); + occStack.push(occ); + break; + case kSOccReal: { + if (occStack.empty()) { + // assign new class + occ->SetClassId(++classCount); + occStack.push(occ); + break; + } + SOcc *topOcc = occStack.top(); + if (topOcc->GetOccTy() == kSOccUse) { + // assign new class + occ->SetClassId(++classCount); + occStack.push(occ); + break; + } + ASSERT(topOcc->GetOccTy() == kSOccLambda || topOcc->GetOccTy() == kSOccReal, + "Rename: unexpected top-of-stack occ"); + occ->SetClassId(topOcc->GetClassId()); + if (topOcc->GetOccTy() == kSOccLambda) { + occStack.push(occ); + } + break; + } + case kSOccLambdaRes: { + if (occStack.empty()) { + // leave classId as 0 + break; + } + SOcc *topOcc = occStack.top(); + if (topOcc->GetOccTy() == kSOccUse) { + // leave classId as 0 + break; + } + ASSERT(topOcc->GetOccTy() == kSOccLambda || topOcc->GetOccTy() == kSOccReal, + "Rename: unexpected top-of-stack occ"); + occ->SetUse(topOcc); + occ->SetClassId(topOcc->GetClassId()); + if (topOcc->GetOccTy() == kSOccReal) { + static_cast(occ)->SetHasRealUse(true); + } + break; + } + case kSOccPhi: + break; + default: + ASSERT(false, "Rename: unexpected type of occurrence"); + } + } + if (enabledDebug) { + LogInfo::MapleLogger() << " _______ after rename _______" << '\n'; + for (SOcc *occ : allOccs) { + occ->Dump(); + LogInfo::MapleLogger() << '\n'; + } + } +} + +// ================ Step 1: insert lambdas ================ +void MeSSUPre::GetIterPdomFrontier(const BB *bb, MapleSet *pdfSet, std::vector &visitedMap) { + CHECK_NULL_FATAL(bb); + CHECK_FATAL(bb->GetBBId() < visitedMap.size(), "index out of range in MeSSUPre::GetIterPdomFrontier"); + if (visitedMap[bb->GetBBId()]) { + return; + } + CHECK_FATAL(!visitedMap.empty(), "visitedMap in MeSSUPre::GetIterPdomFrontier is empty"); + visitedMap[bb->GetBBId()] = true; + CHECK_NULL_FATAL(pdfSet); + for (BBId frontierBBId : dom->GetPdomFrontierItem(bb->GetBBId())) { + pdfSet->insert(dom->GetPdtDfnItem(frontierBBId)); + } + CHECK_NULL_FATAL(func); + for (BBId frontierBBId : dom->GetPdomFrontierItem(bb->GetBBId())) { + BB *frontierBB = func->GetAllBBs().at(frontierBBId); + GetIterPdomFrontier(frontierBB, pdfSet, visitedMap); + } +} + +// form lambda occ based on the real occ in workCand->realOccs; result is +// stored in lambdaDfns +void MeSSUPre::FormLambdas() { + lambdaDfns.clear(); + std::vector visitedMap(func->NumBBs(), false); + CHECK_NULL_FATAL(workCand); + for (SOcc *occ : workCand->GetRealOccs()) { + GetIterPdomFrontier(occ->GetBB(), &lambdaDfns, visitedMap); + } +} + +// form allOccs inclusive of real, use, lambda, lambdaRes, entry occurrences; +// form lambdaOccs containing only the lambdas +void MeSSUPre::CreateSortedOccs() { + // form lambdaRes occs based on the succs of the lambda occs ; result is + // stored in lambdaResDfns + std::multiset lambdaResDfns; + for (uint32 dfn : lambdaDfns) { + const BBId &bbId = dom->GetPdtPreOrderItem(dfn); + BB *bb = func->GetAllBBs().at(bbId); + for (BB *succ : bb->GetSucc()) { + lambdaResDfns.insert(dom->GetPdtDfnItem(succ->GetBBId())); + } + } + allOccs.clear(); + lambdaOccs.clear(); + std::unordered_map> bb2lambdaResMap; + auto realOccIt = workCand->GetRealOccs().begin(); + auto entryOccIt = entryOccs.begin(); + auto lambdaDfnIt = lambdaDfns.begin(); + auto lambdaResDfnIt = lambdaResDfns.begin(); + SOcc *nextRealOcc = nullptr; + if (realOccIt != workCand->GetRealOccs().end()) { + nextRealOcc = *realOccIt; + } + SEntryOcc *nextEntryOcc = nullptr; + if (entryOccIt != entryOccs.end()) { + nextEntryOcc = *entryOccIt; + } + SLambdaOcc *nextLambdaOcc = nullptr; + if (lambdaDfnIt != lambdaDfns.end()) { + nextLambdaOcc = + spreMp->New(func->GetAllBBs().at(dom->GetPdtPreOrderItem(*lambdaDfnIt)), &spreAllocator); + } + SLambdaResOcc *nextLambdaResOcc = nullptr; + if (lambdaResDfnIt != lambdaResDfns.end()) { + nextLambdaResOcc = spreMp->New(func->GetAllBBs().at(dom->GetPdtPreOrderItem(*lambdaResDfnIt))); + auto it = bb2lambdaResMap.find(dom->GetPdtPreOrderItem(*lambdaResDfnIt)); + if (it == bb2lambdaResMap.end()) { + std::forward_list newlist = { nextLambdaResOcc }; + bb2lambdaResMap[dom->GetPdtPreOrderItem(*lambdaResDfnIt)] = newlist; + } else { + it->second.push_front(nextLambdaResOcc); + } + } + SOcc *pickedOcc = nullptr; // the next picked occ in order of preorder traversal of post-dominator tree + do { + pickedOcc = nullptr; + if (nextLambdaOcc != nullptr) { + pickedOcc = nextLambdaOcc; + } + if (nextRealOcc && (pickedOcc == nullptr || dom->GetPdtDfnItem(nextRealOcc->GetBB()->GetBBId()) < + dom->GetPdtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextRealOcc; + } + if (nextLambdaResOcc && + (pickedOcc == nullptr || *lambdaResDfnIt < dom->GetPdtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextLambdaResOcc; + } + if (nextEntryOcc && (pickedOcc == nullptr || dom->GetPdtDfnItem(nextEntryOcc->GetBB()->GetBBId()) < + dom->GetPdtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextEntryOcc; + } + if (pickedOcc != nullptr) { + allOccs.push_back(pickedOcc); + switch (pickedOcc->GetOccTy()) { + case kSOccReal: + case kSOccUse: + case kSOccPhi: + // get the next real/use occ + CHECK_FATAL(realOccIt != workCand->GetRealOccs().end(), "iterator check"); + realOccIt++; + if (realOccIt != workCand->GetRealOccs().end()) { + nextRealOcc = *realOccIt; + } else { + nextRealOcc = nullptr; + } + break; + case kSOccEntry: + CHECK_FATAL(entryOccIt != entryOccs.end(), "iterator check"); + entryOccIt++; + if (entryOccIt != entryOccs.end()) { + nextEntryOcc = *entryOccIt; + } else { + nextEntryOcc = nullptr; + } + break; + case kSOccLambda: + lambdaOccs.push_back(static_cast(pickedOcc)); + CHECK_FATAL(lambdaDfnIt != lambdaDfns.end(), "iterator check"); + lambdaDfnIt++; + if (lambdaDfnIt != lambdaDfns.end()) { + nextLambdaOcc = + spreMp->New(func->GetAllBBs().at(dom->GetPdtPreOrderItem(*lambdaDfnIt)), &spreAllocator); + } else { + nextLambdaOcc = nullptr; + } + break; + case kSOccLambdaRes: + CHECK_FATAL(lambdaResDfnIt != lambdaResDfns.end(), "iterator check"); + lambdaResDfnIt++; + if (lambdaResDfnIt != lambdaResDfns.end()) { + nextLambdaResOcc = + spreMp->New(func->GetAllBBs().at(dom->GetPdtPreOrderItem(*lambdaResDfnIt))); + CHECK_NULL_FATAL(dom); + auto it = bb2lambdaResMap.find(dom->GetPdtPreOrderItem(*lambdaResDfnIt)); + if (it == bb2lambdaResMap.end()) { + std::forward_list newlist = { nextLambdaResOcc }; + bb2lambdaResMap[dom->GetPdtPreOrderItem(*lambdaResDfnIt)] = newlist; + } else { + it->second.push_front(nextLambdaResOcc); + } + } else { + nextLambdaResOcc = nullptr; + } + break; + default: + ASSERT(false, "CreateSortedOccs: unexpected occTy"); + } + } + } while (pickedOcc != nullptr); + // initialize lambdaRes vector in each SLambdaOcc node + for (SLambdaOcc *lambdaOcc : lambdaOccs) { + for (BB *succ : lambdaOcc->GetBB()->GetSucc()) { + SLambdaResOcc *lambdaResOcc = bb2lambdaResMap[succ->GetBBId()].front(); + lambdaOcc->GetLambdaRes().push_back(lambdaResOcc); + lambdaResOcc->SetUseLambdaOcc(lambdaOcc); + bb2lambdaResMap[succ->GetBBId()].pop_front(); + } + } + if (enabledDebug) { + LogInfo::MapleLogger() << " _______ after lambda insertion _______" << '\n'; + for (SOcc *occ : allOccs) { + occ->Dump(); + LogInfo::MapleLogger() << '\n'; + } + } +} + +void MeSSUPre::ApplySSUPre() { + BuildWorkListBB(func->GetCommonExitBB()); + if (preKind != kSecondDecrefPre) { // #0 build worklist + CreateEmptyCleanupIntrinsics(); + } + if (enabledDebug) { + LogInfo::MapleLogger() << "------ worklist initial size " << workCandMap.size() << '\n'; + } + int32 candNum = 0; + for (std::pair wkCandPair : workCandMap) { + if (preKind == kStorePre) { + if (!wkCandPair.second->GetHasStoreOcc()) { + continue; + } + } else if (preKind == kDecrefPre) { + if (wkCandPair.second->GetOst()->IsFormal() && !wkCandPair.second->GetHasStoreOcc()) { + continue; + } + } + workCand = wkCandPair.second; + if (enabledDebug) { + LogInfo::MapleLogger() << "||||||| SPRE candidate " << candNum << " (ostidx " + << workCand->GetOst()->GetIndex() << "): "; + workCand->GetOst()->Dump(); + LogInfo::MapleLogger() << '\n'; + } + PerCandInit(); + // #1 insert lambdas; results in allOccs and lambdaOccs + FormLambdas(); // result put in the set lambda_bbs + CreateSortedOccs(); + // #2 rename + Rename(); + if (!lambdaOccs.empty()) { + // #3 UpSafety + ComputeUpsafe(); + // #4 CanBeAnt + ComputeCanBeAnt(); + ComputeEarlier(); + } + // #5 Finalize + Finalize(); + // #6 Code Mmotion + CHECK_NULL_FATAL(workCand); + if (!workCand->GetHasCriticalEdge()) { + CodeMotion(); + } + candNum++; + } +} +} // namespace maple diff --git a/src/maple_me/src/me_stmt_fre.cpp b/src/maple_me/src/me_stmt_fre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57e22c76c10d2f0a33118087e3d44bec16ef24bf --- /dev/null +++ b/src/maple_me/src/me_stmt_fre.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_stmt_pre.h" + +namespace maple { +void MeStmtPre::ResetFullyAvail(MePhiOcc *occg) { + occg->SetIsCanBeAvail(false); + // reset those phiocc nodes that have oc as one of its operands + for (auto it = phiOccs.begin(); it != phiOccs.end(); ++it) { + MePhiOcc *phiOcc = *it; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() && phiOpnd->GetDef() == occg) { + // phiOpnd is a use of occg + if (!phiOpnd->HasRealUse()) { + ResetCanBeAvail(phiOcc); + } + } + } + } +} + +// the fullyavail attribute is stored in the isCanBeAvail field +void MeStmtPre::ComputeFullyAvail() { + for (auto it = phiOccs.begin(); it != phiOccs.end(); ++it) { + MePhiOcc *phiOcc = *it; + // reset canbeavail if any phi operand is null + bool existNullDef = false; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() == nullptr) { + existNullDef = true; + break; + } + } + if (existNullDef) { + ResetFullyAvail(phiOcc); + } + } +} + +bool MeStmtPre::AllVarsSameVersionStmtFre(MeRealOcc *topOcc, MeRealOcc *curOcc) const { + ASSERT(topOcc->GetOpcodeOfMeStmt() == OP_dassign, "AllVarsSameVersionStmtFre: only dassign is handled"); + auto *dass1 = static_cast(topOcc->GetMeStmt()); + auto *dass2 = static_cast(curOcc->GetMeStmt()); + if (dass1->GetRHS() != dass2->GetRHS()) { + return false; + } + return dass1->GetLHS() == curOcc->GetMeExpr(); +} + +void MeStmtPre::Rename1StmtFre() { + std::stack occStack; + rename2Set.clear(); + classCount = 1; + // iterate the occurrence according to its preorder dominator tree + for (MeOccur *occ : allOccs) { + while (!occStack.empty() && !occStack.top()->IsDominate(dom, occ)) { + occStack.pop(); + } + switch (occ->GetOccType()) { + case kOccReal: { + if (occStack.empty()) { + // assign new class + occ->SetClassID(classCount++); + occStack.push(occ); + break; + } + MeOccur *topOccur = occStack.top(); + if (topOccur->GetOccType() == kOccMembar) { + occ->SetClassID(classCount++); + occStack.push(occ); + break; + } + auto *realOcc = static_cast(occ); + if (topOccur->GetOccType() == kOccReal) { + auto *realTopOccur = static_cast(topOccur); + if (AllVarsSameVersionStmtFre(realTopOccur, realOcc)) { + // all corresponding variables are the same + realOcc->SetClassID(realTopOccur->GetClassID()); + realOcc->SetDef(realTopOccur); + } else { + // assign new class + occ->SetClassID(classCount++); + } + occStack.push(occ); + } else { + // top of stack is a PHI occurrence + std::vector varVec; + CollectVarForCand(realOcc, varVec); + bool isAllDom = true; + for (auto varIt = varVec.begin(); varIt != varVec.end(); ++varIt) { + MeExpr *varMeExpr = *varIt; + if (!DefVarDominateOcc(varMeExpr, topOccur)) { + isAllDom = false; + } + } + if (isAllDom) { + realOcc->SetClassID(topOccur->GetClassID()); + realOcc->SetDef(topOccur); + rename2Set.insert(realOcc->GetPosition()); + occStack.push(realOcc); + } else { + // assign new class + occ->SetClassID(classCount++); + } + occStack.push(occ); + } + break; + } + case kOccPhiocc: { + // assign new class + occ->SetClassID(classCount++); + occStack.push(occ); + break; + } + case kOccPhiopnd: { + if (occStack.empty() || occStack.top()->GetOccType() == kOccMembar) { + occ->SetDef(nullptr); + } else { + MeOccur *topOccur = occStack.top(); + occ->SetDef(topOccur); + occ->SetClassID(topOccur->GetClassID()); + if (topOccur->GetOccType() == kOccReal) { + static_cast(occ)->SetHasRealUse(true); + } + } + break; + } + case kOccExit: + break; + case kOccMembar: + if (occStack.empty() || occStack.top()->GetOccType() != kOccMembar) { + occStack.push(occ); + } + break; + default: + ASSERT(false, "should not be here"); + } + } + if (GetSSAPreDebug()) { + PreWorkCand *curCand = workCand; + mirModule->GetOut() << "======== ssafre candidate " << curCand->GetIndex() << + " after rename1StmtFre ===================\n"; + for (MeOccur *occ : allOccs) { + occ->Dump(*irMap); + mirModule->GetOut() << "\n"; + } + mirModule->GetOut() << "\n" << "rename2 set:\n"; + for (uint32 pos : rename2Set) { + MeRealOcc *occur = workCand->GetRealOcc(pos); + occur->Dump(*irMap); + mirModule->GetOut() << " with def at\n"; + occur->GetDef()->Dump(*irMap); + mirModule->GetOut() << "\n"; + } + mirModule->GetOut() << "\n"; + } +} + +void MeStmtPre::DoSSAFRE() { + if (GetSSAPreDebug()) { + mirModule->GetOut() << "{{{{{{{{ start of SSAFRE }}}}}}}}" << '\n'; + } + // form new allOccs that has no use_occ and reflect insertions and deletions + MapleVector newAllOccs(perCandAllocator.Adapter()); + int32 realOccCnt = 0; + bool hasInsertion = false; // if there is insertion, do not perform SSAFRE + // because SSA form has not been updated + for (MeOccur *occ : allOccs) { + switch (occ->GetOccType()) { + case kOccReal: { + auto *realOcc = static_cast(occ); + if (!realOcc->IsReload()) { + realOcc->SetIsReload(false); + realOcc->SetIsSave(false); + realOcc->SetClassID(0); + realOcc->SetDef(nullptr); + newAllOccs.push_back(realOcc); + ++realOccCnt; + } + break; + } + case kOccPhiopnd: { + auto *phiOpnd = static_cast(occ); + if (phiOpnd->GetDefPhiOcc()->IsWillBeAvail()) { + MeOccur *defOcc = phiOpnd->GetDef(); + if (defOcc != nullptr && defOcc->GetOccType() == kOccInserted && !phiOpnd->IsPhiOpndReload()) { + hasInsertion = true; + break; + } + } + phiOpnd->SetIsProcessed(false); + phiOpnd->SetHasRealUse(false); + phiOpnd->SetIsInsertedOcc(false); + phiOpnd->SetIsPhiOpndReload(false); + phiOpnd->SetClassID(0); + phiOpnd->SetDef(nullptr); + newAllOccs.push_back(phiOpnd); + break; + } + case kOccPhiocc: { + auto *phiOcc = static_cast(occ); + phiOcc->SetIsDownSafe(false); + phiOcc->SetIsCanBeAvail(true); + phiOcc->SetIsLater(false); + phiOcc->SetIsExtraneous(false); + phiOcc->SetIsRemoved(false); + phiOcc->SetClassID(0); + newAllOccs.push_back(phiOcc); + break; + } + case kOccExit: + case kOccMembar: + newAllOccs.push_back(occ); + break; + case kOccUse: + break; + default: + ASSERT(false, "should not be here"); + } + if (hasInsertion) { + break; + } + } + if (hasInsertion || realOccCnt <= 1) { + return; + } + allOccs = newAllOccs; + Rename1StmtFre(); + Rename2(); + ComputeFullyAvail(); + Finalize1(); + Finalize2(); + CodeMotion(); +} +} // namespace maple diff --git a/src/maple_me/src/me_stmt_pre.cpp b/src/maple_me/src/me_stmt_pre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..274ad5b31141ef8806f7a864b58d739b550f55ce --- /dev/null +++ b/src/maple_me/src/me_stmt_pre.cpp @@ -0,0 +1,1068 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "utils.h" +#include "me_stmt_pre.h" +#include "me_dominance.h" +#include "me_option.h" +#include "me_ssa_update.h" +// Note: after the movement of assignments, some phi nodes that used to be dead +// can become live. Before we run another round of dead store elimination, we +// should NOT trust the isLive flag in phi nodes. +// accumulate the BBs that are in the iterated dominance frontiers of bb in +// the set dfset, visiting each BB only once +namespace maple { +void MeStmtPre::GetIterDomFrontier(BB &bb, MapleSet &dfSet, std::vector &visitedMap) { + CHECK_FATAL(bb.GetBBId() < visitedMap.size(), "index out of range in MeStmtPre::GetIterDomFrontier"); + if (visitedMap[bb.GetBBId()]) { + return; + } + visitedMap[bb.GetBBId()] = true; + for (BBId frontierBBId : dom->GetDomFrontier(bb.GetBBId())) { + dfSet.insert(dom->GetDtDfnItem(frontierBBId)); + BB *frontierBB = GetBB(frontierBBId); + GetIterDomFrontier(*frontierBB, dfSet, visitedMap); + } +} + +void MeStmtPre::CodeMotion() { + for (MeOccur *occ : allOccs) { + switch (occ->GetOccType()) { + case kOccReal: { + auto *realOcc = static_cast(occ); + if (realOcc->IsSave()) { + CHECK_FATAL(realOcc->IsReload() == false, "should be false"); + } else if (realOcc->IsReload()) { + realOcc->GetBB()->RemoveMeStmt(realOcc->GetMeStmt()); + if (realOcc->GetOpcodeOfMeStmt() == OP_dassign) { + auto *dass = static_cast(realOcc->GetMeStmt()); + OStIdx ostIdx = dass->GetVarLHS()->GetOStIdx(); + if (candsForSSAUpdate.find(ostIdx) == candsForSSAUpdate.end()) { + candsForSSAUpdate[ostIdx] = + ssaPreMemPool->New>(std::less(), ssaPreAllocator.Adapter()); + } + } else if (realOcc->GetOpcodeOfMeStmt() == OP_callassigned) { + auto *call = static_cast(realOcc->GetMeStmt()); + if (call->GetAssignedLHS() != nullptr) { + CHECK_FATAL(call->GetAssignedLHS()->GetMeOp() == kMeOpVar, "should be var"); + auto *var = static_cast(call->GetAssignedLHS()); + OStIdx ostIdx = var->GetOStIdx(); + if (candsForSSAUpdate.find(ostIdx) == candsForSSAUpdate.end()) { + candsForSSAUpdate[ostIdx] = + ssaPreMemPool->New>(std::less(), ssaPreAllocator.Adapter()); + } + } + } + } + break; + } + case kOccPhiopnd: { + auto *phiOpnd = static_cast(occ); + if (!phiOpnd->GetDefPhiOcc()->IsWillBeAvail()) { + break; + } + MeOccur *defOcc = phiOpnd->GetDef(); + if (defOcc->GetOccType() == kOccInserted) { + if (!phiOpnd->IsPhiOpndReload()) { + auto *insertedOcc = static_cast(defOcc); + if (insertedOcc->GetOpcodeOfMeStmt() == OP_dassign) { + auto *dass = static_cast(insertedOcc->GetMeStmt()); + OStIdx ostIdx = dass->GetVarLHS()->GetOStIdx(); + if (candsForSSAUpdate.find(ostIdx) == candsForSSAUpdate.end()) { + MapleSet *bbSet = + ssaPreMemPool->New>(std::less(), ssaPreAllocator.Adapter()); + bbSet->insert(occ->GetBB()->GetBBId()); + candsForSSAUpdate[ostIdx] = bbSet; + } else { + candsForSSAUpdate[ostIdx]->insert(occ->GetBB()->GetBBId()); + } + // create a new LHS for the dassign in insertedOcc->GetMeStmt() + VarMeExpr *newVarVersion = irMap->CreateVarMeExprVersion(*dass->GetVarLHS()); + dass->UpdateLHS(*newVarVersion); + } else if (insertedOcc->GetOpcodeOfMeStmt() == OP_callassigned) { + auto *call = static_cast(insertedOcc->GetMeStmt()); + if (call->GetAssignedLHS() != nullptr) { + CHECK_FATAL(call->GetAssignedLHS()->GetMeOp() == kMeOpVar, "should be var"); + auto *var = static_cast(call->GetAssignedLHS()); + OStIdx ostIdx = var->GetOStIdx(); + if (candsForSSAUpdate.find(ostIdx) == candsForSSAUpdate.end()) { + MapleSet *bbSet = + ssaPreMemPool->New>(std::less(), ssaPreAllocator.Adapter()); + bbSet->insert(occ->GetBB()->GetBBId()); + candsForSSAUpdate[ostIdx] = bbSet; + } else { + candsForSSAUpdate[ostIdx]->insert(occ->GetBB()->GetBBId()); + } + VarMeExpr *newVarVersion = irMap->CreateVarMeExprVersion(*var); + call->GetMustDefList()->front().UpdateLHS(*newVarVersion); + } + } + if (insertedOcc->GetOpcodeOfMeStmt() == OP_intrinsiccallwithtype && + (static_cast(insertedOcc->GetMeStmt())->GetIntrinsic() == + INTRN_JAVA_CLINIT_CHECK)) { + BB *insertBB = insertedOcc->GetBB(); + // insert at earlist point in BB, but after statements required + // to be first statement in BB + MeStmt *curStmt = to_ptr(insertBB->GetMeStmts().begin()); + while (curStmt && (curStmt->GetOp() == OP_catch || curStmt->GetOp() == OP_try || + curStmt->GetOp() == OP_comment)) { + curStmt = curStmt->GetNext(); + } + if (curStmt == nullptr) { + insertBB->AddMeStmtLast(insertedOcc->GetMeStmt()); + } else { + insertBB->InsertMeStmtBefore(curStmt, insertedOcc->GetMeStmt()); + } + } else { + insertedOcc->GetBB()->InsertMeStmtLastBr(insertedOcc->GetMeStmt()); + } + } + } + break; + } + case kOccPhiocc: + case kOccExit: + case kOccUse: + case kOccMembar: + break; + default: + ASSERT(false, "should not be here"); + } + } +} + +void MeStmtPre::Finalize1() { + PreWorkCand *workCand = GetWorkCand(); + std::vector availDefVec(classCount, nullptr); + // traversal in preoder DT + for (MeOccur *occ : allOccs) { + uint32 classx = static_cast(occ->GetClassID()); + switch (occ->GetOccType()) { + case kOccPhiocc: { + auto *phiOcc = static_cast(occ); + if (phiOcc->IsWillBeAvail()) { + availDefVec[classx] = phiOcc; + } + break; + } + case kOccReal: { + MeOccur *availDef = availDefVec[classx]; + auto *realOcc = static_cast(occ); + if (availDef == nullptr || !availDef->IsDominate(dom, occ)) { + realOcc->SetIsReload(false); + availDefVec[classx] = realOcc; + } else { + realOcc->SetIsReload(true); + ASSERT(!realOcc->IsSave(), "real occ with isSave cannot be set isReload"); + realOcc->SetDef(availDefVec[classx]); + CHECK_NULL_FATAL(realOcc->GetDef()); + } + break; + } + case kOccPhiopnd: { + // we assume one phiOpnd has only one phiOcc use because critical edge split the blocks + auto *phiOpnd = static_cast(occ); + MePhiOcc *phiOcc = phiOpnd->GetDefPhiOcc(); + if (phiOcc->IsWillBeAvail()) { + if (phiOpnd->IsOkToInsert()) { + // insert the current expression at the end of the block containing phiOpnd + if (phiOpnd->GetBB()->GetSucc().size() > 1) { + CHECK_FATAL(!workCand->Redo2HandleCritEdges(), "Finalize1: insertion at critical edge; aborting"); + workCand->SetRedo2HandleCritEdges(true); + if (GetSSAPreDebug()) { + mirModule->GetOut() << "<<<<< Re-doing this candidate due to existence of critical edge >>>>>\n"; + } + return; + } + MeStmt *insertedStmt = phiOpnd->GetCurrentMeStmt(); + ASSERT(insertedStmt != nullptr, "NYI"); + MeInsertedOcc *insertedOcc = + perCandMemPool->New(static_cast(nullptr), insertedStmt, phiOpnd->GetBB()); + insertedOcc->SetClassID(classCount++); + phiOpnd->SetDef(insertedOcc); + phiOpnd->SetClassID(insertedOcc->GetClassID()); + if (workCand->GetPUIdx() != GetPUIdx()) { + ASSERT(!workCand->HasLocalOpnd(), "candidate with local opnd cannot be inserted outside its PU"); + workCand->SetPUIdx(0); + } + phiOpnd->SetIsInsertedOcc(true); + } else { + phiOpnd->SetDef(availDefVec[classx]); + } + } + break; + } + case kOccExit: + case kOccUse: + case kOccMembar: + break; + default: + ASSERT(false, "should not be here"); + } + } + if (GetSSAPreDebug()) { + PreWorkCand *curCand = workCand; + mirModule->GetOut() << "========ssapre candidate " << curCand->GetIndex() + << " after Finalize1===================\n"; + for (auto it = phiOccs.begin(); it != phiOccs.end(); ++it) { + MePhiOcc *phiOcc = *it; + if (phiOcc->IsWillBeAvail()) { + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + ASSERT(phiOpnd->GetDef(), "EPhiFinalizer::DumpFinalize1: phiopndocc cannot have no def"); + MeOccur *defOcc = phiOpnd->GetDef(); + if (defOcc->GetOccType() == kOccInserted) { + auto *realDefOcc = static_cast(defOcc); + phiOpnd->Dump(*irMap); + mirModule->GetOut() << " was inserted by "; + realDefOcc->Dump(*irMap); + mirModule->GetOut() << "\n"; + } + } + } + } + } +} + +bool MeStmtPre::AllVarsSameVersion(MeRealOcc *realOcc1, MeRealOcc *realOcc2) { + MeStmt *stmt1 = realOcc1->GetMeStmt(); + Opcode op = stmt1->GetOp(); + if (op == OP_intrinsiccallwithtype) { + return true; + } + if (op == OP_dassign && realOcc1->GetMeExpr() != realOcc2->GetMeExpr()) { + return false; + } + MeStmt *stmt2 = realOcc2->GetMeStmt(); + for (size_t i = 0; i < stmt1->NumMeStmtOpnds(); ++i) { + if (stmt1->GetOpnd(i) != stmt2->GetOpnd(i)) { + return false; + } + } + return true; +} + +// collect meExpr's variables and put them into varvec; +// varvec can only store RegMeExpr and VarMeExpr +void MeStmtPre::CollectVarForMeStmt(MeStmt *meStmt, MeExpr *meExpr, std::vector &varVec) { + switch (meStmt->GetOp()) { + case OP_assertnonnull: { + auto *unaryStmt = static_cast(meStmt); + if (unaryStmt->GetOpnd()->GetMeOp() == kMeOpVar || unaryStmt->GetOpnd()->GetMeOp() == kMeOpReg) { + varVec.push_back(unaryStmt->GetOpnd()); + } + break; + } + case OP_dassign: { + auto *dassMeStmt = static_cast(meStmt); + if (dassMeStmt->GetRHS()->GetMeOp() == kMeOpVar || dassMeStmt->GetRHS()->GetMeOp() == kMeOpReg) { + varVec.push_back(dassMeStmt->GetRHS()); + } + if (meExpr) { + CHECK_FATAL(meExpr->GetMeOp() == kMeOpVar, "CollectVarForMeStmt:bad meExpr field in realocc node"); + varVec.push_back(meExpr); + } + break; + } + case OP_intrinsiccallwithtype: + case OP_intrinsiccall: + case OP_callassigned: { + auto *nStmt = static_cast(meStmt); + for (size_t i = 0; i < nStmt->NumMeStmtOpnds(); ++i) + if (nStmt->GetOpnds()[i]->GetMeOp() == kMeOpVar || nStmt->GetOpnds()[i]->GetMeOp() == kMeOpReg) { + varVec.push_back(nStmt->GetOpnds()[i]); + } + break; + } + default: + CHECK_FATAL(false, "MeStmtEPre::CollectVarForCand: NYI"); + } +} + +void MeStmtPre::CollectVarForCand(MeRealOcc *realOcc, std::vector &varVec) { + CollectVarForMeStmt(realOcc->GetMeStmt(), realOcc->GetMeExpr(), varVec); +} + +MeStmt *MeStmtPre::CopyMeStmt(MeStmt &meStmt) { + switch (meStmt.GetOp()) { + case OP_assertnonnull: { + auto *unaryStmt = static_cast(&meStmt); + UnaryMeStmt *newUnaryStmt = irMap->New(unaryStmt); + return newUnaryStmt; + } + case OP_dassign: { + auto *dass = static_cast(&meStmt); + DassignMeStmt *newDass = irMap->New(&irMap->GetIRMapAlloc(), dass); + return newDass; + } + case OP_intrinsiccall: + case OP_intrinsiccallwithtype: { + auto *intrnStmt = static_cast(&meStmt); + IntrinsiccallMeStmt *newIntrnStmt = irMap->NewInPool(intrnStmt); + return newIntrnStmt; + } + case OP_callassigned: { + auto *callAss = static_cast(&meStmt); + CallMeStmt *newCallAss = irMap->NewInPool(callAss); + return newCallAss; + } + default: + CHECK_FATAL(false, "MeStmtEPre::CopyMeStmt: NYI"); + } +} + +// for each variable in realz that is defined by a phi, replace it by the jth +// phi opnd; the tagged lhs is returned in the reference parameter lhsvar +MeStmt *MeStmtPre::PhiOpndFromRes4Stmt(MeRealOcc *realZ, size_t j, MeExpr *&lhsVar) { + MeOccur *defZ = realZ->GetDef(); + CHECK_FATAL(defZ, "must be def by phiocc"); + CHECK_FATAL(defZ->GetOccType() == kOccPhiocc, "must be def by phiocc"); + MeStmt *stmtQ = CopyMeStmt(utils::ToRef(realZ->GetMeStmt())); + lhsVar = realZ->GetMeExpr(); + BB *ephiBB = defZ->GetBB(); + CHECK_FATAL(stmtQ != nullptr, "nullptr check"); + switch (stmtQ->GetOp()) { + case OP_assertnonnull: { + auto *unaryStmtQ = static_cast(stmtQ); + MeExpr *retOpnd = GetReplaceMeExpr(unaryStmtQ->GetOpnd(), ephiBB, j); + if (retOpnd != nullptr) { + unaryStmtQ->SetMeStmtOpndValue(retOpnd); + } + break; + } + case OP_dassign: { + auto *dassQ = static_cast(stmtQ); + MeExpr *retOpnd = GetReplaceMeExpr(dassQ->GetRHS(), ephiBB, j); + if (retOpnd != nullptr) { + dassQ->SetRHS(retOpnd); + } + retOpnd = GetReplaceMeExpr(realZ->GetMeExpr(), ephiBB, j); + if (retOpnd != nullptr) { + lhsVar = retOpnd; + } + break; + } + case OP_intrinsiccall: + case OP_intrinsiccallwithtype: + case OP_callassigned: { + auto *nStmtQ = static_cast(stmtQ); + for (size_t i = 0; i < nStmtQ->NumMeStmtOpnds(); ++i) { + MeExpr *retOpnd = GetReplaceMeExpr(nStmtQ->GetOpnds()[i], ephiBB, j); + if (retOpnd != nullptr) { + nStmtQ->GetOpnds()[i] = retOpnd; + } + } + break; + } + default: + ASSERT(false, "MeStmtPre::PhiOpndFromRes4Stmt: NYI"); + } + return stmtQ; +} + +void MeStmtPre::Rename2() { + PreWorkCand *workCand = GetWorkCand(); + while (!rename2Set.empty()) { + MapleSet::iterator it = rename2Set.begin(); + MeRealOcc *realOcc = workCand->GetRealOcc(*it); + rename2Set.erase(it); + MeOccur *defOcc = realOcc->GetDef(); + CHECK_FATAL(defOcc, "should be def by phiocc"); + CHECK_FATAL(defOcc->GetOccType() == kOccPhiocc, "should be def by phiocc"); + auto *defPhiOcc = static_cast(defOcc); + MapleVector &phiOpnds = defPhiOcc->GetPhiOpnds(); + for (size_t i = 0; i < phiOpnds.size(); ++i) { + MePhiOpndOcc *phiOccOpnd = phiOpnds[i]; + if (!phiOccOpnd->IsProcessed()) { + phiOccOpnd->SetIsProcessed(true); + MeExpr *varY = nullptr; + MeStmt *stmtY = PhiOpndFromRes4Stmt(realOcc, i, varY); + stmtY->SetBB(phiOccOpnd->GetBB()); + phiOccOpnd->SetCurrentMeStmt(*stmtY); // stmtY might be inserted at the end of the block + MeOccur *defX = phiOccOpnd->GetDef(); + if (defX == nullptr) { + continue; + } + if (defX->GetOccType() == kOccReal) { + auto *realDefX = static_cast(defX); + std::vector varVecX; + std::vector varVecY; + CollectVarForCand(realDefX, varVecX); + CollectVarForMeStmt(stmtY, varY, varVecY); + CHECK_FATAL(varVecX.size() == varVecY.size(), "vector size should be the same"); + bool hasSameVersion = true; + size_t checkLimit = varVecY.size(); + if (varY != nullptr) { + if (varVecY[checkLimit - 1] == static_cast(stmtY)->GetLHS()) { + --checkLimit; + } + } + for (size_t j = 0; j < checkLimit; ++j) { + if (varVecX[j] != varVecY[j]) { + hasSameVersion = false; + } + } + if (!hasSameVersion) { + phiOccOpnd->SetDef(nullptr); + phiOccOpnd->SetHasRealUse(false); + } + } else if (defX->GetOccType() == kOccPhiocc) { + std::vector varVecY; + bool allDom = true; + CollectVarForMeStmt(stmtY, varY, varVecY); + size_t checkLimit = varVecY.size(); + if (varY != nullptr) { + if (varVecY[checkLimit - 1] == static_cast(stmtY)->GetLHS()) { + --checkLimit; + } + } + for (size_t k = 0; k < checkLimit; ++k) { + if (!DefVarDominateOcc(varVecY[k], defX)) { + allDom = false; + } + } + if (allDom) { + // create a realOcc and add to rename2 set + MeRealOcc *occY = perCandMemPool->New(stmtY, 0, varY); + occY->SetPosition(workCand->GetRealOccs().size()); + workCand->GetRealOccs().push_back(occY); + occY->SetDef(defX); + occY->SetClassID(defX->GetClassID()); + rename2Set.insert(occY->GetPosition()); + if (GetSSAPreDebug()) { + mirModule->GetOut() << "--- rename2 adds to rename2Set manufactured "; + occY->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + } else { + phiOccOpnd->SetDef(nullptr); + phiOccOpnd->SetHasRealUse(false); + auto *phiDefX = static_cast(defX); + phiDefX->SetIsDownSafe(false); + } + } + } + } + } + if (GetSSAPreDebug()) { + PreWorkCand *curCand = workCand; + mirModule->GetOut() << "========ssapre candidate " << curCand->GetIndex() << " after rename2===================\n"; + for (MeOccur *occ : allOccs) { + occ->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + } +} + +// Df phis are computed into the df_phis set; Var Phis in the var_phis set +void MeStmtPre::ComputeVarAndDfPhis() { + varPhiDfns.clear(); + dfPhiDfns.clear(); + PreWorkCand *workCand = GetWorkCand(); + const MapleVector &realOccList = workCand->GetRealOccs(); + CHECK_FATAL(!dom->IsBBVecEmpty(), "size to be allocated is 0"); + for (auto it = realOccList.begin(); it != realOccList.end(); ++it) { + MeRealOcc *realOcc = *it; + if (realOcc->GetOccType() == kOccMembar) { + continue; + } + BB *defBB = realOcc->GetMeStmt()->GetBB(); + std::vector visitedMap(dom->GetBBVecSize(), false); + GetIterDomFrontier(*defBB, dfPhiDfns, visitedMap); + MeStmt *stmt = realOcc->GetMeStmt(); + switch (stmt->GetOp()) { + case OP_assertnonnull: { + auto *unaryStmt = static_cast(stmt); + SetVarPhis(unaryStmt->GetOpnd()); + break; + } + case OP_dassign: { + auto *dassMeStmt = static_cast(stmt); + SetVarPhis(dassMeStmt->GetRHS()); + SetVarPhis(realOcc->GetMeExpr()); + break; + } + case OP_intrinsiccall: + case OP_intrinsiccallwithtype: + case OP_callassigned: { + auto *nStmt = static_cast(stmt); + for (size_t i = 0; i < nStmt->NumMeStmtOpnds(); ++i) { + SetVarPhis(nStmt->GetOpnds()[i]); + } + break; + } + default: + CHECK_FATAL(false, "NYI"); + } + } +} + +// Based on ssapre->workCand's realOccs and dfPhiDfns (which will privides all +// the inserted phis) and the mapped set in useOccurMap, +// create the phi, phiopnd occ nodes and use_occ nodes; link them all +// up in order of dt_preorder in ssapre->allOccs; the phi occ nodes are in +// addition provided in order of dt_preorder in ssapre->phiOccs. +// When a real_occ has uses before it in its bb, ignore (do not insert) +// the real_occ. +void MeStmtPre::CreateSortedOccs() { + // get set of bb dfns that contain uses if candidate is dassign + MapleSet *useDfns; + PreWorkCand *workCand = GetWorkCand(); + auto *stmtWkCand = static_cast(workCand); + if (stmtWkCand->GetTheMeStmt()->GetOp() == OP_dassign && !stmtWkCand->LHSIsFinal()) { + VarMeExpr *lhsVar = static_cast(stmtWkCand->GetTheMeStmt())->GetVarLHS(); + OStIdx ostIdx = lhsVar->GetOStIdx(); + MapleMap*>::iterator uMapIt = useOccurMap.find(ostIdx); + CHECK_FATAL(uMapIt != useOccurMap.end(), "MeStmtPre::CreateSortedOccs: missing entry in useOccurMap"); + useDfns = uMapIt->second; + } else { + // create empty MapleSet to be pointed to by use_dfns + useDfns = perCandMemPool->New>(perCandAllocator.Adapter()); + } + // merge varPhiDfns to dfPhiDfns + dfPhiDfns.insert(varPhiDfns.begin(), varPhiDfns.end()); + // form phiopnd_dfns + std::multiset phiOpndDfns; + for (uint32 dfn : dfPhiDfns) { + BBId bbId = dom->GetDtPreOrderItem(dfn); + BB *bb = GetBB(bbId); + CHECK_FATAL(bb != nullptr, "GetBB error"); + for (BB *pred : bb->GetPred()) { + phiOpndDfns.insert(dom->GetDtDfnItem(pred->GetBBId())); + } + } + std::unordered_map> bb2PhiOpndMap; + MapleVector::iterator realOccIt = workCand->GetRealOccs().begin(); + MapleVector::iterator exitOccIt = exitOccs.begin(); + auto phiDfnIt = dfPhiDfns.begin(); + auto phiOpndDfnIt = phiOpndDfns.begin(); + auto useDfnIt = useDfns->begin(); + MeOccur *nextUseOcc = nullptr; + if (useDfnIt != useDfns->end()) { + CHECK_NULL_FATAL(GetBB(dom->GetDtPreOrderItem(*useDfnIt))); + nextUseOcc = perCandMemPool->New(kOccUse, 0, GetBB(dom->GetDtPreOrderItem(*useDfnIt)), nullptr); + } + MeRealOcc *nextRealOcc = nullptr; + if (realOccIt != workCand->GetRealOccs().end()) { + nextRealOcc = *realOccIt; + } + MeOccur *nextExitOcc = nullptr; + if (exitOccIt != exitOccs.end()) { + nextExitOcc = *exitOccIt; + } + MePhiOcc *nextPhiOcc = nullptr; + if (phiDfnIt != dfPhiDfns.end()) { + CHECK_NULL_FATAL(GetBB(dom->GetDtPreOrderItem(*phiDfnIt))); + nextPhiOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)), &perCandAllocator); + } + MePhiOpndOcc *nextPhiOpndOcc = nullptr; + if (phiOpndDfnIt != phiOpndDfns.end()) { + nextPhiOpndOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiOpndDfnIt))); + std::unordered_map>::iterator it = + bb2PhiOpndMap.find(dom->GetDtPreOrderItem(*phiOpndDfnIt)); + if (it == bb2PhiOpndMap.end()) { + std::forward_list newList = { nextPhiOpndOcc }; + CHECK(*phiOpndDfnIt < dom->GetDtPreOrderSize(), "index out of range in SSAPre::CreateSortedOccs"); + bb2PhiOpndMap[dom->GetDtPreOrderItem(*phiOpndDfnIt)] = newList; + } else { + it->second.push_front(nextPhiOpndOcc); + } + } + bool realOccInserted = false; + MeOccur *pickedOcc = nullptr; // the next picked occ in order of preorder traveral of dominator tree + do { + pickedOcc = nullptr; + // the 5 kinds of occ must be checked in this order, so it will be right + // if more than 1 has the same dfn + if (nextPhiOcc != nullptr) { + pickedOcc = nextPhiOcc; + } + if (nextRealOcc && (pickedOcc == nullptr || + dom->GetDtDfnItem(nextRealOcc->GetBB()->GetBBId()) < dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextRealOcc; + } + if (nextUseOcc != nullptr && (pickedOcc == nullptr || + dom->GetDtDfnItem(nextUseOcc->GetBB()->GetBBId()) < dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextUseOcc; + } + if (nextExitOcc && (pickedOcc == nullptr || + dom->GetDtDfnItem(nextExitOcc->GetBB()->GetBBId()) < dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextExitOcc; + } + if (nextPhiOpndOcc && (pickedOcc == nullptr || + *phiOpndDfnIt < dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextPhiOpndOcc; + } + if (pickedOcc != nullptr) { + allOccs.push_back(pickedOcc); + switch (pickedOcc->GetOccType()) { + case kOccUse: { + // get the next use occ + ++useDfnIt; + if (useDfnIt != useDfns->end()) { + CHECK_NULL_FATAL(GetBB(dom->GetDtPreOrderItem(*useDfnIt))); + nextUseOcc = perCandMemPool->New(kOccUse, 0, GetBB(dom->GetDtPreOrderItem(*useDfnIt)), nullptr); + } else { + nextUseOcc = nullptr; + } + break; + } + case kOccReal: + case kOccMembar: + // get the next real occ + ++realOccIt; + if (realOccIt != workCand->GetRealOccs().end()) { + nextRealOcc = *realOccIt; + } else { + nextRealOcc = nullptr; + } + realOccInserted = true; + break; + case kOccExit: + ++exitOccIt; + if (exitOccIt != exitOccs.end()) { + nextExitOcc = *exitOccIt; + } else { + nextExitOcc = nullptr; + } + break; + case kOccPhiocc: + phiOccs.push_back(static_cast(pickedOcc)); + ++phiDfnIt; + if (phiDfnIt != dfPhiDfns.end()) { + CHECK_FATAL(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)) != nullptr, + "GetBB return null in SSAPre::CreateSortedOccs"); + nextPhiOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)), &perCandAllocator); + } else { + nextPhiOcc = nullptr; + } + break; + case kOccPhiopnd: + ++phiOpndDfnIt; + if (phiOpndDfnIt != phiOpndDfns.end()) { + nextPhiOpndOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiOpndDfnIt))); + std::unordered_map>::iterator it = + bb2PhiOpndMap.find(dom->GetDtPreOrderItem(*phiOpndDfnIt)); + if (it == bb2PhiOpndMap.end()) { + std::forward_list newList = { nextPhiOpndOcc }; + bb2PhiOpndMap[dom->GetDtPreOrderItem(*phiOpndDfnIt)] = newList; + } else { + it->second.push_front(nextPhiOpndOcc); + } + } else { + nextPhiOpndOcc = nullptr; + } + break; + default: + ASSERT(false, "CreateSortedOccs: unexpected occty"); + } + } + } while (pickedOcc != nullptr); + // if no real occ inserted, no more work for this workCand + if (!realOccInserted) { + workCand->GetRealOccs().clear(); + } + // initialize phiOpnds vector in each MePhiOcc node and defPhiOcc field in + // each MePhiOpndOcc node + for (MePhiOcc *phiOcc : phiOccs) + for (BB *pred : phiOcc->GetBB()->GetPred()) { + MePhiOpndOcc *phiOpndOcc = bb2PhiOpndMap[pred->GetBBId()].front(); + phiOcc->AddPhiOpnd(*phiOpndOcc); + phiOpndOcc->SetDefPhiOcc(*phiOcc); + bb2PhiOpndMap[pred->GetBBId()].pop_front(); + } + if (GetSSAPreDebug()) { + mirModule->GetOut() << "========ssapre candidate " << workCand->GetIndex() + << " after phi insert===================\n"; + for (MeOccur *occ : allOccs) { + occ->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + } +} + +void MeStmtPre::ConstructUseOccurMapExpr(uint32 bbDfn, MeExpr *x) { + if (x->GetMeOp() == kMeOpVar) { + OStIdx ostIdx = static_cast(x)->GetOStIdx(); + MapleMap*>::iterator mapIt; + mapIt = useOccurMap.find(ostIdx); + if (mapIt == useOccurMap.end()) { + return; + } + MapleSet *bbDfnSet = mapIt->second; + bbDfnSet->insert(bbDfn); + return; + } + for (int32 i = 0; i < x->GetNumOpnds(); ++i) { + ConstructUseOccurMapExpr(bbDfn, x->GetOpnd(i)); + } +} + +void MeStmtPre::ConstructUseOccurMap() { + for (PreWorkCand *wkCand : workList) { + auto *stmtWkCand = static_cast(wkCand); + if (stmtWkCand->GetTheMeStmt()->GetOp() != OP_dassign) { + continue; + } + if (stmtWkCand->LHSIsFinal()) { + continue; + } + VarMeExpr *lhsVar = static_cast(stmtWkCand->GetTheMeStmt())->GetVarLHS(); + OStIdx ostIdx = lhsVar->GetOStIdx(); + if (useOccurMap.find(ostIdx) == useOccurMap.end()) { + // add an entry for ostIdx + useOccurMap[ostIdx] = ssaPreMemPool->New>(ssaPreAllocator.Adapter()); + } + } + // do a pass over the program + const MapleVector &preOrderDt = dom->GetDtPreOrder(); + for (size_t i = 0; i < preOrderDt.size(); ++i) { + BB *bb = func->GetAllBBs().at(preOrderDt[i]); + for (auto &stmt : bb->GetMeStmts()) { + for (size_t j = 0; j < stmt.NumMeStmtOpnds(); ++j) { + ConstructUseOccurMapExpr(i, stmt.GetOpnd(j)); + } + } + } +} + +// create a new realOcc based on meStmt +PreStmtWorkCand *MeStmtPre::CreateStmtRealOcc(MeStmt &meStmt, int seqStmt) { + uint32 hashIdx = PreStmtWorkCand::ComputeStmtWorkCandHashIndex(meStmt); + auto *wkCand = static_cast(PreWorkCand::GetWorkcandFromIndex(hashIdx)); + while (wkCand != nullptr) { + MeStmt *x = wkCand->GetTheMeStmt(); + ASSERT(x != nullptr, "CreateStmtRealOcc: found workcand with theMeStmt as nullptr"); + if (x->IsTheSameWorkcand(meStmt)) { + break; + } + wkCand = static_cast(wkCand->GetNext()); + } + MeExpr *meExpr = nullptr; + if (meStmt.GetOp() == OP_dassign) { + auto &dass = static_cast(meStmt); + MapleStack *pStack = versionStackVec.at(dass.GetVarLHS()->GetOStIdx()); + meExpr = pStack->top(); + } + MeRealOcc *newOcc = ssaPreMemPool->New(&meStmt, seqStmt, meExpr); + if (wkCand != nullptr) { + wkCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + return wkCand; + } + // workCand not yet created; create a new one and add to workList + wkCand = ssaPreMemPool->New(&ssaPreAllocator, workList.size(), &meStmt, GetPUIdx()); + wkCand->SetHasLocalOpnd(true); // dummy + workList.push_back(wkCand); + wkCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + // add to bucket at workcandHashTable[hashIdx] + wkCand->SetNext(*PreWorkCand::GetWorkcandFromIndex(hashIdx)); + PreWorkCand::SetWorkCandAt(hashIdx, *wkCand); + return wkCand; +} + +void MeStmtPre::VersionStackChiListUpdate(const MapleMap &chiList) { + for (auto it = chiList.begin(); it != chiList.end(); ++it) { + const OriginalSt *ost = ssaTab->GetOriginalStFromID(it->second->GetLHS()->GetOStIdx()); + if (!ost->IsSymbolOst() || ost->GetIndirectLev() != 0) { + continue; + } + MapleStack *pStack = versionStackVec.at(it->second->GetLHS()->GetOStIdx()); + pStack->push(it->second->GetLHS()); + } +} + +// verify that there is no prior use of lhsVar before stmt in its BB +static bool NoPriorUseInBB(const VarMeExpr *lhsVar, MeStmt *defStmt) { + for (MeStmt *stmt = defStmt->GetPrev(); stmt != nullptr; stmt = stmt->GetPrev()) { + for (size_t i = 0; i < stmt->NumMeStmtOpnds(); ++i) { + CHECK_FATAL(stmt->GetOpnd(i), "null ptr check"); + if (stmt->GetOpnd(i)->SymAppears(lhsVar->GetOStIdx())) { + return false; + } + } + } + return true; +} + +void MeStmtPre::BuildWorkListBB(BB *bb) { + if (bb == nullptr) { + return; + } + // record stack size for variable versions, used for stack pop up at return + std::vector curStackSizeVec; + curStackSizeVec.resize(versionStackVec.size()); + for (size_t i = 1; i < versionStackVec.size(); ++i) { + if (versionStackVec[i] == nullptr) { + continue; + } + curStackSizeVec[i] = versionStackVec[i]->size(); + } + // traverse var phi nodes to update versionStack + MapleMap &meVarPhiList = bb->GetMevarPhiList(); + for (auto it = meVarPhiList.begin(); it != meVarPhiList.end(); ++it) { + MeVarPhiNode *phiMeNode = it->second; + const OriginalSt *ost = ssaTab->GetOriginalStFromID(phiMeNode->GetLHS()->GetOStIdx()); + if (!ost->IsSymbolOst() || ost->GetIndirectLev() != 0) { + continue; + } + MapleStack *pStack = versionStackVec.at(phiMeNode->GetLHS()->GetOStIdx()); + pStack->push(phiMeNode->GetLHS()); + } + // traverse statements + uint32 seqStmt = 0; + for (auto &stmt : bb->GetMeStmts()) { + ++seqStmt; + switch (stmt.GetOp()) { + case OP_jstry: + case OP_jscatch: + case OP_finally: + case OP_endtry: + case OP_cleanuptry: + case OP_try: + case OP_catch: + case OP_goto: + case OP_comment: + case OP_brtrue: + case OP_brfalse: + case OP_switch: + break; + case OP_membaracquire: + case OP_membarrelease: + case OP_membarstoreload: + case OP_membarstorestore: + CreateMembarOcc(stmt, seqStmt); + break; + case OP_gosub: + case OP_retsub: + case OP_throw: + case OP_return: + // CreateExitOcc(bb); + break; + case OP_iassign: { + auto &iass = static_cast(stmt); + VersionStackChiListUpdate(*iass.GetChiList()); + break; + } + case OP_maydassign: { + auto &maydStmt = static_cast(stmt); + VersionStackChiListUpdate(*maydStmt.GetChiList()); + break; + } + case OP_regassign: + case OP_eval: + case OP_decref: + case OP_decrefreset: + case OP_incref: + case OP_free: + case OP_syncenter: + case OP_syncexit: + case OP_assertlt: + case OP_assertge: + break; + case OP_call: + case OP_virtualcall: + case OP_virtualicall: + case OP_superclasscall: + case OP_interfacecall: + case OP_interfaceicall: + case OP_customcall: + case OP_polymorphiccall: + case OP_virtualcallassigned: + case OP_virtualicallassigned: + case OP_superclasscallassigned: + case OP_interfacecallassigned: + case OP_interfaceicallassigned: + case OP_customcallassigned: + case OP_polymorphiccallassigned: { + auto &callMeStmt = static_cast(stmt); + VersionStackChiListUpdate(*callMeStmt.GetChiList()); + break; + } + case OP_icall: + case OP_icallassigned: { + auto &icallMeStmt = static_cast(stmt); + VersionStackChiListUpdate(*icallMeStmt.GetChiList()); + break; + } + case OP_xintrinsiccall: + case OP_intrinsiccallassigned: + case OP_xintrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: { + auto &intrinStmt = static_cast(stmt); + VersionStackChiListUpdate(*intrinStmt.GetChiList()); + break; + } + case OP_assertnonnull: { + auto &unaryStmt = static_cast(stmt); + if (!unaryStmt.GetOpnd()->IsLeaf()) { + break; + } + CreateStmtRealOcc(stmt, seqStmt); + break; + } + case OP_dassign: { + auto &dassMeStmt = static_cast(stmt); + if (!MeOption::dassignPre || !dassMeStmt.GetRHS()->IsLeaf() || !dassMeStmt.GetChiList()->empty() || + dassMeStmt.NeedIncref() || + (dassMeStmt.GetRHS()->GetOp() == OP_regread && + static_cast(dassMeStmt.GetRHS())->GetRegIdx() == -kSregThrownval)) { + // update version stacks + MapleStack *pStack = versionStackVec.at(dassMeStmt.GetVarLHS()->GetOStIdx()); + pStack->push(dassMeStmt.GetVarLHS()); + VersionStackChiListUpdate(*dassMeStmt.GetChiList()); + break; + } + VarMeExpr *varMeExpr = dassMeStmt.GetVarLHS(); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varMeExpr->GetOStIdx()); + if (ost->IsFinal()) { + PreStmtWorkCand *stmtWkCand = CreateStmtRealOcc(stmt, seqStmt); + stmtWkCand->SetLHSIsFinal(true); + } else if (!dassMeStmt.GetRHS()->SymAppears(varMeExpr->GetOStIdx()) && dassMeStmt.GetRHS()->Pure()) { + if (NoPriorUseInBB(dassMeStmt.GetVarLHS(), &stmt)) { + CreateStmtRealOcc(stmt, seqStmt); + } + } else if (dassMeStmt.GetLHS()->IsUseSameSymbol(*dassMeStmt.GetRHS())) { + RemoveUnnecessaryDassign(&dassMeStmt); + } + // update version stacks + MapleStack *pStack = versionStackVec.at(dassMeStmt.GetVarLHS()->GetOStIdx()); + pStack->push(dassMeStmt.GetVarLHS()); + VersionStackChiListUpdate(*dassMeStmt.GetChiList()); + break; + } + case OP_intrinsiccallwithtype: { + auto &intrnStmt = static_cast(stmt); + VersionStackChiListUpdate(*intrnStmt.GetChiList()); + if (!MeOption::clinitPre) { + VersionStackChiListUpdate(*intrnStmt.GetChiList()); + break; + } + if (intrnStmt.GetIntrinsic() == INTRN_JAVA_CLINIT_CHECK) { + CreateStmtRealOcc(stmt, seqStmt); + } + break; + } + case OP_intrinsiccall: { + auto &intrnStmt = static_cast(stmt); + bool allOperandsAreLeaf = true; + for (size_t i = 0; i < intrnStmt.NumMeStmtOpnds(); ++i) { + if (!intrnStmt.GetOpnds()[i]->IsLeaf()) { + allOperandsAreLeaf = false; + break; + } + } + if (!allOperandsAreLeaf) { + break; + } + if (intrnStmt.GetIntrinsic() == INTRN_MPL_BOUNDARY_CHECK) { + CreateStmtRealOcc(stmt, seqStmt); + } + VersionStackChiListUpdate(*intrnStmt.GetChiList()); + break; + } + case OP_callassigned: { + auto &callAss = static_cast(stmt); + VersionStackChiListUpdate(*callAss.GetChiList()); + break; + } + default: + ASSERT(stmt.GetOp() == OP_comment, ""); + break; + } + if (kOpcodeInfo.IsCallAssigned(stmt.GetOp())) { + // update version stacks + MapleVector *mustDefList = stmt.GetMustDefList(); + if (!mustDefList->empty()) { + MeExpr *meLHS = mustDefList->front().GetLHS(); + if (meLHS->GetMeOp() == kMeOpVar) { + auto *lhsVar = static_cast(meLHS); + MapleStack *pStack = versionStackVec.at(lhsVar->GetOStIdx()); + pStack->push(lhsVar); + } + } + } + } + if (bb->GetAttributes(kBBAttrIsExit) || bb->GetAttributes(kBBAttrWontExit)) { + CreateExitOcc(bb); + } + // recurse on child BBs in dominator tree + const MapleSet &domChildren = dom->GetDomChildren(bb->GetBBId()); + for (auto bbIt = domChildren.begin(); bbIt != domChildren.end(); ++bbIt) { + BBId childBBId = *bbIt; + BuildWorkListBB(GetBB(childBBId)); + } + // pop the stacks back to their levels on entry + for (size_t i = 1; i < versionStackVec.size(); ++i) { + MapleStack *pStack = versionStackVec[i]; + if (pStack == nullptr) { + continue; + } + size_t curSize = curStackSizeVec[i]; + while (pStack->size() > curSize) { + pStack->pop(); + } + } +} + +void MeStmtPre::BuildWorkList() { + // initialize version stack + const MapleVector &originalStVec = ssaTab->GetOriginalStTable().GetOriginalStVector(); + for (size_t i = 1; i < originalStVec.size(); ++i) { + OriginalSt *ost = originalStVec[i]; + if (!ost->IsSymbolOst() || ost->GetIndirectLev() != 0) { + continue; + } + MapleStack *versStack = ssaPreMemPool->New>(ssaPreAllocator.Adapter()); + versStack->push(static_cast(irMap->GetOrCreateZeroVersionVarMeExpr(*ost))); + versionStackVec[ost->GetIndex()] = versStack; + } + BuildWorkListBB(func->GetCommonEntryBB()); +} + +void MeStmtPre::RemoveUnnecessaryDassign(DassignMeStmt *dssMeStmt) { + BB *bb = dssMeStmt->GetBB(); + bb->RemoveMeStmt(dssMeStmt); + OStIdx ostIdx = dssMeStmt->GetVarLHS()->GetOStIdx(); + MapleSet *bbSet = nullptr; + if (candsForSSAUpdate.find(ostIdx) == candsForSSAUpdate.end()) { + bbSet = ssaPreMemPool->New>(std::less(), ssaPreAllocator.Adapter()); + candsForSSAUpdate[ostIdx] = bbSet; + } else { + bbSet = candsForSSAUpdate[ostIdx]; + } + bbSet->insert(bb->GetBBId()); +} + +AnalysisResult *MeDoStmtPre::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom != nullptr, "dominance phase has problem"); + auto *irMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAP, func)); + ASSERT(irMap != nullptr, "irMap phase has problem"); + MeStmtPre ssaPre(func, *irMap, *dom, *NewMemPool(), *NewMemPool(), MeOption::stmtprePULimit); + if (DEBUGFUNC(func)) { + ssaPre.SetSSAPreDebug(true); + } + ssaPre.ApplySSAPRE(); + if (!ssaPre.GetCandsForSSAUpdate().empty()) { + MemPool *tmp = memPoolCtrler.NewMemPool("MeSSAUpdate"); + CHECK_FATAL(tmp != nullptr, "must be"); + MeSSAUpdate ssaUpdate(*func, *func->GetMeSSATab(), *dom, ssaPre.GetCandsForSSAUpdate(), *tmp); + ssaUpdate.Run(); + } + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "\n============== STMTPRE =============" << '\n'; + func->Dump(false); + } + return nullptr; +} +} // namespace maple diff --git a/src/maple_me/src/me_store_pre.cpp b/src/maple_me/src/me_store_pre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21a83d74f86c9d0a964e98001fc39c2fa09f01ce --- /dev/null +++ b/src/maple_me/src/me_store_pre.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "me_store_pre.h" + +namespace maple { +#define JAVALANG (mirModule->IsJavaModule()) + +// ================ Step 6: Code Motion ================ +void MeStorePre::CheckCreateCurTemp() { + if (curTemp != nullptr) { + return; + } + // try to use the same preg that LPRE used for the variable + auto mapIt = irMap->FindLpreTmpsItem(workCand->GetOst()->GetIndex()); + if (mapIt == irMap->GetLpreTmpsEnd()) { + curTemp = irMap->CreateRegMeExpr(workCand->GetTheVar()->GetPrimType()); + } else { + curTemp = mapIt->second; + } +} + +// Starting at bb's bottom, search for the definition of workCand->theOst and +// save its RHS in curTemp. Since the def must dominate, searching by ascending +// the dominator tree is sufficient. If the def is by a phi, call recursively +// for each phi operand and also insert phi for curTemp if needed. +// bbCurTempMap maps bb to cur_temp_version and is used to avoid re-processing +// each bb. The return value is the curTemp version that contains the RHS value +// at the entry to bb; +RegMeExpr *MeStorePre::EnsureRHSInCurTemp(BB *bb) { + CHECK_FATAL(bb != func->GetCommonEntryBB(), "EnsureRHSInCurTemp: cannot find earlier definition"); + // see if processed before + auto mapIt = bbCurTempMap.find(bb); + if (mapIt != bbCurTempMap.end()) { + return mapIt->second; + } + // traverse statements + auto &meStmts = bb->GetMeStmts(); + for (auto itStmt = meStmts.rbegin(); itStmt != meStmts.rend(); ++itStmt) { + if (itStmt->GetOp() == OP_dassign) { + auto *dass = static_cast(to_ptr(itStmt)); + if (dass->GetVarLHS()->GetOStIdx() != workCand->GetOst()->GetIndex()) { + continue; + } + if (enabledDebug) { + LogInfo::MapleLogger() << "EnsureRHSInCurTemp: found dassign at BB" << bb->GetBBId() << '\n'; + } + if (dass->GetRHS()->GetMeOp() == kMeOpReg && + static_cast(dass->GetRHS())->GetOstIdx() == curTemp->GetOstIdx()) { + return static_cast(dass->GetRHS()); + } + // create and insert regassign before dass + RegMeExpr *lhsReg = irMap->CreateRegMeExprVersion(*curTemp); + RegassignMeStmt *rass = irMap->CreateRegassignMeStmt(*lhsReg, *dass->GetRHS(), *bb); + rass->SetSrcPos(itStmt->GetSrcPosition()); + lhsReg->SetDefByStmt(*rass); + bb->InsertMeStmtBefore(dass, rass); + // change dass's rhs to lhsReg + dass->SetRHS(lhsReg); + bbCurTempMap[bb] = lhsReg; + return lhsReg; + } else if (kOpcodeInfo.IsCallAssigned(itStmt->GetOp())) { + MapleVector *mustDefList = itStmt->GetMustDefList(); + CHECK_NULL_FATAL(mustDefList); + if (!mustDefList->empty()) { + MeExpr *mdLHS = mustDefList->front().GetLHS(); + if (mdLHS->GetMeOp() != kMeOpVar) { + continue; + } + auto *lhsVar = static_cast(mdLHS); + if (lhsVar->GetOStIdx() != workCand->GetOst()->GetIndex()) { + continue; + } + if (enabledDebug) { + LogInfo::MapleLogger() << "EnsureRHSInCurTemp: found callassigned at BB" << bb->GetBBId() << '\n'; + } + // change mustDefList + RegMeExpr *lhsReg = irMap->CreateRegMeExprVersion(*curTemp); + mustDefList->front().UpdateLHS(*lhsReg); + // create dassign + DassignMeStmt *dass = irMap->CreateDassignMeStmt(*lhsVar, *lhsReg, *bb); + dass->SetSrcPos(itStmt->GetSrcPosition()); + lhsVar->SetDefByStmt(*dass); + bb->InsertMeStmtAfter(to_ptr(itStmt), dass); + bbCurTempMap[bb] = lhsReg; + return lhsReg; + } + } + } + // check if there is def by phi + auto phiIt = bb->GetMevarPhiList().find(workCand->GetOst()->GetIndex()); + if (phiIt != bb->GetMevarPhiList().end()) { + if (enabledDebug) { + LogInfo::MapleLogger() << "EnsureRHSInCurTemp: found def-by-phi at BB" << bb->GetBBId() << '\n'; + } + RegMeExpr *lhsReg = irMap->CreateRegMeExprVersion(*curTemp); + bbCurTempMap[bb] = lhsReg; + // form a new phi for the temp + MeRegPhiNode *regPhi = irMap->NewInPool(); + regPhi->SetLHS(lhsReg); + regPhi->SetDefBB(bb); + // call recursively for each varPhi operands + for (BB *pred : bb->GetPred()) { + RegMeExpr *regPhiOpnd = EnsureRHSInCurTemp(pred); + CHECK_NULL_FATAL(regPhiOpnd); + regPhi->GetOpnds().push_back(regPhiOpnd); + regPhiOpnd->GetPhiUseSet().insert(regPhi); + } + // insert the regPhi + bb->GetMeRegPhiList().insert(std::make_pair(lhsReg->GetOstIdx(), regPhi)); + return lhsReg; + } + // continue at immediate dominator + if (enabledDebug) { + LogInfo::MapleLogger() << "EnsureRHSInCurTemp: cannot find def at BB" << bb->GetBBId() << '\n'; + } + RegMeExpr *savedCurTemp = EnsureRHSInCurTemp(dom->GetDom(bb->GetBBId())); + CHECK_NULL_FATAL(savedCurTemp); + bbCurTempMap[bb] = savedCurTemp; + return savedCurTemp; +} + +void MeStorePre::CodeMotion() { + // pass 1 only donig insertion + for (SOcc *occ : allOccs) { + if (occ->GetOccTy() != kSOccLambdaRes) { + continue; + } + auto *lambdaResOcc = static_cast(occ); + if (lambdaResOcc->GetInsertHere()) { + // form the lhs VarMeExpr node + VarMeExpr *lhsVar = irMap->CreateVarMeExprVersion(*workCand->GetTheVar()); + // create a new dassign + BB *insertBB = lambdaResOcc->GetBB(); + CheckCreateCurTemp(); + CHECK_FATAL(insertBB->GetPred().size() == 1, "CodeMotion: encountered critical edge"); + RegMeExpr *rhsReg = EnsureRHSInCurTemp(insertBB->GetPred(0)); + DassignMeStmt *newDass = irMap->CreateDassignMeStmt(*lhsVar, *rhsReg, *insertBB); + lhsVar->SetDefByStmt(*newDass); + // insert at earliest point in BB, but after statements required to be + // first statements in BBG + MeStmt *curStmt = to_ptr(insertBB->GetMeStmts().begin()); + while (curStmt != nullptr && (curStmt->GetOp() == OP_catch || curStmt->GetOp() == OP_try || + curStmt->GetOp() == OP_comment)) { + curStmt = curStmt->GetNext(); + } + if (curStmt == nullptr) { + insertBB->AddMeStmtLast(newDass); + } else { + insertBB->InsertMeStmtBefore(curStmt, newDass); + } + } + } + // pass 2 only doing deletion + for (SOcc *occ : workCand->GetRealOccs()) { + if (occ->GetOccTy() != kSOccReal) { + continue; + } + auto *realOcc = static_cast(occ); + if (realOcc->GetRedundant()) { + if (realOcc->GetStmt()->GetOp() == OP_dassign) { + auto *dass = static_cast(realOcc->GetStmt()); + if (dass->GetRHS()->CouldThrowException()) { + // insert a new eval statement + UnaryMeStmt *evalStmt = irMap->New(OP_eval); + evalStmt->SetBB(dass->GetBB()); + evalStmt->SetSrcPos(dass->GetSrcPosition()); + evalStmt->SetMeStmtOpndValue(dass->GetRHS()); + realOcc->GetBB()->InsertMeStmtBefore(dass, evalStmt); + } + realOcc->GetBB()->RemoveMeStmt(dass); + } else { + CHECK_FATAL(kOpcodeInfo.IsCallAssigned(realOcc->GetStmt()->GetOp()), "CodeMotion: callassign expected"); + MapleVector *mustDefList = realOcc->GetStmt()->GetMustDefList(); + CHECK_NULL_FATAL(mustDefList); + mustDefList->clear(); + } + } + } +} + +// ================ Step 0: collect occurrences ================ +// create a new real occurrence for the store of meStmt of symbol oidx +void MeStorePre::CreateRealOcc(OStIdx ostIdx, MeStmt *meStmt) { + ASSERT_NOT_NULL(meStmt); + SpreWorkCand *wkCand = nullptr; + auto mapIt = workCandMap.find(ostIdx); + if (mapIt != workCandMap.end()) { + wkCand = mapIt->second; + } else { + const OriginalSt *ost = ssaTab->GetSymbolOriginalStFromID(ostIdx); + wkCand = spreMp->New(&spreAllocator, ost); + workCandMap[ostIdx] = wkCand; + // if it is local symbol, insert artificial real occ at common_exit_bb + if (ost->IsLocal()) { + SRealOcc *artOcc = spreMp->New(); + artOcc->SetBB(func->GetCommonExitBB()); + wkCand->GetRealOccs().push_back(artOcc); + } + } + if (wkCand->GetTheVar() == nullptr) { + if (meStmt->GetOp() == OP_dassign) { + wkCand->SetTheVar(static_cast(meStmt)->GetVarLHS()); + } else { + ASSERT(kOpcodeInfo.IsCallAssigned(meStmt->GetOp()), "CreateRealOcc: callassign expected"); + MapleVector *mustDefList = meStmt->GetMustDefList(); + CHECK_FATAL(mustDefList != nullptr, "CreateRealOcc: mustDefList cannot be empty"); + CHECK_FATAL(!mustDefList->empty(), "CreateRealOcc: mustDefList cannot be empty"); + wkCand->SetTheVar(static_cast(mustDefList->front().GetLHS())); + } + } + SRealOcc *newOcc = spreMp->New(meStmt); + wkCand->GetRealOccs().push_back(newOcc); + wkCand->SetHasStoreOcc(true); +} + +// create a new use occurrence for symbol oidx in given bb +void MeStorePre::CreateUseOcc(OStIdx ostIdx, BB *bb) { + SpreWorkCand *wkcand = nullptr; + auto mapIt = workCandMap.find(ostIdx); + if (mapIt == workCandMap.end()) { + return; + } + wkcand = mapIt->second; + CHECK_FATAL(!wkcand->GetRealOccs().empty(), "empty container check"); + SOcc *lastOcc = wkcand->GetRealOccs().back(); + if (lastOcc->GetOccTy() == kSOccUse && lastOcc->GetBB() == bb) { + return; // no need to push consecutive use occurrences at same BB + } + SUseOcc *newOcc = spreMp->New(bb); + wkcand->GetRealOccs().push_back(newOcc); +} + +// create use occurs for all the symbols that alias with muost +void MeStorePre::CreateSpreUseOccsThruAliasing(const OriginalSt *muOst, BB *bb) { + ASSERT_NOT_NULL(muOst); + if (muOst->GetIndex() >= aliasClass->GetAliasElemCount()) { + return; + } + AliasElem *ae = aliasClass->FindAliasElem(*muOst); + if (ae->GetClassSet() == nullptr) { + return; + } + for (auto setIt = ae->GetClassSet()->begin(); setIt != ae->GetClassSet()->end(); setIt++) { + unsigned int elemId = *setIt; + AliasElem *ae0 = aliasClass->FindID2Elem(elemId); + if (ae0->GetOriginalSt().GetIndirectLev() == 0) { + CreateUseOcc(ae0->GetOriginalSt().GetIndex(), bb); + } + } +} + +void MeStorePre::FindAndCreateSpreUseOccs(MeExpr *x, BB *bb) { + ASSERT_NOT_NULL(x); + ASSERT_NOT_NULL(bb); + if (x->GetMeOp() == kMeOpVar) { + auto *varx = static_cast(x); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varx->GetOStIdx()); + if (!ost->IsVolatile()) { + CreateUseOcc(varx->GetOStIdx(), bb); + } + return; + } + for (uint8 i = 0; i < x->GetNumOpnds(); i++) { + FindAndCreateSpreUseOccs(x->GetOpnd(i), bb); + } + if (JAVALANG) { + return; + } + if (x->GetMeOp() == kMeOpIvar) { + auto *ivarMeExpr = static_cast(x); + if (ivarMeExpr->GetMu() != nullptr) { + CreateSpreUseOccsThruAliasing(ssaTab->GetOriginalStFromID(ivarMeExpr->GetMu()->GetOStIdx()), bb); + } + } +} + +void MeStorePre::CreateSpreUseOccsForAll(BB *bb) { + // go thru all workcands and insert a use occurrence for each of them + for (std::pair wkCandPair : workCandMap) { + SpreWorkCand *wkCand = wkCandPair.second; + CHECK_NULL_FATAL(wkCand); + CHECK_FATAL(!wkCand->GetRealOccs().empty(), "container empty check"); + SOcc *lastOcc = wkCand->GetRealOccs().back(); + if (lastOcc->GetOccTy() == kSOccUse && lastOcc->GetBB() == bb) { + continue; // no need to push consecutive use occurrences at same BB + } + SUseOcc *newOcc = spreMp->New(bb); + wkCand->GetRealOccs().push_back(newOcc); + } +} + +void MeStorePre::BuildWorkListBB(BB *bb) { + if (bb == nullptr) { + return; + } + // traverse statements backwards + auto &meStmts = bb->GetMeStmts(); + for (auto stmt = meStmts.rbegin(); stmt != meStmts.rend(); ++stmt) { + // look for real occurrence of stores + OStIdx lhsOstIdx(0); + if (stmt->GetOp() == OP_dassign) { + auto *dass = static_cast(to_ptr(stmt)); + if (dass->GetLHS()->GetPrimType() != PTY_ref) { + lhsOstIdx = dass->GetVarLHS()->GetOStIdx(); + } + } else if (kOpcodeInfo.IsCallAssigned(stmt->GetOp())) { + MapleVector *mustDefList = stmt->GetMustDefList(); + CHECK_NULL_FATAL(mustDefList); + if (!mustDefList->empty()) { + MeExpr *mdLHS = mustDefList->front().GetLHS(); + if (mdLHS->GetMeOp() == kMeOpVar && mdLHS->GetPrimType() != PTY_ref) { + lhsOstIdx = static_cast(mdLHS)->GetOStIdx(); + } + } + } + if (lhsOstIdx != 0u) { + const OriginalSt *ost = ssaTab->GetOriginalStFromID(lhsOstIdx); + if (!ost->IsVolatile()) { + CreateRealOcc(lhsOstIdx, to_ptr(stmt)); + } + } + // look for use occurrence of stores + for (size_t i = 0; i < stmt->NumMeStmtOpnds(); i++) { + CHECK_NULL_FATAL(stmt->GetOpnd(i)); + FindAndCreateSpreUseOccs(stmt->GetOpnd(i), stmt->GetBB()); + } + if (!JAVALANG) { + // go thru mu list + NaryMeStmt *naryMeStmt = safe_cast(to_ptr(stmt)); + if (naryMeStmt != nullptr) { + CHECK_NULL_FATAL(naryMeStmt->GetMuList()); + for (std::pair muPair : *(naryMeStmt->GetMuList())) { + CreateSpreUseOccsThruAliasing(ssaTab->GetOriginalStFromID(muPair.second->GetOStIdx()), bb); + } + } + } + } + if (bb->GetAttributes(kBBAttrIsCatch)) { + CreateSpreUseOccsForAll(bb); + } + if (bb->GetAttributes(kBBAttrIsEntry)) { + CreateEntryOcc(bb); + } + // recurse on child BBs in post-dominator tree + for (BBId bbId : dom->GetPdomChildrenItem(bb->GetBBId())) { + BuildWorkListBB(func->GetAllBBs().at(bbId)); + } +} + +AnalysisResult *MeDoStorePre::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom != nullptr, "dominance phase has problem"); + auto *aliasClass = static_cast(m->GetAnalysisResult(MeFuncPhase_ALIASCLASS, func)); + ASSERT(aliasClass != nullptr, "aliasClass phase has problem"); + auto *meIrMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAP, func)); + CHECK_FATAL(meIrMap != nullptr, "irmap phase has problem"); + MeStorePre storePre(func, dom, aliasClass, NewMemPool(), DEBUGFUNC(func)); + storePre.ApplySSUPre(); + if (DEBUGFUNC(func)) { + func->Dump(false); + } + return nullptr; +} +} // namespace maple diff --git a/src/maple_me/src/occur.cpp b/src/maple_me/src/occur.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7aebc1ef1a0c10ad4d8a6d22ddcffda86e3fa5c3 --- /dev/null +++ b/src/maple_me/src/occur.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "occur.h" +#include "ssa_pre.h" + +// The methods associated with the data structures that represent occurrences +// and work candidates for SSAPRE +namespace { +constexpr uint32_t kOffsetMeExprID = 5; +constexpr uint32_t kOffsetVarMeExprOstIdx = 4; +constexpr uint32_t kOffsetRegMeExprRegIdx = 6; +constexpr uint32_t kOffsetIvarMeExprTyIdx = 3; +constexpr uint32_t kOffsetOpMeExprOpnd = 2; +constexpr uint32_t kOffsetNaryMeExprOpnd = 2; +constexpr uint32_t kOffsetMeStmtOpcode = 3; +constexpr uint32_t kOffsetUnaryMeStmtOpcode = 2; +constexpr uint32_t kOffsetIntrinsicCallMeStmtIntrinsic = 3; +constexpr uint32_t kOffsetNaryMeStmtOpnd = 2; +} + +namespace maple { +std::array PreWorkCand::workCandHashTable; + +void MeOccur::DumpOccur(IRMap &irMap) { + MIRModule *mod = &irMap.GetSSATab().GetModule(); + mod->GetOut() << "MeOccur "; + Dump(irMap); + mod->GetOut() << "\n class: " << classID << '\n'; + if (def) { + mod->GetOut() << " def by class: " << def->GetClassID(); + } else { + mod->GetOut() << " no-def"; + } + mod->GetOut() << '\n'; +} + +// return if this occur dominate occ +bool MeOccur::IsDominate(Dominance *dom, MeOccur *occ) { + switch (occTy) { + case kOccReal: { + switch (occ->GetOccType()) { + case kOccReal: { + if (mirBB == occ->GetBB()) { + auto *thisRealOcc = static_cast(this); + auto *domOcc = static_cast(occ); + return thisRealOcc->GetSequence() <= domOcc->GetSequence(); + } + return dom->Dominate(*mirBB, *occ->GetBB()); + } + case kOccPhiocc: { + if (mirBB == occ->GetBB()) { + return false; + } + return dom->Dominate(*mirBB, *occ->GetBB()); + } + case kOccPhiopnd: + case kOccExit: + case kOccMembar: + case kOccUse: + return dom->Dominate(*mirBB, *occ->GetBB()); + default: + ASSERT(false, "should not be here"); + } + break; + } + case kOccPhiocc: + case kOccMembar: + case kOccUse: + return dom->Dominate(*mirBB, *occ->GetBB()); + default: + ASSERT(false, "should not be here"); + return false; + } + + return false; +} + +MeExpr *MeOccur::GetSavedExpr() { + switch (occTy) { + case kOccReal: + return static_cast(this)->GetSavedExpr(); + case kOccPhiocc: { + auto *phiOcc = static_cast(this); + MeRegPhiNode *regPhi = phiOcc->GetRegPhi(); + if (regPhi != nullptr) { + return regPhi->GetLHS(); + } else { + return phiOcc->GetVarPhi()->GetLHS(); + } + } + case kOccInserted: + return static_cast(this)->GetSavedExpr(); + default: + CHECK_FATAL(false, "error or NYI"); + } +} + +// return true if either: +// operand is nullptr (def is null), or +// hasRealUse is false and defined by a PHI not will be avail +bool MePhiOpndOcc::IsOkToInsert() { + if (!GetDef()) { + return true; + } + if (!hasRealUse) { + MeOccur *defOcc = GetDef(); + if (defOcc->GetOccType() == kOccPhiocc && !static_cast(defOcc)->IsWillBeAvail()) { + return true; + } + } + return false; +} + +bool MePhiOcc::IsOpndDefByRealOrInserted() { + for (MePhiOpndOcc *phiOpnd : phiOpnds) { + MeOccur *defOcc = phiOpnd->GetDef(); + if (defOcc->GetOccType() == kOccReal || defOcc->GetOccType() == kOccInserted) { + return true; + } + } + return false; +} + +void MeOccur::Dump(IRMap &irMap) { + MIRModule *mod = &irMap.GetSSATab().GetModule(); + if (occTy == kOccExit) { + mod->GetOut() << "ExitOcc at bb" << GetBB()->GetBBId(); + } else if (occTy == kOccUse) { + mod->GetOut() << "UseOcc at bb" << GetBB()->GetBBId(); + } else { + CHECK_FATAL(false, "wrong occur type"); + } +} + +void MeRealOcc::Dump(IRMap &irMap) { + MIRModule *mod = &irMap.GetSSATab().GetModule(); + if (GetOccType() == kOccReal) { + if (!isLHS) { + mod->GetOut() << "RealOcc "; + } else { + mod->GetOut() << "RealOcc(LHS) "; + } + if (meExpr) { + meExpr->Dump(&irMap); + } else { + meStmt->Dump(&irMap); + } + if (meStmt && meStmt->GetBB()) { + mod->GetOut() << " at bb" << meStmt->GetBB()->GetBBId() << " seq " << seq << " classID " << GetClassID(); + } else { + mod->GetOut() << " classID " << GetClassID(); + } + } else { + mod->GetOut() << "MembarOcc "; + mod->GetOut() << " at bb" << GetBB()->GetBBId() << " seq " << seq; + } +} + +void MePhiOcc::Dump(IRMap &irMap) { + MIRModule *mod = &irMap.GetSSATab().GetModule(); + mod->GetOut() << "PhiOcc "; + mod->GetOut() << "PHI("; + size_t size = phiOpnds.size(); + for (size_t i = 0; i < size; i++) { + phiOpnds[i]->Dump(irMap); + if (i != size - 1) { + mod->GetOut() << ","; + } + } + mod->GetOut() << ")"; + mod->GetOut() << " at bb" << GetBB()->GetBBId() << " classID " << GetClassID(); +} + +void MePhiOpndOcc::Dump(IRMap &irMap) { + MIRModule *mod = &irMap.GetSSATab().GetModule(); + mod->GetOut() << "PhiOpndOcc at bb" << GetBB()->GetBBId() << " classID " << GetClassID(); + if (hasRealUse) { + mod->GetOut() << "(hasRealUse) "; + } +} + +void MeInsertedOcc::Dump(IRMap &irMap) { + MIRModule *mod = &irMap.GetSSATab().GetModule(); + mod->GetOut() << "InsertedOcc at bb" << GetBB()->GetBBId() << " classID " << GetClassID(); +} + +// compute bucket index for the work candidate in workCandHashTable +uint32 PreWorkCand::ComputeWorkCandHashIndex(MeExpr &meExpr) { + uint32 hIdx = 0; + MeExprOp meOp = meExpr.GetMeOp(); + switch (meOp) { + case kMeOpAddrof: + case kMeOpAddroffunc: + case kMeOpGcmalloc: + case kMeOpConst: + case kMeOpConststr: + case kMeOpConststr16: + case kMeOpSizeoftype: + case kMeOpFieldsDist: + hIdx = (static_cast(meExpr.GetExprID())) << kOffsetMeExprID; + break; + case kMeOpVar: { + auto &varMeExpr = static_cast(meExpr); + hIdx = static_cast(varMeExpr.GetOStIdx()) << kOffsetVarMeExprOstIdx; + break; + } + case kMeOpReg: { + auto ®MeExpr = static_cast(meExpr); + hIdx = (static_cast(static_cast(regMeExpr.GetRegIdx()))) << kOffsetRegMeExprRegIdx; + break; + } + case kMeOpIvar: { + auto &iVar = static_cast(meExpr); + hIdx = ComputeWorkCandHashIndex(*iVar.GetBase()) + + (static_cast(iVar.GetTyIdx()) << kOffsetIvarMeExprTyIdx) + iVar.GetFieldID(); + break; + } + case kMeOpOp: { + hIdx = static_cast(meExpr.GetOp()); + for (size_t idx = 0; idx < kOperandNumTernary; idx++) { + MeExpr *opnd = meExpr.GetOpnd(idx); + if (opnd != nullptr) { + hIdx += ComputeWorkCandHashIndex(*opnd) << kOffsetOpMeExprOpnd; + } else { + break; + } + } + break; + } + case kMeOpNary: { + hIdx = static_cast(meExpr.GetOp()); + for (uint8 i = 0; i < meExpr.GetNumOpnds(); i++) { + hIdx += ComputeWorkCandHashIndex(*meExpr.GetOpnd(i)) << kOffsetNaryMeExprOpnd; + } + break; + } + default: + CHECK_FATAL(false, "MeOP NIY"); + } + return hIdx % kWorkCandHashLength; +} + +// insert occ as realOccs[pos] after shifting the vector elements further down +void PreWorkCand::InsertRealOccAt(MeRealOcc &occ, MapleVector::iterator it, PUIdx pIdx) { + ASSERT(pIdx != 0, "puIdx of realocc cannot be 0"); + if (pIdx != puIdx) { + ASSERT(!hasLocalOpnd, "candidate with local opnd cannot have real occurrences in more than one PU"); + puIdx = 0; + } + CHECK(!realOccs.empty(), "realOccs has no element in PreWorkCand::InsertRealOccAt"); + realOccs.insert(it, &occ); +} + +// insert occ in realOccs maintaining sorted order according to dt_preorder +void PreWorkCand::AddRealOccSorted(Dominance &dom, MeRealOcc &occ, PUIdx pIdx) { + ASSERT(!realOccs.empty(), "AddRealOccSorted: realOccs is empty"); + uint32 occDfn = dom.GetDtDfnItem(occ.GetBB()->GetBBId()); + // check the end of realOccs first because inserting at end is most frequent + if (occDfn > dom.GetDtDfnItem(realOccs.back()->GetBB()->GetBBId())) { + AddRealOccAsLast(occ, pIdx); + } else if (occDfn == dom.GetDtDfnItem(realOccs.back()->GetBB()->GetBBId())) { + if (occ.GetSequence() >= realOccs.back()->GetSequence()) { + AddRealOccAsLast(occ, pIdx); + } else { + auto rIt = realOccs.rbegin(); + rIt++; + while (rIt != realOccs.rend()) { + if (occDfn > dom.GetDtDfnItem((*rIt)->GetBB()->GetBBId())) { + break; + } + if (occ.GetSequence() >= (*rIt)->GetSequence()) { + break; + } + } + InsertRealOccAt(occ, rIt.base(), pIdx); + } + } else { + // search from beginning of realOccs + auto it = realOccs.begin(); + bool found = false; + do { + if (occDfn > dom.GetDtDfnItem((*it)->GetBB()->GetBBId())) { + it++; + } else if (occDfn == dom.GetDtDfnItem((*it)->GetBB()->GetBBId())) { + if (occ.GetSequence() > (*it)->GetSequence()) { + it++; + } else { + found = true; + } + } else { + found = true; + } + } while (!found && it != realOccs.end()); + if (!found) { + AddRealOccAsLast(occ, pIdx); + } else { + InsertRealOccAt(occ, it, pIdx); + } + } +} + +// compute bucket index for the work candidate in workCandHashTable +uint32 PreStmtWorkCand::ComputeStmtWorkCandHashIndex(MeStmt &stmt) { + uint32 hIdx = (static_cast(stmt.GetOp())) << kOffsetMeStmtOpcode; + switch (stmt.GetOp()) { + case OP_assertnonnull: { + hIdx += ComputeWorkCandHashIndex(*stmt.GetOpnd(0)) << kOffsetUnaryMeStmtOpcode; + break; + } + case OP_dassign: { + CHECK_NULL_FATAL(stmt.GetVarLHS()); + CHECK_NULL_FATAL(stmt.GetRHS()); + VarMeExpr *varMeExpr = stmt.GetVarLHS(); + hIdx += static_cast(varMeExpr->GetOStIdx()) << kOffsetVarMeExprOstIdx; + hIdx += ComputeWorkCandHashIndex(*stmt.GetRHS()) << 1; + break; + } + case OP_intrinsiccall: + case OP_intrinsiccallwithtype: { + auto &intrnStmt = static_cast(stmt); + hIdx += (static_cast(intrnStmt.GetIntrinsic())) << kOffsetIntrinsicCallMeStmtIntrinsic; + if (stmt.GetOp() == OP_intrinsiccallwithtype) { + hIdx += static_cast(intrnStmt.GetTyIdx()) << 1; + } + for (size_t i = 0; i < intrnStmt.NumMeStmtOpnds(); i++) { + hIdx += ComputeWorkCandHashIndex(*intrnStmt.GetOpnd(i)) << 1; + } + break; + } + case OP_callassigned: { + auto &callAss = static_cast(stmt); + hIdx += callAss.GetPUIdx(); + for (size_t i = 0; i < callAss.NumMeStmtOpnds(); i++) { + hIdx += ComputeWorkCandHashIndex(*callAss.GetOpnd(i)) << kOffsetNaryMeStmtOpnd; + } + if (!callAss.GetMustDefList()->empty()) { + MeExpr *lhs = callAss.GetMustDefList()->front().GetLHS(); + auto *lhsVar = static_cast(lhs); + hIdx += static_cast(lhsVar->GetOStIdx()) << 1; + } + break; + } + default: + CHECK_FATAL(false, "ComputeStmtWorkCandHashIndex: NYI"); + } + return hIdx % kWorkCandHashLength; +} +} // namespace maple diff --git a/src/maple_me/src/ssa_epre.cpp b/src/maple_me/src/ssa_epre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eefdd2c94a2b1f5f895f7429e15d4d0801356d74 --- /dev/null +++ b/src/maple_me/src/ssa_epre.cpp @@ -0,0 +1,463 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "ssa_epre.h" +namespace maple { +void SSAEPre::GenerateSaveLHSRealocc(MeRealOcc *realOcc, MeExpr *regOrVar) { + CHECK_FATAL(realOcc->GetOpcodeOfMeStmt() == OP_iassign, "GenerateSaveLHSReal: only iassign expected"); + auto *iass = static_cast(realOcc->GetMeStmt()); + IvarMeExpr *theLHS = iass->GetLHSVal(); + MeExpr *savedRHS = iass->GetRHS(); + TyIdx savedTyIdx = iass->GetTyIdx(); + MapleMap savedChiList = *iass->GetChiList(); + iass->GetChiList()->clear(); + SrcPosition savedSrcPos = iass->GetSrcPosition(); + BB *savedBB = iass->GetBB(); + MeStmt *savedPrev = iass->GetPrev(); + MeStmt *savedNext = iass->GetNext(); + RegassignMeStmt *rass = nullptr; + if (!workCand->NeedLocalRefVar() || GetPlacementRCOn()) { + CHECK_FATAL(regOrVar->GetMeOp() == kMeOpReg, "GenerateSaveLHSRealocc: EPRE temp must b e preg here"); + // change original iassign to regassign; + // use placement new to modify in place, because other occ nodes are pointing + // to this statement in order to get to the rhs expression; + // this assumes RegassignMeStmt has smaller size then IassignMeStmt + rass = new (iass) RegassignMeStmt(); + rass->SetLHS(static_cast(regOrVar)); + rass->SetRHS(savedRHS); + rass->SetSrcPos(savedSrcPos); + rass->SetBB(savedBB); + rass->SetPrev(savedPrev); + rass->SetNext(savedNext); + regOrVar->SetDefByStmt(*rass); + } else { + // regOrVar is kMeOpReg and localRefVar is kMeOpVar + VarMeExpr *localRefVar = CreateNewCurLocalRefVar(); + temp2LocalRefVarMap[static_cast(regOrVar)] = localRefVar; + // generate localRefVar = saved_rhs by changing original iassign to dassign; + // use placement new to modify in place, because other occ nodes are pointing + // to this statement in order to get to the rhs expression; + // this assumes DassignMeStmt has smaller size then IassignMeStmt + DassignMeStmt *dass = new (iass) DassignMeStmt(&irMap->GetIRMapAlloc()); + dass->SetLHS(localRefVar); + dass->SetRHS(savedRHS); + dass->SetSrcPos(savedSrcPos); + dass->SetBB(savedBB); + dass->SetPrev(savedPrev); + dass->SetNext(savedNext); + localRefVar->SetDefByStmt(*dass); + rass = irMap->CreateRegassignMeStmt(*regOrVar, *localRefVar, *savedBB); + regOrVar->SetDefByStmt(*rass); + savedBB->InsertMeStmtAfter(dass, rass); + EnterCandsForSSAUpdate(localRefVar->GetOStIdx(), savedBB); + } + // create new iassign for original lhs + IassignMeStmt *newIass = irMap->NewInPool(savedTyIdx, theLHS, regOrVar, &savedChiList); + theLHS->SetDefStmt(newIass); + newIass->SetBB(savedBB); + savedBB->InsertMeStmtAfter(rass, newIass); + // go throu saved_Chi_List to update each chi base to point to newIass + for (auto it = newIass->GetChiList()->begin(); it != newIass->GetChiList()->end(); it++) { + ChiMeNode *chi = it->second; + chi->SetBase(newIass); + } + realOcc->SetSavedExpr(*regOrVar); +} + +void SSAEPre::GenerateSaveRealOcc(MeRealOcc *realOcc) { + ASSERT(GetPUIdx() == workCand->GetPUIdx() || workCand->GetPUIdx() == 0, + "GenerateSaveRealOcc: inconsistent puIdx"); + MeExpr *regOrVar = CreateNewCurTemp(realOcc->GetMeExpr()); + if (realOcc->IsLHS()) { + GenerateSaveLHSRealocc(realOcc, regOrVar); + return; + } + // create a new meStmt before realOcc->GetMeStmt() + MeStmt *newMeStmt = nullptr; + bool isRHSOfDassign = false; + if (workCand->NeedLocalRefVar() && (realOcc->GetOpcodeOfMeStmt() == OP_dassign) && + (realOcc->GetMeStmt()->GetOpnd(0) == realOcc->GetMeExpr())) { + isRHSOfDassign = true; + // setting flag so delegaterc will skip + static_cast(realOcc->GetMeStmt())->GetVarLHS()->SetNoDelegateRC(1); + } + if (!workCand->NeedLocalRefVar() || isRHSOfDassign || GetPlacementRCOn()) { + if (regOrVar->GetMeOp() == kMeOpReg) { + newMeStmt = irMap->CreateRegassignMeStmt(*regOrVar, *realOcc->GetMeExpr(), *realOcc->GetMeStmt()->GetBB()); + } else { + newMeStmt = irMap->CreateDassignMeStmt(*regOrVar, *realOcc->GetMeExpr(), *realOcc->GetMeStmt()->GetBB()); + } + regOrVar->SetDefByStmt(*newMeStmt); + realOcc->GetMeStmt()->GetBB()->InsertMeStmtBefore(realOcc->GetMeStmt(), newMeStmt); + } else { + // regOrVar is MeOp_reg and localRefVar is kMeOpVar + VarMeExpr *localRefVar = CreateNewCurLocalRefVar(); + temp2LocalRefVarMap[static_cast(regOrVar)] = localRefVar; + newMeStmt = irMap->CreateDassignMeStmt(*localRefVar, *realOcc->GetMeExpr(), *realOcc->GetMeStmt()->GetBB()); + localRefVar->SetDefByStmt(*newMeStmt); + realOcc->GetMeStmt()->GetBB()->InsertMeStmtBefore(realOcc->GetMeStmt(), newMeStmt); + newMeStmt = irMap->CreateRegassignMeStmt(*regOrVar, *localRefVar, *realOcc->GetMeStmt()->GetBB()); + regOrVar->SetDefByStmt(*newMeStmt); + realOcc->GetMeStmt()->GetBB()->InsertMeStmtBefore(realOcc->GetMeStmt(), newMeStmt); + EnterCandsForSSAUpdate(localRefVar->GetOStIdx(), realOcc->GetMeStmt()->GetBB()); + } + // replace realOcc->GetMeStmt()'s occ with regOrVar + bool isReplaced = irMap->ReplaceMeExprStmt(*realOcc->GetMeStmt(), *realOcc->GetMeExpr(), *regOrVar); + // rebuild worklist + if (isReplaced) { + BuildWorkListStmt(realOcc->GetMeStmt(), realOcc->GetSequence(), true, regOrVar); + } + realOcc->SetSavedExpr(*regOrVar); +} + +void SSAEPre::GenerateReloadRealOcc(MeRealOcc *realOcc) { + CHECK_FATAL(!realOcc->IsLHS(), "GenerateReloadRealOcc: cannot be LHS occurrence"); + MeExpr *regOrVar = nullptr; + MeOccur *defOcc = realOcc->GetDef(); + if (defOcc->GetOccType() == kOccReal) { + auto *defRealOcc = static_cast(defOcc); + regOrVar = defRealOcc->GetSavedExpr(); + } else if (defOcc->GetOccType() == kOccPhiocc) { + auto *defPhiOcc = static_cast(defOcc); + MeRegPhiNode *regPhi = defPhiOcc->GetRegPhi(); + if (regPhi != nullptr) { + regOrVar = regPhi->GetLHS(); + } else { + regOrVar = defPhiOcc->GetVarPhi()->GetLHS(); + } + } else if (defOcc->GetOccType() == kOccInserted) { + auto *defInsertedOcc = static_cast(defOcc); + regOrVar = defInsertedOcc->GetSavedExpr(); + } else { + CHECK_FATAL(false, "NYI"); + } + ASSERT(regOrVar, "temp not yet generated"); + // replace realOcc->GetMeStmt()'s occ with regOrVar + bool isReplaced = irMap->ReplaceMeExprStmt(*realOcc->GetMeStmt(), *realOcc->GetMeExpr(), *regOrVar); + // update worklist + if (isReplaced) { + BuildWorkListStmt(realOcc->GetMeStmt(), realOcc->GetSequence(), true, regOrVar); + } +} + +// for each variable in realz that is defined by a phi, replace it by the jth +// phi opnd +MeExpr *SSAEPre::PhiOpndFromRes(MeRealOcc *realZ, size_t j) { + MeOccur *defZ = realZ->GetDef(); + CHECK_FATAL(defZ, "must be def by phiocc"); + CHECK_FATAL(defZ->GetOccType() == kOccPhiocc, "must be def by phiocc"); + MeExpr *exprQ = CopyMeExpr(utils::ToRef(realZ->GetMeExpr())); + BB *ePhiBB = defZ->GetBB(); + CHECK_FATAL(exprQ != nullptr, "nullptr check"); + switch (exprQ->GetMeOp()) { + case kMeOpOp: { + auto *opMeExpr = static_cast(exprQ); + for (size_t i = 0; i < 3; i++) { + MeExpr *opnd = opMeExpr->GetOpnd(i); + if (opnd == nullptr) { + break; + }; + MeExpr *retOpnd = GetReplaceMeExpr(opnd, ePhiBB, j); + if (retOpnd != nullptr) { + opMeExpr->SetOpnd(i, retOpnd); + } + } + break; + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(exprQ); + MapleVector &opnds = naryMeExpr->GetOpnds(); + for (size_t i = 0; i < opnds.size(); i++) { + MeExpr *retOpnd = GetReplaceMeExpr(opnds[i], ePhiBB, j); + if (retOpnd) { + opnds[i] = retOpnd; + } + } + break; + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(exprQ); + MeExpr *retOpnd = GetReplaceMeExpr(ivarMeExpr->GetBase(), ePhiBB, j); + if (retOpnd) { + ivarMeExpr->SetBase(retOpnd); + } + MeExpr *muOpnd = GetReplaceMeExpr(ivarMeExpr->GetMu(), ePhiBB, j); + if (muOpnd != nullptr) { + ivarMeExpr->SetMuVal(static_cast(muOpnd)); + } + break; + } + default: + ASSERT(false, "NYI"); + } + return irMap->HashMeExpr(*exprQ); +} + +// Df phis are computed into the df_phis set; Var Phis in the var_phis set +void SSAEPre::ComputeVarAndDfPhis() { + varPhiDfns.clear(); + dfPhiDfns.clear(); + const MapleVector &realOccList = workCand->GetRealOccs(); + CHECK_FATAL(!dom->IsBBVecEmpty(), "size to be allocated is 0"); + for (auto it = realOccList.begin(); it != realOccList.end(); it++) { + MeRealOcc *realOcc = *it; + BB *defBB = realOcc->GetBB(); + std::vector visitedMap(dom->GetBBVecSize(), false); + GetIterDomFrontier(*defBB, dfPhiDfns, visitedMap); + MeExpr *meExpr = realOcc->GetMeExpr(); + switch (meExpr->GetMeOp()) { + case kMeOpOp: { + auto *meExprOp = static_cast(meExpr); + for (uint32 i = 0; i < 3; i++) { + MeExpr *kidExpr = meExprOp->GetOpnd(i); + if (kidExpr != nullptr) { + SetVarPhis(kidExpr); + } + } + break; + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(meExpr); + MapleVector &opnds = naryMeExpr->GetOpnds(); + for (size_t i = 0; i < opnds.size(); i++) { + MeExpr *kidExpr = opnds[i]; + if (kidExpr) { + SetVarPhis(kidExpr); + } + } + break; + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(meExpr); + SetVarPhis(ivarMeExpr->GetBase()); + break; + } + default: + CHECK_FATAL(false, "NYI"); + } + } +} + +// build worklist for each expression; +// isRebuild means the expression is built from second time, in which case, +// tempVar is not nullptr, and it matches only expressions with tempVar as one of +// its operands; isRebuild is true only when called from the code motion phase +void SSAEPre::BuildWorkListExpr(MeStmt *meStmt, int32 seqStmt, MeExpr *meExpr, bool isRebuild, MeExpr *tempVar, + bool isRootExpr) { + if (meExpr->GetTreeID() == (curTreeId + 1)) { + return; // already visited twice in the same tree + } + MeExprOp meOp = meExpr->GetMeOp(); + switch (meOp) { + case kMeOpOp: { + auto *meOpExpr = static_cast(meExpr); + bool isHypo = true; + bool hasTempVarAs1Opnd = false; + for (uint32 i = 0; i < 3; i++) { + MeExpr *opnd = meOpExpr->GetOpnd(i); + if (opnd != nullptr) { + if (!opnd->IsLeaf()) { + BuildWorkListExpr(meStmt, seqStmt, opnd, isRebuild, tempVar, false); + isHypo = false; + } else if (LeafIsVolatile(opnd)) { + isHypo = false; + } else if (tempVar != nullptr && opnd->IsUseSameSymbol(*tempVar)) { + hasTempVarAs1Opnd = true; + } + } + } + if (meExpr->GetPrimType() == PTY_agg) { + isHypo = false; + } + if (isHypo && (!isRebuild || hasTempVarAs1Opnd) && !(isRootExpr && kOpcodeInfo.IsCompare(meOpExpr->GetOp())) && + meOpExpr->GetOp() != OP_gcmallocjarray && meOpExpr->GetOp() != OP_gcmalloc && + (epreIncludeRef || meOpExpr->GetPrimType() != PTY_ref)) { + // create a HypotheTemp for this expr + // Exclude cmp operator + CreateRealOcc(*meStmt, seqStmt, *meExpr, isRebuild); + } + break; + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(meExpr); + bool isHypo = true; + bool hasTempVarAs1Opnd = false; + MapleVector &opnds = naryMeExpr->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); it++) { + MeExpr *opnd = *it; + if (!opnd->IsLeaf()) { + BuildWorkListExpr(meStmt, seqStmt, opnd, isRebuild, tempVar, false); + isHypo = false; + } else if (LeafIsVolatile(opnd)) { + isHypo = false; + } else if (tempVar != nullptr && opnd->IsUseSameSymbol(*tempVar)) { + hasTempVarAs1Opnd = true; + } + } + if (meExpr->GetPrimType() == PTY_agg) { + isHypo = false; + } + if (isHypo && (!isRebuild || hasTempVarAs1Opnd) && naryMeExpr->GetPrimType() != PTY_u1 && + (GetPrimTypeSize(naryMeExpr->GetPrimType()) >= 4 || IsPrimitivePoint(naryMeExpr->GetPrimType()) || + (naryMeExpr->GetOp() == OP_intrinsicop && IntrinDesc::intrinTable[naryMeExpr->GetIntrinsic()].IsPure())) && + (epreIncludeRef || naryMeExpr->GetPrimType() != PTY_ref)) { + if (meExpr->GetOp() == OP_array) { + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeTable().at(naryMeExpr->GetTyIdx()); + CHECK_FATAL(mirType->GetKind() == kTypePointer, "array must have pointer type"); + auto *ptrMIRType = static_cast(mirType); + MIRJarrayType *arryType = safe_cast(ptrMIRType->GetPointedType()); + if (arryType == nullptr) { + CreateRealOcc(*meStmt, seqStmt, *meExpr, isRebuild); + } else { + int dim = arryType->GetDim(); // to compute the dim field + if (dim < 2) { + CreateRealOcc(*meStmt, seqStmt, *meExpr, isRebuild); + } else { + if (GetSSAPreDebug()) { + mirModule->GetOut() << "----- real occ suppressed for jarray with dim " << dim << '\n'; + } + } + } + } else { + IntrinDesc *intrinDesc = &IntrinDesc::intrinTable[naryMeExpr->GetIntrinsic()]; + if (CfgHasDoWhile() && naryMeExpr->GetIntrinsic() == INTRN_JAVA_ARRAY_LENGTH) { + auto *varOpnd = safe_cast(naryMeExpr->GetOpnd(0)); + if (varOpnd != nullptr) { + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varOpnd->GetOStIdx()); + if (ost->IsFormal()) { + break; + } + } + } + if (!intrinDesc->IsLoadMem()) { + CreateRealOcc(*meStmt, seqStmt, *meExpr, isRebuild); + } + } + } + break; + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(meExpr); + MeExpr *base = ivarMeExpr->GetBase(); + if (meExpr->GetPrimType() == PTY_agg) { + break; + } + if (!base->IsLeaf()) { + BuildWorkListExpr(meStmt, seqStmt, ivarMeExpr->GetBase(), isRebuild, tempVar, false); + } else if (ivarMeExpr->IsVolatile()) { + break; + } else if (!epreIncludeRef && ivarMeExpr->GetPrimType() == PTY_ref) { + break; + } else if (!isRebuild || base->IsUseSameSymbol(*tempVar)) { + CreateRealOcc(*meStmt, seqStmt, *meExpr, isRebuild); + } + break; + } + case kMeOpVar: + case kMeOpReg: + case kMeOpAddrof: + case kMeOpAddroffunc: + case kMeOpGcmalloc: + case kMeOpConst: + case kMeOpConststr: + case kMeOpConststr16: + case kMeOpSizeoftype: + case kMeOpFieldsDist: + break; + default: + CHECK_FATAL(false, "MeOP NIY"); + } + if (meExpr->GetTreeID() == curTreeId) { + meExpr->SetTreeID(curTreeId + 1); // just processed 2nd time; not + } + // to be processed again in this tree + else { + meExpr->SetTreeID(curTreeId); // just processed 1st time; willing to + } + // process one more time + return; +} + +void SSAEPre::BuildWorkListIvarLHSOcc(MeStmt *meStmt, int32 seqStmt, bool isRebuild, MeExpr *tempVar) { + if (!enableLHSIvar || GetPlacementRCOn()) { + return; + } + if (meStmt->GetOp() != OP_iassign) { + return; + } + auto *iass = static_cast(meStmt); + IvarMeExpr *ivarMeExpr = iass->GetLHSVal(); + if (ivarMeExpr->GetPrimType() == PTY_agg) { + return; + } + if (ivarMeExpr->IsVolatile()) { + return; + } + if (!epreIncludeRef && ivarMeExpr->GetPrimType() == PTY_ref) { + return; + } + MeExpr *base = ivarMeExpr->GetBase(); + if (!base->IsLeaf()) { + return; + } + if (!isRebuild || base->IsUseSameSymbol(*tempVar)) { + CreateRealOcc(*meStmt, seqStmt, *ivarMeExpr, isRebuild, true); + } +} + +// collect meExpr's variables and put them into varVec +// varVec can only store RegMeExpr and VarMeExpr +void SSAEPre::CollectVarForMeExpr(MeExpr *meExpr, std::vector &varVec) { + switch (meExpr->GetMeOp()) { + case kMeOpOp: { + for (uint32 i = 0; i < 3; i++) { + auto *opMeExpr = static_cast(meExpr); + MeExpr *opnd = opMeExpr->GetOpnd(i); + if (opnd && (opnd->GetMeOp() == kMeOpVar || opnd->GetMeOp() == kMeOpReg)) { + varVec.push_back(opnd); + } + } + break; + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(meExpr); + MapleVector &opnds = naryMeExpr->GetOpnds(); + for (MeExpr *kidExpr : opnds) { + if (kidExpr->GetMeOp() == kMeOpVar || kidExpr->GetMeOp() == kMeOpReg) { + varVec.push_back(kidExpr); + } + } + break; + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(meExpr); + CHECK_FATAL(ivarMeExpr->GetBase()->GetMeOp() == kMeOpVar || ivarMeExpr->GetBase()->GetMeOp() == kMeOpConst || + ivarMeExpr->GetBase()->GetMeOp() == kMeOpAddrof || ivarMeExpr->GetBase()->GetMeOp() == kMeOpReg, + "ivarMeExpr not first order expr"); + if (ivarMeExpr->GetBase()->GetMeOp() == kMeOpVar || ivarMeExpr->GetBase()->GetMeOp() == kMeOpReg) { + varVec.push_back(ivarMeExpr->GetBase()); + } + // in case of lhs occurrence, mu can be nullptr, and can use nullptr as value + varVec.push_back(ivarMeExpr->GetMu()); + break; + } + default: + ASSERT(false, "should not be here"); + } +} + +void SSAEPre::CollectVarForCand(MeRealOcc *realOcc, std::vector &varVec) { + CollectVarForMeExpr(realOcc->GetMeExpr(), varVec); +} +} // namespace maple diff --git a/src/maple_me/src/ssa_pre.cpp b/src/maple_me/src/ssa_pre.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d033b42011cbf15f99d884666af8332ce809601 --- /dev/null +++ b/src/maple_me/src/ssa_pre.cpp @@ -0,0 +1,1699 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +#include "ssa_pre.h" +#include "dominance.h" +#include "mir_builder.h" +namespace maple { +// Implementation of SSAPRE based on the paper "Partial Redundancy Elimination +// in SSA Form" Kennedy et al. +// +// This file represents the base SSAPRE implementation. There are different +// variants of SSAPRE-based optimizations, and they are derived from this base +// implementation and implemented in additional files. The optimizations are +// and the files they are implemented in are: +// 1. EPRE (PRE for Expressions) - ssa_epre.cpp, me_ssa_epre.cpp +// 2. LPRE (PRE for Loads) - me_ssa_lpre.cpp +// 3. STMTPRE (PRE for Statements) - me_stmt_pre.cpp +// 4. STMTFRE (Full Redundancy Elimination for Statements) - me_stmt_fre.cpp +// (called when performing STMTPRE). +// ================ Step 6: Code Motion ================= +MeExpr *SSAPre::CreateNewCurTemp(MeExpr *meExpr) { + if (workCand->NeedLocalRefVar() && GetPlacementRCOn()) { + curTemp = CreateNewCurLocalRefVar(); + return curTemp; + } + if (curTemp != nullptr) { + // only need to create a new version + if (curTemp->GetMeOp() == kMeOpReg) { + RegMeExpr *regVar = irMap->CreateRegMeExprVersion(static_cast(*curTemp)); + return regVar; + } else { + VarMeExpr *tempVar = irMap->CreateVarMeExprVersion(static_cast(*curTemp)); + return tempVar; + } + } + if (workCand->GetPUIdx() != 0) { + // allocate a new temp + SetCurFunction(workCand->GetPUIdx()); + RegMeExpr *regVar = nullptr; + if (meExpr->GetMeOp() == kMeOpVar) { + auto *varMeExpr = static_cast(meExpr); + const MIRSymbol *sym = ssaTab->GetMIRSymbolFromID(varMeExpr->GetOStIdx()); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(sym->GetTyIdx()); + regVar = ty->GetPrimType() == PTY_ref ? irMap->CreateRegRefMeExpr(*ty) + : irMap->CreateRegMeExpr(ty->GetPrimType()); + } else if (meExpr->GetMeOp() == kMeOpIvar) { + auto *ivarMeExpr = static_cast(meExpr); + MIRType *ptrMIRType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivarMeExpr->GetTyIdx()); + CHECK_FATAL(ptrMIRType->GetKind() == kTypePointer, "must be point type for ivar"); + auto *realMIRType = static_cast(ptrMIRType); + FieldID fieldId = ivarMeExpr->GetFieldID(); + MIRType *ty = nullptr; + if (fieldId > 0) { + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(realMIRType->GetPointedTyIdxWithFieldID(fieldId)); + } else { + ty = realMIRType->GetPointedType(); + } + CHECK_FATAL(ty->GetPrimType() == meExpr->GetPrimType() || + !(IsAddress(ty->GetPrimType()) && IsAddress(meExpr->GetPrimType())) || + (ty->GetPrimType() == PTY_ptr && meExpr->GetPrimType() == PTY_ref) || + (ty->GetPrimType() == PTY_ref && meExpr->GetPrimType() == PTY_ptr), + "inconsistent type"); + regVar = (ty->GetPrimType() == PTY_ref) ? (irMap->CreateRegRefMeExpr(*ty)) + : (irMap->CreateRegMeExpr(ty->GetPrimType())); + } else { + regVar = meExpr->GetPrimType() != PTY_ref ? irMap->CreateRegMeExpr(meExpr->GetPrimType()) + : irMap->CreateRegRefMeExpr(*meExpr); + } + curTemp = regVar; + if (preKind == kLoadPre) { + irMap->SetLpreTmps(static_cast(meExpr)->GetOStIdx(), *regVar); + } + return regVar; + } else { + VarMeExpr *tempVar = irMap->CreateNewGlobalTmp(NewTempStrIdx(), meExpr->GetPrimType()); + curTemp = tempVar; + return tempVar; + } +} + + +VarMeExpr *SSAPre::CreateNewCurLocalRefVar() { + if (curLocalRefVar) { + // only need to create a new version + VarMeExpr *tempVar = irMap->CreateVarMeExprVersion(static_cast(*curLocalRefVar)); + return tempVar; + } else { + // allocate a new temp + auto *ivarMeExpr = static_cast(workCand->GetTheMeExpr()); + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivarMeExpr->GetTyIdx()); + CHECK_FATAL(mirType->GetKind() == kTypePointer, "must be point type for ivar"); + auto *realMIRType = static_cast(mirType); + FieldID fieldID = ivarMeExpr->GetFieldID(); + curLocalRefVar = irMap->CreateNewLocalRefVarTmp(NewTempStrIdx(), realMIRType->GetPointedTyIdxWithFieldID(fieldID)); + ssaTab->SetEPreLocalRefVar(curLocalRefVar->GetOStIdx(), true); + SetAddedNewLocalRefVars(true); + return curLocalRefVar; + } +} + +void SSAPre::GenerateSaveInsertedOcc(MeInsertedOcc *insertedOcc) { + ASSERT(GetPUIdx() == workCand->GetPUIdx() || workCand->GetPUIdx() == 0, + "GenerateSaveInsertedOcc: inconsistent puIdx"); + MeExpr *regOrVar = CreateNewCurTemp(insertedOcc->GetMeExpr()); + MeStmt *newMeStmt = nullptr; + if (!workCand->NeedLocalRefVar() || GetPlacementRCOn()) { + if (regOrVar->GetMeOp() == kMeOpReg) { + newMeStmt = irMap->CreateRegassignMeStmt(*regOrVar, *insertedOcc->GetMeExpr(), *insertedOcc->GetBB()); + } else { + newMeStmt = irMap->CreateDassignMeStmt(*regOrVar, *insertedOcc->GetMeExpr(), *insertedOcc->GetBB()); + } + regOrVar->SetDefByStmt(*newMeStmt); + insertedOcc->GetBB()->InsertMeStmtLastBr(newMeStmt); + insertedOcc->SetSavedExpr(*regOrVar); + } else { + // regOrVar is MeOp_reg and lcoalrefvar is kMeOpVar + VarMeExpr *localRefVar = CreateNewCurLocalRefVar(); + temp2LocalRefVarMap[static_cast(regOrVar)] = localRefVar; + newMeStmt = irMap->CreateDassignMeStmt(*localRefVar, *insertedOcc->GetMeExpr(), *insertedOcc->GetBB()); + localRefVar->SetDefByStmt(*newMeStmt); + insertedOcc->GetBB()->InsertMeStmtLastBr(newMeStmt); + EnterCandsForSSAUpdate(localRefVar->GetOStIdx(), insertedOcc->GetBB()); + newMeStmt = irMap->CreateRegassignMeStmt(*regOrVar, *localRefVar, *insertedOcc->GetBB()); + regOrVar->SetDefByStmt(*newMeStmt); + insertedOcc->GetBB()->InsertMeStmtLastBr(newMeStmt); + insertedOcc->SetSavedExpr(*regOrVar); + } +} + +void SSAPre::GenerateSavePhiOcc(MePhiOcc *phiOcc) { + // generate a regOrVar + ASSERT(GetPUIdx() == workCand->GetPUIdx() || workCand->GetPUIdx() == 0, + "GenerateSavePhiOcc: inconsistent puIdx"); + MeExpr *regOrVar = CreateNewCurTemp(workCand->GetTheMeExpr()); + CHECK_NULL_FATAL(regOrVar); + if (instance_of(regOrVar)) { + // create a reg phi + MeRegPhiNode *phiReg = irMap->CreateMeRegPhi(static_cast(*regOrVar)); + phiReg->SetDefBB(phiOcc->GetBB()); + phiOcc->SetRegPhi(*phiReg); + } else { + MeVarPhiNode *phiVar = irMap->CreateMeVarPhi(static_cast(*regOrVar)); + CHECK_NULL_FATAL(phiVar); + phiVar->SetDefBB(phiOcc->GetBB()); + phiOcc->SetVarPhi(*phiVar); + } + // update the phi opnds later + if (workCand->NeedLocalRefVar() && !GetPlacementRCOn()) { + VarMeExpr *localRefVar = CreateNewCurLocalRefVar(); + temp2LocalRefVarMap[static_cast(regOrVar)] = localRefVar; + // create a var phi + MeVarPhiNode *phiVar = irMap->CreateMeVarPhi(*localRefVar); + phiVar->SetDefBB(phiOcc->GetBB()); + phiOcc->SetVarPhi(*phiVar); + EnterCandsForSSAUpdate(localRefVar->GetOStIdx(), phiOcc->GetBB()); + // update the phi opnds later + } +} + +void SSAPre::UpdateInsertedPhiOccOpnd() { + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + if (phiOcc->IsWillBeAvail() && !phiOcc->IsExtraneous()) { + if (phiOcc->GetRegPhi()) { + MeRegPhiNode *phiReg = phiOcc->GetRegPhi(); + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + auto *regOpnd = static_cast(phiOpnd->GetDef()->GetSavedExpr()); + if (regOpnd == nullptr) { + // create a zero version + CHECK_FATAL(curTemp != nullptr, "curTemp can't be null in SSAPre::UpdateInsertedPhiOccOpnd"); + regOpnd = irMap->CreateRegMeExprVersion(static_cast(*curTemp)); + } + phiReg->GetOpnds().push_back(regOpnd); + regOpnd->GetPhiUseSet().insert(phiReg); // record all the uses phi node for preg renaming + } + phiOcc->GetBB()->GetMeRegPhiList().insert(std::make_pair(phiReg->GetOpnd(0)->GetOstIdx(), phiReg)); + if (workCand->NeedLocalRefVar() && phiOcc->GetVarPhi() != nullptr) { + MeVarPhiNode *phiVar = phiOcc->GetVarPhi(); + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + auto *regOpnd = static_cast(phiOpnd->GetDef()->GetSavedExpr()); + VarMeExpr *localRefVarOpnd = nullptr; + if (regOpnd == nullptr) { + // create a zero version + CHECK_FATAL(curLocalRefVar != nullptr, "null ptr check"); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(curLocalRefVar->GetOStIdx()); + localRefVarOpnd = irMap->GetOrCreateZeroVersionVarMeExpr(*ost); + } else { + MapleMap::iterator mapIt = temp2LocalRefVarMap.find(regOpnd); + if (mapIt == temp2LocalRefVarMap.end()) { + CHECK_FATAL(curLocalRefVar != nullptr, "null ptr check"); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(curLocalRefVar->GetOStIdx()); + localRefVarOpnd = irMap->GetOrCreateZeroVersionVarMeExpr(*ost); + } else { + localRefVarOpnd = mapIt->second; + } + } + phiVar->GetOpnds().push_back(localRefVarOpnd); + } + phiOcc->GetBB()->GetMevarPhiList().insert(std::make_pair(phiVar->GetOpnd(0)->GetOStIdx(), phiVar)); + } + } else { + MeVarPhiNode *phiVar = phiOcc->GetVarPhi(); + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + auto *varOpnd = static_cast(phiOpnd->GetDef()->GetSavedExpr()); + if (varOpnd == nullptr) { + CHECK_FATAL(curTemp != nullptr, "curTemp can't be null in SSAPre::UpdateInsertedPhiOccOpnd"); + varOpnd = irMap->CreateVarMeExprVersion(static_cast(*curTemp)); + } + phiVar->GetOpnds().push_back(varOpnd); + } + phiOcc->GetBB()->GetMevarPhiList().insert(std::make_pair(phiVar->GetOpnd(0)->GetOStIdx(), phiVar)); + } + } + } +} + +void SSAPre::CodeMotion() { + curTemp = nullptr; + curLocalRefVar = nullptr; + temp2LocalRefVarMap.clear(); + reBuiltOccIndex = workList.size(); // so we know the elements added due to rebuilding + for (MeOccur *occ : allOccs) { + switch (occ->GetOccType()) { + case kOccReal: { + auto *realOcc = static_cast(occ); + if (realOcc->IsSave()) { + CHECK_FATAL(!(realOcc->IsReload()), "reload failed"); + GenerateSaveRealOcc(realOcc); + } else if (realOcc->IsReload()) { + GenerateReloadRealOcc(realOcc); + } + break; + } + case kOccPhiopnd: { + auto *phiOpnd = static_cast(occ); + if (!phiOpnd->GetDefPhiOcc()->IsWillBeAvail()) { + break; + } + MeOccur *defOcc = phiOpnd->GetDef(); + if (defOcc->GetOccType() == kOccInserted) { + // generate a save of the result in to a new version of t + if (!phiOpnd->IsPhiOpndReload()) { + GenerateSaveInsertedOcc(static_cast(defOcc)); + } + } + break; + } + case kOccPhiocc: { + auto *phiOcc = static_cast(occ); + if (phiOcc->IsExtraneous() || !phiOcc->IsWillBeAvail()) { + break; + }; + GenerateSavePhiOcc(phiOcc); + break; + } + case kOccExit: + break; + case kOccMembar: + case kOccUse: + break; + default: + ASSERT(false, "should not be here"); + } + } + // update the inserted phiOcc's operand + UpdateInsertedPhiOccOpnd(); + if (GetSSAPreDebug()) { + mirModule->GetOut() << "========ssapre candidate " << workCand->GetIndex() << + " after CodeMotion ===================\n"; + if (curTemp) { + mirModule->GetOut() << "curTemp is"; + curTemp->Dump(irMap, 0); + mirModule->GetOut() << "\n"; + } + } +} + +// ================ Step 5: Finalize ================= +void SSAPre::Finalize1() { + std::vector availDefVec(classCount, nullptr); + // traversal in preoder DT + for (MeOccur *occ : allOccs) { + size_t classX = static_cast(static_cast(occ->GetClassID())); + switch (occ->GetOccType()) { + case kOccPhiocc: { + auto *phiOcc = static_cast(occ); + if (phiOcc->IsWillBeAvail()) { + availDefVec[classX] = phiOcc; + } + break; + } + case kOccReal: { + MeOccur *availDef = availDefVec[classX]; + auto *realOcc = static_cast(occ); + if (availDef == nullptr || !availDef->IsDominate(dom, occ)) { + realOcc->SetIsReload(false); + availDefVec[classX] = realOcc; + } else { + realOcc->SetIsReload(true); + ASSERT(!realOcc->IsSave(), "real occ with isSave cannot be set isReload"); + realOcc->SetDef(availDefVec[classX]); + } + break; + } + case kOccPhiopnd: { + // we assume one phiOpnd has only one phiOcc use because critical edge split the blocks + auto *phiOpnd = static_cast(occ); + MePhiOcc *phiOcc = phiOpnd->GetDefPhiOcc(); + if (phiOcc->IsWillBeAvail()) { + if (phiOpnd->IsOkToInsert()) { + // insert the current expression at the end of the block containing phiOpnd + if (phiOpnd->GetBB()->GetSucc().size() > 1) { + CHECK_FATAL(!workCand->Redo2HandleCritEdges(), "Finalize1: insertion at critical edge, aborting"); + workCand->SetRedo2HandleCritEdges(true); + if (GetSSAPreDebug()) { + mirModule->GetOut() << "<<<<< Re-doing this candidate due to existence of critical edge >>>>>\n"; + } + return; + } + MeExpr *insertedExpr = phiOpnd->GetCurrentMeExpr(); + ASSERT(insertedExpr != nullptr, "NYI"); + MeInsertedOcc *insertedOcc = + perCandMemPool->New(insertedExpr, static_cast(nullptr), phiOpnd->GetBB()); + insertedOcc->SetClassID(classCount++); + phiOpnd->SetDef(insertedOcc); + phiOpnd->SetClassID(insertedOcc->GetClassID()); + if (workCand->GetPUIdx() != GetPUIdx()) { + ASSERT(!workCand->HasLocalOpnd(), "candidate with local opnd cannot be inserted outside its PU"); + workCand->SetPUIdx(0); + } + phiOpnd->SetIsInsertedOcc(true); + } else { + phiOpnd->SetDef(availDefVec[classX]); + } + } + break; + } + case kOccExit: + break; + case kOccMembar: + case kOccUse: + break; + default: + ASSERT(false, "should not be here"); + } + } + if (GetSSAPreDebug()) { + PreWorkCand *curCand = workCand; + mirModule->GetOut() << "========ssapre candidate " << curCand->GetIndex() << + " after Finalize1===================\n"; + for (auto it = phiOccs.begin(); it != phiOccs.end(); ++it) { + MePhiOcc *phiOcc = *it; + if (phiOcc->IsWillBeAvail()) { + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + ASSERT(phiOpnd->GetDef(), "EPhiFinalizer::DumpFinalize1: phiopndocc cannot have no def"); + MeOccur *defOcc = phiOpnd->GetDef(); + if (defOcc->GetOccType() == kOccInserted) { + auto *realDefOcc = static_cast(defOcc); + phiOpnd->Dump(*irMap); + mirModule->GetOut() << " was inserted by "; + realDefOcc->Dump(*irMap); + mirModule->GetOut() << "\n"; + } + } + } + } + } +} + +// set save the real occurrence of definition to register +// set the PHI occurence to be needed (extraneous being false) +void SSAPre::SetSave(MeOccur *defX) { + CHECK_FATAL(defX, "invalid defX"); + if (defX->GetOccType() == kOccReal) { + auto *realOcc = static_cast(defX); + realOcc->SetIsSave(true); + ASSERT(!realOcc->IsReload(), "real occ with isReload cannot be set isSave"); + } else if (defX->GetOccType() == kOccPhiocc) { + for (MePhiOpndOcc *phiOpnd : static_cast(defX)->GetPhiOpnds()) { + if (!phiOpnd->IsProcessed()) { + phiOpnd->SetIsProcessed(true); + ASSERT(phiOpnd->GetDef(), "EPhiFinalizer::SetSave: phiopndocc cannot have no def"); + SetSave(phiOpnd->GetDef()); + } + } + } + if (defX->GetOccType() == kOccReal || defX->GetOccType() == kOccInserted) { + BB *fromBb = defX->GetBB(); + MapleSet itFrontier(perCandAllocator.Adapter()); + CHECK_FATAL(!dom->IsBBVecEmpty(), "the size to be allocated is 0"); + std::vector visitedMap(dom->GetBBVecSize(), false); + GetIterDomFrontier(*fromBb, itFrontier, visitedMap); + for (MePhiOcc *phiOcc : phiOccs) { + if (!phiOcc->IsWillBeAvail()) { + continue; + } + if (itFrontier.find(dom->GetDtDfnItem(phiOcc->GetBB()->GetBBId())) == itFrontier.end()) { + continue; + } + phiOcc->SetIsExtraneous(false); + } + } +} + +void SSAPre::SetReplacement(MePhiOcc *occg, MeOccur *repDef) { + occg->SetIsRemoved(true); // exclude recursive PhiOcc + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + if (phiOcc->IsRemoved()) { + continue; + } + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() == occg) { + if (phiOcc->IsExtraneous()) { + // exclude recursive def + SetReplacement(phiOcc, repDef); + } else { + phiOpnd->SetDef(repDef); // replace phiOpnd of phiOcc by replacing def repDef + phiOpnd->SetClassID(repDef->GetClassID()); + phiOpnd->SetIsPhiOpndReload(true); + } + } + } + } + for (auto it = workCand->GetRealOccs().begin(); it != workCand->GetRealOccs().end(); it++) { + MeRealOcc *realOcc = *it; + // when realOcc satisfying reload and def of it is occg, do the replacement + if (realOcc->IsReload() && realOcc->GetDef() == occg) { + realOcc->SetDef(repDef); + realOcc->SetClassID(repDef->GetClassID()); + } + } +} + +void SSAPre::Finalize2() { + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + // initialize extraneouse for each MePhiOcc + phiOcc->SetIsExtraneous(phiOcc->IsWillBeAvail()); + // initialize each operand of phiOcc + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + phiOpnd->SetIsProcessed(false); + } + } + for (auto it = workCand->GetRealOccs().begin(); it != workCand->GetRealOccs().end(); it++) { + MeRealOcc *realOcc = *it; + if (realOcc->IsReload()) { + SetSave(realOcc->GetDef()); + } + } + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + if (phiOcc->IsRemoved() || !phiOcc->IsExtraneous()) { + continue; + } + if (!phiOcc->IsWillBeAvail()) { + phiOcc->SetIsRemoved(true); + continue; + } + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + MeOccur *defOcc = phiOpnd->GetDef(); + switch (defOcc->GetOccType()) { + case kOccReal: + case kOccInserted: + SetReplacement(phiOcc, defOcc); + break; + case kOccPhiocc: + if (!static_cast(defOcc)->IsExtraneous()) { + SetReplacement(phiOcc, defOcc); + } + break; + default: + CHECK_FATAL(false, "unexpected phiOpnd"); + } + } + } + if (GetSSAPreDebug()) { + mirModule->GetOut() << "========after Finalize2====================\n"; + for (MeOccur *occ : allOccs) { + if (occ->GetOccType() == kOccPhiocc) { + auto *phiOcc = static_cast(occ); + if (phiOcc->IsExtraneous()) { + phiOcc->Dump(*irMap); + mirModule->GetOut() << "was removed in Finalize2\n"; + } + } else if (occ->GetOccType() == kOccReal) { + auto *realOcc = static_cast(occ); + if (realOcc->IsReload()) { + realOcc->Dump(*irMap); + mirModule->GetOut() << " isReload\n"; + } + if (realOcc->IsSave()) { + realOcc->Dump(*irMap); + mirModule->GetOut() << " isSave\n"; + } + } else if (occ->GetOccType() == kOccPhiopnd) { + auto *phiopndocc = static_cast(occ); + if (phiopndocc->IsInsertedOcc()) { + phiopndocc->Dump(*irMap); + mirModule->GetOut() << " inserthere\n"; + } + } + } + } +} + +// ================ Step 4: WillBeAvail Computation ================= +// propagate not-can_be_avail attribute forward +// along def-use chain to not-downsafety nodes +void SSAPre::ResetCanBeAvail(MePhiOcc *occg) { + occg->SetIsCanBeAvail(false); + // the following loop is to find occg's use list and reset them + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() && phiOpnd->GetDef() == occg) { + // when comes here, phiOpnd->GetDef() is a use of occg + if (!phiOpnd->HasRealUse() && !phiOcc->IsDownSafe() && phiOcc->IsCanBeAvail()) { + ResetCanBeAvail(phiOcc); + } + } + } + } +} + +void SSAPre::ComputeCanBeAvail() { + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + if (!phiOcc->IsDownSafe() && phiOcc->IsCanBeAvail()) { + bool existNullDef = false; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() == nullptr) { + existNullDef = true; + break; + } + } + if (existNullDef) { + ResetCanBeAvail(phiOcc); + } + } + if (workCand->Redo2HandleCritEdges() && phiOcc->IsCanBeAvail()) { + // check critical edges + bool existCritEdge = false; + for (BB *pred : phiOcc->GetBB()->GetPred()) + if (pred->GetSucc().size() > 1) { + existCritEdge = true; + break; + } + if (existCritEdge) { + ResetCanBeAvail(phiOcc); + } + } + } +} + +void SSAPre::ResetLater(MePhiOcc *occg) { + occg->SetIsLater(false); + // the following loop is to find occg's use list and reset them + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() && phiOpnd->GetDef() == occg) { + // when comes here, phiOpnd->GetDef() is a use of occg + if (phiOcc->IsLater()) { + ResetLater(phiOcc); + } + } + } + } +} + +void SSAPre::ComputeLater() { + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + phiOcc->SetIsLater(phiOcc->IsCanBeAvail()); + } + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + if (phiOcc->IsLater()) { + bool existNonNullDef = false; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (phiOpnd->GetDef() != nullptr && phiOpnd->HasRealUse()) { + existNonNullDef = true; + break; + } + } + if (existNonNullDef || phiOcc->SpeculativeDownSafe()) { + ResetLater(phiOcc); + } + } + } + if (GetSSAPreDebug()) { + mirModule->GetOut() << "========ssapre candidate " << workCand->GetIndex() + << " after WillBeAvail===================\n"; + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + phiOcc->Dump(*irMap); + if (phiOcc->IsCanBeAvail()) { + mirModule->GetOut() << " can be avail;"; + } else { + mirModule->GetOut() << " not can be avail;"; + } + if (phiOcc->IsLater()) { + mirModule->GetOut() << " later;"; + } else { + mirModule->GetOut() << " not later;"; + } + if (phiOcc->IsCanBeAvail() && !phiOcc->IsLater()) { + mirModule->GetOut() << " will be avail"; + } else { + mirModule->GetOut() << " not will be avail"; + } + mirModule->GetOut() << "\n"; + } + } +} + +// ================ Step 3: Downsafe Computation ================= +// reset downsafety +void SSAPre::ResetDS(MePhiOpndOcc *phiOpnd) { + if (phiOpnd->HasRealUse()) { + return; + } + MeOccur *defOcc = phiOpnd->GetDef(); + if (!defOcc || defOcc->GetOccType() != kOccPhiocc) { + return; + } + auto *defPhiOcc = static_cast(defOcc); + if (defPhiOcc->SpeculativeDownSafe()) { + return; + } + if (!defPhiOcc->IsDownSafe()) { + return; + } + defPhiOcc->SetIsDownSafe(false); + for (MePhiOpndOcc *mePhiOpnd : defPhiOcc->GetPhiOpnds()) { + ResetDS(mePhiOpnd); + } +} + +// compute downsafety for each PHI +void SSAPre::ComputeDS() { + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + if (!phiOcc->IsDownSafe()) { + // propagate not-downsafety along use-def edges + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + ResetDS(phiOpnd); + } + } + } + if (GetSSAPreDebug()) { + mirModule->GetOut() << "========ssapre candidate " << workCand->GetIndex() + << " after DownSafety===================\n"; + for (auto it = phiOccs.begin(); it != phiOccs.end(); it++) { + MePhiOcc *phiOcc = *it; + phiOcc->Dump(*irMap); + if (phiOcc->SpeculativeDownSafe()) { + mirModule->GetOut() << " spec_downsafe /"; + } + if (phiOcc->IsDownSafe()) { + mirModule->GetOut() << " is downsafe\n"; + for (MePhiOpndOcc *phiOpnd : phiOcc->GetPhiOpnds()) { + if (!phiOpnd->IsProcessed()) { + phiOpnd->Dump(*irMap); + mirModule->GetOut() << " has not been processed by Rename2\n"; + } + } + } else { + mirModule->GetOut() << " is not downsafe\n"; + } + } + } +} + +// ================ Step 2: Renaming ================= +void SSAPre::Rename1() { + std::stack occStack; + rename2Set.clear(); + classCount = 1; + // iterate the occurrence according to its preorder dominator tree + for (MeOccur *occ : allOccs) { + while (!occStack.empty() && !occStack.top()->IsDominate(dom, occ)) { + occStack.pop(); + } + switch (occ->GetOccType()) { + case kOccReal: { + if (occStack.empty()) { + // assign new class + occ->SetClassID(classCount++); + occStack.push(occ); + break; + } + MeOccur *topOccur = occStack.top(); + if (topOccur->GetOccType() == kOccUse || topOccur->GetOccType() == kOccMembar) { + occ->SetClassID(classCount++); + occStack.push(occ); + break; + } + auto *realOcc = static_cast(occ); + if (topOccur->GetOccType() == kOccReal) { + auto *realTopOccur = static_cast(topOccur); + if (AllVarsSameVersion(realTopOccur, realOcc)) { + // all corresponding variables are the same + realOcc->SetClassID(realTopOccur->GetClassID()); + if (realTopOccur->GetDef() != nullptr) { + realOcc->SetDef(realTopOccur->GetDef()); + } else { + realOcc->SetDef(realTopOccur); + } + } else { + // assign new class + occ->SetClassID(classCount++); + occStack.push(occ); + } + } else { + // top of stack is a PHI occurrence + ASSERT(topOccur->GetOccType() == kOccPhiocc, "invalid kOccPhiocc"); + std::vector varVec; + CollectVarForCand(realOcc, varVec); + bool isAllDom = true; + if (realOcc->IsLHS()) { + isAllDom = false; + } else { + for (auto varIt = varVec.begin(); varIt != varVec.end(); ++varIt) { + MeExpr *varMeExpr = *varIt; + if (!DefVarDominateOcc(varMeExpr, topOccur)) { + isAllDom = false; + } + } + } + if (isAllDom) { + realOcc->SetClassID(topOccur->GetClassID()); + realOcc->SetDef(topOccur); + rename2Set.insert(realOcc->GetPosition()); + occStack.push(realOcc); + if (IsLoopHeadBB(topOccur->GetBB()->GetBBId())) { + static_cast(topOccur)->SetSpeculativeDownSafe(true); + static_cast(topOccur)->SetIsDownSafe(true); + } + } else { + auto *phiTopOccur = static_cast(topOccur); + if (!phiTopOccur->SpeculativeDownSafe()) { + phiTopOccur->SetIsDownSafe(false); + } + // assign new class + occ->SetClassID(classCount++); + occStack.push(occ); + } + } + break; + } + case kOccPhiocc: { + // assign new class + occ->SetClassID(classCount++); + occStack.push(occ); + break; + } + case kOccPhiopnd: { + // stow away the use occurrences at the stack top + MeOccur *stowedUseOcc = nullptr; + if (!occStack.empty() && occStack.top()->GetOccType() == kOccUse) { + stowedUseOcc = occStack.top(); + occStack.pop(); + CHECK_FATAL(occStack.empty() || occStack.top()->GetOccType() != kOccUse, + "Rename1: cannot have 2 consecutive use occurs on stack"); + } + if (occStack.empty() || occStack.top()->GetOccType() == kOccMembar) { + occ->SetDef(nullptr); + } else { + MeOccur *topOccur = occStack.top(); + occ->SetDef(topOccur); + occ->SetClassID(topOccur->GetClassID()); + if (topOccur->GetOccType() == kOccReal) { + static_cast(occ)->SetHasRealUse(true); + } + } + // push stowed use_occ back + if (stowedUseOcc != nullptr) { + occStack.push(stowedUseOcc); + } + break; + } + case kOccExit: { + if (occStack.empty()) { + break; + } + MeOccur *topOccur = occStack.top(); + if (topOccur->GetOccType() == kOccPhiocc) { + auto *phiTopOccur = static_cast(topOccur); + if (!phiTopOccur->SpeculativeDownSafe()) { + phiTopOccur->SetIsDownSafe(false); + } + } + break; + } + case kOccMembar: + case kOccUse: { + if (!occStack.empty()) { + MeOccur *topOccur = occStack.top(); + if (topOccur->GetOccType() == kOccPhiocc) { + auto *phiTopOccur = static_cast(topOccur); + phiTopOccur->SetIsDownSafe(false); + } else if (topOccur->GetOccType() != occ->GetOccType()) { + occStack.push(occ); + } + } else { + occStack.push(occ); + } + break; + } + default: + ASSERT(false, "should not be here"); + } + } + if (GetSSAPreDebug()) { + PreWorkCand *curCand = workCand; + mirModule->GetOut() << "========ssapre candidate " << curCand->GetIndex() << " after rename1===================\n"; + for (MeOccur *occ : allOccs) { + occ->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + mirModule->GetOut() << "\n" << "rename2 set:\n"; + for (uint32 pos : rename2Set) { + MeRealOcc *occur = workCand->GetRealOcc(pos); + occur->Dump(*irMap); + mirModule->GetOut() << " with def at\n"; + occur->GetDef()->Dump(*irMap); + mirModule->GetOut() << "\n"; + } + mirModule->GetOut() << "\n"; + } +} + +// if opnd is defined by phi, return the jth opnd of the phi; +// return nullptr otherwise +MeExpr *SSAPre::GetReplaceMeExpr(MeExpr *opnd, const BB *ePhiBB, size_t j) { + if (opnd->GetMeOp() != kMeOpVar && opnd->GetMeOp() != kMeOpReg) { + return nullptr; + } + MeExpr *retExpr = nullptr; + if (opnd->GetMeOp() == kMeOpVar) { + MeVarPhiNode *defPhi = static_cast(opnd)->GetMeVarPhiDef(); + if (defPhi != nullptr) { + if (ePhiBB->GetBBId() == defPhi->GetDefBB()->GetBBId()) { + ASSERT(defPhi->GetOpnds()[j]->GetMeOp() == opnd->GetMeOp(), "invalid defPhi"); + retExpr = defPhi->GetOpnds()[j]; + } + } + } else { + MeRegPhiNode *defPhi = static_cast(opnd)->GetMeRegPhiDef(); + if (defPhi != nullptr) { + if (ePhiBB->GetBBId() == defPhi->GetDefBB()->GetBBId()) { + ASSERT(j < defPhi->GetOpnds().size(), "index out of range in SSAPre::GetReplaceMeExpr"); + ASSERT(defPhi->GetOpnds()[j]->GetMeOp() == opnd->GetMeOp(), "invalid defPhi"); + retExpr = defPhi->GetOpnds()[j]; + } + } + } + if (retExpr != nullptr && retExpr->GetPrimType() == kPtyInvalid) { + retExpr->SetPtyp(workCand->GetPrimType()); + } + return retExpr; +} + +void SSAPre::Rename2() { + while (!rename2Set.empty()) { + MapleSet::iterator it = rename2Set.begin(); + MeRealOcc *realOcc = workCand->GetRealOcc(*it); + rename2Set.erase(it); + MeOccur *defOcc = realOcc->GetDef(); + if (!defOcc || defOcc->GetOccType() != kOccPhiocc) { + CHECK_FATAL(false, "should be def by phiOcc"); + } + auto *defPhiOcc = static_cast(defOcc); + auto &phiOpnds = defPhiOcc->GetPhiOpnds(); + for (size_t i = 0; i < phiOpnds.size(); i++) { + MePhiOpndOcc *phiOpnd = phiOpnds[i]; + if (!phiOpnd->IsProcessed()) { + phiOpnd->SetIsProcessed(true); + MeExpr *exprY = PhiOpndFromRes(realOcc, i); + phiOpnd->SetCurrentMeExpr(*exprY); // expr_y might be inserted at the end of the block + MeOccur *defX = phiOpnd->GetDef(); + if (defX == nullptr) { + continue; + } + if (defX->GetOccType() == kOccReal) { + auto *realDefX = static_cast(defX); + std::vector varvecX; + std::vector varvecY; + CollectVarForMeExpr(realDefX->GetMeExpr(), varvecX); + CollectVarForMeExpr(exprY, varvecY); + CHECK_FATAL(varvecX.size() == varvecY.size(), "invalid size of varvecY"); + bool hasSameVersion = true; + for (size_t ii = 0; ii < varvecX.size(); ii++) { + if (varvecX[ii] != varvecY[ii]) { + hasSameVersion = false; + } + } + if (!hasSameVersion) { + phiOpnd->SetDef(nullptr); + phiOpnd->SetHasRealUse(false); + } + } else if (defX->GetOccType() == kOccPhiocc) { + std::vector varvecY; + bool alldom = true; + CollectVarForMeExpr(exprY, varvecY); + for (size_t ii = 0; ii < varvecY.size(); ++ii) { + if (!DefVarDominateOcc(varvecY[ii], defX)) { + alldom = false; + } + } + if (alldom) { + // create a realOcc and add to rename2 set + MeRealOcc *occY = perCandMemPool->New(static_cast(nullptr), 0, exprY); + occY->SetPosition(workCand->GetRealOccs().size()); + workCand->GetRealOccs().push_back(occY); + occY->SetDef(defX); + occY->SetClassID(defX->GetClassID()); + rename2Set.insert(occY->GetPosition()); + if (GetSSAPreDebug()) { + mirModule->GetOut() << "--- rename2 adds to rename2Set manufactured "; + occY->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + } else { + phiOpnd->SetDef(nullptr); + phiOpnd->SetHasRealUse(false); + auto *phidefx = static_cast(defX); + if (!phidefx->SpeculativeDownSafe()) { + phidefx->SetIsDownSafe(false); + } + } + } + } + } + } + if (GetSSAPreDebug()) { + PreWorkCand *curCand = workCand; + mirModule->GetOut() << "========ssapre candidate " << curCand->GetIndex() << " after rename2===================\n"; + for (MeOccur *occ : allOccs) { + occ->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + } +} + +// ================ Step 1: Phi Insertion ================= +void SSAPre::SetVarPhis(MeExpr *meExpr) { + MeExprOp meOp = meExpr->GetMeOp(); + if (meOp != kMeOpVar && meOp != kMeOpReg) { + return; + } + if (meOp == kMeOpVar) { + MeVarPhiNode *phiMeNode = static_cast(meExpr)->GetMeVarPhiDef(); + if (phiMeNode != nullptr) { + BBId defbbid = phiMeNode->GetDefBB()->GetBBId(); + if (varPhiDfns.find(dom->GetDtDfnItem(defbbid)) == varPhiDfns.end() && ScreenPhiBB(defbbid)) { + varPhiDfns.insert(dom->GetDtDfnItem(defbbid)); + for (auto opndit = phiMeNode->GetOpnds().begin(); opndit != phiMeNode->GetOpnds().end(); opndit++) { + VarMeExpr *opnd = *opndit; + SetVarPhis(opnd); + } + } + } + } else { + MeRegPhiNode *phiMeNode = static_cast(meExpr)->GetMeRegPhiDef(); + if (phiMeNode) { + BBId defBbId = phiMeNode->GetDefBB()->GetBBId(); + CHECK(defBbId < dom->GetDtDfnSize(), "defBbId.idx out of range in SSAPre::SetVarPhis"); + if (varPhiDfns.find(dom->GetDtDfnItem(defBbId)) == varPhiDfns.end() && ScreenPhiBB(defBbId)) { + varPhiDfns.insert(dom->GetDtDfnItem(defBbId)); + for (auto opndIt = phiMeNode->GetOpnds().begin(); opndIt != phiMeNode->GetOpnds().end(); + ++opndIt) { + RegMeExpr *opnd = *opndIt; + SetVarPhis(opnd); + } + } + } + } +} + +// based on ssapre->workCand's realOccs and dfPhiDfns (which now privides all +// the inserted phis), create the phi and phiOpnd occ nodes; link them all up in +// order of dt_preorder in ssapre->allOccs; the phi occ nodes are in addition +// provided in order of dt_preorder in ssapre->phiOccs +void SSAPre::CreateSortedOccs() { + // merge varPhiDfns to dfPhiDfns + dfPhiDfns.insert(varPhiDfns.begin(), varPhiDfns.end()); + // form phiOpnd_dfns + std::multiset phiOpndDfns; + for (uint32 dfn : dfPhiDfns) { + BBId bbId = dom->GetDtPreOrderItem(dfn); + BB *bb = GetBB(bbId); + ASSERT(bb != nullptr, "GetBB return null in SSAPre::CreateSortedOccs"); + for (BB *pred : bb->GetPred()) { + phiOpndDfns.insert(dom->GetDtDfnItem(pred->GetBBId())); + } + } + // under lpre, form lhs occ for formals at function entry + if (GetRcLoweringOn()) { + BuildEntryLHSOcc4Formals(); + } + std::unordered_map> bb2phiopndMap; + MapleVector::iterator realOccIt = workCand->GetRealOccs().begin(); + MapleVector::iterator exitOccIt = exitOccs.begin(); + auto phiDfnIt = dfPhiDfns.begin(); + auto phiOpndDfnIt = phiOpndDfns.begin(); + MeRealOcc *nextRealOcc = nullptr; + if (realOccIt != workCand->GetRealOccs().end()) { + nextRealOcc = *realOccIt; + } + MeOccur *nextExitOcc = nullptr; + if (exitOccIt != exitOccs.end()) { + nextExitOcc = *exitOccIt; + } + MePhiOcc *nextPhiOcc = nullptr; + if (phiDfnIt != dfPhiDfns.end()) { + CHECK_FATAL(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)) != nullptr, "GetBB return nullptr!"); + nextPhiOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)), &perCandAllocator); + } + MePhiOpndOcc *nextPhiOpndOcc = nullptr; + if (phiOpndDfnIt != phiOpndDfns.end()) { + nextPhiOpndOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiOpndDfnIt))); + auto it = bb2phiopndMap.find(dom->GetDtPreOrderItem(*phiOpndDfnIt)); + if (it == bb2phiopndMap.end()) { + std::forward_list newlist = { nextPhiOpndOcc }; + CHECK(*phiOpndDfnIt < dom->GetDtPreOrderSize(), "index out of range in SSAPre::CreateSortedOccs"); + bb2phiopndMap[dom->GetDtPreOrderItem(*phiOpndDfnIt)] = newlist; + } else { + it->second.push_front(nextPhiOpndOcc); + } + } + MeOccur *pickedOcc; // the next picked occ in order of preorder traveral of dominator tree + do { + pickedOcc = nullptr; + // the 4 kinds of occ must be checked in this order, so it will be right + // if more than 1 has the same dfn + if (nextPhiOcc != nullptr) { + pickedOcc = nextPhiOcc; + } + if (nextRealOcc && (pickedOcc == nullptr || + dom->GetDtDfnItem(nextRealOcc->GetBB()->GetBBId()) < + dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextRealOcc; + } + if (nextExitOcc && (pickedOcc == nullptr || + dom->GetDtDfnItem(nextExitOcc->GetBB()->GetBBId()) < + dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextExitOcc; + } + if (nextPhiOpndOcc && + (pickedOcc == nullptr || *phiOpndDfnIt < dom->GetDtDfnItem(pickedOcc->GetBB()->GetBBId()))) { + pickedOcc = nextPhiOpndOcc; + } + if (pickedOcc != nullptr) { + allOccs.push_back(pickedOcc); + switch (pickedOcc->GetOccType()) { + case kOccReal: + case kOccMembar: + realOccIt++; + if (realOccIt != workCand->GetRealOccs().end()) { + nextRealOcc = *realOccIt; + } else { + nextRealOcc = nullptr; + } + break; + case kOccExit: + exitOccIt++; + if (exitOccIt != exitOccs.end()) { + nextExitOcc = *exitOccIt; + } else { + nextExitOcc = nullptr; + } + break; + case kOccPhiocc: + phiOccs.push_back(static_cast(pickedOcc)); + phiDfnIt++; + if (phiDfnIt != dfPhiDfns.end()) { + CHECK_FATAL(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)) != nullptr, + "GetBB return null in SSAPre::CreateSortedOccs"); + nextPhiOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiDfnIt)), &perCandAllocator); + } else { + nextPhiOcc = nullptr; + } + break; + case kOccPhiopnd: + phiOpndDfnIt++; + if (phiOpndDfnIt != phiOpndDfns.end()) { + nextPhiOpndOcc = perCandMemPool->New(GetBB(dom->GetDtPreOrderItem(*phiOpndDfnIt))); + auto it = bb2phiopndMap.find(dom->GetDtPreOrderItem(*phiOpndDfnIt)); + if (it == bb2phiopndMap.end()) { + std::forward_list newlist = { nextPhiOpndOcc }; + bb2phiopndMap[dom->GetDtPreOrderItem(*phiOpndDfnIt)] = newlist; + } else { + it->second.push_front(nextPhiOpndOcc); + } + } else { + nextPhiOpndOcc = nullptr; + } + break; + default: + ASSERT(false, "CreateSortedOccs: unexpected occty"); + } + } + } while (pickedOcc != nullptr); + // initialize phiOpnds vector in each MePhiOcc node and defPhiOcc field in + // each MePhiOpndOcc node + for (MePhiOcc *phiOcc : phiOccs) + for (BB *pred : phiOcc->GetBB()->GetPred()) { + MePhiOpndOcc *phiopndocc = bb2phiopndMap[pred->GetBBId()].front(); + phiOcc->AddPhiOpnd(*phiopndocc); + phiopndocc->SetDefPhiOcc(*phiOcc); + bb2phiopndMap[pred->GetBBId()].pop_front(); + } + if (GetSSAPreDebug()) { + mirModule->GetOut() << "========ssapre candidate " << workCand->GetIndex() << + " after phi insert===================\n"; + for (MeOccur *occ : allOccs) { + occ->Dump(*irMap); + mirModule->GetOut() << '\n'; + } + } +} + +// ================ End of Step 1: Phi Insertion ================= +IassignMeStmt *SSAPre::CopyIassignMeStmt(const IassignMeStmt &iaStmt) { + IassignMeStmt *meStmt = irMap->NewInPool(iaStmt); + return meStmt; +} + +MeStmt *SSAPre::CopyMeStmt(MeStmt &meStmt) { + CHECK_FATAL(meStmt.GetOp() == OP_assertlt || meStmt.GetOp() == OP_assertge, "invalid value of meStmt.GetOp()"); + auto *oldStmt = static_cast(&meStmt); + AssertMeStmt *newStmt = irMap->New(*oldStmt); + return newStmt; +} + +MeExpr *SSAPre::CopyMeExpr(MeExpr &expr) { + MapleAllocator *irMapAlloc = &irMap->GetIRMapAlloc(); + switch (expr.GetMeOp()) { + case kMeOpOp: { + auto &opExpr = static_cast(expr); + OpMeExpr *newExpr = irMapAlloc->GetMemPool()->New(opExpr, -1); + newExpr->InitBase(opExpr.GetOp(), opExpr.GetPrimType(), opExpr.GetNumOpnds()); + return newExpr; + } + case kMeOpNary: { + auto &naryMeExpr = static_cast(expr); + NaryMeExpr *newNaryMeExpr = irMapAlloc->GetMemPool()->New(irMapAlloc, -1, naryMeExpr); + return newNaryMeExpr; + } + case kMeOpIvar: { + auto &ivarMeExpr = static_cast(expr); + IvarMeExpr *newIvar = irMapAlloc->GetMemPool()->New(-1, ivarMeExpr); + newIvar->InitBase(ivarMeExpr.GetOp(), ivarMeExpr.GetPrimType(), ivarMeExpr.GetNumOpnds()); + return newIvar; + } + default: + CHECK_FATAL(false, "NYI"); + } +} + +// if the definition of varMeExpr dominate meocc then return true. otherwise return false; +bool SSAPre::DefVarDominateOcc(MeExpr *meExpr, MeOccur *meOcc) { + if (meExpr == nullptr) { + // can be nullptr in the case of LHS occurrence + return false; + } + CHECK_FATAL(meOcc->GetOccType() == kOccPhiocc, "invalid value of meOcc->GetOccType()"); + BB *occBB = (static_cast(meOcc))->GetBB(); + if (meExpr->GetMeOp() == kMeOpVar) { + auto *varMeExpr = static_cast(meExpr); + switch (varMeExpr->GetDefBy()) { + case kDefByNo: + return true; // it's an original variable which dominates everything + case kDefByStmt: { + MeStmt *meStmt = varMeExpr->GetDefStmt(); + CHECK_FATAL(meStmt, "should have a def meStmt"); + BB *defBB = meStmt->GetBB(); + if (occBB == defBB) { + return false; + } else { + return dom->Dominate(*defBB, *occBB); + } + } + case kDefByPhi: { + MeVarPhiNode &phiMeNode = varMeExpr->GetDefPhi(); + BB *defBB = phiMeNode.GetDefBB(); + if (defBB->GetBBId() == occBB->GetBBId()) { + return true; + } + return dom->Dominate(*defBB, *occBB); + } + case kDefByMustDef: { + MeStmt *meStmt = varMeExpr->GetDefMustDef().GetBase(); + if (meStmt == nullptr) { + return true; // it's a original variable dominate everything + } + BB *defBB = meStmt->GetBB(); + if (occBB == defBB) { + return false; + } else { + return dom->Dominate(*defBB, *occBB); + } + } + case kDefByChi: { + MeStmt *meStmt = varMeExpr->GetDefChi().GetBase(); + if (!meStmt) { + return true; // it's a original variable dominate everything + } + BB *defBB = meStmt->GetBB(); + if (occBB == defBB) { + return false; + } else { + return dom->Dominate(*defBB, *occBB); + } + } + default: + CHECK_FATAL(false, "to be done"); + } + } else { + CHECK_FATAL(meExpr->GetMeOp() == kMeOpReg, "invalid value of meExpr->GetMeOp()"); + auto *regMeExpr = static_cast(meExpr); + switch (regMeExpr->GetDefBy()) { + case kDefByNo: + return true; // original st dominates everything + case kDefByStmt: { + MeStmt *meStmt = regMeExpr->GetDefStmt(); + CHECK_FATAL(meStmt, "invalid value of meStmt"); + BB *defBB = meStmt->GetBB(); + if (occBB == defBB) { + return false; + } else { + return dom->Dominate(*defBB, *occBB); + } + } + case kDefByPhi: { + MeRegPhiNode &phiMeNode = regMeExpr->GetDefPhi(); + BB *defBB = phiMeNode.GetDefBB(); + if (defBB->GetBBId() == occBB->GetBBId()) { + return true; + } + return dom->Dominate(*defBB, *occBB); + } + case kDefByMustDef: { + MeStmt *meStmt = regMeExpr->GetDefMustDef().GetBase(); + if (meStmt == nullptr) { + return true; // it's a original variable dominate everything + } + BB *defBB = meStmt->GetBB(); + if (occBB == defBB) { + return false; + } else { + return dom->Dominate(*defBB, *occBB); + } + } + default: + CHECK_FATAL(false, "to be done"); + } + } +} + +bool SSAPre::CheckIfAnyLocalOpnd(MeExpr *x) { + switch (x->GetMeOp()) { + case kMeOpReg: + return true; + case kMeOpVar: { + auto *varMeExpr = static_cast(x); + const MIRSymbol *st = ssaTab->GetMIRSymbolFromID(varMeExpr->GetOStIdx()); + return st->IsLocal(); + } + case kMeOpIvar: { + auto *ivarMeExpr = static_cast(x); + return CheckIfAnyLocalOpnd(ivarMeExpr->GetBase()); + } + case kMeOpOp: { + auto *opMeExpr = static_cast(x); + if (CheckIfAnyLocalOpnd(opMeExpr->GetOpnd(0))) { + return true; + } + if (opMeExpr->GetOpnd(1) == nullptr) { + return false; + } + if (CheckIfAnyLocalOpnd(opMeExpr->GetOpnd(1))) { + return true; + } + if (opMeExpr->GetOpnd(2) == nullptr) { + return false; + } + return CheckIfAnyLocalOpnd(opMeExpr->GetOpnd(2)); + } + case kMeOpNary: { + auto *naryMeExpr = static_cast(x); + for (MeExpr *opnd : naryMeExpr->GetOpnds()) + if (CheckIfAnyLocalOpnd(opnd)) { + return true; + } + return false; + } + default: + return false; + } +} + +// create a new realOcc based on the meStmt and meExpr +MeRealOcc *SSAPre::CreateRealOcc(MeStmt &meStmt, int seqStmt, MeExpr &meExpr, bool isRebuilt, bool isLHS) { + uint32 hashIdx = PreWorkCand::ComputeWorkCandHashIndex(meExpr); + PreWorkCand *wkCand = PreWorkCand::GetWorkcandFromIndex(hashIdx); + while (wkCand != nullptr) { + MeExpr *x = wkCand->GetTheMeExpr(); + ASSERT(x != nullptr, "CreateRealOcc: found workcand with theMeExpr as nullptr"); + if (x->IsTheSameWorkcand(meExpr)) { + break; + } + wkCand = static_cast(wkCand->GetNext()); + } + MeRealOcc *newOcc = ssaPreMemPool->New(&meStmt, seqStmt, &meExpr); + newOcc->SetIsLHS(isLHS); + if (wkCand != nullptr) { + if (isRebuilt) { + CHECK_FATAL(wkCand->GetIndex() >= reBuiltOccIndex, "new ssapre work candidate is found as old work candidate"); + // insert to realOccs in dt_preorder of the BBs and seq in each BB + wkCand->AddRealOccSorted(*dom, *newOcc, GetPUIdx()); + } else { + wkCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + } + return newOcc; + } + // workcand not yet created; create a new one and add to worklist + wkCand = ssaPreMemPool->New(&ssaPreAllocator, workList.size(), &meExpr, GetPUIdx()); + wkCand->SetHasLocalOpnd(CheckIfAnyLocalOpnd(&meExpr)); + if (EpreLocalRefVar() && wkCand->GetTheMeExpr()->GetMeOp() == kMeOpIvar) { + // set wkCand->NeedLocalRefVar() flag + auto *ivarMeExpr = static_cast(wkCand->GetTheMeExpr()); + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivarMeExpr->GetTyIdx()); + CHECK_FATAL(mirType->GetKind() == kTypePointer, "must be point type for ivar"); + auto *ptrMIRType = static_cast(mirType); + FieldID fieldId = ivarMeExpr->GetFieldID(); + TyIdxFieldAttrPair fldPair = ptrMIRType->GetPointedTyIdxFldAttrPairWithFieldID(fieldId); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeTable().at(fldPair.first); + bool isFinal = fldPair.second.GetAttr(FLDATTR_final); + wkCand->SetNeedLocalRefVar(ty->GetPrimType() == PTY_ref && !isFinal); + } + workList.push_back(wkCand); + wkCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + // add to bucket at workcandHashTable[hashIdx] + wkCand->SetNext(*PreWorkCand::GetWorkcandFromIndex(hashIdx)); + PreWorkCand::SetWorkCandAt(hashIdx, *wkCand); + return newOcc; +} + +void SSAPre::CreateMembarOcc(MeStmt &meStmt, int seqStmt) { + if (preKind == kLoadPre || preKind == kAddrPre) { + return; + } + // go thru all workcands and insert a membar occurrence for each of them + for (size_t i = 0; i < workList.size() && i <= preLimit; i++) { + PreWorkCand *wkCand = workList[i]; + if (preKind == kExprPre) { + if (wkCand->GetTheMeExpr()->GetMeOp() != kMeOpIvar) { + continue; + } + } else if (preKind == kStmtPre) { + if (static_cast(wkCand)->GetTheMeStmt()->GetOp() != OP_dassign) { + continue; + } + } + MeRealOcc *newOcc = ssaPreMemPool->New(&meStmt, seqStmt, wkCand->GetTheMeExpr()); + newOcc->SetOccType(kOccMembar); + wkCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + } +} + +void SSAPre::CreateMembarOccAtCatch(BB &bb) { + // go thru all workcands and insert a membar occurrence for each of them + for (size_t i = 0; i < workList.size() && i <= preLimit; i++) { + PreWorkCand *wkCand = workList[i]; + MeRealOcc *newOcc = ssaPreMemPool->New(nullptr, 0, wkCand->GetTheMeExpr()); + newOcc->SetOccType(kOccMembar); + newOcc->SetBB(bb); + wkCand->AddRealOccAsLast(*newOcc, GetPUIdx()); + } +} + +void SSAPre::BuildWorkListStmt(MeStmt *meStmt, uint32 seqStmt, bool isRebuilt, MeExpr *tempVar) { + IncTreeid(); + Opcode op = meStmt->GetOp(); + switch (op) { + case OP_jstry: + case OP_jscatch: + case OP_finally: + case OP_endtry: + case OP_cleanuptry: + case OP_try: + case OP_catch: + case OP_goto: + case OP_comment: + break; + case OP_membaracquire: + case OP_membarrelease: + case OP_membarstoreload: + case OP_membarstorestore: + CreateMembarOcc(*meStmt, seqStmt); + break; + case OP_gosub: + case OP_retsub: + break; + case OP_throw: { + auto *thrMeStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, thrMeStmt->GetOpnd(), isRebuilt, tempVar, true); + // if (!isRebuilt) + // CreateExitOcc(bb); + break; + } + case OP_iassign: { + auto *ivarStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, ivarStmt->GetRHS(), isRebuilt, tempVar, true); + BuildWorkListExpr(meStmt, seqStmt, ivarStmt->GetLHSVal()->GetBase(), isRebuilt, tempVar, true); + BuildWorkListIvarLHSOcc(meStmt, seqStmt, isRebuilt, tempVar); + break; + } + case OP_brtrue: + case OP_brfalse: { + auto *condGotoStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, condGotoStmt->GetOpnd(), isRebuilt, tempVar, true); + break; + } + case OP_switch: { + auto *switchStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, switchStmt->GetOpnd(), isRebuilt, tempVar, true); + break; + } + case OP_dassign: { + auto *dassMeStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, dassMeStmt->GetRHS(), isRebuilt, tempVar, true); + BuildWorkListLHSOcc(meStmt, seqStmt); + break; + } + case OP_regassign: { + auto *rassMeStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, rassMeStmt->GetRHS(), isRebuilt, tempVar, true); + break; + } + case OP_maydassign: { + auto *dassMeStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, dassMeStmt->GetRHS(), isRebuilt, tempVar, true); + BuildWorkListLHSOcc(meStmt, seqStmt); + break; + } + case OP_decref: { + auto *unaryStmt = static_cast(meStmt); + if (!GetRcLoweringOn() && unaryStmt->GetOpnd()->IsLeaf() && unaryStmt->GetOpnd()->GetPrimType() == PTY_ref) { + // affects LPRE only; will cause CI failure if this is allowed + break; + } + BuildWorkListExpr(meStmt, seqStmt, unaryStmt->GetOpnd(), isRebuilt, tempVar, true); + break; + } + case OP_incref: + case OP_decrefreset: + case OP_eval: + case OP_assertnonnull: + case OP_free: { + auto *unaryStmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, unaryStmt->GetOpnd(), isRebuilt, tempVar, true); + break; + } + case OP_syncenter: + case OP_syncexit: { + auto *syncMeStmt = static_cast(meStmt); + MapleVector &opnds = syncMeStmt->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); it++) { + BuildWorkListExpr(meStmt, seqStmt, *it, isRebuilt, tempVar, true); + } + break; + } + case OP_return: { + auto *retMeStmt = static_cast(meStmt); + MapleVector &opnds = retMeStmt->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); ++it) { + if ((*it)->IsLeaf() && (*it)->GetPrimType() == PTY_ref) { + // affects LPRE only; will cause CI failure if this is allowed + if (!GetRcLoweringOn()) { + continue; + } + if (!GetRegReadAtReturn()) { + if ((*it)->GetMeOp() == kMeOpVar) { + auto *varMeExpr = static_cast(*it); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varMeExpr->GetOStIdx()); + if (!ost->IsFormal()) { + continue; + } + } + } + } + BuildWorkListExpr(meStmt, seqStmt, *it, isRebuilt, tempVar, true); + } + break; + } + case OP_call: + case OP_virtualcall: + case OP_virtualicall: + case OP_superclasscall: + case OP_interfacecall: + case OP_interfaceicall: + case OP_customcall: + case OP_polymorphiccall: + case OP_icall: + case OP_callassigned: + case OP_virtualcallassigned: + case OP_virtualicallassigned: + case OP_superclasscallassigned: + case OP_interfacecallassigned: + case OP_interfaceicallassigned: + case OP_customcallassigned: + case OP_polymorphiccallassigned: + case OP_icallassigned: { + auto *naryMeStmt = static_cast(meStmt); + MapleVector &opnds = naryMeStmt->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); it++) { + BuildWorkListExpr(meStmt, seqStmt, *it, isRebuilt, tempVar, true); + } + break; + } + case OP_intrinsiccall: { + auto *intrn = static_cast(meStmt); + if (intrn->GetIntrinsic() == INTRN_MPL_CLEANUP_LOCALREFVARS || + intrn->GetIntrinsic() == INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP || + intrn->GetIntrinsic() == INTRN_MPL_CLEANUP_NORETESCOBJS || + intrn->GetIntrinsic() == INTRN_MCCSetObjectPermanent) { + break; + } + // fall thru + } + case OP_xintrinsiccall: + case OP_intrinsiccallwithtype: + case OP_intrinsiccallassigned: + case OP_xintrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: { + auto *naryMeStmt = static_cast(meStmt); + MapleVector &opnds = naryMeStmt->GetOpnds(); + for (auto it = opnds.begin(); it != opnds.end(); it++) { + if (!GetRcLoweringOn() && (*it)->IsLeaf() && (*it)->GetMeOp() == kMeOpVar) { + // affects LPRE only; some later phase needs to transform dread to addrof + auto *varMeExpr = static_cast(*it); + const MIRSymbol *sym = ssaTab->GetMIRSymbolFromID(varMeExpr->GetOStIdx()); + if (sym->GetAttr(ATTR_static)) { + // its address may be taken + continue; + } + } + BuildWorkListExpr(meStmt, seqStmt, *it, isRebuilt, tempVar, true); + } + break; + } + case OP_assertlt: + case OP_assertge: { + auto *assmestmt = static_cast(meStmt); + BuildWorkListExpr(meStmt, seqStmt, assmestmt->GetOpnd(0), isRebuilt, tempVar, true); + BuildWorkListExpr(meStmt, seqStmt, assmestmt->GetOpnd(1), isRebuilt, tempVar, true); + break; + } + default: + CHECK_FATAL(op == OP_comment, "invalid value of opcode"); + break; + } + if (kOpcodeInfo.IsCallAssigned(op)) { + BuildWorkListLHSOcc(meStmt, seqStmt); + } +} + +void SSAPre::BuildWorkListBB(BB *bb) { + if (GetSpillAtCatch() && bb->GetAttributes(kBBAttrIsCatch)) { + CreateMembarOccAtCatch(*bb); + } + uint32 seqStmt = 0; + for (auto &stmt : bb->GetMeStmts()) { + BuildWorkListStmt(&stmt, ++seqStmt, false); + } + if (bb->GetAttributes(kBBAttrIsExit) || bb->GetAttributes(kBBAttrWontExit)) { + CreateExitOcc(bb); + } +} + +void SSAPre::DumpWorkListWrap() { + if (GetSSAPreDebug()) { + DumpWorkList(); + } +} + +void SSAPre::DumpWorkList() { + mirModule->GetOut() << "======== in SSAPRE worklist==============\n"; + for (size_t i = 0; i < workList.size(); i++) { + PreWorkCand *workListCand = workList[i]; + workListCand->Dump(irMap); + } +} + +GStrIdx SSAPre::NewTempStrIdx() { + std::string preStr("ssapre_tempvar"); + preStr.append(std::to_string(strIdxCount++)); + return GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(preStr); +} + +void SSAPre::ApplySSAPRE() { + // #0 build worklist + BuildWorkList(); + if (GetSSAPreDebug()) { + mirModule->GetOut() << " worklist initial size " << workList.size() << '\n'; + } + ConstructUseOccurMap(); + for (size_t i = 0; i < workList.size() && i <= preLimit; i++) { + perCandMemPool->Push(); + workCand = workList[i]; + if (workCand->GetRealOccs().empty()) { + continue; + } + if ((preKind == kExprPre && workCand->GetTheMeExpr()->GetMeOp() == kMeOpIvar) || (preKind == kLoadPre)) { + // if only LHS real occur, skip this candidate + bool hasNonLHS = false; + for (MeRealOcc *realOcc : workCand->GetRealOccs()) { + if (realOcc->GetOccType() == kOccReal && !realOcc->IsLHS()) { + hasNonLHS = true; + break; + } + } + if (!hasNonLHS) { + continue; + } + } + if (GetSSAPreDebug()) { + mirModule->GetOut() << "||||||| SSAPRE candidate " << i << " at worklist index " << workCand->GetIndex() << ": "; + workCand->DumpCand(*irMap); + mirModule->GetOut() << '\n'; + } + allOccs.clear(); + phiOccs.clear(); + // #1 Insert PHI; results in allOccs and phiOccs + ComputeVarAndDfPhis(); + CreateSortedOccs(); + if (workCand->GetRealOccs().empty()) { + continue; + } + // set the position field in the MeRealOcc nodes + for (size_t j = 0; j < workCand->GetRealOccs().size(); j++) { + workCand->GetRealOcc(j)->SetPosition(j); + } + // #2 Rename + Rename1(); + Rename2(); + if (!phiOccs.empty()) { + // if no PHI inserted, no need to compute DSafety, WBAvail + // #3 DownSafty + ComputeDS(); + // #4 WillBeAvail + ComputeCanBeAvail(); + ComputeLater(); + } + // #5 Finalize + Finalize1(); + if (workCand->Redo2HandleCritEdges()) { + // reinitialize def field to nullptr + for (MeOccur *occ : allOccs) { + occ->SetDef(nullptr); + if (occ->GetOccType() == kOccPhiopnd) { + auto *phiOpndOcc = static_cast(occ); + phiOpndOcc->SetIsProcessed(false); + } + } + Rename1(); + Rename2(); + ComputeDS(); + ComputeCanBeAvail(); + ComputeLater(); + Finalize1(); + } + Finalize2(); + // #6 CodeMotion and recompute worklist based on newly occurrence + CodeMotion(); + if (preKind == kStmtPre && workCand->GetRealOccs().front()->GetOpcodeOfMeStmt() == OP_dassign) { + // apply full redundancy elimination + DoSSAFRE(); + } + perCandMemPool->Pop(); + } +} +} // namespace maple diff --git a/src/maple_util/include/safe_cast.h b/src/maple_util/include/safe_cast.h index 19d9e40e379eee5bae1d7b78ed23c25b4c24eae2..47e1a52f61c4a0d6c508a4daa4e2c2f90eeba98c 100644 --- a/src/maple_util/include/safe_cast.h +++ b/src/maple_util/include/safe_cast.h @@ -47,10 +47,8 @@ struct instance_of_impl -struct enabled_safe_cast : - std::conditional_t, safe_cast_condition>::value, - std::true_type, - std::false_type> {}; +struct enabled_safe_cast + : utils::meta_or, safe_cast_condition>::type {}; } template struct meta_and - : public std::conditional_t {}; + : std::conditional_t {}; template struct meta_or - : public std::conditional_t {}; + : std::conditional_t {}; template struct meta_not - : public std::integral_constant(T::value)>::type {}; + : std::integral_constant(T::value)>::type {}; template struct is_signed; template struct is_signed - : public std::is_signed::type {}; + : std::is_signed::type {}; template struct is_signed - : public meta_and, std::is_signed>::type {}; + : meta_and, std::is_signed>::type {}; template constexpr bool is_signed_v = is_signed::value; @@ -49,47 +49,47 @@ struct is_unsigned; template struct is_unsigned - : public std::is_unsigned::type {}; + : std::is_unsigned::type {}; template struct is_unsigned - : public meta_and, std::is_unsigned>::type {}; + : meta_and, std::is_unsigned>::type {}; template constexpr bool is_unsigned_v = is_unsigned::value; template struct is_same_sign - : public meta_or, is_unsigned>::type {}; + : meta_or, is_unsigned>::type {}; template struct is_diff_sign - : public meta_not>::type {}; + : meta_not>::type {}; template struct is_pointer; template struct is_pointer - : std::is_pointer::type {}; + : std::is_pointer::type {}; template struct is_pointer - : meta_and, is_pointer>::type {}; + : meta_and, is_pointer>::type {}; template constexpr bool is_pointer_v = is_pointer::value; template struct const_of - : meta_and, std::is_same, U>>::type {}; + : meta_and, std::is_same, U>>::type {}; template constexpr bool const_of_v = const_of::value; template struct is_ncv_same - : std::is_same, std::remove_cv_t>::type {}; + : std::is_same, std::remove_cv_t>::type {}; template constexpr bool is_ncv_same_v = is_ncv_same::value; @@ -97,14 +97,14 @@ constexpr bool is_ncv_same_v = is_ncv_same::value; namespace ptr { template >> struct const_of - : utils::const_of, std::remove_pointer_t>::type {}; + : utils::const_of, std::remove_pointer_t>::type {}; template >> constexpr bool const_of_v = const_of::value; template >> struct is_ncv_same - : utils::is_ncv_same, std::remove_pointer_t>::type {}; + : utils::is_ncv_same, std::remove_pointer_t>::type {}; template >> constexpr bool is_ncv_same_v = is_ncv_same::value;