aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-22 12:25:50 -0800
committerMichael Forney <mforney@mforney.org>2019-02-22 12:25:50 -0800
commit2cbd75bbab472b6861dc0ae806e41cf139518fe6 (patch)
tree15435cabe49771c07664df83824297cfa3d9f008
parentf2a079fa1a94b6a99e7ce432b6df17fdb4c9b554 (diff)
Implement __builtin_alloca
-rw-r--r--decl.c1
-rw-r--r--decl.h1
-rw-r--r--expr.c10
-rw-r--r--expr.h1
-rw-r--r--main.c1
-rw-r--r--qbe.c3
-rw-r--r--tests/builtin-alloca.c3
-rw-r--r--tests/builtin-alloca.qbe12
8 files changed, 27 insertions, 5 deletions
diff --git a/decl.c b/decl.c
index 67fbef3..b789708 100644
--- a/decl.c
+++ b/decl.c
@@ -24,6 +24,7 @@ struct declaration builtinvaarg = {.kind = DECLBUILTIN};
struct declaration builtinvacopy = {.kind = DECLBUILTIN};
struct declaration builtinvaend = {.kind = DECLBUILTIN};
struct declaration builtinoffsetof = {.kind = DECLBUILTIN};
+struct declaration builtinalloca = {.kind = DECLBUILTIN};
static struct list tentativedefns = {&tentativedefns, &tentativedefns};
diff --git a/decl.h b/decl.h
index db3a956..0fb081b 100644
--- a/decl.h
+++ b/decl.h
@@ -31,6 +31,7 @@ extern struct declaration builtinvaarg;
extern struct declaration builtinvacopy;
extern struct declaration builtinvaend;
extern struct declaration builtinoffsetof;
+extern struct declaration builtinalloca;
struct declaration *mkdecl(enum declarationkind, struct type *, enum linkage);
_Bool decl(struct scope *, struct function *);
diff --git a/expr.c b/expr.c
index a68f5d8..7de75f3 100644
--- a/expr.c
+++ b/expr.c
@@ -443,26 +443,22 @@ postfixexpr(struct scope *s, struct expression *r)
expect(TCOMMA, "after va_list");
free(expect(TIDENT, "after ','"));
// XXX: check that this was actually a parameter name?
- expect(TRPAREN, "after parameter identifier");
} else if (r->ident.decl == &builtinvaarg) {
e = mkexpr(EXPRBUILTIN, NULL, 0);
e->builtin.kind = BUILTINVAARG;
e->builtin.arg = exprconvert(assignexpr(s), &typevalistptr);
expect(TCOMMA, "after va_list");
e->type = typename(s);
- expect(TRPAREN, "after typename");
} else if (r->ident.decl == &builtinvacopy) {
e = mkexpr(EXPRASSIGN, typevalist.base, 0);
e->assign.l = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr));
expect(TCOMMA, "after target va_list");
e->assign.r = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr));
- expect(TRPAREN, "after source va_list");
e = exprconvert(e, &typevoid);
} else if (r->ident.decl == &builtinvaend) {
e = mkexpr(EXPRBUILTIN, &typevoid, 0);
e->builtin.kind = BUILTINVAEND;
exprconvert(assignexpr(s), &typevalistptr);
- expect(TRPAREN, "after va_list");
} else if (r->ident.decl == &builtinoffsetof) {
t = typename(s);
expect(TCOMMA, "after type name");
@@ -474,10 +470,14 @@ postfixexpr(struct scope *s, struct expression *r)
error(&tok.loc, "struct/union has no member named '%s'", name);
e = mkconstexpr(&typeulong, offset);
free(name);
- expect(TRPAREN, "after member name");
+ } else if (r->ident.decl == &builtinalloca) {
+ e = mkexpr(EXPRBUILTIN, mkpointertype(&typevoid), 0);
+ e->builtin.kind = BUILTINALLOCA;
+ e->builtin.arg = exprconvert(assignexpr(s), &typeulong);
} else {
fatal("internal error; unknown builtin");
}
+ expect(TRPAREN, "after builtin parameters");
break;
}
lvalueconvert(r);
diff --git a/expr.h b/expr.h
index a6cac6d..f3ccd69 100644
--- a/expr.h
+++ b/expr.h
@@ -81,6 +81,7 @@ struct expression {
BUILTINVASTART,
BUILTINVAARG,
BUILTINVAEND,
+ BUILTINALLOCA,
} kind;
struct expression *arg;
} builtin;
diff --git a/main.c b/main.c
index db0132b..11f37b2 100644
--- a/main.c
+++ b/main.c
@@ -59,6 +59,7 @@ main(int argc, char *argv[])
scopeputdecl(&filescope, "__builtin_va_arg", &builtinvaarg);
scopeputdecl(&filescope, "__builtin_va_end", &builtinvaend);
scopeputdecl(&filescope, "__builtin_offsetof", &builtinoffsetof);
+ scopeputdecl(&filescope, "__builtin_alloca", &builtinalloca);
while (tok.kind != TEOF) {
if (!decl(&filescope, NULL))
error(&tok.loc, "expected declaration or function definition");
diff --git a/qbe.c b/qbe.c
index 7cc0719..4332b9c 100644
--- a/qbe.c
+++ b/qbe.c
@@ -830,6 +830,9 @@ funcexpr(struct function *f, struct expression *e)
case BUILTINVAEND:
/* no-op */
break;
+ case BUILTINALLOCA:
+ l = funcexpr(f, e->builtin.arg);
+ return funcinst(f, IALLOC16, &iptr, (struct value *[]){l});
default:
fatal("internal error: unimplemented builtin");
}
diff --git a/tests/builtin-alloca.c b/tests/builtin-alloca.c
new file mode 100644
index 0000000..f086f19
--- /dev/null
+++ b/tests/builtin-alloca.c
@@ -0,0 +1,3 @@
+void f(void) {
+ int *x = __builtin_alloca(32);
+}
diff --git a/tests/builtin-alloca.qbe b/tests/builtin-alloca.qbe
new file mode 100644
index 0000000..75a1fe1
--- /dev/null
+++ b/tests/builtin-alloca.qbe
@@ -0,0 +1,12 @@
+export
+function $f() {
+@start.1
+ %.1 =l alloc8 8
+@body.2
+ %.2 =l add %.1, 0
+ %.3 =l extsw 32
+ %.4 =l alloc16 %.3
+ %.5 =l copy %.4
+ storel %.5, %.2
+ ret
+}