diff options
author | Michael Forney <mforney@mforney.org> | 2022-01-19 11:12:59 -0800 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2022-01-22 11:36:12 -0800 |
commit | 51e61fa5fa3de8cabc2191a5c6ac4d18aaaaf049 (patch) | |
tree | 8915d405a6f4aeadb28e06ace14d9459aa0b23b4 | |
parent | d47ebf4c75615d1667a587d53dcd654e12ca6829 (diff) |
Handle unary minus specially instead of 0 - x
This is necessary to fix unary negation of floating-point 0 (also
depends on a pending qbe patch).
-rw-r--r-- | eval.c | 44 | ||||
-rw-r--r-- | expr.c | 3 | ||||
-rw-r--r-- | qbe.c | 3 | ||||
-rw-r--r-- | test/const-expr-neg.c | 1 | ||||
-rw-r--r-- | test/const-expr-neg.qbe | 1 |
5 files changed, 41 insertions, 11 deletions
@@ -27,6 +27,21 @@ cast(struct expr *expr) } static void +unary(struct expr *expr, enum tokenkind op, struct expr *l) +{ + expr->kind = EXPRCONST; + if (l->type->prop & PROPFLOAT) + op |= F; + switch (op) { + case TSUB: expr->u.constant.u = -l->u.constant.u; break; + case TSUB|F: expr->u.constant.f = -l->u.constant.f; break; + default: + fatal("internal error; unknown unary expression"); + } + cast(expr); +} + +static void binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r) { expr->kind = EXPRCONST; @@ -111,19 +126,28 @@ eval(struct expr *expr, enum evalkind kind) break; case EXPRUNARY: l = eval(expr->base, kind); - if (expr->op != TBAND) + switch (expr->op) { + case TBAND: + switch (l->kind) { + case EXPRUNARY: + if (l->op == TMUL) + expr = eval(l->base, kind); + break; + case EXPRSTRING: + if (kind != EVALINIT) + break; + l->u.ident.decl = stringdecl(l); + l->kind = EXPRIDENT; + expr->base = l; + break; + } break; - switch (l->kind) { - case EXPRUNARY: - if (l->op == TMUL) - expr = eval(l->base, kind); + case TMUL: break; - case EXPRSTRING: - if (kind != EVALINIT) + default: + if (l->kind != EXPRCONST) break; - l->u.ident.decl = stringdecl(l); - l->kind = EXPRIDENT; - expr->base = l; + unary(expr, expr->op, l); break; } break; @@ -972,7 +972,8 @@ unaryexpr(struct scope *s) error(&tok.loc, "operand of unary '-' operator must have arithmetic type"); if (e->type->prop & PROPINT) e = exprpromote(e); - e = mkbinaryexpr(&tok.loc, TSUB, mkconstexpr(&typeint, 0), e); + e = mkexpr(EXPRUNARY, e->type, e); + e->op = op; break; case TBNOT: next(); @@ -801,6 +801,9 @@ funcexpr(struct func *f, struct expr *e) case TMUL: r = funcexpr(f, e->base); return funcload(f, e->type, (struct lvalue){r}); + case TSUB: + r = funcexpr(f, e->base); + return funcinst(f, ISUB, qbetype(e->type).base, mkintconst(0), r); } fatal("internal error; unknown unary expression"); break; diff --git a/test/const-expr-neg.c b/test/const-expr-neg.c new file mode 100644 index 0000000..0918aa9 --- /dev/null +++ b/test/const-expr-neg.c @@ -0,0 +1 @@ +double x = -0.0; diff --git a/test/const-expr-neg.qbe b/test/const-expr-neg.qbe new file mode 100644 index 0000000..b380795 --- /dev/null +++ b/test/const-expr-neg.qbe @@ -0,0 +1 @@ +export data $x = align 8 { d d_-0, } |