commit 1557ce048255aed8b072675b250ecdfd6a0df0ab
parent a84618bba7d82a3c2cd9f96bcf12344199174761
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Fri, 10 Feb 2017 20:00:57 +0100
[cc1] Add support for va_arg builtins
Diffstat:
11 files changed, 254 insertions(+), 34 deletions(-)
diff --git a/cc1/Makefile b/cc1/Makefile
@@ -6,7 +6,8 @@ CSTDINC = -I../inc/$(STD)
include ../config.mk
OBJS = types.o decl.o lex.o error.o symbol.o main.o expr.o \
- code.o stmt.o cpp.o fold.o init.o arch/$(ARCH)/arch.o
+ code.o stmt.o cpp.o fold.o init.o builtin.o \
+ arch/$(ARCH)/arch.o
all: cc1-$(ARCH)
diff --git a/cc1/arch/amd64-sysv/arch.c b/cc1/arch/amd64-sysv/arch.c
@@ -183,13 +183,13 @@ static Type types[] = {
.align = 8,
.n.rank = RANK_LONG,
},
- { /* 20 = va_list_type */
- .op = PTR,
- .letter = L_POINTER,
+ { /* 20 = va_type */
+ .op = STRUCT,
+ .letter = L_VA_ARG,
.prop = TDEFINED,
- .size = 8,
+ .size = 24,
.align = 8,
- }
+ },
};
Type *voidtype = &types[0], *pvoidtype = &types[1],
@@ -202,9 +202,21 @@ Type *voidtype = &types[0], *pvoidtype = &types[1],
*floattype = &types[14], *doubletype = &types[15],
*ldoubletype = &types[16],
*sizettype = &types[17], *pdifftype = &types[19],
- *ellipsistype = &types[18],
- *va_list_type = &types[20];
+ *ellipsistype = &types[18], *va_type = &types[20],
+ *va_list_type;
static Symbol dummy0 = {.u.i = 0, .type = &types[9]},
dummy1 = {.u.i = 1, .type = &types[9]};
Symbol *zero = &dummy0, *one = &dummy1;
+
+void
+iarch(void)
+{
+ va_list_type = mktype(va_type, ARY, 1, NULL);
+}
+
+int
+valid_va_list(Type *tp)
+{
+ return tp->op == PTR && tp->type == va_type;
+}
diff --git a/cc1/arch/i386-sysv/arch.c b/cc1/arch/i386-sysv/arch.c
@@ -183,13 +183,13 @@ static Type types[] = {
.align = 4,
.n.rank = RANK_INT,
},
- { /* 20 = va_list_type */
+ { /* 20 = va_list_type */
.op = PTR,
.letter = L_POINTER,
.prop = TDEFINED,
- .size = 8,
- .align = 8,
- }
+ .size = 4,
+ .align = 4,
+ },
};
@@ -203,11 +203,21 @@ Type *voidtype = &types[0], *pvoidtype = &types[1],
*floattype = &types[14], *doubletype = &types[15],
*ldoubletype = &types[16],
*sizettype = &types[17], *pdifftype = &types[19],
- *ellipsistype = &types[18],
- *va_list_type = &types[20];
+ *ellipsistype = &types[18], *va_list_type = &types[20];
static Symbol dummy0 = {.u.i = 0, .type = &types[9]},
dummy1 = {.u.i = 1, .type = &types[9]};
Symbol *zero = &dummy0, *one = &dummy1;
+
+void
+iarch(void)
+{
+}
+
+int
+valid_va_list(Type *tp)
+{
+ return tp == va_list_type;
+}
diff --git a/cc1/arch/qbe/arch.c b/cc1/arch/qbe/arch.c
@@ -183,13 +183,13 @@ static Type types[] = {
.align = 8,
.n.rank = RANK_LONG,
},
- { /* 20 = va_list_type */
- .op = PTR,
- .letter = L_POINTER,
+ { /* 20 = va_type */
+ .op = STRUCT,
+ .letter = L_VA_ARG,
.prop = TDEFINED,
- .size = 8,
+ .size = 24,
.align = 8,
- }
+ },
};
Type *voidtype = &types[0], *pvoidtype = &types[1],
@@ -202,9 +202,21 @@ Type *voidtype = &types[0], *pvoidtype = &types[1],
*floattype = &types[14], *doubletype = &types[15],
*ldoubletype = &types[16],
*sizettype = &types[17], *pdifftype = &types[19],
- *ellipsistype = &types[18],
- *va_list_type = &types[20];
+ *ellipsistype = &types[18], *va_type = &types[20],
+ *va_list_type;
static Symbol dummy0 = {.u.i = 0, .type = &types[9]},
dummy1 = {.u.i = 1, .type = &types[9]};
Symbol *zero = &dummy0, *one = &dummy1;
+
+void
+iarch(void)
+{
+ va_list_type = mktype(va_type, ARY, 1, NULL);
+}
+
+int
+valid_va_list(Type *tp)
+{
+ return tp->op == PTR && tp->type == va_type;
+}
diff --git a/cc1/arch/z80/arch.c b/cc1/arch/z80/arch.c
@@ -187,8 +187,8 @@ static Type types[] = {
.op = PTR,
.letter = L_POINTER,
.prop = TDEFINED,
- .size = 8,
- .align = 8,
+ .size = 2,
+ .align = 1,
}
};
@@ -202,10 +202,20 @@ Type *voidtype = &types[0], *pvoidtype = &types[1],
*floattype = &types[14], *doubletype = &types[15],
*ldoubletype = &types[16],
*sizettype = &types[17], *pdifftype = &types[19],
- *ellipsistype = &types[18],
- *va_list_type = &types[20];
+ *ellipsistype = &types[18], *va_list_type = &types[20];
static Symbol dummy0 = {.u.i = 0, .type = &types[9]},
dummy1 = {.u.i = 1, .type = &types[9]};
Symbol *zero = &dummy0, *one = &dummy1;
+
+void
+iarch(void)
+{
+}
+
+int
+valid_va_list(Type *tp)
+{
+ return tp == va_list_type;
+}
diff --git a/cc1/builtin.c b/cc1/builtin.c
@@ -0,0 +1,100 @@
+/* See LICENSE file for copyright and license details. */
+static char sccsid[] = "@(#) ./cc1/builtin.c";
+
+#include <stdio.h>
+
+#include "../inc/cc.h"
+#include "cc1.h"
+
+static Node *
+builtin_va_arg(Symbol *sym)
+{
+ Node *np, *ap;
+ Type *tp;
+
+ ap = assign();
+ expect(',');
+ tp = typename();
+
+ if (!valid_va_list(ap->type)) {
+ errorp("incorrect parameters for va_arg");
+ return constnode(zero);
+ }
+
+ np = node(OBUILTIN, tp, ap, NULL);
+ np->sym = sym;
+ return np;
+}
+
+static Node *
+builtin_va_copy(Symbol *sym)
+{
+ Node *np, *src, *dst;
+
+ dst = assign();
+ expect(',');
+ src = assign();
+
+ if (!valid_va_list(dst->type) || !valid_va_list(src->type)) {
+ errorp("incorrect parameters for va_copy");
+ return constnode(zero);
+ }
+
+ np = node(OBUILTIN, voidtype, dst, src);
+ np->sym = sym;
+ return np;
+}
+
+static Node *
+builtin_va_start(Symbol *sym)
+{
+ Node *np, *ap, *last;
+
+ ap = assign();
+ expect(',');
+ if (yytoken != IDEN)
+ goto error;
+ last = varnode(yylval.sym);
+ next();
+
+ if (!valid_va_list(ap->type))
+ goto error;
+
+ np = node(OBUILTIN, voidtype, ap, last);
+ np->sym = sym;
+ return np;
+
+error:
+ errorp("incorrect parameters for va_start");
+ return constnode(zero);
+}
+
+static Node *
+builtin_va_end(Symbol *sym)
+{
+ Node *ap, *np;
+
+ ap = assign();
+
+ if (!valid_va_list(ap->type)) {
+ errorp("incorrect parameters for va_end");
+ return constnode(zero);
+ }
+
+ np = node(OBUILTIN, voidtype, ap, NULL);
+ np->sym = sym;
+ return np;
+}
+
+void
+ibuilts(void)
+{
+ struct builtin built[] = {
+ {"__builtin_va_arg", builtin_va_arg},
+ {"__builtin_va_copy", builtin_va_copy},
+ {"__builtin_va_start", builtin_va_start},
+ {"__builtin_va_end", builtin_va_end},
+ {NULL}
+ };
+ builtins(built);
+}
diff --git a/cc1/cc1.h b/cc1/cc1.h
@@ -54,6 +54,7 @@ enum ns {
L_ARRAY = 'V',
L_UNION = 'U',
L_STRUCT = 'S',
+ L_VA_ARG = '1',
};
/* recovery points */
@@ -196,6 +197,7 @@ enum tokens {
IFNDEF,
UNDEF,
ENDIF,
+ BUILTIN,
EOFTOK
};
@@ -260,6 +262,7 @@ enum op {
OBSWITCH,
OESWITCH,
OINIT,
+ OBUILTIN,
OTYP,
};
@@ -283,6 +286,11 @@ struct limits {
} min;
};
+struct builtin {
+ char *str;
+ Node *(*fun)(Symbol *);
+};
+
struct keyword {
char *str;
unsigned char token, value;
@@ -327,6 +335,7 @@ struct symbol {
unsigned char token;
Node **init;
Symbol **pars;
+ Node *(*fun)(Symbol *);
} u;
struct symbol *next;
struct symbol *hash;
@@ -387,6 +396,7 @@ extern void pushctx(void), popctx(void);
extern void killsym(Symbol *sym);
extern Symbol *newlabel(void);
extern void keywords(struct keyword *key, int ns);
+extern void builtins(struct builtin *builts);
extern Symbol *newstring(char *s, size_t len);
extern unsigned newid(void);
@@ -417,6 +427,7 @@ extern Node *varnode(Symbol *sym);
extern Node *constnode(Symbol *sym);
extern Node *sizeofnode(Type *tp);
extern void freetree(Node *np);
+extern void icode(void);
#define BTYPE(np) ((np)->type->op)
/* fold.c */
@@ -444,6 +455,13 @@ extern void outcpp(void);
extern void defdefine(char *macro, char *val, char *source);
extern void undefmacro(char *s);
+/* builtin.c */
+extern void ibuilts(void);
+
+/* arch.c */
+extern void iarch(void);
+extern int valid_va_list(Type *tp);
+
/*
* Definition of global variables
*/
@@ -470,4 +488,4 @@ extern Type *voidtype, *pvoidtype, *booltype,
*longtype, *ulongtype,
*ullongtype, *llongtype,
*floattype, *doubletype, *ldoubletype,
- *ellipsistype, *va_list_type;
+ *ellipsistype, *va_list_type, *va_type;
diff --git a/cc1/code.c b/cc1/code.c
@@ -17,7 +17,8 @@ static void emitbin(unsigned, void *),
emitfun(unsigned, void *),
emitdcl(unsigned, void *),
emitinit(unsigned, void *),
- emittype(unsigned, void *);
+ emittype(unsigned, void *),
+ emitbuilt(unsigned, void *);
char *optxt[] = {
[OADD] = "+",
@@ -134,6 +135,7 @@ void (*opcode[])(unsigned, void *) = {
[OPAR] = emitbin,
[OCALL] = emitbin,
[OINIT] = emitinit,
+ [OBUILTIN] = emitbuilt,
[OTYP] = emittype,
};
@@ -430,12 +432,24 @@ emitbin(unsigned op, void *arg)
emitnode(np->left);
emitnode(np->right);
if ((s = optxt[op]) != NULL) { /* do not print in OCOLON case */
- fprintf(outfp, "\t%s", optxt[op]);
+ fprintf(outfp, "\t%s", s);
emitletter(np->type);
}
}
static void
+emitbuilt(unsigned op, void *arg)
+{
+ Node *np = arg;
+
+ emitnode(np->left);
+ emitnode(np->right);
+ fprintf(outfp, "\t\"%s\tk", np->sym->name);
+ emitletter(np->type);
+}
+
+
+static void
emitexp(unsigned op, void *arg)
{
Node *np = arg;
diff --git a/cc1/expr.c b/cc1/expr.c
@@ -11,7 +11,7 @@ static char sccsid[] = "@(#) ./cc1/expr.c";
#define XCHG(lp, rp, np) (np = lp, lp = rp, rp = np)
-static Node *xexpr(void);
+static Node *xexpr(void), *xassign(void);
int
cmpnode(Node *np, TUINT val)
@@ -614,6 +614,7 @@ primary(void)
{
Node *np;
Symbol *sym;
+ Node *(*fun)(Symbol *);
sym = yylval.sym;
switch (yytoken) {
@@ -624,6 +625,15 @@ primary(void)
emit(OINIT, np);
np = varnode(sym);
break;
+ case BUILTIN:
+ fun = sym->u.fun;
+ next();
+ expect('(');
+ np = (*fun)(sym);
+ expect(')');
+
+ /* do not call to next */
+ return np;
case CONSTANT:
np = constnode(sym);
break;
@@ -675,7 +685,7 @@ arguments(Node *np)
toomany = 0;
do {
- arg = assign();
+ arg = xassign();
argtype = *targs;
if (argtype == ellipsistype) {
n = 0;
@@ -1064,8 +1074,8 @@ ternary(void)
return cond;
}
-Node *
-assign(void)
+static Node *
+xassign(void)
{
Node *np, *(*fun)(int , Node *, Node *);
int op;
@@ -1098,15 +1108,21 @@ xexpr(void)
{
Node *lp, *rp;
- lp = assign();
+ lp = xassign();
while (accept(',')) {
- rp = assign();
+ rp = xassign();
lp = node(OCOMMA, rp->type, lp, rp);
}
return lp;
}
Node *
+assign(void)
+{
+ return simplify(xassign());
+}
+
+Node *
constexpr(void)
{
Node *np;
diff --git a/cc1/main.c b/cc1/main.c
@@ -58,6 +58,7 @@ main(int argc, char *argv[])
ilex();
icpp();
icode();
+ ibuilts();
ARGBEGIN {
case 'D':
@@ -102,6 +103,12 @@ main(int argc, char *argv[])
die("error: failed to open input file '%s': %s",
*argv, strerror(errno));
}
+
+ /*
+ * we cannot initialize types until we have an
+ * output stream, because we maybe want to emit new types
+ */
+ iarch();
if (onlycpp || onlyheader) {
outcpp();
} else {
diff --git a/cc1/symbol.c b/cc1/symbol.c
@@ -296,3 +296,23 @@ keywords(struct keyword *key, int ns)
counterid = 0;
head = NULL;
}
+
+void
+builtins(struct builtin *built)
+{
+ Symbol *sym;
+ struct builtin *bp;
+
+ for (bp = built; bp->str; ++bp) {
+ sym = linkhash(newsym(NS_KEYWORD, bp->str));
+ sym->token = BUILTIN;
+ sym->u.fun = bp->fun;
+ }
+ /*
+ * Remove all the predefined symbols from * the symbol list. It
+ * will make faster some operations. There is no problem of memory
+ * leakeage because this memory is not ever freed
+ */
+ counterid = 0;
+ head = NULL;
+}