summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/_alt.ssa25
-rw-r--r--src/test/_dragon.ssa33
-rw-r--r--src/test/_fix1.ssa15
-rw-r--r--src/test/_fix2.ssa15
-rw-r--r--src/test/_fix3.ssa20
-rw-r--r--src/test/_fix4.ssa27
-rw-r--r--src/test/_live.ssa21
-rw-r--r--src/test/_rpo.ssa12
-rw-r--r--src/test/_spill1.ssa22
-rw-r--r--src/test/_spill2.ssa22
-rw-r--r--src/test/_spill3.ssa24
-rw-r--r--src/test/abi1.ssa59
-rw-r--r--src/test/abi2.ssa18
-rw-r--r--src/test/abi3.ssa43
-rw-r--r--src/test/abi4.ssa38
-rw-r--r--src/test/abi5.ssa105
-rw-r--r--src/test/align.ssa16
-rw-r--r--src/test/collatz.ssa61
-rw-r--r--src/test/cprime.ssa103
-rw-r--r--src/test/cup.ssa17
-rw-r--r--src/test/dark.ssa30
-rw-r--r--src/test/double.ssa24
-rw-r--r--src/test/echo.ssa32
-rw-r--r--src/test/eucl.ssa24
-rw-r--r--src/test/euclc.ssa29
-rw-r--r--src/test/fpcnv.ssa27
-rwxr-xr-xsrc/test/go.sh116
-rw-r--r--src/test/loop.ssa23
-rw-r--r--src/test/mandel.ssa123
-rw-r--r--src/test/max.ssa33
-rw-r--r--src/test/prime.ssa32
-rw-r--r--src/test/puts10.ssa29
-rw-r--r--src/test/sum.ssa31
33 files changed, 1249 insertions, 0 deletions
diff --git a/src/test/_alt.ssa b/src/test/_alt.ssa
new file mode 100644
index 0000000..3f89e5e
--- /dev/null
+++ b/src/test/_alt.ssa
@@ -0,0 +1,25 @@
+# an example with reducible control
+# flow graph that exposes poor
+# handling of looping constructs
+
+function $test() {
+@start
+	%ten =w copy 10
+	%dum =w copy 0  # dummy live-through temporary
+@loop
+	%alt =w phi @start 0, @left %alt1, @right %alt1
+	%cnt =w phi @start 100, @left %cnt, @right %cnt1
+	%alt1 =w sub 1, %alt
+	jnz %alt1, @right, @left
+@left
+	%x =w phi @loop 10, @left %x1
+	%x1 =w sub %x, 1
+	%z =w copy %x
+	jnz %z, @left, @loop
+@right
+	%cnt1 =w sub %cnt, %ten
+	jnz %cnt1, @loop, @end
+@end
+	%ret =w add %cnt, %dum
+	ret
+}
diff --git a/src/test/_dragon.ssa b/src/test/_dragon.ssa
new file mode 100644
index 0000000..b169e1b
--- /dev/null
+++ b/src/test/_dragon.ssa
@@ -0,0 +1,33 @@
+# a moderately complex test for
+# dominators computation from
+# the dragon book
+# because branching is limited to
+# two, I had to split some blocks
+
+function $dragon() {
+@start
+@b1
+	jnz 0, @b2, @b3
+@b2
+	jmp @b3
+@b3
+	jmp @b4.1
+@b4.1
+	jnz 0, @b3, @b4.2
+@b4.2
+	jnz 0, @b5, @b6
+@b5
+	jmp @b7
+@b6
+	jmp @b7
+@b7
+	jnz 0, @b8.1, @b4.1
+@b8.1
+	jnz 0, @b3, @b8.2
+@b8.2
+	jnz 0, @b9, @b10
+@b9
+	jmp @b1
+@b10
+	jmp @b7
+}
diff --git a/src/test/_fix1.ssa b/src/test/_fix1.ssa
new file mode 100644
index 0000000..e89307f
--- /dev/null
+++ b/src/test/_fix1.ssa
@@ -0,0 +1,15 @@
+function $test() {
+@start
+	%x =w copy 1
+@loop
+	jnz %x, @noz, @isz
+@noz
+	%x =w copy 0
+	jmp @end
+@isz
+	%x =w copy 1
+	jmp @loop
+@end
+	%z =w add 10, %x
+	ret
+}
diff --git a/src/test/_fix2.ssa b/src/test/_fix2.ssa
new file mode 100644
index 0000000..89f236d
--- /dev/null
+++ b/src/test/_fix2.ssa
@@ -0,0 +1,15 @@
+function $test() {
+@start
+	%x =w copy 1
+@loop
+	jnz %x, @noz, @isz
+@noz
+	%x =w copy 0
+	jnz %x, @loop, @end
+@isz
+	%x =w copy 1
+	jmp @loop
+@end
+	%z =w add 10, %x
+	ret
+}
diff --git a/src/test/_fix3.ssa b/src/test/_fix3.ssa
new file mode 100644
index 0000000..283e5a1
--- /dev/null
+++ b/src/test/_fix3.ssa
@@ -0,0 +1,20 @@
+function w $test() {
+@start
+	%x =w copy 100
+	%s =w copy 0
+@l
+	%c =w cslew %x, 10
+	jnz %c, @a, @b
+@a
+	%s =w add %s, %x
+	%x =w sub %x, 1
+	jmp @c
+@b
+	%s =w sub %s, %x
+	jmp @c
+@c
+	%x =w sub %x, 1
+	jnz %x, @l, @end
+@end
+	ret %s
+}
diff --git a/src/test/_fix4.ssa b/src/test/_fix4.ssa
new file mode 100644
index 0000000..181768d
--- /dev/null
+++ b/src/test/_fix4.ssa
@@ -0,0 +1,27 @@
+function $test() {
+@start
+	%x =w copy 3
+	%n =w copy 2
+@loop
+	%c =w ceqw %n, 10000
+	jnz %c, @end, @next
+@next
+	%t =w copy 3
+	%x =w add %x, 2
+@tloop
+	%s =w mul %t, %t
+	%c =w csgtw %s, %x
+	jnz %c, @prime, @test
+@test
+	%r =w rem %x, %t
+	jnz %r, @tnext, @loop
+@tnext
+	%t =w add %t, 2
+	jmp @tloop
+@prime
+	%n =w add %n, 1
+	jmp @loop
+@end
+	storew %x, $a
+	ret
+}
diff --git a/src/test/_live.ssa b/src/test/_live.ssa
new file mode 100644
index 0000000..fce4cb9
--- /dev/null
+++ b/src/test/_live.ssa
@@ -0,0 +1,21 @@
+# this control flow graph is irreducible
+# yet, we expecet the liveness analysis
+# to work properly and make %x live in
+# the block @left
+#
+# nothing should ever be live at the entry
+
+function $test() {
+@start
+	%b =w copy 0
+	%x =w copy 10
+	jnz 0, @loop, @left
+@left
+	jmp @inloop
+@loop
+	%x1 =w add %x, 1
+@inloop
+	%b1 =w add %b, 1
+@endloop
+	jmp @loop
+}
diff --git a/src/test/_rpo.ssa b/src/test/_rpo.ssa
new file mode 100644
index 0000000..a10c6b1
--- /dev/null
+++ b/src/test/_rpo.ssa
@@ -0,0 +1,12 @@
+function $test() {
+@start
+	jmp @foo
+@baz
+	jnz 1, @end, @foo
+@bar
+	jmp @end
+@foo
+	jnz 0, @bar, @baz
+@end
+	ret
+}
diff --git a/src/test/_spill1.ssa b/src/test/_spill1.ssa
new file mode 100644
index 0000000..df5e4c2
--- /dev/null
+++ b/src/test/_spill1.ssa
@@ -0,0 +1,22 @@
+# test with NReg == 3
+# there must be a spill
+# happening on %c
+#
+# if you replace the sub
+# by an add or comment
+# the two marked lines
+# there should be no
+# spill
+#
+
+function $test() {
+@start
+	%f =w copy 0      # here
+	%b =w copy 1
+	%c =w copy 2
+	%a =w sub %b, %c
+	%d =w copy %b
+	%e =w copy %f     # and there
+	%g =w copy %a
+	ret
+}
diff --git a/src/test/_spill2.ssa b/src/test/_spill2.ssa
new file mode 100644
index 0000000..d462d0b
--- /dev/null
+++ b/src/test/_spill2.ssa
@@ -0,0 +1,22 @@
+# stupid spilling test
+
+function $test() {
+@start
+	%x1  =w copy 10
+	%x2  =w add %x1, %x1
+	%x3  =w sub %x2, %x1
+	%x4  =w add %x3, %x1
+	%x5  =w sub %x4, %x1
+	%x6  =w add %x5, %x1
+	%x7  =w sub %x6, %x1
+	%x8  =w add %x7, %x1
+	%x9  =w sub %x8, %x8
+	%x10 =w add %x9, %x7
+	%x11 =w sub %x10, %x6
+	%x12 =w add %x11, %x5
+	%x13 =w sub %x12, %x4
+	%x14 =w add %x13, %x3
+	%x15 =w sub %x14, %x2
+	%x16 =w add %x15, %x1
+	ret
+}
diff --git a/src/test/_spill3.ssa b/src/test/_spill3.ssa
new file mode 100644
index 0000000..cdfda2d
--- /dev/null
+++ b/src/test/_spill3.ssa
@@ -0,0 +1,24 @@
+# make sure comparisons
+# never get their two
+# operands in memory
+# run with NReg == 3, or
+# adapt it!
+
+function $test() {
+@start
+	%a =w loadw $a
+	%b =w loadw $a
+
+@loop
+	%c =w phi @start 0, @loop %f
+	%d =w phi @start 0, @loop %g
+	%e =w phi @start 0, @loop %h
+	%f =w add %c, %d
+	%g =w add %c, %e
+	%h =w add %e, %d
+	%x =w cslew %a, %b
+	jnz %x, @loop, @end
+
+@end
+	ret
+}
diff --git a/src/test/abi1.ssa b/src/test/abi1.ssa
new file mode 100644
index 0000000..69cce44
--- /dev/null
+++ b/src/test/abi1.ssa
@@ -0,0 +1,59 @@
+# test calling into C with two
+# large struct arguments (passed
+# on the stack)
+
+type :mem = { b 17 }
+
+function $alpha(l %p, w %l, l %n) {
+@ini
+	%pe =l add %p, %n
+@lop
+	%p1 =l phi @ini %p, @lop %p2
+	%l1 =w phi @ini %l, @lop %l2
+	storeb %l1, %p1
+	%p2 =l add %p1, 1
+	%l2 =w add %l1, 1
+	%c1 =w ceql %p1, %pe
+	jnz %c1, @end, @lop
+@end
+	storeb 0, %pe
+	ret
+}
+
+function $test() {
+@start
+	%p =l alloc4 17
+	%q =l alloc4 17
+	%r0 =w call $alpha(l %p, w 65, l 16)
+	%r1 =w call $alpha(l %q, w 97, l 16)
+	%r2 =w call $fcb(:mem %p, w 1, w 2, w 3, w 4, w 5, w 6, w 7, w 8, w 9, :mem %q)
+	ret
+}
+
+
+# >>> driver
+# #include <stdio.h>
+# typedef struct { char t[17]; } mem;
+# extern void test();
+# void fcb(mem m, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, mem n) {
+# 	printf("fcb: m = (mem){ t = \"%s\" }\n", m.t);
+# 	printf("     n = (mem){ t = \"%s\" }\n", n.t);
+# 	#define T(n) printf("     i%d = %d\n", n, i##n);
+# 	T(1) T(2) T(3) T(4) T(5) T(6) T(7) T(8) T(9)
+# }
+# int main() { test(); return 0; }
+# <<<
+
+# >>> output
+# fcb: m = (mem){ t = "ABCDEFGHIJKLMNOP" }
+#      n = (mem){ t = "abcdefghijklmnop" }
+#      i1 = 1
+#      i2 = 2
+#      i3 = 3
+#      i4 = 4
+#      i5 = 5
+#      i6 = 6
+#      i7 = 7
+#      i8 = 8
+#      i9 = 9
+# <<<
diff --git a/src/test/abi2.ssa b/src/test/abi2.ssa
new file mode 100644
index 0000000..b82c80c
--- /dev/null
+++ b/src/test/abi2.ssa
@@ -0,0 +1,18 @@
+type :fps = { s, b, s }
+
+function s $sum(:fps %p) {
+@start
+	%f1 =s load %p
+	%p8 =l add 8, %p
+	%f2 =s load %p8
+	%s =s add %f1, %f2
+	ret %s
+}
+
+# >>> driver
+# typedef struct { float f1; char b; float f2; } fps;
+# extern float sum(fps);
+# int main() { fps x = { 1.23, -1, 2.34 }; return !(sum(x) == 1.23f+2.34f); }
+# /* Note the f suffixes above are important
+#  * otherwise C does double operations. */
+# <<<
diff --git a/src/test/abi3.ssa b/src/test/abi3.ssa
new file mode 100644
index 0000000..608d1db
--- /dev/null
+++ b/src/test/abi3.ssa
@@ -0,0 +1,43 @@
+type :four = {l, b, w}
+
+data $z = { w 0 }
+
+function $test() {
+ @start
+	%a  =w loadw $z
+	%y  =w add %a, %a
+
+	%s  =l alloc8 16   # allocate a :four struct
+	%s1 =l add %s, 12  # get address of the w
+	storel 4, %s       # set the l
+	storew 5, %s1      # set the w
+
+	# only the last argument should be on the stack
+	%f  =l add $F, %y
+	%x  =w call %f(w %y, w 1, w 2, w 3, :four %s, w 6)
+
+	# store the result in the
+	# global variable a
+
+	%x1 =w add %y, %x
+	storew %x1, $a
+	ret
+}
+
+# >>> driver
+# #include <stdio.h>
+# struct four { long l; char c; int i; };
+# extern void test(void);
+# int F(int a0, int a1, int a2, int a3, struct four s, int a6) {
+# 	printf("%d %d %d %d %d %d %d\n",
+# 		a0, a1, a2, a3, (int)s.l, s.i, a6);
+# 	return 42;
+# }
+# int a;
+# int main() { test(); printf("%d\n", a); return 0; }
+# <<<
+
+# >>> output
+# 0 1 2 3 4 5 6
+# 42
+# <<<
diff --git a/src/test/abi4.ssa b/src/test/abi4.ssa
new file mode 100644
index 0000000..4c3d89b
--- /dev/null
+++ b/src/test/abi4.ssa
@@ -0,0 +1,38 @@
+# return a large struct to C
+
+type :mem = { b 17 }
+
+function $alpha(l %p, w %l, l %n) {
+@ini
+	%pe =l add %p, %n
+@lop
+	%p1 =l phi @ini %p, @lop %p2
+	%l1 =w phi @ini %l, @lop %l2
+	storeb %l1, %p1
+	%p2 =l add %p1, 1
+	%l2 =w add %l1, 1
+	%c1 =w ceql %p1, %pe
+	jnz %c1, @end, @lop
+@end
+	storeb 0, %pe
+	ret
+}
+
+function :mem $test() {
+@start
+	%p =l alloc4 17
+	%r0 =w call $alpha(l %p, w 65, l 16)
+	ret %p
+}
+
+
+# >>> driver
+# #include <stdio.h>
+# typedef struct { char t[17]; } mem;
+# extern mem test(void);
+# int main() { mem m = test(); printf("%s\n", m.t); return 0; }
+# <<<
+
+# >>> output
+# ABCDEFGHIJKLMNOP
+# <<<
diff --git a/src/test/abi5.ssa b/src/test/abi5.ssa
new file mode 100644
index 0000000..4c5eaea
--- /dev/null
+++ b/src/test/abi5.ssa
@@ -0,0 +1,105 @@
+# returning structs from C
+
+type :st1 = { b 17 }
+type :st2 = { w }
+type :st3 = { s, w }
+type :st4 = { w, d }
+type :st5 = { s, l }
+type :st6 = { b 16 }
+type :st7 = { s, d }
+type :st8 = { w 4 }
+
+data $fmt1 = { b "t1: %s\n", b 0 }
+data $fmt2 = { b "t2: %d\n", b 0 }
+data $fmt3 = { b "t3: %f %d\n", b 0 }
+data $fmt4 = { b "t4: %d %f\n", b 0 }
+data $fmt5 = { b "t5: %f %lld\n", b 0 }
+data $fmt6 = { b "t6: %s\n", b 0 }
+data $fmt7 = { b "t7: %f %f\n", b 0 }
+data $fmt8 = { b "t8: %d %d %d %d\n", b 0 }
+
+function $test() {
+@start
+	%r1 =:st1 call $t1()
+	%i1 =w call $printf(l $fmt1, l %r1)
+
+	%r2 =:st2 call $t2()
+	%w2 =w loadw %r2
+	%i2 =w call $printf(l $fmt2, w %w2)
+
+	%r3 =:st3 call $t3()
+	%s3 =s loads %r3
+	%r34 =l add %r3, 4
+	%w3 =w loadw %r34
+	%p3 =d exts %s3
+	%i3 =w call $printf(l $fmt3, d %p3, w %w3)
+
+	%r4 =:st4 call $t4()
+	%w4 =w loadw %r4
+	%r48 =l add 8, %r4
+	%d4 =d loadd %r48
+	%i4 =w call $printf(l $fmt4, w %w4, d %d4)
+
+	%r5 =:st5 call $t5()
+	%s5 =s loads %r5
+	%d5 =d exts %s5
+	%r58 =l add %r5, 8
+	%l5 =l loadl %r58
+	%i5 =w call $printf(l $fmt5, d %d5, l %l5)
+
+	%r6 =:st6 call $t6()
+	%i6 =w call $printf(l $fmt6, l %r6)
+
+	%r7 =:st7 call $t7()
+	%s7 =s loads %r7
+	%d71 =d exts %s7
+	%r78 =l add %r7, 8
+	%d72 =d loadd %r78
+	%i7 =w call $printf(l $fmt7, d %d71, d %d72)
+
+	%r8 =:st8 call $t8()
+	%r84 =l add 4, %r8
+	%r88 =l add 4, %r84
+	%r812 =l add 4, %r88
+	%w81 =w loadw %r8
+	%w82 =w loadw %r84
+	%w83 =w loadw %r88
+	%w84 =w loadw %r812
+	%i8 =w call $printf(l $fmt8, w %w81, w %w82, w %w83, w %w84)
+
+	ret
+}
+
+
+# >>> driver
+# #include <stdio.h>
+# typedef struct { char t[17]; } st1;
+# typedef struct { int i; } st2;
+# typedef struct { float f; int i; } st3;
+# typedef struct { int i; double d; } st4;
+# typedef struct { float f; long l; } st5;
+# typedef struct { char t[16]; } st6;
+# typedef struct { float f; double d; } st7;
+# typedef struct { int i[4]; } st8;
+# extern void test(void);
+# st1 t1() { return (st1){"abcdefghijklmnop"}; }
+# st2 t2() { return (st2){2}; }
+# st3 t3() { return (st3){3.0,30}; }
+# st4 t4() { return (st4){4,-40}; }
+# st5 t5() { return (st5){5.5,-55}; }
+# st6 t6() { return (st6){"abcdefghijklmno"}; }
+# st7 t7() { return (st7){7.77,77.7}; }
+# st8 t8() { return (st8){-8,88,-888,8888}; }
+# int main() { test(); return 0; }
+# <<<
+
+# >>> output
+# t1: abcdefghijklmnop
+# t2: 2
+# t3: 3.000000 30
+# t4: 4 -40.000000
+# t5: 5.500000 -55
+# t6: abcdefghijklmno
+# t7: 7.770000 77.700000
+# t8: -8 88 -888 8888
+# <<<
diff --git a/src/test/align.ssa b/src/test/align.ssa
new file mode 100644
index 0000000..84d1fb9
--- /dev/null
+++ b/src/test/align.ssa
@@ -0,0 +1,16 @@
+function $test() {
+@start
+	%x =l alloc16 16
+	%y =l add %x, 8
+	%m =w rem %y, 16
+	storew %m, %y
+	%n =w loadw %y
+	storew %n, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 8 || a == -8); }
+# <<<
diff --git a/src/test/collatz.ssa b/src/test/collatz.ssa
new file mode 100644
index 0000000..373ecac
--- /dev/null
+++ b/src/test/collatz.ssa
@@ -0,0 +1,61 @@
+# a solution for N=1000 to
+# https://projecteuler.net/problem=14
+# we use a fast local array to
+# memoize small collatz numbers
+
+function $test() {
+@start
+	%mem =l alloc4 4000
+@loop
+	%n =w phi @start 1, @newm %n9, @oldm %n9
+	%cmax =w phi @start 0, @newm %c, @oldm %cmax
+	%fin =w csltw %n, 1000
+	jnz %fin, @cloop, @end
+@cloop
+	%n0 =w phi @loop %n, @odd %n2, @even %n3
+	%c0 =w phi @loop 0, @odd %c1, @even %c1
+	%no1 =w cnew %n0, 1
+	jnz %no1, @iter0, @endcl
+@iter0
+	%ism =w csltw %n0, %n
+	jnz %ism, @getmemo, @iter1
+@iter1
+	%c1 =w add %c0, 1
+	%p =w and %n0, 1
+	jnz %p, @odd, @even
+@odd
+	%n1 =w mul 3, %n0
+	%n2 =w add %n1, 1
+	jmp @cloop
+@even
+	%n3 =w div %n0, 2
+	jmp @cloop
+@getmemo                     # get the count for n0 in mem
+	%n0l =l extsw %n0
+	%idx0 =l mul %n0l, 4
+	%loc0 =l add %idx0, %mem
+	%cn0 =w loadw %loc0
+	%c2 =w add %c0, %cn0
+@endcl                       # store the count for n in mem
+	%c =w phi @getmemo %c2, @cloop %c0
+	%nl =l extsw %n
+	%idx1 =l mul %nl, 4
+	%loc1 =l add %idx1, %mem
+	storew %c, %loc1
+	%n9 =w add 1, %n
+	%big =w cslew %cmax, %c
+	jnz %big, @newm, @oldm
+@newm
+	jmp @loop
+@oldm
+	jmp @loop
+@end
+	storew %cmax, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 178); }
+# <<<
diff --git a/src/test/cprime.ssa b/src/test/cprime.ssa
new file mode 100644
index 0000000..1ca60e1
--- /dev/null
+++ b/src/test/cprime.ssa
@@ -0,0 +1,103 @@
+# generated by Andrew Chambers'
+# compiler from the C program
+# following in comments
+
+function w $main() {
+@start
+	%v0 =l alloc8 4
+	%v1 =l alloc8 4
+	%v2 =l alloc8 4
+	%v3 =l alloc8 4
+	%v4 =l alloc8 4
+	storew 5, %v1
+	storew 11, %v2
+	storew 12, %v3
+@L0
+	%v5 =w loadw %v1
+	%v6 =w cnew %v5, 201
+	jnz %v6, @L8, @L1
+@L8
+	storew 1, %v4
+	%v7 =w loadw %v3
+	%v8 =w rem %v7, 2
+	%v9 =w ceqw %v8, 0
+	jnz %v9, @L9, @L5
+@L9
+	storew 0, %v4
+@L5
+	storew 3, %v0
+@L2
+	%v10 =w loadw %v0
+	%v11 =w loadw %v3
+	%v12 =w csltw %v10, %v11
+	jnz %v12, @L10, @L3
+@L10
+	%v13 =w loadw %v3
+	%v14 =w loadw %v0
+	%v15 =w rem %v13, %v14
+	%v16 =w ceqw %v15, 0
+	jnz %v16, @L11, @L4
+@L11
+	storew 0, %v4
+	jmp @L3
+@L4
+	%v17 =w loadw %v0
+	%v18 =w add %v17, 2
+	storew %v18, %v0
+	jmp @L2
+@L3
+	%v19 =w loadw %v4
+	jnz %v19, @L12, @L6
+@L12
+	%v20 =w loadw %v3
+	storew %v20, %v2
+	%v21 =w loadw %v1
+	%v22 =w add %v21, 1
+	storew %v22, %v1
+@L6
+	%v23 =w loadw %v3
+	%v24 =w add %v23, 1
+	storew %v24, %v3
+	jmp @L0
+@L1
+	%v25 =w loadw %v2
+	%v26 =w cnew %v25, 1229
+	jnz %v26, @L13, @L7
+@L13
+	ret 1
+@L7
+	ret 0
+@end
+	ret 0
+}
+
+# int
+# main()
+# {
+#         int i, n, p, next, isprime;
+#
+#         n = 5;
+#         p = 11;
+#         next = 12;
+#         while(n != 201) {
+#                 isprime = 1;
+#                 if(next % 2 == 0) {
+#                         isprime = 0;
+#                 } else {
+#                         for(i = 3; i < next; i = i + 2) {
+#                                 if(next % i == 0) {
+#                                         isprime = 0;
+#                                         break;
+#                                 }
+#                         }
+#                 }
+#                 if(isprime) {
+#                         p = next;
+#                         n = n + 1;
+#                 }
+#                 next = next + 1;
+#         }
+#         if(p != 1229)
+#                 return 1;
+#         return 0;
+# }
diff --git a/src/test/cup.ssa b/src/test/cup.ssa
new file mode 100644
index 0000000..013394f
--- /dev/null
+++ b/src/test/cup.ssa
@@ -0,0 +1,17 @@
+# counts up from -1988 to 1991
+
+function $test() {
+@start
+@loop
+	%n0  =l phi @start -1988, @loop %n1
+	%n1  =l add 1, %n0
+	%cmp =w cslel 1991, %n1
+	jnz %cmp, @end, @loop
+@end
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int main() { test(); return 0; }
+# <<<
diff --git a/src/test/dark.ssa b/src/test/dark.ssa
new file mode 100644
index 0000000..5046af3
--- /dev/null
+++ b/src/test/dark.ssa
@@ -0,0 +1,30 @@
+# a hack example,
+# we use a dark type to get
+# a pointer to the stack.
+
+type :magic = align 1 { 0 }
+
+data $ret = { l 0 }
+
+function $test(:magic %p) {
+@start
+	%av =w loadw $a
+	%a1 =w add 1, %av
+	storew %a1, $a       # increment $a
+	%r1 =l loadl $ret    # fetch from $ret
+	%p1 =l add %p, -8
+	%r2 =l loadl %p1     # get the return address
+	storel %r2, $ret     # store it in $ret
+	%c =w ceql %r1, %r2
+	jnz %c, @fin, @cal
+@cal
+	%i =w call $test()   # no argument given, intentionally!
+@fin
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a = 2;
+# int main() { test(); return !(a == 5); }
+# <<<
diff --git a/src/test/double.ssa b/src/test/double.ssa
new file mode 100644
index 0000000..d885d28
--- /dev/null
+++ b/src/test/double.ssa
@@ -0,0 +1,24 @@
+function $test() {
+@start
+	%x1 =d copy d_0.1
+	%x2 =d add d_0.2, %x1
+	%x3 =d sub %x2, d_0.3
+
+@loop
+	%x4 =d phi @start %x3, @loop %x5
+	%i1 =w phi @start 0, @loop %i2
+	%x5 =d add %x4, %x4
+	%i2 =w add %i1, 1
+	%c0 =w cled %x5, 4607182418800017408 # d_1.0
+	jnz %c0, @loop, @end
+
+@end
+	storew %i2, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 55); }
+# <<<
diff --git a/src/test/echo.ssa b/src/test/echo.ssa
new file mode 100644
index 0000000..d3c8a25
--- /dev/null
+++ b/src/test/echo.ssa
@@ -0,0 +1,32 @@
+function w $main(w %argc, l %argv) {
+@start
+	%fmt =l alloc8 8
+	storel 1663398693, %fmt             # "%s%c"
+	%av0 =l add %argv, 8
+	%ac0 =w sub %argc, 1
+@loop
+	%av =l phi @start %av0, @loop2 %av1
+	%ac =w phi @start %ac0, @loop2 %ac1
+	%c0 =w ceqw %ac, 0
+	jnz %c0, @end, @loop1
+@loop1
+	%c1 =w ceqw %ac, 1
+	jnz %c1, @last, @nolast
+@last
+	jmp @loop2
+@nolast
+	jmp @loop2
+@loop2
+	%sep =w phi @last 10, @nolast 32
+	%arg =l loadl %av
+	%r =w call $printf(l %fmt, l %arg, w %sep)
+	%av1 =l add %av, 8
+	%ac1 =w sub %ac, 1
+	jmp @loop
+@end
+	ret 0
+}
+
+# >>> output
+# a b c
+# <<<
diff --git a/src/test/eucl.ssa b/src/test/eucl.ssa
new file mode 100644
index 0000000..f50fd2c
--- /dev/null
+++ b/src/test/eucl.ssa
@@ -0,0 +1,24 @@
+# euclide's algorithm in ssa
+# it is a fairly interesting
+# ssa program because of the
+# swap of b and a
+
+function $test() {
+@start
+
+@loop
+	%a =w phi @start 380, @loop %r
+	%b =w phi @start 747, @loop %a
+	%r =w rem %b, %a
+	jnz %r, @loop, @end
+
+@end
+	storew %a, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 1); }
+# <<<
diff --git a/src/test/euclc.ssa b/src/test/euclc.ssa
new file mode 100644
index 0000000..c76db2f
--- /dev/null
+++ b/src/test/euclc.ssa
@@ -0,0 +1,29 @@
+function w $test() {
+@l0
+	%a =l alloc4 4
+	%b =l alloc4 4
+	%r =l alloc4 4
+	storew 747, %a
+	storew 380, %b
+@l1
+	%t4 =w loadw %b
+	jnz %t4, @l2, @l3
+@l2
+	%t7 =w loadw %a
+	%t8 =w loadw %b
+	%t6 =w rem %t7, %t8
+	storew %t6, %r
+	%t10 =w loadw %b
+	storew %t10, %a
+	%t12 =w loadw %r
+	storew %t12, %b
+	jmp @l1
+@l3
+	%t13 =w loadw %a
+	ret %t13
+}
+
+# >>> driver
+# extern int test(void);
+# int main() { return !(test() == 1); }
+# <<<
diff --git a/src/test/fpcnv.ssa b/src/test/fpcnv.ssa
new file mode 100644
index 0000000..5fd3be9
--- /dev/null
+++ b/src/test/fpcnv.ssa
@@ -0,0 +1,27 @@
+# floating point casts and conversions
+
+function s $fneg(s %f) {
+@fneg
+	%b0 =w cast %f
+	%b1 =w xor 2147483648, %b0
+	%rs =s cast %b1
+	ret %rs
+}
+
+function d $ftrunc(d %f) {
+@ftrunc
+	%l0 =l ftosi %f
+	%rt =d sitof %l0
+	ret %rt
+}
+
+# >>> driver
+# extern float fneg(float);
+# extern double ftrunc(double);
+# int main() {
+# 	if (fneg(1.23f) != -1.23f)  return 1;
+# 	if (ftrunc(3.1415) != 3.0)  return 2;
+# 	if (ftrunc(-1.234) != -1.0) return 3;
+# 	return 0;
+# }
+# <<<
diff --git a/src/test/go.sh b/src/test/go.sh
new file mode 100755
index 0000000..35bf525
--- /dev/null
+++ b/src/test/go.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+TMP=/tmp/qbe.zzzz
+
+DRV=$TMP.c
+ASM=$TMP.s
+BIN=$TMP.bin
+OUT=$TMP.out
+
+cleanup() {
+	rm -f $DRV $ASM $BIN $OUT
+}
+
+extract() {
+	WHAT="$1"
+	FILE="$2"
+
+	awk "
+		/^# >>> $WHAT/ {
+			p = 1
+			next
+		}
+		/^# <<</ {
+			if (p)
+				p = 0
+		}
+		p
+	" $FILE \
+	| sed -e 's/# //' \
+	| sed -e 's/#$//'
+}
+
+once() {
+	T="$1"
+
+	if ! test -f $T
+	then
+		echo "invalid test file $T" >&2
+		exit 1
+	fi
+
+	echo "$T... "
+
+	if ! ./qbe $T -o $ASM
+	then
+		echo "[qbe fail]"
+		return 1
+	fi
+
+	extract driver $T > $DRV
+	extract output $T > $OUT
+
+	if test -s $DRV
+	then
+		LNK="$DRV $ASM"
+	else
+		LNK="$ASM"
+	fi
+
+	if ! cc -g -o $BIN $LNK
+	then
+		echo "[cc fail]"
+		return 1
+	fi
+
+	if test -s $OUT
+	then
+		$BIN a b c | diff - $OUT
+		RET=$?
+		REASON="output"
+	else
+		$BIN a b c
+		RET=$?
+		REASON="returned $RET"
+	fi
+
+	if test $RET -ne 0
+	then
+		echo "[$REASON fail]"
+		return 1
+	fi
+
+	printf "\033[1A\033[45C[ok]\n"
+}
+
+
+#trap cleanup TERM QUIT
+
+if test -z "$1"
+then
+	echo "usage: test/go.sh {all, SSAFILE}" 2>&1
+	exit 1
+fi
+
+case $1 in
+	"all")
+		F=0
+		for T in test/[!_]*.ssa
+		do
+			once $T
+			F=`expr $F + $?`
+		done
+		if test $F -ge 1
+		then
+			echo
+			echo "$F test(s) failed!"
+		else
+			echo
+			echo "All is fine!"
+		fi
+		;;
+	*)
+		once $1
+		exit $?
+		;;
+esac
diff --git a/src/test/loop.ssa b/src/test/loop.ssa
new file mode 100644
index 0000000..c8c4ee0
--- /dev/null
+++ b/src/test/loop.ssa
@@ -0,0 +1,23 @@
+# simple looping program
+# sums all integers from 100 to 0
+
+function $test() {
+@start
+
+@loop
+	%s  =w phi @start   0, @loop %s1
+	%n  =w phi @start 100, @loop %n1
+	%s1 =w add %s, %n
+	%n1 =w sub %n, 1
+	jnz %n1, @loop, @end
+
+@end
+	storew %s1, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 5050); }
+# <<<
diff --git a/src/test/mandel.ssa b/src/test/mandel.ssa
new file mode 100644
index 0000000..efefeb3
--- /dev/null
+++ b/src/test/mandel.ssa
@@ -0,0 +1,123 @@
+# Print the Mandelbrot set on the
+# terminal line output.
+
+function w $mandel(d %x, d %y) {
+@mandel
+	%cr =d sub %y, d_0.5
+	%ci =d copy %x
+@loop
+	%i =w phi @mandel 0, @loop1 %i1
+	%zr =d phi @mandel d_0, @loop1 %zr1
+	%zi =d phi @mandel d_0, @loop1 %zi1
+	%i1 =w add 1, %i
+	%tmp =d mul %zr, %zi
+	%zr2 =d mul %zr, %zr
+	%zi2 =d mul %zi, %zi
+	%zrx =d sub %zr2, %zi2
+	%zr1 =d add %zrx, %cr
+	%zix =d add %tmp, %tmp
+	%zi1 =d add %zix, %ci
+	%sum =d add %zi2, %zr2
+	%cmp1 =w cgtd %sum, d_16
+	jnz %cmp1, @reti, @loop1
+@loop1
+	%cmp2 =w csgtw %i1, 1000
+	jnz %cmp2, @ret0, @loop
+@reti
+	ret %i1
+@ret0
+	ret 0
+}
+
+function w $main() {
+@main
+@loopy
+	%y =d phi @main d_-1, @loopy1 %y1
+@loopx
+	%x =d phi @loopy d_-1, @loopx1 %x1
+	%i =w call $mandel(d %x, d %y)
+	jnz %i, @out, @in
+@in
+	%r0 =w call $putchar(w 42)   # '*'
+	jmp @loopx1
+@out
+	%r1 =w call $putchar(w 32)   # ' '
+	jmp @loopx1
+@loopx1
+	%x1 =d add %x, d_0.032
+	%cmp1 =w cgtd %x1, d_1
+	jnz %cmp1, @loopy1, @loopx
+@loopy1
+	%r2 =w call $putchar(w 10)   # '\n'
+	%y1 =d add %y, d_0.032
+	%cmp2 =w cgtd %y1, d_1
+	jnz %cmp2, @ret, @loopy
+@ret
+	ret 0
+}
+
+# >>> output
+#                                                                #
+#                                                                #
+#                                                                #
+#                                                                #
+#                                *                               #
+#                               ****                             #
+#                               ****                             #
+#                               ***                              #
+#                              *****                             #
+#                             *********                          #
+#                           ************                         #
+#                        *****************                       #
+#                         ****************                       #
+#                         ***************                        #
+#                         ****************                       #
+#                         ****************                       #
+#                        *****************                       #
+#                         ****************                       #
+#                         ****************                       #
+#                          **************                        #
+#                          *************                         #
+#                           ************                         #
+#                            *********                           #
+#                              *****                             #
+#                            ***********                         #
+#                         *****************                      #
+#                      **********************                    #
+#                   * *********************** **                 #
+#                   ***************************                  #
+#                  *****************************                 #
+#               * *******************************  **            #
+#              ** ***********************************            #
+#              *********************************** *             #
+#               ***********************************              #
+#              *************************************             #
+#              *************************************             #
+#             ***************************************            #
+#             ***************************************            #
+#             ***************************************            #
+#             ****************************************           #
+#       *     ****************************************           #
+#       ********************************************** ****      #
+#       ****************************************************     #
+#     * *****************************************************    #
+#     * *****************************************************    #
+#       ***** **************************************** ****      #
+#         *   ****************************************    *      #
+#             ****************************************           #
+#             ***************************************            #
+#            ****************************************            #
+#              ***************************************           #
+#             ****************************************           #
+#               ************************************             #
+#               ***********************************              #
+#                *********************************               #
+#               ************************************             #
+#               *** ************* ************** ***             #
+#                    ***********   ************   **             #
+#                      ********      ********                    #
+#                     **                *   *                    #
+#                                                                #
+#                                                                #
+#                                                                #
+# <<<
diff --git a/src/test/max.ssa b/src/test/max.ssa
new file mode 100644
index 0000000..547e9d4
--- /dev/null
+++ b/src/test/max.ssa
@@ -0,0 +1,33 @@
+# find the maximum value
+# in a nul-terminated array
+# of unsigned bytes
+#
+# the output is stored in $a
+
+data $arr = { b 10, b -60, b 10, b 100, b 200, b 0 }
+
+function $test() {
+@start
+@loop
+	%max =w phi @start -1, @new %byt, @old %max
+	%loc =l phi @start $arr,  @new %loc1, @old %loc1
+	%byt =w loadub %loc
+	%loc1 =l add 1, %loc
+	jnz %byt, @iter, @end
+@iter
+	%cmp =w cslew %max, %byt
+	jnz %cmp, @new, @old
+@new
+	jmp @loop
+@old
+	jmp @loop
+@end
+	storew %max, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 200); }
+# <<<
diff --git a/src/test/prime.ssa b/src/test/prime.ssa
new file mode 100644
index 0000000..12d0273
--- /dev/null
+++ b/src/test/prime.ssa
@@ -0,0 +1,32 @@
+# find the 10,001st prime
+# store it in a
+
+function $test() {
+@start
+@loop
+	%n =w phi @start 5, @tloop %n, @yes %n1
+	%p =w phi @start 13, @tloop %p1, @yes %p1
+	%p1 =w add %p, 2
+@tloop
+	%t =w phi @loop 3, @next %t1
+	%r =w rem %p, %t
+	jnz %r, @next, @loop
+@next
+	%t1 =w add 2, %t
+	%tsq =w mul %t1, %t1
+	%c0 =w csgtw %tsq, %p
+	jnz %c0, @yes, @tloop
+@yes
+	%n1 =w add 1, %n
+	%c1 =w ceqw 10001, %n1
+	jnz %c1, @end, @loop
+@end
+	storew %p, $a
+	ret
+}
+
+# >>> driver
+# extern void test(void);
+# int a;
+# int main() { test(); return !(a == 104743); }
+# <<<
diff --git a/src/test/puts10.ssa b/src/test/puts10.ssa
new file mode 100644
index 0000000..1dcf227
--- /dev/null
+++ b/src/test/puts10.ssa
@@ -0,0 +1,29 @@
+function $main() {
+@start
+	%y  =l alloc4 4
+	%y1 =l add %y, 1
+	storeb 0, %y1
+@loop
+	%n =w phi @start 0, @loop %n1
+	%c =w add %n, 48
+	storeb %c, %y
+	%r =w call $puts(l %y)
+	%n1 =w add %n, 1
+	%cmp =w cslew %n1, 9
+	jnz %cmp, @loop, @end
+@end
+	ret
+}
+
+# >>> output
+# 0
+# 1
+# 2
+# 3
+# 4
+# 5
+# 6
+# 7
+# 8
+# 9
+# <<<
diff --git a/src/test/sum.ssa b/src/test/sum.ssa
new file mode 100644
index 0000000..266054e
--- /dev/null
+++ b/src/test/sum.ssa
@@ -0,0 +1,31 @@
+# Simple test for addressing modes.
+
+function w $sum(l %arr, w %num) {
+@start
+@loop
+	%n1 =w phi @start %num, @loop1 %n2
+	%s0 =w phi @start 0, @loop1 %s1
+	%n2 =w sub %n1, 1
+	%c =w cslew %n1, 0
+	jnz %c, @end, @loop1
+@loop1
+	%idx0 =l extsw %n2
+	%idx1 =l mul 4, %idx0
+	%idx2 =l add %idx1, %arr
+	%w =w loadw %idx2
+	%s1 =w add %w, %s0
+	jmp @loop
+@end
+	ret %s0
+}
+
+# >>> driver
+# extern int sum(int *, int);
+# int arr[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 };
+# #define N sizeof arr / sizeof arr[0]
+# int main() {
+# 	int i, s;
+# 	for (s=i=0; i<N; i++) s+=arr[i];
+# 	return !(sum(arr, N) == s);
+# }
+# <<<