aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qbe.c14
-rw-r--r--test/bitfield-short.c7
-rw-r--r--test/bitfield-short.qbe14
3 files changed, 30 insertions, 5 deletions
diff --git a/qbe.c b/qbe.c
index 44742c0..d108479 100644
--- a/qbe.c
+++ b/qbe.c
@@ -280,13 +280,17 @@ funcalloc(struct func *f, struct decl *d)
static struct value *
funcbits(struct func *f, struct type *t, struct value *v, struct bitfield b)
{
- int class;
+ int class, bits;
class = t->size <= 4 ? 'w' : 'l';
- if (b.after)
- v = funcinst(f, ISHL, class, v, mkintconst(b.after));
- if (b.before + b.after)
- v = funcinst(f, t->basic.issigned ? ISAR : ISHR, class, v, mkintconst(b.before + b.after));
+ bits = b.after;
+ if (bits) {
+ bits += (t->size + 3 & ~3) - t->size << 3;
+ v = funcinst(f, ISHL, class, v, mkintconst(bits));
+ }
+ bits += b.before;
+ if (bits)
+ v = funcinst(f, t->basic.issigned ? ISAR : ISHR, class, v, mkintconst(bits));
return v;
}
diff --git a/test/bitfield-short.c b/test/bitfield-short.c
new file mode 100644
index 0000000..b0be6fd
--- /dev/null
+++ b/test/bitfield-short.c
@@ -0,0 +1,7 @@
+struct {
+ short x : 7;
+} s = {.x = -64};
+
+int main(void) {
+ return s.x > 0;
+}
diff --git a/test/bitfield-short.qbe b/test/bitfield-short.qbe
new file mode 100644
index 0000000..e8bc086
--- /dev/null
+++ b/test/bitfield-short.qbe
@@ -0,0 +1,14 @@
+export data $s = align 2 { b 64, z 1 }
+export
+function w $main() {
+@start.1
+@body.2
+ %.1 =l mul 0, 1
+ %.2 =l add $s, %.1
+ %.3 =w loadsh %.2
+ %.4 =w shl %.3, 25
+ %.5 =w sar %.4, 25
+ %.6 =w extsh %.5
+ %.7 =w csgtw %.6, 0
+ ret %.7
+}