~mcf/cproc

97c8fc5358bbecb6e2452425861e6cd5a5c93f91 — Michael Forney a month ago 056c471
expr: Fix varargs again and add more tests
17 files changed, 174 insertions(+), 95 deletions(-)

M expr.c
M test/builtin-va-copy+x86_64.c
M test/builtin-va-copy+x86_64.qbe
D test/varargs+aarch64.c
A test/varargs+aarch64.c
M test/varargs+aarch64.qbe
D test/varargs+riscv64.c
A test/varargs+riscv64.c
M test/varargs+riscv64.qbe
M test/varargs+x86_64.c
M test/varargs+x86_64.qbe
D test/varargs-pass-valist+aarch64.c
D test/varargs-pass-valist+aarch64.qbe
D test/varargs-pass-valist+riscv64.c
D test/varargs-pass-valist+riscv64.qbe
D test/varargs-pass-valist+x86_64.c
D test/varargs-pass-valist+x86_64.qbe
M expr.c => expr.c +6 -6
@@ 645,7 645,7 @@ builtinfunc(struct scope *s, enum builtinkind kind)
		e->base = assignexpr(s);
		if (!typesame(e->base->type, typeadjvalist))
			error(&tok.loc, "va_arg argument must have type va_list");
		if (!e->base->decayed)
		if (typeadjvalist == targ->typevalist)
			e->base = mkunaryexpr(TBAND, e->base);
		expect(TCOMMA, "after va_list");
		e->type = typename(s, &e->qual);


@@ 655,14 655,14 @@ builtinfunc(struct scope *s, enum builtinkind kind)
		e->assign.l = assignexpr(s);
		if (!typesame(e->assign.l->type, typeadjvalist))
			error(&tok.loc, "va_copy destination must have type va_list");
		if (e->assign.l->decayed)
			e->assign.l = e->assign.l->base;
		if (typeadjvalist != targ->typevalist)
			e->assign.l = mkunaryexpr(TMUL, e->assign.l);
		expect(TCOMMA, "after target va_list");
		e->assign.r = assignexpr(s);
		if (!typesame(e->assign.r->type, typeadjvalist))
			error(&tok.loc, "va_copy source must have type va_list");
		if (e->assign.r->decayed)
			e->assign.r = e->assign.r->base;
		if (typeadjvalist != targ->typevalist)
			e->assign.r = mkunaryexpr(TMUL, e->assign.r);
		break;
	case BUILTINVAEND:
		e = assignexpr(s);


@@ 677,7 677,7 @@ builtinfunc(struct scope *s, enum builtinkind kind)
		e->base = assignexpr(s);
		if (!typesame(e->base->type, typeadjvalist))
			error(&tok.loc, "va_start argument must have type va_list");
		if (!e->base->decayed)
		if (typeadjvalist == targ->typevalist)
			e->base = mkunaryexpr(TBAND, e->base);
		expect(TCOMMA, "after va_list");
		param = assignexpr(s);

