diff --git a/auxil/gen-zam b/auxil/gen-zam index 16bcb175dd..113acbada6 160000 --- a/auxil/gen-zam +++ b/auxil/gen-zam @@ -1 +1 @@ -Subproject commit 16bcb175dddaa1cb6e3df7e1951287a29a74164e +Subproject commit 113acbada6478a610dfa639f34ef6662fbb671d9 diff --git a/src/script_opt/ProfileFunc.cc b/src/script_opt/ProfileFunc.cc index dddcfd0e19..6d4072473c 100644 --- a/src/script_opt/ProfileFunc.cc +++ b/src/script_opt/ProfileFunc.cc @@ -522,6 +522,12 @@ void ProfileFunc::TrackID(const ID* id) { // Already tracked. return; + if ( id->IsGlobal() ) + { + globals.insert(id); + all_globals.insert(id); + } + ordered_ids.push_back(id); } diff --git a/src/script_opt/ZAM/Compile.h b/src/script_opt/ZAM/Compile.h index 2ee365e64c..a8b262dfac 100644 --- a/src/script_opt/ZAM/Compile.h +++ b/src/script_opt/ZAM/Compile.h @@ -167,8 +167,14 @@ private: void PushFallThroughs() { PushGoTos(fallthroughs); } void PushCatchReturns() { PushGoTos(catches); } - void ResolveNexts(const InstLabel l) { ResolveGoTos(nexts, l); } - void ResolveBreaks(const InstLabel l) { ResolveGoTos(breaks, l); } + void ResolveNexts(const InstLabel l) { + ResolveGoTos(nexts, l); + AddCFT(l, CFT_NEXT); + } + void ResolveBreaks(const InstLabel l) { + ResolveGoTos(breaks, l); + AddCFT(l, CFT_BREAK); + } void ResolveFallThroughs(const InstLabel l) { ResolveGoTos(fallthroughs, l); } void ResolveCatchReturns(const InstLabel l) { ResolveGoTos(catches, l); } @@ -319,6 +325,9 @@ private: const ZAMStmt ErrorStmt(); const ZAMStmt LastInst(); + // Adds control flow information to an instruction. + void AddCFT(ZInstI* inst, ControlFlowType cft); + // Returns a handle to state associated with building // up a list of values. OpaqueVals* BuildVals(const ListExprPtr&); diff --git a/src/script_opt/ZAM/Driver.cc b/src/script_opt/ZAM/Driver.cc index b37e033d43..d77936cfeb 100644 --- a/src/script_opt/ZAM/Driver.cc +++ b/src/script_opt/ZAM/Driver.cc @@ -203,6 +203,7 @@ StmtPtr ZAMCompiler::CompileBody() { auto zb = make_intrusive(fname, this); zb->SetInsts(insts2); + zb->SetLocationInfo(body->GetLocationInfo()); // Could erase insts1 here to recover memory, but it's handy // for debugging. diff --git a/src/script_opt/ZAM/Low-Level.cc b/src/script_opt/ZAM/Low-Level.cc index 4898393eaa..fa6c95c87c 100644 --- a/src/script_opt/ZAM/Low-Level.cc +++ b/src/script_opt/ZAM/Low-Level.cc @@ -20,9 +20,15 @@ bool ZAMCompiler::NullStmtOK() const { 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::ErrorStmt() { return ZAMStmt(0); } +void ZAMCompiler::AddCFT(ZInstI* inst, ControlFlowType cft) { + if ( ! inst->aux ) + inst->aux = new ZInstAux(0); + inst->aux->cft.insert(cft); +} OpaqueVals* ZAMCompiler::BuildVals(const ListExprPtr& l) { return new OpaqueVals(InternalBuildVals(l.get())); } diff --git a/src/script_opt/ZAM/README.md b/src/script_opt/ZAM/README.md index dc9c62da68..90afbdbf09 100644 --- a/src/script_opt/ZAM/README.md +++ b/src/script_opt/ZAM/README.md @@ -100,6 +100,7 @@ issues: |`profile-ZAM` | Generate to "zprof.out" a ZAM execution profile. (Requires configuring with `--enable-ZAM-profiling` or `--enable-debug`.)| |`report-recursive` | Report on recursive functions and exit.| |`report-uncompilable` | Report on uncompilable functions and exit. For ZAM, all functions should be compilable.| +|`validate-ZAM` | Perform internal validation of ZAM instructions and exit.| |`xform` | Transform scripts to "reduced" form.| diff --git a/src/script_opt/ZAM/Stmt.cc b/src/script_opt/ZAM/Stmt.cc index f5af4b7710..2f80add1d9 100644 --- a/src/script_opt/ZAM/Stmt.cc +++ b/src/script_opt/ZAM/Stmt.cc @@ -145,13 +145,22 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2) else cond_stmt = GenCond(e, branch_v); + auto cft = (s1 && s2) ? CFT_IF_ELSE : (s1 ? CFT_IF : CFT_IF_NOT); + AddCFT(insts1.back(), cft); + if ( s1 ) { auto s1_end = CompileStmt(s1); + AddCFT(insts1.back(), CFT_BLOCK_END); + if ( s2 ) { auto branch_after_s1 = GoToStub(); + auto else_start = insts1.size(); auto s2_end = CompileStmt(s2); + SetV(cond_stmt, GoToTargetBeyond(branch_after_s1), branch_v); SetGoTo(branch_after_s1, GoToTargetBeyond(s2_end)); + AddCFT(insts1[else_start], CFT_ELSE); + AddCFT(insts1.back(), CFT_BLOCK_END); return s2_end; } @@ -164,6 +173,7 @@ const ZAMStmt ZAMCompiler::IfElse(const Expr* e, const Stmt* s1, const Stmt* s2) // Only the else clause is non-empty. auto s2_end = CompileStmt(s2); + AddCFT(insts1.back(), CFT_BLOCK_END); // For complex conditionals, we need to invert their sense since // we're switching to "if ( ! cond ) s2". @@ -705,12 +715,17 @@ const ZAMStmt ZAMCompiler::While(const Stmt* cond_stmt, const Expr* cond, const else cond_IF = GenCond(cond, branch_v); + AddCFT(insts1[head.stmt_num], CFT_LOOP); + AddCFT(insts1[cond_IF.stmt_num], CFT_LOOP_COND); + PushNexts(); PushBreaks(); if ( body && body->Tag() != STMT_NULL ) (void)CompileStmt(body); + AddCFT(insts1.back(), CFT_BLOCK_END); + auto tail = GoTo(GoToTarget(head)); auto beyond_tail = GoToTargetBeyond(tail); @@ -730,17 +745,25 @@ const ZAMStmt ZAMCompiler::CompileFor(const ForStmt* f) { PushNexts(); PushBreaks(); + auto head = StartingBlock(); + ZAMStmt z; + if ( et == TYPE_TABLE ) - return LoopOverTable(f, val); + z = LoopOverTable(f, val); else if ( et == TYPE_VECTOR ) - return LoopOverVector(f, val); + z = LoopOverVector(f, val); else if ( et == TYPE_STRING ) - return LoopOverString(f, e); + z = LoopOverString(f, e); else reporter->InternalError("bad \"for\" loop-over value when compiling"); + + AddCFT(insts1[head.stmt_num], CFT_LOOP); + AddCFT(insts1[z.stmt_num], CFT_BLOCK_END); + + return z; } const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val) { @@ -798,6 +821,7 @@ const ZAMStmt ZAMCompiler::LoopOverTable(const ForStmt* f, const NameExpr* val) } z.aux = aux; // so ZOpt.cc can get to it + AddCFT(&z, CFT_LOOP_COND); return FinishLoop(iter_head, z, body, iter_slot, true); } @@ -842,6 +866,8 @@ const ZAMStmt ZAMCompiler::LoopOverVector(const ForStmt* f, const NameExpr* val) } } + AddCFT(&z, CFT_LOOP_COND); + return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false); } @@ -878,6 +904,8 @@ const ZAMStmt ZAMCompiler::LoopOverString(const ForStmt* f, const Expr* e) { z.is_managed = true; } + AddCFT(&z, CFT_LOOP_COND); + return FinishLoop(iter_head, z, f->LoopBody(), iter_slot, false); } @@ -886,7 +914,11 @@ const ZAMStmt ZAMCompiler::Loop(const Stmt* body) { PushBreaks(); auto head = StartingBlock(); - (void)CompileStmt(body); + auto b = CompileStmt(body); + + AddCFT(insts1[head.stmt_num], CFT_LOOP); + AddCFT(insts1[b.stmt_num], CFT_BLOCK_END); + auto tail = GoTo(GoToTarget(head)); ResolveNexts(GoToTarget(head)); diff --git a/src/script_opt/ZAM/ZInst.h b/src/script_opt/ZAM/ZInst.h index 3772fa97b5..fc013181e9 100644 --- a/src/script_opt/ZAM/ZInst.h +++ b/src/script_opt/ZAM/ZInst.h @@ -375,6 +375,18 @@ private: bool is_managed = false; }; +enum ControlFlowType { + CFT_IF, + CFT_IF_NOT, + CFT_IF_ELSE, + CFT_BLOCK_END, + CFT_ELSE, + CFT_LOOP, + CFT_LOOP_COND, + CFT_NEXT, + CFT_BREAK, +}; + // Auxiliary information, used when the fixed ZInst layout lacks // sufficient expressiveness to represent all of the elements that // an instruction needs. @@ -493,6 +505,9 @@ public: // Whether we know that we're calling a BiF. bool is_BiF_call = false; + // Associated control flow information. + std::set cft; + // Used for referring to events. EventHandler* event_handler = nullptr;