aboutsummaryrefslogtreecommitdiff
path: root/qbe.c
diff options
context:
space:
mode:
Diffstat (limited to 'qbe.c')
-rw-r--r--qbe.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/qbe.c b/qbe.c
index 88cd97b..264bdac 100644
--- a/qbe.c
+++ b/qbe.c
@@ -259,6 +259,7 @@ funcalloc(struct func *f, struct decl *d)
{
enum instkind op;
struct inst *inst;
+ unsigned long long size;
assert(!d->type->incomplete);
assert(d->type->size > 0);
@@ -266,17 +267,24 @@ funcalloc(struct func *f, struct decl *d)
d->align = d->type->align;
else if (d->align < d->type->align)
error(&tok.loc, "object requires alignment %d, which is stricter than %d", d->type->align, d->align);
+ size = d->type->size;
switch (d->align) {
case 1:
case 2:
case 4: op = IALLOC4; break;
case 8: op = IALLOC8; break;
+ default: size += d->align - 16; /* fallthrough */
case 16: op = IALLOC16; break;
- default:
- fatal("internal error: invalid alignment: %d\n", d->align);
}
inst = mkinst(f, op, ptrclass, mkintconst(size), NULL);
arrayaddptr(&f->start->insts, inst);
+ if (d->align > 16) {
+ /* TODO: implement alloc32 in QBE and use that instead */
+ inst = mkinst(f, IADD, ptrclass, &inst->res, mkintconst(d->align - 16));
+ arrayaddptr(&f->start->insts, inst);
+ inst = mkinst(f, IAND, ptrclass, &inst->res, mkintconst(-d->align));
+ arrayaddptr(&f->start->insts, inst);
+ }
d->value = &inst->res;
}