cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit 1ef0706e1f2e97d0872eb801169de5023c3c8b7f
parent 9b52864932ec81033b5c9d34a81828d54192b958
Author: Michael Forney <mforney@mforney.org>
Date:   Sat, 27 Apr 2019 16:24:48 -0700

Sign-extend result of bit-field assignments

Fixes #51.

Thanks to Andrew Chambers for the bug report and test case.

Diffstat:
Mqbe.c | 26++++++++++++++++++--------
Atest/bitfield-assignment-sign-extend.c | 6++++++
Atest/bitfield-assignment-sign-extend.qbe | 21+++++++++++++++++++++
Mtest/bitfield-compound-assign.qbe | 12+++++++-----
4 files changed, 52 insertions(+), 13 deletions(-)

diff --git 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 @@ -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 @@ -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 @@ -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 }