Index: benchmark/plot.py
===================================================================
--- benchmark/plot.py	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ benchmark/plot.py	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -33,5 +33,5 @@
 	"Ops per threads"       : Field('Ops'   , 0, False),
 	"ns per ops/procs"      : Field('ns'    , 0, False),
-	"Number of threads"     : Field('thrd'  , 1, False),
+	"Number of threads"     : Field(''      , 1, False),
 	"Total Operations(ops)" : Field('Ops'   , 0, False),
 	"Ops/sec/procs"         : Field('Ops'   , 0, False),
@@ -40,10 +40,13 @@
 	"Cycle size (# thrds)"  : Field('thrd'  , 1, False),
 	"Duration (ms)"         : Field('ms'    , 0, False),
-	"Target QPS"            : Field('QPS'   , 0, False),
-	"Actual QPS"            : Field('QPS'   , 0, False),
+	"Target QPS"            : Field(''      , 0, False),
+	"Actual QPS"            : Field(''      , 0, False),
+	"Average Read Latency"  : Field('us'    , 0, True),
 	"Median Read Latency"   : Field('us'    , 0, True),
 	"Tail Read Latency"     : Field('us'    , 0, True),
+	"Average Update Latency": Field('us'    , 0, True),
 	"Median Update Latency" : Field('us'    , 0, True),
 	"Tail Update Latency"   : Field('us'    , 0, True),
+	"Update Ratio"          : Field('\%'    , 0, False),
 }
 
@@ -92,5 +95,5 @@
 	print("Making Plots")
 
-	for name, data in series.items():
+	for name, data in sorted(series.items()):
 		_col = next(colors)
 		plt.scatter(data['x'], data['y'], color=_col, label=name, marker='x')
Index: benchmark/process-mutilate.py
===================================================================
--- benchmark/process-mutilate.py	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ benchmark/process-mutilate.py	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -14,4 +14,5 @@
 parser = argparse.ArgumentParser(description='Python Script to convert output from mutilate to rmit like output')
 parser.add_argument('--out', nargs='?', type=argparse.FileType('w'), default=sys.stdout)
+parser.add_argument('--var', nargs='?', type=str, default='Target QPS')
 try:
 	options =  parser.parse_args()
@@ -31,4 +32,5 @@
 
 	try:
+		latAvs = fields[1]
 		lat50s = fields[6]
 		lat99s = fields[9]
@@ -37,4 +39,5 @@
 
 	try:
+		latAv = locale.atof(latAvs)
 		lat50 = locale.atof(lat50s)
 		lat99 = locale.atof(lat99s)
@@ -42,5 +45,5 @@
 		raise Warning("Warning: \"{}\" \"{}\"! can't convert to float".format(lat50s, lat99s))
 
-	return lat50, lat99
+	return latAv, lat50, lat99
 
 def want0(line):
@@ -58,8 +61,8 @@
 		try:
 			if   line.startswith("read"):
-				rlat50, rlat99 = precentile(line)
+				rlatAv, rlat50, rlat99 = precentile(line)
 
 			elif line.startswith("update"):
-				ulat50, ulat99 = precentile(line)
+				ulatAv, ulat50, ulat99 = precentile(line)
 
 			elif line.startswith("Total QPS"):
@@ -84,4 +87,5 @@
 
 	try:
+		out['Average Read Latency'] = rlatAv
 		out['Median Read Latency'] = rlat50
 		out['Tail Read Latency'] = rlat99
@@ -90,4 +94,5 @@
 
 	try:
+		out['Average Update Latency'] = ulatAv
 		out['Median Update Latency'] = ulat50
 		out['Tail Update Latency'] = ulat99
@@ -112,5 +117,5 @@
 			continue
 
-		d = { 'Target QPS': int(rate) }
+		d = { options.var : int(rate) }
 
 		w = extract( f, d )
Index: libcfa/src/concurrency/io.cfa
===================================================================
--- libcfa/src/concurrency/io.cfa	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ libcfa/src/concurrency/io.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -244,5 +244,5 @@
 
 					remote = true;
-					__STATS__( false, io.calls.helped++; )
+					__STATS__( true, io.calls.helped++; )
 				}
 				proc->io.target = MAX;
