commit 04eaf8bf9813e47819a823534b8b53e481088f77
parent 585dc6d025dabe3e95271084e27e6c833c8c3dbf
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Wed, 22 Jul 2015 14:30:27 +0200
Simplify multiplicative expressions
Diffstat:
M | cc1/code.c | | | 115 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
M | cc1/expr.c | | | 1 | + |
2 files changed, 99 insertions(+), 17 deletions(-)
diff --git a/cc1/code.c b/cc1/code.c
@@ -124,15 +124,20 @@ void (*opcode[])(unsigned, void *) = {
[OSWITCH] = emitswitch
};
-static Node *simple_sub(Node *), *simple_add(Node *);
+static Node *simple_add(Type *, Node *, Node *),
+ *simple_sub(Type *, Node *, Node *),
+ *simple_mul(Type *, Node *, Node *),
+ *simple_div(Type *, Node *, Node *),
+ *simple_mod(Type *, Node *, Node *);
-static Node *(*opsimp[])(Node *) = {
+static Node *(*opsimp[])(Type *, Node *, Node *) = {
[OADD] = simple_add,
- [OSUB] = simple_sub
-
+ [OSUB] = simple_sub,
+ [OMUL] = simple_mul,
+ [ODIV] = simple_div,
+ [OMOD] = simple_mod
};
-
void
freetree(Node *np)
{
@@ -388,10 +393,83 @@ sizeofnode(Type *tp)
}
static Node *
-simple_add(Node *np)
+simple_mod(Type *tp, Node *lp, Node *rp)
+{
+ Symbol *sym, *ls = lp->sym, *rs = rp->sym;
+
+ switch (tp->op) {
+ case INT:
+ sym = newsym(NS_IDEN);
+ sym->type = tp;
+ if (tp->sign) {
+ if (rs->u.i == 0)
+ goto division_by_0;
+ sym->u.i = ls->u.i % rs->u.i;
+ } else {
+ if (rs->u.u == 0)
+ goto division_by_0;
+ sym->u.u = ls->u.u % rs->u.u;
+ }
+ return constnode(sym);
+ default:
+ return NULL;
+ }
+
+division_by_0:
+ warn("division by 0");
+ return NULL;
+}
+
+static Node *
+simple_div(Type *tp, Node *lp, Node *rp)
+{
+ Symbol *sym, *ls = lp->sym, *rs = rp->sym;
+
+ switch (tp->op) {
+ case INT:
+ sym = newsym(NS_IDEN);
+ sym->type = tp;
+ if (tp->sign) {
+ if (rs->u.i == 0)
+ goto division_by_0;
+ sym->u.i = ls->u.i / rs->u.i;
+ } else {
+ if (rs->u.u == 0)
+ goto division_by_0;
+ sym->u.u = ls->u.u / rs->u.u;
+ }
+ return constnode(sym);
+ default:
+ return NULL;
+ }
+
+division_by_0:
+ warn("division by 0");
+ return NULL;
+}
+
+static Node *
+simple_mul(Type *tp, Node *lp, Node *rp)
+{
+ Symbol *sym, *ls = lp->sym, *rs = rp->sym;
+
+ switch (tp->op) {
+ case INT:
+ sym = newsym(NS_IDEN);
+ sym->type = tp;
+ if (tp->sign)
+ sym->u.i = ls->u.i * rs->u.i;
+ else
+ sym->u.u = ls->u.u * rs->u.u;
+ return constnode(sym);
+ default:
+ return NULL;
+ }
+}
+
+static Node *
+simple_add(Type *tp, Node *lp, Node *rp)
{
- Node *lp = np->left, *rp = np->right;
- Type *tp = np->type;
Symbol *sym, *ls = lp->sym, *rs = rp->sym;
switch (tp->op) {
@@ -402,18 +480,15 @@ simple_add(Node *np)
sym->u.i = ls->u.i + rs->u.i;
else
sym->u.u = ls->u.u + rs->u.u;
- freetree(np);
return constnode(sym);
default:
- return np;
+ return NULL;
}
}
static Node *
-simple_sub(Node *np)
+simple_sub(Type *tp, Node *lp, Node *rp)
{
- Node *lp = np->left, *rp = np->right;
- Type *tp = np->type;
Symbol *sym, *ls = lp->sym, *rs = rp->sym;
switch (tp->op) {
@@ -424,17 +499,23 @@ simple_sub(Node *np)
sym->u.i = ls->u.i - rs->u.i;
else
sym->u.u = ls->u.u - rs->u.u;
- freetree(np);
return constnode(sym);
default:
- return np;
+ return NULL;
}
}
Node *
simplify(Node *np)
{
- if (!np->left->constant || !np->right->constant)
+ Node *new, *lp = np->left, *rp = np->right;
+
+ if (!lp->constant || !rp->constant)
return np;
- return (*opsimp[np->op])(np);
+ new = (*opsimp[np->op])(np->type, lp, rp);
+ if (new) {
+ freetree(np);
+ np = new;
+ }
+ return np;
}
diff --git a/cc1/expr.c b/cc1/expr.c
@@ -667,6 +667,7 @@ mul(void)
}
next();
np = (*fun)(op, np, cast());
+ np = simplify(np);
}
}