mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 11:38:20 +00:00
confluence fix for inlining
This commit is contained in:
parent
24bbc024c1
commit
71364bd112
6 changed files with 68 additions and 16 deletions
11
src/Stmt.h
11
src/Stmt.h
|
@ -122,6 +122,7 @@ public:
|
||||||
StmtPtr DoReduce(Reducer* c) override;
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
bool NoFlowAfter(bool ignore_break) const override;
|
bool NoFlowAfter(bool ignore_break) const override;
|
||||||
|
bool CouldReturn(bool ignore_break) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) override;
|
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) override;
|
||||||
|
@ -182,6 +183,7 @@ public:
|
||||||
StmtPtr DoReduce(Reducer* c) override;
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
bool NoFlowAfter(bool ignore_break) const override;
|
bool NoFlowAfter(bool ignore_break) const override;
|
||||||
|
bool CouldReturn(bool ignore_break) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class ZAMCompiler;
|
friend class ZAMCompiler;
|
||||||
|
@ -301,6 +303,8 @@ public:
|
||||||
|
|
||||||
// Note, no need for a NoFlowAfter method because the loop might
|
// Note, no need for a NoFlowAfter method because the loop might
|
||||||
// execute zero times, so it's always the default of "false".
|
// execute zero times, so it's always the default of "false".
|
||||||
|
// However, we do need to check for potential returns.
|
||||||
|
bool CouldReturn(bool ignore_break) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) override;
|
||||||
|
@ -350,6 +354,8 @@ public:
|
||||||
|
|
||||||
// Note, no need for a NoFlowAfter method because the loop might
|
// Note, no need for a NoFlowAfter method because the loop might
|
||||||
// execute zero times, so it's always the default of "false".
|
// execute zero times, so it's always the default of "false".
|
||||||
|
// However, we do need to check for potential returns.
|
||||||
|
bool CouldReturn(bool ignore_break) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) override;
|
ValPtr DoExec(Frame* f, Val* v, StmtFlowType& flow) override;
|
||||||
|
@ -395,6 +401,7 @@ public:
|
||||||
StmtPtr Duplicate() override { return SetSucc(new BreakStmt()); }
|
StmtPtr Duplicate() override { return SetSucc(new BreakStmt()); }
|
||||||
|
|
||||||
bool NoFlowAfter(bool ignore_break) const override { return ! ignore_break; }
|
bool NoFlowAfter(bool ignore_break) const override { return ! ignore_break; }
|
||||||
|
bool CouldReturn(bool ignore_break) const override { return ! ignore_break; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
@ -436,6 +443,7 @@ public:
|
||||||
StmtPtr DoReduce(Reducer* c) override;
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
bool NoFlowAfter(bool ignore_break) const override { return true; }
|
bool NoFlowAfter(bool ignore_break) const override { return true; }
|
||||||
|
bool CouldReturn(bool ignore_break) const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class StmtList : public Stmt {
|
class StmtList : public Stmt {
|
||||||
|
@ -460,6 +468,7 @@ public:
|
||||||
StmtPtr DoReduce(Reducer* c) override;
|
StmtPtr DoReduce(Reducer* c) override;
|
||||||
|
|
||||||
bool NoFlowAfter(bool ignore_break) const override;
|
bool NoFlowAfter(bool ignore_break) const override;
|
||||||
|
bool CouldReturn(bool ignore_break) const override;
|
||||||
|
|
||||||
// Idioms commonly used in reduction.
|
// Idioms commonly used in reduction.
|
||||||
StmtList(StmtPtr s1, StmtPtr s2);
|
StmtList(StmtPtr s1, StmtPtr s2);
|
||||||
|
@ -725,7 +734,7 @@ public:
|
||||||
|
|
||||||
// Note, no need for a NoFlowAfter() method because anything that
|
// Note, no need for a NoFlowAfter() method because anything that
|
||||||
// has "NoFlowAfter" inside the body still gets caught and we
|
// has "NoFlowAfter" inside the body still gets caught and we
|
||||||
// continue afterwards.
|
// continue afterwards. Same goes for CouldReturn().
|
||||||
|
|
||||||
StmtPtr Duplicate() override;
|
StmtPtr Duplicate() override;
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,12 @@ public:
|
||||||
// in that case, they do lead to flow reaching the end.
|
// in that case, they do lead to flow reaching the end.
|
||||||
virtual bool NoFlowAfter(bool ignore_break) const { return false; }
|
virtual bool NoFlowAfter(bool ignore_break) const { return false; }
|
||||||
|
|
||||||
|
// True if the statement could potentially execute a return. This is
|
||||||
|
// used by script optimization to track confluence inside catch-return
|
||||||
|
// blocks. Here, ignore_break is false if we're analyzing a coalesced
|
||||||
|
// hook body.
|
||||||
|
virtual bool CouldReturn(bool ignore_break) const { return false; }
|
||||||
|
|
||||||
// Access to the original statement from which this one is derived,
|
// Access to the original statement from which this one is derived,
|
||||||
// or this one if we don't have an original. Returns a bare pointer
|
// or this one if we don't have an original. Returns a bare pointer
|
||||||
// rather than a StmtPtr to emphasize that the access is read-only.
|
// rather than a StmtPtr to emphasize that the access is read-only.
|
||||||
|
|
|
@ -62,17 +62,31 @@ TraversalCode GenIDDefs::PreStmt(const Stmt* s) {
|
||||||
auto block = cr->Block();
|
auto block = cr->Block();
|
||||||
|
|
||||||
cr_active.push_back(confluence_blocks.size());
|
cr_active.push_back(confluence_blocks.size());
|
||||||
cr_return_seen.push_back(false);
|
|
||||||
|
bool did_confluence = false;
|
||||||
|
|
||||||
|
if ( block->Tag() == STMT_LIST )
|
||||||
|
{
|
||||||
|
auto prev_stmt = s;
|
||||||
|
auto& stmts = block->AsStmtList()->Stmts();
|
||||||
|
for ( auto& st : stmts )
|
||||||
|
{
|
||||||
|
if ( ! did_confluence && st->CouldReturn(false) )
|
||||||
|
{
|
||||||
|
StartConfluenceBlock(prev_stmt);
|
||||||
|
did_confluence = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->Traverse(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
block->Traverse(this);
|
block->Traverse(this);
|
||||||
|
|
||||||
if ( cr_return_seen.back() )
|
if ( did_confluence )
|
||||||
// We encountered a return along the way. curr_stmt is
|
EndConfluenceBlock();
|
||||||
// now set to the last statement in the block, so mark
|
|
||||||
// it with a return.
|
|
||||||
ReturnAt(curr_stmt);
|
|
||||||
|
|
||||||
cr_active.pop_back();
|
cr_active.pop_back();
|
||||||
cr_return_seen.pop_back();
|
|
||||||
|
|
||||||
auto retvar = cr->RetVar();
|
auto retvar = cr->RetVar();
|
||||||
if ( retvar )
|
if ( retvar )
|
||||||
|
@ -445,11 +459,9 @@ void GenIDDefs::ReturnAt(const Stmt* s) {
|
||||||
// If we're right at a catch-return then we don't want to make the
|
// If we're right at a catch-return then we don't want to make the
|
||||||
// identifier as encountering a scope-ending "return" here. By avoiding
|
// identifier as encountering a scope-ending "return" here. By avoiding
|
||||||
// that, we're able to do optimization across catch-return blocks.
|
// that, we're able to do optimization across catch-return blocks.
|
||||||
if ( cr_active.empty() || cr_active.back() != confluence_blocks.size() || cr_return_seen.back() )
|
if ( cr_active.empty() || cr_active.back() != confluence_blocks.size() )
|
||||||
for ( auto id : modified_IDs.back() )
|
for ( auto id : modified_IDs.back() )
|
||||||
id->GetOptInfo()->ReturnAt(s);
|
id->GetOptInfo()->ReturnAt(s);
|
||||||
if ( ! cr_active.empty() )
|
|
||||||
cr_return_seen.back() = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenIDDefs::TrackID(const ID* id, const ExprPtr& e) {
|
void GenIDDefs::TrackID(const ID* id, const ExprPtr& e) {
|
||||||
|
|
|
@ -99,9 +99,6 @@ private:
|
||||||
// (new) confluence blocks.
|
// (new) confluence blocks.
|
||||||
std::vector<zeek_uint_t> cr_active;
|
std::vector<zeek_uint_t> cr_active;
|
||||||
|
|
||||||
// Parallel array that tracks whether a return has occurred.
|
|
||||||
std::vector<zeek_uint_t> cr_return_seen;
|
|
||||||
|
|
||||||
// The following is parallel to confluence_blocks except
|
// The following is parallel to confluence_blocks except
|
||||||
// the front entry tracks identifiers at the outermost
|
// the front entry tracks identifiers at the outermost
|
||||||
// (non-confluence) scope. Thus, to index it for a given
|
// (non-confluence) scope. Thus, to index it for a given
|
||||||
|
|
|
@ -273,6 +273,10 @@ bool IfStmt::NoFlowAfter(bool ignore_break) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IfStmt::CouldReturn(bool ignore_break) const {
|
||||||
|
return (s1 && s1->CouldReturn(ignore_break)) || (s2 && s2->CouldReturn(ignore_break));
|
||||||
|
}
|
||||||
|
|
||||||
IntrusivePtr<Case> Case::Duplicate() {
|
IntrusivePtr<Case> Case::Duplicate() {
|
||||||
if ( expr_cases ) {
|
if ( expr_cases ) {
|
||||||
auto new_exprs = expr_cases->Duplicate()->AsListExprPtr();
|
auto new_exprs = expr_cases->Duplicate()->AsListExprPtr();
|
||||||
|
@ -404,6 +408,14 @@ bool SwitchStmt::NoFlowAfter(bool ignore_break) const {
|
||||||
return default_seen_with_no_flow_after;
|
return default_seen_with_no_flow_after;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SwitchStmt::CouldReturn(bool ignore_break) const {
|
||||||
|
for ( const auto& c : *Cases() )
|
||||||
|
if ( c->Body()->CouldReturn(true) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool AddDelStmt::IsReduced(Reducer* c) const { return e->HasReducedOps(c); }
|
bool AddDelStmt::IsReduced(Reducer* c) const { return e->HasReducedOps(c); }
|
||||||
|
|
||||||
StmtPtr AddDelStmt::DoReduce(Reducer* c) {
|
StmtPtr AddDelStmt::DoReduce(Reducer* c) {
|
||||||
|
@ -499,6 +511,10 @@ StmtPtr WhileStmt::DoReduce(Reducer* c) {
|
||||||
return ThisPtr();
|
return ThisPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WhileStmt::CouldReturn(bool ignore_break) const {
|
||||||
|
return body->CouldReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
StmtPtr ForStmt::Duplicate() {
|
StmtPtr ForStmt::Duplicate() {
|
||||||
auto expr_copy = e->Duplicate();
|
auto expr_copy = e->Duplicate();
|
||||||
|
|
||||||
|
@ -568,6 +584,10 @@ StmtPtr ForStmt::DoReduce(Reducer* c) {
|
||||||
return ThisPtr();
|
return ThisPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ForStmt::CouldReturn(bool ignore_break) const {
|
||||||
|
return body->CouldReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
StmtPtr ReturnStmt::Duplicate() { return SetSucc(new ReturnStmt(e ? e->Duplicate() : nullptr, true)); }
|
StmtPtr ReturnStmt::Duplicate() { return SetSucc(new ReturnStmt(e ? e->Duplicate() : nullptr, true)); }
|
||||||
|
|
||||||
ReturnStmt::ReturnStmt(ExprPtr arg_e, bool ignored) : ExprStmt(STMT_RETURN, std::move(arg_e)) {}
|
ReturnStmt::ReturnStmt(ExprPtr arg_e, bool ignored) : ExprStmt(STMT_RETURN, std::move(arg_e)) {}
|
||||||
|
@ -784,6 +804,14 @@ bool StmtList::NoFlowAfter(bool ignore_break) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StmtList::CouldReturn(bool ignore_break) const {
|
||||||
|
for ( auto& s : stmts )
|
||||||
|
if ( s->CouldReturn(ignore_break) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
StmtPtr InitStmt::Duplicate() {
|
StmtPtr InitStmt::Duplicate() {
|
||||||
// Need to duplicate the initializer list since later reductions
|
// Need to duplicate the initializer list since later reductions
|
||||||
// can modify it in place.
|
// can modify it in place.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue