Index: Jenkinsfile
===================================================================
--- Jenkinsfile	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ Jenkinsfile	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -215,12 +215,12 @@
 
 		//Then publish the results
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'       , groupCompile    , false, 'Compilation')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff'  , groupCompile    , true , 'Compilation (relative)')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch'     , groupConcurrency, false, 'Context Switching')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff', groupConcurrency, true , 'Context Switching (relative)')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'         , groupConcurrency, false, 'Mutual Exclusion')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff'    , groupConcurrency, true , 'Mutual Exclusion (relative)')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'signal'        , groupConcurrency, false, 'Internal and External Scheduling')
-		do_plot(Settings.RunBenchmark && Settings.Publish, 'signal.diff'   , groupConcurrency, true , 'Internal and External Scheduling (relative)')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'        , groupCompile    , false, 'Compilation')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff'   , groupCompile    , true , 'Compilation (relative)')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch'      , groupConcurrency, false, 'Context Switching')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff' , groupConcurrency, true , 'Context Switching (relative)')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'          , groupConcurrency, false, 'Mutual Exclusion')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff'     , groupConcurrency, true , 'Mutual Exclusion (relative)')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling'     , groupConcurrency, false, 'Internal and External Scheduling')
+		do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling.diff', groupConcurrency, true , 'Internal and External Scheduling (relative)')
 	}
 }
Index: benchmark/Makefile.am
===================================================================
--- benchmark/Makefile.am	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ benchmark/Makefile.am	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -30,4 +30,5 @@
 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
+BENCH_V_PY = $(__bench_v_PY_$(__quiet))
 BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
 BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
@@ -47,5 +48,6 @@
 __bench_v_UPP_verbose = $(AM_V_UPP)
 __bench_v_GOC_verbose = $(AM_V_GOC)
-__bench_v_RUSTC_verbose = $(AM_V_RUSTC)
+__bench_v_PY_verbose = $(AM_V_PY)
+__bench_v_RUSTC_verbose = $(AM_V_RUST)
 __bench_v_NODEJS_verbose = $(AM_V_NODEJS)
 __bench_v_JAVAC_verbose = $(AM_V_JAVAC)
@@ -72,8 +74,7 @@
 	echo "int main() { return 0; }" > ${@}
 
-#.SILENT:		# do not print recipe
-.ONESHELL:		# use one shell to execute recipe
+.SILENT:		# do not print recipe
 .NOTPARALLEL:
-.PHONY: compile.csv basic.csv ctxswitch.csv mutex.csv schedint.csv
+.PHONY: jenkins cleancsv
 
 ## =========================================================================================================
@@ -142,31 +143,31 @@
 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
 
-jenkins$(EXEEXT):
+cleancsv:
+	rm -f compile.csv basic.csv ctxswitch.csv mutex.csv scheduling.csv
+
+jenkins$(EXEEXT): cleancsv
 @DOifskipcompile@
 	+make compile.csv
 	-+make compile.diff.csv
 @DOendif@
-	+make basic.csv
-	-+make basic.diff.csv
 	+make ctxswitch.csv
 	-+make ctxswitch.diff.csv
 	+make mutex.csv
 	-+make mutex.diff.csv
-	+make schedint.csv
-	-+make schedint.diff.csv
+	+make scheduling.csv
+	-+make scheduling.diff.csv
 @DOifskipcompile@
 	cat compile.csv
 	-cat compile.diff.csv
 @DOendif@
-	cat basic.csv
-	-cat basic.diff.csv
 	cat ctxswitch.csv
 	-cat ctxswitch.diff.csv
 	cat mutex.csv
 	-cat mutex.diff.csv
-	cat schedint.csv
-	-cat schedint.diff.csv
+	cat scheduling.csv
+	-cat scheduling.diff.csv
 
 compile.csv:
+	echo "building $@"
 	echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
 	+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
@@ -180,12 +181,6 @@
 	$(srcdir)/fixcsv.sh $@
 
-basic.csv:
-	echo "generator,coroutine,thread" > $@
-	+make basic-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
-	+make basic-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
-	+make basic-cfa_thread.runquiet >> $@
-	$(srcdir)/fixcsv.sh $@
-
 ctxswitch.csv:
+	echo "building $@"
 	echo "generator,coroutine,thread" > $@
 	+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
@@ -195,4 +190,5 @@
 
 mutex.csv:
+	echo "building $@"
 	echo "1-monitor,2-monitor" > $@
 	+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
@@ -200,5 +196,6 @@
 	$(srcdir)/fixcsv.sh $@
 
-schedint.csv:
+scheduling.csv:
+	echo "building $@"
 	echo "schedint-1,schedint-2,schedext-1,schedext-2" > $@
 	+make schedint-cfa1.runquiet >> $@ && echo -n ',' >> $@
@@ -289,15 +286,15 @@
 
 ctxswitch-python_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_PY)echo "#!/bin/sh" > a.out
 	echo "python3.7 $(srcdir)/ctxswitch/python_cor.py" >> a.out
 	chmod a+x a.out
 
 ctxswitch-nodejs_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
 	echo "nodejs $(srcdir)/ctxswitch/node_cor.js" >> a.out
 	chmod a+x a.out
 
 ctxswitch-nodejs_await$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
 	echo "nodejs $(srcdir)/ctxswitch/node_await.js" >> a.out
 	chmod a+x a.out
@@ -452,10 +449,10 @@
 
 creation-python_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_PY)echo "#!/bin/sh" > a.out
 	echo "python3.7 $(srcdir)/creation/python_cor.py" >> a.out
 	chmod a+x a.out
 
 creation-nodejs_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
 	echo "nodejs $(srcdir)/creation/node_cor.js" >> a.out
 	chmod a+x a.out
Index: benchmark/Makefile.in
===================================================================
--- benchmark/Makefile.in	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ benchmark/Makefile.in	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -368,11 +368,15 @@
 am__v_GOC_0 = @echo "  GOC     " $@;
 am__v_GOC_1 = 
+AM_V_PY = $(am__v_PY_@AM_V@)
+am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
+am__v_PY_0 = @echo "  PYTHON  " $@;
+am__v_PY_1 = 
 AM_V_RUST = $(am__v_RUST_@AM_V@)
 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
-am__v_RUST_0 = @echo "  RUST     " $@;
+am__v_RUST_0 = @echo "  RUST    " $@;
 am__v_RUST_1 = 
 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
-am__v_NODEJS_0 = @echo "  NODEJS     " $@;
+am__v_NODEJS_0 = @echo "  NODEJS  " $@;
 am__v_NODEJS_1 = 
 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
@@ -390,4 +394,5 @@
 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
+BENCH_V_PY = $(__bench_v_PY_$(__quiet))
 BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
 BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
@@ -406,5 +411,6 @@
 __bench_v_UPP_verbose = $(AM_V_UPP)
 __bench_v_GOC_verbose = $(AM_V_GOC)
-__bench_v_RUSTC_verbose = $(AM_V_RUSTC)
+__bench_v_PY_verbose = $(AM_V_PY)
+__bench_v_RUSTC_verbose = $(AM_V_RUST)
 __bench_v_NODEJS_verbose = $(AM_V_NODEJS)
 __bench_v_JAVAC_verbose = $(AM_V_JAVAC)
@@ -784,8 +790,7 @@
 	echo "int main() { return 0; }" > ${@}
 
-#.SILENT:		# do not print recipe
-.ONESHELL:		# use one shell to execute recipe
+.SILENT:		# do not print recipe
 .NOTPARALLEL:
-.PHONY: compile.csv basic.csv ctxswitch.csv mutex.csv schedint.csv
+.PHONY: jenkins cleancsv
 
 all : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
@@ -817,31 +822,31 @@
 	+make -C ${abs_top_builddir}/tools repeat
 
-jenkins$(EXEEXT):
+cleancsv:
+	rm -f compile.csv basic.csv ctxswitch.csv mutex.csv scheduling.csv
+
+jenkins$(EXEEXT): cleancsv
 @DOifskipcompile@
 	+make compile.csv
 	-+make compile.diff.csv
 @DOendif@
-	+make basic.csv
-	-+make basic.diff.csv
 	+make ctxswitch.csv
 	-+make ctxswitch.diff.csv
 	+make mutex.csv
 	-+make mutex.diff.csv
-	+make schedint.csv
-	-+make schedint.diff.csv
+	+make scheduling.csv
+	-+make scheduling.diff.csv
 @DOifskipcompile@
 	cat compile.csv
 	-cat compile.diff.csv
 @DOendif@
-	cat basic.csv
-	-cat basic.diff.csv
 	cat ctxswitch.csv
 	-cat ctxswitch.diff.csv
 	cat mutex.csv
 	-cat mutex.diff.csv
-	cat schedint.csv
-	-cat schedint.diff.csv
+	cat scheduling.csv
+	-cat scheduling.diff.csv
 
 compile.csv:
+	echo "building $@"
 	echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
 	+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
@@ -855,12 +860,6 @@
 	$(srcdir)/fixcsv.sh $@
 
-basic.csv:
-	echo "generator,coroutine,thread" > $@
-	+make basic-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
-	+make basic-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
-	+make basic-cfa_thread.runquiet >> $@
-	$(srcdir)/fixcsv.sh $@
-
 ctxswitch.csv:
+	echo "building $@"
 	echo "generator,coroutine,thread" > $@
 	+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
@@ -870,4 +869,5 @@
 
 mutex.csv:
+	echo "building $@"
 	echo "1-monitor,2-monitor" > $@
 	+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
@@ -875,5 +875,6 @@
 	$(srcdir)/fixcsv.sh $@
 
-schedint.csv:
+scheduling.csv:
+	echo "building $@"
 	echo "schedint-1,schedint-2,schedext-1,schedext-2" > $@
 	+make schedint-cfa1.runquiet >> $@ && echo -n ',' >> $@
@@ -931,15 +932,15 @@
 
 ctxswitch-python_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_PY)echo "#!/bin/sh" > a.out
 	echo "python3.7 $(srcdir)/ctxswitch/python_cor.py" >> a.out
 	chmod a+x a.out
 
 ctxswitch-nodejs_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
 	echo "nodejs $(srcdir)/ctxswitch/node_cor.js" >> a.out
 	chmod a+x a.out
 
 ctxswitch-nodejs_await$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
 	echo "nodejs $(srcdir)/ctxswitch/node_await.js" >> a.out
 	chmod a+x a.out
@@ -1085,10 +1086,10 @@
 
 creation-python_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_PY)echo "#!/bin/sh" > a.out
 	echo "python3.7 $(srcdir)/creation/python_cor.py" >> a.out
 	chmod a+x a.out
 
 creation-nodejs_coroutine$(EXEEXT):
-	echo "#!/bin/sh" > a.out
+	$(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
 	echo "nodejs $(srcdir)/creation/node_cor.js" >> a.out
 	chmod a+x a.out
Index: benchmark/baselines/x64/schedint.csv
===================================================================
--- benchmark/baselines/x64/schedint.csv	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ benchmark/baselines/x64/schedint.csv	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,2 @@
+schedext-2,schedint-1,schedint-2,schedext-1
+393.69606249999987,325.99158333333327,409.01025000000004,319.90975000000003
Index: nchmark/baselines/x64/signal.csv
===================================================================
--- benchmark/baselines/x64/signal.csv	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,2 +1,0 @@
-waitfor-2,signal-1,signal-2,waitfor-1
-393.69606249999987,325.99158333333327,409.01025000000004,319.90975000000003
Index: benchmark/baselines/x86/schedint.csv
===================================================================
--- benchmark/baselines/x86/schedint.csv	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ benchmark/baselines/x86/schedint.csv	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,2 @@
+schedint-2,schedext-1,schedext-2,schedint-1
+532.5297959183672,413.3084897959184,506.7579591836735,423.78826530612247
Index: nchmark/baselines/x86/signal.csv
===================================================================
--- benchmark/baselines/x86/signal.csv	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,2 +1,0 @@
-signal-2,waitfor-1,waitfor-2,signal-1
-532.5297959183672,413.3084897959184,506.7579591836735,423.78826530612247
Index: doc/papers/ibm_CASCON19/ThreadingModels.fig
===================================================================
--- doc/papers/ibm_CASCON19/ThreadingModels.fig	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/papers/ibm_CASCON19/ThreadingModels.fig	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,140 @@
+#FIG 3.2  Produced by xfig version 3.2.5b
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2700 3300 150 150 2700 3300 2850 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3150 3300 150 150 3150 3300 3300 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4050 3300 150 150 4050 3300 4200 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4500 3300 150 150 4500 3300 4650 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4950 3300 150 150 4950 3300 5100 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 5400 3300 150 150 5400 3300 5550 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 5850 3300 150 150 5850 3300 6000 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3600 3300 150 150 3600 3300 3750 3300
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 6450 3150 100 100 6450 3150 6550 3150
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 1800 2175 150 150 1800 2175 1950 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 3000 2175 150 150 3000 2175 3150 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 3450 2175 150 150 3450 2175 3600 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 3900 2175 150 150 3900 2175 4050 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 5100 2175 150 150 5100 2175 5250 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 6300 2175 150 150 6300 2175 6450 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 6750 2175 150 150 6750 2175 6900 2175
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 7200 2175 150 150 7200 2175 7350 2175
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 1800 2175 100 100 1800 2175 1900 2175
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 3000 2175 100 100 3000 2175 3100 2175
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 3450 2175 100 100 3450 2175 3550 2175
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 3900 2175 100 100 3900 2175 4000 2175
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 4650 1425 100 100 4650 1425 4750 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 4950 1425 100 100 4950 1425 5050 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 5250 1425 100 100 5250 1425 5350 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 5550 1425 100 100 5550 1425 5650 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 6300 1425 100 100 6300 1425 6400 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 6600 1425 100 100 6600 1425 6700 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 6900 1425 100 100 6900 1425 7000 1425
+1 3 0 1 0 7 50 -1 15 0.000 1 0.0000 7200 1425 100 100 7200 1425 7300 1425
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 6450 3600 150 150 6450 3600 6600 3600
+1 3 1 1 0 7 50 -1 -1 4.000 1 0.0000 6450 3600 100 100 6450 3600 6550 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1800 2175 2700 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3000 2175 3150 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3450 2175 3600 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3900 2175 4050 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4500 3300 5100 2175
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4950 3300 6300 2175
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5400 3300 6750 2175
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5850 3300 7200 2175
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2775 3450 3825 3675
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3225 3450 3900 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3675 3450 4050 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4125 3450 4200 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4500 3450 4350 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4950 3450 4500 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5400 3450 4650 3600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5850 3450 4725 3675
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3825 3750 3375 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4200 3750 3975 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4350 3750 4575 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 3750 5175 3900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3225 3900 3525 3900 3525 4200 3225 4200 3225 3900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3825 3900 4125 3900 4125 4200 3825 4200 3825 3900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4425 3900 4725 3900 4725 4200 4425 4200 4425 3900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5025 3900 5325 3900 5325 4200 5025 4200 5025 3900
+2 2 0 2 4 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 3000 6150 3000 6150 4350 2400 4350 2400 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6300 3975 6600 3975 6600 4275 6300 4275 6300 3975
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4950 1500 5100 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5250 1500 5100 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 1500 4875 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5550 1500 5325 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5100 1800 5100 2025
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 1500 6750 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6900 1500 6750 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6300 1500 6525 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 1500 6975 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6750 1800 6750 2025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 1275 5700 1275 5700 2400 4500 2400 4500 1275
+2 2 0 2 4 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 1275 7500 1275 7500 2400 6000 2400 6000 1275
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1275 4200 1275 4200 2400 2700 2400 2700 1275
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1275 2400 1275 2400 2400 1200 2400 1200 1275
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 1800 6300 2025
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6900 1800 7200 2025
+4 1 0 50 -1 0 12 0.0000 2 135 435 1800 2775 1:1:4\001
+4 1 0 50 -1 0 12 0.0000 2 135 435 3450 2775 3:3:4\001
+4 1 0 50 -1 0 12 0.0000 2 135 435 5100 2775 4:1:4\001
+4 1 0 50 -1 0 12 0.0000 2 135 435 6750 2775 4:3:4\001
+4 2 0 50 -1 0 12 0.0000 2 180 585 2250 3975 System\001
+4 2 0 50 -1 0 12 0.0000 2 180 810 2250 3750 Operating\001
+4 1 0 50 -1 0 12 0.0000 2 135 780 4275 3750 scheduler\001
+4 0 0 50 -1 0 12 0.0000 2 135 885 6750 3225 user thread\001
+4 0 0 50 -1 0 12 0.0000 2 135 1065 6750 3675 kernel thread\001
+4 0 0 50 -1 0 12 0.0000 2 135 375 6750 4200 CPU\001
+4 1 0 50 -1 0 12 0.0000 2 180 1020 1800 1200 Process$_1$\001
+4 1 0 50 -1 0 12 0.0000 2 180 1020 3450 1200 Process$_2$\001
+4 1 0 50 -1 0 12 0.0000 2 180 1020 5100 1200 Process$_3$\001
+4 1 0 50 -1 0 12 0.0000 2 180 1020 6750 1200 Process$_4$\001
+4 1 0 50 -1 0 11 0.0000 2 120 675 5100 1800 scheduler\001
+4 1 0 50 -1 0 11 0.0000 2 120 675 6750 1800 scheduler\001
Index: doc/papers/ibm_CASCON19/ThreadingModels.svg
===================================================================
--- doc/papers/ibm_CASCON19/ThreadingModels.svg	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/papers/ibm_CASCON19/ThreadingModels.svg	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,683 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.1"
+   id="svg4438"
+   viewBox="1188 1041 6669 3331"
+   height="2.8in"
+   width="5.6in">
+  <metadata
+     id="metadata4640">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4638" />
+  <g
+     transform="translate(185.25001,-26.464286)"
+     id="g4440"
+     style="fill:none;stroke-width:0.025in">
+    <!-- Circle -->
+    <circle
+       id="circle4442"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="2700" />
+    <!-- Circle -->
+    <circle
+       id="circle4444"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="3150" />
+    <!-- Circle -->
+    <circle
+       id="circle4446"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="4050" />
+    <!-- Circle -->
+    <circle
+       id="circle4448"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="4500" />
+    <!-- Circle -->
+    <circle
+       id="circle4450"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="4950" />
+    <!-- Circle -->
+    <circle
+       id="circle4452"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="5400" />
+    <!-- Circle -->
+    <circle
+       id="circle4454"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="5850" />
+    <!-- Circle -->
+    <circle
+       id="circle4456"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3300"
+       cx="3600" />
+    <!-- Circle -->
+    <circle
+       id="circle4458"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="3150"
+       cx="6450" />
+    <!-- Circle -->
+    <circle
+       id="circle4460"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="1800" />
+    <!-- Circle -->
+    <circle
+       id="circle4462"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="3000" />
+    <!-- Circle -->
+    <circle
+       id="circle4464"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="3450" />
+    <!-- Circle -->
+    <circle
+       id="circle4466"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="3900" />
+    <!-- Circle -->
+    <circle
+       id="circle4468"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="5100" />
+    <!-- Circle -->
+    <circle
+       id="circle4470"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="6300" />
+    <!-- Circle -->
+    <circle
+       id="circle4472"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="6750" />
+    <!-- Circle -->
+    <circle
+       id="circle4474"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="150"
+       cy="2175"
+       cx="7200" />
+    <!-- Circle -->
+    <circle
+       id="circle4476"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="2175"
+       cx="1800" />
+    <!-- Circle -->
+    <circle
+       id="circle4478"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="2175"
+       cx="3000" />
+    <!-- Circle -->
+    <circle
+       id="circle4480"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="2175"
+       cx="3450" />
+    <!-- Circle -->
+    <circle
+       id="circle4482"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="2175"
+       cx="3900" />
+    <!-- Circle -->
+    <circle
+       id="circle4484"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="4650" />
+    <!-- Circle -->
+    <circle
+       id="circle4486"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="4950" />
+    <!-- Circle -->
+    <circle
+       id="circle4488"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="5250" />
+    <!-- Circle -->
+    <circle
+       id="circle4490"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="5550" />
+    <!-- Circle -->
+    <circle
+       id="circle4492"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="6300" />
+    <!-- Circle -->
+    <circle
+       id="circle4494"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="6600" />
+    <!-- Circle -->
+    <circle
+       id="circle4496"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="6900" />
+    <!-- Circle -->
+    <circle
+       id="circle4498"
+       style="fill:#bfbfbf;stroke:#000000;stroke-width:7"
+       r="100"
+       cy="1425"
+       cx="7200" />
+    <!-- Circle -->
+    <circle
+       id="circle4500"
+       style="stroke:#000000;stroke-width:7"
+       r="150"
+       cy="3600"
+       cx="6450" />
+    <!-- Circle -->
+    <circle
+       id="circle4502"
+       style="stroke:#000000;stroke-width:7;stroke-dasharray:40, 40"
+       r="100"
+       cy="3600"
+       cx="6450" />
+    <!-- Line -->
+    <polyline
+       id="polyline4504"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="1800,2175 2700,3300 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4506"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="3000,2175 3150,3300 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4508"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="3450,2175 3600,3300 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4510"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="3900,2175 4050,3300 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4512"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4500,3300 5100,2175 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4514"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4950,3300 6300,2175 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4516"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5400,3300 6750,2175 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4518"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5850,3300 7200,2175 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4520"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="2775,3450 3825,3675 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4522"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="3225,3450 3900,3600 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4524"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="3675,3450 4050,3600 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4526"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4125,3450 4200,3600 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4528"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4500,3450 4350,3600 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4530"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4950,3450 4500,3600 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4532"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5400,3450 4650,3600 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4534"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5850,3450 4725,3675 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4536"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="3825,3750 3375,3900 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4538"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4200,3750 3975,3900 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4540"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4350,3750 4575,3900 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4542"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4650,3750 5175,3900 " />
+    <!-- Line: box -->
+    <rect
+       id="rect4544"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="300"
+       width="300"
+       y="3900"
+       x="3225" />
+    <!-- Line: box -->
+    <rect
+       id="rect4546"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="300"
+       width="300"
+       y="3900"
+       x="3825" />
+    <!-- Line: box -->
+    <rect
+       id="rect4548"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="300"
+       width="300"
+       y="3900"
+       x="4425" />
+    <!-- Line: box -->
+    <rect
+       id="rect4550"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="300"
+       width="300"
+       y="3900"
+       x="5025" />
+    <!-- Line: box -->
+    <rect
+       id="rect4552"
+       style="stroke:#ff0000;stroke-width:15;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1350"
+       width="3750"
+       y="3000"
+       x="2400" />
+    <!-- Line: box -->
+    <rect
+       id="rect4554"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="300"
+       width="300"
+       y="3975"
+       x="6300" />
+    <!-- Line -->
+    <polyline
+       id="polyline4556"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4950,1500 5100,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4558"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5250,1500 5100,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4560"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="4650,1500 4875,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4562"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5550,1500 5325,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4564"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="5100,1800 5100,2025 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4566"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="6600,1500 6750,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4568"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="6900,1500 6750,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4570"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="6300,1500 6525,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4572"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="7200,1500 6975,1650 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4574"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="6750,1800 6750,2025 " />
+    <!-- Line: box -->
+    <rect
+       id="rect4576"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1125"
+       width="1200"
+       y="1275"
+       x="4500" />
+    <!-- Line: box -->
+    <rect
+       id="rect4578"
+       style="stroke:#ff0000;stroke-width:15;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1125"
+       width="1500"
+       y="1275"
+       x="6000" />
+    <!-- Line: box -->
+    <rect
+       id="rect4580"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1125"
+       width="1500"
+       y="1275"
+       x="2700" />
+    <!-- Line: box -->
+    <rect
+       id="rect4582"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1125"
+       width="1200"
+       y="1275"
+       x="1200" />
+    <!-- Line -->
+    <polyline
+       id="polyline4584"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="6600,1800 6300,2025 " />
+    <!-- Line -->
+    <polyline
+       id="polyline4586"
+       style="stroke:#000000;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter"
+       points="6900,1800 7200,2025 " />
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4588"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="2775"
+       x="1800"
+       xml:space="preserve">1:1</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4590"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="2775"
+       x="3450"
+       xml:space="preserve">3:3</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4592"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="2775"
+       x="5100"
+       xml:space="preserve">4:1</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4594"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="2775"
+       x="6750"
+       xml:space="preserve">4:3</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:end;fill:#000000"
+       id="text4596"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="3975"
+       x="2250"
+       xml:space="preserve">System</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:end;fill:#000000"
+       id="text4598"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="3750"
+       x="2250"
+       xml:space="preserve">Operating</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4600"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="3750"
+       x="4275"
+       xml:space="preserve">scheduler</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:start;fill:#000000"
+       id="text4602"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="3225"
+       x="6750"
+       xml:space="preserve">user thread</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:start;fill:#000000"
+       id="text4604"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="3675"
+       x="6750"
+       xml:space="preserve">kernel thread</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:start;fill:#000000"
+       id="text4606"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="4200"
+       x="6750"
+       xml:space="preserve">CPU</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4608"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="1200"
+       x="1800"
+       xml:space="preserve">Process<tspan
+   style="font-size:96px"
+   id="tspan4610"
+   dy="35"
+   font-size="96">1</tspan><tspan
+   id="tspan4612"
+   dy="-35" /></text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4614"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="1200"
+       x="3450"
+       xml:space="preserve">Process<tspan
+   style="font-size:96px"
+   id="tspan4616"
+   dy="35"
+   font-size="96">2</tspan><tspan
+   id="tspan4618"
+   dy="-35" /></text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4620"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="1200"
+       x="5100"
+       xml:space="preserve">Process<tspan
+   style="font-size:96px"
+   id="tspan4622"
+   dy="35"
+   font-size="96">3</tspan><tspan
+   id="tspan4624"
+   dy="-35" /></text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:144px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4626"
+       font-size="144"
+       font-weight="normal"
+       font-style="normal"
+       y="1200"
+       x="6750"
+       xml:space="preserve">Process<tspan
+   style="font-size:96px"
+   id="tspan4628"
+   dy="35"
+   font-size="96">4</tspan><tspan
+   id="tspan4630"
+   dy="-35" /></text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:132px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4632"
+       font-size="132"
+       font-weight="normal"
+       font-style="normal"
+       y="1800"
+       x="5100"
+       xml:space="preserve">scheduler</text>
+    <!-- Text -->
+    <text
+       style="font-style:normal;font-weight:normal;font-size:132px;font-family:Times;text-anchor:middle;fill:#000000"
+       id="text4634"
+       font-size="132"
+       font-weight="normal"
+       font-style="normal"
+       y="1800"
+       x="6750"
+       xml:space="preserve">scheduler</text>
+  </g>
+</svg>
Index: doc/papers/ibm_CASCON19/abstract.txt
===================================================================
--- doc/papers/ibm_CASCON19/abstract.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/papers/ibm_CASCON19/abstract.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,40 @@
+Synchronous Programming with User-Level Threads in C∀
+
+When computations cannot be satisfied immediately, programmers must use
+one of two paradigms, Synchronous Programming and Asynchronous Programming.
+This presentation discusses the benefits Synchronous Programming over
+Asynchronous Programming and what requirements exist to use this paradigm.
+It also discusses how C∀, a concurrent and backwards-compatible extension
+of the C programming language, has powerful tools available for simple and
+efficient Synchronous Programming. These tools include user-level threads
+and high-level locking mechanisms which simply solve common problems.
+Finally, the presentation shows different techniques to combine these
+features with existing code to either uses blocking operations provided by
+the kernel or is built according to an asynchronous paradigm.
+
+
+
+
+
+
+
+
+
+C∀ is a polymorphic, non-object-oriented, concurrent, backwards-compatible
+extension of the C programming language. This paper discusses the design
+philosophy and implementation of its advanced control-flow and concurrent/parallel
+features, along with the supporting runtime written in C∀. These features
+are created from scratch as ISO C has only low-level and/or unimplemented
+concurrency, so C programmers continue to rely on library features like pthreads.
+C∀ introduces modern language-level control-flow mechanisms, like generators,
+coroutines, user-level threading, and monitors for mutual exclusion and
+synchronization. The runtime provides significant programmer simplification
+and safety by eliminating spurious wakeup and monitor barging. The runtime
+also ensures multiple monitors can be safely acquired simultaneously (deadlock free),
+and this feature is fully integrated with all monitor synchronization mechanisms.
+All control-flow features integrate with the C∀ polymorphic type-system and
+exception handling, while respecting the expectations and style of C programmers.
+Experimental results show comparable performance of the new features with similar
+mechanisms in other concurrent programming languages.
+KEYWORDS
+generator, coroutine, concurrency, parallelism, thread, monitor, runtime, C, C∀ (Cforall)
Index: doc/papers/ibm_CASCON19/client.cfa
===================================================================
--- doc/papers/ibm_CASCON19/client.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/papers/ibm_CASCON19/client.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,63 @@
+// Original
+void sum_many_async(int[] inputs, lambda_t callback);
+
+// Target
+int  sum_many      (int[] inputs);
+
+//==================================
+
+int  sum_many(int[] inputs) {
+	// setup required data
+	int result;
+	semaphore_t sem = { 0 };
+
+	// call async function
+	sum_many_async( inputs, (int sum) {
+		result = sum;
+		V(sem);
+	});
+
+	// wait for result
+	P(sem);
+
+	// return
+	return result;
+}
+
+
+int sum_many_block(int[] inputs);
+int sum_many      (int[] inputs);
+
+//==================================
+
+struct request_t {
+	int[] inputs;
+	int result;
+	semaphore_t sem = { 0 };
+};
+
+void * call_sum_many_block(void * args) {
+	request_t * req = (request_t *) args;
+	req->result = sum_many_block(req->inputs);
+	V(req->sem);
+}
+
+int  sum_many(int[] inputs) {
+	// setup required data
+	request_t req = { inputs };
+
+	// create thread to
+	pthread_t thrd;
+	int err = pthread_fork(&thrd, 0p, call_sum_many_block, &req);
+	handle(err);
+
+	// wait
+	P(req.sem);
+
+	// Cleanup pthread
+	err = pthread_join(&thrd, 0p);
+	handle(err);
+
+	// get result
+	return req.result;
+}
Index: doc/papers/ibm_CASCON19/server.cfa
===================================================================
--- doc/papers/ibm_CASCON19/server.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/papers/ibm_CASCON19/server.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,13 @@
+
+
+volatile bool shutdown = false;
+
+large_compute_async(unsigned code, int lhs, int rhs, lambda_t callback);
+
+
+void main() {
+	while(!shutdown) {
+
+
+	}
+}
Index: doc/theses/thierry_delisle_PhD/.gitignore
===================================================================
--- doc/theses/thierry_delisle_PhD/.gitignore	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/.gitignore	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,13 @@
+*/a.out
+
+code/*.s
+code/relaxed_list
+code/layout.ast
+code/build/
+code/raw/
+
+comp_II/build/
+comp_II/comp_II.pdf
+comp_II/comp_II.ps
+
+!Makefile
Index: doc/theses/thierry_delisle_PhD/code/Makefile
===================================================================
--- doc/theses/thierry_delisle_PhD/code/Makefile	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/code/Makefile	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,22 @@
+
+
+CXXFLAGS = -O3 -g -Wall -Wextra -std=c++17
+LDFLAGS = -pthread -latomic
+
+push:
+	clang++ relaxed_list.cpp -g -Wall -Wextra -std=c++17 -fsyntax-only &&  rsync -av relaxed_list.cpp relaxed_list.hpp utils.hpp assert.hpp scale.sh plg7b:~/workspace/sched/.
+
+relaxed_list: $(firstword $(MAKEFILE_LIST)) | build
+	clang++ relaxed_list.cpp $(CXXFLAGS) $(LDFLAGS) -lpng -MMD -MF build/$(@).d -o $(@)
+
+-include build/relaxed_list.d
+
+layout.ast: $(firstword $(MAKEFILE_LIST)) | build
+	clang++ relaxed_list_layout.cpp $(CXXFLAGS) -MMD -MF build/$(@).d -MT $(@) -E -o build/$(@).ii
+	clang++ -Xclang -fdump-record-layouts -fsyntax-only $(CXXFLAGS) build/$(@).ii > build/layout.ast.raw
+	cat build/$(@).raw > $(@)
+
+-include build/layout.ast.d
+
+build:
+	mkdir -p build
Index: doc/theses/thierry_delisle_PhD/code/bts_test.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/bts_test.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/code/bts_test.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,32 @@
+#include <cassert>
+#include <iostream>
+
+bool bts(volatile size_t & target, size_t bit ) {
+	bool result = false;
+	asm volatile(
+		"LOCK btsq %[bit], %[target]\n\t"
+		:"=c" (result)
+		: [target] "m" (target), [bit] "r" (bit)
+	);
+ 	return result;
+}
+
+bool btr(volatile size_t & target, size_t bit ) {
+	bool result = false;
+	asm volatile(
+		"LOCK btrq %[bit], %[target]\n\t"
+		:"=c" (result)
+		: [target] "m" (target), [bit] "r" (bit)
+	);
+ 	return result;
+}
+
+int main() {
+	volatile size_t i = 0;
+	std::cout << std::hex << i << std::endl;
+	assert(bts(i, 31));
+	std::cout << std::hex << i << std::endl;
+	assert(btr(i, 31));
+	std::cout << std::hex << i << std::endl;
+	return 0;
+}
Index: doc/theses/thierry_delisle_PhD/code/randbit.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/randbit.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/code/randbit.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,236 @@
+#include <cstddef>
+#include <cstdint>
+#include <x86intrin.h>
+
+__attribute__((noinline)) unsigned nthSetBit(size_t mask, unsigned bit) {
+	uint64_t v = mask;   // Input value to find position with rank r.
+	unsigned int r = bit;// Input: bit's desired rank [1-64].
+	unsigned int s;      // Output: Resulting position of bit with rank r [1-64]
+	uint64_t a, b, c, d; // Intermediate temporaries for bit count.
+	unsigned int t;      // Bit count temporary.
+
+	// Do a normal parallel bit count for a 64-bit integer,
+	// but store all intermediate steps.
+	// a = (v & 0x5555...) + ((v >> 1) & 0x5555...);
+	a =  v - ((v >> 1) & ~0UL/3);
+	// b = (a & 0x3333...) + ((a >> 2) & 0x3333...);
+	b = (a & ~0UL/5) + ((a >> 2) & ~0UL/5);
+	// c = (b & 0x0f0f...) + ((b >> 4) & 0x0f0f...);
+	c = (b + (b >> 4)) & ~0UL/0x11;
+	// d = (c & 0x00ff...) + ((c >> 8) & 0x00ff...);
+	d = (c + (c >> 8)) & ~0UL/0x101;
+
+
+	t = (d >> 32) + (d >> 48);
+	// Now do branchless select!
+	s  = 64;
+	// if (r > t) {s -= 32; r -= t;}
+	s -= ((t - r) & 256) >> 3; r -= (t & ((t - r) >> 8));
+	t  = (d >> (s - 16)) & 0xff;
+	// if (r > t) {s -= 16; r -= t;}
+	s -= ((t - r) & 256) >> 4; r -= (t & ((t - r) >> 8));
+	t  = (c >> (s - 8)) & 0xf;
+	// if (r > t) {s -= 8; r -= t;}
+	s -= ((t - r) & 256) >> 5; r -= (t & ((t - r) >> 8));
+	t  = (b >> (s - 4)) & 0x7;
+	// if (r > t) {s -= 4; r -= t;}
+	s -= ((t - r) & 256) >> 6; r -= (t & ((t - r) >> 8));
+	t  = (a >> (s - 2)) & 0x3;
+	// if (r > t) {s -= 2; r -= t;}
+	s -= ((t - r) & 256) >> 7; r -= (t & ((t - r) >> 8));
+	t  = (v >> (s - 1)) & 0x1;
+	// if (r > t) s--;
+	s -= ((t - r) & 256) >> 8;
+	// s = 65 - s;
+	return s;
+}
+
+unsigned rand_bit(unsigned rnum, uint64_t mask) {
+	unsigned bit = mask ? rnum % __builtin_popcountl(mask) : 0;
+#if defined(BRANCHLESS)
+	uint64_t v = mask;   // Input value to find position with rank r.
+	unsigned int r = bit + 1;// Input: bit's desired rank [1-64].
+	unsigned int s;      // Output: Resulting position of bit with rank r [1-64]
+	uint64_t a, b, c, d; // Intermediate temporaries for bit count.
+	unsigned int t;      // Bit count temporary.
+
+	// Do a normal parallel bit count for a 64-bit integer,
+	// but store all intermediate steps.
+	// a = (v & 0x5555...) + ((v >> 1) & 0x5555...);
+	a =  v - ((v >> 1) & ~0UL/3);
+	// b = (a & 0x3333...) + ((a >> 2) & 0x3333...);
+	b = (a & ~0UL/5) + ((a >> 2) & ~0UL/5);
+	// c = (b & 0x0f0f...) + ((b >> 4) & 0x0f0f...);
+	c = (b + (b >> 4)) & ~0UL/0x11;
+	// d = (c & 0x00ff...) + ((c >> 8) & 0x00ff...);
+	d = (c + (c >> 8)) & ~0UL/0x101;
+
+
+	t = (d >> 32) + (d >> 48);
+	// Now do branchless select!
+	s  = 64;
+	// if (r > t) {s -= 32; r -= t;}
+	s -= ((t - r) & 256) >> 3; r -= (t & ((t - r) >> 8));
+	t  = (d >> (s - 16)) & 0xff;
+	// if (r > t) {s -= 16; r -= t;}
+	s -= ((t - r) & 256) >> 4; r -= (t & ((t - r) >> 8));
+	t  = (c >> (s - 8)) & 0xf;
+	// if (r > t) {s -= 8; r -= t;}
+	s -= ((t - r) & 256) >> 5; r -= (t & ((t - r) >> 8));
+	t  = (b >> (s - 4)) & 0x7;
+	// if (r > t) {s -= 4; r -= t;}
+	s -= ((t - r) & 256) >> 6; r -= (t & ((t - r) >> 8));
+	t  = (a >> (s - 2)) & 0x3;
+	// if (r > t) {s -= 2; r -= t;}
+	s -= ((t - r) & 256) >> 7; r -= (t & ((t - r) >> 8));
+	t  = (v >> (s - 1)) & 0x1;
+	// if (r > t) s--;
+	s -= ((t - r) & 256) >> 8;
+	// s = 65 - s;
+	return s - 1;
+#elif defined(LOOP)
+	for(unsigned i = 0; i < bit; i++) {
+		mask ^= (1ul << (__builtin_ffsl(mask) - 1ul));
+	}
+	return __builtin_ffsl(mask) - 1ul;
+#elif defined(PDEP)
+	uint64_t picked = _pdep_u64(1ul << bit, mask);
+	return __builtin_ffsl(picked) - 1ul;
+#else
+#error must define LOOP, PDEP or BRANCHLESS
+#endif
+}
+
+#include <cassert>
+#include <atomic>
+#include <chrono>
+#include <iomanip>
+#include <iostream>
+#include <locale>
+#include <thread>
+
+#include <unistd.h>
+
+class barrier_t {
+public:
+	barrier_t(size_t total)
+		: waiting(0)
+		, total(total)
+	{}
+
+	void wait(unsigned) {
+		size_t target = waiting++;
+		target = (target - (target % total)) + total;
+		while(waiting < target)
+			asm volatile("pause");
+
+		assert(waiting < (1ul << 60));
+    	}
+
+private:
+	std::atomic<size_t> waiting;
+	size_t total;
+};
+
+class Random {
+private:
+	unsigned int seed;
+public:
+	Random(int seed) {
+		this->seed = seed;
+	}
+
+	/** returns pseudorandom x satisfying 0 <= x < n. **/
+	unsigned int next() {
+		seed ^= seed << 6;
+		seed ^= seed >> 21;
+		seed ^= seed << 7;
+		return seed;
+    	}
+};
+
+using Clock = std::chrono::high_resolution_clock;
+using duration_t = std::chrono::duration<double>;
+using std::chrono::nanoseconds;
+
+template<typename Ratio, typename T>
+T duration_cast(T seconds) {
+	return std::chrono::duration_cast<std::chrono::duration<T, Ratio>>(std::chrono::duration<T>(seconds)).count();
+}
+
+void waitfor(double & duration, barrier_t & barrier, std::atomic_bool & done) {
+
+
+	std::cout << "Starting" << std::endl;
+	auto before = Clock::now();
+	barrier.wait(0);
+
+	while(true) {
+		usleep(100000);
+		auto now = Clock::now();
+		duration_t durr = now - before;
+		if( durr.count() > duration ) {
+			done = true;
+			break;
+		}
+		std::cout << "\r" << std::setprecision(4) << durr.count();
+		std::cout.flush();
+	}
+
+	barrier.wait(0);
+	auto after = Clock::now();
+	duration_t durr = after - before;
+	duration = durr.count();
+	std::cout << "\rClosing down" << std::endl;
+}
+
+__attribute__((noinline)) void body(Random & rand) {
+	uint64_t mask = (uint64_t(rand.next()) << 32ul) | uint64_t(rand.next());
+	unsigned idx = rand.next();
+
+	unsigned bit = rand_bit(idx, mask);
+
+	if(__builtin_expect(((1ul << bit) & mask) == 0, false)) {
+		std::cerr << std::hex <<  "Rand " << idx << " from " << mask;
+		std::cerr << " gave " << (1ul << bit) << "(" << std::dec << bit << ")" << std::endl;
+		std::abort();
+	}
+}
+
+void runRandBit(double duration) {
+
+	std::atomic_bool done  = { false };
+	barrier_t barrier(2);
+
+	size_t count = 0;
+	std::thread thread([&done, &barrier, &count]() {
+
+		Random rand(22);
+
+		barrier.wait(1);
+
+		for(;!done; count++) {
+			body(rand);
+		}
+
+		barrier.wait(1);
+	});
+
+	waitfor(duration, barrier, done);
+	thread.join();
+
+	size_t ops = count;
+	size_t ops_sec = size_t(double(ops) / duration);
+	auto dur_nano = duration_cast<std::nano>(1.0);
+
+	std::cout << "Duration      : " << duration << "s\n";
+	std::cout << "ns/Op         : " << ( dur_nano / ops )<< "\n";
+	std::cout << "Ops/sec       : " << ops_sec << "\n";
+	std::cout << "Total ops     : " << ops << std::endl;
+
+}
+
+int main() {
+	std::cout.imbue(std::locale(""));
+	runRandBit(5);
+}
Index: doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -9,4 +9,5 @@
 #include <vector>
 
+#include <getopt.h>
 #include <unistd.h>
 #include <sys/sysinfo.h>
@@ -21,11 +22,9 @@
 
 	int value;
-	Node(int value): value(value) {
-		creates++;
-	}
-
-	~Node() {
-		destroys++;
-	}
+	int id;
+
+	Node() { creates++; }
+	Node(int value): value(value) { creates++; }
+	~Node() { destroys++; }
 };
 
@@ -33,11 +32,20 @@
 std::atomic_size_t Node::destroys = { 0 };
 
-static const constexpr int nodes_per_threads = 128;
-struct NodeArray {
-	__attribute__((aligned(64))) Node * array[nodes_per_threads];
-	__attribute__((aligned(64))) char pad;
-};
-
 bool enable_stats = false;
+
+template<>
+thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
+
+template<>
+relaxed_list<Node> * relaxed_list<Node>::head = nullptr;
+
+#ifndef NO_STATS
+template<>
+relaxed_list<Node>::GlobalStats relaxed_list<Node>::global_stats = {};
+#endif
+
+// ================================================================================================
+//                        UTILS
+// ================================================================================================
 
 struct local_stat_t {
@@ -47,132 +55,52 @@
 	size_t crc_in  = 0;
 	size_t crc_out = 0;
+	size_t valmax = 0;
+	size_t valmin = 100000000ul;
 };
 
-__attribute__((noinline)) void run_body(
-	std::atomic<bool>& done,
-	Random & rand,
-	Node * (&my_nodes)[128],
-	local_stat_t & local,
-	relaxed_list<Node> & list
-) {
-	while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
-		int idx = rand.next() % nodes_per_threads;
-		if (auto node = my_nodes[idx]) {
-			local.crc_in += node->value;
-			list.push(node);
-			my_nodes[idx] = nullptr;
-			local.in++;
-		}
-		else if(auto node = list.pop()) {
-			local.crc_out += node->value;
-			my_nodes[idx] = node;
-			local.out++;
-		}
-		else {
-			local.empty++;
-		}
-	}
-}
-
-void run(unsigned nthread, unsigned nqueues, unsigned fill, double duration) {
-	// List being tested
-	relaxed_list<Node> list = { nthread * nqueues };
-
-	// Barrier for synchronization
-	barrier_t barrier(nthread + 1);
-
-	// Data to check everything is OK
-	struct {
-		std::atomic_size_t in  = { 0 };
-		std::atomic_size_t out = { 0 };
-		std::atomic_size_t empty = { 0 };
-		std::atomic_size_t crc_in  = { 0 };
-		std::atomic_size_t crc_out = { 0 };
-		struct {
-			struct {
-				std::atomic_size_t attempt = { 0 };
-				std::atomic_size_t success = { 0 };
-			} push;
-			struct {
-				std::atomic_size_t attempt = { 0 };
-				std::atomic_size_t success = { 0 };
-			} pop;
-		} pick;
-	} global;
-
-	// Flag to signal termination
-	std::atomic_bool done  = { false };
-
-	// Prep nodes
-	std::cout << "Initializing ";
-	size_t nnodes  = 0;
-	size_t npushed = 0;
-	NodeArray all_nodes[nthread];
-	for(auto & nodes : all_nodes) {
-		Random rand(rdtscl());
-		for(auto & node : nodes.array) {
-			auto r = rand.next() % 100;
-			if(r < fill) {
-				node = new Node(rand.next() % 100);
-				nnodes++;
-			} else {
-				node = nullptr;
-			}
-		}
-
-		for(int i = 0; i < 10; i++) {
-			int idx = rand.next() % nodes_per_threads;
-			if (auto node = nodes.array[idx]) {
-				global.crc_in += node->value;
-				list.push(node);
-				npushed++;
-				nodes.array[idx] = nullptr;
-			}
-		}
-	}
-
-	std::cout << nnodes << " nodes " << fill << "% (" << npushed << " pushed)" << std::endl;
-
-	enable_stats = true;
-
-	std::thread * threads[nthread];
-	unsigned i = 1;
-	for(auto & t : threads) {
-		auto & my_nodes = all_nodes[i - 1].array;
-		t = new std::thread([&done, &list, &barrier, &global, &my_nodes](unsigned tid) {
-			Random rand(tid + rdtscl());
-
-			local_stat_t local;
-
-			// affinity(tid);
-
-			barrier.wait(tid);
-
-			// EXPERIMENT START
-
-			run_body(done, rand, my_nodes, local, list);
-
-			// EXPERIMENT END
-
-			barrier.wait(tid);
-
-			global.in    += local.in;
-			global.out   += local.out;
-			global.empty += local.empty;
-
-			for(auto node : my_nodes) {
-				delete node;
-			}
-
-			global.crc_in  += local.crc_in;
-			global.crc_out += local.crc_out;
-
-			global.pick.push.attempt += relaxed_list<Node>::tls.pick.push.attempt;
-			global.pick.push.success += relaxed_list<Node>::tls.pick.push.success;
-			global.pick.pop .attempt += relaxed_list<Node>::tls.pick.pop.attempt;
-			global.pick.pop .success += relaxed_list<Node>::tls.pick.pop.success;
-		}, i++);
-	}
-
+struct global_stat_t {
+	std::atomic_size_t in  = { 0 };
+	std::atomic_size_t out = { 0 };
+	std::atomic_size_t empty = { 0 };
+	std::atomic_size_t crc_in  = { 0 };
+	std::atomic_size_t crc_out = { 0 };
+	std::atomic_size_t valmax = { 0 };
+	std::atomic_size_t valmin = { 100000000ul };
+};
+
+void atomic_max(std::atomic_size_t & target, size_t value) {
+	for(;;) {
+		size_t expect = target.load(std::memory_order_relaxed);
+		if(value <= expect) return;
+		bool success = target.compare_exchange_strong(expect, value);
+		if(success) return;
+	}
+}
+
+void atomic_min(std::atomic_size_t & target, size_t value) {
+	for(;;) {
+		size_t expect = target.load(std::memory_order_relaxed);
+		if(value >= expect) return;
+		bool success = target.compare_exchange_strong(expect, value);
+		if(success) return;
+	}
+}
+
+void tally_stats(global_stat_t & global, local_stat_t & local) {
+
+	global.in    += local.in;
+	global.out   += local.out;
+	global.empty += local.empty;
+
+	global.crc_in  += local.crc_in;
+	global.crc_out += local.crc_out;
+
+	atomic_max(global.valmax, local.valmax);
+	atomic_min(global.valmin, local.valmin);
+
+	relaxed_list<Node>::stats_tls_tally();
+}
+
+void waitfor(double & duration, barrier_t & barrier, std::atomic_bool & done) {
 	std::cout << "Starting" << std::endl;
 	auto before = Clock::now();
@@ -196,17 +124,29 @@
 	duration = durr.count();
 	std::cout << "\rClosing down" << std::endl;
-
-	for(auto t : threads) {
-		t->join();
-		delete t;
-	}
-
-	enable_stats = false;
-
-	while(auto node = list.pop()) {
-		global.crc_out += node->value;
-		delete node;
-	}
-
+}
+
+void waitfor(double & duration, barrier_t & barrier, const std::atomic_size_t & count) {
+	std::cout << "Starting" << std::endl;
+	auto before = Clock::now();
+	barrier.wait(0);
+
+	while(true) {
+		usleep(100000);
+		size_t c = count.load();
+		if( c == 0 ) {
+			break;
+		}
+		std::cout << "\r" << c;
+		std::cout.flush();
+	}
+
+	barrier.wait(0);
+	auto after = Clock::now();
+	duration_t durr = after - before;
+	duration = durr.count();
+	std::cout << "\rClosing down" << std::endl;
+}
+
+void print_stats(double duration, unsigned nthread, global_stat_t & global) {
 	assert(Node::creates == Node::destroys);
 	assert(global.crc_in == global.crc_out);
@@ -224,15 +164,373 @@
 	std::cout << "Ops/sec       : " << ops_sec << "\n";
 	std::cout << "Total ops     : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
+	if(global.valmax != 0) {
+		std::cout << "Max runs      : " << global.valmax << "\n";
+		std::cout << "Min runs      : " << global.valmin << "\n";
+	}
 	#ifndef NO_STATS
-		double push_sur = (100.0 * double(global.pick.push.success) / global.pick.push.attempt);
-		double pop_sur  = (100.0 * double(global.pick.pop .success) / global.pick.pop .attempt);
-		std::cout << "Push Pick %   : " << push_sur << "(" << global.pick.push.success << " / " << global.pick.push.attempt << ")\n";
-		std::cout << "Pop  Pick %   : " << pop_sur  << "(" << global.pick.pop .success << " / " << global.pick.pop .attempt << ")\n";
+		relaxed_list<Node>::stats_print(std::cout);
 	#endif
 }
 
-void usage(char * argv[]) {
-	std::cerr << argv[0] << ": [DURATION (FLOAT:SEC)] [NTHREADS] [NQUEUES] [FILL]" << std::endl;;
-	std::exit(1);
+void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output);
+
+// ================================================================================================
+//                        EXPERIMENTS
+// ================================================================================================
+
+// ================================================================================================
+__attribute__((noinline)) void runChurn_body(
+	std::atomic<bool>& done,
+	Random & rand,
+	Node * my_nodes[],
+	unsigned nslots,
+	local_stat_t & local,
+	relaxed_list<Node> & list
+) {
+	while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
+		int idx = rand.next() % nslots;
+		if (auto node = my_nodes[idx]) {
+			local.crc_in += node->value;
+			list.push(node);
+			my_nodes[idx] = nullptr;
+			local.in++;
+		}
+		else if(auto node = list.pop()) {
+			local.crc_out += node->value;
+			my_nodes[idx] = node;
+			local.out++;
+		}
+		else {
+			local.empty++;
+		}
+	}
+}
+
+void runChurn(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const unsigned nslots) {
+	std::cout << "Churn Benchmark" << std::endl;
+	assert(nnodes <= nslots);
+	// List being tested
+
+	// Barrier for synchronization
+	barrier_t barrier(nthread + 1);
+
+	// Data to check everything is OK
+	global_stat_t global;
+
+	// Flag to signal termination
+	std::atomic_bool done  = { false };
+
+	// Prep nodes
+	std::cout << "Initializing ";
+	size_t npushed = 0;
+	relaxed_list<Node> list = { nthread * nqueues };
+	{
+		Node** all_nodes[nthread];
+		for(auto & nodes : all_nodes) {
+			nodes = new __attribute__((aligned(64))) Node*[nslots + 8];
+			Random rand(rdtscl());
+			for(unsigned i = 0; i < nnodes; i++) {
+				nodes[i] = new Node(rand.next() % 100);
+			}
+
+			for(unsigned i = nnodes; i < nslots; i++) {
+				nodes[i] = nullptr;
+			}
+
+			for(int i = 0; i < 10 && i < (int)nslots; i++) {
+				int idx = rand.next() % nslots;
+				if (auto node = nodes[idx]) {
+					global.crc_in += node->value;
+					list.push(node);
+					npushed++;
+					nodes[idx] = nullptr;
+				}
+			}
+		}
+
+		std::cout << nnodes << " nodes (" << nslots << " slots)" << std::endl;
+
+		enable_stats = true;
+
+		std::thread * threads[nthread];
+		unsigned i = 1;
+		for(auto & t : threads) {
+			auto & my_nodes = all_nodes[i - 1];
+			t = new std::thread([&done, &list, &barrier, &global, &my_nodes, nslots](unsigned tid) {
+				Random rand(tid + rdtscl());
+
+				local_stat_t local;
+
+				// affinity(tid);
+
+				barrier.wait(tid);
+
+				// EXPERIMENT START
+
+				runChurn_body(done, rand, my_nodes, nslots, local, list);
+
+				// EXPERIMENT END
+
+				barrier.wait(tid);
+
+				tally_stats(global, local);
+
+				for(unsigned i = 0; i < nslots; i++) {
+					delete my_nodes[i];
+				}
+			}, i++);
+		}
+
+		waitfor(duration, barrier, done);
+
+		for(auto t : threads) {
+			t->join();
+			delete t;
+		}
+
+		enable_stats = false;
+
+		while(auto node = list.pop()) {
+			global.crc_out += node->value;
+			delete node;
+		}
+
+		for(auto nodes : all_nodes) {
+			delete[] nodes;
+		}
+	}
+
+	print_stats(duration, nthread, global);
+}
+
+// ================================================================================================
+__attribute__((noinline)) void runPingPong_body(
+	std::atomic<bool>& done,
+	Node initial_nodes[],
+	unsigned nnodes,
+	local_stat_t & local,
+	relaxed_list<Node> & list
+) {
+	Node * nodes[nnodes];
+	{
+		unsigned i = 0;
+		for(auto & n : nodes) {
+			n = &initial_nodes[i++];
+		}
+	}
+
+	while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
+
+		for(Node * & node : nodes) {
+			local.crc_in += node->value;
+			list.push(node);
+			local.in++;
+		}
+
+		// -----
+
+		for(Node * & node : nodes) {
+			node = list.pop();
+			assert(node);
+			local.crc_out += node->value;
+			local.out++;
+		}
+	}
+}
+
+void runPingPong(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes) {
+	std::cout << "PingPong Benchmark" << std::endl;
+
+
+	// Barrier for synchronization
+	barrier_t barrier(nthread + 1);
+
+	// Data to check everything is OK
+	global_stat_t global;
+
+	// Flag to signal termination
+	std::atomic_bool done  = { false };
+
+	std::cout << "Initializing ";
+	// List being tested
+	relaxed_list<Node> list = { nthread * nqueues };
+	{
+		enable_stats = true;
+
+		std::thread * threads[nthread];
+		unsigned i = 1;
+		for(auto & t : threads) {
+			t = new std::thread([&done, &list, &barrier, &global, nnodes](unsigned tid) {
+				Random rand(tid + rdtscl());
+
+				Node nodes[nnodes];
+				for(auto & n : nodes) {
+					n.value = (int)rand.next() % 100;
+				}
+
+				local_stat_t local;
+
+				// affinity(tid);
+
+				barrier.wait(tid);
+
+				// EXPERIMENT START
+
+				runPingPong_body(done, nodes, nnodes, local, list);
+
+				// EXPERIMENT END
+
+				barrier.wait(tid);
+
+				tally_stats(global, local);
+			}, i++);
+		}
+
+		waitfor(duration, barrier, done);
+
+		for(auto t : threads) {
+			t->join();
+			delete t;
+		}
+
+		enable_stats = false;
+	}
+
+	print_stats(duration, nthread, global);
+}
+
+// ================================================================================================
+__attribute__((noinline)) void runFairness_body(
+	unsigned tid,
+	size_t width,
+	size_t length,
+	int output[],
+	std::atomic_size_t & count,
+	Node initial_nodes[],
+	unsigned nnodes,
+	local_stat_t & local,
+	relaxed_list<Node> & list
+) {
+	Node * nodes[nnodes];
+	{
+		unsigned i = 0;
+		for(auto & n : nodes) {
+			n = &initial_nodes[i++];
+		}
+	}
+
+	while(__builtin_expect(0 != count.load(std::memory_order_relaxed), true)) {
+
+		for(Node * & node : nodes) {
+			local.crc_in += node->id;
+			list.push(node);
+			local.in++;
+		}
+
+		// -----
+
+		for(Node * & node : nodes) {
+			node = list.pop();
+			assert(node);
+
+			if (unsigned(node->value) < length) {
+				size_t idx = (node->value * width) + node->id;
+				assert(idx < (width * length));
+				output[idx] = tid;
+			}
+
+			node->value++;
+			if(unsigned(node->value) == length) count--;
+
+			local.crc_out += node->id;
+			local.out++;
+		}
+	}
+}
+
+void runFairness(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const std::string & output) {
+	std::cout << "Fairness Benchmark, outputing to : " << output << std::endl;
+
+	// Barrier for synchronization
+	barrier_t barrier(nthread + 1);
+
+	// Data to check everything is OK
+	global_stat_t global;
+
+	std::cout << "Initializing ";
+
+	// Check fairness by creating a png of where the threads ran
+	size_t width = nthread * nnodes;
+	size_t length = 100000;
+
+	std::unique_ptr<int[]> data_out { new int[width * length] };
+
+	// Flag to signal termination
+	std::atomic_size_t count = width;
+
+	// List being tested
+	relaxed_list<Node> list = { nthread * nqueues };
+	{
+		enable_stats = true;
+
+		std::thread * threads[nthread];
+		unsigned i = 1;
+		for(auto & t : threads) {
+			t = new std::thread([&count, &list, &barrier, &global, nnodes, width, length, data_out = data_out.get()](unsigned tid) {
+				unsigned int start = (tid - 1) * nnodes;
+				Node nodes[nnodes];
+				for(auto & n : nodes) {
+					n.id = start;
+					n.value = 0;
+					start++;
+				}
+
+				local_stat_t local;
+
+				// affinity(tid);
+
+				barrier.wait(tid);
+
+				// EXPERIMENT START
+
+				runFairness_body(tid, width, length, data_out, count, nodes, nnodes, local, list);
+
+				// EXPERIMENT END
+
+				barrier.wait(tid);
+
+				for(const auto & n : nodes) {
+					local.valmax = max(local.valmax, size_t(n.value));
+					local.valmin = min(local.valmin, size_t(n.value));
+				}
+
+				tally_stats(global, local);
+			}, i++);
+		}
+
+		waitfor(duration, barrier, count);
+
+		for(auto t : threads) {
+			t->join();
+			delete t;
+		}
+
+		enable_stats = false;
+	}
+
+	print_stats(duration, nthread, global);
+
+	save_fairness(data_out.get(), 100, nthread, width, length, output);
+}
+
+// ================================================================================================
+
+bool iequals(const std::string& a, const std::string& b)
+{
+    return std::equal(a.begin(), a.end(),
+                      b.begin(), b.end(),
+                      [](char a, char b) {
+                          return std::tolower(a) == std::tolower(b);
+                      });
 }
 
@@ -241,47 +539,385 @@
 	double duration   = 5.0;
 	unsigned nthreads = 2;
-	unsigned nqueues  = 2;
-	unsigned fill     = 100;
+	unsigned nqueues  = 4;
+	unsigned nnodes   = 100;
+	unsigned nslots   = 100;
+	std::string out   = "fairness.png";
+
+	enum {
+		Churn,
+		PingPong,
+		Fairness,
+		NONE
+	} benchmark = NONE;
 
 	std::cout.imbue(std::locale(""));
 
-	switch (argc)
-	{
+	for(;;) {
+		static struct option options[] = {
+			{"duration",  required_argument, 0, 'd'},
+			{"nthreads",  required_argument, 0, 't'},
+			{"nqueues",   required_argument, 0, 'q'},
+			{"benchmark", required_argument, 0, 'b'},
+			{0, 0, 0, 0}
+		};
+
+		int idx = 0;
+		int opt = getopt_long(argc, argv, "d:t:q:b:", options, &idx);
+
+		std::string arg = optarg ? optarg : "";
+		size_t len = 0;
+		switch(opt) {
+			// Exit Case
+			case -1:
+				/* paranoid */ assert(optind <= argc);
+				switch(benchmark) {
+				case NONE:
+					std::cerr << "Must specify a benchmark" << std::endl;
+					goto usage;
+				case PingPong:
+					nnodes = 1;
+					nslots = 1;
+					switch(argc - optind) {
+					case 0: break;
+					case 1:
+						try {
+							arg = optarg = argv[optind];
+							nnodes = stoul(optarg, &len);
+							if(len != arg.size()) { throw std::invalid_argument(""); }
+						} catch(std::invalid_argument &) {
+							std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
+							goto usage;
+						}
+						break;
+					default:
+						std::cerr << "'PingPong' benchmark doesn't accept more than 2 extra arguments" << std::endl;
+						goto usage;
+					}
+					break;
+				case Churn:
+					nnodes = 100;
+					nslots = 100;
+					switch(argc - optind) {
+					case 0: break;
+					case 1:
+						try {
+							arg = optarg = argv[optind];
+							nnodes = stoul(optarg, &len);
+							if(len != arg.size()) { throw std::invalid_argument(""); }
+							nslots = nnodes;
+						} catch(std::invalid_argument &) {
+							std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
+							goto usage;
+						}
+						break;
+					case 2:
+						try {
+							arg = optarg = argv[optind];
+							nnodes = stoul(optarg, &len);
+							if(len != arg.size()) { throw std::invalid_argument(""); }
+						} catch(std::invalid_argument &) {
+							std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
+							goto usage;
+						}
+						try {
+							arg = optarg = argv[optind + 1];
+							nslots = stoul(optarg, &len);
+							if(len != arg.size()) { throw std::invalid_argument(""); }
+						} catch(std::invalid_argument &) {
+							std::cerr << "Number of slots must be a positive integer, was " << arg << std::endl;
+							goto usage;
+						}
+						break;
+					default:
+						std::cerr << "'Churn' benchmark doesn't accept more than 2 extra arguments" << std::endl;
+						goto usage;
+					}
+					break;
+				case Fairness:
+					nnodes = 1;
+					switch(argc - optind) {
+					case 0: break;
+					case 1:
+						arg = optarg = argv[optind];
+						out = arg;
+						break;
+					default:
+						std::cerr << "'Churn' benchmark doesn't accept more than 2 extra arguments" << std::endl;
+						goto usage;
+					}
+				}
+				goto run;
+			// Benchmarks
+			case 'b':
+				if(benchmark != NONE) {
+					std::cerr << "Only when benchmark can be run" << std::endl;
+					goto usage;
+				}
+				if(iequals(arg, "churn")) {
+					benchmark = Churn;
+					break;
+				}
+				if(iequals(arg, "pingpong")) {
+					benchmark = PingPong;
+					break;
+				}
+				if(iequals(arg, "fairness")) {
+					benchmark = Fairness;
+					break;
+				}
+				std::cerr << "Unkown benchmark " << arg << std::endl;
+				goto usage;
+			// Numeric Arguments
+			case 'd':
+				try {
+					duration = stod(optarg, &len);
+					if(len != arg.size()) { throw std::invalid_argument(""); }
+				} catch(std::invalid_argument &) {
+					std::cerr << "Duration must be a valid double, was " << arg << std::endl;
+					goto usage;
+				}
+				break;
+			case 't':
+				try {
+					nthreads = stoul(optarg, &len);
+					if(len != arg.size()) { throw std::invalid_argument(""); }
+				} catch(std::invalid_argument &) {
+					std::cerr << "Number of threads must be a positive integer, was " << arg << std::endl;
+					goto usage;
+				}
+				break;
+			case 'q':
+				try {
+					nqueues = stoul(optarg, &len);
+					if(len != arg.size()) { throw std::invalid_argument(""); }
+				} catch(std::invalid_argument &) {
+					std::cerr << "Number of queues must be a positive integer, was " << arg << std::endl;
+					goto usage;
+				}
+				break;
+			// Other cases
+			default: /* ? */
+				std::cerr << opt << std::endl;
+			usage:
+				std::cerr << "Usage: " << argv[0] << ": [options] -b churn [NNODES] [NSLOTS = NNODES]" << std::endl;
+				std::cerr << "  or:  " << argv[0] << ": [options] -b pingpong [NNODES]" << std::endl;
+				std::cerr << std::endl;
+				std::cerr << "  -d, --duration=DURATION  Duration of the experiment, in seconds" << std::endl;
+				std::cerr << "  -t, --nthreads=NTHREADS  Number of kernel threads" << std::endl;
+				std::cerr << "  -q, --nqueues=NQUEUES    Number of queues per threads" << std::endl;
+				std::exit(1);
+		}
+	}
+	run:
+
+	check_cache_line_size();
+
+	std::cout << "Running " << nthreads << " threads (" << (nthreads * nqueues) << " queues) for " << duration << " seconds" << std::endl;
+	switch(benchmark) {
+		case Churn:
+			runChurn(nthreads, nqueues, duration, nnodes, nslots);
+			break;
+		case PingPong:
+			runPingPong(nthreads, nqueues, duration, nnodes);
+			break;
+		case Fairness:
+			runFairness(nthreads, nqueues, duration, nnodes, out);
+			break;
+		default:
+			abort();
+	}
+	return 0;
+}
+
+const char * __my_progname = "Relaxed List";
+
+struct rgb_t {
+    double r;       // a fraction between 0 and 1
+    double g;       // a fraction between 0 and 1
+    double b;       // a fraction between 0 and 1
+};
+
+struct hsv_t {
+    double h;       // angle in degrees
+    double s;       // a fraction between 0 and 1
+    double v;       // a fraction between 0 and 1
+};
+
+rgb_t hsv2rgb(hsv_t in) {
+	double hh, p, q, t, ff;
+	long   i;
+	rgb_t  out;
+
+	if(in.s <= 0.0) {       // < is bogus, just shuts up warnings
+		out.r = in.v;
+		out.g = in.v;
+		out.b = in.v;
+		return out;
+	}
+	hh = in.h;
+	if(hh >= 360.0) hh = 0.0;
+	hh /= 60.0;
+	i = (long)hh;
+	ff = hh - i;
+	p = in.v * (1.0 - in.s);
+	q = in.v * (1.0 - (in.s * ff));
+	t = in.v * (1.0 - (in.s * (1.0 - ff)));
+
+	switch(i) {
+	case 0:
+		out.r = in.v;
+		out.g = t;
+		out.b = p;
+		break;
+	case 1:
+		out.r = q;
+		out.g = in.v;
+		out.b = p;
+		break;
+	case 2:
+		out.r = p;
+		out.g = in.v;
+		out.b = t;
+		break;
+
+	case 3:
+		out.r = p;
+		out.g = q;
+		out.b = in.v;
+		break;
+	case 4:
+		out.r = t;
+		out.g = p;
+		out.b = in.v;
+		break;
 	case 5:
-		fill = std::stoul(argv[4]);
-		[[fallthrough]];
-	case 4:
-		nqueues = std::stoul(argv[3]);
-		[[fallthrough]];
-	case 3:
-		nthreads = std::stoul(argv[2]);
-		[[fallthrough]];
-	case 2:
-		duration = std::stod(argv[1]);
-		if( duration <= 0.0 ) {
-			std::cerr << "Duration must be positive, was " << argv[1] << "(" << duration << ")" << std::endl;
-			usage(argv);
-		}
-		[[fallthrough]];
-	case 1:
+	default:
+		out.r = in.v;
+		out.g = p;
+		out.b = q;
 		break;
-	default:
-		usage(argv);
-		break;
-	}
-
-	check_cache_line_size();
-
-	std::cout << "Running " << nthreads << " threads (" << (nthreads * nqueues) << " queues) for " << duration << " seconds" << std::endl;
-	run(nthreads, nqueues, fill, duration);
-
-	return 0;
-}
-
-template<>
-thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
-
-template<>
-relaxed_list<Node>::intrusive_queue_t::stat::Dif relaxed_list<Node>::intrusive_queue_t::stat::dif = {};
-
-const char * __my_progname = "Relaxed List";
+	}
+	return out;
+}
+
+void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
+	std::ofstream os(output);
+	os << "<html>\n";
+	os << "<head>\n";
+	os << "<style>\n";
+	os << "</style>\n";
+	os << "</head>\n";
+	os << "<body>\n";
+	os << "<table style=\"width=100%\">\n";
+
+	size_t idx = 0;
+	for(size_t r = 0ul; r < rows; r++) {
+		os << "<tr>\n";
+		for(size_t c = 0ul; c < columns; c++) {
+			os << "<td class=\"custom custom" << data[idx] << "\"></td>\n";
+			idx++;
+		}
+		os << "</tr>\n";
+	}
+
+	os << "</table>\n";
+	os << "</body>\n";
+	os << "</html>\n";
+	os << std::endl;
+}
+
+#include <png.h>
+#include <setjmp.h>
+
+/*
+void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
+	int width  = columns * factor;
+	int height = rows / factor;
+
+	int code = 0;
+	int idx = 0;
+	FILE *fp = NULL;
+	png_structp png_ptr = NULL;
+	png_infop info_ptr = NULL;
+	png_bytep row = NULL;
+
+	// Open file for writing (binary mode)
+	fp = fopen(output.c_str(), "wb");
+	if (fp == NULL) {
+		fprintf(stderr, "Could not open file %s for writing\n", output.c_str());
+		code = 1;
+		goto finalise;
+	}
+
+	   // Initialize write structure
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (png_ptr == NULL) {
+		fprintf(stderr, "Could not allocate write struct\n");
+		code = 1;
+		goto finalise;
+	}
+
+	// Initialize info structure
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL) {
+		fprintf(stderr, "Could not allocate info struct\n");
+		code = 1;
+		goto finalise;
+	}
+
+	// Setup Exception handling
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		fprintf(stderr, "Error during png creation\n");
+		code = 1;
+		goto finalise;
+	}
+
+	png_init_io(png_ptr, fp);
+
+	// Write header (8 bit colour depth)
+	png_set_IHDR(png_ptr, info_ptr, width, height,
+		8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+		PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+	png_write_info(png_ptr, info_ptr);
+
+	// Allocate memory for one row (3 bytes per pixel - RGB)
+	row = (png_bytep) malloc(3 * width * sizeof(png_byte));
+
+	// Write image data
+	int x, y;
+	for (y=0 ; y<height ; y++) {
+		for (x=0 ; x<width ; x++) {
+			auto & r = row[(x * 3) + 0];
+			auto & g = row[(x * 3) + 1];
+			auto & b = row[(x * 3) + 2];
+			assert(idx < (rows * columns));
+			int color = data[idx] - 1;
+			assert(color < nthreads);
+			assert(color >= 0);
+			idx++;
+
+			double angle = double(color) / double(nthreads);
+
+			auto c = hsv2rgb({ 360.0 * angle, 0.8, 0.8 });
+
+			r = char(c.r * 255.0);
+			g = char(c.g * 255.0);
+			b = char(c.b * 255.0);
+
+		}
+		png_write_row(png_ptr, row);
+	}
+
+	assert(idx == (rows * columns));
+
+	// End write
+	png_write_end(png_ptr, NULL);
+
+	finalise:
+	if (fp != NULL) fclose(fp);
+	if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+	if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+	if (row != NULL) free(row);
+}
+*/
Index: doc/theses/thierry_delisle_PhD/code/relaxed_list.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/relaxed_list.hpp	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ doc/theses/thierry_delisle_PhD/code/relaxed_list.hpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -37,4 +37,35 @@
 };
 
+static inline bool bts(std::atomic_size_t & target, size_t bit ) {
+	//*
+	int result = 0;
+	asm volatile(
+		"LOCK btsq %[bit], %[target]\n\t"
+		:"=@ccc" (result)
+		: [target] "m" (target), [bit] "r" (bit)
+	);
+ 	return result != 0;
+	/*/
+	size_t mask = 1ul << bit;
+	size_t ret = target.fetch_or(mask, std::memory_order_relaxed);
+	return (ret & mask) != 0;
+	//*/
+}
+
+static inline bool btr(std::atomic_size_t & target, size_t bit ) {
+	//*
+	int result = 0;
+	asm volatile(
+		"LOCK btrq %[bit], %[target]\n\t"
+		:"=@ccc" (result)
+		: [target] "m" (target), [bit] "r" (bit)
+	);
+ 	return result != 0;
+	/*/
+	size_t mask = 1ul << bit;
+	size_t ret = target.fetch_and(~mask, std::memory_order_relaxed);
+	return (ret & mask) != 0;
+	//*/
+}
 
 extern bool enable_stats;
@@ -48,4 +79,16 @@
 		size_t attempt = 0;
 		size_t success = 0;
+		size_t mask_attempt = 0;
+	} pop;
+};
+
+struct empty_stat {
+	struct {
+		size_t value = 0;
+		size_t count = 0;
+	} push;
+	struct {
+		size_t value = 0;
+		size_t count = 0;
 	} pop;
 };
@@ -62,19 +105,22 @@
 	static_assert(std::is_same<decltype(node_t::_links), _LinksFields_t<node_t>>::value, "Node must have a links field");
 
-
 public:
 	relaxed_list(unsigned numLists)
-	  	: numNonEmpty{0}
-		, lists(new intrusive_queue_t[numLists])
+	  	: lists(new intrusive_queue_t[numLists])
 		, numLists(numLists)
-	{}
+	{
+		assertf(7 * 8 * 8 >= numLists, "List currently only supports 448 sublists");
+		// assert(sizeof(*this) == 128);
+		std::cout << "Constructing Relaxed List with " << numLists << std::endl;
+
+		#ifndef NO_STATS
+			if(head) this->next = head;
+			head = this;
+		#endif
+	}
 
 	~relaxed_list() {
+		std::cout << "Destroying Relaxed List" << std::endl;
 		lists.reset();
-		#ifndef NO_STATS
-			std::cout << "Difference   : "
-				<< ssize_t(double(intrusive_queue_t::stat::dif.value) / intrusive_queue_t::stat::dif.num  ) << " avg\t"
-				<< intrusive_queue_t::stat::dif.max << "max" << std::endl;
-		#endif
 	}
 
@@ -84,5 +130,5 @@
 		while(true) {
 			// Pick a random list
-			int i = tls.rng.next() % numLists;
+			unsigned i = tls.rng.next() % numLists;
 
 			#ifndef NO_STATS
@@ -93,6 +139,16 @@
 			if( !lists[i].lock.try_lock() ) continue;
 
+			__attribute__((unused)) int num = numNonEmpty;
+
 			// Actually push it
-			lists[i].push(node, numNonEmpty);
+			if(lists[i].push(node)) {
+				numNonEmpty++;
+				size_t qword = i >> 6ull;
+				size_t bit   = i & 63ull;
+				assertf((list_mask[qword] & (1ul << bit)) == 0, "Before set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
+				__attribute__((unused)) bool ret = bts(list_mask[qword], bit);
+				assert(!ret);
+				assertf((list_mask[qword] & (1ul << bit)) != 0, "After set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
+			}
 			assert(numNonEmpty <= (int)numLists);
 
@@ -102,4 +158,6 @@
 			#ifndef NO_STATS
 				tls.pick.push.success++;
+				tls.empty.push.value += num;
+				tls.empty.push.count += 1;
 			#endif
 			return;
@@ -108,47 +166,121 @@
 
 	__attribute__((noinline, hot)) node_t * pop() {
-		while(numNonEmpty != 0) {
-			// Pick two lists at random
-			int i = tls.rng.next() % numLists;
-			int j = tls.rng.next() % numLists;
-
-			#ifndef NO_STATS
-				tls.pick.pop.attempt++;
-			#endif
-
-			// Pick the bet list
-			int w = i;
-			if( __builtin_expect(lists[j].ts() != 0, true) ) {
-				w = (lists[i].ts() < lists[j].ts()) ? i : j;
-			}
-
-			auto & list = lists[w];
-			// If list looks empty retry
-			if( list.ts() == 0 ) continue;
-
-			// If we can't get the lock retry
-			if( !list.lock.try_lock() ) continue;
-
-			// If list is empty, unlock and retry
-			if( list.ts() == 0 ) {
-				list.lock.unlock();
-				continue;
-			}
-
-			// Actually pop the list
-			auto node = list.pop(numNonEmpty);
-			assert(node);
-
-			// Unlock and return
-			list.lock.unlock();
-			assert(numNonEmpty >= 0);
-			#ifndef NO_STATS
-				tls.pick.pop.success++;
-			#endif
-			return node;
-		}
+		#if !defined(NO_BITMASK)
+			// for(int r = 0; r < 10 && numNonEmpty != 0; r++) {
+			// 	// Pick two lists at random
+			// 	unsigned i = tls.rng.next() % numLists;
+			// 	unsigned j = tls.rng.next() % numLists;
+
+			// 	if(auto node = try_pop(i, j)) return node;
+			// }
+			int nnempty;
+			while(0 != (nnempty = numNonEmpty)) {
+				tls.pick.pop.mask_attempt++;
+				unsigned i, j;
+				// if( numLists < 4 || (numLists / nnempty) < 4 ) {
+				// 	// Pick two lists at random
+				// 	i = tls.rng.next() % numLists;
+				// 	j = tls.rng.next() % numLists;
+				// } else
+				{
+					#ifndef NO_STATS
+						// tls.pick.push.mask_attempt++;
+					#endif
+
+					// Pick two lists at random
+					unsigned num = ((numLists - 1) >> 6) + 1;
+
+					unsigned ri = tls.rng.next();
+					unsigned rj = tls.rng.next();
+
+					unsigned wdxi = (ri >> 6u) % num;
+					unsigned wdxj = (rj >> 6u) % num;
+
+					size_t maski = list_mask[wdxi].load(std::memory_order_relaxed);
+					size_t maskj = list_mask[wdxj].load(std::memory_order_relaxed);
+
+					if(maski == 0 && maskj == 0) continue;
+
+					unsigned bi = rand_bit(ri, maski);
+					unsigned bj = rand_bit(rj, maskj);
+
+					assertf(bi < 64, "%zu %u", maski, bi);
+					assertf(bj < 64, "%zu %u", maskj, bj);
+
+					i = bi | (wdxi << 6);
+					j = bj | (wdxj << 6);
+
+					assertf(i < numLists, "%u", wdxi << 6);
+					assertf(j < numLists, "%u", wdxj << 6);
+				}
+
+				if(auto node = try_pop(i, j)) return node;
+			}
+		#else
+			while(numNonEmpty != 0) {
+				// Pick two lists at random
+				int i = tls.rng.next() % numLists;
+				int j = tls.rng.next() % numLists;
+
+				if(auto node = try_pop(i, j)) return node;
+			}
+		#endif
 
 		return nullptr;
     	}
+
+private:
+	node_t * try_pop(unsigned i, unsigned j) {
+		#ifndef NO_STATS
+			tls.pick.pop.attempt++;
+		#endif
+
+		// Pick the bet list
+		int w = i;
+		if( __builtin_expect(lists[j].ts() != 0, true) ) {
+			w = (lists[i].ts() < lists[j].ts()) ? i : j;
+		}
+
+		auto & list = lists[w];
+		// If list looks empty retry
+		if( list.ts() == 0 ) return nullptr;
+
+		// If we can't get the lock retry
+		if( !list.lock.try_lock() ) return nullptr;
+
+		__attribute__((unused)) int num = numNonEmpty;
+
+		// If list is empty, unlock and retry
+		if( list.ts() == 0 ) {
+			list.lock.unlock();
+			return nullptr;
+		}
+
+		// Actually pop the list
+		node_t * node;
+		bool emptied;
+		std::tie(node, emptied) = list.pop();
+		assert(node);
+
+		if(emptied) {
+			numNonEmpty--;
+			size_t qword = w >> 6ull;
+			size_t bit   = w & 63ull;
+			assert((list_mask[qword] & (1ul << bit)) != 0);
+			__attribute__((unused)) bool ret = btr(list_mask[qword], bit);
+			assert(ret);
+			assert((list_mask[qword] & (1ul << bit)) == 0);
+		}
+
+		// Unlock and return
+		list.lock.unlock();
+		assert(numNonEmpty >= 0);
+		#ifndef NO_STATS
+			tls.pick.pop.success++;
+			tls.empty.pop.value += num;
+			tls.empty.pop.count += 1;
+		#endif
+		return node;
+	}
 
 private:
@@ -162,10 +294,8 @@
 		struct stat {
 			ssize_t diff = 0;
-
-			static struct Dif {
-				ssize_t value = 0;
-				size_t  num   = 0;
-				ssize_t max   = 0;
-			} dif;
+			size_t  push = 0;
+			size_t  pop  = 0;
+			// size_t value = 0;
+			// size_t count = 0;
 		};
 
@@ -178,7 +308,12 @@
 		sentinel_t before;
 		sentinel_t after;
-		stat s;
-
+		#ifndef NO_STATS
+			stat s;
+		#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
 		static constexpr auto fields_offset = offsetof( node_t, _links );
+#pragma GCC diagnostic pop
 	public:
 		intrusive_queue_t()
@@ -186,21 +321,15 @@
 			, after {{ head(), nullptr }}
 		{
-			assert((reinterpret_cast<uintptr_t>( head() ) + fields_offset) == reinterpret_cast<uintptr_t>(&before));
-			assert((reinterpret_cast<uintptr_t>( tail() ) + fields_offset) == reinterpret_cast<uintptr_t>(&after ));
-			assert(head()->_links.prev == nullptr);
-			assert(head()->_links.next == tail() );
-			assert(tail()->_links.next == nullptr);
-			assert(tail()->_links.prev == head() );
-			assert(sizeof(*this) == 128);
-			assert((intptr_t(this) % 128) == 0);
-		}
-
-		~intrusive_queue_t() {
-			#ifndef NO_STATS
-				stat::dif.value+= s.diff;
-				stat::dif.num  ++;
-				stat::dif.max  = std::abs(stat::dif.max) > std::abs(s.diff) ? stat::dif.max : s.diff;
-			#endif
-		}
+			/* paranoid */ assert((reinterpret_cast<uintptr_t>( head() ) + fields_offset) == reinterpret_cast<uintptr_t>(&before));
+			/* paranoid */ assert((reinterpret_cast<uintptr_t>( tail() ) + fields_offset) == reinterpret_cast<uintptr_t>(&after ));
+			/* paranoid */ assert(head()->_links.prev == nullptr);
+			/* paranoid */ assert(head()->_links.next == tail() );
+			/* paranoid */ assert(tail()->_links.next == nullptr);
+			/* paranoid */ assert(tail()->_links.prev == head() );
+			/* paranoid */ assert(sizeof(*this) == 128);
+			/* paranoid */ assert((intptr_t(this) % 128) == 0);
+		}
+
+		~intrusive_queue_t() = default;
 
 		inline node_t * head() const {
@@ -220,5 +349,5 @@
 		}
 
-		inline void push(node_t * node, std::atomic_int & nonEmpty) {
+		inline bool push(node_t * node) {
 			assert(lock);
 			assert(node->_links.ts != 0);
@@ -232,14 +361,19 @@
 			prev->_links.next = node;
 			tail->_links.prev = node;
+			#ifndef NO_STATS
+				if(enable_stats) {
+					s.diff++;
+					s.push++;
+				}
+			#endif
 			if(before._links.ts == 0l) {
-				nonEmpty += 1;
 				before._links.ts = node->_links.ts;
-			}
-			#ifndef NO_STATS
-				if(enable_stats) s.diff++;
-			#endif
-		}
-
-		inline node_t * pop(std::atomic_int & nonEmpty) {
+				assert(node->_links.prev == this->head());
+				return true;
+			}
+			return false;
+		}
+
+		inline std::pair<node_t *, bool> pop() {
 			assert(lock);
 			node_t * head = this->head();
@@ -248,12 +382,18 @@
 			node_t * node = head->_links.next;
 			node_t * next = node->_links.next;
-			if(node == tail) return nullptr;
+			if(node == tail) return {nullptr, false};
 
 			head->_links.next = next;
 			next->_links.prev = head;
 
+			#ifndef NO_STATS
+				if(enable_stats) {
+					s.diff--;
+					s.pop ++;
+				}
+			#endif
 			if(next == tail) {
 				before._links.ts = 0l;
-				nonEmpty -= 1;
+				return {node, true};
 			}
 			else {
@@ -261,9 +401,6 @@
 				before._links.ts = next->_links.ts;
 				assert(before._links.ts != 0);
-			}
-			#ifndef NO_STATS
-				if(enable_stats) s.diff--;
-			#endif
-			return node;
+				return {node, false};
+			}
 		}
 
@@ -277,10 +414,13 @@
 
 	static __attribute__((aligned(128))) thread_local struct TLS {
-		Random    rng = { int(rdtscl()) };
-		pick_stat pick;
+		Random     rng = { int(rdtscl()) };
+		pick_stat  pick;
+		empty_stat empty;
 	} tls;
 
+public:
+	std::atomic_int numNonEmpty  = { 0 };  // number of non-empty lists
+	std::atomic_size_t list_mask[7] = { {0}, {0}, {0}, {0}, {0}, {0}, {0} }; // which queues are empty
 private:
-	std::atomic_int numNonEmpty; // number of non-empty lists
     	__attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t []> lists;
 	const unsigned numLists;
@@ -288,3 +428,92 @@
 public:
 	static const constexpr size_t sizeof_queue = sizeof(intrusive_queue_t);
+
+#ifndef NO_STATS
+	static void stats_print(std::ostream & os) {
+		auto it = head;
+		while(it) {
+			it->stats_print_local(os);
+			it = it->next;
+		}
+	}
+
+	static void stats_tls_tally() {
+		global_stats.pick.push.attempt += tls.pick.push.attempt;
+		global_stats.pick.push.success += tls.pick.push.success;
+		global_stats.pick.pop .attempt += tls.pick.pop.attempt;
+		global_stats.pick.pop .success += tls.pick.pop.success;
+		global_stats.pick.pop .mask_attempt += tls.pick.pop.mask_attempt;
+
+		global_stats.qstat.push.value += tls.empty.push.value;
+		global_stats.qstat.push.count += tls.empty.push.count;
+		global_stats.qstat.pop .value += tls.empty.pop .value;
+		global_stats.qstat.pop .count += tls.empty.pop .count;
+	}
+
+private:
+	static struct GlobalStats {
+		struct {
+			struct {
+				std::atomic_size_t attempt = { 0 };
+				std::atomic_size_t success = { 0 };
+			} push;
+			struct {
+				std::atomic_size_t attempt = { 0 };
+				std::atomic_size_t success = { 0 };
+				std::atomic_size_t mask_attempt = { 0 };
+			} pop;
+		} pick;
+		struct {
+			struct {
+				std::atomic_size_t value = { 0 };
+				std::atomic_size_t count = { 0 };
+			} push;
+			struct {
+				std::atomic_size_t value = { 0 };
+				std::atomic_size_t count = { 0 };
+			} pop;
+		} qstat;
+	} global_stats;
+
+	// Link list of all lists for stats
+	__attribute__((aligned(64))) relaxed_list<node_t> * next = nullptr;
+
+	static relaxed_list<node_t> * head;
+
+	void stats_print_local(std::ostream & os ) {
+		std::cout << "----- Relaxed List Stats -----" << std::endl;
+		{
+			ssize_t diff = 0;
+			size_t  num  = 0;
+			ssize_t max  = 0;
+
+			for(size_t i = 0; i < numLists; i++) {
+				const auto & list = lists[i];
+				diff+= list.s.diff;
+				num ++;
+				max  = std::abs(max) > std::abs(list.s.diff) ? max : list.s.diff;
+				os << "Local Q ops   : " << (list.s.push + list.s.pop) << "(" << list.s.push << "i, " << list.s.pop << "o)\n";
+			}
+
+			os << "Difference   : " << ssize_t(double(diff) / num  ) << " avg\t" << max << "max" << std::endl;
+		}
+
+		const auto & global = global_stats;
+
+		double push_sur = (100.0 * double(global.pick.push.success) / global.pick.push.attempt);
+		double pop_sur  = (100.0 * double(global.pick.pop .success) / global.pick.pop .attempt);
+		double mpop_sur = (100.0 * double(global.pick.pop .success) / global.pick.pop .mask_attempt);
+
+		os << "Push   Pick % : " << push_sur << "(" << global.pick.push.success << " / " << global.pick.push.attempt << ")\n";
+		os << "Pop    Pick % : " << pop_sur  << "(" << global.pick.pop .success << " / " << global.pick.pop .attempt << ")\n";
+		os << "TryPop Pick % : " << mpop_sur << "(" << global.pick.pop .success << " / " << global.pick.pop .mask_attempt << ")\n";
+
+		double avgQ_push = double(global.qstat.push.value) / global.qstat.push.count;
+		double avgQ_pop  = double(global.qstat.pop .value) / global.qstat.pop .count;
+		double avgQ      = double(global.qstat.push.value + global.qstat.pop .value) / (global.qstat.push.count + global.qstat.pop .count);
+		os << "Push   Avg Qs : " << avgQ_push << " (" << global.qstat.push.count << "ops)\n";
+		os << "Pop    Avg Qs : " << avgQ_pop  << " (" << global.qstat.pop .count << "ops)\n";
+		os << "Global Avg Qs : " << avgQ      << " (" << (global.qstat.push.count + global.qstat.pop .count) << "ops)\n";
+	}
+#endif
 };
Index: doc/theses/thierry_delisle_PhD/code/relaxed_list_layout.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/relaxed_list_layout.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/code/relaxed_list_layout.cpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,23 @@
+#define NO_IO
+#define NDEBUG
+#include "relaxed_list.hpp"
+
+struct __attribute__((aligned(64))) Node {
+	static std::atomic_size_t creates;
+	static std::atomic_size_t destroys;
+
+	_LinksFields_t<Node> _links;
+
+	int value;
+	Node(int value): value(value) {
+		creates++;
+	}
+
+	~Node() {
+		destroys++;
+	}
+};
+
+int main() {
+	return sizeof(relaxed_list<Node>) + relaxed_list<Node>::sizeof_queue;
+}
Index: doc/theses/thierry_delisle_PhD/code/scale.sh
===================================================================
--- doc/theses/thierry_delisle_PhD/code/scale.sh	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/code/scale.sh	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,7 @@
+#!/bin/bash
+taskset -c 24-31 ./a.out -t  1 -b churn | grep --color -E "(ns|Ops|Running)"
+taskset -c 24-31 ./a.out -t  2 -b churn | grep --color -E "(ns|Ops|Running)"
+taskset -c 24-31 ./a.out -t  4 -b churn | grep --color -E "(ns|Ops|Running)"
+taskset -c 24-31 ./a.out -t  8 -b churn | grep --color -E "(ns|Ops|Running)"
+taskset -c 16-31 ./a.out -t 16 -b churn | grep --color -E "(ns|Ops|Running)"
+taskset -c  0-31 ./a.out -t 32 -b churn | grep --color -E "(ns|Ops|Running)"
Index: doc/theses/thierry_delisle_PhD/code/utils.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/utils.hpp	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ doc/theses/thierry_delisle_PhD/code/utils.hpp	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,4 +10,6 @@
 #include <unistd.h>
 #include <sys/sysinfo.h>
+
+#include <x86intrin.h>
 
 // Barrier from
@@ -56,5 +58,5 @@
 }
 
-void affinity(int tid) {
+static inline void affinity(int tid) {
 	static int cpus = get_nprocs();
 
@@ -70,5 +72,5 @@
 
 static const constexpr std::size_t cache_line_size = 64;
-void check_cache_line_size() {
+static inline void check_cache_line_size() {
 	std::cout << "Checking cache line size" << std::endl;
 	const std::string cache_file = "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size";
@@ -103,2 +105,40 @@
 	return std::chrono::duration_cast<std::chrono::duration<T, Ratio>>(std::chrono::duration<T>(seconds)).count();
 }
+
+static inline unsigned rand_bit(unsigned rnum, size_t mask) {
+	unsigned bit = mask ? rnum % __builtin_popcountl(mask) : 0;
+#if !defined(__BMI2__)
+	uint64_t v = mask;   // Input value to find position with rank r.
+	unsigned int r = bit + 1;// Input: bit's desired rank [1-64].
+	unsigned int s;      // Output: Resulting position of bit with rank r [1-64]
+	uint64_t a, b, c, d; // Intermediate temporaries for bit count.
+	unsigned int t;      // Bit count temporary.
+
+	// Do a normal parallel bit count for a 64-bit integer,
+	// but store all intermediate steps.
+	a =  v - ((v >> 1) & ~0UL/3);
+	b = (a & ~0UL/5) + ((a >> 2) & ~0UL/5);
+	c = (b + (b >> 4)) & ~0UL/0x11;
+	d = (c + (c >> 8)) & ~0UL/0x101;
+
+
+	t = (d >> 32) + (d >> 48);
+	// Now do branchless select!
+	s  = 64;
+	s -= ((t - r) & 256) >> 3; r -= (t & ((t - r) >> 8));
+	t  = (d >> (s - 16)) & 0xff;
+	s -= ((t - r) & 256) >> 4; r -= (t & ((t - r) >> 8));
+	t  = (c >> (s - 8)) & 0xf;
+	s -= ((t - r) & 256) >> 5; r -= (t & ((t - r) >> 8));
+	t  = (b >> (s - 4)) & 0x7;
+	s -= ((t - r) & 256) >> 6; r -= (t & ((t - r) >> 8));
+	t  = (a >> (s - 2)) & 0x3;
+	s -= ((t - r) & 256) >> 7; r -= (t & ((t - r) >> 8));
+	t  = (v >> (s - 1)) & 0x1;
+	s -= ((t - r) & 256) >> 8;
+	return s - 1;
+#else
+	uint64_t picked = _pdep_u64(1ul << bit, mask);
+	return picked ? __builtin_ctzl(picked) : 0;
+#endif
+}
Index: doc/theses/thierry_delisle_PhD/comp_II/Makefile
===================================================================
--- doc/theses/thierry_delisle_PhD/comp_II/Makefile	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/comp_II/Makefile	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,84 @@
+## Define the configuration variables.
+
+Build = build
+Figures = figures
+Macros = ../../../LaTeXmacros
+TeXLIB = .:${Macros}:${Build}:../../../bibliography:
+LaTeX  = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build}
+BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex
+
+MAKEFLAGS = --no-print-directory --silent #
+VPATH = ${Build} ${Figures}
+
+## Define the text source files.
+
+SOURCES = ${addsuffix .tex, \
+comp_II \
+}
+
+FIGURES = ${addsuffix .tex, \
+}
+
+PICTURES = ${addsuffix .pstex, \
+}
+
+PROGRAMS = ${addsuffix .tex, \
+}
+
+GRAPHS = ${addsuffix .tex, \
+}
+
+## Define the documents that need to be made.
+
+DOCUMENT = comp_II.pdf
+BASE = ${basename ${DOCUMENT}}
+
+# Directives #
+
+.PHONY : all clean					# not file names
+
+all : ${DOCUMENT}
+
+clean :
+	@rm -frv ${DOCUMENT} ${BASE}.ps ${Build}
+
+# File Dependencies #
+
+${DOCUMENT} : ${BASE}.ps
+	ps2pdf $<
+
+${BASE}.ps : ${BASE}.dvi
+	dvips ${Build}/$< -o $@
+
+${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
+		${Macros}/common.tex ${Macros}/indexstyle ../../../bibliography/pl.bib \
+		local.bib glossary.tex | ${Build}
+	# Must have *.aux file containing citations for bibtex
+	if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi
+	-${BibTeX} ${Build}/${basename $@}
+	# Some citations reference others so run again to resolve these citations
+	${LaTeX} ${basename $@}.tex
+	-${BibTeX} ${Build}/${basename $@}
+	# Make index from *.aux entries and input index at end of document
+	makeglossaries -q -s ${Build}/${basename $@}.ist ${Build}/${basename $@}
+	# Run again to finish citations
+	${LaTeX} ${basename $@}.tex
+
+## Define the default recipes.
+
+${Build}:
+	mkdir -p ${Build}
+
+%.tex : %.fig ${Build}
+	fig2dev -L eepic $< > ${Build}/$@
+
+%.ps : %.fig | ${Build}
+	fig2dev -L ps $< > ${Build}/$@
+
+%.pstex : %.fig | ${Build}
+	fig2dev -L pstex $< > ${Build}/$@
+	fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t
+
+# Local Variables: #
+# compile-command: "make" #
+# End: #
Index: doc/theses/thierry_delisle_PhD/comp_II/comp_II.tex
===================================================================
--- doc/theses/thierry_delisle_PhD/comp_II/comp_II.tex	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/comp_II/comp_II.tex	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,191 @@
+\documentclass[11pt,fullpage]{article}
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage{listings}		% for code listings
+\usepackage{xspace}
+\usepackage{xcolor}
+\usepackage{graphicx}
+\usepackage[hidelinks]{hyperref}
+\usepackage{glossaries}
+\usepackage{textcomp}
+\usepackage{geometry}
+
+% cfa macros used in the document
+\input{common}
+\input{glossary}
+
+\CFAStyle				% use default CFA format-style
+
+\title{
+	\Huge \vspace*{1in} The \CFA Scheduler\\
+	\huge \vspace*{0.25in} PhD Comprehensive II Research Proposal
+	\vspace*{1in}
+}
+
+\author{
+	\huge Thierry Delisle \\
+	\Large \vspace*{0.1in} \texttt{tdelisle@uwaterloo.ca} \\
+	\Large Cheriton School of Computer Science \\
+	\Large University of Waterloo
+}
+
+\date{
+	\today
+}
+
+\begin{document}
+\maketitle
+\cleardoublepage
+
+\newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace}
+\newcommand{\TODO}{~\newline{\large\bf\color{red} TODO :}\xspace}
+
+% ===============================================================================
+% ===============================================================================
+
+\tableofcontents
+
+% ===============================================================================
+% ===============================================================================
+\newpage
+\section{Introduction}
+\subsection{\CFA and the \CFA concurrency package}
+\CFA\cit is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language. It aims to add high productivity features while maintaning the predictible performance of C. As such concurrency in \CFA\cit aims to offer simple and safe high-level tools while still allowing performant code. Concurrent code is written in the syncrhonous programming paradigm but uses \glspl{uthrd} in order to achieve the simplicity and maintainability of synchronous programming without sacrificing the efficiency of asynchronous programing. As such the \CFA scheduler is a user-level scheduler that maps \glspl{uthrd} onto \glspl{kthrd}.
+
+The goal of this research is to produce a scheduler that is simple to use and offers acceptable performance in all cases. Here simplicity does not refer to the API but to how much scheduling concerns programmers need to take into account when using the \CFA concurrency package. Therefore, the main goal of this proposal is as follows :
+\begin{quote}
+The \CFA scheduler should be \emph{viable} for any workload.
+\end{quote}
+
+This objective includes producing a scheduling strategy with minimal fairness guarantees, creating an abstraction layer over the operating system to handle kernel-threads spinning unnecessarily and hide blocking I/O operations and, writing sufficient library tools to allow developpers to properly use the scheduler.
+
+% ===============================================================================
+% ===============================================================================
+
+\section{Scheduling for \CFA}
+While the \CFA concurrency package doesn't have any particular scheduling needs beyond those of any concurrency package which uses \glspl{uthrd}, it is important that the default \CFA Scheduler be viable in general. Indeed, since the \CFA Scheduler does not target any specific workloads, it is unrealistic to demand that it use the best scheduling strategy in all cases. However, it should offer a viable ``out of the box'' solution for most scheduling problems so that programmers can quickly write performant concurrent without needed to think about which scheduling strategy is more appropriate for their workload. Indeed, only programmers with exceptionnaly high performance requirements should need to write their own scheduler. More specifically, two broad types of schedulering strategies should be avoided in order to avoid penalizing certain types of workloads : feedback-based and priority schedulers.
+
+\subsection{Feedback-Based Schedulers}
+Many operating systems use schedulers based on feadback loops in some form, they measure how much CPU a particular thread has used\footnote{Different metrics can be used to here but it is not relevant to the discussion.} and schedule threads based on this metric. These strategies are sensible for operating systems but rely on two assumptions on the workload :
+
+\begin{enumerate}
+	\item Threads live long enough to be scheduled many times.
+	\item Cooperation among all threads is not simply infeasible, it is a security risk.
+\end{enumerate}
+
+While these two assumptions generally hold for operating systems, they may not for \CFA programs. In fact, \CFA uses \glspl{uthrd} which have the explicit goal of reducing the cost of threading primitives to allow many smaller threads. This can naturally lead to have threads with much shorter lifetime and only being scheduled a few times. Scheduling strategies based on feadback loops cannot be effective in these cases because they will not have the opportunity to measure the metrics that underlay the algorithm. Note that the problem of feadback loop convergence (reacting too slowly to scheduling events) is not specific to short lived threads but can also occur with threads that show drastic changes in scheduling event, e.g., threads running for long periods of time and then suddenly blocking and unblocking quickly and repeatedly.
+
+In the context of operating systems, these concerns can be overshadowed by a more pressing concern : security. When multiple users are involved, it is possible that some users are malevolent and try to exploit the scheduling strategy in order to achieve some nefarious objective. Security concerns mean that more precise and robust fairness metrics must be used. In the case of the \CFA scheduler, every thread runs in the same user-space and are controlled from the same user. It is then possible to safely ignore the possibility that threads are malevolent and assume that all threads will ignore or cooperate with each other. This allows for a much simpler fairness metric and in this proposal ``fairness'' will be considered as equal opportunities to run once scheduled.
+
+Since feadback is not necessarily feasible within the lifetime of all threads and a simple fairness metric can be used, the scheduling strategy proposed for the \CFA runtime does not user per-threads feedback. Feedback loops in general are not rejected for secondary concerns like idle sleep, but no feedback loop is used to decide which thread to run next.
+
+\subsection{Priority Schedulers}
+Another broad category of schedulers are priority schedulers. In these scheduling strategies threads have priorities and the runtime schedules the threads with the highest priority before scheduling other threads. Threads with equal priority are scheduled using a secondary strategy, often something simple like round-robin or FIFO. These priority mean that, as long as there is a thread with a higher priority that desires to run, a thread with a lower priority will not run. This possible starving of threads can dramatically increase programming complexity since starving threads and priority inversion (prioritising a lower priority thread) can both lead to serious problems, leaving programmers between a rock and a hard place.
+
+An important observation to make is that threads do not need to have explicit priorities for problems to be possible. Indeed, any system with multiple ready-queues and attempts to exhaust one queue before accessing the other queues, could encounter starvation problems. A popular scheduling strategy that suffers from implicit priorities is work-stealing. Work-stealing is generally presented as follows :
+
+\begin{itemize}
+	\item Each processor has a list of threads.
+\end{itemize}
+\begin{enumerate}
+	\item Run threads from ``this'' processor's list.
+	\item If ``this'' processor's list is empty, run threads from some other processor's list.
+\end{enumerate}
+
+In a loaded system\footnote{A loaded system is a system where threads are being run at the same rate they are scheduled}, if a thread does not yield or block for an extended period of time, threads on the same processor list will starve if no other processors can exhaust their list.
+
+Since priorities can be complex to handle for programmers, the scheduling strategy proposed for the \CFA runtime does not use a strategy with either implicit or explicit thread priorities.
+
+\subsection{Schedulers without feadback or priorities}
+I claim that the ideal default scheduler for the \CFA runtime is a scheduler that offers good scalability and a simple fairness guarantee that is easy for programmers to reason about. The simplest fairness guarantee is to guarantee FIFO ordering, i.e., threads scheduled first will run first. However, enforcing FIFO ordering generally conflicts with scalability across multiple processors because of the additionnal synchronization. Thankfully, strict FIFO is not needed for scheduling. Since concurrency is inherently non-deterministic, fairness concerns in scheduling are only a problem if a thread repeatedly runs before another thread can run\footnote{This is because the non-determinism means that programmers must already handle ordering problems in order to produce correct code and already must rely on weak guarantees, for example that a specific thread will \emph{eventually} run.}. This need for unfairness to persist before problems occur means that the FIFO fairness guarantee can be significantly relaxed without causing problems. For this proposal, the target guarantee is that the \CFA scheduler guarantees \emph{probable} FIFO ordering, which is defined as follows :
+\begin{itemize}
+	\item Given two threads $X$ and $Y$, the odds that thread $X$ runs $N$ times \emph{after} thread $Y$ is scheduled but \emph{before} it is run, decreases exponentially with regards to $N$.
+\end{itemize}
+
+While this is not a strong guarantee, the probability that problems persist for long period of times decreases exponentially, making persisting problems virtually impossible.
+
+\subsection{Real-Time}
+While the objective of this proposed scheduler is similar to the objective of real-time scheduling, this proposal is not a proposal for real-time scheduler and as such makes no attempt to offer either soft or hard guarantees on scheduling delays.
+
+% ===============================================================================
+% ===============================================================================
+\section{Proposal}
+
+\subsection{Ready-Queue}
+Using trevor's paper\cit as basis, it is simple to build a relaxed FIFO list that is fast and scalable for loaded or overloaded systems. The described queue uses an array of underlying strictly FIFO queue. Pushing new data is done by selecting one of these underlying queues at random, recording a timestamp for the push and pushing to the selected queue. Popping is done by selecting two queues at random and popping from the queue for which the head has the oldest timestamp. In loaded or overloaded systems, it is higly likely that the queues is far from empty, e.i., several tasks are on each of the underlying queues. This means that selecting a queue at random to pop from is higly likely to yield a queue that is not empty.
+
+When the ready queue is "more empty", i.e., several of the inner queues are empty, selecting a random queue for popping is less likely to yield a valid selection and more attempts need to be made, resulting in a performance degradation. In cases, with few elements on the ready queue and few processors running, performance can be improved by adding information to help processors find which inner queues are used. Preliminary performance tests indicate that with few processors, a bitmask can be used to identify which inner queues are currently in use. This is especially effective in the single-thread case, where the bitmask will always be up-to-date. Furthermore, modern x86 CPUs have a BMI2 extension which allow using the bitmask with very little overhead over directly accessing the readyqueue offerring decent performance even in cases with many empty inner queues. This technique does not solve the problem completely, it randomly attempts to find a block of 64 queues where at least one is used, instead of attempting to find a used queue. For systems with a large number of cores this does not completely solve the problem, but it is a fixed improvement. The size of the blocks are limited by the maximum size atomic instruction can operate on, therefore atomic instructions on large words would increase the 64 queues per block limit.
+
+\TODO double check the next sentence
+Preliminary result indicate that the bitmask approach with the BMI2 extension can lead to multi-threaded performance that is contention agnostic in the worst case.
+This result suggests that the contention penalty and the increase performance for additionnal thread cancel each other exactly. This may indicate that a relatively small reduction in contention may tip the performance into positive scalling even for the worst case. It can be noted that in cases of high-contention, the use of the bitmask to find queues that are not empty is much less reliable. Indeed, if contention on the bitmask is high, it means it probably changes significantly between the moment it is read and the actual operation on the queues it represents. Furthermore, the objective of the bitmask is to avoid probing queues that are empty. Therefore, in cases where the bitmask is highly contented, it may be preferrable to probe queues randomly, either until contention decreases or until a prior prefetch of the bitmask completes. Ideally, the scheduler would be able to observe that the bitmask is highly contented and adjust its behaviour appropriately. However, I am not aware of any mechanism to query whether a cacheline is in cache or to run other instructions until a cacheline is fetch without blocking on the cacheline. As such, an alternative that may have a similar impact would be for each thread to have their own bitmask, which would be updated both after each scheduler action and after a certain number of failed probing. If the bitmask has little contention, the local bitmask will be mostly up-to-date and several threads won't need to contend as much on the global bitmask. If the bitmask has significant contention, then fetching it becomes more expensive and threads may as well probe randomly. This solution claims that probing randomly or against an out-of-date bitmask is equivalent.
+
+In cases where this is insufficient, another approach is to use a hiearchical data structure. Creating a tree of nodes to reduce contention has been shown to work in similar cases\cit(SNZI: Scalable NonZero Indicators)\footnote{This particular paper seems to be patented in the US. How does that affect \CFA? Can I use it in my work?}. However, this approach may lead to poorer single-threaded performance due to the inherent pointer chasing, as such, it was not considered as the first approach but as a fallback in case the bitmask approach does not satisfy the performance goals.
+
+Part of this performance relies on contention being low when there are few threads on the readyqueue. However, this can be assumed reliably if the system handles putting idle processors to sleep, which is addressed in section \ref{sleep}.
+
+\paragraph{Objectives and Existing Work}
+How much scalability is actually needed is highly debatable, libfibre\cit is has compared favorably to other schedulers in webserver tests\cit and uses a single atomic counter in its scheduling algorithm similarly to the proposed bitmask. As such the single atomic instruction on a shared cacheline may be sufficiently performant.
+
+I have built a prototype of this ready-queue (including the bitmask and BMI2 usage, but not the sharded bitmask) and ran performance experiments on it but it is difficult to compare this prototype to a thread scheduler as the prototype is used as a data-queue. I have also integrated this prototype into the \CFA runtime, but have not yet created performance experiments to compare results. I believe that the bitmask approach is currently one of the larger risks of the proposal, early tests lead me to believe it may work but it is not clear that the contention problem can be overcome. The worst-case scenario is a case where the number of processors and the number of ready threads are similar, yet scheduling events are very frequent. Fewer threads should lead to the Idle Sleep mechanism reducing contention while having many threads ready leads to optimal performance. It is difficult to evaluate the likeliness of this worst-case scenario in real workloads. I believe, frequent scheduling events suggest a more ``bursty'' workload where new work is finely divided among many threads which race to completion. This type of workload would only see a peek of contention close to the end of the work, but no sustained contention. Very fine-grained pipelines are less ``bursty'', these may lead to more sustained contention. However, they could also easily benefit from a direct hand-off strategy which would circumvent the problem entirely.
+
+\subsection{Dynamic Resizing}
+The \CFA runtime system currently handles dynamically adding and removing processors from clusters at any time. Since this is part of the existing design, the proposed scheduler must also support this behaviour. However, dynamicly resizing the clusters is considered a rare event associated with setup, teardown and major configuration changes. This assumptions is made both in the design of the proposed scheduler as well as in the original design of the \CFA runtime system. As such, the proposed scheduler must honor the correctness of these behaviour but does not have any performance objectives with regards to resizing a cluster. How long adding or removing processors take and how much this disrupts the performance of other threads is considered a secondary concern since it should be amortized over long period of times. This description effectively matches with te description of a Reader-Writer lock, in frequent but invasive updates among frequent (mostly) read operations. In the case of the Ready-Queue described above, read operations are operations that push or pop from the ready-queue but do not invalidate any references to the ready queue data structures. Writes on the other-hand would add or remove inner queues, invalidating references to the array of inner queues in the process. Therefore, the current proposed approach to this problem is the add a per-cluster Reader Writer lock around the ready queue to prevent restructuring of the ready-queue data structure while threads are being pushed or popped.
+
+There are possible alternatives to the Reader Writer lock solution. This problem is effectively a memory reclamation problem and as such there is a large body of research on the subject. However, the RWlock solution is simple and can be leveraged to solve other problems (e.g. processor ordering and memory reclamation of threads) which makes it an attractive solution.
+
+\paragraph{Objectives and Existing Work}
+The lock must offer scalability and performance on par with the actual ready-queue in order not to introduce a new bottle neck. I have already built a lock that fits the desired requirements and preliminary testing show scalability and performance that exceed the target. As such, I do not consider this lock to be a risk on this project.
+
+\subsection{Idle Sleep} \label{sleep}
+As mentionned above, idle sleep is the process of putting processors to sleep while they do not have threads to execute. In this context processors are kernel-threads and sleeping refers to asking the kernel to block a thread. This can be achieved with either thread synchronization operations like pthread\_cond\_wait or using signal operations like sigsuspend.
+
+Support for idle sleep broadly involves calling the operating system to block the kernel thread but also handling the race between the sleeping and the waking up, and handling which kernel thread should sleep or wake-up.
+
+When a processor decides to sleep, there is a race that occurs between it signalling that it will go to sleep (so other processors can find sleeping processors) and actually blocking the kernel thread. This is equivalent to the classic problem of missing signals when using condition variables, the ``sleepy'' processor indicates that it will sleep but has not yet gone to sleep, if another processor attempts to wake it up, the waking-up operation may claim nothing needs to be done and the signal will have been missed. In cases where threads are scheduled from processors on the current cluster, loosing signals is not necessarily critical, because at least some processors on the cluster are awake. Individual processors always finish shceduling threads before looking for new work, which means that the last processor to go to sleep cannot miss threads scheduled from inside the cluster (if they do, that demonstrates the ready-queue is not linearizable). However, this guarantee does not hold if threads are shceduled from outside the cluster, either due to an external event like timers and I/O, or due to a thread migrating from a different cluster. In this case, missed signals can lead to the cluster deadlocking where it should not\footnote{Clusters ``should'' never deadlock, but for this proposal, cases where \CFA users \emph{actually} wrote \CFA code that leads to a deadlock it is considered as a deadlock that ``should'' happen. }. Therefore, it is important that the scheduling of threads include a mechanism where signals \emph{cannot} be missed. For performance reasons, it can be advantageous to have a secondary mechanism that allows signals to be missed in cases where it cannot lead to a deadlock. To be safe, this process must include a ``handshake'' where it is guaranteed that either~: the sleepy processor notices that a thread was scheduled after it signalled its intent to block or code scheduling threads well see the intent to sleep before scheduling and be able to wake-up the processor. This matter is complicated by the fact that pthread offers few tools to implement this solution and offers no guarantee of ordering of threads waking up for most of these tools.
+
+Another issues is trying to avoid kernel sleeping and waking frequently. A possible partial solution is to order the processors so that the one which most recently went to sleep is woken up. This allows other sleeping processors to reach deeper sleep state (when these are available) while keeping ``hot'' processors warmer. Note that while this generally means organising the processors in a stack, I believe that the unique index provided by the ReaderWriter lock can be reused to strictly order the waking order of processors, causing a LIFO like waking order. While a strict LIFO stack is probably better, using the processor index could proove useful and offer a sufficiently LIFO ordering.
+
+Finally, another important aspect of Idle Sleep is when should processors make the decision to sleep and when it is appropriate for sleeping processors to be woken up. Processors that are unnecessarily awake lead to unnecessary contention and power consumption, while too many sleeping processors can lead to sub-optimal throughput. Furthermore, transitions from sleeping to awake and vice-versa also add unnecessary latency. There is already a wealth of research on the subject and I do not plan to implement a novel idea for the Idle Sleep heuristic in this project.
+
+\subsection{Asynchronous I/O}
+The final aspect of this proposal is asynchronous I/O. Without it, user threads that execute I/O operations will block the underlying kernel thread. This leads to poor throughput, it would be preferrable to block the user-thread and reuse the underlying kernel-thread to run other ready threads. This requires intercepting the user-threads' calls to I/O operations, redirecting them to an asynchronous I/O interface and handling the multiplexing between the synchronous and asynchronous API. As such, these are the three components needed to implemented to support asynchronous I/O : an OS abstraction layer over the asynchronous interface, an event-engine to (de)multiplex the operations and a synchronous interface for users to use. None of these components currently exist in \CFA and I will need to build all three for this project.
+
+\paragraph{OS Abstraction}
+One of the fundamental part of this converting blocking I/O operations into non-blocking ones. This relies on having an underlying asynchronous I/O interface to which to direct the I/O operations. While there exists many different APIs for asynchronous I/O, it is not part of this proposal to create a novel API, simply to use an existing one that is sufficient. uC++ uses the \texttt{select} as its interface, which handles pipes and sockets. It entails significant complexity and has performances problems which make it a less interesting alternative. Another interface which is becoming popular recently\cit is \texttt{epoll}. However, epoll also does not handle file system and seems to have problem to linux pipes and \texttt{TTY}s\cit. A very recent alternative that must still be investigated is \texttt{io\_uring}. It claims to address some of the issues with \texttt{epoll} but is too recent to be confident that it does. Finally, a popular cross-platform alternative is \texttt{libuv}, which offers asynchronous sockets and asynchronous file system operations (among other features). However, as a full-featured library it includes much more than what is needed and could conflict with other features of \CFA unless significant efforts are made to merge them together.
+
+\paragraph{Event-Engine}
+Laying on top of the asynchronous interface layer is the event-engine. This engine is responsible for multiplexing (batching) the synchronous I/O requests into an asynchronous I/O request and demultiplexing the results onto appropriate blocked threads. This can be straightforward for the simple cases, but can become quite complex. Decisions that will need to be made include : whether to poll from a seperate kernel thread or a regularly scheduled user thread, what should be the ordering used when results satisfy many requests, how to handle threads waiting for multiple operations, etc.
+
+\paragraph{Interface}
+Finally, for these components to be available, it is necessary to expose them through a synchronous interface. This can be a novel interface but it is preferrable to attempt to intercept the existing POSIX interface in order to be compatible with existing code. This will allow C programs written using this interface to be transparently converted to \CFA with minimal effeort. Where this is not applicable, a novel interface will be created to fill the gaps.
+
+
+% ===============================================================================
+% ===============================================================================
+\section{Discussion}
+
+
+% ===============================================================================
+% ===============================================================================
+\section{Timeline}
+
+
+\cleardoublepage
+
+% B I B L I O G R A P H Y
+% -----------------------------
+\addcontentsline{toc}{chapter}{Bibliography}
+\bibliographystyle{plain}
+\bibliography{pl,local}
+\cleardoublepage
+\phantomsection		% allows hyperref to link to the correct page
+
+% G L O S S A R Y
+% -----------------------------
+\addcontentsline{toc}{chapter}{Glossary}
+\printglossary
+\cleardoublepage
+\phantomsection		% allows hyperref to link to the correct page
+
+\end{document}
Index: doc/theses/thierry_delisle_PhD/comp_II/comp_II_too_big.tex
===================================================================
--- doc/theses/thierry_delisle_PhD/comp_II/comp_II_too_big.tex	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/comp_II/comp_II_too_big.tex	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,316 @@
+\documentclass[11pt,fullpage]{article}
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage{listings}		% for code listings
+\usepackage{xspace}
+\usepackage{xcolor}
+\usepackage{graphicx}
+\usepackage[hidelinks]{hyperref}
+\usepackage{glossaries}
+\usepackage{textcomp}
+\usepackage{geometry}
+
+% cfa macros used in the document
+\input{common}
+\input{glossary}
+
+\CFAStyle				% use default CFA format-style
+
+\title{
+	\Huge \vspace*{1in} The \CFA Scheduler\\
+	\huge \vspace*{0.25in} PhD Comprehensive II Research Proposal
+	\vspace*{1in}
+}
+
+\author{
+	\huge Thierry Delisle \\
+	\Large \vspace*{0.1in} \texttt{tdelisle@uwaterloo.ca} \\
+	\Large Cheriton School of Computer Science \\
+	\Large University of Waterloo
+}
+
+\date{
+	\today
+}
+
+\begin{document}
+\maketitle
+\cleardoublepage
+
+\newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace}
+\newcommand{\TODO}{\newline{\large\bf\color{red} TODO :}\xspace}
+
+% ===============================================================================
+% ===============================================================================
+
+\tableofcontents
+
+% ===============================================================================
+% ===============================================================================
+\section{Introduction}
+\subsection{\CFA and the \CFA concurrency package}
+\CFA\cit is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language. It aims to add high productivity features while maintaning the predictible performance of C. As such concurrency in \CFA\cit aims to offer . Concurrent code is written in the syncrhonous programming paradigm but uses \glspl{uthrd} in order to achieve the simplicity and maintainability of synchronous programming without sacrificing the efficiency of asynchronous programing. As such the \CFA scheduler is a user-level scheduler that maps \glspl{uthrd} onto \glspl{kthrd}
+
+\subsection{Scheduling for \CFA}
+While the \CFA concurrency package doesn't have any particular scheduling needs beyond those of any concurrency package which uses \glspl{uthrd}, it is important that the default \CFA Scheduler be viable in general. Indeed, since the \CFA Scheduler does not target any specific workloads, it is unrealistic to demand that it use the best scheduling strategy in all cases. However, it should offer a viable ``out of the box'' solution for most scheduling problems so that programmers can quickly write performant concurrent without needed to think about which scheduling strategy is more appropriate for their workload. Indeed, only programmers with exceptionnaly high performance requirements should need to write their own scheduler.
+
+As detailed in Section~\ref{metrics}, schedulers can be evaluated according to multiple metrics. It is therefore important to set objective goals for scheduling according to a high-level direction. As such the design goal for the scheduling strategy can be phrased as follows :
+\begin{quote}
+The \CFA scheduling strategy should be \emph{viable} for any workload.
+\end{quote}
+
+% ===============================================================================
+% ===============================================================================
+\section{Scheduling terms}
+Before going into details about scheduling, it is important to define the terms used in this document, especially since many of these terms are often overloaded and may have subtlely different meaning. All scheduling terms used are defined in the Glossary but the following terms are worth explaining now. \TODO fix the glossary ref
+
+\paragraph{\Gls{proc}:} Designates the abstract worker on which the work will be scheduled. The nature of the \gls{proc} can vary depending on the level at which the mapping is done. For example, OS scheduling maps \glspl{kthrd} onto \glspl{hthrd} and therefore in this context the \gls{proc} refers to the \gls{hthrd}. However, in the context of user space scheduling, the scheduler maps \glspl{uthrd}, \glspl{fiber} or \glspl{job} onto \glspl{kthrd}, at this level the \gls{kthrd} becomes the \gls{proc}.
+
+\paragraph{\Gls{at}:} This document uses the term \gls{at} to designate the units of work that are to be scheduled. Like \glspl{proc}, the nature of a \gls{at} varies depending on the level at which the scheduler operates. The \glspl{at} in OS schedulers are \glspl{kthrd}, while the \glspl{at} in user-space scheduling can be \glspl{uthrd}, \glspl{fiber} or \glspl{job}. The term \gls{at} was chosen specifically to avoid collisions with specific types of \gls{at}, \eg thread, \glspl{uthrd} and \glspl{fiber}.
+
+\paragraph{\Gls{Q}:} A \gls{Q} is a list of \glspl{at} that have been \glslink{at}{scheduled} but have yet to be \glslink{atrun}{run}. The number and nature of the \gls{Q} is scheduler specific and is generally a significant portion of the scheduler design.
+
+\paragraph{\Gls{atsched}:} Designates the act of signalling to the scheduler that some \gls{at} is ready to be executed and should eventually be assigned to a \gls{proc}.
+
+\paragraph{\Gls{atrun}:} Designates the act of act of actually running a \gls{at} that was scheduled. That is mapping the \gls{at} onto a specific \gls{proc} and having the \gls{proc} execute its code.
+
+\paragraph{\Gls{atblock}:} A blocked \gls{at} is an \gls{at} that exists outside of any \gls{Q}. Unless some external entity unblocks it (by \glslink{atsched}{scheduling} it), it will never run and will stay in this suspended state. Not all schedulers support blocking. \eg \gls{job} schedulers do not, a new \gls{job} must be created if the current one would need to wait for an external event.
+
+\paragraph{\Gls{atmig}:} A \gls{at} is generally considered to have migrated when it is \glslink{atrun}{run} from a different different \gls{proc} then the previous time it \glslink{atrun}{ran}. This concept is relevant because migration can often come at a performance cost which is mostly due to caching. However, some amount of migration is generally required to achieve load balancing. In the context of \glspl{job}, since \glspl{job} only run once, migration is define as being \glslink{atrun}{run} from a different different \gls{proc} the the one it was created on.
+
+\paragraph{\Gls{atpass}:} A \gls{at} as overtaken another \gls{at} when it was \glslink{atsched}{scheduled} later but \glslink{atrun}{run} before the other \gls{at}. Overtaking can have performance benefits but has obvious fairness concerns.
+
+% =================================================================================================
+% =================================================================================================
+\section{Previous Work}
+
+\subsection{Publications}
+\subsubsection{Work Stealing}
+A populer scheduling algorithm is \emph{Work Stealing}, which was used by \cite{burton1981executing, halstead1984implementation} to divide work among threads to be done in parallel. This specific flavor of work stealing, which maps units of work to be executed once\footnote{This single execution is what fundamentally distinguishes \emph{Jobs} from \emph{Threads}} onto kernel-threads.
+
+There are countless examples of work-stealing variations \cit, all of which shared the same basic idea : each worker has its own set of work units, referred to as work-queue in this document, and once it runs out, it ``steals'' from  other worker. Many variations of the algorithm exist but they generally have the following characteristics :
+
+\begin{itemize}
+	\item There exists a one-to-one mapping between \glspl{proc} and \glspl{Q}, \eg every thread has exactly one queue of jobs to execute.
+	\item Once added to a \gls{Q}, \glspl{at} can \glslink{atmig}{migrate} to another \gls{proc} only as a result of the \gls{proc}'s \gls{Q} being empty.
+\end{itemize}
+
+Where \glspl{at} are initially enqueued and what to do with unblocking \glspl{at} (which must be requeued) is generally where the variations occur in the algorithms.
+
+Distributing the \glspl{at} improves fairness\cit, while enqueuing new and recurring \glspl{at} on the same work-queue as they creator and previous \glspl{atrun} respectively improves locality\cit.
+
+
+It is worth pointing out that while both strategy can be very effective for certain workloads\cit
+
+\subsubsection{Other-Schedulers}
+
+\subsubsection{Theoretical Bounds}
+
+
+\subsection{In practice}
+In practive meany implementations seem to have converge towards schedulers which use a one to one mapping between \glspl{proc} and \glspl{Q}, often with one or several lower-priority shared \glspl{Q}. This is generally perceived as an improvement over schedulers with a single \glspl{Q} which can lead to contention problems. As mentionned further into this document, this is due to the implicit assumption that the \gls{Q} data structure cannot scale to many cores.
+
+Schedulers with multiple \glspl{Q} generally achieve better throughput can also introduce fairness related problems. The underlying problem is that these \glspl{Q} lead to priorities based on placement rather than per \gls{at}.
+
+\paragraph{Indefinite Starvation}
+A scheduler can have starve a \gls{at} indefinetely. In practice, schedulers without support for priorities can starve \glspl{at} if it does not have preemption and can fall in a stable state where a \gls{at} never \glslink{atblock}{blocks} and other \glspl{at} can get stuck behind it. If these \glspl{at} are never stolen (taken from a \gls{proc} which isn't the one mapped to that \gls{Q}) then they will be indefinetely starved.
+
+\paragraph{Poor load-balancing}
+If the scheduler reaches a stable state where per-\gls{proc} \glspl{Q} have significantly different average lengths (and are never-empty), this can lead to significant unfairness. Indeed, if load-balancing only occurs when a \gls{proc} runs out of work, any stable state where no \gls{proc} runs out of work means that there is no longer any load-balancing while in that state.
+
+\paragraph{Aggressive ``Nice'' \glspl{at}}
+Certain workloads can have ``Nice'' \glspl{at}, that is \glspl{at} which run in the background. These \glspl{at} generally have low amount of work and can run when the system isn't too busy. In systems without priorities, There are several techniques to implement background \glspl{at}, but not every technique may work with every scheduler.
+
+One approach is for the background task to yield every time it makes some small progress. If the yielding \gls{at} is put on a higher-priority \gls{Q} than workstealing, this can cause unfairness and can even cause the background task to fully utilize \gls{hthrd}
+
+A similar approach is to sleep for a short duration instead. However, depending on the details of the sleep, this can also cause problems. It is more likely that sleeping will cause a \gls{proc} to steal because the \gls{at} probably transitions out of the ready state. However, not all system support fine grain sleeping. If the sleeping is to coarse, relying on sleep can cause latency issues.
+
+Finally, this can be solve with explicit synchronization, however not all background tasks can be implemented this way since they don't necessarily have to wait for any ressource.
+
+\subsubsection*{Linux's CFS}
+\subsubsection*{FreeBSD scheduler}
+\subsubsection*{Windows OS Scheduler}
+Windows seems to use priority based scheduling, where the priorities can vary dynamically within some limit. Load-balancing across processors is handle using a work-sharing approch and has different rules based on whether or not there are idle processors.
+
+\subsubsection*{Windows User-Mode Scheduler}
+Windows seems to have M:N scheduling support but does not provide a default user-mode scheduler.
+
+\subsubsection*{Go}
+Go's scheduler uses a work-stealing algorithm without preemption that has a global runqueue(\emph{GRQ}) and each processor(\emph{P}) has a fixed-size runqueue(\emph{LRQ}).
+
+The algorithm is as follows :
+\begin{enumerate}
+	\item Once out of 61 times, directly pick 1 element from the \emph{GRQ}.
+	\item If there is a local next pick it.
+	\item Else pick an item from the \emph{LRQ}.
+	\item If it was empty steal (len(\emph{GRQ}) / \#of\emph{P}) + 1 items (max 256) from the \emph{GRQ}.
+	\item If it was empty steal \emph{half} the \emph{LRQ} of an other \emph{P}.
+\end{enumerate}
+
+Ignoring concerns of power consumption, this structure can lead to odd behaviour. Obviously, the fact that it is non-preemptable means that given a set of goroutines where $N$ of these never block (\eg CPU-bound producers) running on $P$ Processors (\emph{P}'s using the Go naming), if $N >= P$ than not all goroutines are guaranteed to ever make progress. However, this can also be the case even if $N < P$. Indeed, if $P - N$ processors can find a sustained amount of work without needing to steal, then indefinite starvation can still occur.
+
+Excluding cases due to the lack of preemption still leads to odd behavior. The fact that the LRQs have a fixed size can also effect the fairness of scheduling in drastic ways. The separation between \emph{LRQ} and \emph{GRQ} can lead to significant unfairness both in homogenous workloads and more heterogenous workloads.
+
+\subsubsection*{Erlang}
+Erlang uses a work-stealing schedulers with the addition that ``underloaded schedulers will also steal jobs from heavily overloaded schedulers in their migration paths''. Depending on the specifics of this heuristic
+
+\subsubsection*{Haskell}
+
+\subsubsection*{D}
+D does not appear to have an M:N threading model.
+\subsubsection*{Intel\textregistered ~Threading Building Blocks}
+https://software.intel.com/en-us/node/506295
+Intel's concurrency and parallelism library uses a more complicated scheduler which has multiple \glspl{Q} with various priority. However, these \glspl{Q} have a strict priority ordering meaning it is subject to tasks indefinetely starving lower priority tasks if programmers are not careful.
+\TODO test it
+
+\subsubsection*{Quasar}
+
+\subsubsection*{Grand Central Dispatch}
+
+\subsubsection*{LibFiber}
+
+\subsubsection*{Fiber Tasking Lib}
+Advertized in GDC and also uses work-stealing.
+
+
+\subsection{Scheduling Needs}
+Things to look at
+
+libuv : polling loop used for async I/O
+
+julia : uses libuv and has multi-threading
+
+
+
+Direction to look at :
+Static web-servers : mostly-I/O bound
+	- single or few thread, event driven
+	- thread per connections
+
+	examples:
+		- memcached
+		- apache
+		- nodejs stuff
+
+
+HPC workloads : compute bound
+
+
+% ===============================================================================
+% ===============================================================================
+
+\section{Overview of Scheduling for \CFA}
+
+\subsection{Scheduling : Core goals}
+
+\subsection{Requirements of the Scheduler Context}
+
+\subsection{Integration with I/O}
+
+\subsection{Blocking in Style}
+
+
+% ===============================================================================
+% ===============================================================================
+\section{Metrics of Scheduling} \label{metrics}
+Before starting to look into the design of the best scheduler for \CFA, it is important to take some time to detail what metrics to pick for scheduling.
+
+Here are a few metrics that should be considered.
+
+\paragraph{Throughput} is a fairly straightforward metric, it can be measured either in terms of how much time was spent to \glslink{atcomplet}{run to completion} for a fix number of \gls{at} or how many \gls{at} where \glslink{atrun}{ran} for a fix number of work.
+
+These two definitions are virtually interchangeable. However, since scheduling can affect application performance getting valid empirical measures for throughput can be difficult.
+
+\paragraph{Latency} measures how long an individual \gls{at} waited between when it was \glslink{atsched}{scheduled} and it was \glslink{atrun}{run}
+
+\paragraph{Fairness}
+
+\paragraph{Ressource Utilization}
+
+\paragraph{Application Performance}
+
+\section{The Core : Multi-Lane Scheduling}
+\subsection{Objectives}
+While work-stealing works well for both trivial cases, \ie all new \glspl{at} distributed evenly or all on a single work-queue, it handles poorly inbetween cases. As mentionned above, the goal is therefore to create a scheduler that is \emph{viable} for any workloads. More concretely, this means a scheduler that has good scalability and offers guarantees eventual progress. For the purpose of this document, eventual progress is defined as follows:
+
+\begin{itemize}
+	\item Any \Gls{at} that is \glslink{atsched}{scheduled} should eventually \glslink{atrun}{run}, regardless\footnote{In the context of guaranteeing eventual progress, we consider only normal program execution. . Depending on the chosen semantics, normal system shutdown can also prevent \glspl{at} from eventually running without considering the guarantee violated. } of any other \glspl{at} being scheduled (prior or otherwise).
+\end{itemize}
+
+Eventual progress is not guaranteed by work-stealing or work-sharing schedulers in every context. Indeed, as mentionned in \cit, when the system is \glslink{load}{loaded} neither work-stealing nor work-sharing guarantee eventual progress. These aberrant cases can be fixed with \gls{preemption}, they still show a fundamental fairness problem in the algorithm. We can offer a stricter guarantee of eventual progress by limitting the amount of \gls{at} \emph{\glslink{atpass}{overtaking}}. Indeed, cases where eventual progress is lost are cases that show \emph{unbounded} \glslink{atpass}{overtaking} and a such, a scheduler that limits \glslink{atpass}{overtaking} in general guarantees eventual progress.
+
+We can then define the first concrete goal of the \CFA scheduler as :
+\begin{itemize}
+	\item The odds that a \gls{at} is overtaken by $N$ other \glspl{at} decreases rapidly when $N$ increases.
+\end{itemize}
+
+As a second, more fuzzy, objective, the Cforall scheduler should also perform no worst than most existing scheduler for any workload.
+
+\subsection{Ideal description}
+The ideal scheduler should similarly to a multi-lane highway. If all lanes are equally fast, lane changes are to be avoided because they induce traffic jam. However, if some lanes are faster than others than lane changes will help balance the traffic.
+
+Similarly, a task should migrate in two cases:
+\begin{itemize}
+	\item When a worker just emptied its work-queue. (like work-stealing)
+	\item \emph{When a work-unit was overtaken too many times by work units in a different lane}.
+\end{itemize}
+
+
+\subsection{Practical terms}
+In practice, the highway lane analogy has to be adjusted slightly to make it practical. First, the \glspl{at} should always respect the order within a given lane. This means only the task at the front can migrate. This both enforces a stronger FIFO order and means that the scheduler can ignore all \glspl{at} that aren't at the front, simplifying processing. Furthermore, migrating \glspl{at} is only usefull when at least one worker is available, \ie looking for a task to run, because any migration made at any other time will only take effect at that moment.
+
+\subsection{Existing Work}
+
+\subsection{Cforall Today}
+
+
+
+% ===============================================================================
+% ===============================================================================
+\section{The Context : Scheduling in \CFA}
+\subsection{Dynamic Clusters}
+
+\subsection{Idle Sleep}
+
+\subsection{Locality}
+
+% ===============================================================================
+% ===============================================================================
+\section{Asynchronous IO}
+\subsection{Cooperation with the OS}
+
+\subsection{Framework Integration}
+
+% ===============================================================================
+% ===============================================================================
+\section{Blocking in Style}
+\subsection{Monitors and Baton-Passing}
+
+\subsection{Futures and Promises}
+
+
+% ===============================================================================
+% ===============================================================================
+\section{Current Work}
+
+\section{Conclusion}
+
+
+\cleardoublepage
+
+% B I B L I O G R A P H Y
+% -----------------------------
+\addcontentsline{toc}{chapter}{Bibliography}
+\bibliographystyle{plain}
+\bibliography{pl,local}
+\cleardoublepage
+\phantomsection		% allows hyperref to link to the correct page
+
+% G L O S S A R Y
+% -----------------------------
+\addcontentsline{toc}{chapter}{Glossary}
+\printglossary
+\cleardoublepage
+\phantomsection		% allows hyperref to link to the correct page
+
+\end{document}
Index: doc/theses/thierry_delisle_PhD/comp_II/glossary.tex
===================================================================
--- doc/theses/thierry_delisle_PhD/comp_II/glossary.tex	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/comp_II/glossary.tex	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,137 @@
+\makeglossaries
+
+\longnewglossaryentry{hthrd}
+{name={hardware thread}}
+{
+Threads representing the underlying hardware directly.
+
+\textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
+}
+
+\longnewglossaryentry{uthrd}
+{name={user-level thread}}
+{
+Threads created and managed inside user-space. Each thread has its own stack and its own thread of execution. User-level threads are invisible to the underlying operating system.
+
+\textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
+}
+
+\longnewglossaryentry{kthrd}
+{name={kernel-level thread}}
+{
+Threads created and managed inside kernel-space. Each thread has its own stack and its own thread of execution. Kernel-level threads are owned, managed and scheduled by the underlying operating system.
+
+\textit{Synonyms : OS threads, Hardware threads, Physical threads.}
+}
+
+\longnewglossaryentry{fiber}
+{name={fiber}}
+{
+Fibers are non-preemptive user-level threads. They share most of the caracteristics of user-level threads except that they cannot be preempted by another fiber.
+
+\textit{Synonyms : Tasks.}
+}
+
+\longnewglossaryentry{job}
+{name={job}}
+{
+Unit of work, often sent to a thread pool or worker pool to be executed. Has neither its own stack nor its own thread of execution.
+
+\textit{Synonyms : Tasks.}
+}
+
+\longnewglossaryentry{pool}
+{name={thread-pool}}
+{
+Group of homogeneuous threads that loop executing units of works after another.
+
+\textit{Synonyms : }
+}
+
+\longnewglossaryentry{preemption}
+{name={preemption}}
+{
+Involuntary context switch imposed on threads at a given rate.
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{proc}
+{name={virtual processor}}
+{
+
+}
+
+\longnewglossaryentry{Q}
+{name={work-queue}}
+{
+
+}
+
+\longnewglossaryentry{at}
+{name={fred}}
+{
+Abstract object representing an unit of work. Systems will offer one or more concrete implementations of this concept (\eg \gls{kthrd}, \gls{job}), however, most of the concept of schedulings are independent of the particular implementations of the work representation. For this reason, this document use the term \Gls{at} to mean any representation and not one in particular.
+}
+
+\longnewglossaryentry{atsched}
+{name={Scheduling a \gls{at}}}
+{
+Scheduling an \gls{at} refers to the act of notifying the scheduler that a task is ready to be ran. When representing the scheduler as a queue of tasks, scheduling is the act of pushing a task onto the end of the queue. This doesn't necesserily means the task will ever be allocated CPU time (\gls{atrun}), for example, if the system terminates abruptly, scheduled \glspl{at} will probably never run.
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{atrun}
+{name={Running a \gls{at}}}
+{
+Running an \gls{at} refers to the act of allocating CPU time to a task that is ready to run. When representing the scheduler as a queue of tasks, running is the act of poping a task from the front of the queue and putting it onto a \gls{proc}. The \gls{at} can than accomplish some or all of the work it is programmed to do.
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{atmig}
+{name={migration of \gls{at}}}
+{
+Migration refers to the idea of an \gls{at} running on a different worker/processor than the last time it was run. It is generally preferable to minimise migration as it incurs cost but any load balancing among workers requires some amount of migration.
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{atpass}
+{name={overtaking \gls{at}}}
+{
+When representing the scheduler as a queue of \glspl{at}, overtaking is the act breaking the FIFO-ness of the queue by moving a \gls{at} in front of some other \gls{at} when it arrived after. This remains true for schedulers that do not use a FIFO queue, when the order in which the \glspl{at} are \glslink{atsched}{scheduled} and \glslink{atrun}{run} in a different order. A \gls{at} is said to \emph{overtake} another if it is run \emph{before} but was \emph{scheduled} after the other \gls{at}.
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{atblock}
+{name={Blocking an \gls{at}}}
+{
+Blocking an abstract task refers to the act of taking a task that us running on a CPU off the CPU. Unless no other task is ready, this action is generally immediately followed by running an other task.
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{atcomplet}
+{name={Running to completion}}
+{
+Running to completion refers to the entire sequence of : being scheduled, running and blocking, for a given task.
+
+See also \gls{atsched}, \gls{atrun}, \gls{atblock}
+
+\textit{Synonyms : None.}
+}
+
+\longnewglossaryentry{load}
+{name={System Load}}
+{
+The load is refers to the rate at which \glspl{at} are \glslink{atsched}{scheduled} versus the rate at which they are \glslink{atrun}{run}. When \glspl{at} are being scheduled faster than they are run, the system is considered \emph{overloaded}. When \glspl{at} are being run faster than they are scheduled, the system is considered \emph{underloaded}. Conrrespondingly, if both rates are equal, the system is considered \emph{loaded}. Note that the system is considered loaded only of the rate at which \glspl{at} are scheduled/run is non-zero, otherwise the system is empty, it has no load.
+}
+
+
+\newacronym{tls}{TLS}{Thread Local Storage}
+\newacronym{api}{API}{Application Program Interface}
+\newacronym{raii}{RAII}{Resource Acquisition Is Initialization}
+\newacronym{numa}{NUMA}{Non-Uniform Memory Access}
Index: doc/theses/thierry_delisle_PhD/comp_II/local.bib
===================================================================
--- doc/theses/thierry_delisle_PhD/comp_II/local.bib	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ doc/theses/thierry_delisle_PhD/comp_II/local.bib	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,222 @@
+
+Scheduling Multithreaded Computations by Work Stealing
+
+% ===============================================================================
+% Work stealing examples
+% ===============================================================================
+
+% Cilk [4],
+@article{frigo1998implementation,
+  title={The implementation of the Cilk-5 multithreaded language},
+  author={Frigo, Matteo and Leiserson, Charles E and Randall, Keith H},
+  journal={ACM Sigplan Notices},
+  volume={33},
+  number={5},
+  pages={212--223},
+  year={1998},
+  publisher={ACM}
+}
+
+% Cilk-NOW
+@inproceedings{blumofe1997adaptive,
+  title={Adaptive and reliable parallel computing on networks of workstations},
+  author={Blumofe, Robert D and Lisiecki, Philip A and others},
+  booktitle={USENIX 1997 Annual Technical Conference on UNIX and Advanced Computing Systems},
+  pages={133--147},
+  year={1997}
+}
+
+% Intel Threading Building Blocks (TBB)
+@article{intelTBB,
+  title={Intel R Threading Building Blocks Documentation. Sept. 2013},
+  author={Intel, R},
+  journal={URL: https://www.threadingbuildingblocks.org/docs/help/index.htm}
+}
+
+% Java's Fork-join Framework
+@inproceedings{lea2000java,
+  title={A Java fork/join framework},
+  author={Lea, Doug},
+  booktitle={Proceedings of the ACM 2000 conference on Java Grande},
+  pages={36--43},
+  year={2000},
+  organization={ACM}
+}
+
+% Microsoft Task Parallel Library
+@article{leijen2009design,
+  title={The design of a task parallel library},
+  author={Leijen, Daan and Schulte, Wolfram and Burckhardt, Sebastian},
+  journal={Acm Sigplan Notices},
+  volume={44},
+  number={10},
+  pages={227--242},
+  year={2009},
+  publisher={ACM}
+}
+
+% StackThreads/MP
+@book{taura1999stackthreads,
+  title={Stackthreads/mp: integrating futures into calling standards},
+  author={Taura, Kenjiro and Tabata, Kunio and Yonezawa, Akinori},
+  volume={34},
+  number={8},
+  year={1999},
+  publisher={ACM}
+}
+
+@article{feldmann1993game,
+  title={Game tree search on massively parallel systems},
+  author={Feldmann, Rainer and Mysliwietz, P and Monien, B},
+  journal={Advances in Computer Chess},
+  volume={7},
+  year={1993},
+  publisher={Citeseer}
+}
+
+@article{finkel1987dib,
+  title={DIB—a distributed implementation of backtracking},
+  author={Finkel, Raphael and Manber, Udi},
+  journal={ACM Transactions on Programming Languages and Systems (TOPLAS)},
+  volume={9},
+  number={2},
+  pages={235--256},
+  year={1987},
+  publisher={ACM}
+}
+
+@phdthesis{halbherr1994mimd,
+  title={MIMD-style parallel programming based on continuation-passing threads},
+  author={Halbherr, Michael Roland Sven},
+  year={1994},
+  school={ETH Zurich}
+}
+
+@phdthesis{kuszmaul1994synchronized,
+  title={Synchronized MIMD computing},
+  author={Kuszmaul, Bradley Clair},
+  year={1994},
+  school={Massachusetts Institute of Technology}
+}
+
+@article{mohr1991lazy,
+  title={Lazy task creation: A technique for increasing the granularity of parallel programs},
+  author={Mohr, Eric and Kranz, David A and Halstead, Robert H},
+  journal={IEEE transactions on Parallel and Distributed Systems},
+  volume={2},
+  number={3},
+  pages={264--280},
+  year={1991},
+  publisher={IEEE}
+}
+
+@article{vandevoorde1988workcrews,
+  title={WorkCrews: An abstraction for controlling parallelism},
+  author={Vandevoorde, Mark T and Roberts, Eric S},
+  journal={International Journal of Parallel Programming},
+  volume={17},
+  number={4},
+  pages={347--366},
+  year={1988},
+  publisher={Springer}
+}
+
+
+% ===============================================================================
+% Work stealing examples
+% ===============================================================================
+
+%----------
+% discussion about best case and worst case for full computation
+% cited by 1720
+@article{blumofe1999scheduling,
+  title={Scheduling multithreaded computations by work stealing},
+  author={Blumofe, Robert D and Leiserson, Charles E},
+  journal={Journal of the ACM (JACM)},
+  volume={46},
+  number={5},
+  pages={720--748},
+  year={1999},
+  publisher={ACM}
+}
+
+%----------
+% executing process trees in parallel
+% mostly used with lazy evaluation and dependency graphs
+% cited by 267
+% cited by blumofe1999scheduling as first 'work-stealing idea'
+@inproceedings{burton1981executing,
+  title={Executing functional programs on a virtual tree of processors},
+  author={Burton, F Warren and Sleep, M Ronan},
+  booktitle={Proceedings of the 1981 conference on Functional programming languages and computer architecture},
+  pages={187--194},
+  year={1981},
+  organization={ACM}
+}
+
+
+%----------
+% work-stealing used for multilisp.
+% "unfair scheduling policy"
+% cited by 285
+% cited by blumofe1999scheduling as first 'work-stealing idea' implementation
+@inproceedings{halstead1984implementation,
+  title={Implementation of Multilisp: Lisp on a multiprocessor},
+  author={Halstead Jr, Robert H},
+  booktitle={Proceedings of the 1984 ACM Symposium on LISP and functional programming},
+  pages={9--17},
+  year={1984},
+  organization={ACM}
+}
+
+
+% ===============================================================================
+% HPC schedulers with bounds
+% ===============================================================================
+
+%----------
+% discussion about bounds
+% cited by blumofe1999scheduling
+% mentionned as not practical
+% CAN'T find it
+@article{burton1996guaranteeing,
+  title={Guaranteeing good memory bounds for parallel programs},
+  author={Burton, F Warren},
+  journal={IEEE Transactions on software engineering},
+  number={10},
+  pages={762--773},
+  year={1996},
+  publisher={IEEE}
+}
+
+%----------
+% discussion about bounds
+% cited by blumofe1999scheduling
+% mentionned as not practical
+% - from abstract
+% talks about implicit concurrency
+% does not work online or for something other than HPC
+@inproceedings{blelloch1995provably,
+  title={Provably efficient scheduling for languages with fine-grained parallelism},
+  author={Blelloch, Guy E and Gibbons, Phillip B and Matias, Yossi},
+  booktitle={Proceedings of the seventh annual ACM symposium on Parallel algorithms and architectures},
+  pages={1--12},
+  year={1995},
+  organization={ACM}
+}
+
+%----------
+% discussion about bounds
+% cited by blumofe1999scheduling
+% mentionned as not practical
+% - from abstract
+% talks about bound on total time and space
+% no concept of fairness or latency among tasks
+@inproceedings{blelloch1997space,
+  title={Space-efficient scheduling of parallelism with synchronization variables},
+  author={Blelloch, Guy E and Gibbons, Phillip B and Matias, Yossi and Narlikar, Girija J},
+  booktitle={Proceedings of the ninth annual ACM symposium on Parallel algorithms and architectures},
+  pages={12--23},
+  year={1997},
+  organization={ACM}
+}
Index: driver/cfa.cc
===================================================================
--- driver/cfa.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ driver/cfa.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -411,5 +411,7 @@
 		args[nargs++] = "-lcfathread";
 		args[nargs++] = "-Wl,--pop-state";
+		args[nargs++] = "-Wl,--push-state,--no-as-needed";
 		args[nargs++] = "-lcfa";
+		args[nargs++] = "-Wl,--pop-state";
 		args[nargs++] = "-pthread";
 		args[nargs++] = "-ldl";
Index: libcfa/prelude/Makefile.am
===================================================================
--- libcfa/prelude/Makefile.am	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/prelude/Makefile.am	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -11,6 +11,6 @@
 ## Created On       : Sun May 31 08:54:01 2015
 ## Last Modified By : Peter A. Buhr
-## Last Modified On : Wed Dec 14 15:00:35 2016
-## Update Count     : 205
+## Last Modified On : Mon Feb  3 21:27:18 2020
+## Update Count     : 208
 ###############################################################################
 
@@ -36,4 +36,5 @@
 extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
 	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx > extras.cf
+	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> extras.cf
 
 # create forward declarations for gcc builtins
Index: libcfa/prelude/Makefile.in
===================================================================
--- libcfa/prelude/Makefile.in	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/prelude/Makefile.in	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -1,6 +1,6 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
@@ -331,6 +331,6 @@
 	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
 	  *) \
-	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
 	esac;
 
@@ -377,5 +377,8 @@
 
 
-distdir: $(DISTFILES)
+distdir: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -540,4 +543,5 @@
 extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
 	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx > extras.cf
+	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> extras.cf
 
 # create forward declarations for gcc builtins
Index: libcfa/prelude/extras.regx
===================================================================
--- libcfa/prelude/extras.regx	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/prelude/extras.regx	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -24,8 +24,2 @@
 typedef.* char32_t;
 typedef.* wchar_t;
-extern.*\*malloc\(.*\).*
-extern.* free\(.*\).*
-extern.* exit\(.*\).*
-extern.* atexit\(.*\).*
-extern.* abort\(.*\).*
-extern.* printf\(.*\).*
Index: libcfa/prelude/extras.regx2
===================================================================
--- libcfa/prelude/extras.regx2	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ libcfa/prelude/extras.regx2	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,6 @@
+extern void \*malloc[^;]*;
+extern void free[^;]*;
+extern void exit[^;]*;
+extern int atexit[^;]*;
+extern void abort[^;]*;
+extern int printf[^;]*;
Index: libcfa/prelude/prototypes.awk
===================================================================
--- libcfa/prelude/prototypes.awk	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/prelude/prototypes.awk	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 # Created On       : Sat May 16 07:57:37 2015
 # Last Modified By : Peter A. Buhr
-# Last Modified On : Thu Jun  6 20:46:28 2019
-# Update Count     : 34
+# Last Modified On : Sat Feb  8 09:46:58 2020
+# Update Count     : 36
 #
 
@@ -17,5 +17,5 @@
 
 BEGIN {
-  FS = "[( )]"
+	FS = "[( )]"
 	# order so string search is longest string
 	i=-1
@@ -84,10 +84,10 @@
 
 /BT_FN/ {
-	for (i = 1; i <= NF; i++) {
-	  if( match($i, "BT_FN") != 0 ) {
-		prototypes[$i] = $i
-	  }
+	for (i = 1; i <= NF; i += 1 ) {
+		if ( match($i, "BT_FN") != 0 ) {
+			prototypes[$i] = $i
+		}
 	}
-  }
+}
 
 END {
@@ -103,47 +103,47 @@
 
 	for ( prototype in prototypes ) {
-	  # printf( "//\"%s\"\n", prototype )
-	  if ( index( "BT_LAST", prototype ) == 1 ) {
-		continue
-	  } # if
+		# printf( "//\"%s\"\n", prototype )
+		if ( index( "BT_LAST", prototype ) == 1 ) {
+			continue
+		} # if
 
-	  printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
+		printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
 
-	  if ( sub( "BT_FN_", "", prototype ) == 0 ) {
-		printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
-		exit 0
-	  } # if
+		if ( sub( "BT_FN_", "", prototype ) == 0 ) {
+			printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
+			exit 0
+		} # if
 
-	  # generate function return type as macro
-	  for ( t = 0; t < N; t += 1 ) {					# find longest match
-		type = types[t];
-		if ( index( prototype, type ) == 1 ) {		# found match
-		  printf( "BT_%s, NAME", type )
-		  sub( type, "", prototype )
-		  break;
+		# generate function return type as macro
+		for ( t = 0; t < N; t += 1 ) {					# find longest match
+			type = types[t];
+			if ( index( prototype, type ) == 1 ) {		# found match
+				printf( "BT_%s, NAME", type )
+				sub( type, "", prototype )
+				break;
+			} # if
+		} # for
+
+		# generate function parameter types as macro
+		if ( index( prototype, "VAR" ) != 2 ) {			# C-style empty parameters ?
+			for ( p = 0; length( prototype ) > 0; p += 1 ) { # until all parameters types are removed
+				sub( "_", "", prototype)				# remove "_"
+				printf( ", ", type )
+				temp = prototype
+				for ( t = 0; t < N; t += 1 ) {			# find longest match
+					type = types[t];
+					if ( index( prototype, type ) == 1 ) { # found match
+						printf( "BT_%s", type )
+						sub( type, "", prototype )
+						break;
+					} # if
+				} # for
+				if ( temp == prototype ) {				# no match found for parameter in macro table
+					printf( "\n********** MISSING TYPE \"%s\" **********\n", prototype )
+					exit 0
+				} # if
+			} # for
 		} # if
-	  } # for
-
-	  # generate function parameter types as macro
-	  if ( index( prototype, "VAR" ) != 2 ) {			# C-style empty parameters ?
-		for ( p = 0; length( prototype ) > 0; p += 1 ) { # until all parameters types are removed
-		  sub( "_", "", prototype)				# remove "_"
-		  printf( ", ", type )
-		  temp = prototype
-		  for ( t = 0; t < N; t += 1 ) {			# find longest match
-			type = types[t];
-			if ( index( prototype, type ) == 1 ) { # found match
-			  printf( "BT_%s", type )
-			  sub( type, "", prototype )
-			  break;
-			} # if
-		  } # for
-		  if ( temp == prototype ) {				# no match found for parameter in macro table
-			printf( "\n********** MISSING TYPE \"%s\" **********\n", prototype )
-			exit 0
-		  } # if
-		} # for
-	  } # if
-	  printf( ")\n" )
+		printf( ")\n" )
 	} # for
 
Index: libcfa/src/assert.cfa
===================================================================
--- libcfa/src/assert.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/assert.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov 28 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Nov 21 17:09:26 2019
-// Update Count     : 5
+// Last Modified On : Tue Feb  4 13:00:18 2020
+// Update Count     : 6
 //
 
@@ -26,5 +26,5 @@
 
 	// called by macro assert in assert.h
-	void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function ) {
+	void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) {
 		__cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
 		abort();
@@ -32,5 +32,5 @@
 
 	// called by macro assertf
-	void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {
+	void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) {
 		__cfaabi_bits_acquire();
 		__cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
Index: libcfa/src/bits/debug.cfa
===================================================================
--- libcfa/src/bits/debug.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/bits/debug.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Thu Mar 30 12:30:01 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Nov 21 17:16:30 2019
-// Update Count     : 10
+// Last Modified On : Tue Feb  4 13:03:16 2020
+// Update Count     : 11
 //
 
@@ -27,6 +27,5 @@
 
 extern "C" {
-
-	void __cfaabi_bits_write( int fd, const char *in_buffer, int len ) {
+	void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) {
 		// ensure all data is written
 		for ( int count = 0, retcode; count < len; count += retcode ) {
Index: libcfa/src/bits/debug.hfa
===================================================================
--- libcfa/src/bits/debug.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/bits/debug.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov 28 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Nov 21 17:06:58 2019
-// Update Count     : 8
+// Last Modified On : Tue Feb  4 12:29:21 2020
+// Update Count     : 9
 //
 
@@ -21,6 +21,6 @@
 	#define __cfaabi_dbg_ctx __PRETTY_FUNCTION__
 	#define __cfaabi_dbg_ctx2 , __PRETTY_FUNCTION__
-	#define __cfaabi_dbg_ctx_param const char * caller
-	#define __cfaabi_dbg_ctx_param2 , const char * caller
+	#define __cfaabi_dbg_ctx_param const char caller[]
+	#define __cfaabi_dbg_ctx_param2 , const char caller[]
 #else
 	#define __cfaabi_dbg_debug_do(...)
@@ -38,5 +38,5 @@
 	#include <stdio.h>
 
-	extern void __cfaabi_bits_write( int fd, const char *buffer, int len );
+	extern void __cfaabi_bits_write( int fd, const char buffer[], int len );
 	extern void __cfaabi_bits_acquire();
 	extern void __cfaabi_bits_release();
Index: libcfa/src/bits/locks.hfa
===================================================================
--- libcfa/src/bits/locks.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/bits/locks.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Oct 31 15:14:38 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Aug 11 15:42:24 2018
-// Update Count     : 10
+// Last Modified On : Tue Feb  4 13:03:19 2020
+// Update Count     : 11
 //
 
@@ -54,5 +54,5 @@
 
 		#ifdef __CFA_DEBUG__
-			void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name);
+			void __cfaabi_dbg_record(__spinlock_t & this, const char prev_name[]);
 		#else
 			#define __cfaabi_dbg_record(x, y)
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/concurrency/coroutine.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov 28 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec  5 14:37:29 2019
-// Update Count     : 15
+// Last Modified On : Tue Feb  4 12:29:25 2020
+// Update Count     : 16
 //
 
@@ -89,5 +89,5 @@
 }
 
-void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
+void ?{}( coroutine_desc & this, const char name[], void * storage, size_t storageSize ) with( this ) {
 	(this.context){0p, 0p};
 	(this.stack){storage, storageSize};
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/concurrency/coroutine.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov 28 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Dec  3 22:47:58 2019
-// Update Count     : 10
+// Last Modified On : Tue Feb  4 12:29:26 2020
+// Update Count     : 11
 //
 
@@ -35,5 +35,5 @@
 // void ^?{}( coStack_t & this );
 
-void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
+void ?{}( coroutine_desc & this, const char name[], void * storage, size_t storageSize );
 void ^?{}( coroutine_desc & this );
 
@@ -41,6 +41,6 @@
 static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
 static inline void ?{}( coroutine_desc & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
-static inline void ?{}( coroutine_desc & this, const char * name)                    { this{ name, 0p, 0 }; }
-static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, 0p, stackSize }; }
+static inline void ?{}( coroutine_desc & this, const char name[])                    { this{ name, 0p, 0 }; }
+static inline void ?{}( coroutine_desc & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
 
 //-----------------------------------------------------------------------------
Index: libcfa/src/concurrency/kernel.cfa
===================================================================
--- libcfa/src/concurrency/kernel.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/concurrency/kernel.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jan 17 12:27:26 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jan 30 22:55:50 2020
-// Update Count     : 56
+// Last Modified On : Tue Feb  4 13:03:15 2020
+// Update Count     : 58
 //
 
@@ -210,5 +210,5 @@
 static void * CtxInvokeProcessor(void * arg);
 
-void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
+void ?{}(processor & this, const char name[], cluster & cltr) with( this ) {
 	this.name = name;
 	this.cltr = &cltr;
@@ -244,5 +244,5 @@
 }
 
-void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {
+void ?{}(cluster & this, const char name[], Duration preemption_rate) with( this ) {
 	this.name = name;
 	this.preemption_rate = preemption_rate;
@@ -459,5 +459,5 @@
 }
 
-static void Abort( int ret, const char * func ) {
+static void Abort( int ret, const char func[] ) {
 	if ( ret ) {										// pthread routines return errno values
 		abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) );
@@ -960,5 +960,5 @@
 __cfaabi_dbg_debug_do(
 	extern "C" {
-		void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
+		void __cfaabi_dbg_record(__spinlock_t & this, const char prev_name[]) {
 			this.prev_name = prev_name;
 			this.prev_thrd = kernelTLS.this_thread;
Index: libcfa/src/concurrency/kernel.hfa
===================================================================
--- libcfa/src/concurrency/kernel.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/concurrency/kernel.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jan 17 12:27:26 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Dec  4 07:54:51 2019
-// Update Count     : 18
+// Last Modified On : Tue Feb  4 12:29:26 2020
+// Update Count     : 22
 //
 
@@ -101,10 +101,10 @@
 };
 
-void  ?{}(processor & this, const char * name, struct cluster & cltr);
+void  ?{}(processor & this, const char name[], struct cluster & cltr);
 void ^?{}(processor & this);
 
 static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
 static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
-static inline void  ?{}(processor & this, const char * name) { this{name, *mainCluster }; }
+static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
 
 static inline [processor *&, processor *& ] __get( processor & this ) /*__attribute__((const))*/ { return this.node.[next, prev]; }
@@ -144,10 +144,10 @@
 extern Duration default_preemption();
 
-void ?{} (cluster & this, const char * name, Duration preemption_rate);
+void ?{} (cluster & this, const char name[], Duration preemption_rate);
 void ^?{}(cluster & this);
 
 static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
 static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
-static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
+static inline void ?{} (cluster & this, const char name[])        { this{name, default_preemption()}; }
 
 static inline [cluster *&, cluster *& ] __get( cluster & this ) /*__attribute__((const))*/ { return this.node.[next, prev]; }
Index: libcfa/src/exception.c
===================================================================
--- libcfa/src/exception.c	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/exception.c	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -248,13 +248,7 @@
 }
 
-#if defined(PIC)
-#warning Exceptions not yet supported when using Position-Independent Code
-__attribute__((noinline))
-void __cfaabi_ehm__try_terminate(void (*try_block)(),
-		void (*catch_block)(int index, exception_t * except),
-		__attribute__((unused)) int (*match_block)(exception_t * except)) {
-	abort();
-}
-#else // PIC
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+
 // This is our personality routine. For every stack frame annotated with
 // ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
@@ -431,6 +425,11 @@
 
 	// Setup the personality routine and exception table.
+#ifdef __PIC__
+	asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
+	asm volatile (".cfi_lsda 0x1b, .LLSDACFA2");
+#else
 	asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
 	asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
+#endif
 
 	// Label which defines the start of the area for which the handler is setup.
@@ -464,4 +463,55 @@
 // have a single call to the try routine.
 
+#ifdef __PIC__
+#if defined( __i386 ) || defined( __x86_64 )
+asm (
+	// HEADER
+	".LFECFA1:\n"
+	"	.globl	__gcfa_personality_v0\n"
+	"	.section	.gcc_except_table,\"a\",@progbits\n"
+	// TABLE HEADER (important field is the BODY length at the end)
+	".LLSDACFA2:\n"
+	"	.byte	0xff\n"
+	"	.byte	0xff\n"
+	"	.byte	0x1\n"
+	"	.uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
+	// BODY (language specific data)
+	// This uses language specific data and can be modified arbitrarily
+	// We use handled area offset, handled area length,
+	// handler landing pad offset and 1 (action code, gcc seems to use 0).
+	".LLSDACSBCFA2:\n"
+	"	.uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
+	"	.uleb128 .TRYEND-.TRYSTART\n"
+	"	.uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
+	"	.uleb128 1\n"
+	".LLSDACSECFA2:\n"
+	// TABLE FOOTER
+	"	.text\n"
+	"	.size	__cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
+);
+
+// Somehow this piece of helps with the resolution of debug symbols.
+__attribute__((unused)) static const int dummy = 0;
+
+asm (
+	// Add a hidden symbol which points at the function.
+	"	.hidden	CFA.ref.__gcfa_personality_v0\n"
+	"	.weak	CFA.ref.__gcfa_personality_v0\n"
+	// No clue what this does specifically
+	"	.section	.data.rel.local.CFA.ref.__gcfa_personality_v0,\"awG\",@progbits,CFA.ref.__gcfa_personality_v0,comdat\n"
+	"	.align 8\n"
+	"	.type CFA.ref.__gcfa_personality_v0, @object\n"
+	"	.size CFA.ref.__gcfa_personality_v0, 8\n"
+	"CFA.ref.__gcfa_personality_v0:\n"
+#if defined( __x86_64 )
+	"	.quad __gcfa_personality_v0\n"
+#else // then __i386
+	"   .long __gcfa_personality_v0\n"
+#endif
+);
+#else
+#error Exception Handling: unknown architecture for position independent code.
+#endif // __i386 || __x86_64
+#else // __PIC__
 #if defined( __i386 ) || defined( __x86_64 )
 asm (
@@ -491,6 +541,10 @@
 	"	.size	__cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
 	"	.ident	\"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
-//	"	.section	.note.GNU-stack,\"x\",@progbits\n"
+	"	.section	.note.GNU-stack,\"x\",@progbits\n"
 );
+#else
+#error Exception Handling: unknown architecture for position dependent code.
 #endif // __i386 || __x86_64
-#endif // PIC
+#endif // __PIC__
+
+#pragma GCC pop_options
Index: libcfa/src/fstream.cfa
===================================================================
--- libcfa/src/fstream.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/fstream.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Nov 29 06:56:46 2019
-// Update Count     : 355
+// Last Modified On : Fri Feb  7 19:01:01 2020
+// Update Count     : 363
 //
 
@@ -32,35 +32,35 @@
 
 void ?{}( ofstream & os, void * file ) {
-	os.file = file;
-	os.sepDefault = true;
-	os.sepOnOff = false;
-	os.nlOnOff = true;
-	os.prt = false;
-	os.sawNL = false;
+	os.$file = file;
+	os.$sepDefault = true;
+	os.$sepOnOff = false;
+	os.$nlOnOff = true;
+	os.$prt = false;
+	os.$sawNL = false;
+	$sepSetCur( os, sepGet( os ) );
 	sepSet( os, " " );
-	sepSetCur( os, sepGet( os ) );
 	sepSetTuple( os, ", " );
 } // ?{}
 
 // private
-bool sepPrt( ofstream & os ) { setNL( os, false ); return os.sepOnOff; }
-void sepReset( ofstream & os ) { os.sepOnOff = os.sepDefault; }
-void sepReset( ofstream & os, bool reset ) { os.sepDefault = reset; os.sepOnOff = os.sepDefault; }
-const char * sepGetCur( ofstream & os ) { return os.sepCur; }
-void sepSetCur( ofstream & os, const char * sepCur ) { os.sepCur = sepCur; }
-bool getNL( ofstream & os ) { return os.sawNL; }
-void setNL( ofstream & os, bool state ) { os.sawNL = state; }
-bool getANL( ofstream & os ) { return os.nlOnOff; }
-bool getPrt( ofstream & os ) { return os.prt; }
-void setPrt( ofstream & os, bool state ) { os.prt = state; }
+bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; }
+void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; }
+void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; }
+const char * $sepGetCur( ofstream & os ) { return os.$sepCur; }
+void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur = sepCur; }
+bool $getNL( ofstream & os ) { return os.$sawNL; }
+void $setNL( ofstream & os, bool state ) { os.$sawNL = state; }
+bool $getANL( ofstream & os ) { return os.$nlOnOff; }
+bool $getPrt( ofstream & os ) { return os.$prt; }
+void $setPrt( ofstream & os, bool state ) { os.$prt = state; }
 
 // public
-void ?{}( ofstream & os ) { os.file = 0; }
-
-void ?{}( ofstream & os, const char * name, const char * mode ) {
+void ?{}( ofstream & os ) { os.$file = 0p; }
+
+void ?{}( ofstream & os, const char name[], const char mode[] ) {
 	open( os, name, mode );
 } // ?{}
 
-void ?{}( ofstream & os, const char * name ) {
+void ?{}( ofstream & os, const char name[] ) {
 	open( os, name, "w" );
 } // ?{}
@@ -70,41 +70,41 @@
 } // ^?{}
 
-void sepOn( ofstream & os ) { os.sepOnOff = ! getNL( os ); }
-void sepOff( ofstream & os ) { os.sepOnOff = false; }
+void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); }
+void sepOff( ofstream & os ) { os.$sepOnOff = false; }
 
 bool sepDisable( ofstream & os ) {
-	bool temp = os.sepDefault;
-	os.sepDefault = false;
-	sepReset( os );
+	bool temp = os.$sepDefault;
+	os.$sepDefault = false;
+	$sepReset( os );
 	return temp;
 } // sepDisable
 
 bool sepEnable( ofstream & os ) {
-	bool temp = os.sepDefault;
-	os.sepDefault = true;
-	if ( os.sepOnOff ) sepReset( os );					// start of line ?
+	bool temp = os.$sepDefault;
+	os.$sepDefault = true;
+	if ( os.$sepOnOff ) $sepReset( os );				// start of line ?
 	return temp;
 } // sepEnable
 
-void nlOn( ofstream & os ) { os.nlOnOff = true; }
-void nlOff( ofstream & os ) { os.nlOnOff = false; }
-
-const char * sepGet( ofstream & os ) { return os.separator; }
-void sepSet( ofstream & os, const char * s ) {
+void nlOn( ofstream & os ) { os.$nlOnOff = true; }
+void nlOff( ofstream & os ) { os.$nlOnOff = false; }
+
+const char * sepGet( ofstream & os ) { return os.$separator; }
+void sepSet( ofstream & os, const char s[] ) {
 	assert( s );
-	strncpy( os.separator, s, sepSize - 1 );
-	os.separator[sepSize - 1] = '\0';
+	strncpy( os.$separator, s, sepSize - 1 );
+	os.$separator[sepSize - 1] = '\0';
 } // sepSet
 
-const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator; }
-void sepSetTuple( ofstream & os, const char * s ) {
+const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; }
+void sepSetTuple( ofstream & os, const char s[] ) {
 	assert( s );
-	strncpy( os.tupleSeparator, s, sepSize - 1 );
-	os.tupleSeparator[sepSize - 1] = '\0';
+	strncpy( os.$tupleSeparator, s, sepSize - 1 );
+	os.$tupleSeparator[sepSize - 1] = '\0';
 } // sepSet
 
 void ends( ofstream & os ) {
-	if ( getANL( os ) ) nl( os );
-	else setPrt( os, false );							// turn off
+	if ( $getANL( os ) ) nl( os );
+	else $setPrt( os, false );							// turn off
 	if ( &os == &exit ) exit( EXIT_FAILURE );
 	if ( &os == &abort ) abort();
@@ -112,15 +112,15 @@
 
 int fail( ofstream & os ) {
-	return os.file == 0 || ferror( (FILE *)(os.file) );
+	return os.$file == 0 || ferror( (FILE *)(os.$file) );
 } // fail
 
 int flush( ofstream & os ) {
-	return fflush( (FILE *)(os.file) );
+	return fflush( (FILE *)(os.$file) );
 } // flush
 
-void open( ofstream & os, const char * name, const char * mode ) {
+void open( ofstream & os, const char name[], const char mode[] ) {
 	FILE * file = fopen( name, mode );
 	#ifdef __CFA_DEBUG__
-	if ( file == 0 ) {
+	if ( file == 0p ) {
 		abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
 	} // if
@@ -129,22 +129,22 @@
 } // open
 
-void open( ofstream & os, const char * name ) {
+void open( ofstream & os, const char name[] ) {
 	open( os, name, "w" );
 } // open
 
 void close( ofstream & os ) {
-	if ( (FILE *)(os.file) == stdout || (FILE *)(os.file) == stderr ) return;
-
-	if ( fclose( (FILE *)(os.file) ) == EOF ) {
+	if ( (FILE *)(os.$file) == stdout || (FILE *)(os.$file) == stderr ) return;
+
+	if ( fclose( (FILE *)(os.$file) ) == EOF ) {
 		abort | IO_MSG "close output" | nl | strerror( errno );
 	} // if
 } // close
 
-ofstream & write( ofstream & os, const char * data, size_t size ) {
+ofstream & write( ofstream & os, const char data[], size_t size ) {
 	if ( fail( os ) ) {
 		abort | IO_MSG "attempt write I/O on failed stream";
 	} // if
 
-	if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
+	if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) {
 		abort | IO_MSG "write" | nl | strerror( errno );
 	} // if
@@ -155,7 +155,7 @@
 	va_list args;
 	va_start( args, format );
-	int len = vfprintf( (FILE *)(os.file), format, args );
+	int len = vfprintf( (FILE *)(os.$file), format, args );
 	if ( len == EOF ) {
-		if ( ferror( (FILE *)(os.file) ) ) {
+		if ( ferror( (FILE *)(os.$file) ) ) {
 			abort | IO_MSG "invalid write";
 		} // if
@@ -163,6 +163,6 @@
 	va_end( args );
 
-	setPrt( os, true );									// called in output cascade
-	sepReset( os );										// reset separator
+	$setPrt( os, true );								// called in output cascade
+	$sepReset( os );									// reset separator
 	return len;
 } // fmt
@@ -184,16 +184,16 @@
 // private
 void ?{}( ifstream & is, void * file ) {
-	is.file = file;
-	is.nlOnOff = false;
+	is.$file = file;
+	is.$nlOnOff = false;
 } // ?{}
 
 // public
-void ?{}( ifstream & is ) {	is.file = 0; }
-
-void ?{}( ifstream & is, const char * name, const char * mode ) {
+void ?{}( ifstream & is ) { is.$file = 0p; }
+
+void ?{}( ifstream & is, const char name[], const char mode[] ) {
 	open( is, name, mode );
 } // ?{}
 
-void ?{}( ifstream & is, const char * name ) {
+void ?{}( ifstream & is, const char name[] ) {
 	open( is, name, "r" );
 } // ?{}
@@ -203,34 +203,34 @@
 } // ^?{}
 
-void nlOn( ifstream & os ) { os.nlOnOff = true; }
-void nlOff( ifstream & os ) { os.nlOnOff = false; }
-bool getANL( ifstream & os ) { return os.nlOnOff; }
+void nlOn( ifstream & os ) { os.$nlOnOff = true; }
+void nlOff( ifstream & os ) { os.$nlOnOff = false; }
+bool getANL( ifstream & os ) { return os.$nlOnOff; }
 
 int fail( ifstream & is ) {
-	return is.file == 0 || ferror( (FILE *)(is.file) );
+	return is.$file == 0p || ferror( (FILE *)(is.$file) );
 } // fail
 
 int eof( ifstream & is ) {
-	return feof( (FILE *)(is.file) );
+	return feof( (FILE *)(is.$file) );
 } // eof
 
-void open( ifstream & is, const char * name, const char * mode ) {
+void open( ifstream & is, const char name[], const char mode[] ) {
 	FILE * file = fopen( name, mode );
 	#ifdef __CFA_DEBUG__
-	if ( file == 0 ) {
+	if ( file == 0p ) {
 		abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
 	} // if
 	#endif // __CFA_DEBUG__
-	is.file = file;
-} // open
-
-void open( ifstream & is, const char * name ) {
+	is.$file = file;
+} // open
+
+void open( ifstream & is, const char name[] ) {
 	open( is, name, "r" );
 } // open
 
 void close( ifstream & is ) {
-	if ( (FILE *)(is.file) == stdin ) return;
-
-	if ( fclose( (FILE *)(is.file) ) == EOF ) {
+	if ( (FILE *)(is.$file) == stdin ) return;
+
+	if ( fclose( (FILE *)(is.$file) ) == EOF ) {
 		abort | IO_MSG "close input" | nl | strerror( errno );
 	} // if
@@ -242,5 +242,5 @@
 	} // if
 
-	if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
+	if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) {
 		abort | IO_MSG "read" | nl | strerror( errno );
 	} // if
@@ -253,5 +253,5 @@
 	} // if
 
-	if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
+	if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) {
 		abort | IO_MSG "ungetc" | nl | strerror( errno );
 	} // if
@@ -263,7 +263,7 @@
 
 	va_start( args, format );
-	int len = vfscanf( (FILE *)(is.file), format, args );
+	int len = vfscanf( (FILE *)(is.$file), format, args );
 	if ( len == EOF ) {
-		if ( ferror( (FILE *)(is.file) ) ) {
+		if ( ferror( (FILE *)(is.$file) ) ) {
 			abort | IO_MSG "invalid read";
 		} // if
Index: libcfa/src/fstream.hfa
===================================================================
--- libcfa/src/fstream.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/fstream.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Nov 29 06:56:02 2019
-// Update Count     : 168
+// Last Modified On : Mon Feb 17 08:29:23 2020
+// Update Count     : 175
 //
 
@@ -24,26 +24,26 @@
 enum { sepSize = 16 };
 struct ofstream {
-	void * file;
-	bool sepDefault;
-	bool sepOnOff;
-	bool nlOnOff;
-	bool prt;											// print text
-	bool sawNL;
-	const char * sepCur;
-	char separator[sepSize];
-	char tupleSeparator[sepSize];
+	void * $file;
+	bool $sepDefault;
+	bool $sepOnOff;
+	bool $nlOnOff;
+	bool $prt;											// print text
+	bool $sawNL;
+	const char * $sepCur;
+	char $separator[sepSize];
+	char $tupleSeparator[sepSize];
 }; // ofstream
 
 // private
-bool sepPrt( ofstream & );
-void sepReset( ofstream & );
-void sepReset( ofstream &, bool );
-const char * sepGetCur( ofstream & );
-void sepSetCur( ofstream &, const char * );
-bool getNL( ofstream & );
-void setNL( ofstream &, bool );
-bool getANL( ofstream & );
-bool getPrt( ofstream & );
-void setPrt( ofstream &, bool );
+bool $sepPrt( ofstream & );
+void $sepReset( ofstream & );
+void $sepReset( ofstream &, bool );
+const char * $sepGetCur( ofstream & );
+void $sepSetCur( ofstream &, const char [] );
+bool $getNL( ofstream & );
+void $setNL( ofstream &, bool );
+bool $getANL( ofstream & );
+bool $getPrt( ofstream & );
+void $setPrt( ofstream &, bool );
 
 // public
@@ -56,20 +56,20 @@
 
 const char * sepGet( ofstream & );
-void sepSet( ofstream &, const char * );
+void sepSet( ofstream &, const char [] );
 const char * sepGetTuple( ofstream & );
-void sepSetTuple( ofstream &, const char * );
+void sepSetTuple( ofstream &, const char [] );
 
 void ends( ofstream & os );
 int fail( ofstream & );
 int flush( ofstream & );
-void open( ofstream &, const char * name, const char * mode );
-void open( ofstream &, const char * name );
+void open( ofstream &, const char name[], const char mode[] );
+void open( ofstream &, const char name[] );
 void close( ofstream & );
-ofstream & write( ofstream &, const char * data, size_t size );
-int fmt( ofstream &, const char format[], ... );
+ofstream & write( ofstream &, const char data[], size_t size );
+int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
 
 void ?{}( ofstream & os );
-void ?{}( ofstream & os, const char * name, const char * mode );
-void ?{}( ofstream & os, const char * name );
+void ?{}( ofstream & os, const char name[], const char mode[] );
+void ?{}( ofstream & os, const char name[] );
 void ^?{}( ofstream & os );
 
@@ -82,6 +82,6 @@
 
 struct ifstream {
-	void * file;
-	bool nlOnOff;
+	void * $file;
+	bool $nlOnOff;
 }; // ifstream
 
@@ -92,14 +92,14 @@
 int fail( ifstream & is );
 int eof( ifstream & is );
-void open( ifstream & is, const char * name, const char * mode );
-void open( ifstream & is, const char * name );
+void open( ifstream & is, const char name[], const char mode[] );
+void open( ifstream & is, const char name[] );
 void close( ifstream & is );
 ifstream & read( ifstream & is, char * data, size_t size );
 ifstream & ungetc( ifstream & is, char c );
-int fmt( ifstream &, const char format[], ... );
+int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
 
 void ?{}( ifstream & is );
-void ?{}( ifstream & is, const char * name, const char * mode );
-void ?{}( ifstream & is, const char * name );
+void ?{}( ifstream & is, const char name[], const char mode[] );
+void ?{}( ifstream & is, const char name[] );
 void ^?{}( ifstream & is );
 
Index: libcfa/src/gmp.hfa
===================================================================
--- libcfa/src/gmp.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/gmp.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Apr 19 08:43:43 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 13 15:25:05 2019
-// Update Count     : 27
+// Last Modified On : Sun Feb  9 09:56:54 2020
+// Update Count     : 31
 //
 
@@ -24,12 +24,10 @@
 
 static inline {
-	// constructor
+	// constructor, zero_t/one_t are unnecessary because of relationship with signed/unsigned int
 	void ?{}( Int & this ) { mpz_init( this.mpz ); }
 	void ?{}( Int & this, Int init ) { mpz_init_set( this.mpz, init.mpz ); }
-	void ?{}( Int & this, zero_t ) { mpz_init_set_si( this.mpz, 0 ); }
-	void ?{}( Int & this, one_t ) { mpz_init_set_si( this.mpz, 1 ); }
 	void ?{}( Int & this, signed long int init ) { mpz_init_set_si( this.mpz, init ); }
 	void ?{}( Int & this, unsigned long int init ) { mpz_init_set_ui( this.mpz, init ); }
-	void ?{}( Int & this, const char * val ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
+	void ?{}( Int & this, const char val[] ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
 	void ^?{}( Int & this ) { mpz_clear( this.mpz ); }
 
@@ -37,5 +35,5 @@
 	Int ?`mp( signed long int init ) { return (Int){ init }; }
 	Int ?`mp( unsigned long int init ) { return (Int){ init }; }
-	Int ?`mp( const char * init ) { return (Int){ init }; }
+	Int ?`mp( const char init[] ) { return (Int){ init }; }
 
 	// assignment
@@ -43,5 +41,5 @@
 	Int ?=?( Int & lhs, long int rhs ) { mpz_set_si( lhs.mpz, rhs ); return lhs; }
 	Int ?=?( Int & lhs, unsigned long int rhs ) { mpz_set_ui( lhs.mpz, rhs ); return lhs; }
-	Int ?=?( Int & lhs, const char * rhs ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
+	Int ?=?( Int & lhs, const char rhs[] ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
 
 	char ?=?( char & lhs, Int rhs ) { char val = mpz_get_si( rhs.mpz ); lhs = val; return lhs; }
@@ -265,5 +263,5 @@
 	forall( dtype ostype | ostream( ostype ) ) {
 		ostype & ?|?( ostype & os, Int mp ) {
-			if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+			if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 			gmp_printf( "%Zd", mp.mpz );
 			sepOn( os );
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/heap.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Dec  8 21:01:31 2019
-// Update Count     : 647
+// Last Modified On : Tue Feb  4 10:04:51 2020
+// Update Count     : 648
 //
 
@@ -380,5 +380,5 @@
 
 
-static inline void checkHeader( bool check, const char * name, void * addr ) {
+static inline void checkHeader( bool check, const char name[], void * addr ) {
 	if ( unlikely( check ) ) {							// bad address ?
 		abort( "Attempt to %s storage %p with address outside the heap.\n"
@@ -418,5 +418,5 @@
 
 
-static inline bool headers( const char * name __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
+static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
 	header = headerAddr( addr );
 
Index: libcfa/src/interpose.cfa
===================================================================
--- libcfa/src/interpose.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/interpose.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Mar 29 16:10:31 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jan 30 17:47:32 2020
-// Update Count     : 156
+// Last Modified On : Mon Feb 17 10:18:53 2020
+// Update Count     : 166
 //
 
@@ -29,4 +29,5 @@
 #include "bits/signal.hfa"								// sigHandler_?
 #include "startup.hfa"									// STARTUP_PRIORITY_CORE
+#include <assert.h>
 
 //=============================================================================================
@@ -40,5 +41,5 @@
 
 typedef void (* generic_fptr_t)(void);
-generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
+generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
 	const char * error;
 
@@ -145,5 +146,5 @@
 extern "C" {
 	void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
-		abort( false, NULL ); // FIX ME: 0p does not work
+		abort( false, "%s", "" );
 	}
 
@@ -161,5 +162,5 @@
 
 void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; }
-void kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
+void kernel_abort_msg( void * data, char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
 // See concurrency/kernel.cfa for strong definition used in multi-processor mode.
 int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
@@ -169,12 +170,10 @@
 
 static void __cfaabi_backtrace( int start ) {
-	enum {
-		Frames = 50,									// maximum number of stack frames
-	};
+	enum { Frames = 50, };								// maximum number of stack frames
 	int last = kernel_abort_lastframe();				// skip last N stack frames
 
 	void * array[Frames];
 	size_t size = backtrace( array, Frames );
-	char ** messages = backtrace_symbols( array, size );
+	char ** messages = backtrace_symbols( array, size ); // does not demangle names
 
 	*index( messages[0], '(' ) = '\0';					// find executable name
@@ -184,5 +183,5 @@
 		char * name = 0p, * offset_begin = 0p, * offset_end = 0p;
 
-		for ( char * p = messages[i]; *p; ++p ) {		// find parantheses and +offset
+		for ( char * p = messages[i]; *p; p += 1 ) {	// find parantheses and +offset
 			//__cfaabi_bits_print_nolock( "X %s\n", p);
 			if ( *p == '(' ) {
@@ -228,19 +227,18 @@
 	__cfaabi_bits_write( STDERR_FILENO, abort_text, len );
 
-	if ( fmt ) {
-		va_list args;
-		va_start( args, fmt );
-
-		len = vsnprintf( abort_text, abort_text_size, fmt, args );
-		va_end( args );
-		__cfaabi_bits_write( STDERR_FILENO, abort_text, len );
-
-		if ( fmt[strlen( fmt ) - 1] != '\n' ) {			// add optional newline if missing at the end of the format text
-			__cfaabi_dbg_write( "\n", 1 );
-		}
-	}
-
+	assert( fmt );
+	va_list args;
+	va_start( args, fmt );
+
+	len = vsnprintf( abort_text, abort_text_size, fmt, args );
+	va_end( args );
+	__cfaabi_bits_write( STDERR_FILENO, abort_text, len );
+
+	if ( fmt[strlen( fmt ) - 1] != '\n' ) {				// add optional newline if missing at the end of the format text
+		__cfaabi_dbg_write( "\n", 1 );
+	} // if
 	kernel_abort_msg( kernel_data, abort_text, abort_text_size );
-	__cfaabi_backtrace( signalAbort ? 4 : 3 );
+
+	__cfaabi_backtrace( signalAbort ? 4 : 2 );
 
 	__cabi_libc.abort();								// print stack trace in handler
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/iostream.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 13 08:07:59 2019
-// Update Count     : 821
+// Last Modified On : Thu Feb 20 15:53:23 2020
+// Update Count     : 829
 //
 
@@ -19,4 +19,5 @@
 #include <stdio.h>
 #include <stdbool.h>									// true/false
+#include <stdint.h>										// UINT64_MAX
 //#include <string.h>									// strlen, strcmp
 extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
@@ -35,5 +36,5 @@
 forall( dtype ostype | ostream( ostype ) ) {
 	ostype & ?|?( ostype & os, zero_t ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%d", 0n );
 		return os;
@@ -44,5 +45,5 @@
 
 	ostype & ?|?( ostype & os, one_t ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%d", 1n );
 		return os;
@@ -53,5 +54,5 @@
 
 	ostype & ?|?( ostype & os, bool b ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%s", b ? "true" : "false" );
 		return os;
@@ -63,5 +64,5 @@
 	ostype & ?|?( ostype & os, char c ) {
 		fmt( os, "%c", c );
-		if ( c == '\n' ) setNL( os, true );
+		if ( c == '\n' ) $setNL( os, true );
 		return sepOff( os );
 	} // ?|?
@@ -71,5 +72,5 @@
 
 	ostype & ?|?( ostype & os, signed char sc ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%hhd", sc );
 		return os;
@@ -80,5 +81,5 @@
 
 	ostype & ?|?( ostype & os, unsigned char usc ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%hhu", usc );
 		return os;
@@ -89,5 +90,5 @@
 
 	ostype & ?|?( ostype & os, short int si ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%hd", si );
 		return os;
@@ -98,5 +99,5 @@
 
 	ostype & ?|?( ostype & os, unsigned short int usi ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%hu", usi );
 		return os;
@@ -107,5 +108,5 @@
 
 	ostype & ?|?( ostype & os, int i ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%d", i );
 		return os;
@@ -116,5 +117,5 @@
 
 	ostype & ?|?( ostype & os, unsigned int ui ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%u", ui );
 		return os;
@@ -125,5 +126,5 @@
 
 	ostype & ?|?( ostype & os, long int li ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%ld", li );
 		return os;
@@ -134,5 +135,5 @@
 
 	ostype & ?|?( ostype & os, unsigned long int uli ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%lu", uli );
 		return os;
@@ -143,5 +144,5 @@
 
 	ostype & ?|?( ostype & os, long long int lli ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%lld", lli );
 		return os;
@@ -152,5 +153,5 @@
 
 	ostype & ?|?( ostype & os, unsigned long long int ulli ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%llu", ulli );
 		return os;
@@ -159,4 +160,44 @@
 		(ostype &)(os | ulli); ends( os );
 	} // ?|?
+
+#if defined( __SIZEOF_INT128__ )
+	//      UINT64_MAX 18_446_744_073_709_551_615_ULL
+	#define P10_UINT64 10_000_000_000_000_000_000_ULL	// 19 zeroes
+
+	static void base10_128( ostype & os, unsigned int128 val ) {
+		if ( val > UINT64_MAX ) {
+			base10_128( os, val / P10_UINT64 );			// recursive
+			fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
+		} else {
+			fmt( os, "%lu", (uint64_t)val );
+		} // if
+	} // base10_128
+
+	static void base10_128( ostype & os, int128 val ) {
+		if ( val < 0 ) {
+			fmt( os, "-" );								// leading negative sign
+			val = -val;
+		} // if
+		base10_128( os, (unsigned int128)val );			// print zero/positive value
+	} // base10_128
+
+	ostype & ?|?( ostype & os, int128 llli ) {
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
+		base10_128( os, llli );
+		return os;
+	} // ?|?
+	void & ?|?( ostype & os, int128 llli ) {
+		(ostype &)(os | llli); ends( os );
+	} // ?|?
+
+	ostype & ?|?( ostype & os, unsigned int128 ullli ) {
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
+		base10_128( os, ullli );
+		return os;
+	} // ?|?
+	void & ?|?( ostype & os, unsigned int128 ullli ) {
+		(ostype &)(os | ullli); ends( os );
+	} // ?|?
+#endif // __SIZEOF_INT128__
 
 	#define PrintWithDP( os, format, val, ... ) \
@@ -175,5 +216,5 @@
 
 	ostype & ?|?( ostype & os, float f ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		PrintWithDP( os, "%g", f );
 		return os;
@@ -184,5 +225,5 @@
 
 	ostype & ?|?( ostype & os, double d ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		PrintWithDP( os, "%.*lg", d, DBL_DIG );
 		return os;
@@ -193,5 +234,5 @@
 
 	ostype & ?|?( ostype & os, long double ld ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
 		return os;
@@ -202,5 +243,5 @@
 
 	ostype & ?|?( ostype & os, float _Complex fc ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 //		os | crealf( fc ) | nonl;
 		PrintWithDP( os, "%g", crealf( fc ) );
@@ -214,5 +255,5 @@
 
 	ostype & ?|?( ostype & os, double _Complex dc ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 //		os | creal( dc ) | nonl;
 		PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG );
@@ -226,5 +267,5 @@
 
 	ostype & ?|?( ostype & os, long double _Complex ldc ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 //		os | creall( ldc ) || nonl;
 		PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG );
@@ -237,5 +278,5 @@
 	} // ?|?
 
-	ostype & ?|?( ostype & os, const char * str ) {
+	ostype & ?|?( ostype & os, const char str[] ) {
 		enum { Open = 1, Close, OpenClose };
 		static const unsigned char mask[256] @= {
@@ -257,28 +298,29 @@
 		// first character IS NOT spacing or closing punctuation => add left separator
 		unsigned char ch = str[0];						// must make unsigned
-		if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
-			fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
+			fmt( os, "%s", $sepGetCur( os ) );
 		} // if
 
 		// if string starts line, must reset to determine open state because separator is off
-		sepReset( os );									// reset separator
+		$sepReset( os );								// reset separator
 
 		// last character IS spacing or opening punctuation => turn off separator for next item
 		size_t len = strlen( str );
 		ch = str[len - 1];								// must make unsigned
-		if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
+		if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
 			sepOn( os );
 		} else {
 			sepOff( os );
 		} // if
-		if ( ch == '\n' ) setNL( os, true );			// check *AFTER* sepPrt call above as it resets NL flag
+		if ( ch == '\n' ) $setNL( os, true );			// check *AFTER* $sepPrt call above as it resets NL flag
 		return write( os, str, len );
 	} // ?|?
-	void ?|?( ostype & os, const char * str ) {
+
+	void ?|?( ostype & os, const char str[] ) {
 		(ostype &)(os | str); ends( os );
 	} // ?|?
 
 // 	ostype & ?|?( ostype & os, const char16_t * str ) {
-// 		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+// 		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 // 		fmt( os, "%ls", str );
 // 		return os;
@@ -287,5 +329,5 @@
 // #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
 // 	ostype & ?|?( ostype & os, const char32_t * str ) {
-// 		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+// 		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 // 		fmt( os, "%ls", str );
 // 		return os;
@@ -294,5 +336,5 @@
 
 // 	ostype & ?|?( ostype & os, const wchar_t * str ) {
-// 		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+// 		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 // 		fmt( os, "%ls", str );
 // 		return os;
@@ -300,5 +342,5 @@
 
 	ostype & ?|?( ostype & os, const void * p ) {
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 		fmt( os, "%p", p );
 		return os;
@@ -315,6 +357,6 @@
 	void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
 		(ostype &)(manip( os ));
-		if ( getPrt( os ) ) ends( os );					// something printed ?
-		setPrt( os, false );							// turn off
+		if ( $getPrt( os ) ) ends( os );				// something printed ?
+		$setPrt( os, false );							// turn off
 	} // ?|?
 
@@ -329,6 +371,6 @@
 	ostype & nl( ostype & os ) {
 		(ostype &)(os | '\n');
-		setPrt( os, false );							// turn off
-		setNL( os, true );
+		$setPrt( os, false );							// turn off
+		$setNL( os, true );
 		flush( os );
 		return sepOff( os );							// prepare for next line
@@ -336,5 +378,5 @@
 
 	ostype & nonl( ostype & os ) {
-		setPrt( os, false );							// turn off
+		$setPrt( os, false );							// turn off
 		return os;
 	} // nonl
@@ -375,7 +417,7 @@
 	ostype & ?|?( ostype & os, T arg, Params rest ) {
 		(ostype &)(os | arg);							// print first argument
-		sepSetCur( os, sepGetTuple( os ) );				// switch to tuple separator
+		$sepSetCur( os, sepGetTuple( os ) );			// switch to tuple separator
 		(ostype &)(os | rest);							// print remaining arguments
-		sepSetCur( os, sepGet( os ) );					// switch to regular separator
+		$sepSetCur( os, sepGet( os ) );					// switch to regular separator
 		return os;
 	} // ?|?
@@ -383,7 +425,7 @@
 		// (ostype &)(?|?( os, arg, rest )); ends( os );
 		(ostype &)(os | arg);							// print first argument
-		sepSetCur( os, sepGetTuple( os ) );				// switch to tuple separator
+		$sepSetCur( os, sepGetTuple( os ) );			// switch to tuple separator
 		(ostype &)(os | rest);							// print remaining arguments
-		sepSetCur( os, sepGet( os ) );					// switch to regular separator
+		$sepSetCur( os, sepGet( os ) );					// switch to regular separator
 		ends( os );
 	} // ?|?
@@ -414,5 +456,5 @@
 forall( dtype ostype | ostream( ostype ) ) { \
 	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
 \
 		if ( f.base == 'b' || f.base == 'B' ) {			/* bespoke binary format */ \
@@ -463,10 +505,10 @@
 \
 		if ( ! f.flags.pc ) {							/* no precision */ \
-			/* printf( "%s\n", &fmtstr[star] ); */ \
 			fmtstr[sizeof(IFMTNP)-2] = f.base;			/* sizeof includes '\0' */ \
+			/* printf( "%s %c %c\n", &fmtstr[star], f.base, CODE ); */ \
 			fmt( os, &fmtstr[star], f.wd, f.val ); \
 		} else {										/* precision */ \
 			fmtstr[sizeof(IFMTP)-2] = f.base;			/* sizeof includes '\0' */ \
-			/* printf( "%s\n", &fmtstr[star] ); */ \
+			/* printf( "%s %c %c\n", &fmtstr[star], f.base, CODE ); */ \
 			fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \
 		} /* if */ \
@@ -486,4 +528,74 @@
 IntegralFMTImpl( signed long long int, 'd', "%    *ll ", "%    *.*ll " )
 IntegralFMTImpl( unsigned long long int, 'u', "%    *ll ", "%    *.*ll " )
+
+
+#if defined( __SIZEOF_INT128__ )
+// Default prefix for non-decimal prints is 0b, 0, 0x.
+#define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
+forall( dtype ostype | ostream( ostype ) ) \
+static void base10_128( ostype & os, _Ostream_Manip(T) fmt ) { \
+	if ( fmt.val > UINT64_MAX ) { \
+		fmt.val /= P10_UINT64; \
+		base10_128( os, fmt ); /* recursive */ \
+		_Ostream_Manip(unsigned long long int) fmt2 @= { (uint64_t)(fmt.val % P10_UINT64), 0, 19, 'u', { .all : 0 } }; \
+		fmt2.flags.nobsdp = true; \
+		printf( "fmt2 %c %lld %d\n", fmt2.base, fmt2.val, fmt2.all );	\
+		sepOff( os ); \
+		(ostype &)(os | fmt2); \
+	} else { \
+		printf( "fmt %c %lld %d\n", fmt.base, fmt.val, fmt.all ); \
+		(ostype &)(os | fmt); \
+	} /* if */ \
+} /* base10_128 */						   \
+forall( dtype ostype | ostream( ostype ) ) { \
+	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
+\
+		if ( f.base == 'b' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
+			unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
+			unsigned long long int lsig = (unsigned long long int)(f.val); \
+			_Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
+			_Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
+			if ( msig == 0 ) { \
+				fmt.val = lsig; \
+				(ostype &)(os | fmt); \
+			} else { \
+				fmt2.flags.pad0 = fmt2.flags.nobsdp = true;	\
+				if ( f.base == 'b' ) { \
+					if ( f.wd > 64 ) fmt.wd = f.wd - 64; \
+					fmt2.wd = 64; \
+					(ostype &)(os | fmt | "" | fmt2); \
+				} else if ( f.base == 'o' ) { \
+					fmt.val = (unsigned long long int)fmt.val >> 2; \
+					if ( f.wd > 21 ) fmt.wd = f.wd - 21; \
+					fmt2.wd = 1; \
+					fmt2.val = ((msig & 0x3) << 1) + 1; \
+					(ostype &)(os | fmt | "" | fmt2); \
+					sepOff( os ); \
+					fmt2.wd = 21; \
+					fmt2.val = lsig & 0x7fffffffffffffff; \
+					(ostype &)(os | fmt2); \
+				} else { \
+					if ( f.flags.left ) { \
+						if ( f.wd > 16 ) fmt2.wd = f.wd - 16;	\
+						fmt.wd = 16;							\
+					} else { \
+						if ( f.wd > 16 ) fmt.wd = f.wd - 16;	\
+						fmt2.wd = 16;							\
+					} /* if */ \
+					(ostype &)(os | fmt | "" | fmt2); \
+				} /* if */ \
+			} /* if */ \
+		} else { \
+			base10_128( os, f ); \
+		} /* if */ \
+		return os; \
+	} /* ?|? */ \
+	void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
+} // distribution
+
+IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
+IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
+#endif // __SIZEOF_INT128__
 
 //*********************************** floating point ***********************************
@@ -513,5 +625,5 @@
 forall( dtype ostype | ostream( ostype ) ) { \
 	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
 		char fmtstr[sizeof(DFMTP)];						/* sizeof includes '\0' */ \
 		if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
@@ -536,4 +648,5 @@
 		return os; \
 	} /* ?|? */ \
+\
 	void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
 } // distribution
@@ -555,5 +668,5 @@
 		} // if
 
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 
 		#define CFMTNP "% * "
@@ -571,4 +684,5 @@
 		return os;
 	} // ?|?
+
 	void ?|?( ostype & os, _Ostream_Manip(char) f ) { (ostype &)(os | f); ends( os ); }
 } // distribution
@@ -592,5 +706,5 @@
 		} // if
 
-		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
+		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
 
 		#define SFMTNP "% * "
@@ -616,4 +730,5 @@
 		return os;
 	} // ?|?
+
 	void ?|?( ostype & os, _Ostream_Manip(const char *) f ) { (ostype &)(os | f); ends( os ); }
 } // distribution
@@ -735,5 +850,5 @@
 	} // ?|?
 
-	// istype & ?|?( istype & is, const char * fmt ) {
+	// istype & ?|?( istype & is, const char fmt[] ) {
 	// 	fmt( is, fmt, "" );
 	// 	return is;
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/iostream.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 12 12:08:38 2019
-// Update Count     : 334
+// Last Modified On : Thu Feb 20 15:30:56 2020
+// Update Count     : 337
 //
 
@@ -24,14 +24,14 @@
 trait ostream( dtype ostype ) {
 	// private
-	bool sepPrt( ostype & );							// get separator state (on/off)
-	void sepReset( ostype & );							// set separator state to default state
-	void sepReset( ostype &, bool );					// set separator and default state
-	const char * sepGetCur( ostype & );					// get current separator string
-	void sepSetCur( ostype &, const char * );			// set current separator string
-	bool getNL( ostype & );								// check newline
-	void setNL( ostype &, bool );						// saw newline
-	bool getANL( ostype & );							// get auto newline (on/off)
-	bool getPrt( ostype & );							// get fmt called in output cascade
-	void setPrt( ostype &, bool );						// set fmt called in output cascade
+	bool $sepPrt( ostype & );							// get separator state (on/off)
+	void $sepReset( ostype & );							// set separator state to default state
+	void $sepReset( ostype &, bool );					// set separator and default state
+	const char * $sepGetCur( ostype & );				// get current separator string
+	void $sepSetCur( ostype &, const char [] );			// set current separator string
+	bool $getNL( ostype & );							// check newline
+	void $setNL( ostype &, bool );						// saw newline
+	bool $getANL( ostype & );							// get auto newline (on/off)
+	bool $getPrt( ostype & );							// get fmt called in output cascade
+	void $setPrt( ostype &, bool );						// set fmt called in output cascade
 	// public
 	void sepOn( ostype & );								// turn separator state on
@@ -43,14 +43,14 @@
 
 	const char * sepGet( ostype & );					// get separator string
-	void sepSet( ostype &, const char * );				// set separator to string (15 character maximum)
+	void sepSet( ostype &, const char [] );				// set separator to string (15 character maximum)
 	const char * sepGetTuple( ostype & );				// get tuple separator string
-	void sepSetTuple( ostype &, const char * );			// set tuple separator to string (15 character maximum)
+	void sepSetTuple( ostype &, const char [] );		// set tuple separator to string (15 character maximum)
 
 	void ends( ostype & os );							// end of output statement
 	int fail( ostype & );
 	int flush( ostype & );
-	void open( ostype & os, const char * name, const char * mode );
+	void open( ostype & os, const char name[], const char mode[] );
 	void close( ostype & os );
-	ostype & write( ostype &, const char *, size_t );
+	ostype & write( ostype &, const char [], size_t );
 	int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
 }; // ostream
@@ -98,4 +98,10 @@
 	ostype & ?|?( ostype &, unsigned long long int );
 	void ?|?( ostype &, unsigned long long int );
+#if defined( __SIZEOF_INT128__ )
+	ostype & ?|?( ostype &, int128 );
+	void ?|?( ostype &, int128 );
+	ostype & ?|?( ostype &, unsigned int128 );
+	void ?|?( ostype &, unsigned int128 );
+#endif // __SIZEOF_INT128__
 
 	ostype & ?|?( ostype &, float );
@@ -113,6 +119,6 @@
 	void ?|?( ostype &, long double _Complex );
 
-	ostype & ?|?( ostype &, const char * );
-	void ?|?( ostype &, const char * );
+	ostype & ?|?( ostype &, const char [] );
+	void ?|?( ostype &, const char [] );
 	// ostype & ?|?( ostype &, const char16_t * );
 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
@@ -206,4 +212,8 @@
 IntegralFMTDecl( signed long long int, 'd' )
 IntegralFMTDecl( unsigned long long int, 'u' )
+#if defined( __SIZEOF_INT128__ )
+IntegralFMTDecl( int128, 'd' )
+IntegralFMTDecl( unsigned int128, 'u' )
+#endif
 
 //*********************************** floating point ***********************************
@@ -256,9 +266,9 @@
 
 static inline {
-	_Ostream_Manip(const char *) bin( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
-	_Ostream_Manip(const char *) oct( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
-	_Ostream_Manip(const char *) hex( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
-	_Ostream_Manip(const char *) wd( unsigned int w, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
-	_Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
+	_Ostream_Manip(const char *) bin( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
+	_Ostream_Manip(const char *) oct( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
+	_Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
+	_Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
+	_Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
 	_Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
 	_Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
@@ -281,5 +291,5 @@
 	int fail( istype & );
 	int eof( istype & );
-	void open( istype & is, const char * name );
+	void open( istype & is, const char name[] );
 	void close( istype & is );
 	istype & read( istype &, char *, size_t );
@@ -316,5 +326,5 @@
 	istype & ?|?( istype &, long double _Complex & );
 
-//	istype & ?|?( istype &, const char * );
+//	istype & ?|?( istype &, const char [] );
 	istype & ?|?( istype &, char * );
 
@@ -343,12 +353,12 @@
 static inline {
 	_Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
-	_Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
-	_Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
-	_Istream_Cstr & incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
-	_Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
-	_Istream_Cstr & excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
-	_Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
+	_Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
+	_Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
+	_Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
+	_Istream_Cstr excl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
+	_Istream_Cstr & excl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
+	_Istream_Cstr ignore( const char s[] ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
 	_Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
-	_Istream_Cstr wdi( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
+	_Istream_Cstr wdi( unsigned int w, char s[] ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
 	_Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
 } // distribution
Index: libcfa/src/math.hfa
===================================================================
--- libcfa/src/math.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/math.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Apr 18 23:37:04 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 13 11:02:15 2018
-// Update Count     : 116
+// Last Modified On : Tue Feb  4 10:27:11 2020
+// Update Count     : 117
 //
 
@@ -51,7 +51,7 @@
 static inline long double fdim( long double x, long double y ) { return fdiml( x, y ); }
 
-static inline float nan( const char * tag ) { return nanf( tag ); }
-// extern "C" { double nan( const char * ); }
-static inline long double nan( const char * tag ) { return nanl( tag ); }
+static inline float nan( const char tag[] ) { return nanf( tag ); }
+// extern "C" { double nan( const char [] ); }
+static inline long double nan( const char tag[] ) { return nanl( tag ); }
 
 //---------------------- Exponential ----------------------
Index: libcfa/src/rational.cfa
===================================================================
--- libcfa/src/rational.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/rational.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Apr  6 17:54:28 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 12 18:12:08 2019
-// Update Count     : 184
+// Last Modified On : Sat Feb  8 17:56:36 2020
+// Update Count     : 187
 //
 
@@ -56,4 +56,11 @@
 	} // rational
 
+	void ?{}( Rational(RationalImpl) & r, zero_t ) {
+		r{ (RationalImpl){0}, (RationalImpl){1} };
+	} // rational
+
+	void ?{}( Rational(RationalImpl) & r, one_t ) {
+		r{ (RationalImpl){1}, (RationalImpl){1} };
+	} // rational
 
 	// getter for numerator/denominator
Index: libcfa/src/startup.cfa
===================================================================
--- libcfa/src/startup.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/startup.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jul 24 16:21:57 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 13:16:45 2019
-// Update Count     : 29
+// Last Modified On : Tue Feb  4 13:03:18 2020
+// Update Count     : 30
 //
 
@@ -41,5 +41,5 @@
 struct __spinlock_t;
 extern "C" {
-	void __cfaabi_dbg_record(struct __spinlock_t & this, const char * prev_name) __attribute__(( weak )) {}
+	void __cfaabi_dbg_record(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {}
 }
 
Index: libcfa/src/stdhdr/assert.h
===================================================================
--- libcfa/src/stdhdr/assert.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdhdr/assert.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jul  4 23:25:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jul 31 23:09:32 2017
-// Update Count     : 13
+// Last Modified On : Tue Feb  4 12:58:49 2020
+// Update Count     : 15
 //
 
@@ -27,5 +27,5 @@
 	#define assertf( expr, fmt, ... ) ((expr) ? ((void)0) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ ))
 
-	void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn, format( printf, 5, 6) ));
+	void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) __attribute__((noreturn, format( printf, 5, 6) ));
 #endif
 
Index: libcfa/src/stdhdr/bfdlink.h
===================================================================
--- libcfa/src/stdhdr/bfdlink.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdhdr/bfdlink.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,11 +10,11 @@
 // Created On       : Tue Jul 18 07:26:04 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 07:15:29 2020
-// Update Count     : 5
+// Last Modified On : Fri Feb  7 19:05:08 2020
+// Update Count     : 6
 // 
 
 // include file uses the CFA keyword "with".
 #if ! defined( with )									// nesting ?
-#define with ``with``									// make keyword an identifier
+#define with ``with										// make keyword an identifier
 #define __CFA_BFDLINK_H__
 #endif
Index: libcfa/src/stdhdr/hwloc.h
===================================================================
--- libcfa/src/stdhdr/hwloc.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdhdr/hwloc.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,11 +10,11 @@
 // Created On       : Tue Jul 18 07:45:00 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 07:15:39 2020
-// Update Count     : 5
+// Last Modified On : Fri Feb  7 19:05:18 2020
+// Update Count     : 6
 // 
 
 // include file uses the CFA keyword "thread".
 #if ! defined( thread )									// nesting ?
-#define thread ``thread``								// make keyword an identifier
+#define thread ``thread									// make keyword an identifier
 #define __CFA_HWLOC_H__
 #endif
Index: libcfa/src/stdhdr/krb5.h
===================================================================
--- libcfa/src/stdhdr/krb5.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdhdr/krb5.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,11 +10,11 @@
 // Created On       : Tue Jul 18 07:55:44 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 07:15:47 2020
-// Update Count     : 5
+// Last Modified On : Fri Feb  7 19:05:35 2020
+// Update Count     : 6
 // 
 
 // include file uses the CFA keyword "enable".
 #if ! defined( enable )									// nesting ?
-#define enable ``enable``								// make keyword an identifier
+#define enable ``enable									// make keyword an identifier
 #define __CFA_KRB5_H__
 #endif
Index: libcfa/src/stdhdr/math.h
===================================================================
--- libcfa/src/stdhdr/math.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdhdr/math.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,11 +10,11 @@
 // Created On       : Mon Jul  4 23:25:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 07:15:58 2020
-// Update Count     : 14
+// Last Modified On : Fri Feb  7 19:05:27 2020
+// Update Count     : 15
 // 
 
 extern "C" {
 #if ! defined( exception )								// nesting ?
-#define exception ``exception``							// make keyword an identifier
+#define exception ``exception							// make keyword an identifier
 #define __CFA_MATH_H__
 #endif
Index: libcfa/src/stdhdr/sys/ucontext.h
===================================================================
--- libcfa/src/stdhdr/sys/ucontext.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdhdr/sys/ucontext.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,10 +10,10 @@
 // Created On       : Thu Feb  8 23:48:16 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 07:16:05 2020
-// Update Count     : 5
+// Last Modified On : Fri Feb  7 19:05:41 2020
+// Update Count     : 6
 // 
 
 #if ! defined( ftype )									// nesting ?
-#define ftype ``ftype``									// make keyword an identifier
+#define ftype ``ftype									// make keyword an identifier
 #define __CFA_UCONTEXT_H__
 #endif
Index: libcfa/src/stdlib.cfa
===================================================================
--- libcfa/src/stdlib.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdlib.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:10:29 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Nov 20 17:22:47 2019
-// Update Count     : 485
+// Last Modified On : Tue Feb  4 08:27:08 2020
+// Update Count     : 486
 //
 
@@ -107,5 +107,5 @@
 //---------------------------------------
 
-float _Complex strto( const char * sptr, char ** eptr ) {
+float _Complex strto( const char sptr[], char ** eptr ) {
 	float re, im;
 	char * eeptr;
@@ -118,5 +118,5 @@
 } // strto
 
-double _Complex strto( const char * sptr, char ** eptr ) {
+double _Complex strto( const char sptr[], char ** eptr ) {
 	double re, im;
 	char * eeptr;
@@ -129,5 +129,5 @@
 } // strto
 
-long double _Complex strto( const char * sptr, char ** eptr ) {
+long double _Complex strto( const char sptr[], char ** eptr ) {
 	long double re, im;
 	char * eeptr;
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/stdlib.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Nov 29 23:08:02 2019
-// Update Count     : 400
+// Last Modified On : Tue Feb  4 08:27:01 2020
+// Update Count     : 401
 //
 
@@ -193,35 +193,35 @@
 
 static inline {
-	int strto( const char * sptr, char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }
-	unsigned int strto( const char * sptr, char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }
-	long int strto( const char * sptr, char ** eptr, int base ) { return strtol( sptr, eptr, base ); }
-	unsigned long int strto( const char * sptr, char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }
-	long long int strto( const char * sptr, char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }
-	unsigned long long int strto( const char * sptr, char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }
-
-	float strto( const char * sptr, char ** eptr ) { return strtof( sptr, eptr ); }
-	double strto( const char * sptr, char ** eptr ) { return strtod( sptr, eptr ); }
-	long double strto( const char * sptr, char ** eptr ) { return strtold( sptr, eptr ); }
-} // distribution
-
-float _Complex strto( const char * sptr, char ** eptr );
-double _Complex strto( const char * sptr, char ** eptr );
-long double _Complex strto( const char * sptr, char ** eptr );
+	int strto( const char sptr[], char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }
+	unsigned int strto( const char sptr[], char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }
+	long int strto( const char sptr[], char ** eptr, int base ) { return strtol( sptr, eptr, base ); }
+	unsigned long int strto( const char sptr[], char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }
+	long long int strto( const char sptr[], char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }
+	unsigned long long int strto( const char sptr[], char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }
+
+	float strto( const char sptr[], char ** eptr ) { return strtof( sptr, eptr ); }
+	double strto( const char sptr[], char ** eptr ) { return strtod( sptr, eptr ); }
+	long double strto( const char sptr[], char ** eptr ) { return strtold( sptr, eptr ); }
+} // distribution
+
+float _Complex strto( const char sptr[], char ** eptr );
+double _Complex strto( const char sptr[], char ** eptr );
+long double _Complex strto( const char sptr[], char ** eptr );
 
 static inline {
-	int ato( const char * sptr ) { return (int)strtol( sptr, 0p, 10 ); }
-	unsigned int ato( const char * sptr ) { return (unsigned int)strtoul( sptr, 0p, 10 ); }
-	long int ato( const char * sptr ) { return strtol( sptr, 0p, 10 ); }
-	unsigned long int ato( const char * sptr ) { return strtoul( sptr, 0p, 10 ); }
-	long long int ato( const char * sptr ) { return strtoll( sptr, 0p, 10 ); }
-	unsigned long long int ato( const char * sptr ) { return strtoull( sptr, 0p, 10 ); }
-
-	float ato( const char * sptr ) { return strtof( sptr, 0p ); }
-	double ato( const char * sptr ) { return strtod( sptr, 0p ); }
-	long double ato( const char * sptr ) { return strtold( sptr, 0p ); }
-
-	float _Complex ato( const char * sptr ) { return strto( sptr, 0p ); }
-	double _Complex ato( const char * sptr ) { return strto( sptr, 0p ); }
-	long double _Complex ato( const char * sptr ) { return strto( sptr, 0p ); }
+	int ato( const char sptr[] ) { return (int)strtol( sptr, 0p, 10 ); }
+	unsigned int ato( const char sptr[] ) { return (unsigned int)strtoul( sptr, 0p, 10 ); }
+	long int ato( const char sptr[] ) { return strtol( sptr, 0p, 10 ); }
+	unsigned long int ato( const char sptr[] ) { return strtoul( sptr, 0p, 10 ); }
+	long long int ato( const char sptr[] ) { return strtoll( sptr, 0p, 10 ); }
+	unsigned long long int ato( const char sptr[] ) { return strtoull( sptr, 0p, 10 ); }
+
+	float ato( const char sptr[] ) { return strtof( sptr, 0p ); }
+	double ato( const char sptr[] ) { return strtod( sptr, 0p ); }
+	long double ato( const char sptr[] ) { return strtold( sptr, 0p ); }
+
+	float _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
+	double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
+	long double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
 } // distribution
 
Index: libcfa/src/time.cfa
===================================================================
--- libcfa/src/time.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/time.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Tue Mar 27 13:33:14 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan  5 17:27:40 2020
-// Update Count     : 69
+// Last Modified On : Tue Feb  4 08:24:18 2020
+// Update Count     : 70
 //
 
@@ -129,5 +129,5 @@
 } // dd_mm_yy
 
-size_t strftime( char * buf, size_t size, const char * fmt, Time time ) with( time ) {
+size_t strftime( char buf[], size_t size, const char fmt[], Time time ) with( time ) {
 	time_t s = tn / TIMEGRAN;
 	tm tm;
Index: libcfa/src/time.hfa
===================================================================
--- libcfa/src/time.hfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ libcfa/src/time.hfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Mar 14 23:18:57 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan  6 12:50:16 2020
-// Update Count     : 653
+// Last Modified On : Tue Feb  4 08:24:32 2020
+// Update Count     : 654
 //
 
@@ -191,5 +191,5 @@
 } // dmy
 
-size_t strftime( char * buf, size_t size, const char * fmt, Time time );
+size_t strftime( char buf[], size_t size, const char fmt[], Time time );
 
 //------------------------- timeval (cont) -------------------------
Index: longrun_tests/Makefile.in
===================================================================
--- longrun_tests/Makefile.in	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ longrun_tests/Makefile.in	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -502,11 +502,15 @@
 am__v_GOC_0 = @echo "  GOC     " $@;
 am__v_GOC_1 = 
+AM_V_PY = $(am__v_PY_@AM_V@)
+am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
+am__v_PY_0 = @echo "  PYTHON  " $@;
+am__v_PY_1 = 
 AM_V_RUST = $(am__v_RUST_@AM_V@)
 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
-am__v_RUST_0 = @echo "  RUST     " $@;
+am__v_RUST_0 = @echo "  RUST    " $@;
 am__v_RUST_1 = 
 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
-am__v_NODEJS_0 = @echo "  NODEJS     " $@;
+am__v_NODEJS_0 = @echo "  NODEJS  " $@;
 am__v_NODEJS_1 = 
 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/CodeGenerator.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:13:28 2019
-// Update Count     : 508
+// Last Modified On : Sun Feb 16 08:32:48 2020
+// Update Count     : 532
 //
 #include "CodeGenerator.h"
@@ -39,5 +39,5 @@
 	int CodeGenerator::tabsize = 4;
 
-	// the kinds of statements that would ideally be followed by whitespace
+	// The kinds of statements that would ideally be followed by whitespace.
 	bool wantSpacing( Statement * stmt) {
 		return dynamic_cast< IfStmt * >( stmt ) || dynamic_cast< CompoundStmt * >( stmt ) ||
@@ -78,7 +78,5 @@
 	}
 
-	/* Using updateLocation at the beginning of a node and endl
-	 * within a node should become the method of formating.
-	 */
+	// Using updateLocation at the beginning of a node and endl within a node should become the method of formating.
 	void CodeGenerator::updateLocation( CodeLocation const & to ) {
 		// skip if linemarks shouldn't appear or if codelocation is unset
@@ -95,5 +93,5 @@
 		} else {
 			output << "\n# " << to.first_line << " \"" << to.filename
-			       << "\"\n" << indent;
+				   << "\"\n" << indent;
 			currentLocation = to;
 		}
@@ -131,5 +129,5 @@
 
 	void CodeGenerator::genAttributes( list< Attribute * > & attributes ) {
-	  if ( attributes.empty() ) return;
+		if ( attributes.empty() ) return;
 		output << "__attribute__ ((";
 		for ( list< Attribute * >::iterator attr( attributes.begin() );; ) {
@@ -140,5 +138,5 @@
 				output << ")";
 			} // if
-		  if ( ++attr == attributes.end() ) break;
+			if ( ++attr == attributes.end() ) break;
 			output << ",";								// separator
 		} // for
@@ -165,8 +163,8 @@
 		previsit( (BaseSyntaxNode *)node );
 		GuardAction( [this, node](){
-			if ( options.printExprTypes && node->result ) {
-				output << " /* " << genType( node->result, "", options ) << " */ ";
-			}
-		} );
+				if ( options.printExprTypes && node->result ) {
+					output << " /* " << genType( node->result, "", options ) << " */ ";
+				}
+			} );
 	}
 
@@ -399,8 +397,8 @@
 		extension( applicationExpr );
 		if ( VariableExpr * varExpr = dynamic_cast< VariableExpr* >( applicationExpr->get_function() ) ) {
-			OperatorInfo opInfo;
-			if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( varExpr->get_var()->get_name(), opInfo ) ) {
+			const OperatorInfo * opInfo;
+			if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && ( opInfo = operatorLookup( varExpr->get_var()->get_name() ) ) ) {
 				std::list< Expression* >::iterator arg = applicationExpr->get_args().begin();
-				switch ( opInfo.type ) {
+				switch ( opInfo->type ) {
 				  case OT_INDEX:
 					assert( applicationExpr->get_args().size() == 2 );
@@ -423,12 +421,12 @@
 						output << "(";
 						(*arg++)->accept( *visitor );
-						output << ") /* " << opInfo.inputName << " */";
+						output << ") /* " << opInfo->inputName << " */";
 					} else if ( applicationExpr->get_args().size() == 2 ) {
 						// intrinsic two parameter constructors are essentially bitwise assignment
 						output << "(";
 						(*arg++)->accept( *visitor );
-						output << opInfo.symbol;
+						output << opInfo->symbol;
 						(*arg)->accept( *visitor );
-						output << ") /* " << opInfo.inputName << " */";
+						output << ") /* " << opInfo->inputName << " */";
 					} else {
 						// no constructors with 0 or more than 2 parameters
@@ -441,5 +439,5 @@
 					assert( applicationExpr->get_args().size() == 1 );
 					output << "(";
-					output << opInfo.symbol;
+					output << opInfo->symbol;
 					(*arg)->accept( *visitor );
 					output << ")";
@@ -450,5 +448,5 @@
 					assert( applicationExpr->get_args().size() == 1 );
 					(*arg)->accept( *visitor );
-					output << opInfo.symbol;
+					output << opInfo->symbol;
 					break;
 
@@ -459,5 +457,5 @@
 					output << "(";
 					(*arg++)->accept( *visitor );
-					output << opInfo.symbol;
+					output << opInfo->symbol;
 					(*arg)->accept( *visitor );
 					output << ")";
@@ -486,8 +484,8 @@
 		extension( untypedExpr );
 		if ( NameExpr * nameExpr = dynamic_cast< NameExpr* >( untypedExpr->function ) ) {
-			OperatorInfo opInfo;
-			if ( operatorLookup( nameExpr->name, opInfo ) ) {
+			const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
+			if ( opInfo ) {
 				std::list< Expression* >::iterator arg = untypedExpr->args.begin();
-				switch ( opInfo.type ) {
+				switch ( opInfo->type ) {
 				  case OT_INDEX:
 					assert( untypedExpr->args.size() == 2 );
@@ -508,12 +506,12 @@
 						output << "(";
 						(*arg++)->accept( *visitor );
-						output << ") /* " << opInfo.inputName << " */";
+						output << ") /* " << opInfo->inputName << " */";
 					} else if ( untypedExpr->get_args().size() == 2 ) {
 						// intrinsic two parameter constructors are essentially bitwise assignment
 						output << "(";
 						(*arg++)->accept( *visitor );
-						output << opInfo.symbol;
+						output << opInfo->symbol;
 						(*arg)->accept( *visitor );
-						output << ") /* " << opInfo.inputName << " */";
+						output << ") /* " << opInfo->inputName << " */";
 					} else {
 						// no constructors with 0 or more than 2 parameters
@@ -521,7 +519,7 @@
 						output << "(";
 						(*arg++)->accept( *visitor );
-						output << opInfo.symbol << "{ ";
+						output << opInfo->symbol << "{ ";
 						genCommaList( arg, untypedExpr->args.end() );
-						output << "}) /* " << opInfo.inputName << " */";
+						output << "}) /* " << opInfo->inputName << " */";
 					} // if
 					break;
@@ -532,5 +530,5 @@
 					assert( untypedExpr->args.size() == 1 );
 					output << "(";
-					output << opInfo.symbol;
+					output << opInfo->symbol;
 					(*arg)->accept( *visitor );
 					output << ")";
@@ -541,5 +539,5 @@
 					assert( untypedExpr->args.size() == 1 );
 					(*arg)->accept( *visitor );
-					output << opInfo.symbol;
+					output << opInfo->symbol;
 					break;
 
@@ -549,5 +547,5 @@
 					output << "(";
 					(*arg++)->accept( *visitor );
-					output << opInfo.symbol;
+					output << opInfo->symbol;
 					(*arg)->accept( *visitor );
 					output << ")";
@@ -581,10 +579,10 @@
 	void CodeGenerator::postvisit( NameExpr * nameExpr ) {
 		extension( nameExpr );
-		OperatorInfo opInfo;
-		if ( operatorLookup( nameExpr->name, opInfo ) ) {
-			if ( opInfo.type == OT_CONSTANT ) {
-				output << opInfo.symbol;
+		const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
+		if ( opInfo ) {
+			if ( opInfo->type == OT_CONSTANT ) {
+				output << opInfo->symbol;
 			} else {
-				output << opInfo.outputName;
+				output << opInfo->outputName;
 			}
 		} else {
@@ -654,7 +652,7 @@
 	void CodeGenerator::postvisit( VariableExpr * variableExpr ) {
 		extension( variableExpr );
-		OperatorInfo opInfo;
-		if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( variableExpr->get_var()->get_name(), opInfo ) && opInfo.type == OT_CONSTANT ) {
-			output << opInfo.symbol;
+		const OperatorInfo * opInfo;
+		if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && (opInfo = operatorLookup( variableExpr->get_var()->get_name() )) && opInfo->type == OT_CONSTANT ) {
+			output << opInfo->symbol;
 		} else {
 			output << mangleName( variableExpr->get_var() );
@@ -1011,5 +1009,5 @@
 		  case BranchStmt::FallThroughDefault:
 			assertf( ! options.genC, "fallthru should not reach code generation." );
-		  output << "fallthru";
+			output << "fallthru";
 			break;
 		} // switch
@@ -1035,5 +1033,5 @@
 
 		output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
-		           "throw" : "throwResume");
+				   "throw" : "throwResume");
 		if (throwStmt->get_expr()) {
 			output << " ";
@@ -1050,5 +1048,5 @@
 
 		output << ((stmt->get_kind() == CatchStmt::Terminate) ?
-		"catch" : "catchResume");
+				   "catch" : "catchResume");
 		output << "( ";
 		stmt->decl->accept( *visitor );
@@ -1187,7 +1185,7 @@
 
 	std::string genName( DeclarationWithType * decl ) {
-		CodeGen::OperatorInfo opInfo;
-		if ( operatorLookup( decl->get_name(), opInfo ) ) {
-			return opInfo.outputName;
+		const OperatorInfo * opInfo = operatorLookup( decl->get_name() );
+		if ( opInfo ) {
+			return opInfo->outputName;
 		} else {
 			return decl->get_name();
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/CodeGenerator.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Apr 30 12:01:00 2019
-// Update Count     : 57
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sun Feb 16 03:58:31 2020
+// Update Count     : 62
 //
 
@@ -29,5 +29,5 @@
 namespace CodeGen {
 	struct CodeGenerator : public WithShortCircuiting, public WithGuards, public WithVisitorRef<CodeGenerator> {
-	  static int tabsize;
+		static int tabsize;
 
 		CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false );
@@ -104,5 +104,5 @@
 		void postvisit( AsmStmt * );
 		void postvisit( DirectiveStmt * );
-		void postvisit( AsmDecl * );				// special: statement in declaration context
+		void postvisit( AsmDecl * );					// special: statement in declaration context
 		void postvisit( IfStmt * );
 		void postvisit( SwitchStmt * );
@@ -147,7 +147,7 @@
 		LabelPrinter printLabels;
 		Options options;
-	public:
+	  public:
 		LineEnder endl;
-	private:
+	  private:
 
 		CodeLocation currentLocation;
@@ -162,8 +162,8 @@
 	template< class Iterator >
 	void CodeGenerator::genCommaList( Iterator begin, Iterator end ) {
-	  if ( begin == end ) return;
+		if ( begin == end ) return;
 		for ( ;; ) {
 			(*begin++)->accept( *visitor );
-		  if ( begin == end ) break;
+			if ( begin == end ) break;
 			output << ", ";								// separator
 		} // for
Index: src/CodeGen/FixMain.h
===================================================================
--- src/CodeGen/FixMain.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/FixMain.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Thr Jan 12 14:11:09 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:12:21 2019
-// Update Count     : 3
+// Last Modified On : Sun Feb 16 03:24:32 2020
+// Update Count     : 5
 //
 
@@ -42,3 +42,3 @@
 		static std::unique_ptr<FunctionDecl> main_signature;
 	};
-};
+} // namespace CodeGen
Index: src/CodeGen/GenType.h
===================================================================
--- src/CodeGen/GenType.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/GenType.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Apr 30 11:47:00 2019
-// Update Count     : 3
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sun Feb 16 04:11:40 2020
+// Update Count     : 5
 //
 
@@ -25,5 +25,5 @@
 	std::string genType( Type *type, const std::string &baseString, const Options &options );
 	std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
-  std::string genPrettyType( Type * type, const std::string & baseString );
+	std::string genPrettyType( Type * type, const std::string & baseString );
 } // namespace CodeGen
 
Index: src/CodeGen/Generate.cc
===================================================================
--- src/CodeGen/Generate.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/Generate.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:38:56 2019
-// Update Count     : 8
+// Last Modified On : Sun Feb 16 03:01:51 2020
+// Update Count     : 9
 //
 #include "Generate.h"
@@ -64,5 +64,5 @@
 	void generate( BaseSyntaxNode * node, std::ostream & os ) {
 		if ( Type * type = dynamic_cast< Type * >( node ) ) {
-			os << CodeGen::genPrettyType( type, "" );
+			os << genPrettyType( type, "" );
 		} else {
 			PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
Index: src/CodeGen/OperatorTable.cc
===================================================================
--- src/CodeGen/OperatorTable.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/OperatorTable.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 15 17:12:22 2017
-// Update Count     : 15
+// Last Modified On : Tue Feb 18 15:55:01 2020
+// Update Count     : 55
 //
 
@@ -17,4 +17,5 @@
 #include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
 #include <utility>    // for pair
+using namespace std;
 
 #include "OperatorTable.h"
@@ -22,128 +23,110 @@
 
 namespace CodeGen {
-	namespace {
-		const OperatorInfo tableValues[] = {
-			{	"?[?]",		"",		"_operator_index",				OT_INDEX			},
-			{	"?{}",		"=",	"_constructor",					OT_CTOR				},
-			{	"^?{}",		"",		"_destructor",					OT_DTOR				},
-			{	"?()",		"",		"_operator_call",				OT_CALL				},
-			{	"?++",		"++",	"_operator_postincr",			OT_POSTFIXASSIGN	},
-			{	"?--",		"--",	"_operator_postdecr",			OT_POSTFIXASSIGN	},
-			{	"*?",		"*",	"_operator_deref",				OT_PREFIX			},
-			{	"+?",		"+",	"_operator_unaryplus",			OT_PREFIX			},
-			{	"-?",		"-",	"_operator_unaryminus",			OT_PREFIX			},
-			{	"~?",		"~",	"_operator_bitnot",				OT_PREFIX			},
-			{	"!?",		"!",	"_operator_lognot",				OT_PREFIX			},
-			{	"++?",		"++",	"_operator_preincr",			OT_PREFIXASSIGN		},
-			{	"--?",		"--",	"_operator_predecr",			OT_PREFIXASSIGN		},
-			{	"?\\?",		"\\",	"_operator_exponential",		OT_INFIX			},
-			{	"?*?",		"*",	"_operator_multiply",			OT_INFIX			},
-			{	"?/?",		"/",	"_operator_divide",				OT_INFIX			},
-			{	"?%?",		"%",	"_operator_modulus",			OT_INFIX			},
-			{	"?+?",		"+",	"_operator_add",				OT_INFIX			},
-			{	"?-?",		"-",	"_operator_subtract",			OT_INFIX			},
-			{	"?<<?",		"<<",	"_operator_shiftleft",			OT_INFIX			},
-			{	"?>>?",		">>",	"_operator_shiftright",			OT_INFIX			},
-			{	"?<?",		"<",	"_operator_less",				OT_INFIX			},
-			{	"?>?",		">",	"_operator_greater",			OT_INFIX			},
-			{	"?<=?",		"<=",	"_operator_lessequal",			OT_INFIX			},
-			{	"?>=?",		">=",	"_operator_greaterequal",		OT_INFIX			},
-			{	"?==?",		"==",	"_operator_equal",				OT_INFIX			},
-			{	"?!=?",		"!=",	"_operator_notequal",			OT_INFIX			},
-			{	"?&?",		"&",	"_operator_bitand",				OT_INFIX			},
-			{	"?^?",		"^",	"_operator_bitxor",				OT_INFIX			},
-			{	"?|?",		"|",	"_operator_bitor",				OT_INFIX			},
-			{	"?=?",		"=",	"_operator_assign",				OT_INFIXASSIGN		},
-			{	"?\\=?",	"\\=",	"_operator_expassign",			OT_INFIXASSIGN		},
-			{	"?*=?",		"*=",	"_operator_multassign",			OT_INFIXASSIGN		},
-			{	"?/=?",		"/=",	"_operator_divassign",			OT_INFIXASSIGN		},
-			{	"?%=?",		"%=",	"_operator_modassign",			OT_INFIXASSIGN		},
-			{	"?+=?",		"+=",	"_operator_addassign",			OT_INFIXASSIGN		},
-			{	"?-=?",		"-=",	"_operator_subassign",			OT_INFIXASSIGN		},
-			{	"?<<=?",	"<<=",	"_operator_shiftleftassign",	OT_INFIXASSIGN		},
-			{	"?>>=?",	">>=",	"_operator_shiftrightassign",	OT_INFIXASSIGN		},
-			{	"?&=?",		"&=",	"_operator_bitandassign",		OT_INFIXASSIGN		},
-			{	"?^=?",		"^=",	"_operator_bitxorassign",		OT_INFIXASSIGN		},
-			{	"?|=?",		"|=",	"_operator_bitorassign",		OT_INFIXASSIGN		},
-		};
+	const OperatorInfo CodeGen::tableValues[] = {
+		// inputName symbol   outputName                     friendlyName                  type
+		{	"?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
+		{	"?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
+		{	"^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
+		{	"?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
+		{	"?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
+		{	"?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
+		{	"*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
+		{	"+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
+		{	"-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
+		{	"~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
+		{	"!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
+		{	"++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
+		{	"--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
+		{	"?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
+		{	"?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
+		{	"?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
+		{	"?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
+		{	"?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
+		{	"?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
+		{	"?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
+		{	"?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
+		{	"?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
+		{	"?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
+		{	"?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
+		{	"?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
+		{	"?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
+		{	"?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
+		{	"?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
+		{	"?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
+		{	"?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
+		{	"?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
+		{	"?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
+		{	"?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
+		{	"?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
+		{	"?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
+		{	"?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
+		{	"?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
+		{	"?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
+		{	"?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
+		{	"?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
+		{	"?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
+		{	"?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
+	}; // tableValues
 
-		const int numOps = sizeof( tableValues ) / sizeof( OperatorInfo );
+	std::map< std::string, OperatorInfo > CodeGen::table;
 
-		std::map< std::string, OperatorInfo > table;
-
-		void initialize() {
-			for ( int i = 0; i < numOps; ++i ) {
-				table[ tableValues[i].inputName ] = tableValues[i];
-			} // for
-		}
-	} // namespace
-
-	bool operatorLookup( const std::string & funcName, OperatorInfo & info ) {
-		static bool init = false;
-		if ( ! init ) {
-			initialize();
-		} // if
-
-		std::map< std::string, OperatorInfo >::const_iterator i = table.find( funcName );
-		if ( i == table.end() ) {
-			if ( isPrefix( funcName, "?`" ) ) {
-				// handle literal suffixes, which are user-defined postfix operators
-				info.inputName = funcName;
-				info.symbol = funcName.substr(2);
-				info.outputName = toString( "__operator_literal_", info.symbol );
-				info.type = OT_POSTFIX;
-				return true;
-			}
-			return false;
-		} else {
-			info = i->second;
-			return true;
-		} // if
+	CodeGen::CodeGen() {
+		enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
+		for ( int i = 0; i < numOps; i += 1 ) {
+			table[ tableValues[i].inputName ] = tableValues[i];
+		} // for
 	}
 
-	bool isOperator( const std::string & funcName ) {
-		OperatorInfo info;
-		return operatorLookup( funcName, info );
+	const OperatorInfo * operatorLookup( const string & funcName ) {
+		if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter
+		const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table
+		assert( ret );
+		return ret;
 	}
 
-	/// determines if a given function name is one of the operator types between [begin, end)
-	template<typename Iterator>
-	bool isOperatorType( const std::string & funcName, Iterator begin, Iterator end ) {
-		OperatorInfo info;
-		if ( operatorLookup( funcName, info ) ) {
-			return std::find( begin, end, info.type ) != end;
-		}
+	bool isOperator( const string & funcName ) {
+		return operatorLookup( funcName ) != nullptr;
+	}
+
+	string operatorFriendlyName( const string & funcName ) {
+		const OperatorInfo * info = operatorLookup( funcName );
+		if ( info ) return info->friendlyName;
+		return "";
+	}
+
+	bool isConstructor( const string & funcName ) {
+		const OperatorInfo * info = operatorLookup( funcName );
+		if ( info ) return info->type == OT_CTOR;
 		return false;
 	}
 
-	bool isConstructor( const std::string & funcName ) {
-		static OperatorType types[] = { OT_CTOR };
-		return isOperatorType( funcName, std::begin(types), std::end(types) );
+	bool isDestructor( const string & funcName ) {
+		const OperatorInfo * info = operatorLookup( funcName );
+		if ( info ) return info->type == OT_DTOR;
+		return false;
 	}
 
-	bool isDestructor( const std::string & funcName ) {
-		static OperatorType types[] = { OT_DTOR };
-		return isOperatorType( funcName, std::begin(types), std::end(types) );
+	bool isCtorDtor( const string & funcName ) {
+		const OperatorInfo * info = operatorLookup( funcName );
+		if ( info ) return info->type <= OT_CONSTRUCTOR;
+		return false;
 	}
 
-	bool isAssignment( const std::string & funcName ) {
-		static OperatorType types[] = { OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
-		return isOperatorType( funcName, std::begin(types), std::end(types) );
+	bool isAssignment( const string & funcName ) {
+		const OperatorInfo * info = operatorLookup( funcName );
+		if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
+		return false;
 	}
 
-	bool isCtorDtor( const std::string & funcName ) {
-		static OperatorType types[] = { OT_CTOR, OT_DTOR };
-		return isOperatorType( funcName, std::begin(types), std::end(types) );
+	bool isCtorDtorAssign( const string & funcName ) {
+		const OperatorInfo * info = operatorLookup( funcName );
+		if ( info ) return info->type <= OT_ASSIGNMENT;
+		return false;
 	}
 
-	bool isCtorDtorAssign( const std::string & funcName ) {
-		static OperatorType types[] = { OT_CTOR, OT_DTOR, OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
-		return isOperatorType( funcName, std::begin(types), std::end(types) );
-	}
+	CodeGen codegen;									// initialize singleton package
 } // namespace CodeGen
 
 // Local Variables: //
 // tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
 // End: //
Index: src/CodeGen/OperatorTable.h
===================================================================
--- src/CodeGen/OperatorTable.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/OperatorTable.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 21 22:17:11 2017
-// Update Count     : 6
+// Last Modified On : Sun Feb 16 08:13:34 2020
+// Update Count     : 26
 //
 
@@ -17,17 +17,20 @@
 
 #include <string>
+#include <map>
 
 namespace CodeGen {
 	enum OperatorType {
-		OT_INDEX,
 		OT_CTOR,
 		OT_DTOR,
-		OT_CALL,
-		OT_PREFIX,
-		OT_POSTFIX,
-		OT_INFIX,
+		OT_CONSTRUCTOR = OT_DTOR,
 		OT_PREFIXASSIGN,
 		OT_POSTFIXASSIGN,
 		OT_INFIXASSIGN,
+		OT_ASSIGNMENT = OT_INFIXASSIGN,
+		OT_CALL,
+		OT_PREFIX,
+		OT_INFIX,
+		OT_POSTFIX,
+		OT_INDEX,
 		OT_LABELADDRESS,
 		OT_CONSTANT
@@ -38,9 +41,20 @@
 		std::string symbol;
 		std::string outputName;
+		std::string friendlyName;
 		OperatorType type;
 	};
 
+	class CodeGen {
+		friend const OperatorInfo * operatorLookup( const std::string & funcName );
+
+		static const OperatorInfo tableValues[];
+		static std::map< std::string, OperatorInfo > table;
+	  public:
+		CodeGen();
+	}; // CodeGen
+
 	bool isOperator( const std::string & funcName );
-	bool operatorLookup( const std::string & funcName, OperatorInfo & info );
+	const OperatorInfo * operatorLookup( const std::string & funcName );
+	std::string operatorFriendlyName( const std::string & funcName );
 
 	bool isConstructor( const std::string & );
Index: src/CodeGen/Options.h
===================================================================
--- src/CodeGen/Options.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeGen/Options.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -9,27 +9,25 @@
 // Author           : Andrew Beach
 // Created On       : Tue Apr 30 11:36:00 2019
-// Last Modified By : Andrew Beach
-// Last Modified On : Thr May  2 10:45:00 2019
-// Update Count     : 2
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Feb 15 18:37:06 2020
+// Update Count     : 3
 //
 
 #pragma once
 
-namespace CodeGen {
-	struct Options {
-		// External Options: Same thoughout a pass.
-		bool pretty;
-		bool genC;
-		bool lineMarks;
-		bool printExprTypes;
+struct Options {
+	// External Options: Same thoughout a pass.
+	bool pretty;
+	bool genC;
+	bool lineMarks;
+	bool printExprTypes;
 
-		// Internal Options: Changed on some recurisive calls.
-		bool anonymousUnused = false;
+	// Internal Options: Changed on some recurisive calls.
+	bool anonymousUnused = false;
 
-		Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) :
-			pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes)
+	Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) :
+		pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes)
 		{}
-	};
-} // namespace CodeGen
+};
 
 // Local Variables: //
Index: src/CodeTools/ResolvProtoDump.cc
===================================================================
--- src/CodeTools/ResolvProtoDump.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/CodeTools/ResolvProtoDump.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -9,7 +9,7 @@
 // Author           : Aaron Moss
 // Created On       : Tue Sep 11 09:04:00 2018
-// Last Modified By : Aaron Moss
-// Last Modified On : Tue Sep 11 09:04:00 2018
-// Update Count     : 1
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Feb 15 13:50:11 2020
+// Update Count     : 3
 //
 
@@ -182,8 +182,8 @@
 
 			// replace operator names
-			CodeGen::OperatorInfo info;
-			if ( CodeGen::operatorLookup( name, info ) ) {
+			const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( name );
+			if ( opInfo ) {
 				ss << new_prefix(pre, "");
-				op_name( info.outputName, ss );
+				op_name( opInfo->outputName, ss );
 				return;
 			}
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Common/PassVisitor.impl.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -3302,5 +3302,5 @@
 	VISIT_START( node );
 
-	indexerAddStruct( node->name );
+	indexerAddUnion( node->name );
 
 	{
@@ -3317,5 +3317,5 @@
 	VISIT_START( node );
 
-	indexerAddStruct( node->name );
+	indexerAddUnion( node->name );
 
 	{
@@ -3332,5 +3332,5 @@
 	MUTATE_START( node );
 
-	indexerAddStruct( node->name );
+	indexerAddUnion( node->name );
 
 	{
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Common/SemanticError.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -49,15 +49,16 @@
 struct WarningData {
 	const char * const name;
+	const Severity default_severity;
 	const char * const message;
-	const Severity default_severity;
 };
 
 constexpr WarningData WarningFormats[] = {
-	{"self-assign"            , "self assignment of expression: %s"            , Severity::Warn},
-	{"reference-conversion"   , "rvalue to reference conversion of rvalue: %s" , Severity::Warn},
-	{"qualifiers-zero_t-one_t", "questionable use of type qualifier %s with %s", Severity::Warn},
-	{"aggregate-forward-decl" , "forward declaration of nested aggregate: %s"  , Severity::Warn},
-	{"superfluous-decl"       , "declaration does not allocate storage: %s"    , Severity::Warn},
-	{"gcc-attributes"         , "invalid attribute: %s"                        , Severity::Warn},
+	{"self-assign"            , Severity::Warn    , "self assignment of expression: %s"                          },
+	{"reference-conversion"   , Severity::Warn    , "rvalue to reference conversion of rvalue: %s"               },
+	{"qualifiers-zero_t-one_t", Severity::Warn    , "questionable use of type qualifier %s with %s"              },
+	{"aggregate-forward-decl" , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
+	{"superfluous-decl"       , Severity::Warn    , "declaration does not allocate storage: %s"                  },
+	{"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 @@
 	SuperfluousDecl,
 	GccAttributes,
+	CppCopy,
 	NUMBER_OF_WARNINGS, // This MUST be the last warning
 };
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Common/utility.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 24 14:28:19 2019
-// Update Count     : 41
+// Last Modified On : Tue Feb 11 13:00:36 2020
+// Update Count     : 50
 //
 
@@ -29,4 +29,5 @@
 #include <utility>
 #include <vector>
+#include <cstring>										// memcmp
 
 #include "Common/Indenter.h"
@@ -264,9 +265,9 @@
 }
 
-/// determines if `pref` is a prefix of `str`
-static inline bool isPrefix( const std::string & str, const std::string & pref ) {
+// determines if pref is a prefix of str
+static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
 	if ( pref.size() > str.size() ) return false;
-	auto its = std::mismatch( pref.begin(), pref.end(), str.begin() );
-	return its.first == pref.end();
+    return 0 == memcmp( str.c_str() + start, pref.c_str(), pref.size() );
+	// return prefix == full.substr(0, prefix.size()); // for future, requires c++17
 }
 
Index: src/ControlStruct/Mutate.cc
===================================================================
--- src/ControlStruct/Mutate.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/ControlStruct/Mutate.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Aug  4 11:39:08 2016
-// Update Count     : 9
+// Last Modified On : Sun Feb 16 03:22:07 2020
+// Update Count     : 10
 //
 
@@ -37,5 +37,5 @@
 		mutateAll( translationUnit, formut );
 	}
-} // namespace CodeGen
+} // namespace ControlStruct
 
 // Local Variables: //
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/InitTweak/FixInit.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Jan 13 16:29:30 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:41:27 2019
-// Update Count     : 77
+// Last Modified On : Sun Feb 16 04:17:07 2020
+// Update Count     : 82
 //
 #include "FixInit.h"
@@ -745,5 +745,5 @@
 		}
 
-		// to prevent warnings (‘_unq0’ may be used uninitialized in this function),
+		// to prevent warnings ('_unq0' may be used uninitialized in this function),
 		// insert an appropriate zero initializer for UniqueExpr temporaries.
 		Initializer * makeInit( Type * t ) {
Index: src/InitTweak/FixInit.h
===================================================================
--- src/InitTweak/FixInit.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/InitTweak/FixInit.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Jan 13 16:29:30 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:31:06 2017
-// Update Count     : 6
+// Last Modified On : Sun Feb 16 07:54:50 2020
+// Update Count     : 8
 //
 
@@ -22,6 +22,5 @@
 
 namespace InitTweak {
-  /// replace constructor initializers with expression statements
-  /// and unwrap basic C-style initializers
+	/// replace constructor initializers with expression statements and unwrap basic C-style initializers
 	void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
 } // namespace
Index: src/MakeLibCfa.cc
===================================================================
--- src/MakeLibCfa.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/MakeLibCfa.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 10:33:33 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:41:40 2019
-// Update Count     : 42
+// Last Modified On : Sun Feb 16 03:49:49 2020
+// Update Count     : 45
 //
 
@@ -96,7 +96,7 @@
 
 			FunctionDecl *funcDecl = origFuncDecl->clone();
-			CodeGen::OperatorInfo opInfo;
-			bool lookResult = CodeGen::operatorLookup( funcDecl->get_name(), opInfo );
-			assert( lookResult );
+			const CodeGen::OperatorInfo * opInfo;
+			opInfo = CodeGen::operatorLookup( funcDecl->get_name() );
+			assert( opInfo );
 			assert( ! funcDecl->get_statements() );
 			// build a recursive call - this is okay, as the call will actually be codegen'd using operator syntax
@@ -120,5 +120,5 @@
 
 			Statement * stmt = nullptr;
-			switch ( opInfo.type ) {
+			switch ( opInfo->type ) {
 			  case CodeGen::OT_INDEX:
 			  case CodeGen::OT_CALL:
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Parser/ParseNode.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 13:28:16 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Dec 16 07:46:01 2019
-// Update Count     : 888
+// Last Modified On : Fri Feb  7 17:56:02 2020
+// Update Count     : 891
 //
 
@@ -449,5 +449,5 @@
 				* out++ = result;
 			} else {
-				assertf(false, "buildList unknown type");
+				SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
 			} // if
 		} catch( SemanticErrorException & e ) {
Index: src/Parser/ParserTypes.h
===================================================================
--- src/Parser/ParserTypes.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Parser/ParserTypes.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep 22 08:58:10 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:33:28 2017
-// Update Count     : 350
+// Last Modified On : Sat Feb 15 11:04:40 2020
+// Update Count     : 351
 //
 
@@ -27,13 +27,13 @@
 // current location in the input
 extern int yylineno;
-extern char *yyfilename;
+extern char * yyfilename;
 
 struct Location {
-    char *file;
+    char * file;
     int line;
 }; // Location
 
 struct Token {
-    std::string *str;									// must be pointer as used in union
+    std::string * str;									// must be pointer as used in union
     Location loc;
 
Index: src/Parser/TypedefTable.cc
===================================================================
--- src/Parser/TypedefTable.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Parser/TypedefTable.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:20:13 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 25 15:32:35 2018
-// Update Count     : 258
+// Last Modified On : Sat Feb 15 08:06:36 2020
+// Update Count     : 259
 //
 
@@ -47,9 +47,9 @@
 } // TypedefTable::~TypedefTable
 
-bool TypedefTable::exists( const string & identifier ) {
+bool TypedefTable::exists( const string & identifier ) const {
 	return kindTable.find( identifier ) != kindTable.end();
 } // TypedefTable::exists
 
-bool TypedefTable::existsCurr( const string & identifier ) {
+bool TypedefTable::existsCurr( const string & identifier ) const {
 	return kindTable.findAt( kindTable.currentScope() - 1, identifier ) != kindTable.end();
 } // TypedefTable::exists
Index: src/Parser/TypedefTable.h
===================================================================
--- src/Parser/TypedefTable.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Parser/TypedefTable.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:24:36 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 25 15:33:55 2018
-// Update Count     : 114
+// Last Modified On : Sat Feb 15 08:06:37 2020
+// Update Count     : 117
 //
 
@@ -30,6 +30,6 @@
 	~TypedefTable();
 
-	bool exists( const std::string & identifier );
-	bool existsCurr( const std::string & identifier );
+	bool exists( const std::string & identifier ) const;
+	bool existsCurr( const std::string & identifier ) const;
 	int isKind( const std::string & identifier ) const;
 	void makeTypedef( const std::string & name, int kind = TYPEDEFname );
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Parser/lex.ll	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
  * Created On       : Sat Sep 22 08:58:10 2001
  * Last Modified By : Peter A. Buhr
- * Last Modified On : Sat Feb  1 07:16:44 2020
- * Update Count     : 724
+ * Last Modified On : Sat Feb 15 11:05:50 2020
+ * Update Count     : 737
  */
 
@@ -42,4 +42,6 @@
 #include "ParseNode.h"
 #include "TypedefTable.h"
+
+string * build_postfix_name( string * name );
 
 char *yyfilename;
@@ -330,6 +332,6 @@
 				/* identifier */
 {identifier}	{ IDENTIFIER_RETURN(); }
-"``"{identifier}"``" {									// CFA
-	yytext[yyleng - 2] = '\0'; yytext += 2;				// SKULLDUGGERY: remove backquotes (ok to shorten?)
+"``"{identifier} {										// CFA
+	yytext[yyleng] = '\0'; yytext += 2;					// SKULLDUGGERY: remove backquotes (ok to shorten?)
 	IDENTIFIER_RETURN();
 }
@@ -432,5 +434,9 @@
 "?"({op_unary_pre_post}|"()"|"[?]"|"{}") { IDENTIFIER_RETURN(); }
 "^?{}"			{ IDENTIFIER_RETURN(); }
-"?`"{identifier} { IDENTIFIER_RETURN(); }				// postfix operator
+"?`"{identifier} {										// postfix operator
+	yylval.tok.str = new string( &yytext[2] );			// remove ?`
+	yylval.tok.str = build_postfix_name( yylval.tok.str ); // add prefix
+	RETURN_LOCN( typedefTable.isKind( *yylval.tok.str ) );
+}
 "?"{op_binary_over}"?"	{ IDENTIFIER_RETURN(); }		// binary
 	/*
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/Parser/parser.yy	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 10:04:40 2020
-// Update Count     : 4440
+// Last Modified On : Fri Feb 21 14:47:29 2020
+// Update Count     : 4468
 //
 
@@ -166,8 +166,7 @@
 } // rebindForall
 
-NameExpr * build_postfix_name( const string * name ) {
-	NameExpr * new_name = build_varref( new string( "?`" + *name ) );
-	delete name;
-	return new_name;
+string * build_postfix_name( string * name ) {
+	*name = string("__postfix_func_") + *name;
+	return name;
 } // build_postfix_name
 
@@ -633,9 +632,9 @@
 		{ $$ = new ExpressionNode( build_func( $1, $3 ) ); }
 	| postfix_expression '`' identifier					// CFA, postfix call
-		{ $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), $1 ) ); }
+		{ $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
 	| constant '`' identifier							// CFA, postfix call
-		{ $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), $1 ) ); }
+		{ $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
 	| string_literal '`' identifier						// CFA, postfix call
-		{ $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), new ExpressionNode( $1 ) ) ); }
+		{ $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
 	| postfix_expression '.' identifier
 		{ $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
@@ -1590,9 +1589,9 @@
 		// type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
 		// flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
-	cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
+	cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
 		// To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
-		{ $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
-	| cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
-		{ $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
+		{ $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
+	| cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
+		{ $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
 	;
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/ResolvExpr/Resolver.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -84,4 +84,5 @@
 		void previsit( ThrowStmt * throwStmt );
 		void previsit( CatchStmt * catchStmt );
+		void postvisit( CatchStmt * catchStmt );
 		void previsit( WaitForStmt * stmt );
 
@@ -567,6 +568,28 @@
 
 	void Resolver_old::previsit( CatchStmt * catchStmt ) {
+		// Until we are very sure this invarent (ifs that move between passes have thenPart)
+		// holds, check it. This allows a check for when to decode the mangling.
+		if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
+			assert( ifStmt->thenPart );
+		}
+		// Encode the catchStmt so the condition can see the declaration.
 		if ( catchStmt->cond ) {
-			findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer );
+			IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
+			catchStmt->cond = nullptr;
+			catchStmt->body = ifStmt;
+		}
+	}
+
+	void Resolver_old::postvisit( CatchStmt * catchStmt ) {
+		// Decode the catchStmt so everything is stored properly.
+		IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
+		if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
+			assert( ifStmt->condition );
+			assert( ifStmt->elsePart );
+			catchStmt->cond = ifStmt->condition;
+			catchStmt->body = ifStmt->elsePart;
+			ifStmt->condition = nullptr;
+			ifStmt->elsePart = nullptr;
+			delete ifStmt;
 		}
 	}
@@ -1466,4 +1489,5 @@
 
 	const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
+		// TODO: This will need a fix for the decl/cond scoping problem.
 		if ( catchStmt->cond ) {
 			ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool };
Index: src/SymTab/Demangle.cc
===================================================================
--- src/SymTab/Demangle.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/SymTab/Demangle.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jul 19 12:52:41 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 14:54:15 2019
-// Update Count     : 4
+// Last Modified On : Tue Feb 11 15:09:18 2020
+// Update Count     : 10
 //
 
@@ -19,4 +19,5 @@
 #include "CodeGen/GenType.h"
 #include "Common/PassVisitor.h"
+#include "Common/utility.h"								// isPrefix
 #include "Mangler.h"
 #include "SynTree/Type.h"
@@ -416,7 +417,13 @@
 
 			bool StringView::isPrefix(const std::string & pref) {
-				if ( pref.size() > str.size()-idx ) return false;
-				auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
-				if (its.first == pref.end()) {
+				// if ( pref.size() > str.size()-idx ) return false;
+				// auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
+				// if (its.first == pref.end()) {
+				// 	idx += pref.size();
+				// 	return true;
+				// }
+
+				// This update is untested because there are no tests for this code.
+				if ( ::isPrefix( str, pref, idx ) ) {
 					idx += pref.size();
 					return true;
@@ -429,5 +436,5 @@
 				PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
 				if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
-				if (! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back())) return false;
+				if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
 
 				// get name
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/SymTab/Mangler.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 21:40:29 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:43:49 2019
-// Update Count     : 28
+// Last Modified On : Sat Feb 15 13:55:12 2020
+// Update Count     : 33
 //
 #include "Mangler.h"
@@ -128,7 +128,7 @@
 				} // if
 				mangleName << Encoding::manglePrefix;
-				CodeGen::OperatorInfo opInfo;
-				if ( operatorLookup( declaration->get_name(), opInfo ) ) {
-					mangleName << opInfo.outputName.size() << opInfo.outputName;
+				const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
+				if ( opInfo ) {
+					mangleName << opInfo->outputName.size() << opInfo->outputName;
 				} else {
 					mangleName << declaration->name.size() << declaration->name;
@@ -471,7 +471,7 @@
 			} // if
 			mangleName << Encoding::manglePrefix;
-			CodeGen::OperatorInfo opInfo;
-			if ( operatorLookup( decl->name, opInfo ) ) {
-				mangleName << opInfo.outputName.size() << opInfo.outputName;
+			const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
+			if ( opInfo ) {
+				mangleName << opInfo->outputName.size() << opInfo->outputName;
 			} else {
 				mangleName << decl->name.size() << decl->name;
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/SymTab/Validate.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -311,4 +311,5 @@
 			Stats::Heap::newPass("validate-A");
 			Stats::Time::BlockGuard guard("validate-A");
+			VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
 			acceptAll( translationUnit, hoistDecls );
 			ReplaceTypedef::replaceTypedef( translationUnit );
@@ -336,5 +337,4 @@
 			Stats::Time::BlockGuard guard("validate-C");
 			acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes_old
-			VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
 			ReturnChecker::checkFunctionReturns( translationUnit );
 			InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen
@@ -1182,12 +1182,14 @@
 		if ( CodeGen::isCtorDtorAssign( funcDecl->get_name() ) ) { // TODO: also check /=, etc.
 			if ( params.size() == 0 ) {
-				SemanticError( funcDecl, "Constructors, destructors, and assignment functions require at least one parameter " );
+				SemanticError( funcDecl->location, "Constructors, destructors, and assignment functions require at least one parameter." );
 			}
 			ReferenceType * refType = dynamic_cast< ReferenceType * >( params.front()->get_type() );
 			if ( ! refType ) {
-				SemanticError( funcDecl, "First parameter of a constructor, destructor, or assignment function must be a reference " );
+				SemanticError( funcDecl->location, "First parameter of a constructor, destructor, or assignment function must be a reference." );
 			}
 			if ( CodeGen::isCtorDtor( funcDecl->get_name() ) && returnVals.size() != 0 ) {
-				SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " );
+				if(!returnVals.front()->get_type()->isVoid()) {
+					SemanticError( funcDecl->location, "Constructors and destructors cannot have explicit return values." );
+				}
 			}
 		}
Index: src/SynTree/Attribute.h
===================================================================
--- src/SynTree/Attribute.h	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/SynTree/Attribute.h	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:54:14 2017
-// Update Count     : 39
+// Last Modified On : Thu Feb 13 21:34:08 2020
+// Update Count     : 40
 //
 
@@ -38,5 +38,5 @@
 	virtual ~Attribute();
 
-	std::string get_name() const { return name; }
+	const std::string & get_name() const { return name; }
 	void set_name( const std::string & newValue ) { name = newValue; }
 	std::list< Expression * > & get_parameters() { return parameters; }
Index: src/cfa.make
===================================================================
--- src/cfa.make	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/cfa.make	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -32,12 +32,17 @@
 am__v_GOC_1 =
 
+AM_V_PY = $(am__v_PY_@AM_V@)
+am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
+am__v_PY_0 = @echo "  PYTHON  " $@;
+am__v_PY_1 =
+
 AM_V_RUST = $(am__v_RUST_@AM_V@)
 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
-am__v_RUST_0 = @echo "  RUST     " $@;
+am__v_RUST_0 = @echo "  RUST    " $@;
 am__v_RUST_1 =
 
 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
-am__v_NODEJS_0 = @echo "  NODEJS     " $@;
+am__v_NODEJS_0 = @echo "  NODEJS  " $@;
 am__v_NODEJS_1 =
 
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ src/main.cc	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Dec 16 17:55:53 2019
-// Update Count     : 627
+// Last Modified On : Sat Feb  8 08:33:50 2020
+// Update Count     : 633
 //
 
@@ -105,7 +105,7 @@
 
 static void backtrace( int start ) {					// skip first N stack frames
-	enum { Frames = 50 };
+	enum { Frames = 50, };								// maximum number of stack frames
 	void * array[Frames];
-	int size = ::backtrace( array, Frames );
+	size_t size = ::backtrace( array, Frames );
 	char ** messages = ::backtrace_symbols( array, size ); // does not demangle names
 
@@ -114,5 +114,5 @@
 
 	// skip last 2 stack frames after main
-	for ( int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
+	for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
 		char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr;
 
@@ -180,4 +180,21 @@
 } // sigSegvBusHandler
 
+static void sigFpeHandler( SIGPARMS ) {
+	const char * msg;
+
+	switch ( sfp->si_code ) {
+	  case FPE_INTDIV: case FPE_FLTDIV: msg = "divide by zero"; break;
+	  case FPE_FLTOVF: msg = "overflow"; break;
+	  case FPE_FLTUND: msg = "underflow"; break;
+	  case FPE_FLTRES: msg = "inexact result"; break;
+	  case FPE_FLTINV: msg = "invalid operation"; break;
+	  default: msg = "unknown";
+	} // choose
+	cerr << "Computation error " << msg << " at location " << sfp->si_addr << endl
+		 << "Possible cause is constant-expression evaluation invalid." << endl;
+	backtrace( 2 );										// skip first 2 stack frames
+	abort();											// cause core dump for debugging
+} // sigFpeHandler
+
 static void sigAbortHandler( SIGPARMS ) {
 	backtrace( 6 );										// skip first 6 stack frames
@@ -193,4 +210,5 @@
 	Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO );
 	Signal( SIGBUS, sigSegvBusHandler, SA_SIGINFO );
+	Signal( SIGFPE, sigFpeHandler, SA_SIGINFO );
 	Signal( SIGABRT, sigAbortHandler, SA_SIGINFO );
 
Index: tests/.expect/alloc-ERROR.txt
===================================================================
--- tests/.expect/alloc-ERROR.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/.expect/alloc-ERROR.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -1,3 +1,3 @@
-alloc.cfa:311:1 error: No reasonable alternatives for expression Applying untyped:
+alloc.cfa:310:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?=?
 ...to:
@@ -19,5 +19,5 @@
 
 
-alloc.cfa:312:1 error: No reasonable alternatives for expression Applying untyped:
+alloc.cfa:311:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?=?
 ...to:
@@ -39,5 +39,5 @@
 
 
-alloc.cfa:313:1 error: No reasonable alternatives for expression Applying untyped:
+alloc.cfa:312:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?=?
 ...to:
@@ -50,5 +50,5 @@
 
 
-alloc.cfa:314:1 error: No reasonable alternatives for expression Applying untyped:
+alloc.cfa:313:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?=?
 ...to:
Index: tests/.expect/alloc.txt
===================================================================
--- tests/.expect/alloc.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/.expect/alloc.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -2,5 +2,4 @@
 CFA malloc 0xdeadbeef
 CFA alloc 0xdeadbeef
-CFA array alloc, fill 0xde
 CFA alloc, fill dededede
 CFA alloc, fill 3
Index: sts/.expect/completeTypeError.txt
===================================================================
--- tests/.expect/completeTypeError.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,141 +1,0 @@
-completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression
-Generated Cast of:
-  Applying untyped:
-    Name: *?
-  ...to:
-    Name: x
-
-... to: nothing Alternatives are:
-Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
-      Application of
-        Variable Expression: *?: forall
-          DT: data type
-          function
-        ... with parameters
-          intrinsic pointer to instance of type DT (not function type)
-        ... returning
-          _retval__operator_deref: reference to instance of type DT (not function type)
-          ... with attributes:
-            Attribute with name: unused
-
-
-      ... to arguments
-        Variable Expression: x: pointer to instance of struct A with body 0
-
-    ... to: nothing
-  (types:
-    void 
-  )
-  Environment:( _83_4_DT ) -> instance of struct A with body 0 (no widening)
-
-
-Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
-      Application of
-        Variable Expression: *?: forall
-          DT: data type
-          function
-        ... with parameters
-          intrinsic pointer to instance of type DT (not function type)
-        ... returning
-          _retval__operator_deref: reference to instance of type DT (not function type)
-          ... with attributes:
-            Attribute with name: unused
-
-
-      ... to arguments
-        Variable Expression: x: pointer to instance of struct B with body 1
-
-    ... to: nothing
-  (types:
-    void 
-  )
-  Environment:( _83_4_DT ) -> instance of struct B with body 1 (no widening)
-
-
-
-completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped:
-  Name: foo
-...to:
-  Name: v
-
-completeTypeError.cfa:36:1 error: No reasonable alternatives for expression Applying untyped:
-  Name: baz
-...to:
-  Name: v
-
-completeTypeError.cfa:37:1 error: No reasonable alternatives for expression Applying untyped:
-  Name: quux
-...to:
-  Name: v
-
-completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
-  Name: baz
-...to:
-  Name: y
-
-completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
-  Name: quux
-...to:
-  Name: y
-
-completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped:
-  Name: baz
-...to:
-  Name: z
-
-      Unsatisfiable alternative:
-Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
-            Variable Expression: baz: forall
-              T: sized data type
-              ... with assertions
-                ?=?: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                  instance of type T (not function type)
-                ... returning
-                  _retval__operator_assign: instance of type T (not function type)
-                  ... with attributes:
-                    Attribute with name: unused
-
-
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                  instance of type T (not function type)
-                ... returning nothing
-
-                ^?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
-
-              function
-            ... with parameters
-              pointer to instance of type T (not function type)
-            ... returning nothing
-
-          ... to arguments
-            Variable Expression: z: pointer to instance of type T (not function type)
-
-        (types:
-          void 
-        )
-        Environment:( _102_0_T ) -> instance of type T (not function type) (no widening)
-
-      Could not satisfy assertion:
-?=?: pointer to function
-        ... with parameters
-          reference to instance of type _102_0_T (not function type)
-          instance of type _102_0_T (not function type)
-        ... returning
-          _retval__operator_assign: instance of type _102_0_T (not function type)
-          ... with attributes:
-            Attribute with name: unused
-
-
Index: sts/.expect/declarationErrors.txt
===================================================================
--- tests/.expect/declarationErrors.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,70 +1,0 @@
-declarationErrors.cfa:16:1 error: duplicate static in declaration of x1: static const volatile short int 
-
-declarationErrors.cfa:17:1 error: conflicting extern & static in declaration of x2: extern const volatile short int 
-
-declarationErrors.cfa:18:1 error: conflicting extern & auto, conflicting extern & static, conflicting extern & static, duplicate extern in declaration of x3: extern const volatile short int 
-
-declarationErrors.cfa:19:1 error: duplicate static in declaration of x4: static const volatile instance of const volatile struct __anonymous0
-  with members
-    i: int 
-   with body
-
-
-declarationErrors.cfa:20:1 error: duplicate const, duplicate static, duplicate volatile in declaration of x5: static const volatile instance of const volatile struct __anonymous1
-  with members
-    i: int 
-   with body
-
-
-declarationErrors.cfa:22:1 error: duplicate static in declaration of x6: static const volatile Int
-
-declarationErrors.cfa:24:1 error: duplicate const in declaration of f01: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:25:1 error: duplicate volatile in declaration of f02: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:26:1 error: duplicate const in declaration of f03: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:27:1 error: duplicate volatile in declaration of f04: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:28:1 error: duplicate const in declaration of f05: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:29:1 error: duplicate volatile in declaration of f06: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:30:1 error: duplicate const in declaration of f07: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:31:1 error: duplicate const, duplicate volatile in declaration of f08: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:33:1 error: duplicate const, duplicate volatile in declaration of f09: static inline function
-  with no parameters
-  returning const volatile int 
-
-
-declarationErrors.cfa:34:1 error: duplicate const, duplicate _Atomic, duplicate _Atomic, duplicate const, duplicate restrict, duplicate volatile in declaration of f09: static inline function
-  with no parameters
-  returning const restrict volatile _Atomic int 
-
-
Index: tests/.expect/nested-types-ERR1.txt
===================================================================
--- tests/.expect/nested-types-ERR1.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/.expect/nested-types-ERR1.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -1,1 +1,1 @@
-nested-types.cfa:70:1 error: Use of undefined type T
+nested-types.cfa:83:1 error: Use of undefined type T
Index: tests/.expect/nested-types-ERR2.txt
===================================================================
--- tests/.expect/nested-types-ERR2.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/.expect/nested-types-ERR2.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -1,5 +1,5 @@
-nested-types.cfa:73:1 error: Use of undefined global type Z
-nested-types.cfa:74:1 error: Qualified type requires an aggregate on the left, but has: signed int
-nested-types.cfa:75:1 error: Undefined type in qualified type: Qualified Type:
+nested-types.cfa:86:1 error: Use of undefined global type Z
+nested-types.cfa:87:1 error: Qualified type requires an aggregate on the left, but has: signed int
+nested-types.cfa:88:1 error: Undefined type in qualified type: Qualified Type:
   instance of struct S with body 1
   instance of type Z (not function type)
Index: tests/.expect/rational.txt
===================================================================
--- tests/.expect/rational.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/.expect/rational.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -1,4 +1,4 @@
 constructor
-3/1 4/1 0/1
+3/1 4/1 0/1 0/1 1/1
 1/2 5/7
 2/3 -3/2
Index: sts/.expect/scopeErrors.txt
===================================================================
--- tests/.expect/scopeErrors.txt	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,12 +1,0 @@
-scopeErrors.cfa:2:1 error: duplicate object definition for thisIsAnError: signed int
-scopeErrors.cfa:20:1 error: duplicate function definition for butThisIsAnError: function
-... with parameters
-  double
-... returning
-  _retval_butThisIsAnError: double
-  ... with attributes:
-    Attribute with name: unused
-
-... with body
-  CompoundStmt
-
Index: tests/.expect/userLiterals.txt
===================================================================
--- tests/.expect/userLiterals.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/.expect/userLiterals.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,26 @@
+11.1
+15.0
+11.1
+24.8
+11.2
+11.1
+28.1
+secs 0
+secs 1
+secs 23
+mins 23
+hours 23
+_A_ 23
+_thingy_ 1234
+secs 65535
+mins 65535
+hours 65535
+_A_ 65535
+_thingy_ 65535
+secs 10
+hours 10
+mins 10
+_A_ 10
+_thingy_ 10
+s abc
+_thingy_ abc
Index: tests/Makefile.in
===================================================================
--- tests/Makefile.in	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/Makefile.in	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -374,11 +374,15 @@
 am__v_GOC_0 = @echo "  GOC     " $@;
 am__v_GOC_1 = 
+AM_V_PY = $(am__v_PY_@AM_V@)
+am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
+am__v_PY_0 = @echo "  PYTHON  " $@;
+am__v_PY_1 = 
 AM_V_RUST = $(am__v_RUST_@AM_V@)
 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
-am__v_RUST_0 = @echo "  RUST     " $@;
+am__v_RUST_0 = @echo "  RUST    " $@;
 am__v_RUST_1 = 
 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
-am__v_NODEJS_0 = @echo "  NODEJS     " $@;
+am__v_NODEJS_0 = @echo "  NODEJS  " $@;
 am__v_NODEJS_1 = 
 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
Index: sts/abort.cfa
===================================================================
--- tests/abort.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,18 +1,0 @@
-#include <stdlib.h>
-
-int level3() {
-	abort();
-	return 0;
-}
-
-int level2() {
-	return level3();
-}
-
-int level1() {
-	return level2();
-}
-
-int main() {
-	return level1();
-}
Index: tests/alloc.cfa
===================================================================
--- tests/alloc.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/alloc.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Feb  3 07:56:22 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Nov 22 15:34:19 2019
-// Update Count     : 404
+// Last Modified On : Sun Feb 16 09:21:13 2020
+// Update Count     : 405
 //
 
@@ -48,5 +48,4 @@
 
 	p = alloc_set( fill );								// CFA alloc, fill
-	printf( "CFA array alloc, fill %#hhx\n", fill );
 	printf( "CFA alloc, fill %08x\n", *p );
 	free( p );
Index: sts/completeTypeError.cfa
===================================================================
--- tests/completeTypeError.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,73 +1,0 @@
-void foo(int *) {}
-void bar(void *) {}
-forall(otype T) void baz(T *);
-forall(dtype T) void qux(T *);
-forall(dtype T | sized(T)) void quux(T *);
-
-struct A;	// incomplete
-struct B {};	// complete
-
-int main() {
-	int * i;
-	void * v;
-
-	A * x;
-	A * y;
-	B * x;
-	B * z;
-
-	// okay
-	*i;
-	*y;
-	*z;
-	foo(i);
-	bar(i);
-	baz(i);
-	qux(i);
-	quux(i);
-
-	bar(v);
-	qux(v);
-
-	// bad
-	*v;
-	*x;	// ambiguous
-	foo(v);
-	baz(v);
-	quux(v);
-}
-
-
-forall(otype T)
-void baz(T * x) {
-	// okay
-	bar(x);
-	baz(x);
-	qux(x);
-	quux(x);
-	*x;
-}
-
-forall(dtype T)
-void qux(T * y) {
-	// okay
-	*y;
-	bar(y);
-	qux(y);
-
-	// bad
-	baz(y);
-	quux(y);
-}
-
-forall(dtype T | sized(T))
-void quux(T * z) {
-	// okay
-	bar(z);
-	qux(z);
-	quux(z);
-	*z;
-
-	// bad
-	baz(z);
-}
Index: tests/concurrent/examples/quickSort.cfa
===================================================================
--- tests/concurrent/examples/quickSort.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/concurrent/examples/quickSort.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -11,6 +11,6 @@
 // Created On       : Wed Dec  6 12:15:52 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Oct 10 13:58:18 2019
-// Update Count     : 176
+// Last Modified On : Wed Feb 12 18:24:47 2020
+// Update Count     : 177
 //
 
@@ -27,5 +27,5 @@
 
 void ?{}( Quicksort & qs, int values[], int size, int depth ) {
-	qs.values = values;  qs.low = 0;  qs.high = size;  qs.depth = depth;
+	qs.[values, low, high, depth] = [values, 0, size, depth];
 } // Quicksort
 
@@ -167,5 +167,5 @@
 			values[counter] = size - counter;			// descending values
 		} // for
-		for ( int i = 0; i < 200; i +=1 ) {				// random shuffle a few values
+		for ( i; 200 ) {								// random shuffle a few values
 			swap( values[rand() % size], values[rand() % size] );
 		} // for
Index: sts/context.cfa
===================================================================
--- tests/context.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,19 +1,0 @@
-// trait declaration
-
-trait has_q( otype T ) {
-	T q( T );
-};
-
-forall( otype z | has_q( z ) ) void f() {
-	trait has_r( otype T, otype U ) {
-		T r( T, T (T,U) );
-	};
-
-	extern otype x, y | has_r( x, y );
-}
-
-//Dummy main
-int main(int argc, char const *argv[])
-{
-	return 0;
-}
Index: sts/declarationErrors.cfa
===================================================================
--- tests/declarationErrors.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,45 +1,0 @@
-// 
-// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-// 
-// declarationErrors.cfa -- 
-// 
-// Author           : Peter A. Buhr
-// Created On       : Wed Aug 17 08:23:43 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Nov  6 17:52:47 2018
-// Update Count     : 32
-// 
-
-static short int volatile static const x1;				// duplicate static
-extern short int static volatile const x2;				// multiple extern & static
-extern short int auto static volatile static extern const x3; // duplicate and multiple storage classes
-struct { int i; } const static volatile static x4;		// duplicate static
-struct { int i; } const static volatile const static volatile x5; // duplicate static & const & volatile
-typedef int Int;
-static Int volatile static const x6;					// duplicate static
-
-const static inline const volatile int f01();			// duplicate const
-volatile inline const volatile static int f02();		// duplicate volatile
-const inline const volatile int static f03();			// duplicate const
-volatile inline static const volatile int f04();		// duplicate volatile
-const static int const inline volatile f05();			// duplicate const
-volatile int static const volatile inline f06();		// duplicate volatile
-const static const int volatile inline f07();			// duplicate const
-volatile static const int inline const volatile f08();	// duplicate volatile
-
-volatile static const int inline const volatile f09();	// duplicate volatile
-_Atomic _Atomic _Atomic volatile restrict static const const int inline restrict const volatile f09();	// duplicate volatile
-
-//Dummy main
-int main(int argc, char const *argv[])
-{
-	return 0;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// compile-command: "cfa declarationErrors.cfa" //
-// End: //
Index: tests/errors/.expect/completeType.txt
===================================================================
--- tests/errors/.expect/completeType.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/.expect/completeType.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,141 @@
+errors/completeType.cfa:34:1 error: Cannot choose between 2 alternatives for expression
+Generated Cast of:
+  Applying untyped:
+    Name: *?
+  ...to:
+    Name: x
+
+... to: nothing Alternatives are:
+Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
+      Application of
+        Variable Expression: *?: forall
+          DT: data type
+          function
+        ... with parameters
+          intrinsic pointer to instance of type DT (not function type)
+        ... returning
+          _retval__operator_deref: reference to instance of type DT (not function type)
+          ... with attributes:
+            Attribute with name: unused
+
+
+      ... to arguments
+        Variable Expression: x: pointer to instance of struct A with body 0
+
+    ... to: nothing
+  (types:
+    void 
+  )
+  Environment:( _83_4_DT ) -> instance of struct A with body 0 (no widening)
+
+
+Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
+      Application of
+        Variable Expression: *?: forall
+          DT: data type
+          function
+        ... with parameters
+          intrinsic pointer to instance of type DT (not function type)
+        ... returning
+          _retval__operator_deref: reference to instance of type DT (not function type)
+          ... with attributes:
+            Attribute with name: unused
+
+
+      ... to arguments
+        Variable Expression: x: pointer to instance of struct B with body 1
+
+    ... to: nothing
+  (types:
+    void 
+  )
+  Environment:( _83_4_DT ) -> instance of struct B with body 1 (no widening)
+
+
+
+errors/completeType.cfa:35:1 error: No reasonable alternatives for expression Applying untyped:
+  Name: foo
+...to:
+  Name: v
+
+errors/completeType.cfa:36:1 error: No reasonable alternatives for expression Applying untyped:
+  Name: baz
+...to:
+  Name: v
+
+errors/completeType.cfa:37:1 error: No reasonable alternatives for expression Applying untyped:
+  Name: quux
+...to:
+  Name: v
+
+errors/completeType.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
+  Name: baz
+...to:
+  Name: y
+
+errors/completeType.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
+  Name: quux
+...to:
+  Name: y
+
+errors/completeType.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped:
+  Name: baz
+...to:
+  Name: z
+
+      Unsatisfiable alternative:
+Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
+            Variable Expression: baz: forall
+              T: sized data type
+              ... with assertions
+                ?=?: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning
+                  _retval__operator_assign: instance of type T (not function type)
+                  ... with attributes:
+                    Attribute with name: unused
+
+
+                ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+                ^?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+
+              function
+            ... with parameters
+              pointer to instance of type T (not function type)
+            ... returning nothing
+
+          ... to arguments
+            Variable Expression: z: pointer to instance of type T (not function type)
+
+        (types:
+          void 
+        )
+        Environment:( _102_0_T ) -> instance of type T (not function type) (no widening)
+
+      Could not satisfy assertion:
+?=?: pointer to function
+        ... with parameters
+          reference to instance of type _102_0_T (not function type)
+          instance of type _102_0_T (not function type)
+        ... returning
+          _retval__operator_assign: instance of type _102_0_T (not function type)
+          ... with attributes:
+            Attribute with name: unused
+
+
Index: tests/errors/.expect/declaration.txt
===================================================================
--- tests/errors/.expect/declaration.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/.expect/declaration.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,70 @@
+errors/declaration.cfa:16:1 error: duplicate static in declaration of x1: static const volatile short int 
+
+errors/declaration.cfa:17:1 error: conflicting extern & static in declaration of x2: extern const volatile short int 
+
+errors/declaration.cfa:18:1 error: conflicting extern & auto, conflicting extern & static, conflicting extern & static, duplicate extern in declaration of x3: extern const volatile short int 
+
+errors/declaration.cfa:19:1 error: duplicate static in declaration of x4: static const volatile instance of const volatile struct __anonymous0
+  with members
+    i: int 
+   with body
+
+
+errors/declaration.cfa:20:1 error: duplicate const, duplicate static, duplicate volatile in declaration of x5: static const volatile instance of const volatile struct __anonymous1
+  with members
+    i: int 
+   with body
+
+
+errors/declaration.cfa:22:1 error: duplicate static in declaration of x6: static const volatile Int
+
+errors/declaration.cfa:24:1 error: duplicate const in declaration of f01: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:25:1 error: duplicate volatile in declaration of f02: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:26:1 error: duplicate const in declaration of f03: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:27:1 error: duplicate volatile in declaration of f04: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:28:1 error: duplicate const in declaration of f05: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:29:1 error: duplicate volatile in declaration of f06: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:30:1 error: duplicate const in declaration of f07: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:31:1 error: duplicate const, duplicate volatile in declaration of f08: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:33:1 error: duplicate const, duplicate volatile in declaration of f09: static inline function
+  with no parameters
+  returning const volatile int 
+
+
+errors/declaration.cfa:34:1 error: duplicate const, duplicate _Atomic, duplicate _Atomic, duplicate const, duplicate restrict, duplicate volatile in declaration of f09: static inline function
+  with no parameters
+  returning const restrict volatile _Atomic int 
+
+
Index: tests/errors/.expect/scope.txt
===================================================================
--- tests/errors/.expect/scope.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/.expect/scope.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,12 @@
+errors/scope.cfa:2:1 error: duplicate object definition for thisIsAnError: signed int
+errors/scope.cfa:20:1 error: duplicate function definition for butThisIsAnError: function
+... with parameters
+  double
+... returning
+  _retval_butThisIsAnError: double
+  ... with attributes:
+    Attribute with name: unused
+
+... with body
+  CompoundStmt
+
Index: tests/errors/.expect/signature.txt
===================================================================
--- tests/errors/.expect/signature.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/.expect/signature.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,12 @@
+errors/signature.cfa:2:1 error: Constructors, destructors, and assignment functions require at least one parameter.
+errors/signature.cfa:3:1 error: Constructors, destructors, and assignment functions require at least one parameter.
+errors/signature.cfa:4:1 error: Constructors, destructors, and assignment functions require at least one parameter.
+errors/signature.cfa:5:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:6:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:7:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:10:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:11:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:12:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:13:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:14:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
+errors/signature.cfa:15:1 error: First parameter of a constructor, destructor, or assignment function must be a reference.
Index: tests/errors/completeType.cfa
===================================================================
--- tests/errors/completeType.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/completeType.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,73 @@
+void foo(int *) {}
+void bar(void *) {}
+forall(otype T) void baz(T *);
+forall(dtype T) void qux(T *);
+forall(dtype T | sized(T)) void quux(T *);
+
+struct A;	// incomplete
+struct B {};	// complete
+
+int main() {
+	int * i;
+	void * v;
+
+	A * x;
+	A * y;
+	B * x;
+	B * z;
+
+	// okay
+	*i;
+	*y;
+	*z;
+	foo(i);
+	bar(i);
+	baz(i);
+	qux(i);
+	quux(i);
+
+	bar(v);
+	qux(v);
+
+	// bad
+	*v;
+	*x;	// ambiguous
+	foo(v);
+	baz(v);
+	quux(v);
+}
+
+
+forall(otype T)
+void baz(T * x) {
+	// okay
+	bar(x);
+	baz(x);
+	qux(x);
+	quux(x);
+	*x;
+}
+
+forall(dtype T)
+void qux(T * y) {
+	// okay
+	*y;
+	bar(y);
+	qux(y);
+
+	// bad
+	baz(y);
+	quux(y);
+}
+
+forall(dtype T | sized(T))
+void quux(T * z) {
+	// okay
+	bar(z);
+	qux(z);
+	quux(z);
+	*z;
+
+	// bad
+	baz(z);
+}
Index: tests/errors/declaration.cfa
===================================================================
--- tests/errors/declaration.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/declaration.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,45 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+// 
+// declarationErrors.cfa -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Wed Aug 17 08:23:43 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Nov  6 17:52:47 2018
+// Update Count     : 32
+// 
+
+static short int volatile static const x1;				// duplicate static
+extern short int static volatile const x2;				// multiple extern & static
+extern short int auto static volatile static extern const x3; // duplicate and multiple storage classes
+struct { int i; } const static volatile static x4;		// duplicate static
+struct { int i; } const static volatile const static volatile x5; // duplicate static & const & volatile
+typedef int Int;
+static Int volatile static const x6;					// duplicate static
+
+const static inline const volatile int f01();			// duplicate const
+volatile inline const volatile static int f02();		// duplicate volatile
+const inline const volatile int static f03();			// duplicate const
+volatile inline static const volatile int f04();		// duplicate volatile
+const static int const inline volatile f05();			// duplicate const
+volatile int static const volatile inline f06();		// duplicate volatile
+const static const int volatile inline f07();			// duplicate const
+volatile static const int inline const volatile f08();	// duplicate volatile
+
+volatile static const int inline const volatile f09();	// duplicate volatile
+_Atomic _Atomic _Atomic volatile restrict static const const int inline restrict const volatile f09();	// duplicate volatile
+
+//Dummy main
+int main(int argc, char const *argv[])
+{
+	return 0;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa declarationErrors.cfa" //
+// End: //
Index: tests/errors/scope.cfa
===================================================================
--- tests/errors/scope.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/scope.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,25 @@
+int thisIsAnError;
+int thisIsAnError;
+
+int thisIsNotAnError;
+float thisIsNotAnError;
+
+int thisIsAlsoNotAnError() {
+  int thisIsNotAnError;
+}
+
+int thisIsAlsoNotAnError( double x ) {
+}
+
+double thisIsStillNotAnError( double );
+double thisIsStillNotAnError( double );
+
+double butThisIsAnError( double ) {
+}
+
+double butThisIsAnError( double ) {
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/errors/signature.cfa
===================================================================
--- tests/errors/signature.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/errors/signature.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,15 @@
+// No parameters
+void  ?{}();
+void ^?{}();
+void  ?=?();
+void  ?{}(void);
+void ^?{}(void);
+void  ?=?(void);
+
+// Wrong parameters
+void  ?{}(int);
+void ^?{}(int);
+void  ?=?(int);
+void  ?{}(int *);
+void ^?{}(int *);
+void  ?=?(int *);
Index: tests/exceptions/.expect/except-0.txt
===================================================================
--- tests/exceptions/.expect/except-0.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/exceptions/.expect/except-0.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,51 @@
+Exiting: terminate function
+Exiting: bar function
+foo caught exception zen.
+Exiting: foo function
+
+alpha caught exception zen
+resume returned
+Exiting: resume function
+Exiting: beta function
+Exiting: alpha function
+
+walk out of farewell
+See you next time
+leaving farewell
+
+jump out of farewell
+See you next time
+leaving farewell
+
+Exiting: resume function
+fallback caught termination zen
+
+Exiting: terminate function
+Exiting: terminate function
+Exiting: terminate_swap
+terminate_swapped caught exception yang
+Exiting: terminate_swapped
+
+resume_swapped caught exception yang
+resume returned
+Exiting: resume function
+resume returned
+Exiting: resume function
+Exiting: resume_swap
+
+Exiting: terminate function
+reterminate zen caught and will rethrow exception zen
+reterminate 1 caught exception zen
+
+reresume zen caught and rethrows exception zen
+reresume 1 caught exception zen
+resume returned
+Exiting: resume function
+
+Exiting: terminate function
+fy caught exception zen
+fee caught exception zen
+resume returned
+Exiting: resume function
+
+Exiting: main function
Index: tests/exceptions/.expect/except-1.txt
===================================================================
--- tests/exceptions/.expect/except-1.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/exceptions/.expect/except-1.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,13 @@
+First Caught
+Both Caught
+Part A Complete
+First Catch and rethrow
+Second Catch
+Part B Complete
+Throw before cleanup
+Catch after cleanup
+Part C Complete
+Caught initial throw.
+Caught intermediate throw.
+Caught final throw.
+Part D Complete
Index: tests/exceptions/.expect/except-2.txt
===================================================================
--- tests/exceptions/.expect/except-2.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/exceptions/.expect/except-2.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,3 @@
+throw yin caught.
+throwResume yang caught <> throwResume returned.
+Should be printed.
Index: tests/exceptions/.expect/except-3.txt
===================================================================
--- tests/exceptions/.expect/except-3.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/exceptions/.expect/except-3.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,1 @@
+throw [] unwind <> catch
Index: tests/exceptions/except-0.cfa
===================================================================
--- tests/exceptions/except-0.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/exceptions/except-0.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -19,10 +19,10 @@
 };
 
-void ?{}(signal_exit * this, const char * area) {
-	this->area = area;
-}
-
-void ^?{}(signal_exit * this) {
-	printf("Exiting: %s\n", this->area);
+void ?{}(signal_exit & this, const char * area) {
+	this.area = area;
+}
+
+void ^?{}(signal_exit & this) {
+	printf("Exiting: %s\n", this.area);
 //	sout | "Exiting:" | this->area;
 }
@@ -242,6 +242,8 @@
 
 	// Uncaught termination test.
+	/* Removed due to non-deterministic output.
 	printf("Throw uncaught.\n");
 	yang z;
 	terminate(&z);
-}
+	*/
+}
Index: tests/exceptions/except-2.cfa
===================================================================
--- tests/exceptions/except-2.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/exceptions/except-2.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -12,6 +12,6 @@
 	struct TABLE(BASE_EXCEPT) const * parent;
 	size_t size;
-	void (*copy)(num_error *this, num_error * other);
-	void (*free)(num_error *this);
+	void (*copy)(num_error &this, num_error & other);
+	void (*free)(num_error &this);
 	const char * (*msg)(num_error *this);
 	int (*code)(num_error *this);
@@ -28,5 +28,5 @@
 	if ( ! this->msg ) {
 		static const char * base = "Num Error with code: X";
-		this->msg = malloc(22);
+		this->msg = (char *)malloc(22);
 		for (int i = 0 ; (this->msg[i] = base[i]) ; ++i);
 	}
@@ -34,16 +34,16 @@
 	return this->msg;
 }
-void ?{}(num_error * this, int num) {
-	this->virtual_table = &INSTANCE(num_error);
-	this->msg = 0;
-	this->num = num;
+void ?{}(num_error & this, int num) {
+	this.virtual_table = &INSTANCE(num_error);
+	this.msg = 0;
+	this.num = num;
 }
-void ?{}(num_error * this, num_error * other) {
-	this->virtual_table = other->virtual_table;
-	this->msg = 0;
-	this->num = other->num;
+void ?{}(num_error & this, num_error & other) {
+	this.virtual_table = other.virtual_table;
+	this.msg = 0;
+	this.num = other.num;
 }
-void ^?{}(num_error * this) {
-	if( this->msg ) free( this->msg );
+void ^?{}(num_error & this) {
+	if( this.msg ) free( this.msg );
 }
 int num_error_code( num_error * this ) {
Index: tests/labelledExit.cfa
===================================================================
--- tests/labelledExit.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/labelledExit.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed Aug 10 07:29:39 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Oct 25 17:41:51 2019
-// Update Count     : 7
+// Last Modified On : Wed Feb  5 16:49:48 2020
+// Update Count     : 9
 // 
 
@@ -162,11 +162,11 @@
 
 	// computed goto
-	// {
-	// 	void *array[] = { &&foo, &&bar, &&hack };
-	//   foo: bar: hack:
-	// 	&&foo;
-	// 	&&bar;
-	// 	goto *array[i];
-	// }
+	{
+		void *array[] = { &&foo, &&bar, &&hack };
+	  foo: bar: hack:
+		&&foo;
+		&&bar;
+		goto *array[i];
+	}
 
   Q: if ( i > 5 ) {
Index: tests/linking/.expect/nostdlib.txt
===================================================================
--- tests/linking/.expect/nostdlib.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/linking/.expect/nostdlib.txt	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,1 @@
+NO
Index: tests/linking/nostdlib.cfa
===================================================================
--- tests/linking/nostdlib.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/linking/nostdlib.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,34 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// nostdlib.cfa --
+//
+// Author           : Thierry Delisle
+// Created On       : Tue Jul 16 12:14:39 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+extern _Bool threading_enabled(void) __attribute__((weak));
+
+int main() {
+	if(threading_enabled) {
+		if(threading_enabled()) {
+			printf("YES\n");
+		} else {
+			printf("NO\n");
+		}
+	} else {
+		printf("NO LIB\n");
+	}
+	return 0;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa nostdlib.cfa" //
+// End: //
Index: sts/namedParmArg.cfa
===================================================================
--- tests/namedParmArg.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,14 +1,0 @@
-int f1( int i = 3, int *j = 0 ) {}  /* ANSI */
-[int, int ] f2( int i = 3, * int j = 0 ) {}  /* CFA */
-
-int main() {
-    f1();		/* identical calls */
-    f1( 3 );
-    f1( 3, );
-    f1( 3, 0 );
-    f1( 3, j : 0 );
-    f1( j : 0, 3 );
-    f1( i : 3, j : 0 );
-    f1( j : 0, i : 3 );
-    f1( [j, i] : f2() );
-}
Index: tests/nested-types.cfa
===================================================================
--- tests/nested-types.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/nested-types.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jul 9 10:20:03 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Nov  6 17:59:40 2018
-// Update Count     : 2
+// Last Modified On : Wed Feb 12 18:21:15 2020
+// Update Count     : 3
 //
 
@@ -50,4 +50,17 @@
 //   double d;
 // };
+
+// struct S {
+//     enum C { R, G, B };
+//     int i;
+//     struct T {
+// 	int i;
+//     };
+//     T t;
+// };
+
+// S s;
+// S.C c;
+// S.T t;
 
 int main() {
Index: sts/occursError.cfa
===================================================================
--- tests/occursError.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,12 +1,0 @@
-forall( otype T ) void f( void (*)( T, T * ) );
-forall( otype U ) void g( U,  U * );
-forall( otype U ) void h( U *, U );
-
-void test() {
-    f( h );
-    f( g );
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: tests/pybin/tools.py
===================================================================
--- tests/pybin/tools.py	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/pybin/tools.py	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -175,15 +175,14 @@
 
 def which(program):
-    fpath, fname = os.path.split(program)
-    if fpath:
-        if is_exe(program):
-            return program
-    else:
-        for path in os.environ["PATH"].split(os.pathsep):
-            exe_file = os.path.join(path, program)
-            if is_exe(exe_file):
-                return exe_file
-
-    return None
+	fpath, fname = os.path.split(program)
+	if fpath:
+		if is_exe(program):
+			return program
+	else:
+		for path in os.environ["PATH"].split(os.pathsep):
+			exe_file = os.path.join(path, program)
+			if is_exe(exe_file):
+				return exe_file
+	return None
 
 @contextlib.contextmanager
@@ -365,15 +364,16 @@
 
 class Timed:
-    def __enter__(self):
-        self.start = time.time()
-        return self
-
-    def __exit__(self, *args):
-        self.end = time.time()
-        self.duration = self.end - self.start
+	def __enter__(self):
+		self.start = time.time()
+		return self
+
+	def __exit__(self, *args):
+		self.end = time.time()
+		self.duration = self.end - self.start
 
 def timed(src, timeout):
 	expire = time.time() + timeout
 	i = iter(src)
-	while True:
-		yield i.next(max(expire - time.time(), 0))
+	with contextlib.suppress(StopIteration):
+		while True:
+			yield i.next(max(expire - time.time(), 0))
Index: tests/quotedKeyword.cfa
===================================================================
--- tests/quotedKeyword.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/quotedKeyword.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb  1 00:02:22 2020
-// Update Count     : 24
+// Last Modified On : Fri Feb  7 19:07:07 2020
+// Update Count     : 25
 //
 
@@ -17,29 +17,29 @@
 
 struct {
-	int ``otype``;
-	int ``struct``;
+	int ``otype;
+	int ``struct;
 } st = { 10, 10 };
 
-typedef int ``forall``;
-``forall`` xxx = 10;
+typedef int ``forall;
+``forall xxx = 10;
 
-int ``_Alignas``, ``_Alignof``, ``__alignof``, ``__alignof__``, ``asm``, ``__asm``, ``__asm__``, ``_At``, ``_Atomic``, ``__attribute``,
-	``__attribute__``, ``auto``, ``_Bool``, ``break``, ``case``, ``catch``, ``catchResume``, ``char``, ``choose``, ``_Complex``, ``__complex``,
-	``__complex__``, ``const``, ``__const``, ``__const__``, ``continue``, ``default``, ``disable``, ``do``, ``double``, ``dtype``, ``else``,
-	``enable``, ``enum``, ``__extension__``, ``extern``, ``fallthru``, ``finally``, ``float``, ``__float128``, ``for``, ``forall``, ``fortran``,
-	``ftype``, ``_Generic``, ``goto``, ``if``, ``_Imaginary``, ``__imag``, ``__imag__``, ``inline``, ``__inline``, ``__inline__``, ``int``,
-	``__int128``, ``__label__``, ``long``, ``lvalue``, ``_Noreturn``, ``__builtin_offsetof``, ``otype``, ``register``, ``restrict``,
-	``__restrict``, ``__restrict__``, ``return``, ``short``, ``signed``, ``__signed``, ``__signed__``, ``sizeof``, ``static``,
-	``_Static_assert``, ``struct``, ``switch``, ``_Thread_local``, ``throw``, ``throwResume``, ``trait``, ``try``, ``typedef``,
-	``typeof``, ``__typeof``, ``__typeof__``, ``union``, ``unsigned``, ``__builtin_va_list``, ``void``, ``volatile``, ``__volatile``,
-	``__volatile__``, ``while``;
+int ``_Alignas, ``_Alignof, ``__alignof, ``__alignof__, ``asm, ``__asm, ``__asm__, ``_At, ``_Atomic, ``__attribute,
+	``__attribute__, ``auto, ``_Bool, ``break, ``case, ``catch, ``catchResume, ``char, ``choose, ``_Complex, ``__complex,
+	``__complex__, ``const, ``__const, ``__const__, ``continue, ``default, ``disable, ``do, ``double, ``dtype, ``else,
+	``enable, ``enum, ``__extension__, ``extern, ``fallthru, ``finally, ``float, ``__float128, ``for, ``forall, ``fortran,
+	``ftype, ``_Generic, ``goto, ``if, ``_Imaginary, ``__imag, ``__imag__, ``inline, ``__inline, ``__inline__, ``int,
+	``__int128, ``__label__, ``long, ``lvalue, ``_Noreturn, ``__builtin_offsetof, ``otype, ``register, ``restrict,
+	``__restrict, ``__restrict__, ``return, ``short, ``signed, ``__signed, ``__signed__, ``sizeof, ``static,
+	``_Static_assert, ``struct, ``switch, ``_Thread_local, ``throw, ``throwResume, ``trait, ``try, ``typedef,
+	``typeof, ``__typeof, ``__typeof__, ``union, ``unsigned, ``__builtin_va_list, ``void, ``volatile, ``__volatile,
+	``__volatile__, ``while;
 
 int main() {
-	int ``if`` = 0;
-	``catch`` = 1;
-	st.``otype`` = 2;
-	st.``struct`` = 3;
-	``throw`` = 4;
-	sout | ``catch`` + st.``otype`` + st.``struct`` + ``throw``;
+	int ``if = 0;
+	``catch = 1;
+	st.``otype = 2;
+	st.``struct = 3;
+	``throw = 4;
+	sout | ``catch + st.``otype + st.``struct + ``throw;
 }
 
Index: tests/rational.cfa
===================================================================
--- tests/rational.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/rational.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -10,6 +10,6 @@
 // Created On       : Mon Mar 28 08:43:12 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Mar 27 07:37:17 2019
-// Update Count     : 80
+// Last Modified On : Sat Feb  8 18:46:23 2020
+// Update Count     : 86
 //
 
@@ -19,25 +19,26 @@
 #include <fstream.hfa>
 
-double convert( int i ) { return (double)i; }
+typedef Rational(int) RatInt;
+double convert( int i ) { return (double)i; }			// used by narrow/widen
 int convert( double d ) { return (int)d; }
 
 int main() {
 	sout | "constructor";
-	Rational(int) a = { 3 }, b = { 4 }, c;
-	sout | a | b | c;
+	RatInt a = { 3 }, b = { 4 }, c, d = 0, e = 1;
+	sout | a | b | c | d | e;
 
-	a = (Rational(int)){ 4, 8 };
-	b = (Rational(int)){ 5, 7 };
+	a = (RatInt){ 4, 8 };
+	b = (RatInt){ 5, 7 };
 	sout | a | b;
-	a = (Rational(int)){ -2, -3 };
-	b = (Rational(int)){ 3, -2 };
+	a = (RatInt){ -2, -3 };
+	b = (RatInt){ 3, -2 };
 	sout | a | b;
-	a = (Rational(int)){ -2, 3 };
-	b = (Rational(int)){ 3, 2 };
+	a = (RatInt){ -2, 3 };
+	b = (RatInt){ 3, 2 };
 	sout | a | b;
 
 	sout | "logical";
-	a = (Rational(int)){ -2 };
-	b = (Rational(int)){ -3, 2 };
+	a = (RatInt){ -2 };
+	b = (RatInt){ -3, 2 };
 	sout | a | b;
 //	sout | a == 1; // FIX ME
@@ -58,9 +59,9 @@
 
 	sout | "conversion";
-	a = (Rational(int)){ 3, 4 };
+	a = (RatInt){ 3, 4 };
 	sout | widen( a );
-	a = (Rational(int)){ 1, 7 };
+	a = (RatInt){ 1, 7 };
 	sout | widen( a );
-	a = (Rational(int)){ 355, 113 };
+	a = (RatInt){ 355, 113 };
 	sout | widen( a );
 	sout | narrow( 0.75, 4 );
@@ -74,5 +75,5 @@
 
 	sout | "more tests";
-	Rational(int) x = { 1, 2 }, y = { 2 };
+	RatInt x = { 1, 2 }, y = { 2 };
 	sout | x - y;
 	sout | x > y;
@@ -80,12 +81,12 @@
 	sout | y | denominator( y, -2 ) | y;
 
-	Rational(int) z = { 0, 5 };
+	RatInt z = { 0, 5 };
 	sout | z;
 
 	sout | x | numerator( x, 0 ) | x;
 
-	x = (Rational(int)){ 1, MAX } + (Rational(int)){ 1, MAX };
+	x = (RatInt){ 1, MAX } + (RatInt){ 1, MAX };
 	sout | x;
-	x = (Rational(int)){ 3, MAX } + (Rational(int)){ 2, MAX };
+	x = (RatInt){ 3, MAX } + (RatInt){ 2, MAX };
 	sout | x;
 
Index: sts/scope.cfa
===================================================================
--- tests/scope.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,73 +1,0 @@
-int x;
-typedef double y;
-typedef float t;
-y z;
-//otype u = struct { int a; double b; };
-typedef struct { int a; double b; } u;
-int f( int y );
-y q;
-struct x { int x; };
-
-y w( y y, u v ) {
-//	otype x | { x t(u); };
-	void ?{}(struct x *);
-	void ^?{}(struct x *);
-	extern struct x t( u );
-	u u = y;
-	struct x z = t(u);
-}
-
-y p;
-
-trait has_u( otype z ) {
-	z u(z);
-};
-
-forall( otype t | has_u( t ) )
-y q( t the_t ) {
-	t y = u( the_t );
-}
-
-t f( y p ) {
-	int y;
-	typedef char x;
-	{
-		x y;
-		typedef x z;
-		{
-			z x;
-			typedef z y;
-			y z = x;
-		}
-		z x = y;
-	}
-	x q = y;
-}
-
-void some_func() {}
-
-t g( void ) {
-	typedef char x;
-//	try {
-		some_func();
-//	} catch ( x x ) {
-//		t y = x;
-//	}
-	x z;
-}
-
-y q( i )												/* K&R style */
-	int i;
-{
-	switch ( i ) {
-		y q = i;
-	  case 0:
-		return q;
-	  default:
-		return i;
-	}
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: sts/scopeErrors.cfa
===================================================================
--- tests/scopeErrors.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,25 +1,0 @@
-int thisIsAnError;
-int thisIsAnError;
-
-int thisIsNotAnError;
-float thisIsNotAnError;
-
-int thisIsAlsoNotAnError() {
-  int thisIsNotAnError;
-}
-
-int thisIsAlsoNotAnError( double x ) {
-}
-
-double thisIsStillNotAnError( double );
-double thisIsStillNotAnError( double );
-
-double butThisIsAnError( double ) {
-}
-
-double butThisIsAnError( double ) {
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: sts/structMember.cfa
===================================================================
--- tests/structMember.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,100 +1,0 @@
-typedef int TD;
-extern struct TTT {};
-
-struct S {
-	int m1:3, m2:4;
-	int :2;
-	int :3, :4;
-	int m3;
-	int m4, m5, m6;
-	int *m7, *m8, *m9;
-	__extension__ int (*m10)();
-	__extension__ int *(*m11)(int);
-//	TD (TD);
-
-// Cforall declarations
-
-	* int m12, m13;
-	* [ * int ] (int) m14;
-
-// C anonymous declarations (padding)
-
-	int :4;
-	int :4, :6;
-
-// Cforall anonymous declarations (padding)
-
-	int @;
-	TD @;
-	int @, @, @;
-	int * @ , @, @;
-	int * @, * @, * @;
-	* int @, @, @;
-	struct TTT @;
-	TTT @, @;
-	int @ :4, @ :6;
-	* int @, @;
-	int (*@)();
-	int (*@)(int), (*@)(int);
-	* [int](int) @, @;
-	int (**@)( int );
-	* * [int](int) @;
-
-// C aggregate open declarations
-
-	__extension__ union { int i; };
-	struct T { int k; };
-
-// Cforall forward declaration
-
-	struct PPP;
-	__extension__ struct QQQ;
-
-// C useless declarations
-
-	int;
-	TD;
-	unsigned int;
-	__extension__ long double;
-	_Complex;
-	double _Complex;
-	volatile zero_t;
-	const one_t;
-	S;
-	.S;
-	S.T;
-	.S.T;
-	forall( otype S, otype T ) struct W {
-		struct X {};
-	};
-	W(int);
-	W(int).X;
-};
-
-struct S s;
-
-// Cforall Plan 9 declarations
-
-struct UUU {};
-extern struct SSS {
-	inline struct WWW {};
-	inline UUU;
-	inline UUU *, **;
-	inline UUU (*)( int p );
-	inline int;
-	inline int *;
-	inline * int;
-	inline int (*)( int p );
-	inline * [int](int p);
-};
-
-union U {
-	[5] int m1;
-	int m2[5];
-	* int m3;
-	int *m4;
-} u;
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: sts/subrange.cfa
===================================================================
--- tests/subrange.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,63 +1,0 @@
-// A small context defining the notion of an ordered otype.  (The standard
-// library should probably contain a context for this purpose.)
-trait ordered(otype T) {
-    int ?<?(T, T), ?<=?(T, T);
-};
-
-// A subrange otype resembling an Ada subotype with a base otype and a range
-// constraint.
-otype subrange(otype base_t | ordered(base_t), base_t low = 0, base_t high = 8) = base_t;
-
-// Note that subrange() can be applied to floating-point and pointer otypes, not
-// just integral otypes.
-//   This requires a "otype generator" extension to Cforall.  Type generators
-// must accept otype and non-otype parameters, which is beyond what we discussed
-// previously.  Type parameters must be usable in the declaration of
-// subsequent parameters: parameter T is used to declare parameters "low"
-// and "high".
-
-// Example usage:
-subrange(unsigned, 1, 31) day_of_month;
-subrange(char, 'a', 'z')  lcase;
-subrange(int, 0, (rand() & 0xF) ) foo;
-
-// What sorts of expressions can be used as arguments of otype generators?  Is
-// "subrange(int, 0, rand() & 0xF)" legal?  Probably.  The nearest C equivalent
-// to the "low" and "high" arguments is the array size in a variable-length
-// array declaration, and C allows assignment expressions there.
-
-// Convenient access to subrange bounds, for instance for iteration:
-forall (otype T, T low, T high)
-T lbound( subrange(T, low, high) v) {
-    return low;
-}
-
-forall (otype T, T low, T high)
-T hbound( subrange(T, low, high) v) {
-    return high;
-}
-
-// Example usage:
-unsigned lday = lbound(day_of_month);
-
-// Assignment from the base otype, with bounds checking.  I'll ignore the issue
-// of exception handling here.  Inlining allows the compiler to eliminate
-// bounds checks.
-forall (otype T | ordered(T), T low, T high)
-inline subrange(T, low, high) ?=?(subrange(T, low, high)* target, T source) {
-    if (low <= source && source <= high) *((T*)target) = source;
-    else abort();
-    return target;
-}
-
-// Assignment between subranges with a common base otype.  The bounds check
-// compares range bounds so that the compiler can optimize checks away when the
-// ranges are known to overlap.
-forall (otype T | ordered(T), T t_low, T t_high, T s_low, T s_high)
-inline subrange(T, t_low, t_high) ?=?(subrange(T, t_low, t_high)* target,
-				      subrange(T, s_low, s_high) source) {
-    if ( (t_low <= s_low || t_low <= source)
-	 && (s_high <= t_high || source <= t_high) ) *((T*)target) = source;
-    else abort();
-    return target;
-}
Index: tests/test.py
===================================================================
--- tests/test.py	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/test.py	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -152,5 +152,5 @@
 	# run everything in a temp directory to make sure core file are handled properly
 	with tempdir():
-		# if the make command succeds continue otherwise skip to diff
+		# if the make command succeeds continue otherwise skip to diff
 		if success(make_ret):
 			with Timed() as run_dur:
Index: sts/typeGenerator.cfa
===================================================================
--- tests/typeGenerator.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,30 +1,0 @@
-context addable( otype T ) {
-	T ?+?( T,T );
-	T ?=?( T*, T);
-};
-
-otype List1( otype T | addable( T ) ) = struct { T data; List1( T ) *next; } *;
-typedef List1( int ) ListOfIntegers;
-//List1( int ) li;
-ListOfIntegers li;
-int f( List1( int ) ( (*g ))( int ) );
-[int] h( * List1( int ) p );							// new declaration syntax
-
-struct( otype T ) S2 { T i; };							// actual definition
-struct( int ) S3 v1, *p;								// expansion and instantiation
-struct( otype T )( int ) S24 { T i; } v2;				// actual definition, expansion and instantiation
-struct( otype T )( int ) { T i; } v2;					// anonymous actual definition, expansion and instantiation
-
-struct( otype T | addable( T ) ) node { T data; struct( T ) node *next; };
-otype List( otype T ) = struct( T ) node *;
-List( int ) my_list;
-
-otype Complex | addable( Complex );
-
-int main() {
-	(struct( int ) node)my_list;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: sts/typedef.cfa
===================================================================
--- tests/typedef.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,47 +1,0 @@
-typedef int T;
-
-void f( void ) {
-    int T( T p ) { return 3; }
-    T( 3 );
-}
-
-struct {
-    T (T);
-} fred = { 3 };
-
-typedef int (*a)(int, char);
-a b;
-
-int g(void) {
-    double a;
-}
-a c;
-
-typedef typeof(3) x, y;  // GCC
-
-x p;
-y q;
-
-int main() {
-    typedef typeof(3) z, p;
-    z w;
-    p x;
-}
-
-// new-style function definitions
-
-typedef [10] * int arrayOf10Pointers;
-arrayOf10Pointers array;
-typedef const * int constantPointer;
-typedef * [ int ]( [] int ) funcPtr;
-typedef [ int ] funcProto( []  int );
-typedef [ int, int ] tupleType;
-typedef * [ int, int ] tupleTypePtr;
-typedef * int c, d;
-typedef [ int ] f( * int ), g;
-typedef [ * [static 10] int ] t;
-typedef [ * [static 10] int x ] h();
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: sts/typedefDeclarator.cfa
===================================================================
--- tests/typedefDeclarator.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,120 +1,0 @@
-typedef int
-	 f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,  f8,  f9,
-	f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
-	f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
-	f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
-	f40, f41, f42, f43, f44, f45, f46, f47, f48, f49,
-	f50, f51, f52, f53, f54, f55, f56, f57, f58, f59,
-	f60, f61, f62, f63, f64, f65, f66, f67, f68, f69,
-	f70, f71, f72, f73, f74, f75, f76, f77, f78, f79,
-	f80, f81, f82, f83, f84, f85, f86, f87, f88, f89;
-
-int main() {
-	//int f0[]();
-	//int (f0[])();
-	//int f0()[];
-	//int f0()();
-	//int (*f0)()();
-	//int ((*f0())())[];
-	
-	int f1;
-	int (f2);
-
-	int *f3;
-	int **f4;
-	int * const *f5;
-	int * const * const f6;
-
-	int *(f7);
-	int **(f8);
-	int * const *(f9);
-	int * const * const (f10);
-
-	int (*f11);
-	int (**f12);
-	int (* const *f13);
-	int (* const * const f14);
-
-	int f15[];
-	int f16[10];
-	int (f17[]);
-	int (f18[10]);
-
-	int *f19[];
-	int *f20[10];
-	int **f21[];
-	int **f22[10];
-	int * const *f23[];
-	int * const *f24[10];
-	int * const * const f25[];
-	int * const * const f26[10];
-
-	int *(f27[]);
-	int *(f28[10]);
-	int **(f29[]);
-	int **(f30[10]);
-	int * const *(f31[]);
-	int * const *(f32[10]);
-	int * const * const (f33[]);
-	int * const * const (f34[10]);
-
-	int (*f35[]);
-	int (*f36[10]);
-	int (**f37[]);
-	int (**f38[10]);
-	int (* const *f39[]);
-	int (* const *f40[10]);
-	int (* const * const f41[]);
-	int (* const * const f42[10]);
-
-	int f43[][3];
-	int f44[3][3];
-	int (f45[])[3];
-	int (f46[3])[3];
-	int ((f47[]))[3];
-	int ((f48[3]))[3];
-
-	int *f49[][3];
-	int *f50[3][3];
-	int **f51[][3];
-	int **f52[3][3];
-	int * const *f53[][3];
-	int * const *f54[3][3];
-	int * const * const f55[][3];
-	int * const * const f56[3][3];
-
-	int (*f57[][3]);
-	int (*f58[3][3]);
-	int (**f59[][3]);
-	int (**f60[3][3]);
-	int (* const *f61[][3]);
-	int (* const *f62[3][3]);
-	int (* const * const f63[][3]);
-	int (* const * const f64[3][3]);
-
-	int f65(int);
-	int (f66)(int);
-
-	int *f67(int);
-	int **f68(int);
-	int * const *f69(int);
-	int * const * const f70(int);
-
-	int *(f71)(int);
-	int **(f72)(int);
-	int * const *(f73)(int);
-	int * const * const (f74)(int);
-
-	int (*f75)(int);
-	int (**f76)(int);
-	int (* const *f77)(int);
-	int (* const * const f78)(int);
-
-	int (*(*f79)(int))();
-	int (*(* const f80)(int))();
-	int (* const(* const f81)(int))();
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: tests/userLiterals.cfa
===================================================================
--- tests/userLiterals.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ tests/userLiterals.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// user_literals.cfa --
+// userLiterals.cfa --
 //
 // Author           : Peter A. Buhr
 // Created On       : Wed Sep  6 21:40:50 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Dec  4 22:03:10 2018
-// Update Count     : 56
+// Last Modified On : Wed Feb 19 07:48:45 2020
+// Update Count     : 74
 //
 
@@ -24,7 +24,7 @@
 int ?`__thingy_( int x ) { sout | "_thingy_" | x; return x; }
 
-int ?`s( const char * s ) { sout | "secs" | s; return 0; }
-int ?`m( const char16_t * m ) { sout | "mins" | m; return 0;}
-int ?`h( const char32_t * h ) { sout | "hours" | h; return 0; }
+int ?`s( const char * s ) { sout | "s" | s; return 0; }
+int ?`m( const char16_t * m ) { sout | "m" | m; return 0;}
+int ?`h( const char32_t * h ) { sout | "h" | h; return 0; }
 int ?`_A_( const wchar_t * str ) { sout | "_A_" | str; return 0; }
 int ?`__thingy_( const char * str ) { sout | "_thingy_" | str; return 0; }
@@ -37,5 +37,6 @@
 	return (Weight){ l.stones + r.stones };
 }
-ofstream & ?|?( ofstream & os, Weight w ) { return os | w.stones; }
+ofstream & ?|?( ofstream & os, Weight w ) { return os | wd(1,1, w.stones); }
+void ?|?( ofstream & os, Weight w ) { (ofstream)(os | w); ends( os ); }
 
 Weight ?`st( double w ) { return (Weight){ w }; }		// backquote for user literals
@@ -60,5 +61,5 @@
 	sout | w;
 
-//	0`secs;
+	0`s;
 	1`s;
 	23`s;
@@ -82,7 +83,8 @@
 
 	"abc"`s;
-//	u"abc"`m;
-//	U_"abc"`h;
-//	L"abc"`_A_;
+	// FIX ME: requires char16_t, char32_t, and wchar_t be unique types
+	// u"abc"`m;
+	// U_"abc"`h;
+	// L"abc"`_A_;
 	u8_"abc"`__thingy_;
 } // main
@@ -90,4 +92,4 @@
 // Local Variables: //
 // tab-width: 4 //
-// compile-command: "cfa user_literals.cfa" //
+// compile-command: "cfa userLiterals.cfa" //
 // End: //
Index: sts/virtualCast.cfa
===================================================================
--- tests/virtualCast.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,76 +1,0 @@
-// Testing the virtual cast, as part of strict inheritance.
-
-/* IMPORTANT: This test does not repersent the final feature set.
- * We are missing a number of important aspects such as:
- * + vtable type generation.
- * + vtable instance generation, that might use different resolution rules.
- * + Virtual syntax to force said generation on structures and traits.
- * + Trait references/pointers that do the virtual_table lookup.
- */
-
-#include <stdlib.hfa>
-#include <assert.h>
-
-struct alpha_vtable {
-	alpha_vtable const * const parent;
-	char (*code)(void);
-};
-
-struct alpha {
-	alpha_vtable const * virtual_table;
-};
-
-char ret_a(void) {
-	return 'a';
-}
-
-
-
-struct beta_vtable {
-	alpha_vtable const * const parent;
-	char (*code)(void);
-};
-
-struct beta {
-	beta_vtable const * virtual_table;
-};
-
-char ret_b(void) {
-	return 'b';
-}
-
-
-
-struct gamma_vtable {
-	beta_vtable const * const parent;
-	char (*code)(void);
-};
-
-struct gamma {
-	gamma_vtable const * virtual_table;
-};
-
-char ret_g(void) {
-	return 'g';
-}
-
-
-extern "C" {
-	alpha_vtable _alpha_vtable_instance = { 0, ret_a };
-	beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
-	gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
-}
-
-int main (int argc, char * argv[]) {
-
-	gamma * tri = malloc(); tri->virtual_table = &_gamma_vtable_instance;
-	beta * mid = (virtual beta *)tri;
-	assert( 'g' == mid->virtual_table->code() );
-
-	alpha * top = malloc(); top->virtual_table = &_alpha_vtable_instance;
-	mid = (virtual beta *)top;
-	assert( ! mid );
-
-	free(tri);
-	free(top);
-}
Index: sts/withStatement.cfa
===================================================================
--- tests/withStatement.cfa	(revision 8c50aed95a361f33369903cfdf38ceaaefeffddf)
+++ 	(revision )
@@ -1,109 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tupleFunction.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Mon Dec 04 17:41:45 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Dec 24 19:08:18 2018
-// Update Count     : 5
-//
-
-#include <fstream.hfa>
-
-struct S {
-	int i;
-	// dynamically allocated member ensures ctor/dtors are called correctly on temporaries
-	int * ptr;
-};
-
-// with clause on reference parameter
-void ?{}( S & this, int n ) with( this ) {
-	i = n;
-	ptr = (int *)malloc( sizeof(int) );
-}
-
-void ?{}( S & this ) {
-	this{ 0 };
-}
-
-void ?{}( S & this, S other ) {
-	this{ other.i };
-}
-
-S ?=?( S & this, S other ) with( this ) {
-	i = other.i;
-	*ptr = *other.ptr;
-	return this;
-}
-
-void ^?{}( S & this ) with( this ) {
-	free( ptr );
-}
-
-struct S2 {
-	S s;
-};
-
-void ?{}( S2 & this, int n ) {
-	(this.s){ n };
-}
-
-forall( otype T )
-struct Box {
-	T x;
-};
-
-forall( otype T )
-void ?{}( Box(T) & this ) with( this ) { // with clause in polymorphic function
-	x{};
-}
-
-void print( int i ) { sout | i; }
-
-forall( otype T | { void print( T ); })
-void foo( T t ) {
-	Box( T ) b = { t };
-	with( b ) {  // with statement in polymorphic function
-		print( x );
-	}
-}
-
-// ensure with-statement temporary generation works correctly
-S mk() {
-	sout | "called mk";
-	return (S){ 444 };
-}
-
-// ensure with-statement temporary generation with reference-returning functions works correctly
-S & ref() {
-	static S var = { 123456789 };
-	return var;
-}
-
-int main() {
-	S2 s2 = { 12345 };
-	with ( s2) {
-		with( s ) { // with s2.s
-			sout | i | s.i | s2.s.i;
-			foo( i );  // s.i
-			with( mk()) {
-				sout | i | i | i;
-				with( ref()) {
-					sout | i | i | i;
-				} // with ref()
-				with( ref()) {
-					sout | i | i | i;
-				} // with ref()
-			} // with mk()
-		} // with s
-	} // with s2
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: tests/zombies/context.cfa
===================================================================
--- tests/zombies/context.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/context.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,19 @@
+// trait declaration
+
+trait has_q( otype T ) {
+	T q( T );
+};
+
+forall( otype z | has_q( z ) ) void f() {
+	trait has_r( otype T, otype U ) {
+		T r( T, T (T,U) );
+	};
+
+	extern otype x, y | has_r( x, y );
+}
+
+//Dummy main
+int main(int argc, char const *argv[])
+{
+	return 0;
+}
Index: tests/zombies/namedParmArg.cfa
===================================================================
--- tests/zombies/namedParmArg.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/namedParmArg.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,14 @@
+int f1( int i = 3, int *j = 0 ) {}  /* ANSI */
+[int, int ] f2( int i = 3, * int j = 0 ) {}  /* CFA */
+
+int main() {
+    f1();		/* identical calls */
+    f1( 3 );
+    f1( 3, );
+    f1( 3, 0 );
+    f1( 3, j : 0 );
+    f1( j : 0, 3 );
+    f1( i : 3, j : 0 );
+    f1( j : 0, i : 3 );
+    f1( [j, i] : f2() );
+}
Index: tests/zombies/occursError.cfa
===================================================================
--- tests/zombies/occursError.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/occursError.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,12 @@
+forall( otype T ) void f( void (*)( T, T * ) );
+forall( otype U ) void g( U,  U * );
+forall( otype U ) void h( U *, U );
+
+void test() {
+    f( h );
+    f( g );
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/zombies/scope.cfa
===================================================================
--- tests/zombies/scope.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/scope.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,73 @@
+int x;
+typedef double y;
+typedef float t;
+y z;
+//otype u = struct { int a; double b; };
+typedef struct { int a; double b; } u;
+int f( int y );
+y q;
+struct x { int x; };
+
+y w( y y, u v ) {
+//	otype x | { x t(u); };
+	void ?{}(struct x *);
+	void ^?{}(struct x *);
+	extern struct x t( u );
+	u u = y;
+	struct x z = t(u);
+}
+
+y p;
+
+trait has_u( otype z ) {
+	z u(z);
+};
+
+forall( otype t | has_u( t ) )
+y q( t the_t ) {
+	t y = u( the_t );
+}
+
+t f( y p ) {
+	int y;
+	typedef char x;
+	{
+		x y;
+		typedef x z;
+		{
+			z x;
+			typedef z y;
+			y z = x;
+		}
+		z x = y;
+	}
+	x q = y;
+}
+
+void some_func() {}
+
+t g( void ) {
+	typedef char x;
+//	try {
+		some_func();
+//	} catch ( x x ) {
+//		t y = x;
+//	}
+	x z;
+}
+
+y q( i )												/* K&R style */
+	int i;
+{
+	switch ( i ) {
+		y q = i;
+	  case 0:
+		return q;
+	  default:
+		return i;
+	}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/zombies/structMember.cfa
===================================================================
--- tests/zombies/structMember.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/structMember.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,100 @@
+typedef int TD;
+extern struct TTT {};
+
+struct S {
+	int m1:3, m2:4;
+	int :2;
+	int :3, :4;
+	int m3;
+	int m4, m5, m6;
+	int *m7, *m8, *m9;
+	__extension__ int (*m10)();
+	__extension__ int *(*m11)(int);
+//	TD (TD);
+
+// Cforall declarations
+
+	* int m12, m13;
+	* [ * int ] (int) m14;
+
+// C anonymous declarations (padding)
+
+	int :4;
+	int :4, :6;
+
+// Cforall anonymous declarations (padding)
+
+	int @;
+	TD @;
+	int @, @, @;
+	int * @ , @, @;
+	int * @, * @, * @;
+	* int @, @, @;
+	struct TTT @;
+	TTT @, @;
+	int @ :4, @ :6;
+	* int @, @;
+	int (*@)();
+	int (*@)(int), (*@)(int);
+	* [int](int) @, @;
+	int (**@)( int );
+	* * [int](int) @;
+
+// C aggregate open declarations
+
+	__extension__ union { int i; };
+	struct T { int k; };
+
+// Cforall forward declaration
+
+	struct PPP;
+	__extension__ struct QQQ;
+
+// C useless declarations
+
+	int;
+	TD;
+	unsigned int;
+	__extension__ long double;
+	_Complex;
+	double _Complex;
+	volatile zero_t;
+	const one_t;
+	S;
+	.S;
+	S.T;
+	.S.T;
+	forall( otype S, otype T ) struct W {
+		struct X {};
+	};
+	W(int);
+	W(int).X;
+};
+
+struct S s;
+
+// Cforall Plan 9 declarations
+
+struct UUU {};
+extern struct SSS {
+	inline struct WWW {};
+	inline UUU;
+	inline UUU *, **;
+	inline UUU (*)( int p );
+	inline int;
+	inline int *;
+	inline * int;
+	inline int (*)( int p );
+	inline * [int](int p);
+};
+
+union U {
+	[5] int m1;
+	int m2[5];
+	* int m3;
+	int *m4;
+} u;
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/zombies/subrange.cfa
===================================================================
--- tests/zombies/subrange.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/subrange.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,63 @@
+// A small context defining the notion of an ordered otype.  (The standard
+// library should probably contain a context for this purpose.)
+trait ordered(otype T) {
+    int ?<?(T, T), ?<=?(T, T);
+};
+
+// A subrange otype resembling an Ada subotype with a base otype and a range
+// constraint.
+otype subrange(otype base_t | ordered(base_t), base_t low = 0, base_t high = 8) = base_t;
+
+// Note that subrange() can be applied to floating-point and pointer otypes, not
+// just integral otypes.
+//   This requires a "otype generator" extension to Cforall.  Type generators
+// must accept otype and non-otype parameters, which is beyond what we discussed
+// previously.  Type parameters must be usable in the declaration of
+// subsequent parameters: parameter T is used to declare parameters "low"
+// and "high".
+
+// Example usage:
+subrange(unsigned, 1, 31) day_of_month;
+subrange(char, 'a', 'z')  lcase;
+subrange(int, 0, (rand() & 0xF) ) foo;
+
+// What sorts of expressions can be used as arguments of otype generators?  Is
+// "subrange(int, 0, rand() & 0xF)" legal?  Probably.  The nearest C equivalent
+// to the "low" and "high" arguments is the array size in a variable-length
+// array declaration, and C allows assignment expressions there.
+
+// Convenient access to subrange bounds, for instance for iteration:
+forall (otype T, T low, T high)
+T lbound( subrange(T, low, high) v) {
+    return low;
+}
+
+forall (otype T, T low, T high)
+T hbound( subrange(T, low, high) v) {
+    return high;
+}
+
+// Example usage:
+unsigned lday = lbound(day_of_month);
+
+// Assignment from the base otype, with bounds checking.  I'll ignore the issue
+// of exception handling here.  Inlining allows the compiler to eliminate
+// bounds checks.
+forall (otype T | ordered(T), T low, T high)
+inline subrange(T, low, high) ?=?(subrange(T, low, high)* target, T source) {
+    if (low <= source && source <= high) *((T*)target) = source;
+    else abort();
+    return target;
+}
+
+// Assignment between subranges with a common base otype.  The bounds check
+// compares range bounds so that the compiler can optimize checks away when the
+// ranges are known to overlap.
+forall (otype T | ordered(T), T t_low, T t_high, T s_low, T s_high)
+inline subrange(T, t_low, t_high) ?=?(subrange(T, t_low, t_high)* target,
+				      subrange(T, s_low, s_high) source) {
+    if ( (t_low <= s_low || t_low <= source)
+	 && (s_high <= t_high || source <= t_high) ) *((T*)target) = source;
+    else abort();
+    return target;
+}
Index: tests/zombies/typeGenerator.cfa
===================================================================
--- tests/zombies/typeGenerator.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/typeGenerator.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,30 @@
+context addable( otype T ) {
+	T ?+?( T,T );
+	T ?=?( T*, T);
+};
+
+otype List1( otype T | addable( T ) ) = struct { T data; List1( T ) *next; } *;
+typedef List1( int ) ListOfIntegers;
+//List1( int ) li;
+ListOfIntegers li;
+int f( List1( int ) ( (*g ))( int ) );
+[int] h( * List1( int ) p );							// new declaration syntax
+
+struct( otype T ) S2 { T i; };							// actual definition
+struct( int ) S3 v1, *p;								// expansion and instantiation
+struct( otype T )( int ) S24 { T i; } v2;				// actual definition, expansion and instantiation
+struct( otype T )( int ) { T i; } v2;					// anonymous actual definition, expansion and instantiation
+
+struct( otype T | addable( T ) ) node { T data; struct( T ) node *next; };
+otype List( otype T ) = struct( T ) node *;
+List( int ) my_list;
+
+otype Complex | addable( Complex );
+
+int main() {
+	(struct( int ) node)my_list;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/zombies/typedef.cfa
===================================================================
--- tests/zombies/typedef.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/typedef.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,47 @@
+typedef int T;
+
+void f( void ) {
+    int T( T p ) { return 3; }
+    T( 3 );
+}
+
+struct {
+    T (T);
+} fred = { 3 };
+
+typedef int (*a)(int, char);
+a b;
+
+int g(void) {
+    double a;
+}
+a c;
+
+typedef typeof(3) x, y;  // GCC
+
+x p;
+y q;
+
+int main() {
+    typedef typeof(3) z, p;
+    z w;
+    p x;
+}
+
+// new-style function definitions
+
+typedef [10] * int arrayOf10Pointers;
+arrayOf10Pointers array;
+typedef const * int constantPointer;
+typedef * [ int ]( [] int ) funcPtr;
+typedef [ int ] funcProto( []  int );
+typedef [ int, int ] tupleType;
+typedef * [ int, int ] tupleTypePtr;
+typedef * int c, d;
+typedef [ int ] f( * int ), g;
+typedef [ * [static 10] int ] t;
+typedef [ * [static 10] int x ] h();
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/zombies/typedefDeclarator.cfa
===================================================================
--- tests/zombies/typedefDeclarator.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/typedefDeclarator.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,120 @@
+typedef int
+	 f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,  f8,  f9,
+	f10, f11, f12, f13, f14, f15, f16, f17, f18, f19,
+	f20, f21, f22, f23, f24, f25, f26, f27, f28, f29,
+	f30, f31, f32, f33, f34, f35, f36, f37, f38, f39,
+	f40, f41, f42, f43, f44, f45, f46, f47, f48, f49,
+	f50, f51, f52, f53, f54, f55, f56, f57, f58, f59,
+	f60, f61, f62, f63, f64, f65, f66, f67, f68, f69,
+	f70, f71, f72, f73, f74, f75, f76, f77, f78, f79,
+	f80, f81, f82, f83, f84, f85, f86, f87, f88, f89;
+
+int main() {
+	//int f0[]();
+	//int (f0[])();
+	//int f0()[];
+	//int f0()();
+	//int (*f0)()();
+	//int ((*f0())())[];
+	
+	int f1;
+	int (f2);
+
+	int *f3;
+	int **f4;
+	int * const *f5;
+	int * const * const f6;
+
+	int *(f7);
+	int **(f8);
+	int * const *(f9);
+	int * const * const (f10);
+
+	int (*f11);
+	int (**f12);
+	int (* const *f13);
+	int (* const * const f14);
+
+	int f15[];
+	int f16[10];
+	int (f17[]);
+	int (f18[10]);
+
+	int *f19[];
+	int *f20[10];
+	int **f21[];
+	int **f22[10];
+	int * const *f23[];
+	int * const *f24[10];
+	int * const * const f25[];
+	int * const * const f26[10];
+
+	int *(f27[]);
+	int *(f28[10]);
+	int **(f29[]);
+	int **(f30[10]);
+	int * const *(f31[]);
+	int * const *(f32[10]);
+	int * const * const (f33[]);
+	int * const * const (f34[10]);
+
+	int (*f35[]);
+	int (*f36[10]);
+	int (**f37[]);
+	int (**f38[10]);
+	int (* const *f39[]);
+	int (* const *f40[10]);
+	int (* const * const f41[]);
+	int (* const * const f42[10]);
+
+	int f43[][3];
+	int f44[3][3];
+	int (f45[])[3];
+	int (f46[3])[3];
+	int ((f47[]))[3];
+	int ((f48[3]))[3];
+
+	int *f49[][3];
+	int *f50[3][3];
+	int **f51[][3];
+	int **f52[3][3];
+	int * const *f53[][3];
+	int * const *f54[3][3];
+	int * const * const f55[][3];
+	int * const * const f56[3][3];
+
+	int (*f57[][3]);
+	int (*f58[3][3]);
+	int (**f59[][3]);
+	int (**f60[3][3]);
+	int (* const *f61[][3]);
+	int (* const *f62[3][3]);
+	int (* const * const f63[][3]);
+	int (* const * const f64[3][3]);
+
+	int f65(int);
+	int (f66)(int);
+
+	int *f67(int);
+	int **f68(int);
+	int * const *f69(int);
+	int * const * const f70(int);
+
+	int *(f71)(int);
+	int **(f72)(int);
+	int * const *(f73)(int);
+	int * const * const (f74)(int);
+
+	int (*f75)(int);
+	int (**f76)(int);
+	int (* const *f77)(int);
+	int (* const * const f78)(int);
+
+	int (*(*f79)(int))();
+	int (*(* const f80)(int))();
+	int (* const(* const f81)(int))();
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: tests/zombies/virtualCast.cfa
===================================================================
--- tests/zombies/virtualCast.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/virtualCast.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,76 @@
+// Testing the virtual cast, as part of strict inheritance.
+
+/* IMPORTANT: This test does not repersent the final feature set.
+ * We are missing a number of important aspects such as:
+ * + vtable type generation.
+ * + vtable instance generation, that might use different resolution rules.
+ * + Virtual syntax to force said generation on structures and traits.
+ * + Trait references/pointers that do the virtual_table lookup.
+ */
+
+#include <stdlib.hfa>
+#include <assert.h>
+
+struct alpha_vtable {
+	alpha_vtable const * const parent;
+	char (*code)(void);
+};
+
+struct alpha {
+	alpha_vtable const * virtual_table;
+};
+
+char ret_a(void) {
+	return 'a';
+}
+
+
+
+struct beta_vtable {
+	alpha_vtable const * const parent;
+	char (*code)(void);
+};
+
+struct beta {
+	beta_vtable const * virtual_table;
+};
+
+char ret_b(void) {
+	return 'b';
+}
+
+
+
+struct gamma_vtable {
+	beta_vtable const * const parent;
+	char (*code)(void);
+};
+
+struct gamma {
+	gamma_vtable const * virtual_table;
+};
+
+char ret_g(void) {
+	return 'g';
+}
+
+
+extern "C" {
+	alpha_vtable _alpha_vtable_instance = { 0, ret_a };
+	beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
+	gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
+}
+
+int main (int argc, char * argv[]) {
+
+	gamma * tri = malloc(); tri->virtual_table = &_gamma_vtable_instance;
+	beta * mid = (virtual beta *)tri;
+	assert( 'g' == mid->virtual_table->code() );
+
+	alpha * top = malloc(); top->virtual_table = &_alpha_vtable_instance;
+	mid = (virtual beta *)top;
+	assert( ! mid );
+
+	free(tri);
+	free(top);
+}
Index: tests/zombies/withStatement.cfa
===================================================================
--- tests/zombies/withStatement.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
+++ tests/zombies/withStatement.cfa	(revision a50502128f8eabae54ded84a8ab9885411aad583)
@@ -0,0 +1,109 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleFunction.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Mon Dec 04 17:41:45 2017
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Dec 24 19:08:18 2018
+// Update Count     : 5
+//
+
+#include <fstream.hfa>
+
+struct S {
+	int i;
+	// dynamically allocated member ensures ctor/dtors are called correctly on temporaries
+	int * ptr;
+};
+
+// with clause on reference parameter
+void ?{}( S & this, int n ) with( this ) {
+	i = n;
+	ptr = (int *)malloc( sizeof(int) );
+}
+
+void ?{}( S & this ) {
+	this{ 0 };
+}
+
+void ?{}( S & this, S other ) {
+	this{ other.i };
+}
+
+S ?=?( S & this, S other ) with( this ) {
+	i = other.i;
+	*ptr = *other.ptr;
+	return this;
+}
+
+void ^?{}( S & this ) with( this ) {
+	free( ptr );
+}
+
+struct S2 {
+	S s;
+};
+
+void ?{}( S2 & this, int n ) {
+	(this.s){ n };
+}
+
+forall( otype T )
+struct Box {
+	T x;
+};
+
+forall( otype T )
+void ?{}( Box(T) & this ) with( this ) { // with clause in polymorphic function
+	x{};
+}
+
+void print( int i ) { sout | i; }
+
+forall( otype T | { void print( T ); })
+void foo( T t ) {
+	Box( T ) b = { t };
+	with( b ) {  // with statement in polymorphic function
+		print( x );
+	}
+}
+
+// ensure with-statement temporary generation works correctly
+S mk() {
+	sout | "called mk";
+	return (S){ 444 };
+}
+
+// ensure with-statement temporary generation with reference-returning functions works correctly
+S & ref() {
+	static S var = { 123456789 };
+	return var;
+}
+
+int main() {
+	S2 s2 = { 12345 };
+	with ( s2) {
+		with( s ) { // with s2.s
+			sout | i | s.i | s2.s.i;
+			foo( i );  // s.i
+			with( mk()) {
+				sout | i | i | i;
+				with( ref()) {
+					sout | i | i | i;
+				} // with ref()
+				with( ref()) {
+					sout | i | i | i;
+				} // with ref()
+			} // with mk()
+		} // with s
+	} // with s2
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
