Skip to content

Commit

Permalink
Add va_arg()
Browse files Browse the repository at this point in the history
  • Loading branch information
rui314 committed Dec 7, 2020
1 parent 7cbfd11 commit 5322ea8
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
24 changes: 24 additions & 0 deletions include/stdarg.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ 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;
ap->gp_offset += 8;
return r;
}

static void *__va_arg_fp(__va_elem *ap) {
void *r = (char *)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 __GNUC_VA_LIST 1
typedef va_list __gnuc_va_list;

Expand Down
13 changes: 13 additions & 0 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -2246,6 +2246,7 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) {
// | "sizeof" unary
// | "_Alignof" "(" type-name ")"
// | "_Alignof" unary
// | "__builtin_reg_class" "(" type-name ")"
// | ident
// | str
// | num
Expand Down Expand Up @@ -2290,6 +2291,18 @@ static Node *primary(Token **rest, Token *tok) {
return new_ulong(node->ty->align, tok);
}

if (equal(tok, "__builtin_reg_class")) {
tok = skip(tok->next, "(");
Type *ty = typename(&tok, tok);
*rest = skip(tok, ")");

if (is_integer(ty) || ty->kind == TY_PTR)
return new_num(0, start);
if (is_flonum(ty))
return new_num(1, start);
return new_num(2, start);
}

if (tok->kind == TK_IDENT) {
// Variable or enum constant
VarScope *sc = find_var(tok);
Expand Down
37 changes: 37 additions & 0 deletions test/varargs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "test.h"
#include <stdarg.h>

int sum1(int x, ...) {
va_list ap;
va_start(ap, x);

for (;;) {
int y = va_arg(ap, int);
if (y == 0)
return x;
x += y;
}
}

int sum2(int x, ...) {
va_list ap;
va_start(ap, x);

for (;;) {
double y = va_arg(ap, double);
x += y;

int z = va_arg(ap, int);
if (z == 0)
return x;
x += z;
}
}

int main() {
ASSERT(6, sum1(1, 2, 3, 0));
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));

printf("OK\n");
return 0;
}

0 comments on commit 5322ea8

Please sign in to comment.