aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-17 13:39:02 -0800
committerMichael Forney <mforney@mforney.org>2019-02-17 13:45:07 -0800
commited176e4211b27218b9182ead05a13fd6d27d46ac (patch)
treed1f9ae26cfb21d6fdc39ab5a05a28b715170ca56
parentfed14a31ca554b54c4f2eebefd09aeaeda782aba (diff)
downloadcproc-ed176e4211b27218b9182ead05a13fd6d27d46ac.tar.xz
Fix returning struct/union types
-rw-r--r--qbe.c4
-rw-r--r--tests/struct-return-1.c3
-rw-r--r--tests/struct-return-1.qbe10
-rw-r--r--tests/struct-return-2.c4
-rw-r--r--tests/struct-return-2.qbe8
5 files changed, 28 insertions, 1 deletions
diff --git a/qbe.c b/qbe.c
index 7c01202..2080e7c 100644
--- a/qbe.c
+++ b/qbe.c
@@ -356,6 +356,7 @@ mkfunc(char *name, struct type *t, struct scope *s)
f->start = f->end = (struct block *)mkblock("start");
f->gotos = mkhtab(8);
f->lastid = 0;
+ emittype(t->base);
/* allocate space for parameters */
for (p = t->func.params; p; p = p->next) {
@@ -593,6 +594,7 @@ funcexpr(struct function *f, struct expression *e)
case EXPRCALL:
argvals = xreallocarray(NULL, e->call.nargs + 3, sizeof(argvals[0]));
argvals[0] = funcexpr(f, e->call.func);
+ emittype(e->type);
for (argval = &argvals[1], arg = e->call.args; arg; ++argval, arg = arg->next) {
emittype(arg->type);
*argval = funcexpr(f, arg);
@@ -991,7 +993,7 @@ emittype(struct type *t)
{
static uint64_t id;
- if (t->repr->abi.id || !(typeprop(t) & PROPAGGR))
+ if (!t->repr || t->repr->abi.id || !(typeprop(t) & PROPAGGR))
return;
t->repr = xmalloc(sizeof(*t->repr));
t->repr->base = 'l';
diff --git a/tests/struct-return-1.c b/tests/struct-return-1.c
new file mode 100644
index 0000000..e1631a8
--- /dev/null
+++ b/tests/struct-return-1.c
@@ -0,0 +1,3 @@
+struct s {int x;} f(void) {
+ return (struct s){2};
+}
diff --git a/tests/struct-return-1.qbe b/tests/struct-return-1.qbe
new file mode 100644
index 0000000..fcdf699
--- /dev/null
+++ b/tests/struct-return-1.qbe
@@ -0,0 +1,10 @@
+type :s.1 = { w, }
+export
+function :s.1 $f() {
+@start.1
+ %.1 =l alloc4 4
+@body.2
+ %.2 =l add %.1, 0
+ storew 2, %.2
+ ret %.1
+}
diff --git a/tests/struct-return-2.c b/tests/struct-return-2.c
new file mode 100644
index 0000000..9fa50f5
--- /dev/null
+++ b/tests/struct-return-2.c
@@ -0,0 +1,4 @@
+struct s {int x;} g(void);
+void f(void) {
+ g();
+}
diff --git a/tests/struct-return-2.qbe b/tests/struct-return-2.qbe
new file mode 100644
index 0000000..2f1d3da
--- /dev/null
+++ b/tests/struct-return-2.qbe
@@ -0,0 +1,8 @@
+type :s.1 = { w, }
+export
+function $f() {
+@start.1
+@body.2
+ %.1 =:s.1 call $g()
+ ret
+}