Index: src/Common/PassVisitor.cc
===================================================================
--- src/Common/PassVisitor.cc	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
+++ src/Common/PassVisitor.cc	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -0,0 +1,18 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// PassVisitor.cc --
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Mar 03 14:53:53 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "Common/PassVisitor.h"
+
+PassVisitorStats pass_visitor_stats;
Index: src/Common/PassVisitor.h
===================================================================
--- src/Common/PassVisitor.h	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Common/PassVisitor.h	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -5,4 +5,5 @@
 #include <stack>
 
+#include "Common/Stats.h"
 #include "Common/utility.h"
 
@@ -426,4 +427,12 @@
 };
 
+#include "Common/Stats.h"
+
+extern struct PassVisitorStats {
+	size_t depth = 0;
+	Stats::Counters::MaxCounter<double> * max = nullptr;
+	Stats::Counters::AverageCounter<double> * avg = nullptr;
+} pass_visitor_stats;
+
 #include "SynTree/TypeSubstitution.h"
 #include "PassVisitor.impl.h"
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Common/PassVisitor.impl.h	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -67,5 +67,10 @@
 	SemanticErrorException errors;
 
+	pass_visitor_stats.depth++;
+	pass_visitor_stats.max->push(pass_visitor_stats.depth);
+	pass_visitor_stats.avg->push(pass_visitor_stats.depth);
 	for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
+
+
 		// splice in new declarations after previous decl
 		if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); }
@@ -83,4 +88,5 @@
 		if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
 	}
+	pass_visitor_stats.depth--;
 	if ( ! errors.isEmpty() ) {
 		throw errors;
@@ -94,4 +100,7 @@
 	SemanticErrorException errors;
 
+	pass_visitor_stats.depth++;
+	pass_visitor_stats.max->push(pass_visitor_stats.depth);
+	pass_visitor_stats.avg->push(pass_visitor_stats.depth);
 	for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
 		// splice in new declarations after previous decl
@@ -109,4 +118,5 @@
 		if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
 	}
+	pass_visitor_stats.depth--;
 	if ( ! errors.isEmpty() ) {
 		throw errors;
@@ -126,4 +136,8 @@
 	if ( ! visitor.get_visit_children() ) return;
 	SemanticErrorException errors;
+
+	pass_visitor_stats.depth++;
+	pass_visitor_stats.max->push(pass_visitor_stats.depth);
+	pass_visitor_stats.avg->push(pass_visitor_stats.depth);
 	for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
 		try {
@@ -135,4 +149,5 @@
 		}
 	}
+	pass_visitor_stats.depth--;
 	if ( ! errors.isEmpty() ) {
 		throw errors;
@@ -153,4 +168,8 @@
 	if ( ! mutator.get_visit_children() ) return;
 	SemanticErrorException errors;
+
+	pass_visitor_stats.depth++;
+	pass_visitor_stats.max->push(pass_visitor_stats.depth);
+	pass_visitor_stats.avg->push(pass_visitor_stats.depth);
 	for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
 		try {
@@ -163,4 +182,5 @@
 		} // try
 	} // for
+	pass_visitor_stats.depth--;
 	if ( ! errors.isEmpty() ) {
 		throw errors;
@@ -185,4 +205,7 @@
 	DeclList_t* afterDecls  = get_afterDecls();
 
+	pass_visitor_stats.depth++;
+	pass_visitor_stats.max->push(pass_visitor_stats.depth);
+	pass_visitor_stats.avg->push(pass_visitor_stats.depth);
 	for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
 
@@ -202,4 +225,5 @@
 		if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
 	}
+	pass_visitor_stats.depth--;
 
 	if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); }
Index: src/Common/Stats/Base.h
===================================================================
--- src/Common/Stats/Base.h	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Common/Stats/Base.h	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -1,2 +1,17 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Heap.h --
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Mar 03 14:53:53 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
 #pragma once
 
Index: src/Common/Stats/Counter.cc
===================================================================
--- src/Common/Stats/Counter.cc	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Common/Stats/Counter.cc	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Heap.h --
+// Counter.cc --
 //
 // Author           : Thierry Delisle
Index: src/Common/Stats/Counter.h
===================================================================
--- src/Common/Stats/Counter.h	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Common/Stats/Counter.h	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Heap.h --
+// Counter.h --
 //
 // Author           : Thierry Delisle
Index: src/Common/module.mk
===================================================================
--- src/Common/module.mk	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Common/module.mk	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -17,8 +17,9 @@
 SRC_COMMON = \
       Common/Assert.cc \