M test/builtin-va-copy+x86_64.c => test/builtin-va-copy+x86_64.c +8 -1
@@ 1,4 1,11 @@
void f(void) {
void f1(void) {
	static __builtin_va_list a, b;
	__builtin_va_copy(a, b);
}
void f2(__builtin_va_list b) {
	static __builtin_va_list a;
	__builtin_va_copy(a, b);
}
void f3(__builtin_va_list a, __builtin_va_list b) {
	__builtin_va_copy(a, b);
}

M test/builtin-va-copy+x86_64.qbe => test/builtin-va-copy+x86_64.qbe +43 -1
@@ 1,7 1,7 @@
data $.La.2 = align 8 { z 24 }
data $.Lb.3 = align 8 { z 24 }
export
function $f() {
function $f1() {
@start.1
@body.2
	%.1 =l loadl $.Lb.3


@@ 16,3 16,45 @@ function $f() {
	storel %.7, %.6
	ret
}
data $.La.5 = align 8 { z 24 }
export
function $f2(l %.1) {
@start.3
	%.2 =l alloc8 8
	storel %.1, %.2
@body.4
	%.3 =l loadl %.2
	%.4 =l loadl %.3
	storel %.4, $.La.5
	%.5 =l add %.3, 8
	%.6 =l add $.La.5, 8
	%.7 =l loadl %.5
	storel %.7, %.6
	%.8 =l add %.5, 8
	%.9 =l add %.6, 8
	%.10 =l loadl %.8
	storel %.10, %.9
	ret
}
export
function $f3(l %.1, l %.3) {
@start.5
	%.2 =l alloc8 8
	storel %.1, %.2
	%.4 =l alloc8 8
	storel %.3, %.4
@body.6
	%.5 =l loadl %.4
	%.6 =l loadl %.2
	%.7 =l loadl %.5
	storel %.7, %.6
	%.8 =l add %.5, 8
	%.9 =l add %.6, 8
	%.10 =l loadl %.8
	storel %.10, %.9
	%.11 =l add %.8, 8
	%.12 =l add %.9, 8
	%.13 =l loadl %.11
	storel %.13, %.12
	ret
}

D test/varargs+aarch64.c => test/varargs+aarch64.c +0 -12
@@ 1,12 0,0 @@
void f(int n, ...) {
	__builtin_va_list ap;

	__builtin_va_start(ap, n);
	while (n) {
		__builtin_va_arg(ap, int);
		__builtin_va_arg(ap, float);
		__builtin_va_arg(ap, char *);
		--n;
	}
	__builtin_va_end(ap);
}

A test/varargs+aarch64.c => test/varargs+aarch64.c +1 -0
@@ 0,0 1,1 @@
varargs+x86_64.c
\ No newline at end of file

M test/varargs+aarch64.qbe => test/varargs+aarch64.qbe +32 -7
@@ 1,22 1,47 @@
type :va_list.1 = align 8 { 32 }
export
function $f(w %.1, ...) {
function w $f1(w %.1, :va_list.1 %.3) {
@start.1
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc8 32
@body.2
	%.4 =w vaarg %.3
	ret %.4
}
export
function w $f2(w %.1, ...) {
@start.3
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc4 4
	%.4 =l alloc8 32
@body.4
	vastart %.4
	%.5 =w loadw %.2
	%.6 =w call $f1(w %.5, :va_list.1 %.4)
	storew %.6, %.3
	%.7 =w loadw %.3
	ret %.7
}
export
function $f3(w %.1, ...) {
@start.5
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc8 32
@body.6
	vastart %.3
@while_cond.3
@while_cond.7
	%.4 =w loadw %.2
	jnz %.4, @while_body.4, @while_join.5
@while_body.4
	jnz %.4, @while_body.8, @while_join.9
@while_body.8
	%.5 =w vaarg %.3
	%.6 =s vaarg %.3
	%.7 =l vaarg %.3
	%.8 =w loadw %.2
	%.9 =w sub %.8, 1
	storew %.9, %.2
	jmp @while_cond.3
@while_join.5
	jmp @while_cond.7
@while_join.9
	ret
}

D test/varargs+riscv64.c => test/varargs+riscv64.c +0 -12
@@ 1,12 0,0 @@
void f(int n, ...) {
	__builtin_va_list ap;

	__builtin_va_start(ap, n);
	while (n) {
		__builtin_va_arg(ap, int);
		__builtin_va_arg(ap, float);
		__builtin_va_arg(ap, char *);
		--n;
	}
	__builtin_va_end(ap);
}

A test/varargs+riscv64.c => test/varargs+riscv64.c +1 -0
@@ 0,0 1,1 @@
varargs+x86_64.c
\ No newline at end of file

M test/varargs+riscv64.qbe => test/varargs+riscv64.qbe +34 -7
@@ 1,22 1,49 @@
export
function $f(w %.1, ...) {
function w $f1(w %.1, l %.3) {
@start.1
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc8 8
	%.4 =l alloc8 8
	storel %.3, %.4
@body.2
	%.5 =w vaarg %.4
	ret %.5
}
export
function w $f2(w %.1, ...) {
@start.3
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc4 4
	%.4 =l alloc8 8
@body.4
	vastart %.4
	%.5 =w loadw %.2
	%.6 =l loadl %.4
	%.7 =w call $f1(w %.5, l %.6)
	storew %.7, %.3
	%.8 =w loadw %.3
	ret %.8
}
export
function $f3(w %.1, ...) {
@start.5
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc8 8
@body.6
	vastart %.3
@while_cond.3
@while_cond.7
	%.4 =w loadw %.2
	jnz %.4, @while_body.4, @while_join.5
@while_body.4
	jnz %.4, @while_body.8, @while_join.9
@while_body.8
	%.5 =w vaarg %.3
	%.6 =s vaarg %.3
	%.7 =l vaarg %.3
	%.8 =w loadw %.2
	%.9 =w sub %.8, 1
	storew %.9, %.2
	jmp @while_cond.3
@while_join.5
	jmp @while_cond.7
@while_join.9
	ret
}

M test/varargs+x86_64.c => test/varargs+x86_64.c +15 -1
@@ 1,4 1,18 @@
void f(int n, ...) {
int f1(int n, __builtin_va_list ap) {
	return __builtin_va_arg(ap, int);
}

int f2(int n, ...) {
	int r;
	__builtin_va_list ap;

	__builtin_va_start(ap, n);
	r = f1(n, ap);
	__builtin_va_end(ap);
	return r;
}

void f3(int n, ...) {
	__builtin_va_list ap;

	__builtin_va_start(ap, n);

M test/varargs+x86_64.qbe => test/varargs+x86_64.qbe +34 -7
@@ 1,22 1,49 @@
export
function $f(w %.1, ...) {
function w $f1(w %.1, l %.3) {
@start.1
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc8 24
	%.4 =l alloc8 8
	storel %.3, %.4
@body.2
	%.5 =l loadl %.4
	%.6 =w vaarg %.5
	ret %.6
}
export
function w $f2(w %.1, ...) {
@start.3
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc4 4
	%.4 =l alloc8 24
@body.4
	vastart %.4
	%.5 =w loadw %.2
	%.6 =w call $f1(w %.5, l %.4)
	storew %.6, %.3
	%.7 =w loadw %.3
	ret %.7
}
export
function $f3(w %.1, ...) {
@start.5
	%.2 =l alloc4 4
	storew %.1, %.2
	%.3 =l alloc8 24
@body.6
	vastart %.3
@while_cond.3
@while_cond.7
	%.4 =w loadw %.2
	jnz %.4, @while_body.4, @while_join.5
@while_body.4
	jnz %.4, @while_body.8, @while_join.9
@while_body.8
	%.5 =w vaarg %.3
	%.6 =s vaarg %.3
	%.7 =l vaarg %.3
	%.8 =w loadw %.2
	%.9 =w sub %.8, 1
	storew %.9, %.2
	jmp @while_cond.3
@while_join.5
	jmp @while_cond.7
@while_join.9
	ret
}

D test/varargs-pass-valist+aarch64.c => test/varargs-pass-valist+aarch64.c +0 -5
@@ 1,5 0,0 @@
void f(__builtin_va_list ap);
void g(void) {
	static __builtin_va_list ap;
	f(ap);
}

D test/varargs-pass-valist+aarch64.qbe => test/varargs-pass-valist+aarch64.qbe +0 -9
@@ 1,9 0,0 @@
data $.Lap.2 = align 8 { z 32 }
type :va_list.1 = align 8 { 32 }
export
function $g() {
@start.1
@body.2
	call $f(:va_list.1 $.Lap.2)
	ret
}

D test/varargs-pass-valist+riscv64.c => test/varargs-pass-valist+riscv64.c +0 -5
@@ 1,5 0,0 @@
void f(__builtin_va_list ap);
void g(void) {
	static __builtin_va_list ap;
	f(ap);
}

D test/varargs-pass-valist+riscv64.qbe => test/varargs-pass-valist+riscv64.qbe +0 -9
@@ 1,9 0,0 @@
data $.Lap.2 = align 8 { z 8 }
export
function $g() {
@start.1
@body.2
	%.1 =l loadl $.Lap.2
	call $f(l %.1)
	ret
}

D test/varargs-pass-valist+x86_64.c => test/varargs-pass-valist+x86_64.c +0 -5
@@ 1,5 0,0 @@
void f(__builtin_va_list ap);
void g(void) {
	static __builtin_va_list ap;
	f(ap);
}

D test/varargs-pass-valist+x86_64.qbe => test/varargs-pass-valist+x86_64.qbe +0 -8
@@ 1,8 0,0 @@
data $.Lap.2 = align 8 { z 24 }
export
function $g() {
@start.1
@body.2
	call $f(l $.Lap.2)
	ret
}