aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--decl.c1
-rw-r--r--decl.h1
-rw-r--r--expr.c7
-rw-r--r--main.c1
-rw-r--r--tests/builtin-va-copy.c4
-rw-r--r--tests/builtin-va-copy.qbe20
6 files changed, 34 insertions, 0 deletions
diff --git a/decl.c b/decl.c
index 67bb361..d350d44 100644
--- a/decl.c
+++ b/decl.c
@@ -21,6 +21,7 @@
struct declaration builtinvalist = {.kind = DECLTYPE, .type = &typevalist};
struct declaration builtinvastart = {.kind = DECLBUILTIN};
struct declaration builtinvaarg = {.kind = DECLBUILTIN};
+struct declaration builtinvacopy = {.kind = DECLBUILTIN};
struct declaration builtinvaend = {.kind = DECLBUILTIN};
struct declaration builtinoffsetof = {.kind = DECLBUILTIN};
diff --git a/decl.h b/decl.h
index 024d78a..db3a956 100644
--- a/decl.h
+++ b/decl.h
@@ -28,6 +28,7 @@ struct function;
extern struct declaration builtinvalist;
extern struct declaration builtinvastart;
extern struct declaration builtinvaarg;
+extern struct declaration builtinvacopy;
extern struct declaration builtinvaend;
extern struct declaration builtinoffsetof;
diff --git a/expr.c b/expr.c
index 13e7533..78881fb 100644
--- a/expr.c
+++ b/expr.c
@@ -453,6 +453,13 @@ postfixexpr(struct scope *s, struct expression *r)
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;
diff --git a/main.c b/main.c
index 4402730..db0132b 100644
--- a/main.c
+++ b/main.c
@@ -55,6 +55,7 @@ main(int argc, char *argv[])
} else {
scopeputdecl(&filescope, "__builtin_va_list", &builtinvalist);
scopeputdecl(&filescope, "__builtin_va_start", &builtinvastart);
+ scopeputdecl(&filescope, "__builtin_va_copy", &builtinvacopy);
scopeputdecl(&filescope, "__builtin_va_arg", &builtinvaarg);
scopeputdecl(&filescope, "__builtin_va_end", &builtinvaend);
scopeputdecl(&filescope, "__builtin_offsetof", &builtinoffsetof);
diff --git a/tests/builtin-va-copy.c b/tests/builtin-va-copy.c
new file mode 100644
index 0000000..7a69596
--- /dev/null
+++ b/tests/builtin-va-copy.c
@@ -0,0 +1,4 @@
+void f(void) {
+ static __builtin_va_list a, b;
+ __builtin_va_copy(a, b);
+}
diff --git a/tests/builtin-va-copy.qbe b/tests/builtin-va-copy.qbe
new file mode 100644
index 0000000..7d88659
--- /dev/null
+++ b/tests/builtin-va-copy.qbe
@@ -0,0 +1,20 @@
+data $.La.2 = align 8 { z 24 }
+data $.Lb.3 = align 8 { z 24 }
+export
+function $f() {
+@start.1
+@body.2
+ %.1 =l loadl $.Lb.3
+ storel %.1, $.La.2
+ %.2 =l add $.Lb.3, 8
+ %.3 =l add $.La.2, 8
+ %.4 =l loadl %.2
+ storel %.4, %.3
+ %.5 =l add %.2, 8
+ %.6 =l add %.3, 8
+ %.7 =l loadl %.5
+ storel %.7, %.6
+ %.8 =l add %.5, 8
+ %.9 =l add %.6, 8
+ ret
+}