aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--decl.c4
-rw-r--r--qbe.c12
-rw-r--r--test/alignas-local-32.c4
-rw-r--r--test/alignas-local-32.qbe11
4 files changed, 26 insertions, 5 deletions
diff --git a/decl.c b/decl.c
index 50fe1c6..268ee01 100644
--- a/decl.c
+++ b/decl.c
@@ -960,10 +960,8 @@ decl(struct scope *s, struct func *f)
if (init || d->linkage == LINKNONE) {
if (d->linkage != LINKNONE || sc & SCSTATIC)
emitdata(d, init);
- else if (d->align <= 16)
- funcinit(f, d, init);
else
- error(&tok.loc, "unsupported alignment %d for object with automatic storage duration", d->align);
+ funcinit(f, d, init);
d->defined = true;
if (d->tentative.next)
listremove(&d->tentative);
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;
}
diff --git a/test/alignas-local-32.c b/test/alignas-local-32.c
new file mode 100644
index 0000000..e69a105
--- /dev/null
+++ b/test/alignas-local-32.c
@@ -0,0 +1,4 @@
+int main(void) {
+ _Alignas(32) char x;
+ return (unsigned long)&x % 32;
+}
diff --git a/test/alignas-local-32.qbe b/test/alignas-local-32.qbe
new file mode 100644
index 0000000..53bfab3
--- /dev/null
+++ b/test/alignas-local-32.qbe
@@ -0,0 +1,11 @@
+export
+function w $main() {
+@start.1
+ %.1 =l alloc16 17
+ %.2 =l add %.1, 16
+ %.3 =l and %.2, 18446744073709551584
+@body.2
+ %.4 =l extsw 32
+ %.5 =l urem %.3, %.4
+ ret %.5
+}