diff --git a/src/bin/maple b/src/bin/maple index d0a8417ee7b654267946bdcb730170f80842ffd9..e15a3bd8a7fef98693724af08bea949c10db5ebc 100755 Binary files a/src/bin/maple and b/src/bin/maple differ diff --git a/src/maple_me/include/dse.h b/src/maple_me/include/dse.h index 959f77f78223bb92b03c85477fa7554a8a18a478..36f823d8c6afb25b6b8b9fd7c297494369ece9b6 100644 --- a/src/maple_me/include/dse.h +++ b/src/maple_me/include/dse.h @@ -108,6 +108,11 @@ class DSE { bool HasNonDeletableExpr(const StmtNode &stmt) const; bool StmtMustRequired(const StmtNode &stmt, const BB &bb) const; void DumpStmt(const StmtNode &stmt, const std::string &msg) const; + void CollectNotNullNode(StmtNode &stmt, BB &bb); + // NotNullNode means it is impossible value of the node is nullptr after go through this stmt. + // nodeType must be one kind of kNodeTypeNormal、kNodeTypeIvar、kNodeTypeNotNull + void CollectNotNullNode(StmtNode &stmt, BaseNode &node, BB &bb, uint8 nodeType = 0); + bool NeedNotNullCheck(BaseNode &node, const BB &bb); std::vector bbVec; BB &commonEntryBB; @@ -117,7 +122,16 @@ class DSE { std::vector bbRequired; std::vector exprRequired; std::forward_list> workList{}; + std::unordered_map> stmt2NotNullExpr; + std::unordered_map>> notNullExpr2Stmt; bool cfgUpdated = false; + // Initial type of all nodes + static const uint8 kNodeTypeNormal = 0; + // IreadNode + static const uint8 kNodeTypeIvar = 1; + // NPE will be throw if the value of this node is nullptr when stmt is executed + // Or the node is opnd of a same type node + static const uint8 kNodeTypeNotNull = 2; }; } // namespace maple #endif // MAPLE_ME_INCLUDE_DSE_H diff --git a/src/maple_me/include/hdse.h b/src/maple_me/include/hdse.h index 22d8701efd2385e93d04af10ae61ab5f79940928..293cd9ecb66333468bdf1b48633dcf1c6f7946b0 100644 --- a/src/maple_me/include/hdse.h +++ b/src/maple_me/include/hdse.h @@ -65,6 +65,11 @@ class HDSE { void MarkLastUnconditionalGotoInPredBBRequired(const BB &bb); void MarkVarDefByStmt(VarMeExpr &varMeExpr); void MarkRegDefByStmt(RegMeExpr ®MeExpr); + void CollectNotNullExpr(MeStmt &stmt); + // NotNullExpr means it is impossible value of the expr is nullptr after go through this stmt. + // exprType must be one kind of NODE_TYPE_NORMAL、NODE_TYPE_IVAR、NODE_TYPE_NOTNULL + void CollectNotNullExpr(MeStmt &stmt, MeExpr &meExpr, uint8 exprType = 0); + bool NeedNotNullCheck(MeExpr &meExpr, const BB &bb); bool IsExprNeeded(const MeExpr &meExpr) const { return exprLive.at(meExpr.GetExprID()); @@ -100,6 +105,15 @@ class HDSE { std::vector bbRequired; std::vector exprLive; std::forward_list workList; + std::unordered_map> stmt2NotNullExpr; + std::unordered_map> notNullExpr2Stmt; + // Initial type of all meExpr + static const uint8 kExprTypeNormal = 0; + // IreadMeExpr + static const uint8 kExprTypeIvar = 1; + // NPE will be throw if the value of this meExpr is nullptr when stmt is executed + // Or the meExpr is opnd of a same type meExpr + static const uint8 kExprTypeNotNull = 2; }; } // namespace maple #endif // MAPLE_ME_INCLUDE_HDSE_H diff --git a/src/maple_me/src/dse.cpp b/src/maple_me/src/dse.cpp index 7f3ac83fde28acb86756c1b0a0e16b20cc179616..e4ef3f0813abc357dfbd29acc0f45fd061282476 100644 --- a/src/maple_me/src/dse.cpp +++ b/src/maple_me/src/dse.cpp @@ -19,6 +19,7 @@ #include "opcode_info.h" #include "mir_function.h" #include "utils.h" +#include "mir_builder.h" // This phase do dead store elimination. This optimization is done on SSA // version basis. @@ -179,6 +180,18 @@ void DSE::RemoveNotRequiredStmtsInBB(BB &bb) { if (!IsStmtRequired(stmt)) { DumpStmt(stmt, "**** DSE1 deleting: "); OnRemoveBranchStmt(bb, stmt); + // A iread node contained in stmt or iass stmt + if (stmt2NotNullExpr.find(&stmt) != stmt2NotNullExpr.end()) { + for (BaseNode *node : stmt2NotNullExpr.at(&stmt)) { + if (NeedNotNullCheck(*node, bb)) { + MIRModule &mod = ssaTab.GetModule(); + UnaryStmtNode *nullCheck = mod.GetMIRBuilder()->CreateStmtUnary(OP_assertnonnull, node); + bb.InsertStmtBefore(&stmt, nullCheck); + nullCheck->SetIsLive(true); + notNullExpr2Stmt[node].push_back(std::make_pair(nullCheck, &bb)); + } + } + } bb.RemoveStmtNode(&stmt); continue; } @@ -187,6 +200,21 @@ void DSE::RemoveNotRequiredStmtsInBB(BB &bb) { } } +// If a ivar's base not used as not null, should insert a not null stmt +// Only make sure throw NPE in same BB +// If must make sure throw at first stmt, much more not null stmt will be inserted +bool DSE::NeedNotNullCheck(BaseNode &node, const BB &bb) { + for (auto item : notNullExpr2Stmt[&node]) { + if (!IsStmtRequired(*(item.first))) { + continue; + } + if (postDom.Dominate(*(item.second), bb)) { + return false; + } + } + return true; +} + void DSE::PropagateUseLive(const VersionSt &vst) { if (IsSymbolLived(vst)) { return; @@ -349,10 +377,87 @@ void DSE::MarkSpecialStmtRequired() { continue; } for (auto itStmt = bb->GetStmtNodes().rbegin(); itStmt != bb->GetStmtNodes().rend(); ++itStmt) { - if (StmtMustRequired(*itStmt, *bb)) { - MarkStmtRequired(*itStmt, *bb); + StmtNode &stmt = *itStmt; + if (StmtMustRequired(stmt, *bb)) { + MarkStmtRequired(stmt, *bb); + } + CollectNotNullNode(stmt, *bb); + } + } +} + +// Find all stmt contains ivar and save to stmt2NotNullExpr +// Find all not null expr used as ivar's base、OP_array's or OP_assertnonnull's opnd +// And save to notNullExpr2Stmt +void DSE::CollectNotNullNode(StmtNode &stmt, BB &bb) { + uint8 opndNum = stmt.NumOpnds(); + uint8 nodeType = kNodeTypeNormal; + for (uint8 i = 0; i < opndNum; ++i) { + BaseNode *opnd = stmt.Opnd(i); + if (i == 0 && instance_of(stmt)) { + // A non-static call's first opnd is this, should be not null + CallNode &call = static_cast(stmt); + if (!GlobalTables::GetFunctionTable().GetFunctionFromPuidx(call.GetPUIdx())->IsStatic()) { + nodeType = kNodeTypeNotNull; + } + } else if (i == 0 && stmt.GetOpCode() == OP_iassign) { + // A iass stmt, mark and save + BaseNode &base = static_cast(stmt).GetAddrExprBase(); + stmt2NotNullExpr[&stmt].push_back(&base); + MarkSingleUseLive(base); + notNullExpr2Stmt[&base].push_back(std::make_pair(&stmt, &bb)); + nodeType = kNodeTypeIvar; + } else { + // A normal opnd not sure + Opcode opndOp = opnd->GetOpCode(); + if (opndOp == OP_dread || opndOp == OP_regread) { continue; } + nodeType = kNodeTypeNormal; + } + CollectNotNullNode(stmt, ToRef(opnd), bb, nodeType); + } +} + +void DSE::CollectNotNullNode(StmtNode &stmt, BaseNode &node, BB &bb, uint8 nodeType) { + Opcode op = node.GetOpCode(); + switch (op) { + case OP_dread: + case OP_regread: + case OP_constval: { + // Ref expr used in ivar、array or assertnotnull + PrimType type = node.GetPrimType(); + if (nodeType != kNodeTypeNormal && (type == PTY_ref || type == PTY_ptr)) { + notNullExpr2Stmt[&node].push_back(std::make_pair(&stmt, &bb)); + } + break; + } + case OP_iread: { + BaseNode &base = static_cast(node).GetAddrExprBase(); + if (nodeType != kNodeTypeIvar) { + stmt2NotNullExpr[&stmt].push_back(&base); + MarkSingleUseLive(base); + } + notNullExpr2Stmt[&base].push_back(std::make_pair(&stmt, &bb)); + CollectNotNullNode(stmt, base, bb, kNodeTypeIvar); + break; + } + default: { + if (nodeType != kNodeTypeNormal) { + // Ref expr used in ivar、array or assertnotnull + PrimType type = node.GetPrimType(); + if (type == PTY_ref || type == PTY_ptr) { + notNullExpr2Stmt[&node].push_back(std::make_pair(&stmt, &bb)); + } + } else { + // Ref expr used array or assertnotnull + bool notNull = op == OP_array || op == OP_assertnonnull; + nodeType = notNull ? kNodeTypeNotNull : kNodeTypeNormal; + } + for (size_t i = 0; i < node.GetNumOpnds(); ++i) { + CollectNotNullNode(stmt, ToRef(node.Opnd(i)), bb, nodeType); + } + break; } } } diff --git a/src/maple_me/src/hdse.cpp b/src/maple_me/src/hdse.cpp index 580ae0ce47372d42d644f79a6461fa5a0a45dbeb..dd89a0c6166349356f4c2caa1ed3e2b721ec89a2 100644 --- a/src/maple_me/src/hdse.cpp +++ b/src/maple_me/src/hdse.cpp @@ -51,11 +51,40 @@ void HDSE::RemoveNotRequiredStmtsInBB(BB &bb) { } bb.SetKind(kBBFallthru); } + // A ivar contained in stmt + if (stmt2NotNullExpr.find(&meStmt) != stmt2NotNullExpr.end()) { + for (MeExpr *meExpr : stmt2NotNullExpr.at(&meStmt)) { + if (NeedNotNullCheck(*meExpr, bb)) { + UnaryMeStmt *nullCheck = irMap.New(OP_assertnonnull); + nullCheck->SetBB(&bb); + nullCheck->SetSrcPos(meStmt.GetSrcPosition()); + nullCheck->SetMeStmtOpndValue(meExpr); + bb.InsertMeStmtBefore(&meStmt, nullCheck); + nullCheck->SetIsLive(true); + notNullExpr2Stmt[meExpr].push_back(nullCheck); + } + } + } bb.RemoveMeStmt(&meStmt); } } } +// If a ivar's base not used as not null, should insert a not null stmt +// Only make sure throw NPE in same BB +// If must make sure throw at first stmt, much more not null stmt will be inserted +bool HDSE::NeedNotNullCheck(MeExpr &meExpr, const BB &bb) { + for (MeStmt *stmt : notNullExpr2Stmt[&meExpr]) { + if (!stmt->GetIsLive()) { + continue; + } + if (postDom.Dominate(*(stmt->GetBB()), bb)) { + return false; + } + } + return true; +} + void HDSE::MarkMuListRequired(MapleMap &muList) { for (auto &pair : muList) { workList.push_front(pair.second); @@ -157,6 +186,74 @@ void HDSE::MarkRegDefByStmt(RegMeExpr ®MeExpr) { } } +// Find all stmt contains ivar and save to stmt2NotNullExpr +// Find all not null expr used as ivar's base、OP_array's or OP_assertnonnull's opnd +// And save to notNullExpr2Stmt +void HDSE::CollectNotNullExpr(MeStmt &stmt) { + size_t opndNum = stmt.NumMeStmtOpnds(); + uint8 exprType = kExprTypeNormal; + for (size_t i = 0; i < opndNum; ++i) { + MeExpr *opnd = stmt.GetOpnd(i); + if (i == 0 && instance_of(stmt)) { + // A non-static call's first opnd is this, should be not null + CallMeStmt &callStmt = static_cast(stmt); + exprType = callStmt.GetTargetFunction().IsStatic() ? kExprTypeNormal : kExprTypeNotNull; + } else { + // A normal opnd not sure + MeExprOp meOp = opnd->GetMeOp(); + if (meOp == kMeOpVar || meOp == kMeOpReg) { + continue; + } + exprType = kExprTypeNormal; + } + CollectNotNullExpr(stmt, ToRef(opnd), exprType); + } +} + +void HDSE::CollectNotNullExpr(MeStmt &stmt, MeExpr &meExpr, uint8 exprType) { + MeExprOp meOp = meExpr.GetMeOp(); + switch (meOp) { + case kMeOpVar: + case kMeOpReg: + case kMeOpConst: { + PrimType type = meExpr.GetPrimType(); + // Ref expr used in ivar、array or assertnotnull + if (exprType != kExprTypeNormal && (type == PTY_ref || type == PTY_ptr)) { + notNullExpr2Stmt[&meExpr].push_back(&stmt); + } + break; + } + case kMeOpIvar: { + MeExpr *base = static_cast(meExpr).GetBase(); + if (exprType != kExprTypeIvar) { + stmt2NotNullExpr[&stmt].push_back(base); + MarkSingleUseLive(meExpr); + } + notNullExpr2Stmt[base].push_back(&stmt); + CollectNotNullExpr(stmt, ToRef(base), kExprTypeIvar); + break; + } + default: { + if (exprType != kExprTypeNormal) { + // Ref expr used in ivar、array or assertnotnull + PrimType type = meExpr.GetPrimType(); + if (type == PTY_ref || type == PTY_ptr) { + notNullExpr2Stmt[&meExpr].push_back(&stmt); + } + } else { + // Ref expr used array or assertnotnull + Opcode op = meExpr.GetOp(); + bool notNull = op == OP_array || op == OP_assertnonnull; + exprType = notNull ? kExprTypeNotNull : kExprTypeNormal; + } + for (size_t i = 0; i < meExpr.GetNumOpnds(); ++i) { + CollectNotNullExpr(stmt, ToRef(meExpr.GetOpnd(i)), exprType); + } + break; + } + } +} + void HDSE::PropagateUseLive(MeExpr &meExpr) { switch (meExpr.GetMeOp()) { case kMeOpVar: { @@ -399,6 +496,7 @@ void HDSE::MarkSpecialStmtRequired() { auto &meStmtNodes = bb->GetMeStmts(); for (auto itStmt = meStmtNodes.rbegin(); itStmt != meStmtNodes.rend(); ++itStmt) { MeStmt *pStmt = to_ptr(itStmt); + CollectNotNullExpr(*pStmt); if (pStmt->GetIsLive()) { continue; }