diff --git a/src/mapleall/maple_driver/defs/phases.def b/src/mapleall/maple_driver/defs/phases.def index 24de1a99aeb4ec4fd1e697c7dc7f36afd1fe0ed0..0f40f59a49c39a67cab66d26fa9dab112ad14c46 100644 --- a/src/mapleall/maple_driver/defs/phases.def +++ b/src/mapleall/maple_driver/defs/phases.def @@ -32,6 +32,7 @@ ADD_PHASE("aliasclass", CLANG && MeOption::optLevel >= 3) ADD_PHASE("ssa", CLANG && MeOption::optLevel >= 3) ADD_PHASE("dse", CLANG && MeOption::optLevel >= 3) ADD_PHASE("irmapbuild", CLANG && MeOption::optLevel >= 3) +ADD_PHASE("ivcanon", CLANG && MeOption::optLevel >= 3) ADD_PHASE("hprop", CLANG && MeOption::optLevel >= 3) ADD_PHASE("hdse", CLANG && MeOption::optLevel >= 3) ADD_PHASE("lfopreemit", CLANG && MeOption::optLevel >= 3) diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index 7d4f7e9924e50b2291d852c41012ac58f5951658..feed31ee6acc8ee5fe5c3e8a5d7bf6eed97fb517 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -93,6 +93,7 @@ src_libmplme = [ "src/lfo_mir_lower.cpp", "src/lfo_inject_iv.cpp", "src/lfo_pre_emit.cpp", + "src/lfo_iv_canon.cpp", ] src_libmplmewpo = [ diff --git a/src/mapleall/maple_me/include/dse.h b/src/mapleall/maple_me/include/dse.h index d49cbc69b3de8d1716e07740574e42e74ff20021..118345945db3c67cfee3bbb926c63ae74467e089 100644 --- a/src/mapleall/maple_me/include/dse.h +++ b/src/mapleall/maple_me/include/dse.h @@ -27,13 +27,13 @@ namespace maple { class DSE { public: DSE(std::vector &&bbVec, BB &commonEntryBB, BB &commonExitBB, SSATab &ssaTab, - Dominance &postDom, bool enableDebug = false, bool decouple = false) + Dominance &postDom, bool enableDebug = false, bool decouple = false, bool islfo = false) : enableDebug(enableDebug), bbVec(bbVec), commonEntryBB(commonEntryBB), commonExitBB(commonExitBB), ssaTab(ssaTab), postDom(postDom), bbRequired(bbVec.size(), false), exprRequired(ssaTab.GetVersionStTableSize(), false), - decoupleStatic(decouple) {} + decoupleStatic(decouple), isLfo(islfo) {} ~DSE() = default; @@ -134,6 +134,7 @@ class DSE { // Or the node is opnd of a same type node static const uint8 kNodeTypeNotNull = 2; bool decoupleStatic = false; + bool isLfo = false; }; } // namespace maple #endif // MAPLE_ME_INCLUDE_DSE_H diff --git a/src/mapleall/maple_me/include/lfo_iv_canon.h b/src/mapleall/maple_me/include/lfo_iv_canon.h new file mode 100644 index 0000000000000000000000000000000000000000..3775bf9d424f8f0cf4ad4a377b11a4e1e90afa23 --- /dev/null +++ b/src/mapleall/maple_me/include/lfo_iv_canon.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * 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 MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLE_ME_INCLUDE_LFO_IV_CANON_H +#define MAPLE_ME_INCLUDE_LFO_IV_CANON_H + +#include "lfo_function.h" +#include "me_loop_analysis.h" +#include "me_irmap.h" +#include "me_phase.h" + +namespace maple { + +// describe characteristics of one IV +class IVDesc { + public: + OriginalSt *ost; + PrimType primType; + MeExpr *initExpr = nullptr; + int32 stepValue = 0; + + public: + explicit IVDesc(OriginalSt *o) : ost(o) { + MIRType *mirtype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ost->GetTyIdx()); + primType = mirtype->GetPrimType(); + } +}; + +// this is for processing a single loop +class IVCanon { + public: + MemPool *mp; + MapleAllocator alloc; + MeFunction *func; + Dominance *dominance; + SSATab *ssatab; + LoopDesc *aloop; + uint32 loopID; + LfoWhileInfo *whileInfo; + MapleVector ivvec; + int32 idxPrimaryIV = -1; // the index in ivvec of the primary IV + MeExpr *tripCount = nullptr; + + public: + explicit IVCanon(MemPool *m, MeFunction *f, Dominance *dom, LoopDesc *ldesc, uint32 id, LfoWhileInfo *winfo) : + mp(m), alloc(m), func(f), dominance(dom), ssatab(f->GetMeSSATab()), + aloop(ldesc), loopID(id), whileInfo(winfo), ivvec(alloc.Adapter()) {} + bool ResolveExprValue(MeExpr *x, ScalarMeExpr *philhs); + int32 ComputeIncrAmt(MeExpr *x, ScalarMeExpr *philhs, int32 *appearances); + void CharacterizeIV(ScalarMeExpr *initversion, ScalarMeExpr *loopbackversion, ScalarMeExpr *philhs); + void FindPrimaryIV(); + bool IsLoopInvariant(MeExpr *x); + void CanonEntryValues(); + void ComputeTripCount(); + void CanonExitValues(); + void ReplaceSecondaryIVPhis(); + void PerformIVCanon(); + std::string PhaseName() const { return "ivcanon"; } +}; + +class DoLfoIVCanon : public MeFuncPhase { + public: + DoLfoIVCanon(MePhaseID id) : MeFuncPhase(id) {} + + ~DoLfoIVCanon() {} + + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *moduleResMgr) override; + + std::string PhaseName() const override { return "ivcanon"; } + + private: + void IVCanonLoop(LoopDesc *aloop, LfoWhileInfo *whileInfo); +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_LFO_IV_CANON_H diff --git a/src/mapleall/maple_me/include/me_dse.h b/src/mapleall/maple_me/include/me_dse.h index f6fb4a7e23ceb1cd317b7b0a06174b627c5aa179..43c58183d75d9c72697d258d2b0cdbd2e9acb3bd 100644 --- a/src/mapleall/maple_me/include/me_dse.h +++ b/src/mapleall/maple_me/include/me_dse.h @@ -29,7 +29,7 @@ class MeDSE : public DSE { MeDSE(MeFunction &func, Dominance *dom, bool enabledDebug) : DSE(std::vector(func.GetCfg()->GetAllBBs().begin(), func.GetCfg()->GetAllBBs().end()), *func.GetCfg()->GetCommonEntryBB(), *func.GetCfg()->GetCommonExitBB(), *func.GetMeSSATab(), - *dom, enabledDebug, MeOption::decoupleStatic), + *dom, enabledDebug, MeOption::decoupleStatic, func.IsLfo()), func(func), cfg(func.GetCfg()) {} virtual ~MeDSE() = default; diff --git a/src/mapleall/maple_me/include/me_loop_analysis.h b/src/mapleall/maple_me/include/me_loop_analysis.h index 1cdb243eadbe825f0fe4e8dd36eeb36ac0450d2e..67b789c21c2b8e2091f6abcfadf71c031e672f1f 100644 --- a/src/mapleall/maple_me/include/me_loop_analysis.h +++ b/src/mapleall/maple_me/include/me_loop_analysis.h @@ -30,6 +30,7 @@ struct LoopDesc { BB *tail; BB *preheader; BB *latch; + BB *exitBB; MapleMap*> inloopBB2exitBBs; MapleSet loopBBs; LoopDesc *parent; // points to its closest nesting loop @@ -38,7 +39,7 @@ struct LoopDesc { bool hasIgotoBB = false; // backedge is construted by igoto bool isCanonicalLoop = false; LoopDesc(MapleAllocator &mapleAllocator, BB *headBB, BB *tailBB) - : alloc(&mapleAllocator), head(headBB), tail(tailBB), preheader(nullptr), latch(nullptr), + : alloc(&mapleAllocator), head(headBB), tail(tailBB), preheader(nullptr), latch(nullptr), exitBB(nullptr), inloopBB2exitBBs(alloc->Adapter()), loopBBs(alloc->Adapter()), parent(nullptr), nestDepth(0), hasTryBB(false), hasIgotoBB(false) {} @@ -129,6 +130,7 @@ class IdentifyLoops : public AnalysisResult { LoopDesc *CreateLoopDesc(BB &hd, BB &tail); void SetLoopParent4BB(const BB &bb, LoopDesc &loopDesc); + void SetExitBB(LoopDesc &loop); void InsertExitBB(LoopDesc &loop); void ProcessBB(BB *bb); void MarkBB(); diff --git a/src/mapleall/maple_me/include/me_phases.def b/src/mapleall/maple_me/include/me_phases.def index 51b0a469f245556c70690dc300d51d3ae846ebb3..53144a3c4c8aeb8bb1e4865676fbd3337c45b7c3 100644 --- a/src/mapleall/maple_me/include/me_phases.def +++ b/src/mapleall/maple_me/include/me_phases.def @@ -52,6 +52,7 @@ FUNCTPHASE(MeFuncPhase_INTERCONSTPROP, MeDoInterConstProp) FUNCAPHASE(MeFuncPhase_MECFG, MeDoMeCfg) FUNCTPHASE(MeFuncPhase_LFOINJECTIV, DoLfoInjectIV) FUNCTPHASE(MeFuncPhase_LFOPREEMIT, DoLfoPreEmission) +FUNCTPHASE(MeFuncPhase_LFOIVCANON, DoLfoIVCanon) #if MIR_JAVA FUNCTPHASE(MeFuncPhase_SYNCSELECT, MeDoSyncSelect) #endif diff --git a/src/mapleall/maple_me/include/me_ssa.h b/src/mapleall/maple_me/include/me_ssa.h index cccfefd4ab2f80612c8de3953d1966128c07249e..b26bb763dbc9687b0482776775b8d3d9ca40b751 100644 --- a/src/mapleall/maple_me/include/me_ssa.h +++ b/src/mapleall/maple_me/include/me_ssa.h @@ -21,23 +21,26 @@ #include "me_phase.h" #include "ssa.h" #include "dominance.h" +#include "me_loop_analysis.h" namespace maple { class MeSSA : public SSA, public AnalysisResult { public: - MeSSA(MeFunction &func, SSATab *stab, Dominance &dom, MemPool &memPool) + MeSSA(MeFunction &func, SSATab *stab, Dominance &dom, MemPool &memPool, bool enabledDebug = false) : SSA(memPool, *stab, func.GetCfg()->GetAllBBs(), &dom), AnalysisResult(&memPool), - func(&func) {} + func(&func), eDebug(enabledDebug) {} ~MeSSA() = default; void VerifySSA() const; void InsertPhiNode(); + void InsertIdentifyAssignments(IdentifyLoops *identloops); private: void VerifySSAOpnd(const BaseNode &node) const; MeFunction *func; + bool eDebug = false; }; class MeDoSSA : public MeFuncPhase { diff --git a/src/mapleall/maple_me/include/orig_symbol.h b/src/mapleall/maple_me/include/orig_symbol.h index 0e7f100229c4d0c8c613acdb97667c191ea9c311..32c6f79390e337519b59cd30cbb34a8b16f8c4d9 100644 --- a/src/mapleall/maple_me/include/orig_symbol.h +++ b/src/mapleall/maple_me/include/orig_symbol.h @@ -198,6 +198,15 @@ class OriginalSt { return puIdx; } + bool IsIVCandidate() const { + if (indirectLev != 0 || + (IsSymbolOst() && GetMIRSymbol()->GetName() == "__nads_dummysym__")) { + return false; + } + MIRType *mirtype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + return IsPrimitiveInteger(mirtype->GetPrimType()) && (mirtype->GetKind() != kTypeBitField); + } + MIRType *GetType() const { return GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); } diff --git a/src/mapleall/maple_me/src/dse.cpp b/src/mapleall/maple_me/src/dse.cpp index b62273aa4a5eb508ad1060706102cabb43ff94f3..d0c9dc7888e16b30e96f1698583bcc55d2e1902a 100644 --- a/src/mapleall/maple_me/src/dse.cpp +++ b/src/mapleall/maple_me/src/dse.cpp @@ -96,11 +96,13 @@ bool DSE::HasNonDeletableExpr(const StmtNode &stmt) const { case OP_dassign: { auto &node = static_cast(stmt); const MIRSymbol &sym = ssaTab.GetStmtMIRSymbol(stmt); - bool isInjectIV = (strncmp(sym.GetName().c_str(), "injected.iv", 11) == 0); - if (!isInjectIV) { + bool isInjectIV = false; + if (isLfo) { // check identify assignments - if (node.Opnd()->GetOpCode() == OP_dread) { - AddrofNode *dread = static_cast(node.Opnd()); + if (strncmp(sym.GetName().c_str(), "injected.iv", 11) == 0) { + isInjectIV = true; + } else if (node.Opnd()->GetOpCode() == OP_dread) { + auto *dread = static_cast(node.Opnd()); if (node.GetStIdx() == dread->GetStIdx() && node.GetFieldID() == dread->GetFieldID()) { isInjectIV = true; } @@ -110,11 +112,13 @@ bool DSE::HasNonDeletableExpr(const StmtNode &stmt) const { ExprNonDeletable(ToRef(node.GetRHS())) || isInjectIV); } case OP_regassign: { - auto &rass = static_cast(stmt); - if (rass.Opnd()->GetOpCode() == OP_regread) { - RegreadNode *regread = static_cast(rass.Opnd()); - if (rass.GetRegIdx() == regread->GetRegIdx()) { - return true; + if (isLfo) { + auto &rass = static_cast(stmt); + if (rass.Opnd()->GetOpCode() == OP_regread) { + RegreadNode *regread = static_cast(rass.Opnd()); + if (rass.GetRegIdx() == regread->GetRegIdx()) { + return true; + } } } return ExprNonDeletable(ToRef(stmt.Opnd(0))); diff --git a/src/mapleall/maple_me/src/lfo_iv_canon.cpp b/src/mapleall/maple_me/src/lfo_iv_canon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..856cc40aa0007e88dc946a2711aa142d5f9a2585 --- /dev/null +++ b/src/mapleall/maple_me/src/lfo_iv_canon.cpp @@ -0,0 +1,533 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * 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 MulanPSL - 2.0 for more details. + */ + +#include +#include "lfo_iv_canon.h" +#include "me_option.h" +#include "lfo_function.h" + +// This phase implements Step 4 of the paper: +// S.-M. Liu, R. Lo and F. Chow, "Loop Induction Variable +// Canonicalization in Parallelizing Compiler", Intl. Conf. on Parallel +// Architectures and Compilation Techniques (PACT 96), Oct 1996. + +using namespace std; + +namespace maple { + +// Resolve value of x; return false if result is not of induction expression +// form; goal is to resolve to an expression where the only non-constant is +// philhs +bool IVCanon::ResolveExprValue(MeExpr *x, ScalarMeExpr *philhs) { + switch (x->GetMeOp()) { + case kMeOpConst: return IsPrimitiveInteger(x->GetPrimType()); + case kMeOpVar: + case kMeOpReg:{ + if (x == philhs) { + return true; + } + ScalarMeExpr *scalar = static_cast(x); + if (scalar->GetDefBy() != kDefByStmt) { + return false; + } + AssignMeStmt *defstmt = static_cast(scalar->GetDefStmt()); + return ResolveExprValue(defstmt->GetRHS(), philhs); + } + case kMeOpOp: { // restricting to only + and - for now + if (x->GetOp() != OP_add && x->GetOp() != OP_sub) { + return false; + } + OpMeExpr *opexp = static_cast(x); + return ResolveExprValue(opexp->GetOpnd(0), philhs) && + ResolveExprValue(opexp->GetOpnd(1), philhs); + } + default: ; + } + return false; +} + +// appearances accumulates the number of appearances of the induction variable; +// it is negative if it is subtracted +int32 IVCanon::ComputeIncrAmt(MeExpr *x, ScalarMeExpr *philhs, int32 *appearances) { + switch (x->GetMeOp()) { + case kMeOpConst: { + MIRConst *konst = static_cast(x)->GetConstVal(); + CHECK_FATAL(konst->GetKind() == kConstInt, "ComputeIncrAmt: must be integer constant"); + MIRIntConst *intconst = static_cast(konst); + return intconst->GetValue(); + } + case kMeOpVar: + case kMeOpReg:{ + if (x == philhs) { + *appearances = 1; + return 0; + } + ScalarMeExpr *scalar = static_cast(x); + CHECK_FATAL(scalar->GetDefBy() == kDefByStmt, "ComputeIncrAmt: cannot be here"); + AssignMeStmt *defstmt = static_cast(scalar->GetDefStmt()); + return ComputeIncrAmt(defstmt->GetRHS(), philhs, appearances); + } + case kMeOpOp: { + CHECK_FATAL(x->GetOp() == OP_add || x->GetOp() == OP_sub, "ComputeIncrAmt: cannot be here"); + OpMeExpr *opexp = static_cast(x); + int32 appear0 = 0; + int64 incrAmt0 = ComputeIncrAmt(opexp->GetOpnd(0), philhs, &appear0); + int32 appear1 = 0; + int64 incrAmt1 = ComputeIncrAmt(opexp->GetOpnd(1), philhs, &appear1); + if (x->GetOp() == OP_sub) { + *appearances = appear0 - appear1; + return incrAmt0 - incrAmt1; + } else { + *appearances = appear0 + appear1; + return incrAmt0 + incrAmt1; + } + } + default: ; + } + CHECK_FATAL(false, "ComputeIncrAmt: should not be here"); + return 0; +} + +// determine the initial and step values of the IV and push info to ivvec +void IVCanon::CharacterizeIV(ScalarMeExpr *initversion, ScalarMeExpr *loopbackversion, ScalarMeExpr *philhs) { + IVDesc *ivdesc = mp->New(initversion->GetOst()); + if (initversion->GetDefBy() == kDefByStmt) { + AssignMeStmt *defstmt = static_cast(initversion->GetDefStmt()); + if (defstmt->GetRHS()->GetMeOp() == kMeOpConst || + defstmt->GetRHS()->GetMeOp() == kMeOpAddrof || + defstmt->GetRHS()->GetMeOp() == kMeOpConststr || + defstmt->GetRHS()->GetMeOp() == kMeOpConststr16) { + ivdesc->initExpr = defstmt->GetRHS(); + } else { + ivdesc->initExpr = initversion; + } + } else { + ivdesc->initExpr = initversion; + } + int32 appearances = 0; + ivdesc->stepValue = ComputeIncrAmt(loopbackversion, philhs, &appearances); + if (appearances == 1) { + ivvec.push_back(ivdesc); + } +} + +void IVCanon::FindPrimaryIV() { + for (uint32 i = 0; i < ivvec.size(); i++) { + IVDesc *ivdesc = ivvec[i]; + if (ivdesc->stepValue == 1) { + bool injected = false; + if (ivdesc->ost->IsSymbolOst() && + strncmp(ivdesc->ost->GetMIRSymbol()->GetName().c_str(), "injected.iv", 11) == 0) { + injected = true; + } + if (injected) { + if (idxPrimaryIV == -1) { + idxPrimaryIV = i; + } + } else { + // verify its increment is the last statement in loop body + BB *tailbb = aloop->tail; + MeStmt *laststmt = tailbb->GetLastMe()->GetPrev(); // skipping the branch stmt + if (laststmt == nullptr || laststmt->GetOp() != OP_dassign) { + continue; + } + DassignMeStmt *lastdass = static_cast(laststmt); + if (strncmp(lastdass->GetLHS()->GetOst()->GetMIRSymbol()->GetName().c_str(), "injected.iv", 11) == 0) { + laststmt = laststmt->GetPrev(); + if (laststmt == nullptr || laststmt->GetOp() != OP_dassign) { + continue; + } + lastdass = static_cast(laststmt); + } + if (lastdass->GetLHS()->GetOst() == ivdesc->ost) { + idxPrimaryIV = i; + return; + } + } + } + } +} + +bool IVCanon::IsLoopInvariant(MeExpr *x) { + if (x == nullptr) { + return true; + } + switch (x->GetMeOp()) { + case kMeOpAddrof: + case kMeOpAddroffunc: + case kMeOpConst: + case kMeOpConststr: + case kMeOpConststr16: + case kMeOpSizeoftype: + case kMeOpFieldsDist: return true; + case kMeOpVar: + case kMeOpReg: { + ScalarMeExpr *scalar = static_cast(x); + BB *defBB = scalar->DefByBB(); + return defBB == nullptr || dominance->Dominate(*defBB, *aloop->head); + } + case kMeOpIvar: { + IvarMeExpr *ivar = static_cast(x); + BB *defBB = ivar->GetMu()->DefByBB(); + return defBB == nullptr || dominance->Dominate(*defBB, *aloop->head); + } + case kMeOpOp: { + OpMeExpr *opexp = static_cast(x); + return IsLoopInvariant(opexp->GetOpnd(0)) && + IsLoopInvariant(opexp->GetOpnd(1)) && + IsLoopInvariant(opexp->GetOpnd(2)); + } + case kMeOpNary: { + NaryMeExpr *opexp = static_cast(x); + for (uint32 i = 0; i < opexp->GetNumOpnds(); i++) { + if (!IsLoopInvariant(opexp->GetOpnd(i))) { + return false; + } + } + return true; + } + default: ; + } + return false; +} + +void IVCanon::ComputeTripCount() { + MeIRMap *irMap = func->GetIRMap(); + // find the termination test expression + if (!aloop->head->GetLastMe()->IsCondBr()) { + return; + } + CondGotoMeStmt *condbr = static_cast(aloop->head->GetLastMe()); + if (!kOpcodeInfo.IsCompare(condbr->GetOpnd()->GetOp())) { + return; + } + OpMeExpr *testexp = static_cast(condbr->GetOpnd()); + // make the side that consists of a single IV the left operand + // check left operand + ScalarMeExpr *iv = dynamic_cast(testexp->GetOpnd(0)); + IVDesc *ivdesc = nullptr; + if (iv) { + for (uint32 i = 0; i < ivvec.size(); i++) { + if (iv->GetOst() == ivvec[i]->ost) { + ivdesc = ivvec[i]; + break; + } + } + } + if (ivdesc == nullptr) { // check second operand + iv = dynamic_cast(testexp->GetOpnd(1)); + if (iv) { + for (uint32 i = 0; i < ivvec.size(); i++) { + if (iv->GetOst() == ivvec[i]->ost) { + ivdesc = ivvec[i]; + break; + } + } + } + if (ivdesc) { // swap the 2 sides + Opcode newop = testexp->GetOp(); + switch (testexp->GetOp()) { + case OP_lt: newop = OP_gt; break; + case OP_le: newop = OP_ge; break; + case OP_gt: newop = OP_lt; break; + case OP_ge: newop = OP_le; break; + default: ; + } + OpMeExpr opmeexpr(-1, newop, testexp->GetPrimType(), 2); + opmeexpr.SetOpnd(0, testexp->GetOpnd(1)); + opmeexpr.SetOpnd(1, testexp->GetOpnd(0)); + opmeexpr.SetOpndType(testexp->GetOpndType()); + testexp = static_cast(irMap->HashMeExpr(opmeexpr)); + condbr->SetOpnd(0, testexp); + } + } + if (ivdesc == nullptr || ivdesc->stepValue == 0) { + return; // no IV in the termination test + } + if (!IsLoopInvariant(testexp->GetOpnd(1))) { + return; // the right side is not loop-invariant + } + + // check the termination test is in the right sense + if (ivdesc->stepValue > 0) { + if (condbr->GetOpnd()->GetOp() == OP_gt || condbr->GetOpnd()->GetOp() == OP_ge) { + return; + } + } else { + if (condbr->GetOpnd()->GetOp() == OP_lt || condbr->GetOpnd()->GetOp() == OP_le) { + return; + } + } + + // form the trip count expression + PrimType primTypeUsed = testexp->GetOpnd(0)->GetPrimType(); + PrimType divPrimType = primTypeUsed; + if (ivdesc->stepValue < 0) { + divPrimType = GetSignedPrimType(divPrimType); + } + OpMeExpr add(-1, OP_add, primTypeUsed, 2); + add.SetOpnd(0, testexp->GetOpnd(1)); // IV bound + add.SetOpnd(1, irMap->CreateIntConstMeExpr(ivdesc->stepValue > 0 ? ivdesc->stepValue-1 : ivdesc->stepValue+1, primTypeUsed)); + MeExpr *subx = irMap->HashMeExpr(add); + if (!ivdesc->initExpr->IsZero()) { + OpMeExpr subtract(-1, OP_sub, primTypeUsed, 2); + subtract.SetOpnd(0, subx); + subtract.SetOpnd(1, ivdesc->initExpr); + subx = irMap->HashMeExpr(subtract); + } + MeExpr *divx = subx; + if (ivdesc->stepValue != 1) { + OpMeExpr divide(-1, OP_div, divPrimType, 2); + divide.SetOpnd(0, divx); + divide.SetOpnd(1, irMap->CreateIntConstMeExpr(ivdesc->stepValue, divPrimType)); + divx = irMap->HashMeExpr(divide); + } + tripCount = irMap->SimplifyMeExpr(dynamic_cast(divx)); +} + +void IVCanon::CanonEntryValues() { + for (uint32 i = 0; i < ivvec.size(); i++) { + IVDesc *ivdesc = ivvec[i]; + if (ivdesc->initExpr->GetMeOp() == kMeOpVar || ivdesc->initExpr->GetMeOp() == kMeOpReg) { +#if 1 // create temp var + std::string initName = ivdesc->ost->GetMIRSymbol()->GetName(); + initName.append(std::to_string(ivdesc->ost->GetFieldID())); + initName.append(std::to_string(loopID)); + initName.append(std::to_string(i)); + initName.append(".init"); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(initName); + ScalarMeExpr *scalarmeexpr = func->GetIRMap()->CreateNewVar(strIdx, ivdesc->primType, false); +#else // create preg + ScalarMeExpr *scalarmeexpr = func->irMap->CreateRegMeExpr(ivdesc->primType); +#endif + AssignMeStmt *ass = func->GetIRMap()->CreateAssignMeStmt(*scalarmeexpr, *ivdesc->initExpr, *aloop->preheader); + aloop->preheader->AddMeStmtLast(ass); + ivdesc->initExpr = scalarmeexpr; + } + } +} + +void IVCanon::CanonExitValues() { + for (IVDesc *ivdesc : ivvec) { + // look for the identity assignment + MeStmt *stmt = aloop->exitBB->GetFirstMe(); + while (stmt) { + if (stmt->GetOp() == OP_dassign || stmt->GetOp() == OP_regassign) { + AssignMeStmt *ass = static_cast(stmt); + if (ass->GetLHS()->GetOst() == ivdesc->ost) { + break; + } + } + stmt = stmt->GetNext(); + } + CHECK_FATAL(stmt != nullptr, "CanonExitValues: cannot find identity assignments at an exit node"); + AssignMeStmt *ass = static_cast(stmt); + CHECK_FATAL(ass->GetRHS()->GetMeOp() == kMeOpVar || ass->GetRHS()->GetMeOp() == kMeOpReg, + "CanonExitValues: assignment at exit node is not identity assignment"); + ScalarMeExpr *rhsvar = static_cast(ass->GetRHS()); + CHECK_FATAL(rhsvar->GetOst() == ivdesc->ost, + "CanonExitValues: assignment at exit node is not identity assignment"); + MeExpr *tripCountUsed = tripCount; + if (GetPrimTypeSize(tripCount->GetPrimType()) != GetPrimTypeSize(ivdesc->primType)) { + OpMeExpr cvtx(-1, OP_cvt, ivdesc->primType, 1); + cvtx.SetOpnd(0, tripCount); + cvtx.SetOpndType(tripCount->GetPrimType()); + tripCountUsed = func->GetIRMap()->HashMeExpr(cvtx); + } + MeExpr *mulx = tripCountUsed; + if (ivdesc->stepValue != 1) { + PrimType primTypeUsed = ivdesc->stepValue < 0 ? GetSignedPrimType(ivdesc->primType) : ivdesc->primType; + OpMeExpr mulmeexpr(-1, OP_mul, primTypeUsed, 2); + mulmeexpr.SetOpnd(0, mulx); + mulmeexpr.SetOpnd(1, func->GetIRMap()->CreateIntConstMeExpr(ivdesc->stepValue, primTypeUsed)); + mulx = func->GetIRMap()->HashMeExpr(mulmeexpr); + } + MeExpr *addx = mulx; + if (!ivdesc->initExpr->IsZero()) { + OpMeExpr addmeexpr(-1, OP_add, ivdesc->primType, 2); + addmeexpr.SetOpnd(0, ivdesc->initExpr); + addmeexpr.SetOpnd(1, mulx); + addx = func->GetIRMap()->HashMeExpr(addmeexpr); + } + ass->SetRHS(addx); + } +} + +void IVCanon::ReplaceSecondaryIVPhis() { + BB *headBB = aloop->head; + // first, form the expression of the primary IV minus its init value + IVDesc *primaryIVDesc = ivvec[idxPrimaryIV]; + // find its phi in the phi list at the loop head + MapleMap::iterator it = headBB->GetMePhiList().find(primaryIVDesc->ost->GetIndex()); + MePhiNode *phi = it->second; + MeExpr *iterCountExpr = phi->GetLHS(); + if (!primaryIVDesc->initExpr->IsZero()) { + OpMeExpr submeexpr(-1, OP_sub, primaryIVDesc->primType, 2); + submeexpr.SetOpnd(0, phi->GetLHS()); + submeexpr.SetOpnd(1, primaryIVDesc->initExpr); + iterCountExpr = func->GetIRMap()->HashMeExpr(submeexpr); + } + + for (uint32 i = 0; i < ivvec.size(); i++) { + if (i == idxPrimaryIV) { + continue; + } + IVDesc *ivdesc = ivvec[i]; + // find its phi in the phi list at the loop head + it = headBB->GetMePhiList().find(ivdesc->ost->GetIndex()); + phi = it->second; + + MeExpr *iterCountUsed = iterCountExpr; + if (GetPrimTypeSize(iterCountExpr->GetPrimType()) != GetPrimTypeSize(ivdesc->primType)) { + OpMeExpr cvtx(-1, OP_cvt, ivdesc->primType, 1); + cvtx.SetOpnd(0, iterCountExpr); + cvtx.SetOpndType(iterCountExpr->GetPrimType()); + iterCountUsed = func->GetIRMap()->HashMeExpr(cvtx); + } + MeExpr *mulx = iterCountUsed; + if (ivdesc->stepValue != 1) { + PrimType primTypeUsed = ivdesc->stepValue < 0 ? GetSignedPrimType(ivdesc->primType) : ivdesc->primType; + OpMeExpr mulmeexpr(-1, OP_mul, primTypeUsed, 2); + mulmeexpr.SetOpnd(0, mulx); + mulmeexpr.SetOpnd(1, func->GetIRMap()->CreateIntConstMeExpr(ivdesc->stepValue, primTypeUsed)); + mulx = func->GetIRMap()->HashMeExpr(mulmeexpr); + } + OpMeExpr addmeexpr(-1, OP_add, ivdesc->primType, 2); + MeExpr *addx = mulx; + if (!ivdesc->initExpr->IsZero()) { + addmeexpr.SetOpnd(0, ivdesc->initExpr); + addmeexpr.SetOpnd(1, mulx); + addx = func->GetIRMap()->HashMeExpr(addmeexpr); + } + AssignMeStmt *ass = func->GetIRMap()->CreateAssignMeStmt(*phi->GetLHS(), *addx, *headBB); + headBB->PrependMeStmt(ass); + // change phi's lhs to new version + ScalarMeExpr *newlhs; + if (phi->GetLHS()->GetMeOp() == kMeOpVar) { + newlhs = func->GetIRMap()->CreateVarMeExprVersion(ivdesc->ost); + } else { + newlhs = func->GetIRMap()->CreateRegMeExprVersion(*ivdesc->ost); + } + phi->SetLHS(newlhs); + newlhs->SetDefBy(kDefByPhi); + newlhs->SetDefPhi(*phi); + } +} + +void IVCanon::PerformIVCanon() { + BB *headbb = aloop->head; + uint32 phiOpndIdxOfInit = 1; + uint32 phiOpndIdxOfLoopBack = 0; + if (aloop->loopBBs.count(headbb->GetPred(0)->GetBBId()) == 0) { + phiOpndIdxOfInit = 0; + phiOpndIdxOfLoopBack = 1; + } + CHECK_FATAL(aloop->tail == headbb->GetPred(phiOpndIdxOfLoopBack), "PerformIVCanon: tail BB inaccurate"); + // go thru the list of phis at the loop head to find all IVs + for (std::pair mapEntry: headbb->GetMePhiList()) { + OriginalSt *ost = ssatab->GetOriginalStFromID(mapEntry.first); + if (!ost->IsIVCandidate()) { + continue; + } + ScalarMeExpr *philhs = mapEntry.second->GetLHS(); + ScalarMeExpr *initVersion = mapEntry.second->GetOpnd(phiOpndIdxOfInit); + ScalarMeExpr *loopbackVersion = mapEntry.second->GetOpnd(phiOpndIdxOfLoopBack); + if (ResolveExprValue(loopbackVersion, philhs)) { + CharacterizeIV(initVersion, loopbackVersion, philhs); + } + } + FindPrimaryIV(); + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "****** while loop at label " << "@" << func->GetMirFunc()->GetLabelName(headbb->GetBBLabel()); + LogInfo::MapleLogger() << ", BB id:" << headbb->GetBBId() << " has IVs:" << endl; + for (uint32 i = 0; i < ivvec.size(); i++) { + IVDesc *ivdesc = ivvec[i]; + ivdesc->ost->Dump(); + LogInfo::MapleLogger() << " step: " << ivdesc->stepValue << " initExpr: "; + ivdesc->initExpr->Dump(0); + if (i == idxPrimaryIV) { + LogInfo::MapleLogger() << " [PRIMARY IV]"; + } + LogInfo::MapleLogger() << endl; + } + } + CanonEntryValues(); + ComputeTripCount(); + if (tripCount == nullptr) { + return; + } + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "****** trip count is: "; + tripCount->Dump(func->GetIRMap(), 0); + LogInfo::MapleLogger() << endl; + } + CanonExitValues(); + ReplaceSecondaryIVPhis(); +} + +AnalysisResult *DoLfoIVCanon::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *) { + Dominance *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom != nullptr, "dominance phase has problem"); + + MeIRMap *irmap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + ASSERT(irmap != nullptr, "hssamap has problem"); + + IdentifyLoops *identloops = static_cast(m->GetAnalysisResult(MeFuncPhase_MELOOP, func)); + CHECK_FATAL(identloops != nullptr, "identloops has problem"); + + LfoFunction *lfoFunc = func->GetLfoFunc(); + + // loop thru all the loops in reverse order so inner loops are processed first + for (int32 i = identloops->GetMeLoops().size()-1; i >= 0; i--) { + LoopDesc *aloop = identloops->GetMeLoops()[i]; + BB *headbb = aloop->head; + // check if the label has associated LfoWhileInfo + if (headbb->GetBBLabel() == 0) { + continue; + } + if (aloop->exitBB == nullptr || aloop->preheader == nullptr) { + continue; + } + MapleMap::iterator it = lfoFunc->label2WhileInfo.find(headbb->GetBBLabel()); + if (it == lfoFunc->label2WhileInfo.end()) { + continue; + } + LfoWhileInfo *whileInfo = it->second; + if (whileInfo->injectedIVSym == nullptr) { + continue; + } + MemPool *ivmp = NewMemPool(); + IVCanon ivCanon(ivmp, func, dom, aloop, i, whileInfo); + ivCanon.PerformIVCanon(); + // transfer primary IV info to whileinfo + if (ivCanon.idxPrimaryIV != -1) { + IVDesc *primaryIVDesc = ivCanon.ivvec[ivCanon.idxPrimaryIV]; + CHECK_FATAL(primaryIVDesc->ost->IsSymbolOst(), "primary IV cannot be preg"); + whileInfo->ivOst = primaryIVDesc->ost; + whileInfo->initExpr = primaryIVDesc->initExpr; + whileInfo->stepValue = primaryIVDesc->stepValue; + whileInfo->tripCount = ivCanon.tripCount; + whileInfo->canConvertDoloop = ivCanon.tripCount != nullptr; + } + } + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "\n============== After IV Canonicalization =============" << endl; + irmap->Dump(); + } + + return nullptr; +} + +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_loop_analysis.cpp b/src/mapleall/maple_me/src/me_loop_analysis.cpp index 9c4de46b78404adda7489d95f3816400ee04adcb..2dbb1115c20b0e6603d17c3d19ab36222340bb4e 100644 --- a/src/mapleall/maple_me/src/me_loop_analysis.cpp +++ b/src/mapleall/maple_me/src/me_loop_analysis.cpp @@ -38,6 +38,19 @@ void IdentifyLoops::SetLoopParent4BB(const BB &bb, LoopDesc &loopDesc) { bbLoopParent[bb.GetBBId()] = &loopDesc; } +void IdentifyLoops::SetExitBB(LoopDesc& loop) { + BB *headBB = loop.head; + // the exit BB is the succeessor of headBB that does not belong to the loop + if (headBB->GetSucc().size() != 2) { + return; + } + if (loop.loopBBs.count(headBB->GetSucc()[0]->GetBBId()) != 1) { + loop.exitBB = headBB->GetSucc()[0]; + } else { + loop.exitBB = headBB->GetSucc()[1]; + } +} + void IdentifyLoops::InsertExitBB(LoopDesc &loop) { std::set traveledBBs; std::queue inLoopBBs; @@ -105,6 +118,7 @@ void IdentifyLoops::ProcessBB(BB *bb) { } (void)loop->loopBBs.insert(bb->GetBBId()); SetLoopParent4BB(*bb, *loop); + SetExitBB(*loop); } } // recursive call diff --git a/src/mapleall/maple_me/src/me_phase_manager.cpp b/src/mapleall/maple_me/src/me_phase_manager.cpp index 39b48cb5dcef717dd526e42e04523473ef8d74f5..8a48ac63f9eed45fc48ed00a9cfd1ceb6297245a 100644 --- a/src/mapleall/maple_me/src/me_phase_manager.cpp +++ b/src/mapleall/maple_me/src/me_phase_manager.cpp @@ -71,6 +71,7 @@ #include "me_verify.h" #include "lfo_inject_iv.h" #include "lfo_pre_emit.h" +#include "lfo_iv_canon.h" #define JAVALANG (mirModule.IsJavaModule()) diff --git a/src/mapleall/maple_me/src/me_ssa.cpp b/src/mapleall/maple_me/src/me_ssa.cpp index 541fb9d79081786a8707d101c4d182d79ec16e11..3c7f1add16163cb2d55c135a891ab0ed314157fc 100644 --- a/src/mapleall/maple_me/src/me_ssa.cpp +++ b/src/mapleall/maple_me/src/me_ssa.cpp @@ -20,6 +20,7 @@ #include "ver_symbol.h" #include "dominance.h" #include "me_function.h" +#include "mir_builder.h" // This phase builds the SSA form of a function. Before this we have got the dominator tree // and each bb's dominance frontiers. Then the algorithm follows this outline: @@ -111,16 +112,92 @@ void MeSSA::VerifySSA() const { } } +void MeSSA::InsertIdentifyAssignments(IdentifyLoops *identloops) { + MIRBuilder *mirbuilder = func->GetMIRModule().GetMIRBuilder(); + LfoFunction *lfoFunc = func->GetLfoFunc(); + SSATab *ssatab = func->GetMeSSATab(); + + for (LoopDesc *aloop : identloops->GetMeLoops()) { + BB *headbb = aloop->head; + // check if the label has associated LfoWhileInfo + if (headbb->GetBBLabel() == 0) { + continue; + } + if (aloop->exitBB == nullptr) { + continue; + } + MapleMap::iterator it = lfoFunc->label2WhileInfo.find(headbb->GetBBLabel()); + if (it == lfoFunc->label2WhileInfo.end()) { + continue; + } + if (headbb->GetPred().size() != 2) { + continue; + } + // collect the symbols for inserting identity assignments + std::set ostSet; + for (auto& mapEntry: (headbb->GetPhiList())) { + OriginalSt *ost = func->GetMeSSATab()->GetOriginalStFromID(mapEntry.first); + if (ost->IsIVCandidate()) { + ostSet.insert(ost); + } + } + if (ostSet.empty()) { + continue; + } + // for the exitBB, insert identify assignment for any var that has phi at + // headbb + for (OriginalSt *ost : ostSet) { + MIRType *mirtype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ost->GetTyIdx()); + if (ost->IsSymbolOst()) { + AddrofNode *dread = func->GetMirFunc()->GetCodeMempool()->New(OP_dread, + mirtype->GetPrimType(), ost->GetMIRSymbol()->GetStIdx(), ost->GetFieldID()); + AddrofSSANode *ssadread = func->GetMirFunc()->GetCodeMempool()->New(*dread); + ssadread->SetSSAVar(*ssatab->GetVersionStTable().GetZeroVersionSt(ost)); + + DassignNode *dass = mirbuilder->CreateStmtDassign(*ost->GetMIRSymbol(), ost->GetFieldID(), ssadread); + aloop->exitBB->PrependStmtNode(dass); + + MayDefPartWithVersionSt *thessapart = + ssatab->GetStmtsSSAPart().GetSSAPartMp()->New(&ssatab->GetStmtsSSAPart().GetSSAPartAlloc()); + ssatab->GetStmtsSSAPart().SetSSAPartOf(*dass, thessapart); + thessapart->SetSSAVar(*ssatab->GetVersionStTable().GetZeroVersionSt(ost)); + } else { + RegreadNode *regread = func->GetMirFunc()->GetCodeMempool()->New(ost->GetPregIdx()); + MIRPreg *preg = func->GetMirFunc()->GetPregTab()->PregFromPregIdx(ost->GetPregIdx()); + regread->SetPrimType(preg->GetPrimType()); + RegreadSSANode *ssaregread = func->GetMirFunc()->GetCodeMempool()->New(*regread); + ssaregread->SetSSAVar(*ssatab->GetVersionStTable().GetZeroVersionSt(ost)); + + RegassignNode *rass = mirbuilder->CreateStmtRegassign(mirtype->GetPrimType(), ost->GetPregIdx(), ssaregread); + aloop->exitBB->PrependStmtNode(rass); + + VersionSt *vst = ssatab->GetVersionStTable().GetZeroVersionSt(ost); + ssatab->GetStmtsSSAPart().SetSSAPartOf(*rass, vst); + } + ssatab->AddDefBB4Ost(ost->GetIndex(), aloop->exitBB->GetBBId()); + } + if (eDebug) { + LogInfo::MapleLogger() << "****** Identity assignments inserted at loop exit BB " << aloop->exitBB->GetBBId() << std::endl; + } + } +} + AnalysisResult *MeDoSSA::Run(MeFunction *func, MeFuncResultMgr *funcResMgr, ModuleResultMgr*) { auto *dom = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); CHECK_FATAL(dom != nullptr, "dominance phase has problem"); auto *ssaTab = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_SSATAB, func)); CHECK_FATAL(ssaTab != nullptr, "ssaTab phase has problem"); MemPool *ssaMp = NewMemPool(); - auto *ssa = ssaMp->New(*func, func->GetMeSSATab(), *dom, *ssaMp); + auto *ssa = ssaMp->New(*func, func->GetMeSSATab(), *dom, *ssaMp, DEBUGFUNC(func)); auto cfg = func->GetCfg(); ssa->InsertPhiNode(); + if (func->IsLfo()) { + IdentifyLoops *identloops = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_MELOOP, func)); + CHECK_FATAL(identloops != nullptr, "identloops has problem"); + ssa->InsertIdentifyAssignments(identloops); + } + ssa->InitRenameStack(func->GetMeSSATab()->GetOriginalStTable(), cfg->GetAllBBs().size(), func->GetMeSSATab()->GetVersionStTable());