scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit 8addc23ae4c1b201b63690f1ec7d99aa92a6eaf7
parent 65c1d7d2f64cb02e25a6bc4cf7956154c0bfef83
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Fri, 20 Jan 2023 00:30:09 +0100

cc1/cc2: Fix abbreviations with reduce cast

When the left part of an abbreviation operation is smaller than
the right part then the code was generating casts in the left
part that by definition is wrong. The fix in cc1 introduces a
new case in cc2 because then we can have operations with
size smaller than 4 bytes, that is not allowed by qbe.

Diffstat:
Msrc/cmd/cc/cc1/expr.c | 29+++++++++++++++++++++++++++--
Msrc/cmd/cc/cc2/target/qbe/cgen.c | 29+++++++++++++++++++----------
Atests/cc/execute/0219-abbrev.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/cc/execute/scc-tests.lst | 1+
4 files changed, 115 insertions(+), 12 deletions(-)

diff --git a/src/cmd/cc/cc1/expr.c b/src/cmd/cc/cc1/expr.c @@ -259,7 +259,22 @@ integerop(int op, Node *lp, Node *rp) { if (!(lp->type->prop & TINTEGER) || !(rp->type->prop & TINTEGER)) error("operator requires integer operands"); - arithconv(&lp, &rp); + + + switch (op) { + case OA_MOD: + case OA_SHL: + case OA_SHR: + case OA_AND: + case OA_XOR: + case OA_OR: + rp = convert(rp, lp->type, 0); + break; + default: + arithconv(&lp, &rp); + break; + } + return node(op, lp->type, lp, rp); } @@ -369,7 +384,17 @@ arithmetic(int op, Node *lp, Node *rp) Type *ltp = lp->type, *rtp = rp->type; if ((ltp->prop & TARITH) && (rtp->prop & TARITH)) { - arithconv(&lp, &rp); + switch (op) { + case OA_ADD: + case OA_SUB: + case OA_MUL: + case OA_DIV: + rp = convert(rp, lp->type, 0); + break; + default: + arithconv(&lp, &rp); + break; + } return node(op, lp->type, lp, rp); } else if ((ltp->op == PTR || rtp->op == PTR)) { switch (op) { diff --git a/src/cmd/cc/cc2/target/qbe/cgen.c b/src/cmd/cc/cc2/target/qbe/cgen.c @@ -176,16 +176,7 @@ sethi(Node *np) np->address = 11; break; case OASSIG: - if (lp->op == OCAST) { - Node *tmp = node(OCAST); - tmp->type = lp->left->type; - tmp->left = rp; - tmp->right = NULL; - rp = tmp; - tmp = lp; - lp = lp->left; - delnode(tmp); - } + assert(lp->op != OCAST); goto binary; case OCPL: assert(np->type.flags & INTF); @@ -582,6 +573,24 @@ assign(Node *np) break; default: /* assign abbreviation */ + assert(l->type.size == r->type.size); + if (r->type.size < 4) { + if (l->complex >= r->complex) { + l = lhs(l); + r = rhs(r); + } else { + r = rhs(r); + l = lhs(l); + } + aux.op = np->u.subop; + aux.left = load(&r->type, l); + aux.right = r; + aux.type = int32type; + aux.address = np->address; + ret = r = sethi(rhs(&aux)); + break; + } + aux.op = np->u.subop; aux.left = l; aux.right = r; diff --git a/tests/cc/execute/0219-abbrev.c b/tests/cc/execute/0219-abbrev.c @@ -0,0 +1,68 @@ +int +main() +{ + unsigned long c; + char s[1]; + + *s = 10; + c = 6; + *s %= c; + if (*s != 4) + return 1; + + *s = 8; + c = 2; + *s <<= c; + if (*s != 32) + return 2; + + *s = 8; + c = 2; + *s >>= c; + if (*s != 2) + return 3; + + *s = 12; + c = 8; + *s &= c; + if (*s != 8) + return 4; + + *s = 3; + c = 1; + *s ^= c; + if (*s != 2) + return 5; + + *s = 1; + c = 2; + *s |= c; + if (*s != 3) + return 6; + + *s = 1; + c = 3; + *s += c; + if (*s != 4) + return 7; + + *s = 4; + c = 1; + *s -= c; + if (*s != 3) + return 8; + + *s = 8; + c = 2; + *s /= c; + if (*s != 4) + return 9; + + *s = 4; + c = 4; + *s *= c; + if (*s != 16) + return 10; + + return 0; +} diff --git a/tests/cc/execute/scc-tests.lst b/tests/cc/execute/scc-tests.lst @@ -209,3 +209,4 @@ 0216-initialize.c [TODO] 0217-lchar.c 0218-initialize.c [TODO] +0219-abbrev.c