add tracking of control flow information

This commit is contained in:
Vern Paxson 2024-08-05 17:59:50 +01:00 committed by Arne Welzel
parent e94764982d
commit a1185ee6bb
6 changed files with 144 additions and 24 deletions

View file

@ -962,17 +962,76 @@ void ZAMCompiler::KillInst(zeek_uint_t i) {
} }
} }
if ( num_labels == 0 ) ZInstI* succ = nullptr;
// No labels to propagate.
return;
if ( num_labels > 0 ) {
for ( auto j = i + 1; j < insts1.size(); ++j ) { for ( auto j = i + 1; j < insts1.size(); ++j ) {
auto succ = insts1[j]; if ( insts1[j]->live ) {
if ( succ->live ) { succ = insts1[j];
succ->num_labels += num_labels;
break; break;
} }
} }
if ( succ )
succ->num_labels += num_labels;
}
// Look into propagating control flow info.
if ( inst->aux && ! inst->aux->cft.empty() ) {
auto& cft = inst->aux->cft;
if ( cft.count(CFT_ELSE) > 0 ) {
// Push forward unless this was the end of the block.
if ( cft.count(CFT_BLOCK_END) == 0 ) {
ASSERT(succ);
AddCFT(succ, CFT_ELSE);
}
else
// But if it *was* the end of the block, remove that block.
--cft[CFT_BLOCK_END];
}
if ( cft.count(CFT_BREAK) > 0 ) {
// ### Factor this with the following
// Propagate breaks backwards.
int j = i;
while ( --j >= 0 )
if ( insts1[j]->live )
break;
ASSERT(j >= 0);
// Make sure the CFT entry is created.
AddCFT(insts1[j], CFT_BREAK);
auto be_cnt = cft[CFT_BREAK];
--be_cnt; // we already did one above
insts1[j]->aux->cft[CFT_BREAK] += be_cnt;
}
if ( cft.count(CFT_BLOCK_END) > 0 ) {
// Propagate block-ends backwards.
int j = i;
while ( --j >= 0 )
if ( insts1[j]->live )
break;
ASSERT(j >= 0);
// Make sure the CFT entry is created.
AddCFT(insts1[j], CFT_BLOCK_END);
auto be_cnt = cft[CFT_BLOCK_END];
--be_cnt; // we already did one above
insts1[j]->aux->cft[CFT_BLOCK_END] += be_cnt;
}
// If's can be killed because their bodies become empty,
// break's because they just lead to their following instruction,
// and next's if they become dead code.
// However, loop's and next's should not be killed.
ASSERT(cft.count(CFT_LOOP) == 0);
ASSERT(cft.count(CFT_LOOP_COND) == 0);
}
} }
void ZAMCompiler::KillInsts(zeek_uint_t i) { void ZAMCompiler::KillInsts(zeek_uint_t i) {

View file

@ -10,9 +10,12 @@ namespace zeek::detail {
void ZAMCompiler::PushGoTos(GoToSets& gotos) { gotos.emplace_back(); } void ZAMCompiler::PushGoTos(GoToSets& gotos) { gotos.emplace_back(); }
void ZAMCompiler::ResolveGoTos(GoToSets& gotos, const InstLabel l) { void ZAMCompiler::ResolveGoTos(GoToSets& gotos, const InstLabel l, ControlFlowType cft) {
for ( auto& gi : gotos.back() ) for ( auto& gi : gotos.back() ) {
SetGoTo(gi, l); SetGoTo(gi, l);
if ( cft != CFT_NONE )
AddCFT(insts1[gi.stmt_num], cft);
}
gotos.pop_back(); gotos.pop_back();
} }

View file

@ -159,16 +159,17 @@ private:
const ZAMStmt ValueSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c); const ZAMStmt ValueSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c);
const ZAMStmt TypeSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c); const ZAMStmt TypeSwitch(const SwitchStmt* sw, const NameExpr* v, const ConstExpr* c);
const ZAMStmt GenSwitch(const SwitchStmt* sw, int slot, InternalTypeTag it);
void PushNexts() { PushGoTos(nexts); } void PushNexts() { PushGoTos(nexts); }
void PushBreaks() { PushGoTos(breaks); } void PushBreaks() { PushGoTos(breaks); }
void PushFallThroughs() { PushGoTos(fallthroughs); } void PushFallThroughs() { PushGoTos(fallthroughs); }
void PushCatchReturns() { PushGoTos(catches); } void PushCatchReturns() { PushGoTos(catches); }
void ResolveNexts(const InstLabel l) { ResolveGoTos(nexts, l); } void ResolveNexts(const InstLabel l) { ResolveGoTos(nexts, l, CFT_NEXT); }
void ResolveBreaks(const InstLabel l) { ResolveGoTos(breaks, l); } void ResolveBreaks(const InstLabel l) { ResolveGoTos(breaks, l, CFT_BREAK); }
void ResolveFallThroughs(const InstLabel l) { ResolveGoTos(fallthroughs, l); } void ResolveFallThroughs(const InstLabel l) { ResolveGoTos(fallthroughs, l); }
void ResolveCatchReturns(const InstLabel l) { ResolveGoTos(catches, l); } void ResolveCatchReturns(const InstLabel l) { ResolveGoTos(catches, l, CFT_INLINED_RETURN); }
const ZAMStmt LoopOverTable(const ForStmt* f, const NameExpr* val); const ZAMStmt LoopOverTable(const ForStmt* f, const NameExpr* val);
const ZAMStmt LoopOverVector(const ForStmt* f, const NameExpr* val); const ZAMStmt LoopOverVector(const ForStmt* f, const NameExpr* val);
@ -229,8 +230,8 @@ private:
const ZAMStmt CompileIndex(const NameExpr* n1, int n2_slot, const TypePtr& n2_type, const ListExpr* l, const ZAMStmt CompileIndex(const NameExpr* n1, int n2_slot, const TypePtr& n2_type, const ListExpr* l,
bool in_when); bool in_when);
const ZAMStmt BuildLambda(const NameExpr* n, ExprPtr le); // marker const ZAMStmt BuildLambda(const NameExpr* n, ExprPtr le);
const ZAMStmt BuildLambda(int n_slot, ExprPtr le); // marker const ZAMStmt BuildLambda(int n_slot, ExprPtr le);
// Second argument is which instruction slot holds the branch target. // Second argument is which instruction slot holds the branch target.
const ZAMStmt GenCond(const Expr* e, int& branch_v); const ZAMStmt GenCond(const Expr* e, int& branch_v);
@ -277,7 +278,7 @@ private:
using GoToSets = std::vector<GoToSet>; using GoToSets = std::vector<GoToSet>;
void PushGoTos(GoToSets& gotos); void PushGoTos(GoToSets& gotos);
void ResolveGoTos(GoToSets& gotos, const InstLabel l); void ResolveGoTos(GoToSets& gotos, const InstLabel l, ControlFlowType cft = CFT_NONE);
ZAMStmt GenGoTo(GoToSet& v); ZAMStmt GenGoTo(GoToSet& v);
ZAMStmt GoToStub(); ZAMStmt GoToStub();
@ -322,6 +323,9 @@ private:
const ZAMStmt ErrorStmt(); const ZAMStmt ErrorStmt();
const ZAMStmt LastInst(); const ZAMStmt LastInst();
// Adds control flow information to an instruction.
void AddCFT(ZInstI* inst, ControlFlowType cft);
// Returns a handle to state associated with building // Returns a handle to state associated with building
// up a list of values. // up a list of values.
std::unique_ptr<OpaqueVals> BuildVals(const ListExprPtr&); std::unique_ptr<OpaqueVals> BuildVals(const ListExprPtr&);

