aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qbe.c26
-rw-r--r--test/bitfield-assignment-sign-extend.c6
-rw-r--r--test/bitfield-assignment-sign-extend.qbe21
-rw-r--r--test/bitfield-compound-assign.qbe12
4 files changed, 52 insertions, 13 deletions
diff --git a/qbe.c b/qbe.c
index c69d875..e707942 100644
--- a/qbe.c
+++ b/qbe.c
@@ -237,9 +237,20 @@ funcalloc(struct func *f, struct decl *d)
arrayaddptr(&f->start->insts, inst);
}
-static void
+static struct value *
+funcbits(struct func *f, struct type *t, struct value *v, struct bitfield b)
+{
+ if (b.after)
+ v = funcinst(f, ISHL, t->repr, v, mkintconst(&i32, b.after));
+ if (b.before + b.after)
+ v = funcinst(f, t->basic.issigned ? ISAR : ISHR, t->repr, v, mkintconst(&i32, b.before + b.after));
+ return v;
+}
+
+static struct value *
funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval, struct value *v)
{
+ struct value *r;
enum instkind loadop, storeop;
enum typeprop tp;
unsigned long long mask;
@@ -250,6 +261,7 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval,
error(&tok.loc, "cannot store to 'const' object");
tp = t->prop;
assert(!lval.bits.before && !lval.bits.after || tp & PROPINT);
+ r = v;
switch (t->kind) {
case TYPESTRUCT:
case TYPEUNION:
@@ -292,6 +304,7 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval,
if (lval.bits.before || lval.bits.after) {
mask = 0xffffffffffffffffu >> lval.bits.after + 64 - t->size * 8 ^ (1 << lval.bits.before) - 1;
v = funcinst(f, ISHL, t->repr, v, mkintconst(&i32, lval.bits.before));
+ r = funcbits(f, t, v, lval.bits);
v = funcinst(f, IAND, t->repr, v, mkintconst(t->repr, mask));
v = funcinst(f, IOR, t->repr, v,
funcinst(f, IAND, t->repr,
@@ -303,6 +316,7 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval,
funcinst(f, storeop, NULL, v, lval.addr);
break;
}
+ return r;
}
static struct value *
@@ -334,11 +348,7 @@ funcload(struct func *f, struct type *t, struct lvalue lval)
}
}
v = funcinst(f, op, t->repr, lval.addr);
- if (lval.bits.after)
- v = funcinst(f, ISHL, t->repr, v, mkintconst(&i32, lval.bits.after));
- if (lval.bits.before + lval.bits.after)
- v = funcinst(f, t->basic.issigned ? ISAR : ISHR, t->repr, v, mkintconst(&i32, lval.bits.before + lval.bits.after));
- return v;
+ return funcbits(f, t, v, lval.bits);
}
struct value *
@@ -653,7 +663,7 @@ funcexpr(struct func *f, struct expr *e)
else
fatal("not a scalar");
v = funcinst(f, e->op == TINC ? IADD : ISUB, e->type->repr, l, r);
- funcstore(f, e->type, e->qual, lval, v);
+ v = funcstore(f, e->type, e->qual, lval, v);
return e->incdec.post ? l : v;
case EXPRCALL:
argvals = xreallocarray(NULL, e->call.nargs + 3, sizeof(argvals[0]));
@@ -869,7 +879,7 @@ funcexpr(struct func *f, struct expr *e)
e->assign.l->temp = r;
} else {
lval = funclval(f, e->assign.l);
- funcstore(f, e->assign.l->type, e->assign.l->qual, lval, r);
+ r = funcstore(f, e->assign.l->type, e->assign.l->qual, lval, r);
}
return r;
case EXPRCOMMA:
diff --git a/test/bitfield-assignment-sign-extend.c b/test/bitfield-assignment-sign-extend.c
new file mode 100644
index 0000000..f466881
--- /dev/null
+++ b/test/bitfield-assignment-sign-extend.c
@@ -0,0 +1,6 @@
+struct {
+ signed x : 4;
+} s;
+int main(void) {
+ return (s.x = 15) != -1;
+}
diff --git a/test/bitfield-assignment-sign-extend.qbe b/test/bitfield-assignment-sign-extend.qbe
new file mode 100644
index 0000000..05ffbf9
--- /dev/null
+++ b/test/bitfield-assignment-sign-extend.qbe
@@ -0,0 +1,21 @@
+export
+function w $main() {
+@start.1
+@body.2
+ %.1 =l copy $s
+ %.2 =l mul 0, 1
+ %.3 =l add %.1, %.2
+ %.4 =l copy %.3
+ %.5 =w shl 15, 0
+ %.6 =w shl %.5, 28
+ %.7 =w sar %.6, 28
+ %.8 =w and %.5, 15
+ %.9 =w loaduw %.4
+ %.10 =w and %.9, 18446744073709551600
+ %.11 =w or %.8, %.10
+ storew %.11, %.4
+ %.12 =w sub 0, 1
+ %.13 =w cnew %.7, %.12
+ ret %.13
+}
+export data $s = align 4 { z 4 }
diff --git a/test/bitfield-compound-assign.qbe b/test/bitfield-compound-assign.qbe
index 5cc38de..8e08ff6 100644
--- a/test/bitfield-compound-assign.qbe
+++ b/test/bitfield-compound-assign.qbe
@@ -11,11 +11,13 @@ function $f() {
%.7 =w sar %.6, 23
%.8 =w add %.7, 3
%.9 =w shl %.8, 4
- %.10 =w and %.9, 8176
- %.11 =w loaduw %.4
- %.12 =w and %.11, 18446744073709543439
- %.13 =w or %.10, %.12
- storew %.13, %.4
+ %.10 =w shl %.9, 19
+ %.11 =w sar %.10, 23
+ %.12 =w and %.9, 8176
+ %.13 =w loaduw %.4
+ %.14 =w and %.13, 18446744073709543439
+ %.15 =w or %.12, %.14
+ storew %.15, %.4
ret
}
export data $s = align 4 { z 4 }