scc

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

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:
Msrc/cmd/cc/cc1/builtin.c | 10+++++-----
Msrc/cmd/cc/cc1/cc1.h | 2++
Msrc/cmd/cc/cc1/code.c | 20+++++++++++++++++---
Msrc/cmd/cc/cc1/expr.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/cmd/cc/cc1/fold.c | 198++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/cmd/cc/cc1/init.c | 17++++++++---------
Msrc/cmd/cc/cc1/stmt.c | 11++++++-----
Msrc/libmach/libmach.h | 7+++++++
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)