summary refs log tree commit diff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/vatest.py157
1 files changed, 157 insertions, 0 deletions
diff --git a/tools/vatest.py b/tools/vatest.py
new file mode 100644
index 0000000..c9b1bbd
--- /dev/null
+++ b/tools/vatest.py
@@ -0,0 +1,157 @@
+# generate variadic calls to test the
+# abi implementation
+
+from random import seed, randint, uniform
+from struct import unpack
+
+I, D = 'd', 'g'
+
+formats = [
+	# list of format to tests
+	[I],
+	[D],
+	[I,D],
+	[D,D],
+	[I,I,I,I],
+	[D,D,D,D],
+	[I,D,I,D],
+	[D,D,I,I],
+	[I,I,D,D],
+	[],
+]
+
+generate = [
+	# numbers of fixed integer and
+	# floating point arguments to
+	# test
+	(0, 0), (1, 0), (0, 1), (4, 0),
+	(0, 6), (5, 7), (10, 10),
+]
+
+def mkargs(nargs, type, name):
+	args = map(
+		lambda n: ''.join([type, name, str(n), ', ']),
+		range(nargs)
+	)
+	return ''.join(args)
+
+def mkfstr(fmt):
+	fstr = map(
+		lambda x: {I: '%d ', D: '%g '}[x],
+		fmt
+	)
+	return '"' + ''.join(fstr) + '\\n"'
+
+def randargs(fmt):
+	ra = {
+		I: lambda: '{}'.format(randint(-10, 10)),
+		D: lambda: '{0:.4g}'.format(uniform(-10, 10))
+	}
+	return list(map(lambda x: ra[x](), fmt))
+
+def genssa(qbeprint, qbecall):
+	funcs = [('qbeprint', qbeprint), ('qbecall', qbecall)]
+	for fnum, (nia, nfa) in enumerate(generate):
+		params = "{}{}l %fmt, ...".format(
+			mkargs(nia, 'w ', '%argw'),
+			mkargs(nfa, 'd ', '%argd')
+		)
+		for name, code in funcs:
+			print('export function ${}{}({}) {}'
+				.format(name, fnum, params, code)
+			)
+
+def gendriver():
+	print('# >>> driver')
+	print('# #include <stdio.h>')
+
+	for fnum, (nia, nfa) in enumerate(generate):
+		params = "{}{}char *, ...".format(
+			mkargs(nia, 'int ', 'argw'),
+			mkargs(nfa, 'double ', 'argd')
+		)
+		for name in ['qbeprint', 'qbecall']:
+			print('# extern void {}{}({});'
+				.format(name, fnum, params)
+			)
+
+	output = ''
+	print('# int main() {')
+
+	for fnum, (nia, nfa) in enumerate(generate):
+		info = '# ({} int, {} double)'.format(nia, nfa)
+		print('# 	puts("{}");'.format(info))
+		output += '# {}\n'.format(info)
+		for fmt in formats:
+			ra = randargs(fmt)
+			vaargs = ', '.join(ra)
+			expect = ' '.join(ra)
+			if fmt:
+				vaargs = ', ' + vaargs
+				expect = expect + ' '
+			args = ''.join(
+				['0, '] * (nia+nfa) +
+				[mkfstr(fmt), vaargs]
+			)
+			for name in ['qbeprint', 'qbecall']:
+				print('# 	{}{}({});'
+					.format(name, fnum, args)
+				)
+				output += '# {}\n'.format(expect)
+
+	print('# }')
+	print('# <<<')
+
+	print('\n# >>> output\n' + output + '# <<<')
+
+
+qbeprint="""{{
+@start
+	%fmtdbl =l alloc4 4
+	%fmtint =l alloc4 4
+	%emptys =l alloc4 4
+	storew {}, %fmtint
+	storew {}, %fmtdbl
+	storew 0, %emptys
+	%vp =l alloc8 24
+	%fmt1 =l add 1, %fmt
+	vastart %vp
+@loop
+	%p =l phi @start %fmt1, @casef %p1, @cased %p1
+	%c =w loadsb %p
+	%p1 =l add 3, %p
+	jnz %c, @loop1, @end
+@loop1
+	%isg =w ceqw %c, 103
+	jnz %isg, @casef, @cased
+@casef
+	%dbl =d vaarg %vp
+	call $printf(l %fmtdbl, d %dbl, ...)
+	jmp @loop
+@cased
+	%int =w vaarg %vp
+	call $printf(l %fmtint, w %int, ...)
+	jmp @loop
+@end
+	call $puts(l %emptys)
+	ret
+}}
+""".format(
+	unpack("i", b'%d \x00')[0],
+	unpack("i", b'%g \x00')[0]
+)
+
+qbecall="""{
+@start
+	%vp =l alloc8 24
+	vastart %vp
+	call $vprintf(l %fmt, l %vp)
+	ret
+}
+"""
+
+
+if __name__ == "__main__":
+	seed(42)
+	genssa(qbeprint, qbecall)
+	gendriver()