diff --git a/ghc-tests/bronze/CompareAndSwap.out b/ghc-tests/bronze/CompareAndSwap.out
new file mode 100644
index 0000000000000000000000000000000000000000..6572566ea6426a5c74961fde4195bd783b213602
--- /dev/null
+++ b/ghc-tests/bronze/CompareAndSwap.out
@@ -0,0 +1,11 @@
+ret > ExitSuccess
+out > Perform a CAS within an IORef
+out >   1st try should succeed: (True,44)
+out >   2nd should fail: (False,44)
+out > Perform a CAS within a MutableArray#
+out >   1st try should succeed: (True,44)
+out >   2nd should fail: (False,44)
+out > Printing array:
+out >   33  33  33  44  33
+out > Done.
+out >
diff --git a/ghc-tests/bronze/CopySmallArrayStressTest.out b/ghc-tests/bronze/CopySmallArrayStressTest.out
new file mode 100644
index 0000000000000000000000000000000000000000..53b0591fe8e0ed5affd2870faa172aac75b1be8f
--- /dev/null
+++ b/ghc-tests/bronze/CopySmallArrayStressTest.out
@@ -0,0 +1,4 @@
+ret > ExitSuccess
+out > test_copyMutableArray: OK
+out > test_cloneMutableArray: OK
+out >
diff --git a/ghc-tests/bronze/Drvrun022.out b/ghc-tests/bronze/Drvrun022.out
new file mode 100644
index 0000000000000000000000000000000000000000..d0aef3483c1d5d9e003acc3f86c8edcae1aaba14
--- /dev/null
+++ b/ghc-tests/bronze/Drvrun022.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > ["testz"]
+out >
diff --git a/ghc-tests/bronze/FFI009.out b/ghc-tests/bronze/FFI009.out
new file mode 100644
index 0000000000000000000000000000000000000000..af55e201498b179f6fda169c9ade6ebf0a75e2b2
--- /dev/null
+++ b/ghc-tests/bronze/FFI009.out
@@ -0,0 +1,167 @@
+ret > ExitSuccess
+out > Testing 5 Int arguments...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing 11 Double arguments...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing 11 mixed arguments...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 1st argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 2nd argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 3rd argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 4th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 5th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 6th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 7th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 8th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 9th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 10th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 11th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > Testing Double as 12th argument, rest Int...
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out > True
+out >
diff --git a/ghc-tests/bronze/T14768.out b/ghc-tests/bronze/T14768.out
new file mode 100644
index 0000000000000000000000000000000000000000..9cc96eddc83f53695d9e58701cd70b2c9a11be2f
--- /dev/null
+++ b/ghc-tests/bronze/T14768.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > True
+out >
diff --git a/ghc-tests/bronze/T14854.out b/ghc-tests/bronze/T14854.out
new file mode 100644
index 0000000000000000000000000000000000000000..9cc96eddc83f53695d9e58701cd70b2c9a11be2f
--- /dev/null
+++ b/ghc-tests/bronze/T14854.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > True
+out >
diff --git a/ghc-tests/bronze/T15038.out b/ghc-tests/bronze/T15038.out
new file mode 100644
index 0000000000000000000000000000000000000000..139fa17797b282cf67a9eda00b5556aa23fd60c8
--- /dev/null
+++ b/ghc-tests/bronze/T15038.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > 5
+out >
diff --git a/ghc-tests/bronze/T3087.out b/ghc-tests/bronze/T3087.out
new file mode 100644
index 0000000000000000000000000000000000000000..ac3829ed078aa7582a045aaf9bb55799c06e733a
--- /dev/null
+++ b/ghc-tests/bronze/T3087.out
@@ -0,0 +1,6 @@
+ret > ExitSuccess
+out > ()
+out > ()
+out > ()
+out > ()
+out >
diff --git a/ghc-tests/bronze/T367.out b/ghc-tests/bronze/T367.out
new file mode 100644
index 0000000000000000000000000000000000000000..e919a3a9972b881ebb79139fb2f3a9ce7b414131
--- /dev/null
+++ b/ghc-tests/bronze/T367.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > Done
+out >
diff --git a/ghc-tests/bronze/T367A.out b/ghc-tests/bronze/T367A.out
new file mode 100644
index 0000000000000000000000000000000000000000..3a2be73f7720903e2abcc654aa1026fcb014482e
--- /dev/null
+++ b/ghc-tests/bronze/T367A.out
@@ -0,0 +1,5 @@
+ret > ExitSuccess
+out > About to fork
+out > Why is this never printed?!
+out > Done
+out >
diff --git a/ghc-tests/bronze/T7953.out b/ghc-tests/bronze/T7953.out
new file mode 100644
index 0000000000000000000000000000000000000000..5e98ef6c1b5a6d73a52b39f9f24d13aba45e8509
--- /dev/null
+++ b/ghc-tests/bronze/T7953.out
@@ -0,0 +1,7 @@
+ret > ExitSuccess
+out > Winner (E {_key = 1, prio = 500.0}) (Fork (E {_key = 2, prio = 400.0}) Start (Fork (E {_key = 3, prio = 300.0}) Start (Fork (E {_key = 4, prio = 200.0}) Start (Fork (E {_key = 5, prio = 100.0}) Start (Fork (E {_key = 6, prio = 0.0}) Start (Fork (E {_key = 7, prio = -100.0}) Start (Fork (E {_key = 8, prio = -200.0}) Start (Fork (E {_key = 9, prio = -300.0}) Start (Fork (E {_key = 10, prio = -400.0}) Start (Fork (E {_key = 11, prio = -500.0}) Start (Fork (E {_key = 12, prio = -600.0}) Start (Fork (E {_key = 13, prio = -700.0}) Start (Fork (E {_key = 14, prio = -800.0}) Start (Fork (E {_key = 15, prio = -900.0}) Start (Fork (E {_key = 16, prio = -1000.0}) Start (Fork (E {_key = 17, prio = -1100.0}) Start (Fork (E {_key = 18, prio = -1200.0}) Start (Fork (E {_key = 19, prio = -1300.0}) Start (Fork (E {_key = 20, prio = -1400.0}) Start (Fork (E {_key = 21, prio = -1500.0}) Start (Fork (E {_key = 22, prio = -1600.0}) Start (Fork (E {_key = 23, prio = -1700.0}) Start (Fork (E {_key = 24, prio = -1800.0}) Start (Fork (E {_key = 25, prio = -1900.0}) Start (Fork (E {_key = 26, prio = -2000.0}) Start (Fork (E {_key = 27, prio = -2100.0}) Start (Fork (E {_key = 28, prio = -2200.0}) Start (Fork (E {_key = 29, prio = -2300.0}) Start (Fork (E {_key = 30, prio = -2400.0}) Start (Fork (E {_key = 31, prio = -2500.0}) Start (Fork (E {_key = 32, prio = -2600.0}) Start (Fork (E {_key = 33, prio = -2700.0}) Start (Fork (E {_key = 34, prio = -2800.0}) Start (Fork (E {_key = 35, prio = -2900.0}) Start (Fork (E {_key = 36, prio = -3000.0}) Start (Fork (E {_key = 37, prio = -3100.0}) Start (Fork (E {_key = 38, prio = -3200.0}) Start (Fork (E {_key = 39, prio = -3300.0}) Start (Fork (E {_key = 40, prio = -3400.0}) Start (Fork (E {_key = 41, prio = -3500.0}) Start (Fork (E {_key = 42, prio = -3600.0}) Start (Fork (E {_key = 43, prio = -3700.0}) Start (Fork (E {_key = 44, prio = -3800.0}) Start (Fork (E {_key = 45, prio = -3900.0}) Start (Fork (E {_key = 46, prio = -4000.0}) Start (Fork (E {_key = 47, prio = -4100.0}) Start (Fork (E {_key = 48, prio = -4200.0}) Start (Fork (E {_key = 49, prio = -4300.0}) Start (Fork (E {_key = 50, prio = -4400.0}) Start (Fork (E {_key = 51, prio = -4500.0}) Start (Fork (E {_key = 52, prio = -4600.0}) Start (Fork (E {_key = 53, prio = -4700.0}) Start (Fork (E {_key = 54, prio = -4800.0}) Start (Fork (E {_key = 55, prio = -4900.0}) Start (Fork (E {_key = 56, prio = -5000.0}) Start (Fork (E {_key = 57, prio = -5100.0}) Start (Fork (E {_key = 58, prio = -5200.0}) Start (Fork (E {_key = 59, prio = -5300.0}) Start (Fork (E {_key = 60, prio = -5400.0}) Start (Fork (E {_key = 61, prio = -5500.0}) Start (Fork (E {_key = 62, prio = -5600.0}) Start (Fork (E {_key = 63, prio = -5700.0}) Start (Fork (E {_key = 64, prio = -5800.0}) Start (Fork (E {_key = 65, prio = -5900.0}) Start (Fork (E {_key = 66, prio = -6000.0}) Start (Fork (E {_key = 67, prio = -6100.0}) Start (Fork (E {_key = 68, prio = -6200.0}) Start (Fork (E {_key = 69, prio = -6300.0}) Start (Fork (E {_key = 70, prio = -6400.0}) Start (Fork (E {_key = 71, prio = -6500.0}) Start (Fork (E {_key = 72, prio = -6600.0}) Start (Fork (E {_key = 73, prio = -6700.0}) Start (Fork (E {_key = 74, prio = -6800.0}) Start (Fork (E {_key = 75, prio = -6900.0}) Start (Fork (E {_key = 76, prio = -7000.0}) Start (Fork (E {_key = 77, prio = -7100.0}) Start (Fork (E {_key = 78, prio = -7200.0}) Start (Fork (E {_key = 79, prio = -7300.0}) Start (Fork (E {_key = 80, prio = -7400.0}) Start (Fork (E {_key = 81, prio = -7500.0}) Start (Fork (E {_key = 82, prio = -7600.0}) Start (Fork (E {_key = 83, prio = -7700.0}) Start (Fork (E {_key = 84, prio = -7800.0}) Start (Fork (E {_key = 85, prio = -7900.0}) Start (Fork (E {_key = 86, prio = -8000.0}) Start (Fork (E {_key = 87, prio = -8100.0}) Start (Fork (E {_key = 88, prio = -8200.0}) Start (Fork (E {_key = 89, prio = -8300.0}) Start (Fork (E {_key = 90, prio = -8400.0}) Start (Fork (E {_key = 91, prio = -8500.0}) Start (Fork (E {_key = 92, prio = -8600.0}) Start (Fork (E {_key = 93, prio = -8700.0}) Start (Fork (E {_key = 94, prio = -8800.0}) Start (Fork (E {_key = 95, prio = -8900.0}) Start (Fork (E {_key = 96, prio = -9000.0}) Start (Fork (E {_key = 97, prio = -9100.0}) Start (Fork (E {_key = 98, prio = -9200.0}) Start (Fork (E {_key = 99, prio = -9300.0}) Start (Fork (E {_key = 100, prio = -9400.0}) Start (Fork (E {_key = 101, prio = -9500.0}) Start (Fork (E {_key = 102, prio = -9600.0}) Start (Fork (E {_key = 103, prio = -9700.0}) Start (Fork (E {_key = 104, prio = -9800.0}) Start (Fork (E {_key = 105, prio = -9900.0}) Start (Fork (E {_key = 106, prio = -10000.0}) Start (Fork (E {_key = 107, prio = -10100.0}) Start (Fork (E {_key = 108, prio = -10200.0}) Start (Fork (E {_key = 109, prio = -10300.0}) Start (Fork (E {_key = 110, prio = -10400.0}) Start (Fork (E {_key = 111, prio = -10500.0}) Start (Fork (E {_key = 112, prio = -10600.0}) Start (Fork (E {_key = 113, prio = -10700.0}) Start (Fork (E {_key = 114, prio = -10800.0}) Start (Fork (E {_key = 115, prio = -10900.0}) Start (Fork (E {_key = 116, prio = -11000.0}) Start (Fork (E {_key = 117, prio = -11100.0}) Start (Fork (E {_key = 118, prio = -11200.0}) Start (Fork (E {_key = 119, prio = -11300.0}) Start (Fork (E {_key = 120, prio = -11400.0}) Start (Fork (E {_key = 121, prio = -11500.0}) Start (Fork (E {_key = 122, prio = -11600.0}) Start (Fork (E {_key = 123, prio = -11700.0}) Start (Fork (E {_key = 124, prio = -11800.0}) Start (Fork (E {_key = 125, prio = -11900.0}) Start (Fork (E {_key = 126, prio = -12000.0}) Start (Fork (E {_key = 127, prio = -12100.0}) Start (Fork (E {_key = 128, prio = -12200.0}) Start (Fork (E {_key = 129, prio = -12300.0}) Start (Fork (E {_key = 130, prio = -12400.0}) Start (Fork (E {_key = 131, prio = -12500.0}) Start (Fork (E {_key = 132, prio = -12600.0}) Start (Fork (E {_key = 133, prio = -12700.0}) Start (Fork (E {_key = 134, prio = -12800.0}) Start (Fork (E {_key = 135, prio = -12900.0}) Start (Fork (E {_key = 136, prio = -13000.0}) Start (Fork (E {_key = 137, prio = -13100.0}) Start (Fork (E {_key = 138, prio = -13200.0}) Start (Fork (E {_key = 139, prio = -13300.0}) Start (Fork (E {_key = 140, prio = -13400.0}) Start (Fork (E {_key = 141, prio = -13500.0}) Start (Fork (E {_key = 142, prio = -13600.0}) Start (Fork (E {_key = 143, prio = -13700.0}) Start (Fork (E {_key = 144, prio = -13800.0}) Start (Fork (E {_key = 145, prio = -13900.0}) Start (Fork (E {_key = 146, prio = -14000.0}) Start (Fork (E {_key = 147, prio = -14100.0}) Start (Fork (E {_key = 148, prio = -14200.0}) Start (Fork (E {_key = 149, prio = -14300.0}) Start (Fork (E {_key = 150, prio = -14400.0}) Start (Fork (E {_key = 151, prio = -14500.0}) Start (Fork (E {_key = 152, prio = -14600.0}) Start (Fork (E {_key = 153, prio = -14700.0}) Start (Fork (E {_key = 154, prio = -14800.0}) Start (Fork (E {_key = 155, prio = -14900.0}) Start (Fork (E {_key = 156, prio = -15000.0}) Start (Fork (E {_key = 157, prio = -15100.0}) Start (Fork (E {_key = 158, prio = -15200.0}) Start (Fork (E {_key = 159, prio = -15300.0}) Start (Fork (E {_key = 160, prio = -15400.0}) Start (Fork (E {_key = 161, prio = -15500.0}) Start (Fork (E {_key = 162, prio = -15600.0}) Start (Fork (E {_key = 163, prio = -15700.0}) Start (Fork (E {_key = 164, prio = -15800.0}) Start (Fork (E {_key = 165, prio = -15900.0}) Start (Fork (E {_key = 166, prio = -16000.0}) Start (Fork (E {_key = 167, prio = -16100.0}) Start (Fork (E {_key = 168, prio = -16200.0}) Start (Fork (E {_key = 169, prio = -16300.0}) Start (Fork (E {_key = 170, prio = -16400.0}) Start (Fork (E {_key = 171, prio = -16500.0}) Start (Fork (E {_key = 172, prio = -16600.0}) Start (Fork (E {_key = 173, prio = -16700.0}) Start (Fork (E {_key = 174, prio = -16800.0}) Start (Fork (E {_key = 175, prio = -16900.0}) Start (Fork (E {_key = 176, prio = -17000.0}) Start (Fork (E {_key = 177, prio = -17100.0}) Start (Fork (E {_key = 178, prio = -17200.0}) Start (Fork (E {_key = 179, prio = -17300.0}) Start (Fork (E {_key = 180, prio = -17400.0}) Start (Fork (E {_key = 181, prio = -17500.0}) Start (Fork (E {_key = 182, prio = -17600.0}) Start (Fork (E {_key = 183, prio = -17700.0}) Start (Fork (E {_key = 184, prio = -17800.0}) Start (Fork (E {_key = 185, prio = -17900.0}) Start (Fork (E {_key = 186, prio = -18000.0}) Start (Fork (E {_key = 187, prio = -18100.0}) Start (Fork (E {_key = 188, prio = -18200.0}) Start (Fork (E {_key = 189, prio = -18300.0}) Start (Fork (E {_key = 190, prio = -18400.0}) Start (Fork (E {_key = 191, prio = -18500.0}) Start (Fork (E {_key = 192, prio = -18600.0}) Start (Fork (E {_key = 193, prio = -18700.0}) Start (Fork (E {_key = 194, prio = -18800.0}) Start (Fork (E {_key = 195, prio = -18900.0}) Start (Fork (E {_key = 196, prio = -19000.0}) Start (Fork (E {_key = 197, prio = -19100.0}) Start (Fork (E {_key = 198, prio = -19200.0}) Start (Fork (E {_key = 199, prio = -19300.0}) Start (Fork (E {_key = 200, prio = -19400.0}) Start Start)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+out > Before atMost
+out > []
+out > Winner (E {_key = 1, prio = 500.0}) (Fork (E {_key = 2, prio = 400.0}) Start (Fork (E {_key = 3, prio = 300.0}) Start (Fork (E {_key = 4, prio = 200.0}) Start (Fork (E {_key = 5, prio = 100.0}) Start (Fork (E {_key = 6, prio = 0.0}) Start (Fork (E {_key = 7, prio = -100.0}) Start (Fork (E {_key = 8, prio = -200.0}) Start (Fork (E {_key = 9, prio = -300.0}) Start (Fork (E {_key = 10, prio = -400.0}) Start (Fork (E {_key = 11, prio = -500.0}) Start (Fork (E {_key = 12, prio = -600.0}) Start (Fork (E {_key = 13, prio = -700.0}) Start (Fork (E {_key = 14, prio = -800.0}) Start (Fork (E {_key = 15, prio = -900.0}) Start (Fork (E {_key = 16, prio = -1000.0}) Start (Fork (E {_key = 17, prio = -1100.0}) Start (Fork (E {_key = 18, prio = -1200.0}) Start (Fork (E {_key = 19, prio = -1300.0}) Start (Fork (E {_key = 20, prio = -1400.0}) Start (Fork (E {_key = 21, prio = -1500.0}) Start (Fork (E {_key = 22, prio = -1600.0}) Start (Fork (E {_key = 23, prio = -1700.0}) Start (Fork (E {_key = 24, prio = -1800.0}) Start (Fork (E {_key = 25, prio = -1900.0}) Start (Fork (E {_key = 26, prio = -2000.0}) Start (Fork (E {_key = 27, prio = -2100.0}) Start (Fork (E {_key = 28, prio = -2200.0}) Start (Fork (E {_key = 29, prio = -2300.0}) Start (Fork (E {_key = 30, prio = -2400.0}) Start (Fork (E {_key = 31, prio = -2500.0}) Start (Fork (E {_key = 32, prio = -2600.0}) Start (Fork (E {_key = 33, prio = -2700.0}) Start (Fork (E {_key = 34, prio = -2800.0}) Start (Fork (E {_key = 35, prio = -2900.0}) Start (Fork (E {_key = 36, prio = -3000.0}) Start (Fork (E {_key = 37, prio = -3100.0}) Start (Fork (E {_key = 38, prio = -3200.0}) Start (Fork (E {_key = 39, prio = -3300.0}) Start (Fork (E {_key = 40, prio = -3400.0}) Start (Fork (E {_key = 41, prio = -3500.0}) Start (Fork (E {_key = 42, prio = -3600.0}) Start (Fork (E {_key = 43, prio = -3700.0}) Start (Fork (E {_key = 44, prio = -3800.0}) Start (Fork (E {_key = 45, prio = -3900.0}) Start (Fork (E {_key = 46, prio = -4000.0}) Start (Fork (E {_key = 47, prio = -4100.0}) Start (Fork (E {_key = 48, prio = -4200.0}) Start (Fork (E {_key = 49, prio = -4300.0}) Start (Fork (E {_key = 50, prio = -4400.0}) Start (Fork (E {_key = 51, prio = -4500.0}) Start (Fork (E {_key = 52, prio = -4600.0}) Start (Fork (E {_key = 53, prio = -4700.0}) Start (Fork (E {_key = 54, prio = -4800.0}) Start (Fork (E {_key = 55, prio = -4900.0}) Start (Fork (E {_key = 56, prio = -5000.0}) Start (Fork (E {_key = 57, prio = -5100.0}) Start (Fork (E {_key = 58, prio = -5200.0}) Start (Fork (E {_key = 59, prio = -5300.0}) Start (Fork (E {_key = 60, prio = -5400.0}) Start (Fork (E {_key = 61, prio = -5500.0}) Start (Fork (E {_key = 62, prio = -5600.0}) Start (Fork (E {_key = 63, prio = -5700.0}) Start (Fork (E {_key = 64, prio = -5800.0}) Start (Fork (E {_key = 65, prio = -5900.0}) Start (Fork (E {_key = 66, prio = -6000.0}) Start (Fork (E {_key = 67, prio = -6100.0}) Start (Fork (E {_key = 68, prio = -6200.0}) Start (Fork (E {_key = 69, prio = -6300.0}) Start (Fork (E {_key = 70, prio = -6400.0}) Start (Fork (E {_key = 71, prio = -6500.0}) Start (Fork (E {_key = 72, prio = -6600.0}) Start (Fork (E {_key = 73, prio = -6700.0}) Start (Fork (E {_key = 74, prio = -6800.0}) Start (Fork (E {_key = 75, prio = -6900.0}) Start (Fork (E {_key = 76, prio = -7000.0}) Start (Fork (E {_key = 77, prio = -7100.0}) Start (Fork (E {_key = 78, prio = -7200.0}) Start (Fork (E {_key = 79, prio = -7300.0}) Start (Fork (E {_key = 80, prio = -7400.0}) Start (Fork (E {_key = 81, prio = -7500.0}) Start (Fork (E {_key = 82, prio = -7600.0}) Start (Fork (E {_key = 83, prio = -7700.0}) Start (Fork (E {_key = 84, prio = -7800.0}) Start (Fork (E {_key = 85, prio = -7900.0}) Start (Fork (E {_key = 86, prio = -8000.0}) Start (Fork (E {_key = 87, prio = -8100.0}) Start (Fork (E {_key = 88, prio = -8200.0}) Start (Fork (E {_key = 89, prio = -8300.0}) Start (Fork (E {_key = 90, prio = -8400.0}) Start (Fork (E {_key = 91, prio = -8500.0}) Start (Fork (E {_key = 92, prio = -8600.0}) Start (Fork (E {_key = 93, prio = -8700.0}) Start (Fork (E {_key = 94, prio = -8800.0}) Start (Fork (E {_key = 95, prio = -8900.0}) Start (Fork (E {_key = 96, prio = -9000.0}) Start (Fork (E {_key = 97, prio = -9100.0}) Start (Fork (E {_key = 98, prio = -9200.0}) Start (Fork (E {_key = 99, prio = -9300.0}) Start (Fork (E {_key = 100, prio = -9400.0}) Start (Fork (E {_key = 101, prio = -9500.0}) Start (Fork (E {_key = 102, prio = -9600.0}) Start (Fork (E {_key = 103, prio = -9700.0}) Start (Fork (E {_key = 104, prio = -9800.0}) Start (Fork (E {_key = 105, prio = -9900.0}) Start (Fork (E {_key = 106, prio = -10000.0}) Start (Fork (E {_key = 107, prio = -10100.0}) Start (Fork (E {_key = 108, prio = -10200.0}) Start (Fork (E {_key = 109, prio = -10300.0}) Start (Fork (E {_key = 110, prio = -10400.0}) Start (Fork (E {_key = 111, prio = -10500.0}) Start (Fork (E {_key = 112, prio = -10600.0}) Start (Fork (E {_key = 113, prio = -10700.0}) Start (Fork (E {_key = 114, prio = -10800.0}) Start (Fork (E {_key = 115, prio = -10900.0}) Start (Fork (E {_key = 116, prio = -11000.0}) Start (Fork (E {_key = 117, prio = -11100.0}) Start (Fork (E {_key = 118, prio = -11200.0}) Start (Fork (E {_key = 119, prio = -11300.0}) Start (Fork (E {_key = 120, prio = -11400.0}) Start (Fork (E {_key = 121, prio = -11500.0}) Start (Fork (E {_key = 122, prio = -11600.0}) Start (Fork (E {_key = 123, prio = -11700.0}) Start (Fork (E {_key = 124, prio = -11800.0}) Start (Fork (E {_key = 125, prio = -11900.0}) Start (Fork (E {_key = 126, prio = -12000.0}) Start (Fork (E {_key = 127, prio = -12100.0}) Start (Fork (E {_key = 128, prio = -12200.0}) Start (Fork (E {_key = 129, prio = -12300.0}) Start (Fork (E {_key = 130, prio = -12400.0}) Start (Fork (E {_key = 131, prio = -12500.0}) Start (Fork (E {_key = 132, prio = -12600.0}) Start (Fork (E {_key = 133, prio = -12700.0}) Start (Fork (E {_key = 134, prio = -12800.0}) Start (Fork (E {_key = 135, prio = -12900.0}) Start (Fork (E {_key = 136, prio = -13000.0}) Start (Fork (E {_key = 137, prio = -13100.0}) Start (Fork (E {_key = 138, prio = -13200.0}) Start (Fork (E {_key = 139, prio = -13300.0}) Start (Fork (E {_key = 140, prio = -13400.0}) Start (Fork (E {_key = 141, prio = -13500.0}) Start (Fork (E {_key = 142, prio = -13600.0}) Start (Fork (E {_key = 143, prio = -13700.0}) Start (Fork (E {_key = 144, prio = -13800.0}) Start (Fork (E {_key = 145, prio = -13900.0}) Start (Fork (E {_key = 146, prio = -14000.0}) Start (Fork (E {_key = 147, prio = -14100.0}) Start (Fork (E {_key = 148, prio = -14200.0}) Start (Fork (E {_key = 149, prio = -14300.0}) Start (Fork (E {_key = 150, prio = -14400.0}) Start (Fork (E {_key = 151, prio = -14500.0}) Start (Fork (E {_key = 152, prio = -14600.0}) Start (Fork (E {_key = 153, prio = -14700.0}) Start (Fork (E {_key = 154, prio = -14800.0}) Start (Fork (E {_key = 155, prio = -14900.0}) Start (Fork (E {_key = 156, prio = -15000.0}) Start (Fork (E {_key = 157, prio = -15100.0}) Start (Fork (E {_key = 158, prio = -15200.0}) Start (Fork (E {_key = 159, prio = -15300.0}) Start (Fork (E {_key = 160, prio = -15400.0}) Start (Fork (E {_key = 161, prio = -15500.0}) Start (Fork (E {_key = 162, prio = -15600.0}) Start (Fork (E {_key = 163, prio = -15700.0}) Start (Fork (E {_key = 164, prio = -15800.0}) Start (Fork (E {_key = 165, prio = -15900.0}) Start (Fork (E {_key = 166, prio = -16000.0}) Start (Fork (E {_key = 167, prio = -16100.0}) Start (Fork (E {_key = 168, prio = -16200.0}) Start (Fork (E {_key = 169, prio = -16300.0}) Start (Fork (E {_key = 170, prio = -16400.0}) Start (Fork (E {_key = 171, prio = -16500.0}) Start (Fork (E {_key = 172, prio = -16600.0}) Start (Fork (E {_key = 173, prio = -16700.0}) Start (Fork (E {_key = 174, prio = -16800.0}) Start (Fork (E {_key = 175, prio = -16900.0}) Start (Fork (E {_key = 176, prio = -17000.0}) Start (Fork (E {_key = 177, prio = -17100.0}) Start (Fork (E {_key = 178, prio = -17200.0}) Start (Fork (E {_key = 179, prio = -17300.0}) Start (Fork (E {_key = 180, prio = -17400.0}) Start (Fork (E {_key = 181, prio = -17500.0}) Start (Fork (E {_key = 182, prio = -17600.0}) Start (Fork (E {_key = 183, prio = -17700.0}) Start (Fork (E {_key = 184, prio = -17800.0}) Start (Fork (E {_key = 185, prio = -17900.0}) Start (Fork (E {_key = 186, prio = -18000.0}) Start (Fork (E {_key = 187, prio = -18100.0}) Start (Fork (E {_key = 188, prio = -18200.0}) Start (Fork (E {_key = 189, prio = -18300.0}) Start (Fork (E {_key = 190, prio = -18400.0}) Start (Fork (E {_key = 191, prio = -18500.0}) Start (Fork (E {_key = 192, prio = -18600.0}) Start (Fork (E {_key = 193, prio = -18700.0}) Start (Fork (E {_key = 194, prio = -18800.0}) Start (Fork (E {_key = 195, prio = -18900.0}) Start (Fork (E {_key = 196, prio = -19000.0}) Start (Fork (E {_key = 197, prio = -19100.0}) Start (Fork (E {_key = 198, prio = -19200.0}) Start (Fork (E {_key = 199, prio = -19300.0}) Start (Fork (E {_key = 200, prio = -19400.0}) Start Start)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+out > After atMost
+out >
diff --git a/ghc-tests/bronze/T8138.out b/ghc-tests/bronze/T8138.out
new file mode 100644
index 0000000000000000000000000000000000000000..ebf6f77cd6d9b8a0e5837236bd4ff62c649c841c
--- /dev/null
+++ b/ghc-tests/bronze/T8138.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0]
+out >
diff --git a/ghc-tests/bronze/cgrun068.out b/ghc-tests/bronze/cgrun068.out
new file mode 100644
index 0000000000000000000000000000000000000000..53b0591fe8e0ed5affd2870faa172aac75b1be8f
--- /dev/null
+++ b/ghc-tests/bronze/cgrun068.out
@@ -0,0 +1,4 @@
+ret > ExitSuccess
+out > test_copyMutableArray: OK
+out > test_cloneMutableArray: OK
+out >
diff --git a/ghc-tests/bronze/concio002.out b/ghc-tests/bronze/concio002.out
new file mode 100644
index 0000000000000000000000000000000000000000..8c8a3a69e0b20c8341efca47e631ed77a394be7d
--- /dev/null
+++ b/ghc-tests/bronze/concio002.out
@@ -0,0 +1,6 @@
+ret > ExitSuccess
+out > parent1
+out > child
+out > msg
+out > parent2
+out >
diff --git a/ghc-tests/bronze/hClose003.out b/ghc-tests/bronze/hClose003.out
new file mode 100644
index 0000000000000000000000000000000000000000..292f228449bbafc8569b8cd3e2d804a5790653bb
--- /dev/null
+++ b/ghc-tests/bronze/hClose003.out
@@ -0,0 +1,6 @@
+ret > ExitSuccess
+out > Right ()
+out > False
+out > Left <file descriptor: X>: hClose: resource vanished (Broken pipe)
+out > False
+out >
diff --git a/ghc-tests/bronze/hwaitPipe.out b/ghc-tests/bronze/hwaitPipe.out
new file mode 100644
index 0000000000000000000000000000000000000000..babd3c29811f7ee5d3f17015b36ad133aacceb28
--- /dev/null
+++ b/ghc-tests/bronze/hwaitPipe.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > delta >= 0: True
+out >
diff --git a/ghc-tests/bronze/hwaitSocket.out b/ghc-tests/bronze/hwaitSocket.out
new file mode 100644
index 0000000000000000000000000000000000000000..babd3c29811f7ee5d3f17015b36ad133aacceb28
--- /dev/null
+++ b/ghc-tests/bronze/hwaitSocket.out
@@ -0,0 +1,3 @@
+ret > ExitSuccess
+out > delta >= 0: True
+out >
diff --git a/ghc-tests/bronze/rand001.out b/ghc-tests/bronze/rand001.out
new file mode 100644
index 0000000000000000000000000000000000000000..16cc8829d815f5f68254c0c371891b92801de2cd
--- /dev/null
+++ b/ghc-tests/bronze/rand001.out
@@ -0,0 +1,7 @@
+ret > ExitSuccess
+out > True
+out > True
+out > True
+out > True
+out > True
+out >
diff --git a/ghc-tests/ghc-tests.cabal b/ghc-tests/ghc-tests.cabal
index db7a4b09155dfacf7b612879661f35196db69367..aa7414878d1ae5011a6f9d1d7437d713ae25e910 100644
--- a/ghc-tests/ghc-tests.cabal
+++ b/ghc-tests/ghc-tests.cabal
@@ -23,12 +23,86 @@ extra-source-files: CHANGELOG.md
 
 test-suite ghc-tests
     type:       exitcode-stdio-1.0
-    build-depends: base, ghc, tasty
+    build-depends: base,
+       ghc,
+       tasty,
+       QuickCheck,
+       unix,
+       process,
+       random,
+       primitive,
+       containers,
+       regex-compat,
+       parallel,
+       vector,
+       syb,
+       stm,
+       transformers,
+       network,
+       utf8-string,
+       tasty-quickcheck,
+       tasty-silver,
+       text,
+       temporary,
+       array,
+       tasty-hunit,
+       ghc-prim,
+       directory,
+       filepath,
+       async,
+       bytestring,
+       time,
+       deepseq,
+
+       mtl
     main-is:          Main.hs
-    -- other-modules:
+    other-modules: Chan001
+                 , MVar001
+                 , HClose003
+                 , Concio002
+                 , Rand001
+                 , HWaitPipe
+                 , HWaitSocket
+                 , Arr016
+                 , Cgrun068
+                 , T7953
+                 , CopySmallArrayStressTest
+                 , T367
+                 , T367A
+                 , Throwto001
+                 , PerformGC
+                 , Conc023
+                 , CompareAndSwap
+                 , T13916
+                 , T13916_Bracket
+                 , T8138
+                 , Drvrun022
+                 , T3087
+                 , FFI009
+                 , T2267
+                 , T14768
+                 , TC191
+                 , TC220
+                 , T12926
+                 , T14854
+
+                 , MaessenHashtab.Data.HashTab
+                 , MaessenHashtab.HashTest
+
+                 , T15038.Main
+                 , T15038.Packed.Bytes
+                 , T15038.Packed.Bytes.Parser
+                 , T15038.Packed.Bytes.Stream.ST
+                 , T15038.Parser
+                 , T15038.Data.Trie.Naive
+
+                 , Tasty.Bronze
 
-    -- LANGUAGE extensions used by modules in this package.
-    -- other-extensions:
     build-depends:    base >=4.14.1.0 && <5
     hs-source-dirs:   tests
     default-language: Haskell2010
+    ghc-options: -threaded "-with-rtsopts=-qg -N" -O2 -dcore-lint
+
+    if arch(i386)
+      -- For reliable floating point results on i386
+      ghc-options: -msse2
diff --git a/ghc-tests/tests/Arr016.hs b/ghc-tests/tests/Arr016.hs
new file mode 100644
index 0000000000000000000000000000000000000000..c2848fbe5e5d582852688478126c2e3173dabfda
--- /dev/null
+++ b/ghc-tests/tests/Arr016.hs
@@ -0,0 +1,229 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Arr016 where
+
+{-
+ - This is a test framework for Arrays, using QuickCheck
+ -
+ -}
+
+import qualified Data.Array as Array
+import Control.Monad ( liftM2, liftM3, liftM4 )
+import System.Random
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+
+import Data.Ix
+import Data.List( (\\) )
+
+infixl 9  !, //
+
+prop_array =
+    forAll genBounds       $ \ (b :: (Int,Int))     ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)]) ->
+    Array.array b vs
+         `same_arr`
+    array b vs
+prop_listArray =
+    forAll genBounds       $ \ (b :: (Int,Int))     ->
+    forAll (vector (length [fst b..snd b]))
+                           $ \ (vs :: [Bool]) ->
+    Array.listArray b vs == Array.array b (zipWith (\ a b -> (a,b))
+                                                   (Array.range b) vs)
+
+prop_indices =
+    forAll genBounds       $ \ (b :: (Int,Int))     ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)]) ->
+    let arr = Array.array b vs
+    in Array.indices arr == ((Array.range . Array.bounds) arr)
+
+prop_elems =
+    forAll genBounds       $ \ (b :: (Int,Int))     ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)]) ->
+    let arr = Array.array b vs
+    in Array.elems arr == [arr Array.! i | i <- Array.indices arr]
+
+prop_assocs =
+    forAll genBounds       $ \ (b :: (Int,Int))     ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)]) ->
+    let arr = Array.array b vs
+    in Array.assocs arr == [(i, arr Array.! i) | i <- Array.indices arr]
+
+prop_slashslash =
+    forAll genBounds       $ \ (b :: (Int,Int))     ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)])  ->
+    let arr = Array.array b vs
+        us = []
+    in arr Array.// us == Array.array (Array.bounds arr)
+                          ([(i,arr Array.! i)
+                            | i <- Array.indices arr \\ [i | (i,_) <- us]]
+                             ++ us)
+prop_accum =
+    forAll genBounds          $ \ (b :: (Int,Int))    ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)]) ->
+
+    forAll (genIVPs b 10)     $ \ (us :: [(Int,Int)]) ->
+    forAll (choose (0,length us))
+                           $ \ n ->
+    let us' = take n us in
+    forAll arbitrary       $ \ (fn :: Int -> Int -> Int) ->
+    let arr = Array.array b vs
+    in Array.accum fn arr us'
+        == foldl (\a (i,v) -> a Array.// [(i,fn (a Array.! i) v)]) arr us'
+
+prop_accumArray =
+    forAll arbitrary          $ \ (f :: Int -> Int -> Int) ->
+    forAll arbitrary          $ \ (z :: Int) ->
+    forAll genBounds          $ \ (b :: (Int,Int))    ->
+    forAll (genIVPs b 10)     $ \ (vs :: [(Int,Int)]) ->
+    Array.accumArray f z b vs == Array.accum f
+                (Array.array b [(i,z) | i <- Array.range b]) vs
+
+
+same_arr :: (Eq b) => Array.Array Int b -> Array Int b -> Bool
+same_arr a1 a2 = a == c && b == d
+                 && all (\ n -> (a1 Array.! n) == (a2 ! n)) [a..b]
+    where (a,b) = Array.bounds a1 :: (Int,Int)
+          (c,d) = bounds a2 :: (Int,Int)
+
+genBounds :: Gen (Int,Int)
+genBounds = do m <- choose (0,20)
+               n <- choose (minBound,maxBound-m)
+               return (n,n+m-1)
+
+genIVP :: Arbitrary a => (Int,Int) -> Gen (Int,a)
+genIVP b = do { i <- choose b
+              ; v <- arbitrary
+              ; return (i,v)
+              }
+
+genIVPs :: Arbitrary a => (Int,Int) -> Int -> Gen [(Int,a)]
+genIVPs b@(low,high) s
+  = do { let is = [low..high]
+       ; vs <- vector (length is)
+       ; shuffleN s (zip is vs)
+       }
+
+shuffleN 0 xs = return xs
+shuffleN n xs = shuffle xs >>= shuffleN (n - 1)
+
+prop_id = forAll genBounds $ \ (b :: (Int,Int)) ->
+          forAll (genIVPs b 10) $ \ (ivps :: [(Int,Int)])  ->
+          label (show (ivps :: [(Int,Int)])) True
+
+-- rift takes a list, split it (using an Int argument),
+-- and then rifts together the split lists into one.
+-- Think: rifting a pack of cards.
+rift :: Int -> [a] -> [a]
+rift n xs = comb (drop n xs) (take n xs)
+   where
+      comb (a:as) (b:bs) = a : b : comb as bs
+      comb (a:as) []     = a : as
+      comb []     (b:bs) = b : bs
+      comb []     []     = []
+
+
+prop_shuffle =
+    forAll (shuffleN 10 [1..10::Int]) $ \ lst ->
+    label (show lst) True
+
+------------------------------------------------------------------------------
+
+arr016 :: TestTree
+arr016 = testGroup "arr016"
+  [ testProperty "array" prop_array
+  , testProperty "listArray" prop_listArray
+  , testProperty "indicies" prop_indices
+  , testProperty "elems" prop_elems
+  , testProperty "assocs" prop_assocs
+  , testProperty "slashslash" prop_slashslash
+  , testProperty "accum" prop_accum
+  , testProperty "accumArray" prop_accumArray ]
+
+
+instance Show (a -> b) where { show _ = "<FN>" }
+
+------------------------------------------------------------------------------
+
+data Array a b = MkArray (a,a) (a -> b) deriving ()
+
+array       :: (Ix a) => (a,a) -> [(a,b)] -> Array a b
+array b ivs =
+    if and [inRange b i | (i,_) <- ivs]
+        then MkArray b
+                     (\j -> case [v | (i,v) <- ivs, i == j] of
+                            [v]   -> v
+                            []    -> error "Array.!: \
+                                           \undefined array element"
+                            _     -> error "Array.!: \
+                                           \multiply defined array element")
+        else error "Array.array: out-of-range array association"
+
+listArray             :: (Ix a) => (a,a) -> [b] -> Array a b
+listArray b vs        =  array b (zipWith (\ a b -> (a,b)) (range b) vs)
+
+(!)                   :: (Ix a) => Array a b -> a -> b
+(!) (MkArray _ f)     =  f
+
+bounds                :: (Ix a) => Array a b -> (a,a)
+bounds (MkArray b _)  =  b
+
+indices               :: (Ix a) => Array a b -> [a]
+indices               =  range . bounds
+
+elems                 :: (Ix a) => Array a b -> [b]
+elems a               =  [a!i | i <- indices a]
+
+assocs                :: (Ix a) => Array a b -> [(a,b)]
+assocs a              =  [(i, a!i) | i <- indices a]
+
+(//)                  :: (Ix a) => Array a b -> [(a,b)] -> Array a b
+a // us               =  array (bounds a)
+                            ([(i,a!i) | i <- indices a \\ [i | (i,_) <- us]]
+                             ++ us)
+
+accum                 :: (Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]
+                                   -> Array a b
+accum f               =  foldl (\a (i,v) -> a // [(i,f (a!i) v)])
+
+accumArray            :: (Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]
+                                   -> Array a b
+accumArray f z b      =  accum f (array b [(i,z) | i <- range b])
+
+ixmap                 :: (Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c
+                                         -> Array a c
+ixmap b f a           = array b [(i, a ! f i) | i <- range b]
+
+instance  (Ix a)          => Functor (Array a) where
+    fmap fn (MkArray b f) =  MkArray b (fn . f)
+
+instance  (Ix a, Eq b)  => Eq (Array a b)  where
+    a == a'             =  assocs a == assocs a'
+
+instance  (Ix a, Ord b) => Ord (Array a b)  where
+    a <=  a'            =  assocs a <=  assocs a'
+
+instance  (Ix a, Show a, Show b) => Show (Array a b)  where
+    showsPrec p a = showParen (p > 9) (
+                    showString "array " .
+                    shows (bounds a) . showChar ' ' .
+                    shows (assocs a)                  )
+
+instance  (Ix a, Read a, Read b) => Read (Array a b)  where
+    readsPrec p = readParen (p > 9)
+           (\r -> [(array b as, u) | ("array",s) <- lex r,
+                                     (b,t)       <- reads s,
+                                     (as,u)      <- reads t   ])
+--------------------------------------------------------------------
+
+-- QuickCheck v.0.2
+-- DRAFT implementation; last update 000104.
+-- Koen Claessen, John Hughes.
+-- This file represents work in progress, and might change at a later date.
+
+
+--------------------------------------------------------------------
+-- Generator
+
+
diff --git a/ghc-tests/tests/Cgrun068.hs b/ghc-tests/tests/Cgrun068.hs
new file mode 100644
index 0000000000000000000000000000000000000000..d0ea90b411e5b9afce94867103614cbf95bb2c0d
--- /dev/null
+++ b/ghc-tests/tests/Cgrun068.hs
@@ -0,0 +1,384 @@
+{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, MagicHash,
+             UnboxedTuples #-}
+
+-- !!! stress tests of copying/cloning primitive arrays
+
+-- Note: You can run this test manually with an argument
+-- (i.e. ./cgrun068 10000) if you want to run the stress test for
+-- longer.
+
+{-
+Test strategy
+=============
+
+We create an array of arrays of integers. Repeatedly we then either
+
+* allocate a new array in place of an old, or
+
+* copy a random segment of an array into another array (which might be
+  the source array).
+
+By running this process long enough we hope to trigger any bugs
+related to garbage collection or edge cases.
+
+We only test copyMutableArray# and cloneArray# as they are
+representative of all the primops.
+-}
+
+module Cgrun068 ( main ) where
+
+import Debug.Trace (trace)
+
+import Control.Exception (assert)
+import Control.Monad
+import Control.Monad.Trans.State.Strict
+import Control.Monad.Trans.Class
+import GHC.Exts hiding (IsList(..))
+import GHC.ST hiding (liftST)
+import Prelude hiding (length, read)
+import qualified Prelude as P
+import qualified Prelude as P
+import System.Environment
+import System.Random
+import System.IO
+
+main :: Int -> Handle -> Handle -> IO ()
+main numMods stdout _ = do
+    hPutStr stdout
+           (test_copyMutableArray numMods ++ "\n" ++
+            test_cloneMutableArray numMods ++ "\n"
+           )
+
+-- Number of arrays
+numArrays :: Int
+numArrays = 100
+
+-- Maxmimum length of a sub-array
+maxLen :: Int
+maxLen = 1024
+
+-- Create an array of arrays, with each sub-array having random length
+-- and content.
+setup :: Rng s (MArray s (MArray s Int))
+setup = do
+    len <- rnd (1, numArrays)
+    marr <- liftST $ new_ len
+    let go i
+            | i >= len = return ()
+            | otherwise = do
+                n <- rnd (1, maxLen)
+                subarr <- liftST $ fromList [j*j | j <- [(0::Int)..n-1]]
+                liftST $ write marr i subarr
+                go (i+1)
+    go 0
+    return marr
+
+-- Replace one of the sub-arrays with a newly allocated array.
+allocate :: MArray s (MArray s Int) -> Rng s ()
+allocate marr = do
+    ix <- rnd (0, length marr - 1)
+    n <- rnd (1, maxLen)
+    subarr <- liftST $ fromList [j*j | j <- [(0::Int)..n-1]]
+    liftST $ write marr ix subarr
+
+type CopyFunction s a =
+    MArray s a -> Int -> MArray s a -> Int -> Int -> ST s ()
+
+-- Copy a random segment of an array onto another array, using the
+-- supplied copy function.
+copy :: MArray s (MArray s a) -> CopyFunction s a
+     -> Rng s (Int, Int, Int, Int, Int)
+copy marr f = do
+    six <- rnd (0, length marr - 1)
+    dix <- rnd (0, length marr - 1)
+    src <- liftST $ read marr six
+    dst <- liftST $ read marr dix
+    let srcLen = length src
+    srcOff <- rnd (0, srcLen - 1)
+    let dstLen = length dst
+    dstOff <- rnd (0, dstLen - 1)
+    n <- rnd (0, min (srcLen - srcOff) (dstLen - dstOff))
+    liftST $ f src srcOff dst dstOff n
+    return (six, dix, srcOff, dstOff, n)
+
+type CloneFunction s a = MArray s a -> Int -> Int -> ST s (MArray s a)
+
+-- Clone a random segment of an array, replacing another array, using
+-- the supplied clone function.
+clone :: MArray s (MArray s a) -> CloneFunction s a
+      -> Rng s (Int, Int, Int, Int)
+clone marr f = do
+    six <- rnd (0, length marr - 1)
+    dix <- rnd (0, length marr - 1)
+    src <- liftST $ read marr six
+    let srcLen = length src
+    -- N.B. The array length might be zero if we previously cloned
+    -- zero elements from some array.
+    srcOff <- rnd (0, max 0 (srcLen - 1))
+    n <- rnd (0, srcLen - srcOff)
+    dst <- liftST $ f src srcOff n
+    liftST $ write marr dix dst
+    return (six, dix, srcOff, n)
+
+------------------------------------------------------------------------
+-- copyMutableArray#
+
+-- Copy a slice of the source array into a destination array and check
+-- that the copy succeeded.
+test_copyMutableArray :: Int -> String
+test_copyMutableArray numMods = runST $ run $ do
+    marr <- local setup
+    marrRef <- setup
+    let go i
+            | i >= numMods = return "test_copyMutableArray: OK"
+            | otherwise = do
+                -- Either allocate or copy
+                alloc <- rnd (True, False)
+                if alloc then doAlloc else doCopy
+                go (i+1)
+
+        doAlloc = do
+            local $ allocate marr
+            allocate marrRef
+
+        doCopy = do
+            inp <- liftST $ asList marr
+            _ <- local $ copy marr copyMArray
+            (six, dix, srcOff, dstOff, n) <- copy marrRef copyMArraySlow
+            el <- liftST $ asList marr
+            elRef <- liftST $ asList marrRef
+            when (el /= elRef) $
+                fail inp el elRef six dix srcOff dstOff n
+    go 0
+  where
+    fail inp el elRef six dix srcOff dstOff n =
+        error $ "test_copyMutableArray: FAIL\n"
+        ++ "   Input: " ++ unlinesShow inp
+        ++ "    Copy: six: " ++ show six ++ " dix: " ++ show dix ++ " srcOff: "
+        ++ show srcOff ++ " dstOff: " ++ show dstOff ++ " n: " ++ show n ++ "\n"
+        ++ "Expected: " ++ unlinesShow elRef
+        ++ "  Actual: " ++ unlinesShow el
+
+asList :: MArray s (MArray s a) -> ST s [[a]]
+asList marr = toListM =<< mapArrayM toListM marr
+
+unlinesShow :: Show a => [a] -> String
+unlinesShow =  concatMap (\ x -> show x ++ "\n")
+
+------------------------------------------------------------------------
+-- cloneMutableArray#
+
+-- Copy a slice of the source array into a destination array and check
+-- that the copy succeeded.
+test_cloneMutableArray :: Int -> String
+test_cloneMutableArray numMods = runST $ run $ do
+    marr <- local setup
+    marrRef <- setup
+    let go i
+            | i >= numMods = return "test_cloneMutableArray: OK"
+            | otherwise = do
+                -- Either allocate or clone
+                alloc <- rnd (True, False)
+                if alloc then doAlloc else doClone
+                go (i+1)
+
+        doAlloc = do
+            local $ allocate marr
+            allocate marrRef
+
+        doClone = do
+            inp <- liftST $ asList marr
+            _ <- local $ clone marr cloneMArray
+            (six, dix, srcOff, n) <- clone marrRef cloneMArraySlow
+            el <- liftST $ asList marr
+            elRef <- liftST $ asList marrRef
+            when (el /= elRef) $
+                fail inp el elRef six dix srcOff n
+    go 0
+  where
+    fail inp el elRef six dix srcOff n =
+        error $ "test_cloneMutableArray: FAIL\n"
+        ++ "   Input: " ++ unlinesShow inp
+        ++ "   Clone: six: " ++ show six ++ " dix: " ++ show dix ++ " srcOff: "
+        ++ show srcOff ++ " n: " ++ show n ++ "\n"
+        ++ "Expected: " ++ unlinesShow elRef
+        ++ "  Actual: " ++ unlinesShow el
+
+------------------------------------------------------------------------
+-- Convenience wrappers for Array# and MutableArray#
+
+data Array a = Array
+    { unArray :: Array# a
+    , lengthA :: {-# UNPACK #-} !Int}
+
+data MArray s a = MArray
+    { unMArray :: MutableArray# s a
+    , lengthM :: {-# UNPACK #-} !Int}
+
+class IArray a where
+    length :: a -> Int
+instance IArray (Array a) where
+    length = lengthA
+instance IArray (MArray s a) where
+    length = lengthM
+
+instance Eq a => Eq (Array a) where
+    arr1 == arr2 = toList arr1 == toList arr2
+
+new :: Int -> a -> ST s (MArray s a)
+new n@(I# n#) a =
+    assert (n >= 0) $
+    ST $ \s# -> case newArray# n# a s# of
+        (# s2#, marr# #) -> (# s2#, MArray marr# n #)
+
+new_ :: Int -> ST s (MArray s a)
+new_ n = new n (error "Undefined element")
+
+write :: MArray s a -> Int -> a -> ST s ()
+write marr i@(I# i#) a =
+    assert (i >= 0) $
+    assert (i < length marr) $
+    ST $ \ s# ->
+    case writeArray# (unMArray marr) i# a s# of
+        s2# -> (# s2#, () #)
+
+read :: MArray s a -> Int -> ST s a
+read marr i@(I# i#) =
+    assert (i >= 0) $
+    assert (i < length marr) $
+    ST $ \ s# ->
+    readArray# (unMArray marr) i# s#
+
+index :: Array a -> Int -> a
+index arr i@(I# i#) =
+    assert (i >= 0) $
+    assert (i < length arr) $
+    case indexArray# (unArray arr) i# of
+        (# a #) -> a
+
+unsafeFreeze :: MArray s a -> ST s (Array a)
+unsafeFreeze marr = ST $ \ s# ->
+    case unsafeFreezeArray# (unMArray marr) s# of
+        (# s2#, arr# #) -> (# s2#, Array arr# (length marr) #)
+
+toList :: Array a -> [a]
+toList arr = go 0
+  where
+    go i | i >= length arr = []
+         | otherwise = index arr i : go (i+1)
+
+fromList :: [e] -> ST s (MArray s e)
+fromList es = do
+    marr <- new_ n
+    let go !_ [] = return ()
+        go i (x:xs) = write marr i x >> go (i+1) xs
+    go 0 es
+    return marr
+  where
+    n = P.length es
+
+mapArrayM :: (a -> ST s b) -> MArray s a -> ST s (MArray s b)
+mapArrayM f src = do
+    dst <- new_ n
+    let go i
+            | i >= n = return dst
+            | otherwise = do
+                el <- read src i
+                el' <- f el
+                write dst i el'
+                go (i+1)
+    go 0
+  where
+    n = length src
+
+toListM :: MArray s e -> ST s [e]
+toListM marr =
+    sequence [read marr i | i <- [0..(length marr)-1]]
+
+------------------------------------------------------------------------
+-- Wrappers around copy/clone primops
+
+copyMArray :: MArray s a -> Int -> MArray s a -> Int -> Int -> ST s ()
+copyMArray src six@(I# six#) dst dix@(I# dix#) n@(I# n#) =
+    assert (six >= 0) $
+    assert (six + n <= length src) $
+    assert (dix >= 0) $
+    assert (dix + n <= length dst) $
+    ST $ \ s# ->
+    case copyMutableArray# (unMArray src) six# (unMArray dst) dix# n# s# of
+        s2# -> (# s2#, () #)
+
+cloneMArray :: MArray s a -> Int -> Int -> ST s (MArray s a)
+cloneMArray marr off@(I# off#) n@(I# n#) =
+    assert (off >= 0) $
+    assert (off + n <= length marr) $
+    ST $ \ s# ->
+    case cloneMutableArray# (unMArray marr) off# n# s# of
+        (# s2#, marr2 #) -> (# s2#, MArray marr2 n #)
+
+------------------------------------------------------------------------
+-- Manual versions of copy/clone primops.  Used to validate the
+-- primops
+
+copyMArraySlow :: MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()
+copyMArraySlow !src !six !dst !dix n =
+    assert (six >= 0) $
+    assert (six + n <= length src) $
+    assert (dix >= 0) $
+    assert (dix + n <= length dst) $
+       if six < dix
+       then goB (six+n-1) (dix+n-1) 0  -- Copy backwards
+       else goF six dix 0  -- Copy forwards
+  where
+    goF !i !j c
+        | c >= n = return ()
+        | otherwise = do b <- read src i
+                         write dst j b
+                         goF (i+1) (j+1) (c+1)
+    goB !i !j c
+        | c >= n = return ()
+        | otherwise = do b <- read src i
+                         write dst j b
+                         goB (i-1) (j-1) (c+1)
+
+cloneMArraySlow :: MArray s a -> Int -> Int -> ST s (MArray s a)
+cloneMArraySlow !marr !off n =
+    assert (off >= 0) $
+    assert (off + n <= length marr) $ do
+        marr2 <- new_ n
+        let go !i !j c
+                | c >= n = return marr2
+                | otherwise = do
+                    b <- read marr i
+                    write marr2 j b
+                    go (i+1) (j+1) (c+1)
+        go off 0 0
+
+------------------------------------------------------------------------
+-- Utilities for simplifying RNG passing
+
+newtype Rng s a = Rng { unRng :: StateT StdGen (ST s) a }
+                deriving (Functor, Applicative, Monad)
+
+-- Same as 'randomR', but using the RNG state kept in the 'Rng' monad.
+rnd :: Random a => (a, a) -> Rng s a
+rnd r = Rng $ do
+    g <- get
+    let (x, g') = randomR r g
+    put g'
+    return x
+
+-- Run a sub-computation without affecting the RNG state.
+local :: Rng s a -> Rng s a
+local m = Rng $ do
+    g <- get
+    x <- unRng m
+    put g
+    return x
+
+liftST :: ST s a -> Rng s a
+liftST m = Rng $ lift m
+
+run :: Rng s a -> ST s a
+run = flip evalStateT (mkStdGen 13) . unRng
+
diff --git a/ghc-tests/tests/Chan001.hs b/ghc-tests/tests/Chan001.hs
new file mode 100644
index 0000000000000000000000000000000000000000..d1ef0d8d2c2ef6f6f2b4e6e8c2d370a508db198c
--- /dev/null
+++ b/ghc-tests/tests/Chan001.hs
@@ -0,0 +1,101 @@
+module Chan001 where
+import Test.QuickCheck
+import System.IO.Unsafe
+import Control.Concurrent.Chan
+import Control.Concurrent
+import Control.Monad
+import Test.Tasty.QuickCheck
+import Test.Tasty
+
+data Action = NewChan | ReadChan | WriteChan Int | ReturnInt Int
+            | ReturnBool Bool
+  deriving (Eq,Show)
+
+
+main = do
+  t <- myThreadId
+  forkIO (threadDelay 1000000 >> killThread t)
+        -- just in case we deadlock
+  quickCheck prop_NewWriteRead_NewRet
+
+testChan :: TestTree
+testChan =
+  testGroup "Chan001" $ [
+    testProperty "NewWriteRead_NewRet" prop_NewWriteRead_NewRet ]
+
+
+prop_NewWriteRead_NewRet n =
+  [NewChan,WriteChan n,ReadChan] =^ [NewChan,ReturnInt n]
+
+
+perform :: [Action] -> IO ([Bool],[Int])
+perform [] = return ([],[])
+
+perform (a:as) =
+  case a of
+    ReturnInt v  -> liftM (\(b,l) -> (b,v:l)) (perform as)
+    ReturnBool v -> liftM (\(b,l) -> (v:b,l)) (perform as)
+    NewChan      -> newChan >>= \chan -> perform' chan as
+    _            -> error $ "Please use NewChan as first action"
+
+
+perform' :: Chan Int -> [Action] -> IO ([Bool],[Int])
+perform' _ [] = return ([],[])
+
+perform' chan (a:as) =
+  case a of
+    ReturnInt v  -> liftM (\(b,l) -> (b,v:l)) (perform' chan as)
+    ReturnBool v -> liftM (\(b,l) -> (v:b,l)) (perform' chan as)
+    ReadChan     -> liftM2 (\v (b,l) -> (b,v:l)) (readChan chan)
+                                (perform' chan as)
+    WriteChan n  -> writeChan chan n >> perform' chan as
+    _                -> error $ "If you want to use " ++ show a
+                                ++ " please use the =^ operator"
+
+
+actions :: Gen [Action]
+actions =
+  liftM (NewChan:) (actions' 0)
+
+
+actions' :: Int -> Gen [Action]
+actions' contents =
+  oneof ([return [],
+          liftM2 (:) (liftM WriteChan arbitrary) (actions' (contents+1))]
+          ++
+          if contents==0
+             then []
+             else [liftM (ReadChan:) (actions' (contents-1))])
+
+
+(=^) :: [Action] -> [Action] -> Property
+c =^ c' =
+  forAll (actions' (delta 0 c))
+         (\suff -> observe c suff == observe c' suff)
+  where observe x suff = unsafePerformIO (perform (x++suff))
+
+
+(^=^) :: [Action] -> [Action] -> Property
+c ^=^ c' =
+  forAll actions
+         (\pref -> forAll (actions' (delta 0 (pref++c)))
+                          (\suff -> observe c pref suff ==
+                                      observe c' pref suff))
+  where observe x pref suff = unsafePerformIO (perform (pref++x++suff))
+
+
+delta :: Int -> [Action] -> Int
+delta i [] = i
+
+delta i (ReturnInt _:as) = delta i as
+
+delta i (ReturnBool _:as) = delta i as
+
+delta _ (NewChan:as) = delta 0 as
+
+delta i (WriteChan _:as) = delta (i+1) as
+
+delta i (ReadChan:as) = delta (if i==0
+                                  then error "read on empty Chan"
+                                  else i-1) as
+
diff --git a/ghc-tests/tests/CompareAndSwap.hs b/ghc-tests/tests/CompareAndSwap.hs
new file mode 100644
index 0000000000000000000000000000000000000000..b6978b82cd08eec76f10b730155e2485c55c4133
--- /dev/null
+++ b/ghc-tests/tests/CompareAndSwap.hs
@@ -0,0 +1,80 @@
+{-# Language MagicHash, UnboxedTuples  #-}
+module CompareAndSwap where
+
+-- | Note: extensive testing of atomic operations is performed in the
+-- "atomic-primops" library.  Only extremely rudimentary tests appear
+-- here.
+
+import GHC.IO
+import GHC.IORef
+import GHC.ST
+import GHC.STRef
+import GHC.Prim
+import GHC.Base
+import Data.Primitive.Array
+import Data.IORef
+import Control.Monad
+import System.IO
+
+------------------------------------------------------------------------
+
+casArrayST :: MutableArray s a -> Int -> a -> a -> ST s (Bool, a)
+casArrayST (MutableArray arr#) (I# i#) old new = ST$ \s1# ->
+  case casArray# arr# i# old new s1# of
+    (# s2#, x#, res #) -> (# s2#, (isTrue# (x# ==# 0#), res) #)
+
+casSTRef :: STRef s a -- ^ The 'STRef' containing a value 'current'
+         -> a -- ^ The 'old' value to compare
+         -> a -- ^ The 'new' value to replace 'current' if @old == current@
+         -> ST s (Bool, a)
+casSTRef (STRef var#) old new = ST $ \s1# ->
+   -- The primop treats the boolean as a sort of error code.
+   -- Zero means the CAS worked, one that it didn't.
+   -- We flip that here:
+    case casMutVar# var# old new s1# of
+      (# s2#, x#, res #) -> (# s2#, (isTrue# (x# ==# 0#), res) #)
+
+-- | Performs a machine-level compare and swap operation on an
+-- 'IORef'. Returns a tuple containing a 'Bool' which is 'True' when a
+-- swap is performed, along with the 'current' value from the 'IORef'.
+--
+-- Note \"compare\" here means pointer equality in the sense of
+-- 'GHC.Prim.reallyUnsafePtrEquality#'.
+casIORef :: IORef a -- ^ The 'IORef' containing a value 'current'
+         -> a -- ^ The 'old' value to compare
+         -> a -- ^ The 'new' value to replace 'current' if @old == current@
+         -> IO (Bool, a)
+casIORef (IORef var) old new = stToIO (casSTRef var old new)
+
+
+------------------------------------------------------------------------
+-- Make sure this Int corresponds to a single object in memory (NOINLINE):
+{-# NOINLINE mynum #-}
+mynum :: Int
+mynum = 33
+
+main stdout _ = do
+  hPutStrLn stdout "Perform a CAS within an IORef"
+  ref  <- newIORef mynum
+  res  <- casIORef ref mynum 44
+  res2 <- casIORef ref mynum 44
+  hPutStrLn stdout $ "  1st try should succeed: "++show res
+  hPutStrLn stdout $ "  2nd should fail: "++show res2
+
+  ------------------------------------------------------------
+  hPutStrLn stdout "Perform a CAS within a MutableArray#"
+  arr <- newArray 5 mynum
+
+  res  <- stToIO$ casArrayST arr 3 mynum 44
+  res2 <- stToIO$ casArrayST arr 3 mynum 44
+  hPutStrLn stdout $ "  1st try should succeed: "++show res
+  hPutStrLn stdout $ "  2nd should fail: "++show res2
+
+  hPutStrLn stdout "Printing array:"
+  forM_ [0..4] $ \ i -> do
+    x <- readArray arr i
+    hPutStr stdout ("  "++show x)
+  hPutStrLn stdout ""
+
+  ------------------------------------------------------------
+  hPutStrLn stdout "Done."
diff --git a/ghc-tests/tests/Conc023.hs b/ghc-tests/tests/Conc023.hs
new file mode 100644
index 0000000000000000000000000000000000000000..e80f9bf3eed74525b66c2fe55cf0783689b3f5b7
--- /dev/null
+++ b/ghc-tests/tests/Conc023.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Conc023 where
+-- !!! test threadDelay, Random, and QSemN.
+
+-- start a large number (n) of threads each of which will wait for a
+-- random delay between 0 and m seconds.  We use a semaphore to wait
+-- for all the threads to finish.
+
+import System.Random
+import Control.Concurrent
+import Control.Exception
+import Control.Monad
+
+n = 5000  -- no. of threads
+m = 3000  -- maximum delay
+
+main = do
+   v <- newEmptyMVar
+   is <- replicateM n $ getStdRandom (randomR (1,m))
+   mapM_ (fork_sleep v) is
+   replicateM_ n (takeMVar v)
+   where
+     fork_sleep v i = forkIO $ do threadDelay (i*1000); putMVar v ()
diff --git a/ghc-tests/tests/Concio002.hs b/ghc-tests/tests/Concio002.hs
new file mode 100644
index 0000000000000000000000000000000000000000..e54045943c4a47d2d755e4ccbb563871aabe90e3
--- /dev/null
+++ b/ghc-tests/tests/Concio002.hs
@@ -0,0 +1,15 @@
+module Concio002 where
+import System.Process
+import System.IO
+import Control.Concurrent
+
+main stdout _ = do
+  (hin,hout,herr,ph) <- runInteractiveProcess "cat" [] Nothing Nothing
+  forkIO $ do threadDelay 100000
+              hPutStrLn stdout "child"
+              hFlush stdout
+              hPutStrLn hin "msg"
+              hFlush hin
+  hPutStrLn stdout "parent1"
+  hGetLine hout >>= hPutStrLn stdout
+  hPutStrLn stdout "parent2"
diff --git a/ghc-tests/tests/CopySmallArrayStressTest.hs b/ghc-tests/tests/CopySmallArrayStressTest.hs
new file mode 100644
index 0000000000000000000000000000000000000000..7f7fad22be30a305a1152ff188f6be593535587f
--- /dev/null
+++ b/ghc-tests/tests/CopySmallArrayStressTest.hs
@@ -0,0 +1,383 @@
+{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, MagicHash,
+             UnboxedTuples #-}
+
+-- !!! stress tests of copying/cloning primitive arrays
+
+-- Note: You can run this test manually with an argument (i.e.
+-- ./CopySmallArrayStressTest 10000) if you want to run the stress
+-- test for longer.
+
+{-
+Test strategy
+=============
+
+We create an array of arrays of integers. Repeatedly we then either
+
+* allocate a new array in place of an old, or
+
+* copy a random segment of an array into another array (which might be
+  the source array).
+
+By running this process long enough we hope to trigger any bugs
+related to garbage collection or edge cases.
+
+We only test copySmallMutableArray# and cloneSmallArray# as they are
+representative of all the primops.
+-}
+
+module CopySmallArrayStressTest ( main ) where
+
+
+import Control.Exception (assert)
+import Control.Monad
+import Control.Monad.Trans.State.Strict
+import Control.Monad.Trans.Class
+import GHC.Exts hiding (IsList(..))
+import GHC.ST hiding (liftST)
+import Prelude hiding (length, read)
+import qualified Prelude as P
+import qualified Prelude as P
+import System.Environment
+import System.Random
+import System.IO
+
+main :: Int -> Handle -> Handle -> IO ()
+main numMods stdout _ = do
+    hPutStr stdout
+           (test_copyMutableArray numMods ++ "\n" ++
+            test_cloneMutableArray numMods ++ "\n"
+           )
+
+-- Number of arrays
+numArrays :: Int
+numArrays = 100
+
+-- Maxmimum length of a sub-array
+maxLen :: Int
+maxLen = 1024
+
+-- Create an array of arrays, with each sub-array having random length
+-- and content.
+setup :: Rng s (MArray s (MArray s Int))
+setup = do
+    len <- rnd (1, numArrays)
+    marr <- liftST $ new_ len
+    let go i
+            | i >= len = return ()
+            | otherwise = do
+                n <- rnd (1, maxLen)
+                subarr <- liftST $ fromList [j*j | j <- [(0::Int)..n-1]]
+                liftST $ write marr i subarr
+                go (i+1)
+    go 0
+    return marr
+
+-- Replace one of the sub-arrays with a newly allocated array.
+allocate :: MArray s (MArray s Int) -> Rng s ()
+allocate marr = do
+    ix <- rnd (0, length marr - 1)
+    n <- rnd (1, maxLen)
+    subarr <- liftST $ fromList [j*j | j <- [(0::Int)..n-1]]
+    liftST $ write marr ix subarr
+
+type CopyFunction s a =
+    MArray s a -> Int -> MArray s a -> Int -> Int -> ST s ()
+
+-- Copy a random segment of an array onto another array, using the
+-- supplied copy function.
+copy :: MArray s (MArray s a) -> CopyFunction s a
+     -> Rng s (Int, Int, Int, Int, Int)
+copy marr f = do
+    six <- rnd (0, length marr - 1)
+    dix <- rnd (0, length marr - 1)
+    src <- liftST $ read marr six
+    dst <- liftST $ read marr dix
+    let srcLen = length src
+    srcOff <- rnd (0, srcLen - 1)
+    let dstLen = length dst
+    dstOff <- rnd (0, dstLen - 1)
+    n <- rnd (0, min (srcLen - srcOff) (dstLen - dstOff))
+    liftST $ f src srcOff dst dstOff n
+    return (six, dix, srcOff, dstOff, n)
+
+type CloneFunction s a = MArray s a -> Int -> Int -> ST s (MArray s a)
+
+-- Clone a random segment of an array, replacing another array, using
+-- the supplied clone function.
+clone :: MArray s (MArray s a) -> CloneFunction s a
+      -> Rng s (Int, Int, Int, Int)
+clone marr f = do
+    six <- rnd (0, length marr - 1)
+    dix <- rnd (0, length marr - 1)
+    src <- liftST $ read marr six
+    let srcLen = length src
+    -- N.B. The array length might be zero if we previously cloned
+    -- zero elements from some array.
+    srcOff <- rnd (0, max 0 (srcLen - 1))
+    n <- rnd (0, srcLen - srcOff)
+    dst <- liftST $ f src srcOff n
+    liftST $ write marr dix dst
+    return (six, dix, srcOff, n)
+
+------------------------------------------------------------------------
+-- copySmallMutableArray#
+
+-- Copy a slice of the source array into a destination array and check
+-- that the copy succeeded.
+test_copyMutableArray :: Int -> String
+test_copyMutableArray numMods = runST $ run $ do
+    marr <- local setup
+    marrRef <- setup
+    let go i
+            | i >= numMods = return "test_copyMutableArray: OK"
+            | otherwise = do
+                -- Either allocate or copy
+                alloc <- rnd (True, False)
+                if alloc then doAlloc else doCopy
+                go (i+1)
+
+        doAlloc = do
+            local $ allocate marr
+            allocate marrRef
+
+        doCopy = do
+            inp <- liftST $ asList marr
+            _ <- local $ copy marr copyMArray
+            (six, dix, srcOff, dstOff, n) <- copy marrRef copyMArraySlow
+            el <- liftST $ asList marr
+            elRef <- liftST $ asList marrRef
+            when (el /= elRef) $
+                fail inp el elRef six dix srcOff dstOff n
+    go 0
+  where
+    fail inp el elRef six dix srcOff dstOff n =
+        error $ "test_copyMutableArray: FAIL\n"
+        ++ "   Input: " ++ unlinesShow inp
+        ++ "    Copy: six: " ++ show six ++ " dix: " ++ show dix ++ " srcOff: "
+        ++ show srcOff ++ " dstOff: " ++ show dstOff ++ " n: " ++ show n ++ "\n"
+        ++ "Expected: " ++ unlinesShow elRef
+        ++ "  Actual: " ++ unlinesShow el
+
+asList :: MArray s (MArray s a) -> ST s [[a]]
+asList marr = toListM =<< mapArrayM toListM marr
+
+unlinesShow :: Show a => [a] -> String
+unlinesShow =  concatMap (\ x -> show x ++ "\n")
+
+------------------------------------------------------------------------
+-- cloneSmallMutableArray#
+
+-- Copy a slice of the source array into a destination array and check
+-- that the copy succeeded.
+test_cloneMutableArray :: Int -> String
+test_cloneMutableArray numMods = runST $ run $ do
+    marr <- local setup
+    marrRef <- setup
+    let go i
+            | i >= numMods = return "test_cloneMutableArray: OK"
+            | otherwise = do
+                -- Either allocate or clone
+                alloc <- rnd (True, False)
+                if alloc then doAlloc else doClone
+                go (i+1)
+
+        doAlloc = do
+            local $ allocate marr
+            allocate marrRef
+
+        doClone = do
+            inp <- liftST $ asList marr
+            _ <- local $ clone marr cloneMArray
+            (six, dix, srcOff, n) <- clone marrRef cloneMArraySlow
+            el <- liftST $ asList marr
+            elRef <- liftST $ asList marrRef
+            when (el /= elRef) $
+                fail inp el elRef six dix srcOff n
+    go 0
+  where
+    fail inp el elRef six dix srcOff n =
+        error $ "test_cloneMutableArray: FAIL\n"
+        ++ "   Input: " ++ unlinesShow inp
+        ++ "   Clone: six: " ++ show six ++ " dix: " ++ show dix ++ " srcOff: "
+        ++ show srcOff ++ " n: " ++ show n ++ "\n"
+        ++ "Expected: " ++ unlinesShow elRef
+        ++ "  Actual: " ++ unlinesShow el
+
+------------------------------------------------------------------------
+-- Convenience wrappers for SmallArray# and SmallMutableArray#
+
+data Array a = Array
+    { unArray :: SmallArray# a
+    , lengthA :: {-# UNPACK #-} !Int}
+
+data MArray s a = MArray
+    { unMArray :: SmallMutableArray# s a
+    , lengthM :: {-# UNPACK #-} !Int}
+
+class IArray a where
+    length :: a -> Int
+instance IArray (Array a) where
+    length = lengthA
+instance IArray (MArray s a) where
+    length = lengthM
+
+instance Eq a => Eq (Array a) where
+    arr1 == arr2 = toList arr1 == toList arr2
+
+new :: Int -> a -> ST s (MArray s a)
+new n@(I# n#) a =
+    assert (n >= 0) $
+    ST $ \s# -> case newSmallArray# n# a s# of
+        (# s2#, marr# #) -> (# s2#, MArray marr# n #)
+
+new_ :: Int -> ST s (MArray s a)
+new_ n = new n (error "Undefined element")
+
+write :: MArray s a -> Int -> a -> ST s ()
+write marr i@(I# i#) a =
+    assert (i >= 0) $
+    assert (i < length marr) $
+    ST $ \ s# ->
+    case writeSmallArray# (unMArray marr) i# a s# of
+        s2# -> (# s2#, () #)
+
+read :: MArray s a -> Int -> ST s a
+read marr i@(I# i#) =
+    assert (i >= 0) $
+    assert (i < length marr) $
+    ST $ \ s# ->
+    readSmallArray# (unMArray marr) i# s#
+
+index :: Array a -> Int -> a
+index arr i@(I# i#) =
+    assert (i >= 0) $
+    assert (i < length arr) $
+    case indexSmallArray# (unArray arr) i# of
+        (# a #) -> a
+
+unsafeFreeze :: MArray s a -> ST s (Array a)
+unsafeFreeze marr = ST $ \ s# ->
+    case unsafeFreezeSmallArray# (unMArray marr) s# of
+        (# s2#, arr# #) -> (# s2#, Array arr# (length marr) #)
+
+toList :: Array a -> [a]
+toList arr = go 0
+  where
+    go i | i >= length arr = []
+         | otherwise = index arr i : go (i+1)
+
+fromList :: [e] -> ST s (MArray s e)
+fromList es = do
+    marr <- new_ n
+    let go !_ [] = return ()
+        go i (x:xs) = write marr i x >> go (i+1) xs
+    go 0 es
+    return marr
+  where
+    n = P.length es
+
+mapArrayM :: (a -> ST s b) -> MArray s a -> ST s (MArray s b)
+mapArrayM f src = do
+    dst <- new_ n
+    let go i
+            | i >= n = return dst
+            | otherwise = do
+                el <- read src i
+                el' <- f el
+                write dst i el'
+                go (i+1)
+    go 0
+  where
+    n = length src
+
+toListM :: MArray s e -> ST s [e]
+toListM marr =
+    sequence [read marr i | i <- [0..(length marr)-1]]
+
+------------------------------------------------------------------------
+-- Wrappers around copy/clone primops
+
+copyMArray :: MArray s a -> Int -> MArray s a -> Int -> Int -> ST s ()
+copyMArray src six@(I# six#) dst dix@(I# dix#) n@(I# n#) =
+    assert (six >= 0) $
+    assert (six + n <= length src) $
+    assert (dix >= 0) $
+    assert (dix + n <= length dst) $
+    ST $ \ s# ->
+    case copySmallMutableArray# (unMArray src) six# (unMArray dst) dix# n# s# of
+        s2# -> (# s2#, () #)
+
+cloneMArray :: MArray s a -> Int -> Int -> ST s (MArray s a)
+cloneMArray marr off@(I# off#) n@(I# n#) =
+    assert (off >= 0) $
+    assert (off + n <= length marr) $
+    ST $ \ s# ->
+    case cloneSmallMutableArray# (unMArray marr) off# n# s# of
+        (# s2#, marr2 #) -> (# s2#, MArray marr2 n #)
+
+------------------------------------------------------------------------
+-- Manual versions of copy/clone primops.  Used to validate the
+-- primops
+
+copyMArraySlow :: MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()
+copyMArraySlow !src !six !dst !dix n =
+    assert (six >= 0) $
+    assert (six + n <= length src) $
+    assert (dix >= 0) $
+    assert (dix + n <= length dst) $
+       if six < dix
+       then goB (six+n-1) (dix+n-1) 0  -- Copy backwards
+       else goF six dix 0  -- Copy forwards
+  where
+    goF !i !j c
+        | c >= n = return ()
+        | otherwise = do b <- read src i
+                         write dst j b
+                         goF (i+1) (j+1) (c+1)
+    goB !i !j c
+        | c >= n = return ()
+        | otherwise = do b <- read src i
+                         write dst j b
+                         goB (i-1) (j-1) (c+1)
+
+cloneMArraySlow :: MArray s a -> Int -> Int -> ST s (MArray s a)
+cloneMArraySlow !marr !off n =
+    assert (off >= 0) $
+    assert (off + n <= length marr) $ do
+        marr2 <- new_ n
+        let go !i !j c
+                | c >= n = return marr2
+                | otherwise = do
+                    b <- read marr i
+                    write marr2 j b
+                    go (i+1) (j+1) (c+1)
+        go off 0 0
+
+------------------------------------------------------------------------
+-- Utilities for simplifying RNG passing
+
+newtype Rng s a = Rng { unRng :: StateT StdGen (ST s) a }
+                deriving (Functor, Applicative, Monad)
+
+-- Same as 'randomR', but using the RNG state kept in the 'Rng' monad.
+rnd :: Random a => (a, a) -> Rng s a
+rnd r = Rng $ do
+    g <- get
+    let (x, g') = randomR r g
+    put g'
+    return x
+
+-- Run a sub-computation without affecting the RNG state.
+local :: Rng s a -> Rng s a
+local m = Rng $ do
+    g <- get
+    x <- unRng m
+    put g
+    return x
+
+liftST :: ST s a -> Rng s a
+liftST m = Rng $ lift m
+
+run :: Rng s a -> ST s a
+run = flip evalStateT (mkStdGen 13) . unRng
+
diff --git a/ghc-tests/tests/Drvrun022.hs b/ghc-tests/tests/Drvrun022.hs
new file mode 100644
index 0000000000000000000000000000000000000000..6f8bdc7cb66d33ff4380ce273ccf6b22fbf67a6b
--- /dev/null
+++ b/ghc-tests/tests/Drvrun022.hs
@@ -0,0 +1,13 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+module Drvrun022 where
+
+-- GHC 6.4.1 output "testz" in z-encoded form!
+
+import Data.Generics
+import System.IO
+
+data TestZ = TestZ { testz :: Int }
+             deriving (Show, Read, Eq, Data, Typeable)
+
+main stdout _ = hPrint stdout $ constrFields . toConstr $ TestZ { testz = 2 }
diff --git a/ghc-tests/tests/FFI009.hs b/ghc-tests/tests/FFI009.hs
new file mode 100644
index 0000000000000000000000000000000000000000..8c61a2ae5369c3853748c54153e159945328a148
--- /dev/null
+++ b/ghc-tests/tests/FFI009.hs
@@ -0,0 +1,555 @@
+module FFI009 where
+
+import Foreign
+import System.Random
+import System.IO
+
+--------------------------------------------------------------------------------
+
+type FunType5I = Int -> Int -> Int -> Int -> Int -> Int
+
+foreign import ccall "dynamic" callFun5I :: FunPtr FunType5I -> FunType5I
+foreign import ccall "wrapper" mkFun5I   :: FunType5I -> IO (FunPtr FunType5I)
+
+manyArgs5I :: FunType5I
+manyArgs5I a1 a2 a3 a4 a5 = (((a1 * 31 + a2) * 31 + a3) * 31 + a4) * 31 + a5
+
+test5I :: Handle -> IO ()
+test5I stdout = do
+  a1 <- randomIO
+  a2 <- randomIO
+  a3 <- randomIO
+  a4 <- randomIO
+  a5 <- randomIO
+  funAddr <- mkFun5I manyArgs5I
+  hPrint stdout (callFun5I funAddr a1 a2 a3 a4 a5 ==
+         manyArgs5I        a1 a2 a3 a4 a5)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunType11D = Double -> Double -> Double -> Double -> Double -> Double
+               -> Double -> Double -> Double -> Double -> Double -> Double
+
+foreign import ccall "dynamic" callFun11D :: FunPtr FunType11D -> FunType11D
+foreign import ccall "wrapper" mkFun11D   :: FunType11D -> IO (FunPtr FunType11D)
+
+manyArgs11D :: FunType11D
+manyArgs11D a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 =
+  ((((a1 * 31 + a2) * 31 + a3) * 31 + a4) * 31 + a5) * 31 + a6
+  + a7 + a8 + a9 + a10 + a11
+
+test11D :: Handle -> IO ()
+test11D stdout = do
+  a1 <- randomIO
+  a2 <- randomIO
+  a3 <- randomIO
+  a4 <- randomIO
+  a5 <- randomIO
+  a6 <- randomIO
+  a7 <- randomIO
+  a8 <- randomIO
+  a9 <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  funAddr <- mkFun11D manyArgs11D
+  let x = callFun11D funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11
+      y = manyArgs11D        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11
+  if x /= y then
+        hPrint stdout x >> hPrint stdout y
+     else
+       hPrint stdout True
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunType11M = Int -> Double -> Float -> Char -> Bool -> Int -> Float -> Int
+               -> Char -> Double -> Bool -> Double
+
+foreign import ccall "dynamic" callFun11M :: FunPtr FunType11M -> FunType11M
+foreign import ccall "wrapper" mkFun11M   :: FunType11M -> IO (FunPtr FunType11M)
+
+manyArgs11M :: FunType11M
+manyArgs11M a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 =
+   (((((((((fromIntegral           a1   * 31 +                         a2)  * 31 +
+            realToFrac             a3)  * 31 + fromIntegral (fromEnum  a4)) * 31 +
+            fromIntegral (fromEnum a5)) * 31 + fromIntegral            a6)  * 31 +
+            realToFrac             a7)  * 31 + fromIntegral            a8)  * 31 +
+            fromIntegral (fromEnum a9)) * 31 +                         a10) * 31 +
+            fromIntegral (fromEnum a11)
+
+test11M :: Handle -> IO ()
+test11M stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  funAddr <- mkFun11M manyArgs11M
+  hPrint stdout (callFun11M funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 ==
+         manyArgs11M        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM1 = Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM1 :: FunPtr FunTypeM1 -> FunTypeM1
+foreign import ccall "wrapper" mkFunM1   :: FunTypeM1 -> IO (FunPtr FunTypeM1)
+
+manyArgsM1 :: FunTypeM1
+manyArgsM1 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((              a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM1 :: Handle -> IO ()
+testM1 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM1 manyArgsM1
+  hPrint stdout (callFunM1 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM1        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM2 = Int -> Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM2 :: FunPtr FunTypeM2 -> FunTypeM2
+foreign import ccall "wrapper" mkFunM2   :: FunTypeM2 -> IO (FunPtr FunTypeM2)
+
+manyArgsM2 :: FunTypeM2
+manyArgsM2 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 +               a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM2 :: Handle -> IO ()
+testM2 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM2 manyArgsM2
+  hPrint stdout (callFunM2 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM2        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM3 = Int -> Int -> Double -> Int -> Int -> Int -> Int -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM3 :: FunPtr FunTypeM3 -> FunTypeM3
+foreign import ccall "wrapper" mkFunM3   :: FunTypeM3 -> IO (FunPtr FunTypeM3)
+
+manyArgsM3 :: FunTypeM3
+manyArgsM3 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+                           a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM3 :: Handle -> IO ()
+testM3 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM3 manyArgsM3
+  hPrint stdout (callFunM3 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM3        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM4 = Int -> Int -> Int -> Double -> Int -> Int -> Int -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM4 :: FunPtr FunTypeM4 -> FunTypeM4
+foreign import ccall "wrapper" mkFunM4   :: FunTypeM4 -> IO (FunPtr FunTypeM4)
+
+manyArgsM4 :: FunTypeM4
+manyArgsM4 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 +               a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM4 :: Handle -> IO ()
+testM4 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM4 manyArgsM4
+  hPrint stdout (callFunM4 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM4        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM5 = Int -> Int -> Int -> Int -> Double -> Int -> Int -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM5 :: FunPtr FunTypeM5 -> FunTypeM5
+foreign import ccall "wrapper" mkFunM5   :: FunTypeM5 -> IO (FunPtr FunTypeM5)
+
+manyArgsM5 :: FunTypeM5
+manyArgsM5 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+                           a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM5 :: Handle -> IO ()
+testM5 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM5 manyArgsM5
+  hPrint stdout (callFunM5 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM5        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM6 = Int -> Int -> Int -> Int -> Int -> Double -> Int -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM6 :: FunPtr FunTypeM6 -> FunTypeM6
+foreign import ccall "wrapper" mkFunM6   :: FunTypeM6 -> IO (FunPtr FunTypeM6)
+
+manyArgsM6 :: FunTypeM6
+manyArgsM6 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 +               a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM6 :: Handle -> IO ()
+testM6 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM6 manyArgsM6
+  hPrint stdout (callFunM6 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM6        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM7 = Int -> Int -> Int -> Int -> Int -> Int -> Double -> Int -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM7 :: FunPtr FunTypeM7 -> FunTypeM7
+foreign import ccall "wrapper" mkFunM7   :: FunTypeM7 -> IO (FunPtr FunTypeM7)
+
+manyArgsM7 :: FunTypeM7
+manyArgsM7 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+                           a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM7 :: Handle -> IO ()
+testM7 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM7 manyArgsM7
+  hPrint stdout (callFunM7 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM7        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM8 = Int -> Int -> Int -> Int -> Int -> Int -> Int -> Double -> Int
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM8 :: FunPtr FunTypeM8 -> FunTypeM8
+foreign import ccall "wrapper" mkFunM8   :: FunTypeM8 -> IO (FunPtr FunTypeM8)
+
+manyArgsM8 :: FunTypeM8
+manyArgsM8 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 +               a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM8 :: Handle -> IO ()
+testM8 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM8 manyArgsM8
+  hPrint stdout (callFunM8 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM8        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM9 = Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Double
+              -> Int -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM9 :: FunPtr FunTypeM9 -> FunTypeM9
+foreign import ccall "wrapper" mkFunM9   :: FunTypeM9 -> IO (FunPtr FunTypeM9)
+
+manyArgsM9 :: FunTypeM9
+manyArgsM9 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+                           a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM9 :: Handle -> IO ()
+testM9 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM9 manyArgsM9
+  hPrint stdout (callFunM9 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM9        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM10 = Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int
+               -> Double -> Int -> Int -> Double
+
+foreign import ccall "dynamic" callFunM10 :: FunPtr FunTypeM10 -> FunTypeM10
+foreign import ccall "wrapper" mkFunM10   :: FunTypeM10 -> IO (FunPtr FunTypeM10)
+
+manyArgsM10 :: FunTypeM10
+manyArgsM10 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 +              a10) * 31 +
+             fromIntegral a11) * 31 + fromIntegral a12
+
+testM10 :: Handle -> IO ()
+testM10 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM10 manyArgsM10
+  hPrint stdout (callFunM10 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM10        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM11 = Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int
+               -> Int -> Double -> Int -> Double
+
+foreign import ccall "dynamic" callFunM11 :: FunPtr FunTypeM11 -> FunTypeM11
+foreign import ccall "wrapper" mkFunM11   :: FunTypeM11 -> IO (FunPtr FunTypeM11)
+
+manyArgsM11 :: FunTypeM11
+manyArgsM11 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+                          a11) * 31 + fromIntegral a12
+
+testM11 :: Handle -> IO ()
+testM11 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM11 manyArgsM11
+  hPrint stdout (callFunM11 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM11        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+type FunTypeM12 = Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int
+               -> Int -> Int -> Double -> Double
+
+foreign import ccall "dynamic" callFunM12 :: FunPtr FunTypeM12 -> FunTypeM12
+foreign import ccall "wrapper" mkFunM12   :: FunTypeM12 -> IO (FunPtr FunTypeM12)
+
+manyArgsM12 :: FunTypeM12
+manyArgsM12 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
+   ((((((((((fromIntegral  a1  * 31 + fromIntegral  a2) * 31 +
+             fromIntegral  a3) * 31 + fromIntegral  a4) * 31 +
+             fromIntegral  a5) * 31 + fromIntegral  a6) * 31 +
+             fromIntegral  a7) * 31 + fromIntegral  a8) * 31 +
+             fromIntegral  a9) * 31 + fromIntegral a10) * 31 +
+             fromIntegral a11) * 31 +              a12
+
+testM12 :: Handle -> IO ()
+testM12 stdout = do
+  a1  <- randomIO
+  a2  <- randomIO
+  a3  <- randomIO
+  a4  <- randomIO
+  a5  <- randomIO
+  a6  <- randomIO
+  a7  <- randomIO
+  a8  <- randomIO
+  a9  <- randomIO
+  a10 <- randomIO
+  a11 <- randomIO
+  a12 <- randomIO
+  funAddr <- mkFunM12 manyArgsM12
+  hPrint stdout (callFunM12 funAddr a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 ==
+         manyArgsM12        a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12)
+  freeHaskellFunPtr funAddr
+
+--------------------------------------------------------------------------------
+
+rep :: Handle -> String -> (Handle -> IO ()) -> IO ()
+rep stdout msg tst = do
+   hPutStrLn stdout ("Testing " ++ msg ++ "...")
+   sequence_ (replicate 10 (tst stdout))
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+  setStdGen (mkStdGen 4711)
+  rep stdout "5 Int arguments" test5I
+  rep stdout "11 Double arguments" test11D
+  rep stdout "11 mixed arguments" test11M
+  rep stdout "Double as 1st argument, rest Int" testM1
+  rep stdout "Double as 2nd argument, rest Int" testM2
+  rep stdout "Double as 3rd argument, rest Int" testM3
+  rep stdout "Double as 4th argument, rest Int" testM4
+  rep stdout "Double as 5th argument, rest Int" testM5
+  rep stdout "Double as 6th argument, rest Int" testM6
+  rep stdout "Double as 7th argument, rest Int" testM7
+  rep stdout "Double as 8th argument, rest Int" testM8
+  rep stdout "Double as 9th argument, rest Int" testM9
+  rep stdout "Double as 10th argument, rest Int" testM10
+  rep stdout "Double as 11th argument, rest Int" testM11
+  rep stdout "Double as 12th argument, rest Int" testM12
diff --git a/ghc-tests/tests/HClose003.hs b/ghc-tests/tests/HClose003.hs
new file mode 100644
index 0000000000000000000000000000000000000000..87d55ff918e2afdf58a5a7ed016364062b9f7c3d
--- /dev/null
+++ b/ghc-tests/tests/HClose003.hs
@@ -0,0 +1,45 @@
+-- Test for #3128, file descriptor leak when hClose fails
+module HClose003 where
+
+import System.IO
+import Control.Exception
+import Data.Char
+
+import System.Posix
+import qualified GHC.IO.Device as IODevice
+import GHC.IO.Handle
+import GHC.IO.Handle.Internals
+import GHC.IO.Handle.Types
+import System.Posix.Internals
+import Tasty.Bronze
+
+
+main stdout _stderr = do
+  (read,write) <- createPipe
+  hread <- fdToHandle read
+  hwrite <- fdToHandle write
+
+        -- close the FD without telling the IO library:
+  showPossibleException stdout (hClose hread)
+  hIsOpen hread >>= hPrint stdout
+
+        -- put some data in the Handle's write buffer:
+  hPutStr hwrite "testing"
+        -- now try to close the Handle:
+  showPossibleException stdout (hClose hwrite)
+  hIsOpen hwrite >>= hPrint stdout
+
+showPossibleException :: Handle -> IO () -> IO ()
+showPossibleException stdout f = do
+  e <- try f
+  hPutStrLn stdout (sanitise (show (e :: Either SomeException ())))
+ where
+  -- we don't care which file descriptor it is
+  sanitise [] = []
+  sanitise (x:xs) = if isDigit x then ('X':(sanitise' xs)) else (x:(sanitise xs))
+  sanitise' [] = []
+  sanitise' (x:xs) = if isDigit x then (sanitise' xs) else (x:(sanitise xs))
+
+naughtyClose h =
+  withHandle_ "naughtyClose" h $ \ Handle__{haDevice=dev} ->
+     IODevice.close dev
diff --git a/ghc-tests/tests/HWaitPipe.hs b/ghc-tests/tests/HWaitPipe.hs
new file mode 100644
index 0000000000000000000000000000000000000000..4f8ff011c6f8ced5e2617cb4b47bdfee2c9d274e
--- /dev/null
+++ b/ghc-tests/tests/HWaitPipe.hs
@@ -0,0 +1,24 @@
+module HWaitPipe where
+import Control.Concurrent
+import Control.Monad
+import GHC.Clock
+import System.IO
+import System.Posix.IO
+import System.Timeout
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+    (readPipe, _) <- createPipe
+    readPipeHandle <- fdToHandle readPipe
+    let nanoSecondsPerSecond = 1000 * 1000 * 1000
+    let milliSecondsPerSecond = 1000
+    let timeToSpend = 1
+    let timeToSpendNano = timeToSpend * nanoSecondsPerSecond
+    let timeToSpendMilli = timeToSpend * milliSecondsPerSecond
+    start <- getMonotonicTimeNSec
+    b <- hWaitForInput readPipeHandle timeToSpendMilli
+    end <- getMonotonicTimeNSec
+    let timeSpentNano = fromIntegral $ end - start
+    let delta = timeSpentNano - timeToSpendNano
+    -- We can never wait for a shorter amount of time than specified
+    hPutStrLn stdout $ "delta >= 0: " ++ show (delta > 0)
diff --git a/ghc-tests/tests/HWaitSocket.hs b/ghc-tests/tests/HWaitSocket.hs
new file mode 100644
index 0000000000000000000000000000000000000000..980f126d8f650e2e8f423336d2d837ed4cf6e23f
--- /dev/null
+++ b/ghc-tests/tests/HWaitSocket.hs
@@ -0,0 +1,49 @@
+module HWaitSocket where
+import Control.Concurrent
+import Control.Monad
+import Foreign.C
+import GHC.Clock
+import GHC.IO.Device
+import GHC.IO.Handle.FD
+import System.IO
+import System.Posix.IO
+import System.Posix.Types
+import System.Timeout
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+    socketHandle <- makeTestSocketHandle
+    let nanoSecondsPerSecond = 1000 * 1000 * 1000
+    let milliSecondsPerSecond = 1000
+    let timeToSpend = 1
+    let timeToSpendNano = timeToSpend * nanoSecondsPerSecond
+    let timeToSpendMilli = timeToSpend * milliSecondsPerSecond
+    start <- getMonotonicTimeNSec
+    b <- hWaitForInput socketHandle timeToSpendMilli
+    end <- getMonotonicTimeNSec
+    let timeSpentNano = fromIntegral $ end - start
+    let delta = timeSpentNano - timeToSpendNano
+    -- We can never wait for a shorter amount of time than specified
+    hPutStrLn stdout $ "delta >= 0: " ++ show (delta >= 0)
+
+foreign import ccall unsafe "socket" c_socket ::
+               CInt -> CInt -> CInt -> IO CInt
+
+makeTestSocketHandle :: IO Handle
+makeTestSocketHandle = do
+    sockNum <-
+        c_socket
+            1 -- PF_LOCAL
+            2 -- SOCK_DGRAM
+            0
+    let fd = fromIntegral sockNum :: Fd
+    h <-
+        fdToHandle'
+            (fromIntegral fd)
+            (Just GHC.IO.Device.Stream)
+            True
+            "testsocket"
+            ReadMode
+            True
+    hSetBuffering h NoBuffering
+    pure h
diff --git a/ghc-tests/tests/MVar001.hs b/ghc-tests/tests/MVar001.hs
new file mode 100644
index 0000000000000000000000000000000000000000..c6dc97f1c9c97ad5483cc6aecad4c9ee350921bc
--- /dev/null
+++ b/ghc-tests/tests/MVar001.hs
@@ -0,0 +1,145 @@
+module MVar001 where
+import Test.QuickCheck
+import System.IO.Unsafe
+import Control.Concurrent.MVar
+import Control.Concurrent
+import Control.Monad
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+
+data Action = NewEmptyMVar | NewMVar Int | TakeMVar | ReadMVar | PutMVar Int
+            | SwapMVar Int | IsEmptyMVar | ReturnInt Int | ReturnBool Bool
+  deriving (Eq,Show)
+
+testMVar :: TestTree
+testMVar = testGroup "MVar001" $ [
+    testProperty "NewEIs_NewERet" prop_NewEIs_NewERet
+  , testProperty "NewIs_NewRet" prop_NewIs_NewRet
+  , testProperty "NewTake_NewRet" prop_NewTake_NewRet
+  , testProperty "NewEPutTake_NewERet" prop_NewEPutTake_NewERet
+  , testProperty "NewRead_NewRet" prop_NewRead_NewRet
+  , testProperty "NewSwap_New" prop_NewSwap_New ]
+
+
+prop_NewEIs_NewERet =
+  [NewEmptyMVar,IsEmptyMVar] =^ [NewEmptyMVar,ReturnBool True]
+
+prop_NewIs_NewRet n =
+  [NewMVar n,IsEmptyMVar] =^ [NewMVar n,ReturnBool False]
+
+prop_NewTake_NewRet n =
+  [NewMVar n,TakeMVar] =^ [NewEmptyMVar,ReturnInt n]
+
+prop_NewEPutTake_NewERet n =
+  [NewEmptyMVar,PutMVar n,TakeMVar] =^
+    [NewEmptyMVar,ReturnInt n]
+
+prop_NewRead_NewRet n =
+  [NewMVar n,ReadMVar] =^ [NewMVar n,ReturnInt n]
+
+prop_NewSwap_New m n =
+  [NewMVar m,SwapMVar n] =^ [NewMVar n]
+
+
+perform :: [Action] -> IO ([Bool],[Int])
+perform [] = return ([],[])
+
+perform (a:as) =
+  case a of
+    ReturnInt v  -> liftM (\(b,l) -> (b,v:l)) (perform as)
+    ReturnBool v -> liftM (\(b,l) -> (v:b,l)) (perform as)
+    NewEmptyMVar -> newEmptyMVar >>= \mv -> perform' mv as
+    NewMVar n    -> newMVar n >>= \mv -> perform' mv as
+    _            -> error $ "Please use NewMVar or NewEmptyMVar as first "
+                            ++ "action"
+
+
+perform' :: MVar Int -> [Action] -> IO ([Bool],[Int])
+perform' _ [] = return ([],[])
+
+perform' mv (a:as) =
+  case a of
+    ReturnInt v  -> liftM (\(b,l) -> (b,v:l)) (perform' mv as)
+    ReturnBool v -> liftM (\(b,l) -> (v:b,l)) (perform' mv as)
+    TakeMVar     -> liftM2 (\v (b,l) -> (b,v:l)) (takeMVar mv)
+                                (perform' mv as)
+    ReadMVar     -> liftM2 (\v (b,l) -> (b,v:l)) (readMVar mv)
+                                (perform' mv as)
+    PutMVar n    -> putMVar mv n >> perform' mv as
+    SwapMVar n   -> swapMVar mv n >> perform' mv as
+    IsEmptyMVar  -> liftM2 (\v (b,l) -> (v:b,l)) (isEmptyMVar mv)
+                                (perform' mv as)
+    _            -> error $ "If you want to use " ++ show a
+                            ++ " please use the =^ operator"
+
+
+actions :: Gen [Action]
+actions =
+  oneof [liftM (NewEmptyMVar:) (actions' True),
+         liftM2 (:) (liftM NewMVar arbitrary) (actions' False)]
+
+
+actions' :: Bool -> Gen [Action]
+actions' empty =
+  oneof ([return [],
+          liftM (IsEmptyMVar:) (actions' empty)] ++
+          if empty
+             then [liftM2 (:) (liftM PutMVar arbitrary) (actions' False)]
+             else []
+          ++
+          if empty
+             then []
+             else [liftM (TakeMVar:) (actions' True)]
+          ++
+          if empty
+             then []
+             else [liftM (ReadMVar:) (actions' False)]
+          ++
+          if empty
+             then []
+             else [liftM2 (:) (liftM SwapMVar arbitrary) (actions' False)]   )
+
+
+(=^) :: [Action] -> [Action] -> Property
+c =^ c' =
+  forAll (actions' (delta True c))
+         (\suff -> observe c suff == observe c' suff)
+  where observe x suff = unsafePerformIO (perform (x++suff))
+
+
+(^=^) :: [Action] -> [Action] -> Property
+c ^=^ c' =
+  forAll actions
+         (\pref -> forAll (actions' (delta True (pref++c)))
+                          (\suff -> observe c pref suff ==
+                                      observe c' pref suff))
+  where observe x pref suff = unsafePerformIO (perform (pref++x++suff))
+
+
+delta :: Bool -> [Action] -> Bool
+delta b [] = b
+
+delta b (ReturnInt _:as) = delta b as
+
+delta b (ReturnBool _:as) = delta b as
+
+delta _ (NewEmptyMVar:as) = delta True as
+
+delta _ (NewMVar _:as) = delta False as
+
+delta b (TakeMVar:as) = delta (if b
+                                  then error "take on empty MVar"
+                                  else True) as
+
+delta b (ReadMVar:as) = delta (if b
+                                  then error "read on empty MVar"
+                                  else False) as
+
+delta _ (PutMVar _:as) = delta False as
+
+delta b (SwapMVar _:as) = delta (if b
+                                  then error "swap on empty MVar"
+                                  else False) as
+
+delta b (IsEmptyMVar:as) = delta b as
diff --git a/ghc-tests/tests/MaessenHashtab/Data/HashTab.hs b/ghc-tests/tests/MaessenHashtab/Data/HashTab.hs
new file mode 100644
index 0000000000000000000000000000000000000000..fe2d86769a48c0204e0679825b123b25ba68a959
--- /dev/null
+++ b/ghc-tests/tests/MaessenHashtab/Data/HashTab.hs
@@ -0,0 +1,340 @@
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.HashTable
+-- Copyright   :  (c) The University of Glasgow 2003
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- An implementation of extensible hash tables, as described in
+-- Per-Ake Larson, /Dynamic Hash Tables/, CACM 31(4), April 1988,
+-- pp. 446--457.  The implementation is also derived from the one
+-- in GHC's runtime system (@ghc\/rts\/Hash.{c,h}@).
+--
+-----------------------------------------------------------------------------
+
+module MaessenHashtab.Data.HashTab (
+        -- * Basic hash table operations
+        HashTable, new, insert, delete, lookup, update,
+        -- * Converting to and from lists
+        fromList, toList,
+        -- * Hash functions
+        -- $hash_functions
+        hashInt, hashString,
+        prime,
+        -- * Diagnostics
+        longestChain
+ ) where
+
+-- This module is imported by Data.Typeable, which is pretty low down in the
+-- module hierarchy, so don't import "high-level" modules
+
+-- Right now we import high-level modules with gay abandon.
+import Prelude  hiding  ( lookup )
+import Data.Tuple       ( fst )
+import Data.Bits
+import Data.Maybe
+import Data.List        ( maximumBy, partition )
+import Data.Int         ( Int32 )
+
+import Data.Array.Base
+import Data.Array       hiding (bounds)
+import Data.Array.IO
+
+import Data.Char        ( ord )
+import Data.IORef       ( IORef, newIORef, readIORef, writeIORef )
+import Control.Monad    ( mapM, sequence_ )
+
+
+-----------------------------------------------------------------------
+
+readHTArray  :: HTArray a -> Int32 -> IO a
+readMutArray  :: MutArray a -> Int32 -> IO a
+writeMutArray :: MutArray a -> Int32 -> a -> IO ()
+freezeArray  :: MutArray a -> IO (HTArray a)
+thawArray    :: HTArray a -> IO (MutArray a)
+newMutArray   :: (Int32, Int32) -> a -> IO (MutArray a)
+#if defined(DEBUG) || defined(__NHC__)
+type MutArray a = IOArray Int32 a
+type HTArray a = MutArray a
+newMutArray = newArray
+readHTArray  = readArray
+readMutArray = readArray
+writeMutArray = writeArray
+freezeArray = return
+thawArray = return
+#else
+type MutArray a = IOArray Int32 a
+type HTArray a = Array Int32 a
+newMutArray = newArray
+readHTArray arr i = return $! (unsafeAt arr (fromIntegral i))
+readMutArray arr i = unsafeRead arr (fromIntegral i)
+writeMutArray arr i x = unsafeWrite arr (fromIntegral i) x
+freezeArray = unsafeFreeze
+thawArray = unsafeThaw
+#endif
+
+newtype HashTable key val = HashTable (IORef (HT key val))
+-- TODO: the IORef should really be an MVar.
+
+data HT key val
+  = HT {
+        kcount  :: !Int32,              -- Total number of keys.
+        buckets :: !(HTArray [(key,val)]),
+        bmask   :: !Int32,
+        hash_fn :: key -> Int32,
+        cmp     :: key -> key -> Bool
+   }
+
+-- -----------------------------------------------------------------------------
+-- Sample hash functions
+
+-- $hash_functions
+--
+-- This implementation of hash tables uses the low-order /n/ bits of the hash
+-- value for a key, where /n/ varies as the hash table grows.  A good hash
+-- function therefore will give an even distribution regardless of /n/.
+--
+-- If your keyspace is integrals such that the low-order bits between
+-- keys are highly variable, then you could get away with using 'id'
+-- as the hash function.
+--
+-- We provide some sample hash functions for 'Int' and 'String' below.
+
+-- | A sample hash function for 'Int', implemented as simply @(x `mod` P)@
+-- where P is a suitable prime (currently 1500007).  Should give
+-- reasonable results for most distributions of 'Int' values, except
+-- when the keys are all multiples of the prime!
+--
+hashInt :: Int -> Int32
+hashInt = (`rem` prime) . fromIntegral
+
+-- | A sample hash function for 'String's.  The implementation is:
+--
+-- >    hashString = fromIntegral . foldr f 0
+-- >      where f c m = ord c + (m * 128) `rem` 1500007
+--
+-- which seems to give reasonable results.
+--
+hashString :: String -> Int32
+hashString = fromIntegral . foldl f 0
+  where f m c = ord c + (m * 128) `rem` fromIntegral prime
+
+-- | A prime larger than the maximum hash table size
+prime :: Int32
+prime = 1500007
+
+-- -----------------------------------------------------------------------------
+-- Parameters
+
+tABLE_MAX  = 1024 * 1024 :: Int32  -- Maximum size of hash table
+#if tABLE_MIN
+#else
+tABLE_MIN  = 16 :: Int32
+
+hLOAD = 4 :: Int32 -- Maximum average load of a single hash bucket
+
+hYSTERESIS = 0 :: Int32 -- entries to ignore in load computation
+#endif
+
+{- Hysteresis favors long association-list-like behavior for small tables. -}
+
+-- -----------------------------------------------------------------------------
+-- Creating a new hash table
+
+-- | Creates a new hash table.  The following property should hold for the @eq@
+-- and @hash@ functions passed to 'new':
+--
+-- >   eq A B  =>  hash A == hash B
+--
+new
+  :: (key -> key -> Bool)    -- ^ @eq@: An equality comparison on keys
+  -> (key -> Int32)          -- ^ @hash@: A hash function on keys
+  -> IO (HashTable key val)  -- ^ Returns: an empty hash table
+
+new cmpr hash = do
+  -- make a new hash table with a single, empty, segment
+  let mask = tABLE_MIN-1
+  bkts'  <- newMutArray (0,mask) []
+  bkts   <- freezeArray bkts'
+
+  let
+    kcnt = 0
+    ht = HT {  buckets=bkts, kcount=kcnt, bmask=mask,
+               hash_fn=hash, cmp=cmpr }
+
+  table <- newIORef ht
+  return (HashTable table)
+
+-- -----------------------------------------------------------------------------
+-- Inserting a key\/value pair into the hash table
+
+-- | Inserts a key\/value mapping into the hash table.
+--
+-- Note that 'insert' doesn't remove the old entry from the table -
+-- the behaviour is like an association list, where 'lookup' returns
+-- the most-recently-inserted mapping for a key in the table.  The
+-- reason for this is to keep 'insert' as efficient as possible.  If
+-- you need to update a mapping, then we provide 'update'.
+--
+insert :: HashTable key val -> key -> val -> IO ()
+
+insert (HashTable ref) key val = do
+  table@HT{ kcount=k, buckets=bkts, bmask=b } <- readIORef ref
+  let table1 = table{ kcount = k+1 }
+      indx = bucketIndex table key
+  bucket <- readHTArray bkts indx
+  bkts' <- thawArray bkts
+  writeMutArray bkts' indx ((key,val):bucket)
+  freezeArray bkts'
+  table2 <-
+        if tooBig k b
+           then expandHashTable table1
+           else return table1
+  writeIORef ref table2
+
+tooBig :: Int32 -> Int32 -> Bool
+tooBig k b = k-hYSTERESIS > hLOAD * b
+
+bucketIndex :: HT key val -> key -> Int32
+bucketIndex HT{ hash_fn=hash, bmask=mask } key =
+  let h = hash key
+  in  (h .&. mask)
+
+expandHashTable :: HT key val -> IO (HT key val)
+expandHashTable
+      table@HT{ buckets=bkts, bmask=mask } = do
+   let
+      oldsize = mask + 1
+      newmask = mask + mask + 1
+      newsize = newmask + 1
+   --
+   if newsize > tABLE_MAX
+      then return table
+      else do
+   --
+       newbkts' <- newMutArray (0,newmask) []
+
+       let
+        table'=table{ bmask=newmask }
+        splitBucket oldindex = do
+          bucket <- readHTArray bkts oldindex
+          let (oldb,newb) = partition ((oldindex==).bucketIndex table' . fst) bucket
+          writeMutArray newbkts' oldindex oldb
+          writeMutArray newbkts' (oldindex + oldsize) newb
+       mapM_ splitBucket [0..mask]
+
+       newbkts <- freezeArray newbkts'
+
+       return ( table'{ buckets=newbkts } )
+
+-- -----------------------------------------------------------------------------
+-- Deleting a mapping from the hash table
+
+-- Remove a key from a bucket
+deleteBucket :: (key -> Bool) -> [(key,val)] -> (Int32, [(key, val)])
+deleteBucket _   [] = (0,[])
+deleteBucket del (pair@(k,_):bucket) =
+  case deleteBucket del bucket of
+    (dels, bucket') | del k     -> dels' `seq` (dels', bucket')
+                    | otherwise -> (dels, pair:bucket')
+      where dels' = dels + 1
+
+-- | Remove an entry from the hash table.
+delete :: HashTable key val -> key -> IO ()
+
+delete (HashTable ref) key = do
+  table@HT{ buckets=bkts, kcount=kcnt, cmp=cmpr } <- readIORef ref
+  let indx = bucketIndex table key
+  bkts' <- thawArray bkts
+  bucket <- readMutArray bkts' indx
+  let (removed,bucket') = deleteBucket (cmpr key) bucket
+  writeMutArray bkts' indx bucket'
+  freezeArray bkts'
+  writeIORef ref ( table{kcount = kcnt - removed} )
+
+-- -----------------------------------------------------------------------------
+-- Updating a mapping in the hash table
+
+-- | Updates an entry in the hash table, returning 'True' if there was
+-- already an entry for this key, or 'False' otherwise.  After 'update'
+-- there will always be exactly one entry for the given key in the table.
+--
+-- 'insert' is more efficient than 'update' if you don't care about
+-- multiple entries, or you know for sure that multiple entries can't
+-- occur.  However, 'update' is more efficient than 'delete' followed
+-- by 'insert'.
+update :: HashTable key val -> key -> val -> IO Bool
+
+update (HashTable ref) key val = do
+  table@HT{ kcount=k, buckets=bkts, cmp=cmpr, bmask=b } <- readIORef ref
+  let indx = bucketIndex table key
+  bkts' <- thawArray bkts
+  bucket <- readMutArray bkts' indx
+  let (deleted,bucket') = deleteBucket (cmpr key) bucket
+      k' = k + 1 - deleted
+      table1 = table{ kcount=k' }
+
+  writeMutArray bkts' indx ((key,val):bucket')
+  freezeArray bkts'
+  table2 <-
+        if tooBig k' b          -- off by one from insert's resize heuristic.
+           then expandHashTable table1
+           else return table1
+  writeIORef ref table2
+  return (deleted>0)
+
+-- -----------------------------------------------------------------------------
+-- Looking up an entry in the hash table
+
+-- | Looks up the value of a key in the hash table.
+lookup :: HashTable key val -> key -> IO (Maybe val)
+
+lookup (HashTable ref) key = do
+  table@HT{ buckets=bkts, cmp=cmpr } <- readIORef ref
+  let indx = bucketIndex table key
+  bucket <- readHTArray bkts indx
+  case [ val | (key',val) <- bucket, cmpr key key' ] of
+        [] -> return Nothing
+        (v:_) -> return (Just v)
+
+-- -----------------------------------------------------------------------------
+-- Converting to/from lists
+
+-- | Convert a list of key\/value pairs into a hash table.  Equality on keys
+-- is taken from the Eq instance for the key type.
+--
+fromList :: (Eq key) => (key -> Int32) -> [(key,val)] -> IO (HashTable key val)
+fromList hash list = do
+  table <- new (==) hash
+  sequence_ [ insert table k v | (k,v) <- list ]
+  return table
+
+-- | Converts a hash table to a list of key\/value pairs.
+--
+toList :: (Ord key, Ord val) => HashTable key val -> IO [(key,val)]
+toList (HashTable ref) = do
+  HT{ buckets=bkts, bmask=b } <- readIORef ref
+  fmap concat (mapM (readHTArray bkts) [0..b])
+
+-- -----------------------------------------------------------------------------
+-- Diagnostics
+
+-- | This function is useful for determining whether your hash function
+-- is working well for your data set.  It returns the longest chain
+-- of key\/value pairs in the hash table for which all the keys hash to
+-- the same bucket.  If this chain is particularly long (say, longer
+-- than 10 elements), then it might be a good idea to try a different
+-- hash function.
+--
+longestChain :: HashTable key val -> IO [(key,val)]
+longestChain (HashTable ref) = do
+  HT{ buckets=bkts, bmask=b } <- readIORef ref
+  let lengthCmp (_:x)(_:y) = lengthCmp x y
+      lengthCmp []   []    = EQ
+      lengthCmp []   _     = LT
+      lengthCmp _    []    = GT
+  fmap (maximumBy lengthCmp) (mapM (readHTArray bkts) [0..b])
diff --git a/ghc-tests/tests/MaessenHashtab/HashTest.hs b/ghc-tests/tests/MaessenHashtab/HashTest.hs
new file mode 100644
index 0000000000000000000000000000000000000000..660dd8c2e5c2bffd06a1e0b43593c0f9005a4d86
--- /dev/null
+++ b/ghc-tests/tests/MaessenHashtab/HashTest.hs
@@ -0,0 +1,273 @@
+{- Test code for Data.HashTable -}
+
+module MaessenHashtab.HashTest(hashTest) where
+
+import Prelude hiding (lookup)
+import qualified Prelude (lookup)
+import Data.Maybe(isJust,isNothing)
+import Data.Int(Int32)
+import Test.QuickCheck
+import System.IO.Unsafe(unsafePerformIO)
+import MaessenHashtab.Data.HashTab
+import Control.Monad(liftM2, foldM)
+import System.Random
+import System.Environment
+import System.IO
+
+
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+infixr 0 ==.
+infixr 0 ==~
+infixr 0 ~~
+
+type HT = HashTable Int Int
+newtype HashFun = HF {unHF :: (Int -> Int32)}
+data Empty = E {e :: (IO HT), hfe :: HashFun}
+data MkH   = H {h :: (IO HT), hfh :: HashFun}
+newtype List a = L [a]
+
+data Action = Lookup Int
+            | Insert Int Int
+            | Delete Int
+            | Update Int Int
+            deriving (Show)
+
+instance Arbitrary Action where
+  arbitrary = frequency [(10,fmap Lookup arbitrary),
+                         (5, liftM2 Insert arbitrary arbitrary),
+                         (3, liftM2 Update arbitrary arbitrary),
+                         (1, fmap Delete arbitrary)]
+
+simA :: [Action] -> [Either Bool [Int]]
+simA = fst . foldl sim ([],[])
+  where sim :: ([Either Bool [Int]], [Action]) -> Action ->
+               ([Either Bool [Int]], [Action])
+        sim (res, past) (Lookup k)   = (Right (lkup k past) : res, past)
+        sim (res, past) (Insert k v) = (res, Insert k v : past)
+        sim (res, past) (Delete k)   = (res, Delete k   : past)
+        sim (res, past) (Update k v) =
+          (Left (not (null l)) : res, Update k v : past)
+          where l = lkup k past
+        lkup _ [] = []
+        lkup k (Delete k' : _)
+          | k==k' = []
+        lkup k (Update k' v : _)
+          | k==k'     = [v]
+        lkup k (Insert k' v : past)
+          | k==k'     = v:lkup k past
+        lkup k (_ : past) = lkup k past
+
+runA :: HashFun -> [Action] -> IO [Either Bool (Maybe Int)]
+runA hf acts = do
+  ht <- new (==) (unHF hf)
+  let run res (Lookup a) = fmap (lkup res) $ lookup ht a
+      run res (Insert k v) = insert ht k v >> return res
+      run res (Delete k)   = delete ht k   >> return res
+      run res (Update k v) = fmap (upd res) $ update ht k v
+      lkup res m = Right m : res
+      upd res b = Left b : res
+  foldM run [] acts
+
+(~~) :: IO [Either Bool (Maybe Int)] -> [Either Bool [Int]] -> Bool
+acts ~~ sims = and $ zipWith same (unsafePerformIO acts) sims
+  where same (Left b)         (Left b')  = b==b'
+        same (Right Nothing)  (Right []) = True
+        same (Right (Just a)) (Right xs) = a `elem` xs
+        same _                _          = False
+
+lookups :: HT -> [Int] -> IO [Maybe Int]
+lookups ht ks = mapM (lookup ht) ks
+
+instance Show HashFun where
+  showsPrec _ (HF hf) r
+      | hf 1 == 0 = "degenerate"++r
+      | otherwise = "usual"++r
+
+instance Show Empty where
+  showsPrec _ ee r = shows (hfe ee) r
+
+instance Show MkH where
+  showsPrec _ hh r = shows (hfh hh) $
+                     ("; "++shows (unsafePerformIO (h hh >>= toList)) r)
+
+instance Show a => Show (List a) where
+  showsPrec _ (L l) r = shows l r
+
+instance Arbitrary HashFun where
+  arbitrary = frequency [(20,return (HF hashInt)),
+                         (1,return (HF (const 0)))]
+
+instance Arbitrary Empty where
+  arbitrary = fmap mkE arbitrary
+    where mkE (HF hf) = E {e = new (==) hf, hfe=HF hf}
+
+instance Arbitrary a => Arbitrary (List a) where
+  arbitrary = do
+    sz <- frequency [(50, sized return),
+                     (1,return (4096*2)),
+                     (0, return (1024*1024))]
+    resize sz $ fmap L $ sized vector
+
+instance Arbitrary MkH where
+  arbitrary = do
+    hf <- arbitrary
+    L list <- arbitrary
+    let mkH act = H { h = act, hfh = hf }
+    return (mkH . fromList (unHF hf) $ list)
+
+(==~) :: (Eq a) => IO a -> IO a -> Bool
+act1 ==~ act2 = unsafePerformIO act1 == unsafePerformIO act2
+
+(==.) :: (Eq a) => IO a -> a -> Bool
+act ==. v = unsafePerformIO act == v
+
+notin :: (Testable a) => Int -> MkH -> a -> Property
+k `notin` hh = \prop ->
+  let f = (not . isJust . unsafePerformIO) (h hh >>= flip lookup k) in
+  f `trivial` prop
+
+prop_emptyLookup :: Empty -> Int -> Bool
+prop_emptyLookup ee k =
+  isNothing . unsafePerformIO $
+  (do mt <- e ee
+      lookup mt k)
+
+prop_emptyToList :: Empty -> Bool
+prop_emptyToList ee =
+  (do mt <- e ee
+      toList mt) ==. []
+
+prop_emptyFromList :: HashFun -> Int -> Bool
+prop_emptyFromList hf k =
+  (do mt <- new (==) (unHF hf) :: IO HT
+      lookup mt k) ==~
+  (do mt <- fromList (unHF hf) []
+      lookup mt k)
+
+prop_insert :: MkH -> Int -> Int -> Bool
+prop_insert hh k v =
+  (do ht <- h hh
+      insert ht k v
+      lookup ht k) ==. Just v
+
+prop_insertu :: MkH -> Int -> Int -> List Int -> Bool
+prop_insertu hh k v (L ks) =
+  let ks' = filter (k /=) ks in
+  (do ht <- h hh
+      insert ht k v
+      lookups ht ks') ==~
+  (do ht <- h hh
+      lookups ht ks')
+
+prop_delete :: MkH -> Int -> Property
+prop_delete hh k =
+  k `notin` hh $
+  isNothing . unsafePerformIO $
+  (do ht <- h hh
+      delete ht k
+      lookup ht k)
+
+prop_deleteu :: MkH -> Int -> List Int -> Bool
+prop_deleteu hh k (L ks) =
+  let ks' = filter (k /=) ks in
+  (do ht <- h hh
+      delete ht k
+      lookups ht ks') ==~
+  (do ht <- h hh
+      lookups ht ks')
+
+naiveUpdate :: HT -> Int -> Int -> IO ()
+naiveUpdate ht k v = do
+  delete ht k
+  insert ht k v
+
+prop_update :: MkH -> Int -> Int -> List Int -> Bool
+prop_update hh k v (L ks) =
+  (do ht <- h hh
+      _ <- update ht k v
+      lookups ht ks) ==~
+  (do ht <- h hh
+      naiveUpdate ht k v
+      lookups ht ks)
+
+prop_updatec :: MkH -> Int -> Int -> Bool
+prop_updatec hh k v =
+  (do ht <- h hh
+      _ <- update ht k v
+      lookup ht k) ==. Just v
+
+prop_updateLookup :: MkH -> Int -> Int -> Property
+prop_updateLookup hh k v =
+  k `notin` hh $
+  (do ht <- h hh
+      update ht k v) ==~
+  (do ht <- h hh
+      fmap isJust (lookup ht k))
+
+prop_simulation :: HashFun -> List Action -> Property
+prop_simulation hf (L acts) =
+  (null acts `trivial`) $
+  runA hf acts ~~ simA acts
+
+trivial b = classify b "trivial"
+
+{-
+
+For "fromList" and "toList" properties we're a bit sloppy: we perform
+multiple insertions for a key (potentially) but give nor promises
+about which one we will retrieve with lookup, or what order they'll be
+returned by toList (or if they'll all be returned at all).  Thus we
+insert all occurrences of a key with the same value, and do all
+checking via lookups.
+
+-}
+
+prop_fromList :: HashFun -> List Int -> List Int -> Property
+prop_fromList hf (L l) (L ks) =
+  null l `trivial`
+  let assocs = map (\t -> (t,t)) l in
+  ( do ht <- fromList (unHF hf) assocs
+       lookups ht ks) ==. (map (`Prelude.lookup` assocs) ks)
+
+prop_fromListInsert :: HashFun -> List (Int,Int) -> Int -> Int -> List Int -> Property
+prop_fromListInsert hf (L l) k v (L ks) =
+  null l `trivial`
+  (( do ht <- fromList (unHF hf) l
+        insert ht k v
+        lookups ht ks) ==~
+   ( do ht <- fromList (unHF hf) (l++[(k,v)])
+        lookups ht ks))
+
+prop_toList :: HashFun -> List Int -> List Int -> Property
+prop_toList hf (L l) (L ks) =
+  null l `trivial`
+  let assocs = map (\t -> (t,t)) l in
+  ( do ht <- fromList (unHF hf) assocs
+       lookups ht ks) ==~
+  ( do ht <- fromList (unHF hf) assocs
+       fmap (\as -> map (`Prelude.lookup` as) ks) $ toList ht )
+
+
+hashTest :: TestTree
+hashTest =
+  testGroup "hashTest" $
+    [ te "emptyLookup:" prop_emptyLookup,
+      te "emptyToList:" prop_emptyToList,
+      te "emptyFromList:" prop_emptyFromList,
+      te "insert:" prop_insert,
+      te "insertu:" prop_insertu,
+      te "delete:" prop_delete,
+      te "deleteu:" prop_deleteu,
+      te "update:" prop_update,
+      te "updatec:" prop_updatec,
+      te "updateLookup:" prop_updateLookup,
+      te "fromList:" prop_fromList,
+      te "fromListInsert:" prop_fromListInsert,
+      te "toList:" prop_toList,
+      te "simulation:" prop_simulation
+    ]
+
+  where
+  te name prop = testProperty name prop
diff --git a/ghc-tests/tests/Main.hs b/ghc-tests/tests/Main.hs
index b18367d5d78233ed941e980045c0718a7301b3a8..cb78f7e7981c4edc10d04fc62d8f39e57cca82a7 100644
--- a/ghc-tests/tests/Main.hs
+++ b/ghc-tests/tests/Main.hs
@@ -1,6 +1,75 @@
+{-# LANGUAGE NumericUnderscores #-}
 module Main where
 
 import System.Exit
 
+import Chan001
+import MVar001
+import qualified HClose003
+import qualified Concio002
+import qualified Rand001
+import qualified HWaitPipe
+import qualified HWaitSocket
+import qualified Cgrun068
+import qualified T7953
+import qualified CopySmallArrayStressTest
+import qualified T367
+import qualified T367A
+import qualified Throwto001
+import qualified PerformGC
+import qualified Conc023
+import qualified CompareAndSwap
+import qualified T13916
+import qualified T8138
+import qualified Drvrun022
+import qualified T3087
+import qualified FFI009
+import qualified T2267
+import qualified T14768
+import qualified T15038.Main
+import qualified TC191
+import qualified TC220
+import qualified T12926
+import qualified T14854
+import qualified T15038.Main as T15038
+import qualified MaessenHashtab.HashTest as HashTest
+import Arr016
+
+import Test.Tasty
+import Test.Tasty.HUnit
+import Tasty.Bronze
+import qualified Test.Tasty.Silver.Interactive as I
+
+bronzeDir = "bronze/"
+
 main :: IO ()
-main = return ()
+main = defaultMainWithIngredients (I.interactiveTests (const False) : defaultIngredients) $
+        testGroup "all" [ testChan
+                        , testMVar
+                        , arr016
+                        -- flaky
+                        -- , goldenVsOut "hClose003" "bronze/hClose003.out" HClose003.main
+                        , goldenVsOut "concio002" "bronze/concio002.out" Concio002.main
+                        , goldenVsOut "rand001" "bronze/rand001.out" Rand001.main
+                        , goldenVsOut "hwaitPipe" "bronze/hwaitPipe.out" HWaitPipe.main
+                        , goldenVsOut "hwaitSocket" "bronze/hwaitSocket.out" HWaitSocket.main
+                        , goldenVsOut "cgrun068" "bronze/cgrun068.out" (Cgrun068.main 100)
+                        , goldenVsOut "CopySmallArrayStressTest" "bronze/CopySmallArrayStressTest.out" (CopySmallArrayStressTest.main 100)
+                        , goldenVsOut "T7953" "bronze/T7953.out" T7953.main
+                        , goldenVsOut "T367" "bronze/T367.out" T367.main
+                        , goldenVsOut "CompareAndSwap" "bronze/CompareAndSwap.out" CompareAndSwap.main
+                        , goldenVsOut "T8138" "bronze/T8138.out" T8138.main
+                        , goldenVsOut "Drvrun022" "bronze/Drvrun022.out" Drvrun022.main
+                        , goldenVsOut "T3087" "bronze/T3087.out" T3087.main
+                        , goldenVsOut "FFI009" "bronze/FFI009.out" FFI009.main
+                        , HashTest.hashTest
+                        , goldenVsOut "T14768" "bronze/T14768.out" T14768.main
+                        , goldenVsOut "T14854" "bronze/T14854.out" T14854.main
+                        , goldenVsOut "T14854" "bronze/T15038.out" T15038.main
+
+                        , localOption (mkTimeout 2_000_000) $ goldenVsOut "T367A" "bronze/T367A.out" T367A.main
+                        , testCase "Throwto001" (Throwto001.main 1000 2000)
+                        , testCase "PerformGC" (PerformGC.main 400)
+                        , testCase "Conc023" Conc023.main
+                        , testCase "T13916" T13916.main
+                        ]
diff --git a/ghc-tests/tests/PerformGC.hs b/ghc-tests/tests/PerformGC.hs
new file mode 100644
index 0000000000000000000000000000000000000000..853fdcd08c1d8a9249c66223577f100723202329
--- /dev/null
+++ b/ghc-tests/tests/PerformGC.hs
@@ -0,0 +1,23 @@
+module PerformGC (main) where
+
+-- Test for #10545
+
+import System.Environment
+import Control.Concurrent
+import Control.Exception
+import Control.Monad
+import System.Random
+import System.Mem
+import qualified Data.Set as Set
+
+main n = do
+  forkIO $ doSomeWork
+  forM_ [1..n] $ \n -> do threadDelay 1000; performMinorGC
+
+doSomeWork :: IO ()
+doSomeWork = forever $ do
+  ns <- replicateM 10000 randomIO :: IO [Int]
+  ms <- replicateM 1000 randomIO
+  let set = Set.fromList ns
+      elems = filter (`Set.member` set) ms
+  evaluate $ sum elems
diff --git a/ghc-tests/tests/Rand001.hs b/ghc-tests/tests/Rand001.hs
new file mode 100644
index 0000000000000000000000000000000000000000..96da02a8e7583102543b570bd371c3166c218222
--- /dev/null
+++ b/ghc-tests/tests/Rand001.hs
@@ -0,0 +1,23 @@
+module Rand001(main) where
+
+import System.Random
+import System.IO
+
+tstRnd rng = checkRange rng (genRnd 50 rng)
+
+genRnd n rng = take n (randomRs rng (mkStdGen 2))
+
+checkRange (lo,hi) = all pred
+  where
+   pred
+    | lo <= hi  = \ x -> x >= lo && x <= hi
+    | otherwise = \ x -> x >= hi && x <= lo
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+  hPrint stdout (tstRnd (1,5::Double))
+  hPrint stdout (tstRnd (1,5::Int))
+  hPrint stdout (tstRnd (10,54::Integer))
+  hPrint stdout (tstRnd ((-6),2::Int))
+  hPrint stdout (tstRnd (2,(-6)::Int))
+
diff --git a/ghc-tests/tests/T12926.hs b/ghc-tests/tests/T12926.hs
new file mode 100644
index 0000000000000000000000000000000000000000..66ed946b60c89318434041a3501a4f778fb3d628
--- /dev/null
+++ b/ghc-tests/tests/T12926.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# OPTIONS_GHC -O2 #-}
+
+module T12926 where
+
+import GHC.Base
+import qualified Data.Vector.Unboxed.Base
+import qualified Data.Vector.Generic.Base
+import Data.Vector.Generic.Mutable
+import qualified Data.Vector.Generic.Mutable.Base
+import Data.Vector.Generic (fromList)
+
+data A = A Int Int Int
+
+instance Data.Vector.Unboxed.Base.Unbox A
+
+newtype instance Data.Vector.Unboxed.Base.MVector s_a4iX A
+  = MV_A (Data.Vector.Unboxed.Base.MVector s_a4iX (Int, Int, Int))
+
+instance MVector Data.Vector.Unboxed.Base.MVector A where
+  basicLength (MV_A v) =
+    basicLength v
+  basicUnsafeSlice idx len (MV_A v) =
+    MV_A (basicUnsafeSlice idx len v)
+  basicUnsafeNew len =
+    MV_A `liftM` (basicUnsafeNew len)
+  basicUnsafeWrite (MV_A v) idx val_a4iW =
+    basicUnsafeWrite v idx ((\ (A a_a4iT b_a4iU c_a4iV) -> (a_a4iT, b_a4iU, c_a4iV)) val_a4iW)
+
+newtype instance Data.Vector.Unboxed.Base.Vector A =
+  V_A (Data.Vector.Unboxed.Base.Vector (Int, Int, Int))
+
+instance Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector A where
+
+mkA :: Data.Vector.Unboxed.Base.Vector A
+mkA = fromList []
diff --git a/ghc-tests/tests/T13916.hs b/ghc-tests/tests/T13916.hs
new file mode 100755
index 0000000000000000000000000000000000000000..09496d5f2c227a06ce7ded3160de254b99bf9ab7
--- /dev/null
+++ b/ghc-tests/tests/T13916.hs
@@ -0,0 +1,33 @@
+module T13916 where
+
+import Data.IORef
+import System.IO.Unsafe
+import Control.Concurrent.STM
+import Control.Concurrent.Async
+import Control.Concurrent
+import System.IO
+import System.Directory
+import System.FilePath
+import T13916_Bracket
+
+type Thing = MVar Bool
+
+main :: IO ()
+main = do
+    withEnvCache limit spawner $ \cache ->
+        forConcurrently_ [1..1000 :: Int] $ \n -> withEnv cache (\handle -> put handle n)
+    where
+        limit :: Limit
+        limit = Hard 1
+
+        put handle n = return ()
+
+spawner :: Spawner Thing
+spawner = Spawner
+    { maker  = mkhandle
+    , killer = \thing -> takeMVar thing >> putMVar thing True
+    , isDead = \thing -> readMVar thing
+    }
+
+mkhandle :: IO Thing
+mkhandle = newMVar False
diff --git a/ghc-tests/tests/T13916_Bracket.hs b/ghc-tests/tests/T13916_Bracket.hs
new file mode 100755
index 0000000000000000000000000000000000000000..45b13733739e015f5aae2e11acd80ee50f232639
--- /dev/null
+++ b/ghc-tests/tests/T13916_Bracket.hs
@@ -0,0 +1,135 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecordWildCards #-}
+{- |
+Module      : Bracket
+Description : Handling multiple environments with bracket-like apis
+Maintainer  : robertkennedy@clearwateranalytics.com
+Stability   : stable
+
+This module is meant for ie Sql or mongo connections, where you may wish for some number of easy to grab
+environments. In particular, this assumes your connection has some initialization/release functions
+
+This module creates bugs with any optimizations enabled. The bugs do not occur if the program is in the same
+module.
+-}
+module T13916_Bracket (
+    -- * Data Types
+    Spawner(..), Limit(..), Cache,
+    -- * Usage
+    withEnvCache, withEnv
+    ) where
+
+import Control.Concurrent.STM
+import Control.Concurrent.STM.TSem
+import Control.Exception hiding (handle)
+import Control.Monad
+import Data.Vector (Vector)
+import qualified Data.Vector as Vector
+
+-- * Data Types
+-- | Tells the program how many environments it is allowed to spawn.
+-- A `Lax` limit will spawn extra connections if the `Cache` is empty,
+-- while a `Hard` limit will not spawn any more than the given number of connections simultaneously.
+--
+-- @since 0.3.7
+data Limit = Hard {getLimit :: {-# unpack #-} !Int}
+
+data Spawner env = Spawner
+    { maker  :: IO env
+    , killer :: env -> IO ()
+    , isDead :: env -> IO Bool
+    }
+
+type VCache env = Vector (TMVar env)
+data Cache env = Unlimited { spawner :: Spawner env
+                           , vcache :: !(VCache env)
+                           }
+               | Limited   { spawner :: Spawner env
+                           , vcache :: !(VCache env)
+                           , envsem :: TSem
+                           }
+
+-- ** Initialization
+withEnvCache :: Limit -> Spawner env -> (Cache env -> IO a) -> IO a
+withEnvCache limit spawner = bracket starter releaseCache
+    where starter = case limit of
+            Hard n -> Limited spawner <$> initializeEmptyCache n <*> atomically (newTSem (fromIntegral n))
+
+-- ** Using a single value
+withEnv :: Cache env -> (env -> IO a) -> IO a
+withEnv cache = case cache of
+    Unlimited{..} -> withEnvUnlimited spawner vcache
+    Limited{..}   -> withEnvLimited   spawner vcache envsem
+
+-- *** Unlimited
+-- | Takes an env and returns it on completion of the function.
+-- If all envs are already taken or closed, this will spin up a new env.
+-- When the function finishes, this will attempt to put the env into the cache. If it cannot,
+-- it will kill the env. Note this can lead to many concurrent connections.
+--
+-- @since 0.3.5
+withEnvUnlimited :: Spawner env -> VCache env -> (env -> IO a) -> IO a
+withEnvUnlimited Spawner{..} cache = bracket taker putter
+  where
+    taker = do
+        mpipe <- atomically $ tryTakeEnv cache
+        case mpipe of
+            Nothing  -> maker
+            Just env -> isDead env >>= \b -> if not b then return env else killer env >> maker
+
+    putter env = do
+        accepted <- atomically $ tryPutEnv cache env
+        unless accepted $ killer env
+
+-- *** Limited
+-- | Takes an env and returns it on completion of the function.
+-- If all envs are already taken, this will wait. This should have a constant number of environments
+--
+-- @since 0.3.6
+withEnvLimited :: Spawner env -> VCache env -> TSem -> (env -> IO a) -> IO a
+withEnvLimited spawner vcache envsem = bracket taker putter
+  where
+    taker = limitMakeEnv spawner vcache envsem
+    putter env = atomically $ putEnv vcache env
+
+limitMakeEnv :: Spawner env -> VCache env -> TSem -> IO env
+limitMakeEnv Spawner{..} vcache envsem = go
+  where
+    go = do
+        eenvpermission <- atomically $ ( Left  <$> takeEnv  vcache )
+                              `orElse` ( Right <$> waitTSem envsem )
+        case eenvpermission of
+            Right () -> maker
+            Left env -> do
+                -- Given our env, we check if it's dead. If it's not, we are done and return it.
+                -- If it is dead, we release it, signal that a new env can be created, and then recurse
+                isdead <- isDead env
+                if not isdead then return env
+                    else do
+                         killer env
+                         atomically $ signalTSem envsem
+                         go
+
+-- * Low level
+initializeEmptyCache :: Int -> IO (VCache env)
+initializeEmptyCache n | n < 1     = return mempty
+                       | otherwise = Vector.replicateM n newEmptyTMVarIO
+
+takeEnv :: VCache env -> STM env
+takeEnv = Vector.foldl folding retry
+    where folding m stmenv = m `orElse` takeTMVar stmenv
+
+tryTakeEnv :: VCache env -> STM (Maybe env)
+tryTakeEnv cache = (Just <$> takeEnv cache) `orElse` pure Nothing
+
+putEnv :: VCache env -> env -> STM ()
+putEnv cache env = Vector.foldl folding retry cache
+    where folding m stmenv = m `orElse` putTMVar stmenv env
+
+tryPutEnv :: VCache env -> env -> STM Bool
+tryPutEnv cache env = (putEnv cache env *> return True) `orElse` pure False
+
+releaseCache :: Cache env -> IO ()
+releaseCache cache = Vector.mapM_ qkRelease (vcache cache)
+    where qkRelease tenv = atomically (tryTakeTMVar tenv)
+                       >>= maybe (return ()) (killer $ spawner cache)
diff --git a/ghc-tests/tests/T14768.hs b/ghc-tests/tests/T14768.hs
new file mode 100644
index 0000000000000000000000000000000000000000..e8a82cf333db991173040878ccad2943092b1a73
--- /dev/null
+++ b/ghc-tests/tests/T14768.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE MagicHash             #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies          #-}
+
+module T14768 where
+
+import Control.Monad (forM_, liftM)
+import qualified Data.Vector.Generic         as G
+import qualified Data.Vector.Generic.Mutable as M
+import qualified Data.Vector.Primitive as P
+import qualified Data.Vector.Unboxed         as U
+import qualified Data.Vector.Unboxed.Mutable as MU
+import GHC.Exts
+import System.IO
+
+vec :: U.Vector Moebius
+vec = U.singleton Moebius0
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = hPrint stdout $ U.head vec == U.head vec
+
+data Moebius = Moebius0 | Moebius1 | Moebius2
+  deriving (Eq)
+
+fromMoebius :: Moebius -> Int
+fromMoebius Moebius0 = 0
+fromMoebius Moebius1 = 1
+fromMoebius Moebius2 = 2
+
+toMoebius :: Int -> Moebius
+toMoebius (I# i#) = tagToEnum# i#
+
+newtype instance U.MVector s Moebius = MV_Moebius (P.MVector s Int)
+newtype instance U.Vector    Moebius = V_Moebius  (P.Vector    Int)
+
+instance U.Unbox Moebius
+
+instance M.MVector U.MVector Moebius where
+  basicLength (MV_Moebius v) = M.basicLength v
+  basicUnsafeSlice i n (MV_Moebius v) = MV_Moebius $ M.basicUnsafeSlice i n v
+  basicOverlaps (MV_Moebius v1) (MV_Moebius v2) = M.basicOverlaps v1 v2
+  basicUnsafeNew n = MV_Moebius `liftM` M.basicUnsafeNew n
+  basicInitialize (MV_Moebius v) = M.basicInitialize v
+  basicUnsafeReplicate n x = MV_Moebius `liftM` M.basicUnsafeReplicate n (fromMoebius x)
+  basicUnsafeRead (MV_Moebius v) i = toMoebius `liftM` M.basicUnsafeRead v i
+  basicUnsafeWrite (MV_Moebius v) i x = M.basicUnsafeWrite v i (fromMoebius x)
+  basicClear (MV_Moebius v) = M.basicClear v
+  basicSet (MV_Moebius v) x = M.basicSet v (fromMoebius x)
+  basicUnsafeCopy (MV_Moebius v1) (MV_Moebius v2) = M.basicUnsafeCopy v1 v2
+  basicUnsafeMove (MV_Moebius v1) (MV_Moebius v2) = M.basicUnsafeMove v1 v2
+  basicUnsafeGrow (MV_Moebius v) n = MV_Moebius `liftM` M.basicUnsafeGrow v n
+
+instance G.Vector U.Vector Moebius where
+  basicUnsafeFreeze (MV_Moebius v) = V_Moebius `liftM` G.basicUnsafeFreeze v
+  basicUnsafeThaw (V_Moebius v) = MV_Moebius `liftM` G.basicUnsafeThaw v
+  basicLength (V_Moebius v) = G.basicLength v
+  basicUnsafeSlice i n (V_Moebius v) = V_Moebius $ G.basicUnsafeSlice i n v
+  basicUnsafeIndexM (V_Moebius v) i = toMoebius `liftM` G.basicUnsafeIndexM v i
+  basicUnsafeCopy (MV_Moebius mv) (V_Moebius v) = G.basicUnsafeCopy mv v
+  elemseq _ = seq
diff --git a/ghc-tests/tests/T14854.hs b/ghc-tests/tests/T14854.hs
new file mode 100644
index 0000000000000000000000000000000000000000..070a94edebf57ed9599c03544675a91a53a6c5ac
--- /dev/null
+++ b/ghc-tests/tests/T14854.hs
@@ -0,0 +1,87 @@
+{-# LANGUAGE RecordWildCards #-}
+module T14854 (main) where
+
+import GHC.Data.FastString
+
+import Control.Concurrent
+import Control.DeepSeq
+import Control.Exception
+import Control.Monad
+import Data.ByteString (ByteString)
+import Data.ByteString.Builder
+import qualified Data.ByteString.Char8 as Char
+import Data.ByteString.Lazy (toStrict)
+import Data.List (transpose)
+import Data.Monoid
+import qualified Data.Sequence as Seq
+import Data.Time
+import GHC.Conc
+import System.IO
+import System.Random
+import Text.Printf
+
+data Options = Options
+  { optThreads :: Int   -- ^ the number of threads to run concurrently
+  , optRepeat :: Int    -- ^ how many times do we create the same 'FastString'
+  , optCount :: Int     -- ^ the total number of different 'FastString's
+  , optPrefix :: Int    -- ^ the length of prefix in each 'FastString'
+  }
+
+defOptions :: Options
+defOptions = Options
+  { optThreads = 8
+  , optRepeat = 16
+  , optCount = 10000
+  , optPrefix = 0
+  }
+
+run :: [[ByteString]] -> (ByteString -> Int) -> IO Int
+run jobs op = do
+  mvars <- forM ([0 ..] `zip` jobs) $ \(i, job) -> do
+    mvar <- newEmptyMVar
+    forkOn i $ do
+      uniq <- evaluate $ force $ maximum $ map op job
+      putMVar mvar uniq
+    return mvar
+  uniqs <- mapM takeMVar mvars
+  evaluate $ force $ maximum uniqs - 603979775
+
+summary :: IO [[[a]]] -> IO Int
+summary getTable = do
+  table <- getTable
+  evaluate $ force $ length $ concat $ concat table
+
+timeIt :: String -> IO a -> IO a
+timeIt name io = do
+  before <- getCurrentTime
+  ret <- io
+  after <- getCurrentTime
+  hPrintf stderr "%s: %.2fms\n" name
+    (realToFrac $ diffUTCTime after before * 1000 :: Double)
+  return ret
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+  seed <- randomIO
+  let Options{..} = defOptions
+      shuffle (i:is) s
+        | Seq.null s = []
+        | otherwise = m: shuffle is (l <> r)
+        where
+          (l, m Seq.:< r) = Seq.viewl <$> Seq.splitAt (i `rem` Seq.length s) s
+      inputs =
+        shuffle (randoms $ mkStdGen seed) $
+        mconcat $ replicate optRepeat $
+        Seq.fromFunction optCount $ \i -> toStrict $ toLazyByteString $
+          byteString (Char.replicate optPrefix '_') <> intDec i
+  jobs <- evaluate $ force $ transpose $
+    map (take optThreads) $
+    takeWhile (not . null) $
+    iterate (drop optThreads) inputs
+  setNumCapabilities (length jobs)
+  -- The maximum unique may be greater than 'optCount'
+  u <- timeIt "run" $ run jobs $ uniqueOfFS . mkFastStringByteString
+  print $ optCount <= u && u <= min optThreads optRepeat * optCount
+  -- But we should never have duplicate 'FastString's in the table
+  n <- timeIt "summary" $ summary getFastStringTable
+  hPrint stdout $ n == optCount
diff --git a/ghc-tests/tests/T15038/Data/Trie/Naive.hs b/ghc-tests/tests/T15038/Data/Trie/Naive.hs
new file mode 100644
index 0000000000000000000000000000000000000000..f0a38a5b8f938b49a133cdb5822a86755f25fa5a
--- /dev/null
+++ b/ghc-tests/tests/T15038/Data/Trie/Naive.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE DeriveFunctor #-}
+
+module T15038.Data.Trie.Naive
+  ( Trie
+  , singleton
+  , singletonString
+  , lookup
+  , parser
+  , fromList
+  , fromListAppend
+  , fromStringList
+  ) where
+
+import Prelude hiding (lookup)
+
+import Data.Semigroup (Semigroup)
+import Data.Word (Word8)
+import Data.Map (Map)
+import Data.Bifunctor (second)
+import T15038.Packed.Bytes (Bytes)
+import qualified Data.Char
+import qualified Data.List as L
+import qualified T15038.Packed.Bytes.Parser as P
+import qualified T15038.Packed.Bytes as B
+import qualified Data.Semigroup as SG
+import qualified Data.Map.Strict as M
+
+data Trie a = Trie (Maybe a) (Map Word8 (Trie a))
+  deriving (Functor)
+
+instance Semigroup a => Semigroup (Trie a) where
+  (<>) = append
+
+instance Semigroup a => Monoid (Trie a) where
+  mempty = Trie Nothing M.empty
+  mappend = (SG.<>)
+
+append :: Semigroup a => Trie a -> Trie a -> Trie a
+append (Trie v1 m1) (Trie v2 m2) = Trie
+  (v1 SG.<> v2)
+  (M.unionWith append m1 m2)
+
+singleton :: Bytes -> a -> Trie a
+singleton k v = B.foldr (\b r -> Trie Nothing (M.singleton b r)) (Trie (Just v) M.empty) k
+
+singletonString :: String -> a -> Trie a
+singletonString k v = L.foldr (\c r -> Trie Nothing (M.singleton (c2w c) r)) (Trie (Just v) M.empty) k
+
+lookup :: Bytes -> Trie a -> Maybe a
+lookup k t0 = case B.foldr lookupStep (Just t0) k of
+  Nothing -> Nothing
+  Just (Trie v _) -> v
+
+lookupStep :: Word8 -> Maybe (Trie a) -> Maybe (Trie a)
+lookupStep w Nothing = Nothing
+lookupStep w (Just (Trie _ m)) = M.lookup w m
+
+parser :: Trie (P.Parser a) -> P.Parser a
+parser (Trie mp m) = case mp of
+  Just p -> p
+  Nothing -> do
+    w <- P.any
+    case M.lookup w m of
+      Nothing -> P.failure
+      Just t -> parser t
+
+fromList :: [(Bytes,a)] -> Trie a
+fromList = fmap SG.getFirst . fromListAppend . map (second SG.First)
+
+fromListAppend :: Semigroup a => [(Bytes,a)] -> Trie a
+fromListAppend = foldMap (uncurry singleton)
+
+fromStringList :: [(String,a)] -> Trie a
+fromStringList = fmap SG.getFirst . fromStringListAppend . map (second SG.First)
+
+fromStringListAppend :: Semigroup a => [(String,a)] -> Trie a
+fromStringListAppend = foldMap (uncurry singletonString)
+
+c2w :: Char -> Word8
+c2w = fromIntegral . Data.Char.ord
diff --git a/ghc-tests/tests/T15038/Main.hs b/ghc-tests/tests/T15038/Main.hs
new file mode 100644
index 0000000000000000000000000000000000000000..dbf7000c4ac9e016ad53f78a29f67e37dd8c87e4
--- /dev/null
+++ b/ghc-tests/tests/T15038/Main.hs
@@ -0,0 +1,6 @@
+module T15038.Main where
+import qualified T15038.Parser as Parser
+import System.IO
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = hPrint stdout (iterate Parser.byteParserBadOnce 5 !! 100000)
diff --git a/ghc-tests/tests/T15038/Makefile b/ghc-tests/tests/T15038/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48493c08ef2426d2ae5bd3c307644f4451771d7e
--- /dev/null
+++ b/ghc-tests/tests/T15038/Makefile
@@ -0,0 +1,15 @@
+TOP=../../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+.PHONY: T15038
+T15038:
+	'$(TEST_HC)' $(TEST_HC_OPTS)  -O2 -o Main \
+	  ./test/Main.hs \
+	  ./test/Parser.hs \
+	  ./src/Packed/Bytes/Stream/ST.hs \
+	  ./src/Packed/Bytes/Parser.hs \
+	  ./src/Packed/Bytes.hs \
+	  ./common/Data/Trie/Naive.hs \
+		-package containers -package ghc-prim -package primitive
+	./Main
diff --git a/ghc-tests/tests/T15038/Packed/Bytes.hs b/ghc-tests/tests/T15038/Packed/Bytes.hs
new file mode 100644
index 0000000000000000000000000000000000000000..ecd57feaeac21114fc9a8fb372f4ff9635f51b8d
--- /dev/null
+++ b/ghc-tests/tests/T15038/Packed/Bytes.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-# OPTIONS_GHC
+ -fno-warn-unsafe
+ -fno-warn-implicit-prelude
+ -fno-warn-missing-import-lists
+ -O2
+#-}
+
+module T15038.Packed.Bytes
+  ( Bytes(..)
+  , pack
+  , unpack
+  , length
+    -- * Folds
+  , foldr
+    -- * Unsliced Byte Arrays
+  , fromByteArray
+  ) where
+
+import Prelude hiding (take,length,replicate,drop,null,concat,foldr)
+
+import Data.Primitive (ByteArray(..))
+import Data.Word (Word8)
+import Control.Monad.ST (runST, ST)
+import qualified Data.Primitive as PM
+import qualified Data.List as L
+
+data Bytes = Bytes
+  {-# UNPACK #-} !ByteArray -- payload
+  {-# UNPACK #-} !Int -- offset
+  {-# UNPACK #-} !Int -- length
+
+instance Show Bytes where
+  show x = "pack " ++ show (unpack x)
+
+pack :: [Word8] -> Bytes
+pack bs = let arr = packByteArray bs in Bytes arr 0 (lengthByteArray arr)
+
+unpack :: Bytes -> [Word8]
+unpack (Bytes arr off len) = go off
+  where
+  go :: Int -> [Word8]
+  go !ix = if ix < len + off
+    then PM.indexByteArray arr ix : go (ix + 1)
+    else []
+
+fromByteArray :: ByteArray -> Bytes
+fromByteArray ba = Bytes ba 0 (lengthByteArray ba)
+
+length :: Bytes -> Int
+length (Bytes _ _ len) = len
+
+foldr :: (Word8 -> a -> a) -> a -> Bytes -> a
+foldr f a0 (Bytes arr off0 len) = go off0 where
+  !end = off0 + len
+  go !ix = if ix < end
+    then f (PM.indexByteArray arr ix) (go (ix + 1))
+    else a0
+
+packByteArray :: [Word8] -> ByteArray
+packByteArray ws0 = runST $ do
+  marr <- PM.newByteArray (L.length ws0)
+  let go [] !_ = return ()
+      go (w : ws) !ix = PM.writeByteArray marr ix w >> go ws (ix + 1)
+  go ws0 0
+  PM.unsafeFreezeByteArray marr
+
+unpackByteArray :: ByteArray -> [Word8]
+unpackByteArray arr = go 0 where
+  go :: Int -> [Word8]
+  go !ix = if ix < lengthByteArray arr
+    then PM.indexByteArray arr ix : go (ix + 1)
+    else []
+
+lengthByteArray :: ByteArray -> Int
+lengthByteArray = PM.sizeofByteArray
diff --git a/ghc-tests/tests/T15038/Packed/Bytes/Parser.hs b/ghc-tests/tests/T15038/Packed/Bytes/Parser.hs
new file mode 100644
index 0000000000000000000000000000000000000000..6ae681c6a11d2f6ace7be4fe04ce0aa26d8693bc
--- /dev/null
+++ b/ghc-tests/tests/T15038/Packed/Bytes/Parser.hs
@@ -0,0 +1,166 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeInType #-}
+{-# LANGUAGE UnboxedSums #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE PartialTypeSignatures #-}
+
+{-# OPTIONS_GHC
+ -Weverything
+ -fno-warn-unsafe
+ -fno-warn-implicit-prelude
+ -fno-warn-missing-import-lists
+ -fno-warn-noncanonical-monoid-instances
+ -O2
+#-}
+
+module T15038.Packed.Bytes.Parser
+  ( Parser(..)
+  , Result(..)
+  , Leftovers(..)
+  , parseStreamST
+  , any
+  , failure
+  ) where
+
+import Control.Applicative
+import Data.Primitive (ByteArray(..))
+import GHC.Int (Int(I#))
+import GHC.ST (ST(..),runST)
+import GHC.Types (TYPE)
+import GHC.Word (Word8(W8#))
+import T15038.Packed.Bytes (Bytes(..))
+import T15038.Packed.Bytes.Stream.ST (ByteStream(..))
+import Prelude hiding (any,replicate)
+
+import qualified Data.Primitive as PM
+import qualified Control.Monad
+
+import GHC.Exts (Int#,ByteArray#,Word#, Word8#, State#,(+#),(-#),(>#),indexWord8Array#)
+
+type Bytes# = (# ByteArray#, Int#, Int# #)
+type Maybe# (a :: TYPE r) = (# (# #) | a #)
+type Leftovers# s = (# Bytes# , ByteStream s #)
+type Result# s a = (# Maybe# (Leftovers# s), Maybe# a #)
+
+data Result s a = Result
+  { resultLeftovers :: !(Maybe (Leftovers s))
+  , resultValue :: !(Maybe a)
+  }
+
+data Leftovers s = Leftovers
+  { leftoversChunk :: {-# UNPACK #-} !Bytes
+    -- ^ The last chunk pulled from the stream
+  , leftoversStream :: ByteStream s
+    -- ^ The remaining stream
+  }
+
+data PureResult a = PureResult
+  { pureResultLeftovers :: {-# UNPACK #-} !Bytes
+  , pureResultValue :: !(Maybe a)
+  } deriving (Show)
+
+emptyByteArray :: ByteArray
+emptyByteArray = runST (PM.newByteArray 0 >>= PM.unsafeFreezeByteArray)
+
+parseStreamST :: ByteStream s -> Parser a -> ST s (Result s a)
+parseStreamST stream (Parser f) = ST $ \s0 ->
+  case f (# | (# (# unboxByteArray emptyByteArray, 0#, 0# #), stream #) #) s0 of
+    (# s1, r #) -> (# s1, boxResult r #)
+
+boxResult :: Result# s a -> Result s a
+boxResult (# leftovers, val #) = case val of
+  (# (# #) | #) -> Result (boxLeftovers leftovers) Nothing
+  (# | a #) -> Result (boxLeftovers leftovers) (Just a)
+
+boxLeftovers :: Maybe# (Leftovers# s) -> Maybe (Leftovers s)
+boxLeftovers (# (# #) | #) = Nothing
+boxLeftovers (# | (# theBytes, stream #) #) = Just (Leftovers (boxBytes theBytes) stream)
+
+instance Functor Parser where
+  fmap = mapParser
+
+-- Remember to write liftA2 by hand at some point.
+instance Applicative Parser where
+  pure = pureParser
+  (<*>) = Control.Monad.ap
+
+instance Monad Parser where
+  return = pure
+  (>>=) = bindLifted
+
+newtype Parser a = Parser
+  { getParser :: forall s.
+       Maybe# (Leftovers# s)
+    -> State# s
+    -> (# State# s, Result# s a #)
+  }
+
+nextNonEmpty :: ByteStream s -> State# s -> (# State# s, Maybe# (Leftovers# s) #)
+nextNonEmpty (ByteStream f) s0 = case f s0 of
+  (# s1, r #) -> case r of
+    (# (# #) | #) -> (# s1, (# (# #) | #) #)
+    (# | (# theBytes@(# _,_,len #), stream #) #) -> case len of
+      0# -> nextNonEmpty stream s1
+      _ -> (# s1, (# | (# theBytes, stream #) #) #)
+
+withNonEmpty :: forall s b.
+     Maybe# (Leftovers# s)
+  -> State# s
+  -> (State# s -> (# State# s, Result# s b #))
+  -> (_ -> Bytes# -> ByteStream s -> State# s -> (# State# s, Result# s b #))
+     -- The first argument is a Word8, not a full machine word.
+     -- The second argument is the complete,non-empty chunk
+     -- with the head byte still intact.
+  -> (# State# s, Result# s b #)
+withNonEmpty (# (# #) | #) s0 g _ = g s0
+withNonEmpty (# | (# bytes0@(# arr0,off0,len0 #), stream0 #) #) s0 g f = case len0 ># 0# of
+  1# -> f (indexWord8Array# arr0 off0) bytes0 stream0 s0
+  _ -> case nextNonEmpty stream0 s0 of
+    (# s1, r #) -> case r of
+      (# (# #) | #) -> g s1
+      (# | (# bytes1@(# arr1, off1, _ #), stream1 #) #) ->
+        f (indexWord8Array# arr1 off1) bytes1 stream1 s1
+
+-- | Consume the next byte from the input.
+any :: Parser Word8
+any = Parser go where
+  go :: Maybe# (Leftovers# s) -> State# s -> (# State# s, Result# s Word8 #)
+  go m s0 = withNonEmpty m s0
+    (\s -> (# s, (# (# (# #) | #), (# (# #) | #) #) #))
+    (\theByte theBytes stream s ->
+      (# s, (# (# | (# unsafeDrop# 1# theBytes, stream #) #), (# | W8# theByte #) #) #)
+    )
+
+-- TODO: improve this
+mapParser :: (a -> b) -> Parser a -> Parser b
+mapParser f p = bindLifted p (pureParser . f)
+
+pureParser :: a -> Parser a
+pureParser a = Parser $ \leftovers0 s0 ->
+  (# s0, (# leftovers0, (# | a #) #) #)
+
+bindLifted :: Parser a -> (a -> Parser b) -> Parser b
+bindLifted (Parser f) g = Parser $ \leftovers0 s0 -> case f leftovers0 s0 of
+  (# s1, (# leftovers1, val #) #) -> case val of
+    (# (# #) | #) -> (# s1, (# leftovers1, (# (# #) | #) #) #)
+    (# | x #) -> case g x of
+      Parser k -> k leftovers1 s1
+
+-- This assumes that the Bytes is longer than the index. It also does
+-- not eliminate zero-length references to byte arrays.
+unsafeDrop# :: Int# -> Bytes# -> Bytes#
+unsafeDrop# i (# arr, off, len #) = (# arr, off +# i, len -# i #)
+
+unboxByteArray :: ByteArray -> ByteArray#
+unboxByteArray (ByteArray arr) = arr
+
+boxBytes :: Bytes# -> Bytes
+boxBytes (# a, b, c #) = Bytes (ByteArray a) (I# b) (I# c)
+
+failure :: Parser a
+failure = Parser (\m s -> (# s, (# m, (# (# #) | #) #) #))
diff --git a/ghc-tests/tests/T15038/Packed/Bytes/Stream/ST.hs b/ghc-tests/tests/T15038/Packed/Bytes/Stream/ST.hs
new file mode 100644
index 0000000000000000000000000000000000000000..765636700b74bf0e57307063cfd726cd8f5d306c
--- /dev/null
+++ b/ghc-tests/tests/T15038/Packed/Bytes/Stream/ST.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnboxedSums #-}
+
+{-# OPTIONS_GHC -O2 #-}
+
+module T15038.Packed.Bytes.Stream.ST
+  ( ByteStream(..)
+  , empty
+  , unpack
+  , fromBytes
+  ) where
+
+import Data.Primitive (Array,ByteArray(..))
+import Data.Semigroup (Semigroup)
+import Data.Word (Word8)
+import GHC.Exts (RealWorld,State#,Int#,ByteArray#)
+import GHC.Int (Int(I#))
+import GHC.ST (ST(..))
+import T15038.Packed.Bytes (Bytes(..))
+import System.IO (Handle)
+import qualified Data.Primitive as PM
+import qualified Data.Semigroup as SG
+import qualified T15038.Packed.Bytes as B
+
+type Bytes# = (# ByteArray#, Int#, Int# #)
+
+newtype ByteStream s = ByteStream
+  (State# s -> (# State# s, (# (# #) | (# Bytes# , ByteStream s #) #) #) )
+
+fromBytes :: Bytes -> ByteStream s
+fromBytes b = ByteStream
+  (\s0 -> (# s0, (# | (# unboxBytes b, empty #) #) #))
+
+nextChunk :: ByteStream s -> ST s (Maybe (Bytes,ByteStream s))
+nextChunk (ByteStream f) = ST $ \s0 -> case f s0 of
+  (# s1, r #) -> case r of
+    (# (# #) | #) -> (# s1, Nothing #)
+    (# | (# theBytes, theStream #) #) -> (# s1, Just (boxBytes theBytes, theStream) #)
+
+empty :: ByteStream s
+empty = ByteStream (\s -> (# s, (# (# #) | #) #) )
+
+boxBytes :: Bytes# -> Bytes
+boxBytes (# a, b, c #) = Bytes (ByteArray a) (I# b) (I# c)
+
+unboxBytes :: Bytes -> Bytes#
+unboxBytes (Bytes (ByteArray a) (I# b) (I# c)) = (# a,b,c #)
+
+unpack :: ByteStream s -> ST s [Word8]
+unpack stream = ST (unpackInternal stream)
+
+unpackInternal :: ByteStream s -> State# s -> (# State# s, [Word8] #)
+unpackInternal (ByteStream f) s0 = case f s0 of
+  (# s1, r #) -> case r of
+    (# (# #) | #) -> (# s1, [] #)
+    (# | (# bytes, stream #) #) -> case unpackInternal stream s1 of
+      (# s2, ws #) -> (# s2, B.unpack (boxBytes bytes) ++ ws #)
diff --git a/ghc-tests/tests/T15038/Parser.hs b/ghc-tests/tests/T15038/Parser.hs
new file mode 100644
index 0000000000000000000000000000000000000000..537019928b382867f18662cdefc624fc22d8aca5
--- /dev/null
+++ b/ghc-tests/tests/T15038/Parser.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeInType #-}
+{-# LANGUAGE UnboxedSums #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+{-# OPTIONS_GHC -Wall #-}
+
+module T15038.Parser
+  ( byteParserBadOnce
+  ) where
+
+import Control.Monad.ST (runST)
+import Data.Word (Word8)
+import T15038.Packed.Bytes (Bytes)
+import T15038.Packed.Bytes.Parser (Parser)
+import T15038.Packed.Bytes.Stream.ST (ByteStream)
+import qualified Data.Char
+import qualified T15038.Packed.Bytes as B
+import qualified T15038.Packed.Bytes.Parser as P
+import qualified T15038.Packed.Bytes.Stream.ST as Stream
+
+-- from common directory
+import qualified T15038.Data.Trie.Naive as Naive
+
+snmptrapdNaive :: Naive.Trie (Parser Word)
+snmptrapdNaive = Naive.fromStringList
+  [ ("STRING: ", P.any >>= \_ -> return 5)
+  ]
+
+runExampleParser :: Parser a -> (forall s. ByteStream s) -> (Maybe a, Maybe String)
+runExampleParser parser stream = runST $ do
+  P.Result mleftovers r <- P.parseStreamST stream parser
+  mextra <- case mleftovers of
+    Nothing -> return Nothing
+    Just (P.Leftovers chunk remainingStream) -> do
+      bs <- Stream.unpack remainingStream
+      return (Just (map word8ToChar (B.unpack chunk ++ bs)))
+  return (r,mextra)
+
+byteParserBadOnce :: Int -> Int
+byteParserBadOnce x = do
+  let sample = ("STRING: _6_ " ++ show x)
+      stream = Stream.fromBytes (s2b sample)
+      expected = 6
+      (r,mextra) = runExampleParser (Naive.parser snmptrapdNaive) stream
+      a1 = if Nothing == mextra then 1 else 0
+      a2 = if Just expected == r then 1 else 0
+   in a1 + (a2 + x)
+
+s2b :: String -> Bytes
+s2b = B.pack . map charToWord8
+
+charToWord8 :: Char -> Word8
+charToWord8 = fromIntegral . Data.Char.ord
+
+word8ToChar :: Word8 -> Char
+word8ToChar = Data.Char.chr . fromIntegral
diff --git a/ghc-tests/tests/T15038/all.T b/ghc-tests/tests/T15038/all.T
new file mode 100644
index 0000000000000000000000000000000000000000..08910f0c960019e60dad354dc483eb5713252d9e
--- /dev/null
+++ b/ghc-tests/tests/T15038/all.T
@@ -0,0 +1,3 @@
+test('T15038',
+     [reqlib('containers'), reqlib('ghc-prim'), reqlib('primitive')],
+     makefile_test, [])
diff --git a/ghc-tests/tests/T2267.hs b/ghc-tests/tests/T2267.hs
new file mode 100644
index 0000000000000000000000000000000000000000..46359825459bc9733a0c84b23a26dc585527043a
--- /dev/null
+++ b/ghc-tests/tests/T2267.hs
@@ -0,0 +1,12 @@
+{-# OPTIONS_GHC -Wunused-imports -Werror #-}
+
+module T2267 where
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.UTF8 as BU
+
+toString :: B.ByteString -> String
+toString = BU.toString
+
+fromString :: String -> B.ByteString
+fromString = BU.fromString
diff --git a/ghc-tests/tests/T2317/Makefile b/ghc-tests/tests/T2317/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9101fbd40ada5d47b499a48e62cb4ccd7f67ef71
--- /dev/null
+++ b/ghc-tests/tests/T2317/Makefile
@@ -0,0 +1,3 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
diff --git a/ghc-tests/tests/T2317/T2317.hs b/ghc-tests/tests/T2317/T2317.hs
new file mode 100644
index 0000000000000000000000000000000000000000..5025582ebe0ea08eb7faf7077c625675ff2e9eee
--- /dev/null
+++ b/ghc-tests/tests/T2317/T2317.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE PatternSignatures #-}
+
+import Control.Monad
+import Control.Parallel
+import System.Environment
+import System.Random
+
+sort (x:xs) = sort lesser ++ [x] ++ sort greater
+    where lesser = filter (<  x) xs
+          greater = filter (>= x) xs
+sort _ = []
+
+
+psort xs 10 = sort xs
+psort (x:xs) d = let d' = d + 1
+                     l = psort lesser d'
+                     g = psort greater d'
+              in l `par` g `par` (l ++ [x] ++ g)
+    where lesser = filter (<  x) xs
+          greater = filter (>= x) xs
+psort _ _ = []
+
+main = do
+  args <- getArgs
+  let counts | null args = [100000]
+             | otherwise = map read args
+  rs :: [Int] <- randoms `fmap` getStdGen
+  forM_ counts $ \k -> do
+    let xs = take k rs
+    print . length $ xs
+--    s <- getCurrentTime
+    print . length $ psort xs 0
+--    e <- getCurrentTime
+--    print (e `diffUTCTime` s)
diff --git a/ghc-tests/tests/T2317/T2317.stdout b/ghc-tests/tests/T2317/T2317.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..7ab314964ee984633e3a2d6095a428f88f4c13e0
--- /dev/null
+++ b/ghc-tests/tests/T2317/T2317.stdout
@@ -0,0 +1,2 @@
+100000
+100000
diff --git a/ghc-tests/tests/T2317/all.T b/ghc-tests/tests/T2317/all.T
new file mode 100644
index 0000000000000000000000000000000000000000..c9bcda2434c04437024a317c4da259560a96e81c
--- /dev/null
+++ b/ghc-tests/tests/T2317/all.T
@@ -0,0 +1,5 @@
+test('T2317',
+     [when(fast(), skip),
+      reqlib('parallel'), reqlib('random')],
+     multimod_compile_and_run,
+     ['T2317',''])
diff --git a/ghc-tests/tests/T3087.hs b/ghc-tests/tests/T3087.hs
new file mode 100644
index 0000000000000000000000000000000000000000..22eb59bb47c1641bd36ef3697698a62e514ee362
--- /dev/null
+++ b/ghc-tests/tests/T3087.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE RankNTypes, DeriveDataTypeable #-}
+
+module T3087 where
+
+import Data.Generics hiding (ext2Q)
+import System.IO
+
+data MyMaybe a = MyNothing | MyJust a deriving (Data, Typeable)
+
+test1 :: ()
+test1 = undefined `ext1Q` (\ (Just _) -> ()) $ Just ()
+
+test1' :: ()
+test1' = undefined `ext1Q` (\ (MyJust _) -> ()) $ MyJust ()
+
+newtype Q r a = Q { unQ :: a -> r }
+
+ext2Q :: (Data d, Typeable t)
+      => (d -> q) -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)
+      -> d -> q
+ext2Q def ext arg =
+  case dataCast2 (Q ext) of
+    Just (Q ext') -> ext' arg
+    Nothing       -> def arg
+
+data MyPair a b = MyPair a b deriving (Data, Typeable)
+
+test2 :: ()
+test2 = undefined `ext2Q` (\(_,_) -> ()) $ ((),())
+
+test2' :: ()
+test2' = undefined `ext2Q` (\(MyPair _ _) -> ()) $ MyPair () ()
+
+main stdout _ = do { print test1; print test1'; print test2; print test2' }
+  where
+    print = hPrint stdout
diff --git a/ghc-tests/tests/T367.hs b/ghc-tests/tests/T367.hs
new file mode 100644
index 0000000000000000000000000000000000000000..b02f2e19155f9e41f2c142d5f567cd5dadb2a330
--- /dev/null
+++ b/ghc-tests/tests/T367.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE MagicHash #-}
+{-# OPTIONS_GHC  -O2 #-}
+module T367 where
+import Control.Concurrent
+import qualified Data.Vector as U
+import System.IO
+
+main stdout _ = do
+    -- Non allocating loop, needs -fno-omit-yields in order for the kill to
+    -- work
+    t <- forkIO (U.sum (U.enumFromTo 1 (1000000000 :: Int)) `seq` return ())
+    threadDelay 10
+    killThread t
+    hPutStrLn stdout "Done"
diff --git a/ghc-tests/tests/T367A.hs b/ghc-tests/tests/T367A.hs
new file mode 100644
index 0000000000000000000000000000000000000000..6cb297db49dcaacfb13424164026196b8eaa82f5
--- /dev/null
+++ b/ghc-tests/tests/T367A.hs
@@ -0,0 +1,24 @@
+{-# OPTIONS_GHC -O2 -fno-omit-yields #-}
+-- Without -fno-omit-yields this test doesn't terminate
+module T367A where
+
+import Data.IORef
+import Control.Concurrent
+import System.IO
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+    r <- newIORef False
+    done_var <- newEmptyMVar
+    hPutStrLn stdout "About to fork"
+
+    forkIO $ f stdout done_var r
+    threadDelay 1000000 -- 1 second
+
+    hPutStrLn stdout "Why is this never printed?!"
+    writeIORef r True
+    readMVar done_var
+    -- and why do we never exit?
+
+f :: Handle -> MVar () -> IORef Bool -> IO ()
+f stdout done_var r = readIORef r >>= \b-> if b then hPutStrLn stdout "Done" >> putMVar done_var ()  else f stdout done_var r
diff --git a/ghc-tests/tests/T7953.hs b/ghc-tests/tests/T7953.hs
new file mode 100644
index 0000000000000000000000000000000000000000..f7fce007ed00f62f53ed108c21278049d1cb8824
--- /dev/null
+++ b/ghc-tests/tests/T7953.hs
@@ -0,0 +1,66 @@
+module T7953 (main) where
+
+import Control.Monad
+import System.IO
+import System.Random
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+    hSetBuffering stdout NoBuffering
+    let q = fold $ zip [1..] (take 200 [500.0,400.0..])
+    hPrint stdout q
+    hPutStrLn stdout "Before atMost"
+    let (xs,q') = atMost 0.5 q -- this causes seqfault with -O2
+    hPrint stdout xs
+    hPrint stdout q'
+    hPutStrLn stdout "After atMost"
+
+fold :: [(Key, Prio)] -> PSQ
+fold []         = Void
+fold ((u,r):xs) = insert u r $ fold xs
+
+data Elem = E
+    { _key   :: Key
+    , prio   :: Prio
+    } deriving (Eq, Show)
+
+type Prio = Double
+type Key = Int
+
+data PSQ = Void
+           | Winner Elem Tree
+           deriving (Eq, Show)
+
+singleton :: Key -> Prio -> PSQ
+singleton k p = Winner (E k p) Start
+
+insert :: Key -> Prio -> PSQ -> PSQ
+insert k p q = case q of
+    Void -> singleton k p
+    Winner e t -> Winner (E k p) (Fork e Start t)
+
+atMost :: Prio -> PSQ -> ([Elem], PSQ)
+atMost pt q = case q of
+    (Winner e _)
+        | prio e > pt -> ([], q)
+    Void              -> ([], Void)
+    Winner e Start    -> ([e], Void)
+    Winner e (Fork e' tl tr) ->
+        let (sequ, q')   = atMost pt (Winner e' tl)
+            (sequ', q'') = atMost pt (Winner e tr)
+        in (sequ ++ sequ', q' `play` q'')
+
+data Tree = Start
+          | Fork Elem Tree Tree
+    deriving (Eq, Show)
+
+lloser :: Key -> Prio -> Tree -> Tree -> Tree
+lloser k p tl tr = Fork (E k p) tl tr
+
+play :: PSQ -> PSQ -> PSQ
+Void `play` t' = t'
+t `play` Void  = t
+Winner e@(E k p) t `play` Winner e'@(E k' p') t'
+    | p <= p'   = Winner e  (lloser k' p' t t')
+    | otherwise = Winner e' (lloser k  p  t t')
+
diff --git a/ghc-tests/tests/T8138.hs b/ghc-tests/tests/T8138.hs
new file mode 100644
index 0000000000000000000000000000000000000000..9d869113e1c3a71cf9439def690bec3dbc25195c
--- /dev/null
+++ b/ghc-tests/tests/T8138.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module T8138 where
+
+import Control.Monad.ST
+import Data.Primitive
+import System.IO
+
+main :: Handle -> Handle -> IO ()
+main stdout _ = do
+    let xs :: [Float] = runST $ do
+          barr <- mutableByteArrayFromList [1..fromIntegral n::Float]
+          peekByteArray n barr
+    hPrint stdout xs
+  where
+    n = 13
+
+mutableByteArrayFromList :: forall s a . (Prim a)
+                         => [a]
+                         -> ST s (MutableByteArray s)
+mutableByteArrayFromList xs = do
+    arr <- newByteArray (length xs*sizeOf (undefined :: a))
+    loop arr 0 xs
+    return arr
+  where
+    loop :: MutableByteArray s -> Int -> [a] -> ST s ()
+    loop _ _ [] = return ()
+
+    loop arr i (x : xs) = do
+        writeByteArray arr i x
+        loop arr (i+1) xs
+
+peekByteArray :: (Prim a)
+              => Int
+              -> MutableByteArray s
+              -> ST s [a]
+peekByteArray n arr =
+    loop 0 arr
+  where
+    loop :: (Prim a)
+         => Int
+         -> MutableByteArray s
+         -> ST s [a]
+    loop i _ | i >= n = return []
+
+    loop i arr = do
+        x  <- readByteArray arr i
+        xs <- loop (i+1) arr
+        return (x : xs)
diff --git a/ghc-tests/tests/TC191.hs b/ghc-tests/tests/TC191.hs
new file mode 100644
index 0000000000000000000000000000000000000000..a8cee168463da44aced16b3a3a5197848aa06a05
--- /dev/null
+++ b/ghc-tests/tests/TC191.hs
@@ -0,0 +1,29 @@
+{-# LANGUAGE RankNTypes #-}
+
+-- This only typechecks if forall-hoisting works ok when
+-- importing from an interface file.  The type of Twins.gzipWithQ
+-- is this:
+--   type GenericQ r = forall a. Data a => a -> r
+--   gzipWithQ :: GenericQ (GenericQ r) -> GenericQ (GenericQ [r])
+-- It's kept this way in the interface file for brevity and documentation,
+-- but when the type synonym is expanded, the foralls need expanding
+
+module TC191 where
+
+import Data.Generics.Basics
+import Data.Generics.Aliases
+import Data.Generics.Twins(gzipWithQ)
+
+-- | Generic equality: an alternative to \deriving Eq\
+geq :: Data a => a -> a -> Bool
+geq x y = geq' x y
+  where
+--    This type signature no longer works, because it is
+--    insufficiently polymorphic.
+--    geq' :: forall a b. (Data a, Data b) => a -> b -> Bool
+    geq' :: GenericQ (GenericQ Bool)
+    geq' x y =     (toConstr x == toConstr y)
+                && and (gzipWithQ geq' x y)
+
+
+
diff --git a/ghc-tests/tests/TC220.hs b/ghc-tests/tests/TC220.hs
new file mode 100644
index 0000000000000000000000000000000000000000..b1b8c3ec10ca3a53a4941bc1e51dcf6d652f306b
--- /dev/null
+++ b/ghc-tests/tests/TC220.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- See #1033
+
+module TC220 where
+
+import Data.Generics
+import Control.Monad.State
+
+data HsExp = HsWildCard deriving( Typeable, Data )
+data HsName = HsName deriving( Typeable, Data )
+
+-- rename :: () -> HsExp -> State (HsName, [HsName]) HsExp
+-- Type sig commented out
+rename1 = \_ -> everywhereM (mkM (\e -> case e of HsWildCard -> return e))
+
+rename2 _ = everywhereM (mkM (\e -> case e of  HsWildCard -> return e))
+
+uncomb1 :: State (HsName, [HsName]) HsExp
+uncomb1 = rename1 () undefined
+
+uncomb2 :: State (HsName, [HsName]) HsExp
+uncomb2 = rename2 () undefined
+
+
+
diff --git a/ghc-tests/tests/Tasty/Bronze.hs b/ghc-tests/tests/Tasty/Bronze.hs
new file mode 100644
index 0000000000000000000000000000000000000000..c735b47860389dab1a4e559e7a3503b20483d409
--- /dev/null
+++ b/ghc-tests/tests/Tasty/Bronze.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE ScopedTypeVariables, BangPatterns #-}
+module Tasty.Bronze where
+
+import System.Exit
+import Test.Tasty
+import Test.Tasty.Silver
+import qualified System.Process as PT
+import Control.Exception
+import System.IO
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as T
+import System.Posix.Process.Internals
+import System.IO.Temp
+
+
+-- | Compares a given file with the output (exit code, stdout, stderr) of a program. Assumes
+-- that the program output is utf8 encoded.
+goldenVsOut
+  :: TestName   -- ^ test name
+  -> FilePath   -- ^ path to the golden file
+  -> (Handle -> Handle -> IO ())
+  -> TestTree
+goldenVsOut name ref cmd =
+  goldenVsAction name ref runProg printProcResult
+  where runProg = wrapAction cmd
+
+wrapAction :: (Handle -> Handle -> IO ()) -> IO (ExitCode, T.Text, T.Text)
+wrapAction io =
+  withSystemTempFile "stdout" $ \stdout_fp stdout_h -> do
+    withSystemTempFile "stderr" $ \stderr_fp stderr_h -> do
+      e_code <- catchExit (io stdout_h stderr_h)
+      hClose stdout_h
+      hClose stderr_h
+      !std_o <- readFile stdout_fp
+      !std_e <- readFile stderr_fp
+      return (e_code, T.pack std_o, T.pack std_e)
+
+catchExit :: IO () -> IO ExitCode
+catchExit io = catch (ExitSuccess <$ io) (\(e :: ExitCode) -> return e)
diff --git a/ghc-tests/tests/Throwto001.hs b/ghc-tests/tests/Throwto001.hs
new file mode 100644
index 0000000000000000000000000000000000000000..5635bd265d8810a2971e40ab36d51b1fc5f32d74
--- /dev/null
+++ b/ghc-tests/tests/Throwto001.hs
@@ -0,0 +1,38 @@
+module Throwto001 where
+import Control.Concurrent
+import Control.Exception
+import Data.Array
+import System.Random
+import System.Environment
+import Control.Monad
+import GHC.Conc
+
+-- A fiendish throwTo test.  A bunch of threads take random MVars from
+-- a shared array; if the MVar has Nothing in it, replace it with Just
+-- of the current thread's ThreadId.  If the MVar has another ThreadId
+-- in it, then killThread that thread, and replace it with the current
+-- thread's ThreadId.  We keep going until only one thread is left
+-- standing.
+--
+-- On multiple CPUs this should give throwTo a good workout.
+--
+main m t = do
+  ms <- replicateM m $ newMVar Nothing
+  let arr = listArray (1,m) ms
+  dead <- newTVarIO 0
+  ts <- replicateM t $ forkIO (thread m arr `onException`
+                                      (atomically $ do d <- readTVar dead
+                                                       writeTVar dead $! d+1))
+  atomically $ do
+    d <- readTVar dead
+    when (d < t-1) $ retry
+
+thread m arr = do
+  x <- randomIO
+  id <- myThreadId
+  modifyMVar_ (arr ! ((x `mod` m) + 1)) $ \b ->
+    case b of
+      Nothing    -> return (Just id)
+      Just other -> do when (other /= id) $ killThread other
+                       return (Just id)
+  thread m arr