commit ac186af698aa2ab93a70d73f39151d2c8d269e65
parent 6220d3865e26ca9a5de3afa960939de22f1bd2f7
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Wed, 18 Jan 2023 21:20:30 +0100
Merge commit '8466cca1'
Diffstat:
8 files changed, 251 insertions(+), 99 deletions(-)
diff --git a/src/cmd/cc/cc1/builtin.c b/src/cmd/cc/cc1/builtin.c
@@ -9,7 +9,7 @@ builtin_va_arg(Symbol *sym)
Node *np, *ap;
Type *tp;
- ap = assign();
+ ap = simplify(assign());
expect(',');
tp = typename();
@@ -37,9 +37,9 @@ builtin_va_copy(Symbol *sym)
{
Node *np, *src, *dst;
- dst = assign();
+ dst = simplify(assign());
expect(',');
- src = assign();
+ src = simplify(assign());
if (!valid_va_list(dst->type) || !valid_va_list(src->type)) {
errorp("incorrect parameters for va_copy");
@@ -63,7 +63,7 @@ builtin_va_start(Symbol *sym)
Symbol **p;
Type *tp;
- ap = assign();
+ ap = simplify(assign());
expect(',');
last = assign();
if (last->op != OSYM)
@@ -98,7 +98,7 @@ builtin_va_end(Symbol *sym)
{
Node *ap, *np;
- ap = assign();
+ ap = simplify(assign());
if (!valid_va_list(ap->type)) {
errorp("incorrect parameters for va_end");
diff --git a/src/cmd/cc/cc1/cc1.h b/src/cmd/cc/cc1/cc1.h
@@ -482,6 +482,7 @@ extern Node *node(int op, Type *tp, Node *left, Node *rigth);
extern Node *varnode(Symbol *sym);
extern Node *constnode(Symbol *sym);
extern Node *sizeofnode(Type *tp);
+extern Node *offsetnode(Symbol *, Type *);
extern void freetree(Node *np);
extern void icode(void);
#define BTYPE(np) ((np)->type->op)
@@ -497,6 +498,7 @@ extern Node *constexpr(void), *condexpr(int neg), *expr(void);
extern int isnodecmp(int op);
extern int negop(int op);
extern int cmpnode(Node *np, TUINT val);
+extern int power2node(Node *, int *);
/* init.c */
extern void initializer(Symbol *sym, Type *tp);
diff --git a/src/cmd/cc/cc1/code.c b/src/cmd/cc/cc1/code.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -564,7 +565,6 @@ constnode(Symbol *sym)
Node *np;
np = node(OSYM, sym->type, NULL, NULL);
- np->type = sym->type;
np->flags = NCONST;
np->sym = sym;
return np;
@@ -577,7 +577,21 @@ sizeofnode(Type *tp)
sym = newsym(NS_IDEN, NULL);
sym->type = sizettype;
- sym->u.i = tp->size;
- DBG("EXPR sizeof %llu", sym->u.i);
+ sym->u.u = tp->size;
+ DBG("EXPR sizeof %llu", sym->u.u);
+ return constnode(sym);
+}
+
+Node *
+offsetnode(Symbol *field, Type *tp)
+{
+ Symbol *sym;
+
+ assert(field->flags & SFIELD);
+ sym = newsym(NS_IDEN, NULL);
+ sym->type = tp;
+ sym->flags |= SCONSTANT;
+ sym->u.u = field->u.u;
+
return constnode(sym);
}
diff --git a/src/cmd/cc/cc1/expr.c b/src/cmd/cc/cc1/expr.c
@@ -9,6 +9,32 @@
#define XCHG(lp, rp, np) (np = lp, lp = rp, rp = np)
int
+power2node(Node *np, int *log)
+{
+ int n;
+ TUINT u;
+ Symbol *sym;
+
+ if (!np || !(np->flags & NCONST) || !np->sym)
+ return 0;
+
+ sym = np->sym;
+ if (sym->type->op != INT)
+ return 0;
+
+ n = 0;
+ for (u = sym->u.u; u; u >>= 1) {
+ if (u & 1)
+ n++;
+ }
+
+ if (log)
+ *log = n;
+
+ return n == 1;
+}
+
+int
cmpnode(Node *np, TUINT val)
{
Symbol *sym;
@@ -189,6 +215,18 @@ chklvalue(Node *np)
errorp("invalid use of void expression");
}
+static Node *
+chkconstaddr(Node *var, Node *addr)
+{
+ if (var->sym && var->sym->flags & (SGLOBAL|SLOCAL|SPRIVATE)
+ || var->op == OFIELD && var->left->op == OSYM
+ || var->op == OFIELD && (var->left->flags & NCONST)) {
+ addr->flags |= NCONST;
+ }
+
+ return addr;
+}
+
Node *
decay(Node *np)
{
@@ -199,26 +237,21 @@ decay(Node *np)
case ARY:
DBG("EXPR decay ary");
tp = tp->type;
- if (np->op == OPTR) {
- new = np->left;
- free(np);
- new->type = mktype(tp, PTR, 0, NULL);
- return new;
- }
- break;
+ if (np->op != OPTR)
+ goto new_node;
+ new = np->left;
+ free(np);
+ new->type = mktype(tp, PTR, 0, NULL);
+ return chkconstaddr(new, new);
case FTN:
DBG("EXPR decay function");
- break;
+ new_node:
+ new = node(OADDR, mktype(tp, PTR, 0, NULL), np, NULL);
+ new->flags |= NDECAY;
+ return chkconstaddr(np, new);
default:
return np;
}
-
- new = node(OADDR, mktype(tp, PTR, 0, NULL), np, NULL);
- if (np->sym && np->sym->flags & (SGLOBAL|SLOCAL|SPRIVATE))
- new->flags |= NCONST;
- new->flags |= NDECAY;
-
- return new;
}
static Node *
@@ -332,6 +365,7 @@ incorrect:
static Node *
arithmetic(int op, Node *lp, Node *rp)
{
+ Node *np;
Type *ltp = lp->type, *rtp = rp->type;
if ((ltp->prop & TARITH) && (rtp->prop & TARITH)) {
@@ -345,7 +379,10 @@ arithmetic(int op, Node *lp, Node *rp)
case OA_SUB:
case OINC:
case ODEC:
- return parithmetic(op, lp, rp);
+ np = parithmetic(op, lp, rp);
+ if ((lp->flags&NCONST) && (rp->flags&NCONST))
+ np->flags |= NCONST;
+ return np;
}
}
errorp("incorrect arithmetic operands");
@@ -571,9 +608,8 @@ dont_check_lvalue:
if (sym && (sym->flags & SREGISTER))
errorp("address of register variable '%s' requested", yytext);
new = node(op, mktype(tp, PTR, 0, NULL), np, NULL);
- if (sym && sym->flags & (SGLOBAL|SLOCAL|SPRIVATE))
- new->flags |= NCONST;
- return new;
+
+ return chkconstaddr(np, new);
}
static Node *
@@ -1093,7 +1129,7 @@ assign(void)
case AND_EQ: op = OA_AND; fun = integerop; break;
case XOR_EQ: op = OA_XOR; fun = integerop; break;
case OR_EQ: op = OA_OR; fun = integerop; break;
- default: return simplify(np);
+ default: return np;
}
chklvalue(np);
np->flags |= NEFFECT;
@@ -1108,15 +1144,12 @@ expr(void)
Node *lp, *rp;
lp = assign();
- if (!accept(','))
- return lp;
-
- do {
+ while (accept(',')) {
rp = assign();
lp = node(OCOMMA, rp->type, lp, rp);
- } while (accept(','));
+ }
- return simplify(lp);
+ return lp;
}
Node *
diff --git a/src/cmd/cc/cc1/fold.c b/src/cmd/cc/cc1/fold.c
@@ -369,16 +369,18 @@ foldcast(Node *np, Node *l)
}
static Node *
-foldunary(Node *np, Node *l)
+foldunary(Node *np)
{
- int op = l->op;
+ Node *l = np->left;
Node *aux;
+ Symbol *sym;
+ int op = l->op;
switch (np->op) {
case ONEG:
if (l->op == ONEG)
break;
- return NULL;
+ return np;
case OADD:
DBG("FOLD unary delete %d", np->op);
np->left = NULL;
@@ -389,18 +391,48 @@ foldunary(Node *np, Node *l)
case OSNEG:
case OCPL:
if (op != np->op)
- return NULL;
+ return np;
break;
case OPTR:
if (op != OADDR || np->type != l->left->type)
- return NULL;
+ return np;
break;
case OADDR:
+ /* &(*s).f -> s + offsetof(typeof(*s), f) */
+ if (op == OFIELD && l->left->op == OPTR) {
+ DBG("FOLD collapse '&(*s).f' %d", np->op);
+ aux = node(OADD,
+ np->type,
+ l->left->left,
+ offsetnode(l->right->sym, np->type));
+
+ if (aux->left->flags & NCONST)
+ aux->flags |= NCONST;
+ l->left->left = NULL;
+ freetree(np);
+ return aux;
+ }
+
+ /* &s.f -> &s + offsetof(typeof(s), f) */
+ if (op == OFIELD) {
+ DBG("FOLD collapse '&s.f' %d", np->op);
+ aux = node(OADD,
+ np->type,
+ node(OADDR, np->type, l->left, NULL),
+ offsetnode(l->right->sym, np->type));
+
+ if (np->flags & NCONST)
+ aux->flags |= NCONST;
+ l->left = NULL;
+ freetree(np);
+ return aux;
+ }
+
if (op != OPTR)
- return NULL;
+ return np;
break;
default:
- return NULL;
+ return np;
}
DBG("FOLD unary cancel %d", np->op);
aux = l->left;
@@ -424,7 +456,7 @@ fold(Node *np)
if ((op == ODIV || op == OMOD) && cmpnode(rp, 0)) {
warn("division by 0");
- return NULL;
+ return np;
}
/*
* Return if any of the children is no constant,
@@ -437,12 +469,12 @@ fold(Node *np)
rs = NULL;
} else {
if (!(rp->flags & NCONST) || !rp->sym)
- return NULL;
+ return np;
rs = rp->sym;
}
if ((lp->flags & NCONST) == 0 || !lp->sym)
- return NULL;
+ return np;
optype = lp->type;
ls = lp->sym;
@@ -456,19 +488,20 @@ fold(Node *np)
case FLOAT:
if ((p = foldconst(type, op, tp, ls, rs)) == NULL) {
np->flags &= ~NCONST;
- return NULL;
+ return np;
}
freetree(np);
return p;
default:
- return NULL;
+ return np;
}
}
static void
-commutative(Node *np, Node *l, Node *r)
+commutative(Node *np)
{
int op = np->op;
+ Node *l = np->left, *r = np->right;
if (r == NULL || r->flags&NCONST || !(l->flags&NCONST))
return;
@@ -502,7 +535,7 @@ identity(Node *np)
Node *lp = np->left, *rp = np->right;
if (!rp)
- return NULL;
+ return np;
iszeror = cmpnode(rp, 0);
isoner = cmpnode(rp, 1),
@@ -523,7 +556,7 @@ identity(Node *np)
goto free_left;
if (isoner)
goto change_to_comma;
- return NULL;
+ return np;
case OAND:
/*
* 0 && i => 0 (free right)
@@ -537,7 +570,7 @@ identity(Node *np)
goto free_left;
if (iszeror)
goto change_to_comma;
- return NULL;
+ return np;
case OSHL:
case OSHR:
/*
@@ -548,7 +581,7 @@ identity(Node *np)
*/
if (iszeror | iszerol)
goto free_right;
- return NULL;
+ return np;
case OBXOR:
case OADD:
case OBOR:
@@ -561,34 +594,33 @@ identity(Node *np)
*/
if (iszeror)
goto free_right;
- return NULL;
+ return np;
case OMUL:
/*
- * i * 0 => i,0
- * i * 1 => i
+ * i * 0 => i,0 (comma)
+ * i * 1 => i (free right)
*/
if (iszeror)
goto change_to_comma;
if (isoner)
goto free_right;
- return NULL;
+ return np;
case ODIV:
/* i / 1 => i */
if (isoner)
goto free_right;
- return NULL;
+ return np;
case OBAND:
/* i & ~0 => i */
if (cmpnode(rp, -1))
goto free_right;
- return NULL;
+ return np;
case OMOD:
/* i % 1 => i,1 */
- /* TODO: i % 2^n => i & n-1 */
if (isoner)
goto change_to_comma;
default:
- return NULL;
+ return np;
}
free_right:
@@ -610,8 +642,10 @@ change_to_comma:
}
static Node *
-foldternary(Node *np, Node *cond, Node *body)
+foldternary(Node *np)
{
+ Node *cond = np->left, *body = np->right;
+
if ((cond->flags & NCONST) == 0)
return np;
if (cmpnode(cond, 0)) {
@@ -630,22 +664,70 @@ foldternary(Node *np, Node *cond, Node *body)
return np;
}
-/* TODO: fold OCOMMA */
+static Node *xsimplify(Node *);
-Node *
-xsimplify(Node *np)
+static void
+reduce(Node *np)
{
- Node *p, *l, *r;
+ Node *lp = np->left, *rp = np->right;
+ Node *aux, *aux2;
+ int op = np->op;
- if (!np)
- return NULL;
+ switch (op) {
+ case OMOD:
+ /* i % 2^n => i & n-1 */
+ if (power2node(rp, NULL)) {
+ np->op = OBAND;
+ rp->sym->u.u--;
+ break;
+ }
+ return;
+ default:
+ return;
+ }
- l = np->left = xsimplify(np->left);
- r = np->right = xsimplify(np->right);
+ DBG("FOLD reduce %d->%d", op, np->op);
+}
+
+static void
+associative(Node *np)
+{
+ Node *l = np->left, *r = np->right;
switch (np->op) {
+ case OADD:
+ case OMUL:
+ case OBAND:
+ case OBXOR:
+ case OBOR:
+ if (np->op != l->op
+ || l->right->op != OSYM
+ || !(l->right->sym->flags&SCONSTANT)) {
+ return;
+ }
+
+ DBG("FOLD associative %d", np->op);
+ np->left = l->left;
+ l->left = r;
+ np->right = fold(l);
+ break;
+ }
+}
+
+/* TODO: fold OCOMMA */
+static Node *
+xxsimplify(Node *np)
+{
+ int op;
+
+ np->left = xsimplify(np->left);
+ np->right = xsimplify(np->right);
+
+repeat:
+ switch (op = np->op) {
case OASK:
- return foldternary(np, l, r);
+ np = foldternary(np);
+ break;
case OCALL:
case OPAR:
case OSYM:
@@ -660,7 +742,7 @@ xsimplify(Node *np)
case OA_AND:
case OA_XOR:
case OA_OR:
- return np;
+ break;
case OSNEG:
case OCPL:
case OADDR:
@@ -669,29 +751,43 @@ xsimplify(Node *np)
case DEC:
case OCAST:
case ONEG:
- assert(!r);
- if ((p = foldunary(np, l)) != NULL)
- np = p;
- if ((p = fold(np)) != NULL)
- np = p;
- return np;
+ assert(!np->right);
+ np = foldunary(np);
+ np = fold(np);
+ break;
default:
- commutative(np, l, r);
- if ((p = fold(np)) != NULL)
- np = p;
- if ((p = identity(np)) != NULL)
- np = p;
- return np;
+ commutative(np);
+ associative(np);
+ np = fold(np);
+ np = identity(np);
+ reduce(np);
+ break;
}
+
+ if (op != np->op)
+ goto repeat;
+ return np;
}
-Node *
-simplify(Node *np)
+static Node *
+xsimplify(Node *np)
{
+ if (!np)
+ return NULL;
+
if (enadebug)
prtree("simplify before", np);
- np = xsimplify(np);
+ np = xxsimplify(np);
if (enadebug)
prtree("simplify after", np);
+
return np;
}
+
+Node *
+simplify(Node *np)
+{
+ DBG("SIMPLIFY");
+ return xsimplify(np);
+ DBG("SIMPLIFY DONE");
+}
diff --git a/src/cmd/cc/cc1/init.c b/src/cmd/cc/cc1/init.c
@@ -61,7 +61,7 @@ fielddesig(Type *tp, Init *ip)
if ((sym->flags & SDECLARED) == 0) {
errorp("unknown field '%s' specified in initializer",
sym->name);
- return 0;
+ return -1;
}
for (p = tp->p.fields; *p != sym; ++p)
;
@@ -123,13 +123,12 @@ initialize(Type *tp)
return initlist(tp);
np = assign();
- if (eqtype(tp, np->type, EQUIV))
- return np;
-
- np = convert(decay(np), tp, 0);
- if (!np) {
- errorp("incorrect initializer");
- return constnode(zero);
+ if (!eqtype(tp, np->type, EQUIV)) {
+ np = convert(decay(np), tp, 0);
+ if (!np) {
+ errorp("incorrect initializer");
+ return constnode(zero);
+ }
}
return simplify(np);
@@ -233,7 +232,7 @@ initlist_helper(Type *tp)
goto desig_list;
case '.':
in.pos = fielddesig(tp, &in);
- if (in.pos < nelem)
+ if (in.pos >= 0 && in.pos < nelem)
curtp = tp->p.fields[in.pos]->type;
desig_list:
if (yytoken == '[' || yytoken == '.') {
diff --git a/src/cmd/cc/cc1/stmt.c b/src/cmd/cc/cc1/stmt.c
@@ -47,7 +47,7 @@ stmtexp(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
stmt(lbreak, lcont, lswitch);
return;
}
- np = expr();
+ np = simplify(expr());
if ((np->flags & NEFFECT) == 0)
warn("expression without side effects");
emit(OEXPR, np);
@@ -115,14 +115,14 @@ For(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
decl();
break;
default:
- emit(OEXPR, expr());
+ emit(OEXPR, simplify(expr()));
case ';':
expect(';');
break;
}
econd = (yytoken != ';') ? condexpr(NONEGATE) : NULL;
expect(';');
- einc = (yytoken != ')') ? expr() : NULL;
+ einc = (yytoken != ')') ? simplify(expr()) : NULL;
expect(')');
emit(OJUMP, cond);
@@ -178,7 +178,7 @@ Return(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
expect(RETURN);
if (yytoken != ';')
- np = decay(expr());
+ np = simplify(decay(expr()));
expect(';');
if (!np && tp != voidtype)
@@ -248,7 +248,8 @@ Swtch(Symbol *obr, Symbol *lcont, Switch *osw)
expect(SWITCH);
expect ('(');
- if ((cond = convert(expr(), inttype, 0)) == NULL) {
+ cond = simplify(convert(expr(), inttype, 0));
+ if (cond == NULL) {
errorp("incorrect type in switch statement");
cond = constnode(zero);
}
diff --git a/src/libmach/libmach.h b/src/libmach/libmach.h
@@ -1,3 +1,10 @@
+/*
+ * some systems define macros with this name even when
+ * they should be c99 compliant.
+ */
+#undef LITTLE_ENDIAN
+#undef BIG_ENDIAN
+
#define NBYTES 32
#define OBJ(format,arch,order) ((order) << 10 | (arch) << 5 | (format))
#define FORMAT(t) ((t) & 0x1f)