+      Common/Eval.cc \
+      Common/PassVisitor.cc \
+      Common/SemanticError.cc \
       Common/Stats/Heap.cc \
       Common/Stats/Counter.cc \
-      Common/Eval.cc \
-      Common/SemanticError.cc \
       Common/UniqueName.cc
 
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/Makefile.in	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -165,7 +165,8 @@
 	CodeGen/FixMain.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \
 	CodeGen/OperatorTable.$(OBJEXT)
-am__objects_2 = Common/Assert.$(OBJEXT) Common/Stats/Heap.$(OBJEXT) \
-	Common/Stats/Counter.$(OBJEXT) Common/Eval.$(OBJEXT) \
-	Common/SemanticError.$(OBJEXT) Common/UniqueName.$(OBJEXT)
+am__objects_2 = Common/Assert.$(OBJEXT) Common/Eval.$(OBJEXT) \
+	Common/PassVisitor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \
+	Common/Stats/Heap.$(OBJEXT) Common/Stats/Counter.$(OBJEXT) \
+	Common/UniqueName.$(OBJEXT)
 am__objects_3 = ControlStruct/ForExprMutator.$(OBJEXT) \
 	ControlStruct/LabelFixer.$(OBJEXT) \
@@ -560,8 +561,9 @@
 SRC_COMMON = \
       Common/Assert.cc \
+      Common/Eval.cc \
+      Common/PassVisitor.cc \
+      Common/SemanticError.cc \
       Common/Stats/Heap.cc \
       Common/Stats/Counter.cc \
-      Common/Eval.cc \
-      Common/SemanticError.cc \
       Common/UniqueName.cc
 
@@ -721,4 +723,10 @@
 Common/Assert.$(OBJEXT): Common/$(am__dirstamp) \
 	Common/$(DEPDIR)/$(am__dirstamp)
+Common/Eval.$(OBJEXT): Common/$(am__dirstamp) \
+	Common/$(DEPDIR)/$(am__dirstamp)
+Common/PassVisitor.$(OBJEXT): Common/$(am__dirstamp) \
+	Common/$(DEPDIR)/$(am__dirstamp)
+Common/SemanticError.$(OBJEXT): Common/$(am__dirstamp) \
+	Common/$(DEPDIR)/$(am__dirstamp)
 Common/Stats/$(am__dirstamp):
 	@$(MKDIR_P) Common/Stats
@@ -731,8 +739,4 @@
 Common/Stats/Counter.$(OBJEXT): Common/Stats/$(am__dirstamp) \
 	Common/Stats/$(DEPDIR)/$(am__dirstamp)
-Common/Eval.$(OBJEXT): Common/$(am__dirstamp) \
-	Common/$(DEPDIR)/$(am__dirstamp)
-Common/SemanticError.$(OBJEXT): Common/$(am__dirstamp) \
-	Common/$(DEPDIR)/$(am__dirstamp)
 Common/UniqueName.$(OBJEXT): Common/$(am__dirstamp) \
 	Common/$(DEPDIR)/$(am__dirstamp)
@@ -1115,4 +1119,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/DebugMalloc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Eval.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/PassVisitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/SemanticError.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/UniqueName.Po@am__quote@
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 8e70823920df10bf60abd7a63291bfdbcf88c901)
+++ src/main.cc	(revision 675716ec02a392a1cd187946766c1829aeb097e5)
@@ -65,7 +65,17 @@
 using namespace std;
 
-#define PASS(name, pass)                   \
+auto pass_visitor_group = new Stats::Counters::CounterGroup("Pass Visitor");
+
+void NewPass(const char * const name) {
+	Stats::Heap::newPass(name);
+	auto pass = new Stats::Counters::CounterGroup(name, pass_visitor_group);
+	pass_visitor_stats.depth = 0;
+	pass_visitor_stats.avg = new Stats::Counters::AverageCounter<double>("Average Depth", pass);
+	pass_visitor_stats.max = new Stats::Counters::MaxCounter<double>("Max Depth", pass);
+}
+
+#define PASS(name, pass)                  \
 	if ( errorp ) { cerr << name << endl; } \
-	Stats::Heap::newPass(name);               \
+	NewPass(name);                          \
 	pass;
 
@@ -142,5 +152,5 @@
 	backtrace( 6 );										// skip first 6 stack frames
 	signal( SIGABRT, SIG_DFL);							// reset default signal handler
