From cb387d16cfc1c497382cd65561eec6e53c64ff39 Mon Sep 17 00:00:00 2001 From: Fred Chow Date: Mon, 27 Sep 2021 17:07:23 -0700 Subject: [PATCH 1/5] Added new phase "reassoc" to perform reassociation mainly for address expression s under iread/assign In the reassociation, the add/sub terms less likely to vary are separated from the parts likely to vary. This is done on a per loop basis, and is applied only to expressions in innermost loops. For now, only IVs in loops are regarded as likely to vary. The goal is to result in more loop-invariant expressions. --- src/mapleall/maple_me/BUILD.gn | 1 + src/mapleall/maple_me/include/me_ir.h | 3 +- .../maple_me/include/me_phase_manager.h | 1 + src/mapleall/maple_me/include/me_reassoc.h | 57 +++ src/mapleall/maple_me/src/irmap.cpp | 23 +- .../maple_me/src/me_phase_manager.cpp | 1 + src/mapleall/maple_me/src/me_reassoc.cpp | 384 ++++++++++++++++++ src/mapleall/maple_phase/include/phases.def | 1 + 8 files changed, 459 insertions(+), 12 deletions(-) create mode 100644 src/mapleall/maple_me/include/me_reassoc.h create mode 100644 src/mapleall/maple_me/src/me_reassoc.cpp diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index cc5bf06bc2..9cb80db316 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -105,6 +105,7 @@ src_libmplme = [ "src/simplifyCFG.cpp", "src/seqvec.cpp", "src/me_autovec.cpp", + "src/me_reassoc.cpp", "src/safety_warning.cpp" ] diff --git a/src/mapleall/maple_me/include/me_ir.h b/src/mapleall/maple_me/include/me_ir.h index b3633b953a..37b7aa8ce7 100644 --- a/src/mapleall/maple_me/include/me_ir.h +++ b/src/mapleall/maple_me/include/me_ir.h @@ -465,7 +465,7 @@ class MePhiNode { return defBB; } - ScalarMeExpr *GetLHS() { + ScalarMeExpr *GetLHS() const { return lhs; } @@ -918,6 +918,7 @@ class OpMeExpr : public MeExpr { FieldID fieldID = 0; // this is also used to store puIdx public: bool hasAddressValue = false; // used only when op is ADD or SUB + bool canApplyReassoc = false; // hint to apply reassociation to this tree }; class IvarMeExpr : public MeExpr { diff --git a/src/mapleall/maple_me/include/me_phase_manager.h b/src/mapleall/maple_me/include/me_phase_manager.h index e3752d3312..f95d5ede9b 100644 --- a/src/mapleall/maple_me/include/me_phase_manager.h +++ b/src/mapleall/maple_me/include/me_phase_manager.h @@ -82,6 +82,7 @@ #include "cfg_opt.h" #include "lfo_dep_test.h" #include "me_autovec.h" +#include "me_reassoc.h" #include "safety_warning.h" namespace maple { diff --git a/src/mapleall/maple_me/include/me_reassoc.h b/src/mapleall/maple_me/include/me_reassoc.h new file mode 100644 index 0000000000..a039349b15 --- /dev/null +++ b/src/mapleall/maple_me/include/me_reassoc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_REASSOC_H +#define MAPLE_ME_INCLUDE_ME_REASSOC_H + +#include "me_function.h" +#include "me_irmap.h" +#include "me_cfg.h" +#include "me_loop_analysis.h" + +namespace maple { +// for representing the reults of ReassociateAddSub() +class ReassociatedParts { + public: + ReassociatedParts(MeExpr *ivpart, MeExpr *nonivpart) : ivPart(ivpart), nonIVPart(nonivpart) {} + public: + MeExpr *ivPart = nullptr; // the expr part likely to vary during exec + MeExpr *nonIVPart = nullptr; // the expr part not likely to change during exec + bool ivPartNegated = false; + bool nonIVPartNegated = false; +}; + +class MeReassoc { + public: + explicit MeReassoc(MeFunction *f, IRMap *map) : func(f), irMap(map), mirModule(&map->GetMIRModule()), cfg(f->GetCfg()) {} + virtual ~MeReassoc() = default; + + void FindSelfIncDecs(MeStmt *stmt, std::unordered_set *selfIncDefs); + MeExpr *FormReassociatedExpr(ReassociatedParts reassoc); + ReassociatedParts ReassociateAddSub(MeExpr *x, std::unordered_set *selfIncDefs); + void ProcessLoop(LoopDesc *aloop); + MeExpr *ApplyReassocExpr(MeExpr *x, std::unordered_set *selfIncDefs, bool *changed); + std::string PhaseName() const { + return "reassoc"; + } + public: + MeFunction *func; + IRMap *irMap; + MIRModule *mirModule; + MeCFG *cfg; +}; + +MAPLE_FUNC_PHASE_DECLARE(MEReassoc, MeFunction) +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_REASSOC_H diff --git a/src/mapleall/maple_me/src/irmap.cpp b/src/mapleall/maple_me/src/irmap.cpp index ec8acdfd71..9979fcfd47 100644 --- a/src/mapleall/maple_me/src/irmap.cpp +++ b/src/mapleall/maple_me/src/irmap.cpp @@ -424,21 +424,22 @@ MeExpr *IRMap::SimplifyIvarWithIaddrofBase(IvarMeExpr *ivar, bool lhsIvar) { } MeExpr *IRMap::SimplifyIvar(IvarMeExpr *ivar, bool lhsIvar) { - auto *simplifiedIvar = SimplifyIvarWithConstOffset(ivar, lhsIvar); - if (simplifiedIvar != nullptr) { - return simplifiedIvar; + MeExpr *simplifiedIvar = SimplifyIvarWithConstOffset(ivar, lhsIvar); + if (simplifiedIvar == nullptr) { + simplifiedIvar = SimplifyIvarWithAddrofBase(ivar); + if (simplifiedIvar == nullptr) { + simplifiedIvar = SimplifyIvarWithIaddrofBase(ivar, lhsIvar); + } } - - simplifiedIvar = SimplifyIvarWithAddrofBase(ivar); - if (simplifiedIvar != nullptr) { + if (simplifiedIvar != nullptr && simplifiedIvar->GetMeOp() != kMeOpIvar) { return simplifiedIvar; } - - simplifiedIvar = SimplifyIvarWithIaddrofBase(ivar, lhsIvar); - if (simplifiedIvar != nullptr) { - return simplifiedIvar; + // set canApplyReassoc + IvarMeExpr *retIvar = simplifiedIvar != nullptr ? static_cast(simplifiedIvar) : ivar ; + if (retIvar->GetBase()->GetOp() == OP_add || retIvar->GetBase()->GetOp() == OP_sub) { + static_cast(retIvar->GetBase())->canApplyReassoc = true; } - return nullptr; + return simplifiedIvar; } IvarMeExpr *IRMap::BuildLHSIvar(MeExpr &baseAddr, IassignMeStmt &iassignMeStmt, FieldID fieldID) { diff --git a/src/mapleall/maple_me/src/me_phase_manager.cpp b/src/mapleall/maple_me/src/me_phase_manager.cpp index 963a508303..cc14485b45 100644 --- a/src/mapleall/maple_me/src/me_phase_manager.cpp +++ b/src/mapleall/maple_me/src/me_phase_manager.cpp @@ -198,5 +198,6 @@ MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEProfGen, profileGen) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEPlacementRC, placementrc) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEDse, dse) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEABCOpt, abcopt) +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEReassoc, reassoc) MAPLE_TRANSFORM_PHASE_REGISTER(MEEmit, meemit) } // namespace maple diff --git a/src/mapleall/maple_me/src/me_reassoc.cpp b/src/mapleall/maple_me/src/me_reassoc.cpp new file mode 100644 index 0000000000..2d8465d8af --- /dev/null +++ b/src/mapleall/maple_me/src/me_reassoc.cpp @@ -0,0 +1,384 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 v2 for more details. + */ +#include "me_phase_manager.h" +#include "me_reassoc.h" + +// This reassoc phase performs reassociation mainly for address expressions +// under iread/iassign. In the reassociation, the add/sub terms less likely to +// vary are separated from the parts likely to vary. This is done on a per loop// basis, and is applied only to expressions in innermost loops. For now, only +// IVs in loops are regarded as likely to vary. The goal is to result in more +// loop-invariant expressions after the reassociation. + +namespace maple { + +void MeReassoc::FindSelfIncDecs(MeStmt *stmt, std::unordered_set *selfIncDefs) { + if (stmt->GetOp() != OP_dassign && stmt->GetOp() != OP_regassign) { + return; + } + ScalarMeExpr *lhs = static_cast(stmt)->GetLHS(); + OriginalSt *ost = lhs->GetOst(); + if (!IsPrimitiveInteger(ost->GetType()->GetPrimType())) { + return; + } + MeExpr *rhs = static_cast(stmt)->GetRHS(); + if (rhs->GetOp() != OP_add && rhs->GetOp() != OP_sub) { + return; + } + MeExpr *opnd0 = rhs->GetOpnd(0); + if (opnd0->GetOp() != OP_dread && opnd0->GetOp() != OP_regread) { + return; + } + if (static_cast(opnd0)->GetOst() != ost) { + return; + } + MeExpr *opnd1 = rhs->GetOpnd(1); + if (opnd1->GetMeOp() != kMeOpConst) { + return; + } + selfIncDefs->insert(ost->GetIndex()); +} + +// Given an address expression, group the terms into ivPart containing the +// terms likely to vary frequently during execution, and nonIVPart containing +// the rest of the terms. Return the 2 parts in ReassociatedParts. +ReassociatedParts MeReassoc::ReassociateAddSub(MeExpr *x, std::unordered_set *selfIncDefs) { + switch (x->GetMeOp()) { + case kMeOpVar: + case kMeOpReg: { + ScalarMeExpr *scalar = static_cast(x); + if (selfIncDefs->count(scalar->GetOst()->GetIndex()) > 0) { + return ReassociatedParts(x, nullptr); + } + return ReassociatedParts(nullptr, x); + } + case kMeOpOp: { + OpMeExpr *opX = static_cast(x); + if (!IsPrimitiveInteger(opX->GetPrimType())) { + return ReassociatedParts(nullptr, x); + } + switch (opX->GetOp()) { + case OP_cvt: { + if (!IsPrimitiveInteger(opX->GetOpndType())) { + return ReassociatedParts(nullptr, x); + } + ReassociatedParts opndReassoc = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + if (opndReassoc.ivPart != nullptr) { + opndReassoc.ivPart = irMap->CreateMeExprTypeCvt(opX->GetPrimType(), opX->GetOpndType(), *opndReassoc.ivPart); + } + if (opndReassoc.nonIVPart != nullptr) { + opndReassoc.nonIVPart = irMap->CreateMeExprTypeCvt(opX->GetPrimType(), opX->GetOpndType(), *opndReassoc.nonIVPart); + } + return opndReassoc; + } + case OP_neg: { + ReassociatedParts opndReassoc = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + if (opndReassoc.ivPart != nullptr) { + opndReassoc.ivPartNegated = !opndReassoc.ivPartNegated; + } + if (opndReassoc.nonIVPart != nullptr) { + opndReassoc.nonIVPartNegated = !opndReassoc.nonIVPartNegated; + } + return opndReassoc; + } + case OP_mul: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + if (reassoc0.ivPart != nullptr || reassoc1.ivPart != nullptr) { + return ReassociatedParts(x, nullptr); + } + return ReassociatedParts(nullptr, x); + } + case OP_add: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + ReassociatedParts answer(nullptr, nullptr); + // set answer.ivPart + if (reassoc0.ivPart == nullptr) { + answer.ivPart = reassoc1.ivPart; + answer.ivPartNegated = reassoc1.ivPartNegated; + } else if (reassoc1.ivPart == nullptr) { + answer.ivPart = reassoc0.ivPart; + answer.ivPartNegated = reassoc0.ivPartNegated; + } else { + if (reassoc0.ivPartNegated == reassoc1.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = reassoc0.ivPartNegated; + } else if (!reassoc0.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + } else { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc1.ivPart, *reassoc0.ivPart); + } + } + // set answer.nonIVPart + if (reassoc0.nonIVPart == nullptr) { + answer.nonIVPart = reassoc1.nonIVPart; + answer.nonIVPartNegated = reassoc1.nonIVPartNegated; + } else if (reassoc1.nonIVPart == nullptr) { + answer.nonIVPart = reassoc0.nonIVPart; + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else { + if (reassoc0.nonIVPartNegated == reassoc1.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else if (!reassoc0.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + } else { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc1.nonIVPart, *reassoc0.nonIVPart); + } + } + return answer; + } + case OP_sub: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + ReassociatedParts answer(nullptr, nullptr); + // set answer.ivPart + if (reassoc0.ivPart == nullptr) { + answer.ivPart = reassoc1.ivPart; + if (answer.ivPart != nullptr) { + answer.ivPartNegated = !reassoc1.ivPartNegated; + } + } else if (reassoc1.ivPart == nullptr) { + answer.ivPart = reassoc0.ivPart; + answer.ivPartNegated = reassoc0.ivPartNegated; + } else { + if (reassoc0.ivPartNegated == reassoc1.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = reassoc0.ivPartNegated; + } else if (!reassoc0.ivPartNegated) { // reassoc1 must ivPartNegated + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + } else { // reassoc0.ivPartNegated and !reassoc1.ivPartNegated + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = true; + } + } + // set answer.nonIVPart + if (reassoc0.nonIVPart == nullptr) { + answer.nonIVPart = reassoc1.nonIVPart; + if (answer.nonIVPart != nullptr) { + answer.nonIVPartNegated = !reassoc1.nonIVPartNegated; + } + } else if (reassoc1.nonIVPart == nullptr) { + answer.nonIVPart = reassoc0.nonIVPart; + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else { + if (reassoc0.nonIVPartNegated == reassoc1.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else if (!reassoc0.nonIVPartNegated) { // reassoc1 must nonIVPartNegated + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + } else { // reassoc0.nonIVPartNegated and !reassoc1.nonIVPartNegated + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = true; + } + } + return answer; + } + default: return ReassociatedParts(nullptr, x); + } + } + default: return ReassociatedParts(nullptr, x); + } +} + +// form and return the final reassociated expression +MeExpr *MeReassoc::FormReassociatedExpr(ReassociatedParts reassoc) { + if (reassoc.ivPart != nullptr ^ reassoc.nonIVPart != nullptr) { + CHECK_FATAL(!reassoc.ivPartNegated && !reassoc.nonIVPartNegated, + "SimplifyIvar: top level reassociated address expression must not be negated"); + // no re-association + if (reassoc.ivPart != nullptr) { + if (!reassoc.ivPartNegated) { + return reassoc.ivPart; + } + return irMap->CreateMeExprUnary(OP_neg, reassoc.ivPart->GetPrimType(), *reassoc.ivPart); + } + if (!reassoc.nonIVPartNegated) { + return reassoc.nonIVPart; + } + return irMap->CreateMeExprUnary(OP_neg, reassoc.nonIVPart->GetPrimType(), *reassoc.nonIVPart); + } + CHECK_FATAL(!(reassoc.ivPart->HasAddressValue() && reassoc.nonIVPart->HasAddressValue()), + "SimplifyIvar: Conflicting settings of HasAddressValue() in reassociated operands"); + if (reassoc.ivPart->HasAddressValue()) { + CHECK_FATAL(!reassoc.ivPartNegated, "SimplifyIvar: cannot negate an address value"); + Opcode opToUse = reassoc.nonIVPartNegated ? OP_sub : OP_add; + OpMeExpr opMeExpr(kInvalidExprID, opToUse, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.ivPart); + opMeExpr.SetOpnd(1, reassoc.nonIVPart); + MeExpr *finalMeExpr = irMap->HashMeExpr(opMeExpr); + static_cast(finalMeExpr)->hasAddressValue = true; + return finalMeExpr; + } else if (reassoc.nonIVPart->HasAddressValue()) { + CHECK_FATAL(!reassoc.nonIVPartNegated, "SimplifyIvar: cannot negate an address value"); + Opcode opToUse = reassoc.ivPartNegated ? OP_sub : OP_add; + OpMeExpr opMeExpr(kInvalidExprID, opToUse, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.nonIVPart); + opMeExpr.SetOpnd(1, reassoc.ivPart); + MeExpr *finalMeExpr = irMap->HashMeExpr(opMeExpr); + static_cast(finalMeExpr)->hasAddressValue = true; + return finalMeExpr; + } else { // not sure which part has address value + CHECK_FATAL(!(reassoc.ivPartNegated && reassoc.nonIVPartNegated), "SimplifyIvar: negative address expression cannot be negated"); + if (reassoc.nonIVPartNegated) { + OpMeExpr opMeExpr(kInvalidExprID, OP_sub, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.ivPart); + opMeExpr.SetOpnd(1, reassoc.nonIVPart); + return irMap->HashMeExpr(opMeExpr); + } else { + OpMeExpr opMeExpr(kInvalidExprID, reassoc.ivPartNegated ? OP_sub : OP_add, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.nonIVPart); + opMeExpr.SetOpnd(1, reassoc.ivPart); + return irMap->HashMeExpr(opMeExpr); + } + } +} + +// Descend the expression tree to find reassociation candidates. "changed" is +// for indicating back to caller whether expression has been changed. Any +// change can be due to reassociation or due to rehash on the way back up. +MeExpr *MeReassoc::ApplyReassocExpr(MeExpr *x, std::unordered_set *selfIncDefs, bool *changed) { + switch (x->GetMeOp()) { + case kMeOpOp: { + bool isChanged = false; + OpMeExpr *opX = static_cast(x); + OpMeExpr newX(*opX, kInvalidExprID); + for (uint32 i = 0; i < x->GetNumOpnds(); ++i) { + newX.SetOpnd(i, ApplyReassocExpr(x->GetOpnd(i), selfIncDefs, &isChanged)); + } + if (isChanged) { + *changed = true; + x = irMap->HashMeExpr(newX); + } + if (!static_cast(x)->canApplyReassoc) { + return x; + } + // perform reassociation for this reassociation candidate + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Reassociating "; + x->Dump(irMap,0); + mirModule->GetOut() << std::endl; + } + ReassociatedParts reassoc = ReassociateAddSub(x, selfIncDefs); + if (reassoc.ivPart != nullptr ^ reassoc.nonIVPart != nullptr) { + CHECK_FATAL(!reassoc.ivPartNegated && !reassoc.nonIVPartNegated, + "ApplyReassocExpr: top level reassociated address expression must not be negated"); + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Unchanged" << std::endl; + } + return x; // not reassociated + } + MeExpr *reassociatedX = FormReassociatedExpr(reassoc); + if (reassociatedX != x) { + *changed = true; + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "changing it to "; + reassociatedX->Dump(irMap,0); + mirModule->GetOut() << std::endl; + } + } else { + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Unchanged" << std::endl; + } + } + return reassociatedX; + } + case kMeOpNary: { + bool isChanged = false; + NaryMeExpr *naryX = static_cast(x); + NaryMeExpr newNary(&irMap->GetIRMapAlloc(), kInvalidExprID, *naryX); + for (uint32 i = 0; i < x->GetNumOpnds(); ++i) { + newNary.SetOpnd(i, ApplyReassocExpr(x->GetOpnd(i), selfIncDefs, &isChanged)); + } + if (isChanged) { + *changed = true; + return irMap->HashMeExpr(newNary); + } + return x; + } + case kMeOpIvar: { + bool isChanged = false; + IvarMeExpr *ivarX = static_cast(x); + IvarMeExpr newIvar(kInvalidExprID, *ivarX); + newIvar.SetBase(ApplyReassocExpr(ivarX->GetBase(), selfIncDefs, &isChanged)); + if (isChanged) { + *changed = true; + return irMap->HashMeExpr(newIvar); + } + return x; + } + default: return x; + } +} + +// apply reassociation to all the expressions in this innermost loop +void MeReassoc::ProcessLoop(LoopDesc *aloop) { + std::unordered_set selfIncDefSyms; // symbols with self increment/decrement + // first pass over loop BBs to set selfIncDefSyms + for (BBId bbId : aloop->loopBBs) { + BB *bb = cfg->GetBBFromID(bbId); + for (MeStmt &stmt : bb->GetMeStmts()) { + FindSelfIncDecs(&stmt, &selfIncDefSyms); + } + } + // final pass: reassociate only expressions marked canApplyReassoc + for (BBId bbId : aloop->loopBBs) { + BB *bb = cfg->GetBBFromID(bbId); + for (MeStmt &stmt : bb->GetMeStmts()) { + for (uint32 i = 0; i < stmt.NumMeStmtOpnds(); i++) { + bool changed = false; + MeExpr *newOpnd = ApplyReassocExpr(stmt.GetOpnd(i), &selfIncDefSyms, &changed); + if (changed) { + stmt.SetOpnd(i, newOpnd); + } + } + } + } +} + +bool MEReassoc::PhaseRun(maple::MeFunction &f) { + IRMap *irMap = GET_ANALYSIS(MEIRMapBuild, f); + ASSERT(irMap != nullptr, "irMap phase has problem"); + IdentifyLoops *identLoops = GET_ANALYSIS(MELoopAnalysis, f); + CHECK_NULL_FATAL(identLoops); + MeReassoc reassoc(&f, irMap); + + // go thru all the loops to find innermost loops; do in reverse order so + // innermost loops are visited first + uint32 lastNestDepth = 0; + for (int32 i = identLoops->GetMeLoops().size()-1; i >= 0; i--) { + LoopDesc *aloop = identLoops->GetMeLoops()[i]; + if (aloop->nestDepth < lastNestDepth) { // not innermost + lastNestDepth = aloop->nestDepth; + continue; + } + reassoc.ProcessLoop(aloop); + lastNestDepth = aloop->nestDepth; + } + + if (DEBUGFUNC_NEWPM(f)) { + LogInfo::MapleLogger() << "\n============== after REASSOC =============" << '\n'; + f.Dump(false); + } + + return true; +} + +void MEReassoc::GetAnalysisDependence(AnalysisDep &aDep) const { + aDep.AddRequired(); + aDep.AddRequired(); + aDep.SetPreservedAll(); +} +} // namespace maple diff --git a/src/mapleall/maple_phase/include/phases.def b/src/mapleall/maple_phase/include/phases.def index 4bfd58725a..080cc3fae1 100644 --- a/src/mapleall/maple_phase/include/phases.def +++ b/src/mapleall/maple_phase/include/phases.def @@ -55,6 +55,7 @@ ADDMAPLEMEPHASE("safetyWarning", CLANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("hdse", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("may2dassign", JAVALANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("condbasednpc", JAVALANG && MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("reassoc", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("epre", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("stmtpre", JAVALANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("analyzerc", MeOption::optLevel != 0 && JAVALANG && !MeOption::noRC && !MeOption::gcOnly) -- Gitee From 9be5e11df582823433738721df00448cab24f446 Mon Sep 17 00:00:00 2001 From: Fred Chow Date: Mon, 27 Sep 2021 17:07:23 -0700 Subject: [PATCH 2/5] Added new phase "reassoc" to perform reassociation mainly for address expression s under iread/assign In the reassociation, the add/sub terms less likely to vary are separated from the parts likely to vary. This is done on a per loop basis, and is applied only to expressions in innermost loops. For now, only IVs in loops are regarded as likely to vary. The goal is to result in more loop-invariant expressions. --- src/mapleall/maple_me/BUILD.gn | 2 + src/mapleall/maple_me/include/me_ir.h | 3 +- .../maple_me/include/me_phase_manager.h | 2 + src/mapleall/maple_me/include/me_reassoc.h | 57 +++ src/mapleall/maple_me/src/irmap.cpp | 23 +- .../maple_me/src/me_phase_manager.cpp | 1 + src/mapleall/maple_me/src/me_reassoc.cpp | 384 ++++++++++++++++++ src/mapleall/maple_phase/include/phases.def | 1 + 8 files changed, 461 insertions(+), 12 deletions(-) create mode 100644 src/mapleall/maple_me/include/me_reassoc.h create mode 100644 src/mapleall/maple_me/src/me_reassoc.cpp diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index f8e479cea8..9ec81dc9f1 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -106,6 +106,8 @@ src_libmplme = [ "src/seqvec.cpp", "src/me_autovec.cpp", "src/me_safety_warning.cpp" + "src/me_reassoc.cpp", + "src/safety_warning.cpp" ] src_libmplmewpo = [ diff --git a/src/mapleall/maple_me/include/me_ir.h b/src/mapleall/maple_me/include/me_ir.h index 1213617da3..289b90c726 100644 --- a/src/mapleall/maple_me/include/me_ir.h +++ b/src/mapleall/maple_me/include/me_ir.h @@ -469,7 +469,7 @@ class MePhiNode { return defBB; } - ScalarMeExpr *GetLHS() { + ScalarMeExpr *GetLHS() const { return lhs; } @@ -924,6 +924,7 @@ class OpMeExpr : public MeExpr { FieldID fieldID = 0; // this is also used to store puIdx public: bool hasAddressValue = false; // used only when op is ADD or SUB + bool canApplyReassoc = false; // hint to apply reassociation to this tree }; class IvarMeExpr : public MeExpr { diff --git a/src/mapleall/maple_me/include/me_phase_manager.h b/src/mapleall/maple_me/include/me_phase_manager.h index 9afd986dba..3cb2af6169 100644 --- a/src/mapleall/maple_me/include/me_phase_manager.h +++ b/src/mapleall/maple_me/include/me_phase_manager.h @@ -83,6 +83,8 @@ #include "lfo_dep_test.h" #include "me_autovec.h" #include "me_safety_warning.h" +#include "me_reassoc.h" +#include "safety_warning.h" namespace maple { using meFuncOptTy = MapleFunctionPhase; diff --git a/src/mapleall/maple_me/include/me_reassoc.h b/src/mapleall/maple_me/include/me_reassoc.h new file mode 100644 index 0000000000..a039349b15 --- /dev/null +++ b/src/mapleall/maple_me/include/me_reassoc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_REASSOC_H +#define MAPLE_ME_INCLUDE_ME_REASSOC_H + +#include "me_function.h" +#include "me_irmap.h" +#include "me_cfg.h" +#include "me_loop_analysis.h" + +namespace maple { +// for representing the reults of ReassociateAddSub() +class ReassociatedParts { + public: + ReassociatedParts(MeExpr *ivpart, MeExpr *nonivpart) : ivPart(ivpart), nonIVPart(nonivpart) {} + public: + MeExpr *ivPart = nullptr; // the expr part likely to vary during exec + MeExpr *nonIVPart = nullptr; // the expr part not likely to change during exec + bool ivPartNegated = false; + bool nonIVPartNegated = false; +}; + +class MeReassoc { + public: + explicit MeReassoc(MeFunction *f, IRMap *map) : func(f), irMap(map), mirModule(&map->GetMIRModule()), cfg(f->GetCfg()) {} + virtual ~MeReassoc() = default; + + void FindSelfIncDecs(MeStmt *stmt, std::unordered_set *selfIncDefs); + MeExpr *FormReassociatedExpr(ReassociatedParts reassoc); + ReassociatedParts ReassociateAddSub(MeExpr *x, std::unordered_set *selfIncDefs); + void ProcessLoop(LoopDesc *aloop); + MeExpr *ApplyReassocExpr(MeExpr *x, std::unordered_set *selfIncDefs, bool *changed); + std::string PhaseName() const { + return "reassoc"; + } + public: + MeFunction *func; + IRMap *irMap; + MIRModule *mirModule; + MeCFG *cfg; +}; + +MAPLE_FUNC_PHASE_DECLARE(MEReassoc, MeFunction) +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_REASSOC_H diff --git a/src/mapleall/maple_me/src/irmap.cpp b/src/mapleall/maple_me/src/irmap.cpp index 859c43f598..e1bc160dc9 100644 --- a/src/mapleall/maple_me/src/irmap.cpp +++ b/src/mapleall/maple_me/src/irmap.cpp @@ -445,21 +445,22 @@ MeExpr *IRMap::SimplifyIvarWithIaddrofBase(IvarMeExpr *ivar, bool lhsIvar) { } MeExpr *IRMap::SimplifyIvar(IvarMeExpr *ivar, bool lhsIvar) { - auto *simplifiedIvar = SimplifyIvarWithConstOffset(ivar, lhsIvar); - if (simplifiedIvar != nullptr) { - return simplifiedIvar; + MeExpr *simplifiedIvar = SimplifyIvarWithConstOffset(ivar, lhsIvar); + if (simplifiedIvar == nullptr) { + simplifiedIvar = SimplifyIvarWithAddrofBase(ivar); + if (simplifiedIvar == nullptr) { + simplifiedIvar = SimplifyIvarWithIaddrofBase(ivar, lhsIvar); + } } - - simplifiedIvar = SimplifyIvarWithAddrofBase(ivar); - if (simplifiedIvar != nullptr) { + if (simplifiedIvar != nullptr && simplifiedIvar->GetMeOp() != kMeOpIvar) { return simplifiedIvar; } - - simplifiedIvar = SimplifyIvarWithIaddrofBase(ivar, lhsIvar); - if (simplifiedIvar != nullptr) { - return simplifiedIvar; + // set canApplyReassoc + IvarMeExpr *retIvar = simplifiedIvar != nullptr ? static_cast(simplifiedIvar) : ivar ; + if (retIvar->GetBase()->GetOp() == OP_add || retIvar->GetBase()->GetOp() == OP_sub) { + static_cast(retIvar->GetBase())->canApplyReassoc = true; } - return nullptr; + return simplifiedIvar; } IvarMeExpr *IRMap::BuildLHSIvar(MeExpr &baseAddr, IassignMeStmt &iassignMeStmt, FieldID fieldID) { diff --git a/src/mapleall/maple_me/src/me_phase_manager.cpp b/src/mapleall/maple_me/src/me_phase_manager.cpp index df97904c18..058c15a859 100644 --- a/src/mapleall/maple_me/src/me_phase_manager.cpp +++ b/src/mapleall/maple_me/src/me_phase_manager.cpp @@ -199,6 +199,7 @@ MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEProfGen, profileGen) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEPlacementRC, placementrc) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEDse, dse) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEABCOpt, abcopt) +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEReassoc, reassoc) MAPLE_TRANSFORM_PHASE_REGISTER(MEEmit, meemit) MAPLE_TRANSFORM_PHASE_REGISTER(EmitForIPA, emitforipa) } // namespace maple diff --git a/src/mapleall/maple_me/src/me_reassoc.cpp b/src/mapleall/maple_me/src/me_reassoc.cpp new file mode 100644 index 0000000000..2d8465d8af --- /dev/null +++ b/src/mapleall/maple_me/src/me_reassoc.cpp @@ -0,0 +1,384 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 v2 for more details. + */ +#include "me_phase_manager.h" +#include "me_reassoc.h" + +// This reassoc phase performs reassociation mainly for address expressions +// under iread/iassign. In the reassociation, the add/sub terms less likely to +// vary are separated from the parts likely to vary. This is done on a per loop// basis, and is applied only to expressions in innermost loops. For now, only +// IVs in loops are regarded as likely to vary. The goal is to result in more +// loop-invariant expressions after the reassociation. + +namespace maple { + +void MeReassoc::FindSelfIncDecs(MeStmt *stmt, std::unordered_set *selfIncDefs) { + if (stmt->GetOp() != OP_dassign && stmt->GetOp() != OP_regassign) { + return; + } + ScalarMeExpr *lhs = static_cast(stmt)->GetLHS(); + OriginalSt *ost = lhs->GetOst(); + if (!IsPrimitiveInteger(ost->GetType()->GetPrimType())) { + return; + } + MeExpr *rhs = static_cast(stmt)->GetRHS(); + if (rhs->GetOp() != OP_add && rhs->GetOp() != OP_sub) { + return; + } + MeExpr *opnd0 = rhs->GetOpnd(0); + if (opnd0->GetOp() != OP_dread && opnd0->GetOp() != OP_regread) { + return; + } + if (static_cast(opnd0)->GetOst() != ost) { + return; + } + MeExpr *opnd1 = rhs->GetOpnd(1); + if (opnd1->GetMeOp() != kMeOpConst) { + return; + } + selfIncDefs->insert(ost->GetIndex()); +} + +// Given an address expression, group the terms into ivPart containing the +// terms likely to vary frequently during execution, and nonIVPart containing +// the rest of the terms. Return the 2 parts in ReassociatedParts. +ReassociatedParts MeReassoc::ReassociateAddSub(MeExpr *x, std::unordered_set *selfIncDefs) { + switch (x->GetMeOp()) { + case kMeOpVar: + case kMeOpReg: { + ScalarMeExpr *scalar = static_cast(x); + if (selfIncDefs->count(scalar->GetOst()->GetIndex()) > 0) { + return ReassociatedParts(x, nullptr); + } + return ReassociatedParts(nullptr, x); + } + case kMeOpOp: { + OpMeExpr *opX = static_cast(x); + if (!IsPrimitiveInteger(opX->GetPrimType())) { + return ReassociatedParts(nullptr, x); + } + switch (opX->GetOp()) { + case OP_cvt: { + if (!IsPrimitiveInteger(opX->GetOpndType())) { + return ReassociatedParts(nullptr, x); + } + ReassociatedParts opndReassoc = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + if (opndReassoc.ivPart != nullptr) { + opndReassoc.ivPart = irMap->CreateMeExprTypeCvt(opX->GetPrimType(), opX->GetOpndType(), *opndReassoc.ivPart); + } + if (opndReassoc.nonIVPart != nullptr) { + opndReassoc.nonIVPart = irMap->CreateMeExprTypeCvt(opX->GetPrimType(), opX->GetOpndType(), *opndReassoc.nonIVPart); + } + return opndReassoc; + } + case OP_neg: { + ReassociatedParts opndReassoc = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + if (opndReassoc.ivPart != nullptr) { + opndReassoc.ivPartNegated = !opndReassoc.ivPartNegated; + } + if (opndReassoc.nonIVPart != nullptr) { + opndReassoc.nonIVPartNegated = !opndReassoc.nonIVPartNegated; + } + return opndReassoc; + } + case OP_mul: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + if (reassoc0.ivPart != nullptr || reassoc1.ivPart != nullptr) { + return ReassociatedParts(x, nullptr); + } + return ReassociatedParts(nullptr, x); + } + case OP_add: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + ReassociatedParts answer(nullptr, nullptr); + // set answer.ivPart + if (reassoc0.ivPart == nullptr) { + answer.ivPart = reassoc1.ivPart; + answer.ivPartNegated = reassoc1.ivPartNegated; + } else if (reassoc1.ivPart == nullptr) { + answer.ivPart = reassoc0.ivPart; + answer.ivPartNegated = reassoc0.ivPartNegated; + } else { + if (reassoc0.ivPartNegated == reassoc1.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = reassoc0.ivPartNegated; + } else if (!reassoc0.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + } else { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc1.ivPart, *reassoc0.ivPart); + } + } + // set answer.nonIVPart + if (reassoc0.nonIVPart == nullptr) { + answer.nonIVPart = reassoc1.nonIVPart; + answer.nonIVPartNegated = reassoc1.nonIVPartNegated; + } else if (reassoc1.nonIVPart == nullptr) { + answer.nonIVPart = reassoc0.nonIVPart; + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else { + if (reassoc0.nonIVPartNegated == reassoc1.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else if (!reassoc0.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + } else { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc1.nonIVPart, *reassoc0.nonIVPart); + } + } + return answer; + } + case OP_sub: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + ReassociatedParts answer(nullptr, nullptr); + // set answer.ivPart + if (reassoc0.ivPart == nullptr) { + answer.ivPart = reassoc1.ivPart; + if (answer.ivPart != nullptr) { + answer.ivPartNegated = !reassoc1.ivPartNegated; + } + } else if (reassoc1.ivPart == nullptr) { + answer.ivPart = reassoc0.ivPart; + answer.ivPartNegated = reassoc0.ivPartNegated; + } else { + if (reassoc0.ivPartNegated == reassoc1.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = reassoc0.ivPartNegated; + } else if (!reassoc0.ivPartNegated) { // reassoc1 must ivPartNegated + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + } else { // reassoc0.ivPartNegated and !reassoc1.ivPartNegated + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = true; + } + } + // set answer.nonIVPart + if (reassoc0.nonIVPart == nullptr) { + answer.nonIVPart = reassoc1.nonIVPart; + if (answer.nonIVPart != nullptr) { + answer.nonIVPartNegated = !reassoc1.nonIVPartNegated; + } + } else if (reassoc1.nonIVPart == nullptr) { + answer.nonIVPart = reassoc0.nonIVPart; + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else { + if (reassoc0.nonIVPartNegated == reassoc1.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else if (!reassoc0.nonIVPartNegated) { // reassoc1 must nonIVPartNegated + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + } else { // reassoc0.nonIVPartNegated and !reassoc1.nonIVPartNegated + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = true; + } + } + return answer; + } + default: return ReassociatedParts(nullptr, x); + } + } + default: return ReassociatedParts(nullptr, x); + } +} + +// form and return the final reassociated expression +MeExpr *MeReassoc::FormReassociatedExpr(ReassociatedParts reassoc) { + if (reassoc.ivPart != nullptr ^ reassoc.nonIVPart != nullptr) { + CHECK_FATAL(!reassoc.ivPartNegated && !reassoc.nonIVPartNegated, + "SimplifyIvar: top level reassociated address expression must not be negated"); + // no re-association + if (reassoc.ivPart != nullptr) { + if (!reassoc.ivPartNegated) { + return reassoc.ivPart; + } + return irMap->CreateMeExprUnary(OP_neg, reassoc.ivPart->GetPrimType(), *reassoc.ivPart); + } + if (!reassoc.nonIVPartNegated) { + return reassoc.nonIVPart; + } + return irMap->CreateMeExprUnary(OP_neg, reassoc.nonIVPart->GetPrimType(), *reassoc.nonIVPart); + } + CHECK_FATAL(!(reassoc.ivPart->HasAddressValue() && reassoc.nonIVPart->HasAddressValue()), + "SimplifyIvar: Conflicting settings of HasAddressValue() in reassociated operands"); + if (reassoc.ivPart->HasAddressValue()) { + CHECK_FATAL(!reassoc.ivPartNegated, "SimplifyIvar: cannot negate an address value"); + Opcode opToUse = reassoc.nonIVPartNegated ? OP_sub : OP_add; + OpMeExpr opMeExpr(kInvalidExprID, opToUse, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.ivPart); + opMeExpr.SetOpnd(1, reassoc.nonIVPart); + MeExpr *finalMeExpr = irMap->HashMeExpr(opMeExpr); + static_cast(finalMeExpr)->hasAddressValue = true; + return finalMeExpr; + } else if (reassoc.nonIVPart->HasAddressValue()) { + CHECK_FATAL(!reassoc.nonIVPartNegated, "SimplifyIvar: cannot negate an address value"); + Opcode opToUse = reassoc.ivPartNegated ? OP_sub : OP_add; + OpMeExpr opMeExpr(kInvalidExprID, opToUse, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.nonIVPart); + opMeExpr.SetOpnd(1, reassoc.ivPart); + MeExpr *finalMeExpr = irMap->HashMeExpr(opMeExpr); + static_cast(finalMeExpr)->hasAddressValue = true; + return finalMeExpr; + } else { // not sure which part has address value + CHECK_FATAL(!(reassoc.ivPartNegated && reassoc.nonIVPartNegated), "SimplifyIvar: negative address expression cannot be negated"); + if (reassoc.nonIVPartNegated) { + OpMeExpr opMeExpr(kInvalidExprID, OP_sub, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.ivPart); + opMeExpr.SetOpnd(1, reassoc.nonIVPart); + return irMap->HashMeExpr(opMeExpr); + } else { + OpMeExpr opMeExpr(kInvalidExprID, reassoc.ivPartNegated ? OP_sub : OP_add, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.nonIVPart); + opMeExpr.SetOpnd(1, reassoc.ivPart); + return irMap->HashMeExpr(opMeExpr); + } + } +} + +// Descend the expression tree to find reassociation candidates. "changed" is +// for indicating back to caller whether expression has been changed. Any +// change can be due to reassociation or due to rehash on the way back up. +MeExpr *MeReassoc::ApplyReassocExpr(MeExpr *x, std::unordered_set *selfIncDefs, bool *changed) { + switch (x->GetMeOp()) { + case kMeOpOp: { + bool isChanged = false; + OpMeExpr *opX = static_cast(x); + OpMeExpr newX(*opX, kInvalidExprID); + for (uint32 i = 0; i < x->GetNumOpnds(); ++i) { + newX.SetOpnd(i, ApplyReassocExpr(x->GetOpnd(i), selfIncDefs, &isChanged)); + } + if (isChanged) { + *changed = true; + x = irMap->HashMeExpr(newX); + } + if (!static_cast(x)->canApplyReassoc) { + return x; + } + // perform reassociation for this reassociation candidate + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Reassociating "; + x->Dump(irMap,0); + mirModule->GetOut() << std::endl; + } + ReassociatedParts reassoc = ReassociateAddSub(x, selfIncDefs); + if (reassoc.ivPart != nullptr ^ reassoc.nonIVPart != nullptr) { + CHECK_FATAL(!reassoc.ivPartNegated && !reassoc.nonIVPartNegated, + "ApplyReassocExpr: top level reassociated address expression must not be negated"); + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Unchanged" << std::endl; + } + return x; // not reassociated + } + MeExpr *reassociatedX = FormReassociatedExpr(reassoc); + if (reassociatedX != x) { + *changed = true; + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "changing it to "; + reassociatedX->Dump(irMap,0); + mirModule->GetOut() << std::endl; + } + } else { + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Unchanged" << std::endl; + } + } + return reassociatedX; + } + case kMeOpNary: { + bool isChanged = false; + NaryMeExpr *naryX = static_cast(x); + NaryMeExpr newNary(&irMap->GetIRMapAlloc(), kInvalidExprID, *naryX); + for (uint32 i = 0; i < x->GetNumOpnds(); ++i) { + newNary.SetOpnd(i, ApplyReassocExpr(x->GetOpnd(i), selfIncDefs, &isChanged)); + } + if (isChanged) { + *changed = true; + return irMap->HashMeExpr(newNary); + } + return x; + } + case kMeOpIvar: { + bool isChanged = false; + IvarMeExpr *ivarX = static_cast(x); + IvarMeExpr newIvar(kInvalidExprID, *ivarX); + newIvar.SetBase(ApplyReassocExpr(ivarX->GetBase(), selfIncDefs, &isChanged)); + if (isChanged) { + *changed = true; + return irMap->HashMeExpr(newIvar); + } + return x; + } + default: return x; + } +} + +// apply reassociation to all the expressions in this innermost loop +void MeReassoc::ProcessLoop(LoopDesc *aloop) { + std::unordered_set selfIncDefSyms; // symbols with self increment/decrement + // first pass over loop BBs to set selfIncDefSyms + for (BBId bbId : aloop->loopBBs) { + BB *bb = cfg->GetBBFromID(bbId); + for (MeStmt &stmt : bb->GetMeStmts()) { + FindSelfIncDecs(&stmt, &selfIncDefSyms); + } + } + // final pass: reassociate only expressions marked canApplyReassoc + for (BBId bbId : aloop->loopBBs) { + BB *bb = cfg->GetBBFromID(bbId); + for (MeStmt &stmt : bb->GetMeStmts()) { + for (uint32 i = 0; i < stmt.NumMeStmtOpnds(); i++) { + bool changed = false; + MeExpr *newOpnd = ApplyReassocExpr(stmt.GetOpnd(i), &selfIncDefSyms, &changed); + if (changed) { + stmt.SetOpnd(i, newOpnd); + } + } + } + } +} + +bool MEReassoc::PhaseRun(maple::MeFunction &f) { + IRMap *irMap = GET_ANALYSIS(MEIRMapBuild, f); + ASSERT(irMap != nullptr, "irMap phase has problem"); + IdentifyLoops *identLoops = GET_ANALYSIS(MELoopAnalysis, f); + CHECK_NULL_FATAL(identLoops); + MeReassoc reassoc(&f, irMap); + + // go thru all the loops to find innermost loops; do in reverse order so + // innermost loops are visited first + uint32 lastNestDepth = 0; + for (int32 i = identLoops->GetMeLoops().size()-1; i >= 0; i--) { + LoopDesc *aloop = identLoops->GetMeLoops()[i]; + if (aloop->nestDepth < lastNestDepth) { // not innermost + lastNestDepth = aloop->nestDepth; + continue; + } + reassoc.ProcessLoop(aloop); + lastNestDepth = aloop->nestDepth; + } + + if (DEBUGFUNC_NEWPM(f)) { + LogInfo::MapleLogger() << "\n============== after REASSOC =============" << '\n'; + f.Dump(false); + } + + return true; +} + +void MEReassoc::GetAnalysisDependence(AnalysisDep &aDep) const { + aDep.AddRequired(); + aDep.AddRequired(); + aDep.SetPreservedAll(); +} +} // namespace maple diff --git a/src/mapleall/maple_phase/include/phases.def b/src/mapleall/maple_phase/include/phases.def index 8b70d335fe..d984f38ccc 100644 --- a/src/mapleall/maple_phase/include/phases.def +++ b/src/mapleall/maple_phase/include/phases.def @@ -57,6 +57,7 @@ ADDMAPLEMEPHASE("hprop", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("hdse", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("may2dassign", JAVALANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("condbasednpc", JAVALANG && MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("reassoc", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("epre", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("stmtpre", JAVALANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("analyzerc", MeOption::optLevel != 0 && JAVALANG && !MeOption::noRC && !MeOption::gcOnly) -- Gitee From e9aab42940fa1d6e1f997b111965faf0bc64aa1a Mon Sep 17 00:00:00 2001 From: Fred Chow Date: Wed, 27 Oct 2021 19:33:11 -0700 Subject: [PATCH 3/5] Rebased to master and fixed conflicts --- src/mapleall/maple_me/BUILD.gn | 5 ++--- src/mapleall/maple_me/include/me_phase_manager.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index 9ec81dc9f1..4e15950d9c 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -105,9 +105,8 @@ src_libmplme = [ "src/simplifyCFG.cpp", "src/seqvec.cpp", "src/me_autovec.cpp", - "src/me_safety_warning.cpp" - "src/me_reassoc.cpp", - "src/safety_warning.cpp" + "src/me_safety_warning.cpp", + "src/me_reassoc.cpp" ] src_libmplmewpo = [ diff --git a/src/mapleall/maple_me/include/me_phase_manager.h b/src/mapleall/maple_me/include/me_phase_manager.h index 3cb2af6169..f1a5dc52b1 100644 --- a/src/mapleall/maple_me/include/me_phase_manager.h +++ b/src/mapleall/maple_me/include/me_phase_manager.h @@ -84,7 +84,6 @@ #include "me_autovec.h" #include "me_safety_warning.h" #include "me_reassoc.h" -#include "safety_warning.h" namespace maple { using meFuncOptTy = MapleFunctionPhase; -- Gitee From 1d92f48de9b621402137e77bec7782b726c45106 Mon Sep 17 00:00:00 2001 From: Fred Chow Date: Mon, 27 Sep 2021 17:07:23 -0700 Subject: [PATCH 4/5] Added new phase "reassoc" to perform reassociation mainly for address expression s under iread/assign In the reassociation, the add/sub terms less likely to vary are separated from the parts likely to vary. This is done on a per loop basis, and is applied only to expressions in innermost loops. For now, only IVs in loops are regarded as likely to vary. The goal is to result in more loop-invariant expressions. --- src/mapleall/maple_me/BUILD.gn | 2 + src/mapleall/maple_me/include/me_ir.h | 3 +- .../maple_me/include/me_phase_manager.h | 1 + src/mapleall/maple_me/include/me_reassoc.h | 57 +++ src/mapleall/maple_me/src/irmap.cpp | 23 +- .../maple_me/src/me_phase_manager.cpp | 1 + src/mapleall/maple_me/src/me_reassoc.cpp | 384 ++++++++++++++++++ src/mapleall/maple_phase/include/phases.def | 1 + 8 files changed, 460 insertions(+), 12 deletions(-) create mode 100644 src/mapleall/maple_me/include/me_reassoc.h create mode 100644 src/mapleall/maple_me/src/me_reassoc.cpp diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index 270c5df53e..afba268a17 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -107,6 +107,8 @@ src_libmplme = [ "src/seqvec.cpp", "src/me_autovec.cpp", "src/me_safety_warning.cpp" + "src/me_reassoc.cpp", + "src/safety_warning.cpp" ] src_libmplmewpo = [ diff --git a/src/mapleall/maple_me/include/me_ir.h b/src/mapleall/maple_me/include/me_ir.h index 3bda5eff22..eca543ac68 100644 --- a/src/mapleall/maple_me/include/me_ir.h +++ b/src/mapleall/maple_me/include/me_ir.h @@ -489,7 +489,7 @@ class MePhiNode { return defBB; } - ScalarMeExpr *GetLHS() { + ScalarMeExpr *GetLHS() const { return lhs; } @@ -948,6 +948,7 @@ class OpMeExpr : public MeExpr { FieldID fieldID = 0; // this is also used to store puIdx public: bool hasAddressValue = false; // used only when op is ADD or SUB + bool canApplyReassoc = false; // hint to apply reassociation to this tree }; class IvarMeExpr : public MeExpr { diff --git a/src/mapleall/maple_me/include/me_phase_manager.h b/src/mapleall/maple_me/include/me_phase_manager.h index 98c3a6662b..c655da751e 100644 --- a/src/mapleall/maple_me/include/me_phase_manager.h +++ b/src/mapleall/maple_me/include/me_phase_manager.h @@ -84,6 +84,7 @@ #include "me_autovec.h" #include "me_safety_warning.h" #include "me_sink.h" +#include "me_reassoc.h" namespace maple { using meFuncOptTy = MapleFunctionPhase; diff --git a/src/mapleall/maple_me/include/me_reassoc.h b/src/mapleall/maple_me/include/me_reassoc.h new file mode 100644 index 0000000000..a039349b15 --- /dev/null +++ b/src/mapleall/maple_me/include/me_reassoc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_REASSOC_H +#define MAPLE_ME_INCLUDE_ME_REASSOC_H + +#include "me_function.h" +#include "me_irmap.h" +#include "me_cfg.h" +#include "me_loop_analysis.h" + +namespace maple { +// for representing the reults of ReassociateAddSub() +class ReassociatedParts { + public: + ReassociatedParts(MeExpr *ivpart, MeExpr *nonivpart) : ivPart(ivpart), nonIVPart(nonivpart) {} + public: + MeExpr *ivPart = nullptr; // the expr part likely to vary during exec + MeExpr *nonIVPart = nullptr; // the expr part not likely to change during exec + bool ivPartNegated = false; + bool nonIVPartNegated = false; +}; + +class MeReassoc { + public: + explicit MeReassoc(MeFunction *f, IRMap *map) : func(f), irMap(map), mirModule(&map->GetMIRModule()), cfg(f->GetCfg()) {} + virtual ~MeReassoc() = default; + + void FindSelfIncDecs(MeStmt *stmt, std::unordered_set *selfIncDefs); + MeExpr *FormReassociatedExpr(ReassociatedParts reassoc); + ReassociatedParts ReassociateAddSub(MeExpr *x, std::unordered_set *selfIncDefs); + void ProcessLoop(LoopDesc *aloop); + MeExpr *ApplyReassocExpr(MeExpr *x, std::unordered_set *selfIncDefs, bool *changed); + std::string PhaseName() const { + return "reassoc"; + } + public: + MeFunction *func; + IRMap *irMap; + MIRModule *mirModule; + MeCFG *cfg; +}; + +MAPLE_FUNC_PHASE_DECLARE(MEReassoc, MeFunction) +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_REASSOC_H diff --git a/src/mapleall/maple_me/src/irmap.cpp b/src/mapleall/maple_me/src/irmap.cpp index 859c43f598..e1bc160dc9 100644 --- a/src/mapleall/maple_me/src/irmap.cpp +++ b/src/mapleall/maple_me/src/irmap.cpp @@ -445,21 +445,22 @@ MeExpr *IRMap::SimplifyIvarWithIaddrofBase(IvarMeExpr *ivar, bool lhsIvar) { } MeExpr *IRMap::SimplifyIvar(IvarMeExpr *ivar, bool lhsIvar) { - auto *simplifiedIvar = SimplifyIvarWithConstOffset(ivar, lhsIvar); - if (simplifiedIvar != nullptr) { - return simplifiedIvar; + MeExpr *simplifiedIvar = SimplifyIvarWithConstOffset(ivar, lhsIvar); + if (simplifiedIvar == nullptr) { + simplifiedIvar = SimplifyIvarWithAddrofBase(ivar); + if (simplifiedIvar == nullptr) { + simplifiedIvar = SimplifyIvarWithIaddrofBase(ivar, lhsIvar); + } } - - simplifiedIvar = SimplifyIvarWithAddrofBase(ivar); - if (simplifiedIvar != nullptr) { + if (simplifiedIvar != nullptr && simplifiedIvar->GetMeOp() != kMeOpIvar) { return simplifiedIvar; } - - simplifiedIvar = SimplifyIvarWithIaddrofBase(ivar, lhsIvar); - if (simplifiedIvar != nullptr) { - return simplifiedIvar; + // set canApplyReassoc + IvarMeExpr *retIvar = simplifiedIvar != nullptr ? static_cast(simplifiedIvar) : ivar ; + if (retIvar->GetBase()->GetOp() == OP_add || retIvar->GetBase()->GetOp() == OP_sub) { + static_cast(retIvar->GetBase())->canApplyReassoc = true; } - return nullptr; + return simplifiedIvar; } IvarMeExpr *IRMap::BuildLHSIvar(MeExpr &baseAddr, IassignMeStmt &iassignMeStmt, FieldID fieldID) { diff --git a/src/mapleall/maple_me/src/me_phase_manager.cpp b/src/mapleall/maple_me/src/me_phase_manager.cpp index fb5b32e76e..3d9b824874 100644 --- a/src/mapleall/maple_me/src/me_phase_manager.cpp +++ b/src/mapleall/maple_me/src/me_phase_manager.cpp @@ -197,6 +197,7 @@ MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEProfGen, profileGen) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEPlacementRC, placementrc) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEDse, dse) MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEABCOpt, abcopt) +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEReassoc, reassoc) MAPLE_TRANSFORM_PHASE_REGISTER(MEEmit, meemit) MAPLE_TRANSFORM_PHASE_REGISTER(EmitForIPA, emitforipa) } // namespace maple diff --git a/src/mapleall/maple_me/src/me_reassoc.cpp b/src/mapleall/maple_me/src/me_reassoc.cpp new file mode 100644 index 0000000000..2d8465d8af --- /dev/null +++ b/src/mapleall/maple_me/src/me_reassoc.cpp @@ -0,0 +1,384 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 v2 for more details. + */ +#include "me_phase_manager.h" +#include "me_reassoc.h" + +// This reassoc phase performs reassociation mainly for address expressions +// under iread/iassign. In the reassociation, the add/sub terms less likely to +// vary are separated from the parts likely to vary. This is done on a per loop// basis, and is applied only to expressions in innermost loops. For now, only +// IVs in loops are regarded as likely to vary. The goal is to result in more +// loop-invariant expressions after the reassociation. + +namespace maple { + +void MeReassoc::FindSelfIncDecs(MeStmt *stmt, std::unordered_set *selfIncDefs) { + if (stmt->GetOp() != OP_dassign && stmt->GetOp() != OP_regassign) { + return; + } + ScalarMeExpr *lhs = static_cast(stmt)->GetLHS(); + OriginalSt *ost = lhs->GetOst(); + if (!IsPrimitiveInteger(ost->GetType()->GetPrimType())) { + return; + } + MeExpr *rhs = static_cast(stmt)->GetRHS(); + if (rhs->GetOp() != OP_add && rhs->GetOp() != OP_sub) { + return; + } + MeExpr *opnd0 = rhs->GetOpnd(0); + if (opnd0->GetOp() != OP_dread && opnd0->GetOp() != OP_regread) { + return; + } + if (static_cast(opnd0)->GetOst() != ost) { + return; + } + MeExpr *opnd1 = rhs->GetOpnd(1); + if (opnd1->GetMeOp() != kMeOpConst) { + return; + } + selfIncDefs->insert(ost->GetIndex()); +} + +// Given an address expression, group the terms into ivPart containing the +// terms likely to vary frequently during execution, and nonIVPart containing +// the rest of the terms. Return the 2 parts in ReassociatedParts. +ReassociatedParts MeReassoc::ReassociateAddSub(MeExpr *x, std::unordered_set *selfIncDefs) { + switch (x->GetMeOp()) { + case kMeOpVar: + case kMeOpReg: { + ScalarMeExpr *scalar = static_cast(x); + if (selfIncDefs->count(scalar->GetOst()->GetIndex()) > 0) { + return ReassociatedParts(x, nullptr); + } + return ReassociatedParts(nullptr, x); + } + case kMeOpOp: { + OpMeExpr *opX = static_cast(x); + if (!IsPrimitiveInteger(opX->GetPrimType())) { + return ReassociatedParts(nullptr, x); + } + switch (opX->GetOp()) { + case OP_cvt: { + if (!IsPrimitiveInteger(opX->GetOpndType())) { + return ReassociatedParts(nullptr, x); + } + ReassociatedParts opndReassoc = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + if (opndReassoc.ivPart != nullptr) { + opndReassoc.ivPart = irMap->CreateMeExprTypeCvt(opX->GetPrimType(), opX->GetOpndType(), *opndReassoc.ivPart); + } + if (opndReassoc.nonIVPart != nullptr) { + opndReassoc.nonIVPart = irMap->CreateMeExprTypeCvt(opX->GetPrimType(), opX->GetOpndType(), *opndReassoc.nonIVPart); + } + return opndReassoc; + } + case OP_neg: { + ReassociatedParts opndReassoc = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + if (opndReassoc.ivPart != nullptr) { + opndReassoc.ivPartNegated = !opndReassoc.ivPartNegated; + } + if (opndReassoc.nonIVPart != nullptr) { + opndReassoc.nonIVPartNegated = !opndReassoc.nonIVPartNegated; + } + return opndReassoc; + } + case OP_mul: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + if (reassoc0.ivPart != nullptr || reassoc1.ivPart != nullptr) { + return ReassociatedParts(x, nullptr); + } + return ReassociatedParts(nullptr, x); + } + case OP_add: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + ReassociatedParts answer(nullptr, nullptr); + // set answer.ivPart + if (reassoc0.ivPart == nullptr) { + answer.ivPart = reassoc1.ivPart; + answer.ivPartNegated = reassoc1.ivPartNegated; + } else if (reassoc1.ivPart == nullptr) { + answer.ivPart = reassoc0.ivPart; + answer.ivPartNegated = reassoc0.ivPartNegated; + } else { + if (reassoc0.ivPartNegated == reassoc1.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = reassoc0.ivPartNegated; + } else if (!reassoc0.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + } else { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc1.ivPart, *reassoc0.ivPart); + } + } + // set answer.nonIVPart + if (reassoc0.nonIVPart == nullptr) { + answer.nonIVPart = reassoc1.nonIVPart; + answer.nonIVPartNegated = reassoc1.nonIVPartNegated; + } else if (reassoc1.nonIVPart == nullptr) { + answer.nonIVPart = reassoc0.nonIVPart; + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else { + if (reassoc0.nonIVPartNegated == reassoc1.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else if (!reassoc0.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + } else { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc1.nonIVPart, *reassoc0.nonIVPart); + } + } + return answer; + } + case OP_sub: { + ReassociatedParts reassoc0 = ReassociateAddSub(opX->GetOpnd(0), selfIncDefs); + ReassociatedParts reassoc1 = ReassociateAddSub(opX->GetOpnd(1), selfIncDefs); + ReassociatedParts answer(nullptr, nullptr); + // set answer.ivPart + if (reassoc0.ivPart == nullptr) { + answer.ivPart = reassoc1.ivPart; + if (answer.ivPart != nullptr) { + answer.ivPartNegated = !reassoc1.ivPartNegated; + } + } else if (reassoc1.ivPart == nullptr) { + answer.ivPart = reassoc0.ivPart; + answer.ivPartNegated = reassoc0.ivPartNegated; + } else { + if (reassoc0.ivPartNegated == reassoc1.ivPartNegated) { + answer.ivPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = reassoc0.ivPartNegated; + } else if (!reassoc0.ivPartNegated) { // reassoc1 must ivPartNegated + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + } else { // reassoc0.ivPartNegated and !reassoc1.ivPartNegated + answer.ivPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.ivPart, *reassoc1.ivPart); + answer.ivPartNegated = true; + } + } + // set answer.nonIVPart + if (reassoc0.nonIVPart == nullptr) { + answer.nonIVPart = reassoc1.nonIVPart; + if (answer.nonIVPart != nullptr) { + answer.nonIVPartNegated = !reassoc1.nonIVPartNegated; + } + } else if (reassoc1.nonIVPart == nullptr) { + answer.nonIVPart = reassoc0.nonIVPart; + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else { + if (reassoc0.nonIVPartNegated == reassoc1.nonIVPartNegated) { + answer.nonIVPart = irMap->CreateMeExprBinary(OP_sub, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = reassoc0.nonIVPartNegated; + } else if (!reassoc0.nonIVPartNegated) { // reassoc1 must nonIVPartNegated + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + } else { // reassoc0.nonIVPartNegated and !reassoc1.nonIVPartNegated + answer.nonIVPart = irMap->CreateMeExprBinary(OP_add, x->GetPrimType(), *reassoc0.nonIVPart, *reassoc1.nonIVPart); + answer.nonIVPartNegated = true; + } + } + return answer; + } + default: return ReassociatedParts(nullptr, x); + } + } + default: return ReassociatedParts(nullptr, x); + } +} + +// form and return the final reassociated expression +MeExpr *MeReassoc::FormReassociatedExpr(ReassociatedParts reassoc) { + if (reassoc.ivPart != nullptr ^ reassoc.nonIVPart != nullptr) { + CHECK_FATAL(!reassoc.ivPartNegated && !reassoc.nonIVPartNegated, + "SimplifyIvar: top level reassociated address expression must not be negated"); + // no re-association + if (reassoc.ivPart != nullptr) { + if (!reassoc.ivPartNegated) { + return reassoc.ivPart; + } + return irMap->CreateMeExprUnary(OP_neg, reassoc.ivPart->GetPrimType(), *reassoc.ivPart); + } + if (!reassoc.nonIVPartNegated) { + return reassoc.nonIVPart; + } + return irMap->CreateMeExprUnary(OP_neg, reassoc.nonIVPart->GetPrimType(), *reassoc.nonIVPart); + } + CHECK_FATAL(!(reassoc.ivPart->HasAddressValue() && reassoc.nonIVPart->HasAddressValue()), + "SimplifyIvar: Conflicting settings of HasAddressValue() in reassociated operands"); + if (reassoc.ivPart->HasAddressValue()) { + CHECK_FATAL(!reassoc.ivPartNegated, "SimplifyIvar: cannot negate an address value"); + Opcode opToUse = reassoc.nonIVPartNegated ? OP_sub : OP_add; + OpMeExpr opMeExpr(kInvalidExprID, opToUse, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.ivPart); + opMeExpr.SetOpnd(1, reassoc.nonIVPart); + MeExpr *finalMeExpr = irMap->HashMeExpr(opMeExpr); + static_cast(finalMeExpr)->hasAddressValue = true; + return finalMeExpr; + } else if (reassoc.nonIVPart->HasAddressValue()) { + CHECK_FATAL(!reassoc.nonIVPartNegated, "SimplifyIvar: cannot negate an address value"); + Opcode opToUse = reassoc.ivPartNegated ? OP_sub : OP_add; + OpMeExpr opMeExpr(kInvalidExprID, opToUse, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.nonIVPart); + opMeExpr.SetOpnd(1, reassoc.ivPart); + MeExpr *finalMeExpr = irMap->HashMeExpr(opMeExpr); + static_cast(finalMeExpr)->hasAddressValue = true; + return finalMeExpr; + } else { // not sure which part has address value + CHECK_FATAL(!(reassoc.ivPartNegated && reassoc.nonIVPartNegated), "SimplifyIvar: negative address expression cannot be negated"); + if (reassoc.nonIVPartNegated) { + OpMeExpr opMeExpr(kInvalidExprID, OP_sub, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.ivPart); + opMeExpr.SetOpnd(1, reassoc.nonIVPart); + return irMap->HashMeExpr(opMeExpr); + } else { + OpMeExpr opMeExpr(kInvalidExprID, reassoc.ivPartNegated ? OP_sub : OP_add, PTY_u64, 2); + opMeExpr.SetOpnd(0, reassoc.nonIVPart); + opMeExpr.SetOpnd(1, reassoc.ivPart); + return irMap->HashMeExpr(opMeExpr); + } + } +} + +// Descend the expression tree to find reassociation candidates. "changed" is +// for indicating back to caller whether expression has been changed. Any +// change can be due to reassociation or due to rehash on the way back up. +MeExpr *MeReassoc::ApplyReassocExpr(MeExpr *x, std::unordered_set *selfIncDefs, bool *changed) { + switch (x->GetMeOp()) { + case kMeOpOp: { + bool isChanged = false; + OpMeExpr *opX = static_cast(x); + OpMeExpr newX(*opX, kInvalidExprID); + for (uint32 i = 0; i < x->GetNumOpnds(); ++i) { + newX.SetOpnd(i, ApplyReassocExpr(x->GetOpnd(i), selfIncDefs, &isChanged)); + } + if (isChanged) { + *changed = true; + x = irMap->HashMeExpr(newX); + } + if (!static_cast(x)->canApplyReassoc) { + return x; + } + // perform reassociation for this reassociation candidate + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Reassociating "; + x->Dump(irMap,0); + mirModule->GetOut() << std::endl; + } + ReassociatedParts reassoc = ReassociateAddSub(x, selfIncDefs); + if (reassoc.ivPart != nullptr ^ reassoc.nonIVPart != nullptr) { + CHECK_FATAL(!reassoc.ivPartNegated && !reassoc.nonIVPartNegated, + "ApplyReassocExpr: top level reassociated address expression must not be negated"); + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Unchanged" << std::endl; + } + return x; // not reassociated + } + MeExpr *reassociatedX = FormReassociatedExpr(reassoc); + if (reassociatedX != x) { + *changed = true; + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "changing it to "; + reassociatedX->Dump(irMap,0); + mirModule->GetOut() << std::endl; + } + } else { + if (DEBUGFUNC_NEWPM(*func)) { + mirModule->GetOut() << "Unchanged" << std::endl; + } + } + return reassociatedX; + } + case kMeOpNary: { + bool isChanged = false; + NaryMeExpr *naryX = static_cast(x); + NaryMeExpr newNary(&irMap->GetIRMapAlloc(), kInvalidExprID, *naryX); + for (uint32 i = 0; i < x->GetNumOpnds(); ++i) { + newNary.SetOpnd(i, ApplyReassocExpr(x->GetOpnd(i), selfIncDefs, &isChanged)); + } + if (isChanged) { + *changed = true; + return irMap->HashMeExpr(newNary); + } + return x; + } + case kMeOpIvar: { + bool isChanged = false; + IvarMeExpr *ivarX = static_cast(x); + IvarMeExpr newIvar(kInvalidExprID, *ivarX); + newIvar.SetBase(ApplyReassocExpr(ivarX->GetBase(), selfIncDefs, &isChanged)); + if (isChanged) { + *changed = true; + return irMap->HashMeExpr(newIvar); + } + return x; + } + default: return x; + } +} + +// apply reassociation to all the expressions in this innermost loop +void MeReassoc::ProcessLoop(LoopDesc *aloop) { + std::unordered_set selfIncDefSyms; // symbols with self increment/decrement + // first pass over loop BBs to set selfIncDefSyms + for (BBId bbId : aloop->loopBBs) { + BB *bb = cfg->GetBBFromID(bbId); + for (MeStmt &stmt : bb->GetMeStmts()) { + FindSelfIncDecs(&stmt, &selfIncDefSyms); + } + } + // final pass: reassociate only expressions marked canApplyReassoc + for (BBId bbId : aloop->loopBBs) { + BB *bb = cfg->GetBBFromID(bbId); + for (MeStmt &stmt : bb->GetMeStmts()) { + for (uint32 i = 0; i < stmt.NumMeStmtOpnds(); i++) { + bool changed = false; + MeExpr *newOpnd = ApplyReassocExpr(stmt.GetOpnd(i), &selfIncDefSyms, &changed); + if (changed) { + stmt.SetOpnd(i, newOpnd); + } + } + } + } +} + +bool MEReassoc::PhaseRun(maple::MeFunction &f) { + IRMap *irMap = GET_ANALYSIS(MEIRMapBuild, f); + ASSERT(irMap != nullptr, "irMap phase has problem"); + IdentifyLoops *identLoops = GET_ANALYSIS(MELoopAnalysis, f); + CHECK_NULL_FATAL(identLoops); + MeReassoc reassoc(&f, irMap); + + // go thru all the loops to find innermost loops; do in reverse order so + // innermost loops are visited first + uint32 lastNestDepth = 0; + for (int32 i = identLoops->GetMeLoops().size()-1; i >= 0; i--) { + LoopDesc *aloop = identLoops->GetMeLoops()[i]; + if (aloop->nestDepth < lastNestDepth) { // not innermost + lastNestDepth = aloop->nestDepth; + continue; + } + reassoc.ProcessLoop(aloop); + lastNestDepth = aloop->nestDepth; + } + + if (DEBUGFUNC_NEWPM(f)) { + LogInfo::MapleLogger() << "\n============== after REASSOC =============" << '\n'; + f.Dump(false); + } + + return true; +} + +void MEReassoc::GetAnalysisDependence(AnalysisDep &aDep) const { + aDep.AddRequired(); + aDep.AddRequired(); + aDep.SetPreservedAll(); +} +} // namespace maple diff --git a/src/mapleall/maple_phase/include/phases.def b/src/mapleall/maple_phase/include/phases.def index 9735c3e36b..071c9b7af9 100644 --- a/src/mapleall/maple_phase/include/phases.def +++ b/src/mapleall/maple_phase/include/phases.def @@ -56,6 +56,7 @@ ADDMAPLEMEPHASE("hprop", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("hdse", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("may2dassign", JAVALANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("condbasednpc", JAVALANG && MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("reassoc", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("epre", MeOption::optLevel >= 2) ADDMAPLEMEPHASE("stmtpre", JAVALANG && MeOption::optLevel >= 2) ADDMAPLEMEPHASE("analyzerc", MeOption::optLevel != 0 && JAVALANG && !MeOption::noRC && !MeOption::gcOnly) -- Gitee From 3d6e47c6cb1e39b60c53aae34531f940bd594619 Mon Sep 17 00:00:00 2001 From: Fred Chow Date: Wed, 27 Oct 2021 19:33:11 -0700 Subject: [PATCH 5/5] Rebased to master and fixed conflicts --- src/mapleall/maple_me/BUILD.gn | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index afba268a17..7d6abffa87 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -106,9 +106,8 @@ src_libmplme = [ "src/simplifyCFG.cpp", "src/seqvec.cpp", "src/me_autovec.cpp", - "src/me_safety_warning.cpp" - "src/me_reassoc.cpp", - "src/safety_warning.cpp" + "src/me_safety_warning.cpp", + "src/me_reassoc.cpp" ] src_libmplmewpo = [ -- Gitee