Index: libcfa/src/concurrency/locks.cfa
===================================================================
--- libcfa/src/concurrency/locks.cfa	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ libcfa/src/concurrency/locks.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -220,7 +220,9 @@
 
 //-----------------------------------------------------------------------------
-// condition variable
+// Synchronization Locks
 forall(L & | is_blocking_lock(L)) {
 
+	//-----------------------------------------------------------------------------
+	// condition variable
 	void ?{}( condition_variable(L) & this ){
 		this.lock{};
@@ -337,4 +339,51 @@
 	bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , duration ) }
 	bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , duration ) }
+
+	//-----------------------------------------------------------------------------
+	// fast_cond_var
+	void  ?{}( fast_cond_var(L) & this ){
+		this.blocked_threads{}; 
+		#ifdef __CFA_DEBUG__
+		this.lock_used = 0p;
+		#endif
+	}
+	void ^?{}( fast_cond_var(L) & this ){ }
+
+	bool notify_one( fast_cond_var(L) & this ) with(this) {
+		bool ret = ! blocked_threads`isEmpty;
+		if ( ret ) {
+			info_thread(L) & popped = try_pop_front( blocked_threads );
+			on_notify(*popped.lock, popped.t);
+		}
+		return ret;
+	}
+	bool notify_all( fast_cond_var(L) & this ) with(this) {
+		bool ret = ! blocked_threads`isEmpty;
+		while( ! blocked_threads`isEmpty ) {
+			info_thread(L) & popped = try_pop_front( blocked_threads );
+			on_notify(*popped.lock, popped.t);
+		}
+		return ret;
+	}
+
+	uintptr_t front( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty ? NULL : blocked_threads`first.info; }
+	bool empty ( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
+
+	void wait( fast_cond_var(L) & this, L & l ) {
+		wait( this, l, 0 );
+	}
+
+	void wait( fast_cond_var(L) & this, L & l, uintptr_t info ) with(this) {
+		// brand cond lock with lock
+		#ifdef __CFA_DEBUG__
+			if ( lock_used == 0p ) lock_used = &l;
+			else { assert(lock_used == &l); }
+		#endif
+		info_thread( L ) i = { active_thread(), info, &l };
+		insert_last( blocked_threads, i );
+		size_t recursion_count = on_wait( *i.lock );
+		park( );
+		on_wakeup(*i.lock, recursion_count);
+	}
 }
 
Index: libcfa/src/concurrency/locks.hfa
===================================================================
--- libcfa/src/concurrency/locks.hfa	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ libcfa/src/concurrency/locks.hfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -73,4 +73,6 @@
 static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
 
+//-----------------------------------------------------------------------------
+// MCS Lock
 struct mcs_node {
 	mcs_node * volatile next;
@@ -98,4 +100,6 @@
 }
 
+//-----------------------------------------------------------------------------
+// Linear backoff Spinlock
 struct linear_backoff_then_block_lock {
 	// Spin lock used for mutual exclusion
@@ -199,4 +203,56 @@
 
 //-----------------------------------------------------------------------------
+// Fast Block Lock
+
+// High efficiency minimal blocking lock
+// - No reacquire for cond var
+// - No recursive acquisition
+// - No ownership
+struct fast_block_lock {
+	// Spin lock used for mutual exclusion
+	__spinlock_t lock;
+
+	// List of blocked threads
+	dlist( thread$ ) blocked_threads;
+
+	bool held:1;
+};
+
+static inline void  ?{}( fast_block_lock & this ) with(this) {
+	lock{};
+	blocked_threads{};
+	held = false;
+}
+static inline void ^?{}( fast_block_lock & this ) {}
+static inline void ?{}( fast_block_lock & this, fast_block_lock this2 ) = void;
+static inline void ?=?( fast_block_lock & this, fast_block_lock this2 ) = void;
+
+// if this is called recursively IT WILL DEADLOCK!!!!!
+static inline void lock(fast_block_lock & this) with(this) {
+	lock( lock __cfaabi_dbg_ctx2 );
+	if (held) {
+		insert_last( blocked_threads, *active_thread() );
+		unlock( lock );
+		park( );
+		return;
+	}
+	held = true;
+	unlock( lock );
+}
+
+static inline void unlock(fast_block_lock & this) with(this) {
+	lock( lock __cfaabi_dbg_ctx2 );
+	/* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );
+	thread$ * t = &try_pop_front( blocked_threads );
+	held = ( t ? true : false );
+	unpark( t );
+	unlock( lock );
+}
+
+static inline void on_notify(fast_block_lock & this, struct thread$ * t ) { unpark(t); }
+static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }
+static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }
+
+//-----------------------------------------------------------------------------
 // is_blocking_lock
 trait is_blocking_lock(L & | sized(L)) {
@@ -226,4 +282,14 @@
 // Synchronization Locks
 forall(L & | is_blocking_lock(L)) {
+
+	//-----------------------------------------------------------------------------
+	// condition_variable
+
+	// The multi-tool condition variable
+	// - can pass timeouts to wait for either a signal or timeout
+	// - can wait without passing a lock
+	// - can have waiters reacquire different locks while waiting on the same cond var
+	// - has shadow queue
+	// - can be signalled outside of critical sections with no locks held
 	struct condition_variable {
 		// Spin lock used for mutual exclusion
@@ -258,3 +324,33 @@
 	bool wait( condition_variable(L) & this, L & l, Duration duration );
 	bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
-}
+
+	//-----------------------------------------------------------------------------
+	// fast_cond_var
+
+	// The trimmed and slim condition variable
+	// - no internal lock so you must hold a lock while using this cond var
+	// - signalling without holding branded lock is UNSAFE!
+	// - only allows usage of one lock, cond var is branded after usage
+	struct fast_cond_var {
+		// List of blocked threads
+		dlist( info_thread(L) ) blocked_threads;
+
+		#ifdef __CFA_DEBUG__
+		L * lock_used;
+		#endif
+	};
+
+
+	void  ?{}( fast_cond_var(L) & this );
+	void ^?{}( fast_cond_var(L) & this );
+
+	bool notify_one( fast_cond_var(L) & this );
+	bool notify_all( fast_cond_var(L) & this );
+
+	uintptr_t front( fast_cond_var(L) & this );
+
+	bool empty  ( fast_cond_var(L) & this );
+
+	void wait( fast_cond_var(L) & this, L & l );
+	void wait( fast_cond_var(L) & this, L & l, uintptr_t info );
+}
Index: libcfa/src/concurrency/ready_subqueue.hfa
===================================================================
--- libcfa/src/concurrency/ready_subqueue.hfa	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ libcfa/src/concurrency/ready_subqueue.hfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -83,4 +83,5 @@
 	/* paranoid */ verify( node->link.ts   != 0  );
 	/* paranoid */ verify( this.anchor.ts  != 0  );
+	/* paranoid */ verify( (this.anchor.ts  == MAX) == is_empty );
 	return [node, this.anchor.ts];
 }
@@ -93,5 +94,5 @@
 // Return the timestamp
 static inline unsigned long long ts(__intrusive_lane_t & this) {
-	// Cannot verify here since it may not be locked
+	// Cannot verify 'emptiness' here since it may not be locked
 	/* paranoid */ verify(this.anchor.ts != 0);
 	return this.anchor.ts;
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Convert.cpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -93,8 +93,8 @@
 	};
 
-    template<typename T>
-    Getter<T> get() {
-        return Getter<T>{ *this };
-    }
+	template<typename T>
+	Getter<T> get() {
+		return Getter<T>{ *this };
+	}
 
 	Label makeLabel(Statement * labelled, const ast::Label& label) {
@@ -1651,4 +1651,5 @@
 			// GET_ACCEPT_1(type, FunctionType),
 			std::move(forall),
+			std::move(assertions),
 			std::move(paramVars),
 			std::move(returnVars),
@@ -1664,5 +1665,4 @@
 		cache.emplace( old, decl );
 
-		decl->assertions = std::move(assertions);
 		decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
 		decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
Index: src/AST/Copy.cpp
===================================================================
--- src/AST/Copy.cpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Copy.cpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -10,6 +10,6 @@
 // Created On       : Thr Nov 11  9:16:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thr Nov 11  9:28:00 2021
-// Update Count     : 0
+// Last Modified On : Tue May  3 16:28:00 2022
+// Update Count     : 1
 //
 
@@ -77,4 +77,8 @@
 	}
 
+	void postvisit( const UniqueExpr * node ) {
+		readonlyInsert( &node->object );
+	}
+
 	void postvisit( const MemberExpr * node ) {
 		readonlyInsert( &node->member );
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Decl.cpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Thu May 9 10:00:00 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jan 12 16:54:55 2021
-// Update Count     : 23
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu May  5 12:10:00 2022
+// Update Count     : 24
 //
 
@@ -53,5 +53,5 @@
 // --- FunctionDecl
 
-FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 
+FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
 	std::vector<ptr<TypeDecl>>&& forall,
 	std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
@@ -74,4 +74,30 @@
 	}
 	this->type = ftype;
+}
+
+FunctionDecl::FunctionDecl( const CodeLocation & location, const std::string & name,
+	std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
+	std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
+	CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
+	std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
+: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
+		params( std::move(params) ), returns( std::move(returns) ),
+		type_params( std::move( forall) ), assertions( std::move( assertions ) ),
+		type( nullptr ), stmts( stmts ) {
+	FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
+	for ( auto & param : this->params ) {
+		type->params.emplace_back( param->get_type() );
+	}
+	for ( auto & ret : this->returns ) {
+		type->returns.emplace_back( ret->get_type() );
+	}
+	for ( auto & param : this->type_params ) {
+		type->forall.emplace_back( new TypeInstType( param ) );
+	}
+	for ( auto & assertion : this->assertions ) {
+		type->assertions.emplace_back(
+			new VariableExpr( assertion->location, assertion ) );
+	}
+	this->type = type;
 }
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Decl.hpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Thu May 9 10:00:00 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Mar 12 18:25:05 2021
-// Update Count     : 32
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu May  5 12:09:00 2022
+// Update Count     : 33
 //
 
@@ -135,10 +135,20 @@
 	std::vector< ptr<Expr> > withExprs;
 
+	// The difference between the two constructors is in how they handle
+	// assertions. The first constructor uses the assertions from the type
+	// parameters, in the style of the old ast, and puts them on the type.
+	// The second takes an explicite list of assertions and builds a list of
+	// references to them on the type.
+
 	FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
 		std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
 		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
 		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
-	// : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
-	//  stmts( stmts ) {}
+
+	FunctionDecl( const CodeLocation & location, const std::string & name,
+		std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
+		std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
+		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
+		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
 
 	const Type * get_type() const override;
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Expr.hpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -784,5 +784,5 @@
 public:
 	ptr<Expr> expr;
-	ptr<ObjectDecl> object;
+	readonly<ObjectDecl> object;
 	ptr<VariableExpr> var;
 	unsigned long long id;
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Node.hpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 8 10:27:04 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Mar 25 10:33:00 2022
-// Update Count     : 7
+// Last Modified On : Mon May  9 10:20:00 2022
+// Update Count     : 8
 //
 
@@ -49,5 +49,6 @@
 
 	bool unique() const { return strong_count == 1; }
-	bool isManaged() const {return strong_count > 0; }
+	bool isManaged() const { return strong_count > 0; }
+	bool isReferenced() const { return weak_count > 0; }
 
 private:
Index: src/AST/Stmt.cpp
===================================================================
--- src/AST/Stmt.cpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/AST/Stmt.cpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -9,12 +9,12 @@
 // Author           : Aaron B. Moss
 // Created On       : Wed May  8 13:00:00 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Feb  2 19:01:20 2022
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue May  3 15:18:20 2022
+// Update Count     : 4
 //
 
 #include "Stmt.hpp"
 
-
+#include "Copy.hpp"
 #include "DeclReplacer.hpp"
 #include "Type.hpp"
@@ -23,5 +23,17 @@
 
 // --- CompoundStmt
-CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) {
+CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids() {
+	// Statements can have weak references to them, if that happens inserting
+	// the original node into the new list will put the original node in a
+	// bad state, where it cannot be mutated. To avoid this, just perform an
+	// additional shallow copy on the statement.
+	for ( const Stmt * kid : other.kids ) {
+		if ( kid->isReferenced() ) {
+			kids.emplace_back( ast::shallowCopy( kid ) );
+		} else {
+			kids.emplace_back( kid );
+		}
+	}
+
 	// when cloning a compound statement, we may end up cloning declarations which
 	// are referred to by VariableExprs throughout the block. Cloning a VariableExpr
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/Common/SemanticError.h	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 19 10:09:17 2018
-// Update Count     : 31
+// Last Modified On : Wed May  4 14:08:26 2022
+// Update Count     : 35
 //
 
@@ -59,4 +59,5 @@
 	{"aggregate-forward-decl" , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
 	{"superfluous-decl"       , Severity::Warn    , "declaration does not allocate storage: %s"                  },
+	{"superfluous-else"       , Severity::Warn    , "else clause never executed for empty loop conditional"      },
 	{"gcc-attributes"         , Severity::Warn    , "invalid attribute: %s"                                      },
 	{"c++-like-copy"          , Severity::Warn    , "Constructor from reference is not a valid copy constructor" },
@@ -69,4 +70,5 @@
 	AggrForwardDecl,
 	SuperfluousDecl,
+	SuperfluousElse,
 	GccAttributes,
 	CppCopy,
@@ -79,5 +81,5 @@
 );
 
-#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, __VA_ARGS__)
+#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, ##__VA_ARGS__)
 
 void SemanticWarningImpl (CodeLocation loc, Warning warn, const char * const fmt, ...) __attribute__((format(printf, 3, 4)));
Index: src/ControlStruct/MultiLevelExit.cpp
===================================================================
--- src/ControlStruct/MultiLevelExit.cpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/ControlStruct/MultiLevelExit.cpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -594,4 +594,10 @@
 		}
 
+		// check if loop node and if so add else clause if it exists
+		const WhileDoStmt * whilePtr = dynamic_cast<const WhileDoStmt *>(kid.get());
+		if ( whilePtr && whilePtr->else_) ret.push_back(whilePtr->else_);
+		const ForStmt * forPtr = dynamic_cast<const ForStmt *>(kid.get());
+		if ( forPtr && forPtr->else_) ret.push_back(forPtr->else_);
+
 		if ( ! break_label.empty() ) {
 			ret.push_back( labelledNullStmt( ret.back()->location, break_label ) );
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/Parser/parser.yy	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar 14 16:35:29 2022
-// Update Count     : 5276
+// Last Modified On : Wed May  4 17:22:48 2022
+// Update Count     : 5279
 //
 
@@ -111,5 +111,5 @@
 
 void distInl( DeclarationNode * declaration ) {
-	// distribute EXTENSION across all declarations
+	// distribute INLINE across all declarations
 	for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
 		iter->set_inLine( true );
@@ -1221,6 +1221,11 @@
 
 iteration_statement:
-	WHILE '(' ')' statement								// CFA => while ( 1 )
+	WHILE '(' ')' statement								%prec THEN // CFA => while ( 1 )
 		{ $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
+	| WHILE '(' ')' statement ELSE statement			// CFA
+		{
+			$$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );
+			SemanticWarning( yylloc, Warning::SuperfluousElse );
+		}
 	| WHILE '(' conditional_declaration ')' statement	%prec THEN
 		{ $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
@@ -1229,10 +1234,20 @@
 	| DO statement WHILE '(' ')' ';'					// CFA => do while( 1 )
 		{ $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
-	| DO statement WHILE '(' comma_expression ')' ';'	%prec THEN
+	| DO statement WHILE '(' ')' ELSE statement			// CFA
+		{
+			$$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) );
+			SemanticWarning( yylloc, Warning::SuperfluousElse );
+		}
+	| DO statement WHILE '(' comma_expression ')' ';'
 		{ $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
 	| DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
 		{ $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
-	| FOR '(' ')' statement								// CFA => for ( ;; )
+	| FOR '(' ')' statement								%prec THEN // CFA => for ( ;; )
 		{ $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
+	| FOR '(' ')' statement ELSE statement				// CFA
+		{
+			$$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
+			SemanticWarning( yylloc, Warning::SuperfluousElse );
+		}
 	| FOR '(' for_control_expression_list ')' statement	%prec THEN
 	  	{ $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
@@ -2318,5 +2333,5 @@
 			{ SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
 
-			$$ = DeclarationNode::newEnum( nullptr, $7, true, $3 ) ->addQualifiers( $5 );
+			$$ = DeclarationNode::newEnum( nullptr, $7, true, $3 )->addQualifiers( $5 );
 		}
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
@@ -2327,5 +2342,5 @@
 	  '{' enumerator_list comma_opt '}'
 		{
-			$$ = DeclarationNode::newEnum( $6, $10, true, $3 ) -> addQualifiers( $5 ) -> addQualifiers( $7 );
+			$$ = DeclarationNode::newEnum( $6, $10, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
 		}
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
@@ -2333,5 +2348,5 @@
 			if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
 			typedefTable.makeTypedef( *$6->name );
-			$$ = DeclarationNode::newEnum( $6->name, $9, true, $3 ) -> addQualifiers( $5 ) -> addQualifiers( $7 );
+			$$ = DeclarationNode::newEnum( $6->name, $9, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
 		}
 	| enum_type_nobody
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ src/Validate/Autogen.cpp	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -350,4 +350,5 @@
 		name,
 		std::move( type_params ),
+		std::move( assertions ),
 		std::move( params ),
 		std::move( returns ),
@@ -360,5 +361,4 @@
 		// Auto-generated routines are inline to avoid conflicts.
 		ast::Function::Specs( ast::Function::Inline ) );
-	decl->assertions = std::move( assertions );
 	decl->fixUniqueId();
 	return decl;
Index: tests/.expect/loop_else.txt
===================================================================
--- tests/.expect/loop_else.txt	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
+++ tests/.expect/loop_else.txt	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -0,0 +1,64 @@
+empty
+empty
+empty
+
+false else
+
+else zero
+A else
+A A A A A A A A A A else
+A A A A A A A A A A A else
+B B B B B else
+C C C C C else
+D D D D D else
+E E E E E else
+
+0 1 2 3 4 5 6 7 8 9 else
+0 1 2 3 4 5 6 7 8 9 10 else
+1 3 5 7 9 else
+10 8 6 4 2 else
+0.5 1.5 2.5 3.5 4.5 else
+5.5 4.5 3.5 2.5 1.5 else
+2 4 6 8 10 else
+10 8 6 4 2 else
+
+1 2 3 4 5 6 7 8 9 10
+10 9 8 7 6 5 4 3 2 1 0
+2 4 6 8 10
+2.1 3.8 5.5 7.2 8.9
+10 8 6 4 2 0
+12.1 10.4 8.7 7. 5.3 3.6
+
+N N N N N N N N N N else
+0 1 2 3 4 5 6 7 8 9 else
+0 1 2 3 4 5 6 7 8 9 10 else
+10 9 8 7 6 5 4 3 2 1 else
+
+3 6 9 else
+
+(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)else
+(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)else
+
+(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)else
+(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)else
+(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)(10 10)else
+(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)(10 10)else
+
+(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)else
+(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)else
+(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)else
+(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)else
+
+0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4 else
+0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14 else
+0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13 else
+0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23 else
+
+0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4 else
+0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14 else
+0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13 else
+0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23 else
+
+0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 else
+0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 else
+0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 else
Index: tests/loop_else.cfa
===================================================================
--- tests/loop_else.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
+++ tests/loop_else.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -0,0 +1,110 @@
+#include <fstream.hfa>
+
+struct S { int i, j; };
+void ?{}( S & s ) { s.[i, j] = 0; }
+void ?{}( S & s, int i ) { s.[i, j] = [i, 0]; }
+void ?{}( S & s, int i, int j ) { s.[i, j] = [i, j]; }
+void ?{}( S & s, zero_t ) { s.[i, j] = 0; }
+void ?{}( S & s, one_t ) { s.[i, j] = 1; }
+int ?<?( S t1, S t2 ) { return t1.i < t2.i && t1.j < t2.j; }
+int ?<=?( S t1, S t2 ) { return t1.i <= t2.i && t1.j <= t2.j; }
+int ?>?( S t1, S t2 ) { return t1.i > t2.i && t1.j > t2.j; }
+int ?>=?( S t1, S t2 ) { return t1.i >= t2.i && t1.j >= t2.j; }
+S ?=?( S & t1, S t2 ) { t1.i = t2.i; t1.j = t2.j; return t1; }
+S ?+=?( S & t1, S t2 ) { t1.i += t2.i; t1.j += t2.j; return t1; }
+S ?+=?( S & t, one_t ) { t.i += 1; t.j += 1; return t; }
+S ?-=?( S & t1, S t2 ) { t1.i -= t2.i; t1.j -= t2.j; return t1; }
+S ?-=?( S & t, one_t ) { t.i -= 1; t.j -= 1; return t; }
+ofstream & ?|?( ofstream & os, S v ) { return os | '(' | v.i | v.j | ')'; }
+void & ?|?( ofstream & os, S v ) { (ofstream &)(os | v); ends( os ); }
+
+int main() {
+    sout | nlOff;										// turn off auto newline
+	while () { sout | "empty"; break; } else { sout | "else"; }					    sout | nl;
+	do { sout | "empty"; break; } while () else { sout | "else"; }				    sout | nl;
+	for () { sout | "empty"; break; } else { sout | "else"; }					    sout | nl | nl;
+
+    do { sout | "false"; } while (false) else { sout | "else"; }				    sout | nl | nl;
+
+	for ( 0 ) { sout | "A"; } else { sout | "else"; }	        				    sout | "zero" | nl;
+	for ( 1 ) { sout | "A"; } else { sout | "else"; }								sout | nl;
+	for ( 10 ) { sout | "A"; } else { sout | "else"; }							    sout | nl;
+	for ( = 10 ) { sout | "A"; } else { sout | "else"; }							sout | nl;
+	for ( 1 ~= 10 ~ 2 ) { sout | "B"; } else { sout | "else"; }						sout | nl;
+	for ( 10 -~= 1 ~ 2 ) { sout | "C"; } else { sout | "else"; }					sout | nl;
+	for ( 0.5 ~ 5.5 ) { sout | "D"; } else { sout | "else"; }						sout | nl;
+	for ( 5.5 -~ 0.5 ) { sout | "E"; } else { sout | "else"; }						sout | nl | nl;
+
+	for ( i; 10 ) { sout | i; } else { sout | "else"; }								sout | nl;
+	for ( i; = 10 ) { sout | i; } else { sout | "else"; }							sout | nl;
+	for ( i; 1 ~= 10 ~ 2 ) { sout | i; } else { sout | "else"; }					sout | nl;
+	for ( i; 10 -~= 1 ~ 2 ) { sout | i; } else { sout | "else"; }					sout | nl;
+	for ( i; 0.5 ~ 5.5 ) { sout | i; } else { sout | "else"; }						sout | nl;
+	for ( i; 5.5 -~ 0.5 ) { sout | i; } else { sout | "else"; }						sout | nl;
+	for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; } else { sout | "else"; }				sout | nl;
+	for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; } else { sout | "else"; }				sout | nl | nl;
+
+	// @ means do nothing
+	for ( i; 1 ~ @ ) {
+	  if ( i > 10 ) break;
+		sout | i;
+	} else { sout | "else"; }														sout | nl;
+	for ( i; 10 -~ @ ) {
+	  if ( i < 0 ) break;
+		sout | i;
+	} else { sout | "else"; }														sout | nl;
+	for ( i; 2 ~ @ ~ 2 ) {
+	  if ( i > 10 ) break;
+		sout | i;
+	} else { sout | "else"; }														sout | nl;
+	for ( i; 2.1 ~ @ ~ @ ) {
+	  if ( i > 10.5 ) break;
+		sout | i;
+		i += 1.7;
+	} else { sout | "else"; }														sout | nl;
+	for ( i; 10 -~ @ ~ 2 ) {
+	  if ( i < 0 ) break;
+		sout | i;
+	} else { sout | "else"; }														sout | nl;
+	for ( i; 12.1 ~ @ ~ @ ) {
+	  if ( i < 2.5 ) break;
+		sout | i;
+		i -= 1.7;
+	} else { sout | "else"; }														sout | nl | nl;
+	
+	enum { N = 10 };
+	for ( N ) { sout | "N"; } else { sout | "else"; }							sout | nl;
+	for ( i; N ) { sout | i; } else { sout | "else"; }							sout | nl;
+	for ( i; = N ) { sout | i; } else { sout | "else"; }						sout | nl;
+	for ( i; N -~ 0 ) { sout | i; } else { sout | "else"; }						sout | nl | nl;
+
+	const int start = 3, comp = 10, inc = 2;
+	for ( i; start ~ comp ~ inc + 1 ) { sout | i; } else { sout | "else"; }		sout | nl | nl;
+
+	for ( S s = (S){0}; s < (S){10,10}; s += (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
+	for ( s; (S){10,10} ) { sout | s; } else { sout | "else"; } sout | nl;
+	sout | nl;
+	for ( s; (S){0} ~ (S){10,10} ) { sout | s; } else { sout | "else"; }		 sout | nl;
+	for ( s; (S){0} ~ (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
+	for ( s; (S){0} ~= (S){10,10} ) { sout | s; } else { sout | "else"; }		 sout | nl;
+	for ( s; (S){0} ~= (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
+	sout | nl;
+	for ( s; (S){10,10} -~ (S){0} ) { sout | s; } else { sout | "else"; }		 sout | nl;
+	for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
+	for ( s; (S){10,10} -~= (S){0} ) { sout | s; } else { sout | "else"; }		 sout | nl;
+	for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl | nl;
+
+	for ( i; 10 : j; -5 ~ @ ) { sout | i | j; } else { sout | "else"; } sout | nl;
+	for ( i; 10 : j; -5 -~ @ ) { sout | i | j; } else { sout | "else"; } sout | nl;
+	for ( i; 10 : j; -5 ~ @ ~ 2 ) { sout | i | j; } else { sout | "else"; } sout | nl;
+	for ( i; 10 : j; -5 -~ @ ~ 2 ) { sout | i | j; } else { sout | "else"; } sout | nl | nl;
+
+	for ( j; -5 ~ @ : i; 10 ) { sout | i | j; } else { sout | "else"; } sout | nl;
+	for ( j; -5 -~ @ : i; 10 ) { sout | i | j; } else { sout | "else"; } sout | nl;
+	for ( j; -5 ~ @ ~ 2 : i; 10 ) { sout | i | j; } else { sout | "else"; } sout | nl;
+	for ( j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j; } else { sout | "else"; } sout | nl | nl;
+
+	for ( j; -5 -~ @ ~ 2 : i; 10 : k; 1.5 ~ @ ) { sout | i | j | k; } else { sout | "else"; } sout | nl;
+	for ( j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 10 ) { sout | i | j | k; } else { sout | "else"; } sout | nl;
+	for ( k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j | k; } else { sout | "else"; } sout | nl;
+}
Index: tests/unified_locking/.expect/fast_block_lock.txt
===================================================================
--- tests/unified_locking/.expect/fast_block_lock.txt	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
+++ tests/unified_locking/.expect/fast_block_lock.txt	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -0,0 +1,3 @@
+Starting
+Done!
+Match!
Index: tests/unified_locking/.expect/locks.txt
===================================================================
--- tests/unified_locking/.expect/locks.txt	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ tests/unified_locking/.expect/locks.txt	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -23,2 +23,4 @@
 Start Test 12: locked condition variable wait/notify with front()
 Done Test 12
+Start Test 13: fast block lock and fast cond var single wait/notify
+Done Test 13
Index: tests/unified_locking/fast_block_lock.cfa
===================================================================
--- tests/unified_locking/fast_block_lock.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
+++ tests/unified_locking/fast_block_lock.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -0,0 +1,8 @@
+#include <locks.hfa>
+
+#define LOCK fast_block_lock
+#include "mutex_test.hfa"
+
+int main() {
+    test();
+}
Index: tests/unified_locking/locks.cfa
===================================================================
--- tests/unified_locking/locks.cfa	(revision 3b80db89ad8057ef837786b049cd89765ab7a20d)
+++ tests/unified_locking/locks.cfa	(revision 00675a12696d6b64398fbee5d3706447dcef3707)
@@ -18,4 +18,7 @@
 condition_variable( linear_backoff_then_block_lock ) c_l;
 
+fast_block_lock f;
+fast_cond_var( fast_block_lock ) f_c_f;
+
 thread T_C_M_WS1 {};
 
@@ -99,4 +102,18 @@
 		}
 		unlock(l);
+	}
+}
+
+thread T_F_C_F_WS1 {};
+
+void main( T_F_C_F_WS1 & this ) {
+	for (unsigned int i = 0; i < num_times; i++) {
+		lock(f);
+		if(empty(f_c_f) && i != num_times - 1) {
+			wait(f_c_f,f);
+		}else{
+			notify_one(f_c_f);
+			unlock(f);
+		}
 	}
 }
@@ -322,3 +339,10 @@
 	}
 	printf("Done Test 12\n");
-}
+
+	printf("Start Test 13: fast block lock and fast cond var single wait/notify\n");
+	{
+		T_F_C_F_WS1 t1[2];
+	}
+	printf("Done Test 13\n");
+	
+}
