mirror of
https://github.com/rui314/chibicc
synced 2024-11-22 06:11:18 +03:00
Allow variadic function to take more than 6 parameters
This commit is contained in:
parent
d7bad96114
commit
b6d3cd00df
@ -1178,9 +1178,11 @@ static void emit_text(Obj *prog) {
|
||||
int off = fn->va_area->offset;
|
||||
|
||||
// va_elem
|
||||
println(" movl $%d, %d(%%rbp)", gp * 8, off);
|
||||
println(" movl $%d, %d(%%rbp)", fp * 8 + 48, off + 4);
|
||||
println(" movq %%rbp, %d(%%rbp)", off + 16);
|
||||
println(" movl $%d, %d(%%rbp)", gp * 8, off); // gp_offset
|
||||
println(" movl $%d, %d(%%rbp)", fp * 8 + 48, off + 4); // fp_offset
|
||||
println(" movq %%rbp, %d(%%rbp)", off + 8); // overflow_arg_area
|
||||
println(" addq $16, %d(%%rbp)", off + 8);
|
||||
println(" movq %%rbp, %d(%%rbp)", off + 16); // reg_save_area
|
||||
println(" addq $%d, %d(%%rbp)", off + 24, off + 16);
|
||||
|
||||
// __reg_save_area__
|
||||
|
@ -15,28 +15,38 @@ typedef __va_elem va_list[1];
|
||||
|
||||
#define va_end(ap)
|
||||
|
||||
static void *__va_arg_gp(__va_elem *ap) {
|
||||
void *r = (char *)ap->reg_save_area + ap->gp_offset;
|
||||
static void *__va_arg_mem(__va_elem *ap, int sz, int align) {
|
||||
void *p = ap->overflow_arg_area;
|
||||
if (align > 8)
|
||||
p = (p + 15) / 16 * 16;
|
||||
ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void *__va_arg_gp(__va_elem *ap, int sz, int align) {
|
||||
if (ap->gp_offset >= 48)
|
||||
return __va_arg_mem(ap, sz, align);
|
||||
|
||||
void *r = ap->reg_save_area + ap->gp_offset;
|
||||
ap->gp_offset += 8;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void *__va_arg_fp(__va_elem *ap) {
|
||||
void *r = (char *)ap->reg_save_area + ap->fp_offset;
|
||||
static void *__va_arg_fp(__va_elem *ap, int sz, int align) {
|
||||
if (ap->fp_offset >= 112)
|
||||
return __va_arg_mem(ap, sz, align);
|
||||
|
||||
void *r = ap->reg_save_area + ap->fp_offset;
|
||||
ap->fp_offset += 8;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void *__va_arg_mem(__va_elem *ap) {
|
||||
1 / 0; // not implemented
|
||||
}
|
||||
|
||||
#define va_arg(ap, type) \
|
||||
({ \
|
||||
int klass = __builtin_reg_class(type); \
|
||||
*(type *)(klass == 0 ? __va_arg_gp(ap) : \
|
||||
klass == 1 ? __va_arg_fp(ap) : \
|
||||
__va_arg_mem(ap)); \
|
||||
#define va_arg(ap, ty) \
|
||||
({ \
|
||||
int klass = __builtin_reg_class(ty); \
|
||||
*(ty *)(klass == 0 ? __va_arg_gp(ap, sizeof(ty), _Alignof(ty)) : \
|
||||
klass == 1 ? __va_arg_fp(ap, sizeof(ty), _Alignof(ty)) : \
|
||||
__va_arg_mem(ap, sizeof(ty), _Alignof(ty))); \
|
||||
})
|
||||
|
||||
#define __GNUC_VA_LIST 1
|
||||
|
@ -3,6 +3,7 @@
|
||||
void assert(int expected, int actual, char *code);
|
||||
int printf(char *fmt, ...);
|
||||
int sprintf(char *buf, char *fmt, ...);
|
||||
int vsprintf(char *buf, char *fmt, void *ap);
|
||||
int strcmp(char *p, char *q);
|
||||
int strncmp(char *p, char *q, long n);
|
||||
int memcmp(char *p, char *q, long n);
|
||||
|
@ -28,9 +28,20 @@ int sum2(int x, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
char *fmt(char *buf, char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT(6, sum1(1, 2, 3, 0));
|
||||
ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0));
|
||||
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));
|
||||
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));
|
||||
ASSERT(210, sum2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user