summary refs log tree commit diff
path: root/test
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-09-04 17:23:54 -0700
committerQuentin Carbonneaux <quentin@c9x.me>2021-09-07 08:31:48 +0200
commit6a69210b0faf33ad4feb6adc97d094022c520978 (patch)
tree1e1902fd35d5dffa34eda6be15f9dc822ba74ec1 /test
parent649a546d702b41474fe76e9c779086cc8d35f3d2 (diff)
downloadroux-6a69210b0faf33ad4feb6adc97d094022c520978.tar.gz
test: use architecture-neutral wrapper for calling vprintf
Different architectures use different types for va_list:

x86_64 uses an 1-length array of struct type[0]:

	typedef struct {
		unsigned int gp_offset;
		unsigned int fp_offset;
		void *overflow_arg_area;
		void *reg_save_area;
	} va_list[1];

aarch64 uses a struct type[1]

	typedef struct {
		void *__stack;
		void *__gr_top;
		void *__vr_top;
		int   __gr_offs;
		int   __vr_offs;
	} va_list;

Consequently, C functions which takes a va_list as an argument,
such as vprintf, may pass va_list in different ways depending on
the architecture.

On x86_64, va_list is an array type, so parameter decays to a pointer
and passing the address of the va_list is correct.

On aarch64, the va_list struct is passed by value, but since it is
larger than 16 bytes, the parameter is replaced with a pointer to
caller-allocated memory. Thus, passing the address as an l argument
happens to work.

However, this pattern of passing the address of the va_list to
vprintf doesn't extend to other architectures. On riscv64, va_list
is defined as

	typedef void *va_list;

which is *not* passed by reference. This means that tests that call
vprintf using the address of a va_list (vararg1 and vararg2) will
not work on riscv.

To fix this while keeping the tests architecture-neutral, add a
small wrapper function to the driver which takes a va_list *, and
let the C compiler deal with the details of passing va_list by
value.

[0] https://c9x.me/compile/bib/abi-x64.pdf#figure.3.34
[1] https://c9x.me/compile/bib/abi-arm64.pdf#%5B%7B%22num%22%3A63%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C52%2C757%2C0%5D
[2] https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#va_list-va_start-and-va_arg$
Diffstat (limited to 'test')
-rw-r--r--test/vararg1.ssa7
-rw-r--r--test/vararg2.ssa18
2 files changed, 17 insertions, 8 deletions
diff --git a/test/vararg1.ssa b/test/vararg1.ssa
index 393743c..3b33890 100644
--- a/test/vararg1.ssa
+++ b/test/vararg1.ssa
@@ -13,13 +13,18 @@ function w $g(l %fmt, ...) {
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret %r
 }
 
 # >>> driver
+# #include <stdarg.h>
+# #include <stdio.h>
 # extern double f(int, ...);
 # extern int g(char *, ...);
+# int print(const char *fmt, va_list *ap) {
+# 	return vprintf(fmt, *ap);
+# }
 # int main() {
 # 	g("Hell%c %s %g!\n", 'o', "world", f(42, "x", 42.0));
 # }
diff --git a/test/vararg2.ssa b/test/vararg2.ssa
index 52a6906..7e85774 100644
--- a/test/vararg2.ssa
+++ b/test/vararg2.ssa
@@ -34,7 +34,7 @@ export function $qbecall0(l %fmt, ...) {
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
@@ -74,7 +74,7 @@ export function $qbecall1(w %argw0, l %fmt, ...) {
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
@@ -114,7 +114,7 @@ export function $qbecall2(d %argd0, l %fmt, ...) {
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
@@ -154,7 +154,7 @@ export function $qbecall3(w %argw0, w %argw1, w %argw2, w %argw3, l %fmt, ...) {
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
@@ -194,7 +194,7 @@ export function $qbecall4(d %argd0, d %argd1, d %argd2, d %argd3, d %argd4, d %a
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
@@ -234,7 +234,7 @@ export function $qbecall5(w %argw0, w %argw1, w %argw2, w %argw3, w %argw4, d %a
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
@@ -274,11 +274,12 @@ export function $qbecall6(w %argw0, w %argw1, w %argw2, w %argw3, w %argw4, w %a
 @start
 	%vp =l alloc8 32
 	vastart %vp
-	%r =w call $vprintf(l %fmt, l %vp)
+	%r =w call $print(l %fmt, l %vp)
 	ret
 }
 
 # >>> driver
+# #include <stdarg.h>
 # #include <stdio.h>
 # extern void qbeprint0(char *, ...);
 # extern void qbecall0(char *, ...);
@@ -294,6 +295,9 @@ export function $qbecall6(w %argw0, w %argw1, w %argw2, w %argw3, w %argw4, w %a
 # extern void qbecall5(int argw0, int argw1, int argw2, int argw3, int argw4, double argd0, double argd1, double argd2, double argd3, double argd4, double argd5, double argd6, char *, ...);
 # extern void qbeprint6(int argw0, int argw1, int argw2, int argw3, int argw4, int argw5, int argw6, int argw7, int argw8, int argw9, double argd0, double argd1, double argd2, double argd3, double argd4, double argd5, double argd6, double argd7, double argd8, double argd9, char *, ...);
 # extern void qbecall6(int argw0, int argw1, int argw2, int argw3, int argw4, int argw5, int argw6, int argw7, int argw8, int argw9, double argd0, double argd1, double argd2, double argd3, double argd4, double argd5, double argd6, double argd7, double argd8, double argd9, char *, ...);
+# int print(const char *fmt, va_list *ap) {
+# 	return vprintf(fmt, *ap);
+# }
 # int main() {
 # 	puts("# (0 int, 0 double)");
 # 	qbeprint0("%d \n", 3);