View file

@ -20,9 +20,25 @@ bool ZAMCompiler::NullStmtOK() const {
const ZAMStmt ZAMCompiler::EmptyStmt() { return ZAMStmt(insts1.size() - 1); } const ZAMStmt ZAMCompiler::EmptyStmt() { return ZAMStmt(insts1.size() - 1); }
const ZAMStmt ZAMCompiler::ErrorStmt() { return ZAMStmt(0); }
const ZAMStmt ZAMCompiler::LastInst() { return ZAMStmt(insts1.size() - 1); } const ZAMStmt ZAMCompiler::LastInst() { return ZAMStmt(insts1.size() - 1); }
const ZAMStmt ZAMCompiler::ErrorStmt() { return ZAMStmt(0); } void ZAMCompiler::AddCFT(ZInstI* inst, ControlFlowType cft) {
if ( cft == CFT_NONE )
return;
if ( ! inst->aux )
inst->aux = new ZInstAux(0);
auto cft_entry = inst->aux->cft.find(cft);
if ( cft_entry == inst->aux->cft.end() )
inst->aux->cft[cft] = 1;
else {
ASSERT(cft == CFT_BLOCK_END || cft == CFT_BREAK);
++cft_entry->second;
}
}
std::unique_ptr<OpaqueVals> ZAMCompiler::BuildVals(const ListExprPtr& l) { std::unique_ptr<OpaqueVals> ZAMCompiler::BuildVals(const ListExprPtr& l) {
return std::make_unique<OpaqueVals>(InternalBuildVals(l.get())); return std::make_unique<OpaqueVals>(InternalBuildVals(l.get()));

View file

@ -141,13 +141,21 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2)
else else
cond_stmt = GenCond(e, branch_v); cond_stmt = GenCond(e, branch_v);
AddCFT(insts1.back(), CFT_IF);
if ( s1 ) { if ( s1 ) {
auto s1_end = CompileStmt(s1); auto s1_end = CompileStmt(s1);
AddCFT(insts1.back(), CFT_BLOCK_END);
if ( s2 ) { if ( s2 ) {
auto branch_after_s1 = GoToStub(); auto branch_after_s1 = GoToStub();
auto else_start = insts1.size();
auto s2_end = CompileStmt(s2); auto s2_end = CompileStmt(s2);
SetV(cond_stmt, GoToTargetBeyond(branch_after_s1), branch_v); SetV(cond_stmt, GoToTargetBeyond(branch_after_s1), branch_v);
SetGoTo(branch_after_s1, GoToTargetBeyond(s2_end)); SetGoTo(branch_after_s1, GoToTargetBeyond(s2_end));
AddCFT(insts1[else_start], CFT_ELSE);
AddCFT(insts1.back(), CFT_BLOCK_END);
return s2_end; return s2_end;
} }
@ -462,6 +470,7 @@ const ZAMStmt ZAMCompiler::GenSwitch(const SwitchStmt* sw, int slot, InternalTyp
// Generate each of the cases. // Generate each of the cases.
auto cases = sw->Cases(); auto cases = sw->Cases();
std::vector<InstLabel> case_start; std::vector<InstLabel> case_start;
int case_index = 0;
PushFallThroughs(); PushFallThroughs();
for ( auto sw_case : *cases ) { for ( auto sw_case : *cases ) {
@ -477,8 +486,11 @@ const ZAMStmt ZAMCompiler::GenSwitch(const SwitchStmt* sw, int slot, InternalTyp
ResolveBreaks(sw_end); ResolveBreaks(sw_end);
int def_ind = sw->DefaultCaseIndex(); int def_ind = sw->DefaultCaseIndex();
if ( def_ind >= 0 ) if ( def_ind >= 0 ) {
SetV3(sw_head, case_start[def_ind]); auto def = case_start[def_ind];
SetV3(sw_head, def);
AddCFT(def, CFT_DEFAULT);
}
else else
SetV3(sw_head, sw_end); SetV3(sw_head, sw_end);
@ -651,18 +663,23 @@ const ZAMStmt ZAMCompiler::While(const Stmt* cond_stmt, const Expr* cond, const
if ( cond->Tag() == EXPR_NAME ) { if ( cond->Tag() == EXPR_NAME ) {
auto n = cond->AsNameExpr(); auto n = cond->AsNameExpr();
cond_IF = AddInst(ZInstI(OP_IF_VV, FrameSlot(n), 0)); cond_IF = AddInst(ZInstI(OP_IF_Vb, FrameSlot(n), 0));
branch_v = 2; branch_v = 2;
} }
else else
cond_IF = GenCond(cond, branch_v); cond_IF = GenCond(cond, branch_v);
AddCFT(insts1[head.stmt_num], CFT_LOOP);
AddCFT(insts1[cond_IF.stmt_num], CFT_LOOP_COND);
PushNexts(); PushNexts();
PushBreaks(); PushBreaks();
if ( body && body->Tag() != STMT_NULL ) if ( body && body->Tag() != STMT_NULL )
(void)CompileStmt(body); (void)CompileStmt(body);
AddCFT(insts1.back(), CFT_BLOCK_END);
auto tail = GoTo(GoToTarget(head)); auto tail = GoTo(GoToTarget(head));
auto beyond_tail = GoToTargetBeyond(tail); auto beyond_tail = GoToTargetBeyond(tail);
@ -682,17 +699,21 @@ const ZAMStmt ZAMCompiler::CompileFor(const ForStmt* f) {
PushNexts(); PushNexts();
PushBreaks(); PushBreaks();
ZAMStmt z;
if ( et == TYPE_TABLE ) if ( et == TYPE_TABLE )
return LoopOverTable(f, val); z = LoopOverTable(f, val);
else if ( et == TYPE_VECTOR ) else if ( et == TYPE_VECTOR )
return LoopOverVector(f, val); z = LoopOverVector(f, val);
else if ( et == TYPE_STRING ) else if ( et == TYPE_STRING )
return LoopOverString(f, e); z = LoopOverString(f, e);
else else
reporter->InternalError("bad \"for\" loop-over value when compiling"); reporter->InternalError("bad \"for\" loop-over value when compiling");
return z;
} }
const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val) { const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val) {

View file

@ -385,6 +385,20 @@ private:
bool is_managed = false; bool is_managed = false;
}; };
enum ControlFlowType {
CFT_IF,
CFT_BLOCK_END,
CFT_ELSE,
CFT_LOOP,
CFT_LOOP_COND,
CFT_NEXT,
CFT_BREAK,
CFT_DEFAULT,
CFT_INLINED_RETURN,
CFT_NONE,
};
// Auxiliary information, used when the fixed ZInst layout lacks // Auxiliary information, used when the fixed ZInst layout lacks
// sufficient expressiveness to represent all of the elements that // sufficient expressiveness to represent all of the elements that
// an instruction needs. // an instruction needs.
@ -500,11 +514,14 @@ public:
// Whether we know that we're calling a BiF. // Whether we know that we're calling a BiF.
bool is_BiF_call = false; bool is_BiF_call = false;
// Associated control flow information.
std::map<ControlFlowType, int> cft;
// Used for referring to events. // Used for referring to events.
EventHandler* event_handler = nullptr; EventHandler* event_handler = nullptr;
// Used for things like constructors. // Used for things like constructors.
AttributesPtr attrs = nullptr; AttributesPtr attrs;
// Whether the instruction can lead to globals/captures changing. // Whether the instruction can lead to globals/captures changing.
// Currently only needed by the optimizer, but convenient to // Currently only needed by the optimizer, but convenient to