-    raise( SIGABRT );									// reraise SIGABRT
+		raise( SIGABRT );									// reraise SIGABRT
 } // sigAbortHandler
 
@@ -181,4 +191,6 @@
 		} // if
 
+		NewPass("Parse");
+
 		// read in the builtins, extras, and the prelude
 		if ( ! nopreludep ) {							// include gcc builtins
@@ -233,5 +245,5 @@
 
 		// add the assignment statement after the initialization of a type parameter
-		PASS( "validate", SymTab::validate( translationUnit, symtabp ) );
+		PASS( "Validate", SymTab::validate( translationUnit, symtabp ) );
 		if ( symtabp ) {
 			deleteAll( translationUnit );
@@ -250,8 +262,8 @@
 		} // if
 
-		PASS( "fixLabels", ControlStruct::fixLabels( translationUnit ) );
-		PASS( "fixNames", CodeGen::fixNames( translationUnit ) );
-		PASS( "genInit", InitTweak::genInit( translationUnit ) );
-		PASS( "expandMemberTuples" , Tuples::expandMemberTuples( translationUnit ) );
+		PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
+		PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
+		PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
+		PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
 		if ( libcfap ) {
 			// generate the bodies of cfa library functions
@@ -277,5 +289,5 @@
 		}
 
-		PASS( "resolve", ResolvExpr::resolve( translationUnit ) );
+		PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
 		if ( exprp ) {
 			dump( translationUnit );
@@ -284,5 +296,5 @@
 
 		// fix ObjectDecl - replaces ConstructorInit nodes
-		PASS( "fixInit", InitTweak::fix( translationUnit, buildingLibrary() ) );
+		PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
 		if ( ctorinitp ) {
 			dump ( translationUnit );
@@ -290,13 +302,13 @@
 		} // if
 
-		PASS( "expandUniqueExpr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
-
-		PASS( "translateEHM" , ControlStruct::translateEHM( translationUnit ) );
-
-		PASS( "generateWaitfor" , Concurrency::generateWaitFor( translationUnit ) );
-
-		PASS( "convertSpecializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
-
-		PASS( "expandTuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?
+		PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
+
+		PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );
+
+		PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
+
+		PASS( "Convert Specializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
+
+		PASS( "Expand Tuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?
 
 		if ( tuplep ) {
@@ -305,12 +317,12 @@
 		}
 
-		PASS( "virtual expandCasts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
-
-		PASS( "instantiateGenerics", GenPoly::instantiateGeneric( translationUnit ) );
+		PASS( "Virtual Expand Casts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
+
+		PASS( "Instantiate Generics", GenPoly::instantiateGeneric( translationUnit ) );
 		if ( genericsp ) {
 			dump( translationUnit );
 			return 0;
 		}
-		PASS( "convertLvalue", GenPoly::convertLvalue( translationUnit ) );
+		PASS( "Convert L-Value", GenPoly::convertLvalue( translationUnit ) );
 
 
@@ -319,5 +331,5 @@
 			return 0;
 		} // if
-		PASS( "box", GenPoly::box( translationUnit ) );
+		PASS( "Box", GenPoly::box( translationUnit ) );
 
 		if ( bcodegenp ) {
@@ -331,5 +343,5 @@
 
 		CodeTools::fillLocations( translationUnit );
-		PASS( "codegen", CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true, linemarks ) );
+		PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true, linemarks ) );
 
 		CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() );
@@ -421,79 +433,79 @@
 	while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrRstTvwW:yzZD:F:", long_opts, &long_index )) != -1 ) {
 		switch ( c ) {
-		  case Ast:
-		  case 'a':										// dump AST
+			case Ast:
+			case 'a':										// dump AST
 			astp = true;
 			break;
-		  case Bresolver:
-		  case 'b':										// print before resolver steps
+			case Bresolver:
+			case 'b':										// print before resolver steps
 			bresolvep = true;
 			break;
-		  case 'B':										// print before box steps
+			case 'B':										// print before box steps
 			bboxp = true;
 			break;
-		  case CtorInitFix:
-		  case 'c':										// print after constructors and destructors are replaced
+			case CtorInitFix:
+			case 'c':										// print after constructors and destructors are replaced
 			ctorinitp = true;
 			break;
-		  case 'C':										// print before code generation
+			case 'C':										// print before code generation
 			bcodegenp = true;
 			break;
-		  case DeclStats:
-		  case 'd':
-		    declstatsp = true;
-			break;
-		  case Expr:
-		  case 'e':										// dump AST after expression analysis
+			case DeclStats:
+			case 'd':
+				declstatsp = true;
+			break;
+			case Expr:
+			case 'e':										// dump AST after expression analysis
 			exprp = true;
 			break;
-		  case ExprAlt:
-		  case 'f':										// print alternatives for expressions
+			case ExprAlt:
+			case 'f':										// print alternatives for expressions
 			expraltp = true;
 			break;
-		  case Grammar:
-		  case 'g':										// bison debugging info (grammar rules)
+			case Grammar:
+			case 'g':										// bison debugging info (grammar rules)
 			yydebug = true;
 			break;
-		  case 'G':										// dump AST after instantiate generics
+			case 'G':										// dump AST after instantiate generics
 			genericsp = true;
 			break;
-		  case LibCFA:
-		  case 'l':										// generate libcfa.c
+			case LibCFA:
+			case 'l':										// generate libcfa.c
 			libcfap = true;
 			break;
-		  case Linemarks:
-		  case 'L':										// print lines marks
+			case Linemarks:
+			case 'L':										// print lines marks
 			linemarks = true;
 			break;
-		  case Nopreamble:
-		  case 'n':										// do not read preamble
+			case Nopreamble:
+			case 'n':										// do not read preamble
 			nopreludep = true;
 			break;
-		  case Nolinemarks:
-		  case 'N':										// suppress line marks
+			case Nolinemarks:
+			case 'N':										// suppress line marks
 			linemarks = false;
 			break;
-		  case Prototypes:
-		  case 'p':										// generate prototypes for preamble functions
+			case Prototypes:
+			case 'p':										// generate prototypes for preamble functions
 			noprotop = true;
 			break;
-		  case PreludeDir:
-		  	PreludeDirector = optarg;
-			break;
-		  case 'm':										// don't replace the main
-		  	nomainp = true;
-			break;
-		  case Parse:
-		  case 'q':										// dump parse tree
+			case PreludeDir:
+				PreludeDirector = optarg;
+			break;
+			case 'm':										// don't replace the main
+				nomainp = true;
+			break;
+			case Parse:
+			case 'q':										// dump parse tree
 			parsep = true;
 			break;
-		  case Resolver:
-		  case 'r':										// print resolver steps
+			case Resolver:
+			case 'r':										// print resolver steps
 			resolvep = true;
 			break;
-		  case 'R':										// dump resolv-proto instance
+			case 'R':										// dump resolv-proto instance
 			resolvprotop = true;
 			break;
-		  case Stats:
+			case Stats:
 			{
 				std::stringstream ss(optarg);
@@ -515,23 +527,23 @@
 			}
 			break;
-		  case Symbol:
-		  case 's':										// print symbol table events
+			case Symbol:
+			case 's':										// print symbol table events
 			symtabp = true;
 			break;
-		  case Tree:
-		  case 't':										// build in tree
+			case Tree:
+			case 't':										// build in tree
 			treep = true;
 			break;
-		  case TupleExpansion:
-		  case 'T':										// print after tuple expansion
+			case TupleExpansion:
+			case 'T':										// print after tuple expansion
 			tuplep = true;
 			break;
-		  case 'v':										// dump AST after decl validation pass
+			case 'v':										// dump AST after decl validation pass
 			validp = true;
 			break;
-		  case 'w':
+			case 'w':
 			Wsuppress = true;
 			break;
-		  case 'W':
+			case 'W':
 			if ( strcmp( optarg, "all" ) == 0 ) {
 				SemanticWarning_EnableAll();
@@ -550,8 +562,8 @@
 			} // if
 			break;
-		  case 'y':										// dump AST on error
+			case 'y':										// dump AST on error
 			errorp = true;
 			break;
-		  case 'z':										// dump as codegen rather than AST
+			case 'z':										// dump as codegen rather than AST
 			codegenp = true;
 			break;
@@ -559,10 +571,10 @@
 			prettycodegenp = true;
 			break;
-		  case 'D':										// ignore -Dxxx
-			break;
-		  case 'F':										// source file-name without suffix
+			case 'D':										// ignore -Dxxx
+			break;
+			case 'F':										// source file-name without suffix
 			filename = optarg;
 			break;
-		  case '?':
+			case '?':
 			if ( optopt ) {								// short option ?
 				assertf( false, "Unknown option: -%c\n", (char)optopt );
@@ -573,5 +585,5 @@
 				__attribute__((fallthrough));
 			#endif
-		  default:
+			default:
 			abort();
 		} // switch
