scc

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

commit c3b8a3ef1ef7df8ae85b1d0b9061725a02c356dc
parent b057d1fdf510c655916a99184421b0197c5da056
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Fri, 30 Jan 2026 12:49:24 +0100

cc1: Add support for c99 float arithmetic

C99 allows arithmetic operations to be performed in floats, while K&R and C90
promoted floats to double. This was the behaviour of scc until now, but this
commit enables operations in float and also add folding of long double constants.

Diffstat:
Minclude/scc/bits/amd64/arch/float.h | 6++++++
Minclude/scc/float.h | 6++++++
Msrc/cmd/scc-cc/cc1/cc1.h | 4+++-
Msrc/cmd/scc-cc/cc1/cpp.c | 1+
Msrc/cmd/scc-cc/cc1/expr.c | 8+++-----
Msrc/cmd/scc-cc/cc1/fold.c | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
6 files changed, 124 insertions(+), 12 deletions(-)

diff --git a/include/scc/bits/amd64/arch/float.h b/include/scc/bits/amd64/arch/float.h @@ -1,3 +1,9 @@ +#ifdef __FLT_EVAL_METHOD__ +#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#else +#define FLT_EVAL_METHOD 1 +#endif + #define FLT_RADIX 2 #define FLT_MANT_DIG 24 #define FLT_DIG 6 diff --git a/include/scc/float.h b/include/scc/float.h @@ -1,6 +1,12 @@ #ifndef _FLOAT_H #define _FLOAT_H +#ifdef __FLT_EVAL_METHOD__ +#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#else +#define FLT_EVAL_METHOD 0 +#endif + #include <arch/float.h> #endif diff --git a/src/cmd/scc-cc/cc1/cc1.h b/src/cmd/scc-cc/cc1/cc1.h @@ -344,7 +344,9 @@ struct symbol { union { long long i; unsigned long long u; - double f; + float f; + double d; + long double ld; char *s; unsigned char token; Node **init; diff --git a/src/cmd/scc-cc/cc1/cpp.c b/src/cmd/scc-cc/cc1/cpp.c @@ -75,6 +75,7 @@ icpp(void) {"__STDC_VERSION__", STDC_VERSION}, {"__LINE__", NULL}, {"__FILE__", NULL}, + {"__FLT_EVAL_METHOD__", 0}, {NULL, NULL} }; diff --git a/src/cmd/scc-cc/cc1/expr.c b/src/cmd/scc-cc/cc1/expr.c @@ -52,8 +52,8 @@ cmpnode(Node *np, unsigned long long val) mask = (val > 1) ? ones(np->type->size) : -1; nodeval = (tp->prop & TSIGNED) ? sym->u.i : sym->u.u; return (nodeval & mask) == (val & mask); - case FLOAT: - return sym->u.f == val; + default: + abort(); } return 0; } @@ -77,9 +77,7 @@ promote(Node *np) tp = (lim->max.i <= ilim->max.i) ? inttype : uinttype; break; case FLOAT: - /* TODO: Add support for C99 float math */ - tp = doubletype; - break; + return np; default: abort(); } diff --git a/src/cmd/scc-cc/cc1/fold.c b/src/cmd/scc-cc/cc1/fold.c @@ -236,7 +236,50 @@ sign: } static int -foldfloat(int op, Symbol *res, double l, double r) +foldldouble(int op, Symbol *res, long double l, long double r) +{ + long double f; + long long i; + int (*validate)(double, double, Type *tp); + + switch (op) { + case OADD: validate = addf; break; + case OSUB: validate = subf; break; + case OMUL: validate = mulf; break; + case ODIV: validate = divf; break; + default: validate = NULL; break; + } + + if (validate && !(*validate)(l, r, res->type)) + return 0; + + switch (op) { + case OADD: f = l + r; break; + case OSUB: f = l - r; break; + case OMUL: f = l * r; break; + case ODIV: f = l / r; break; + case OLT: i = l < r; goto comparison; + case OGT: i = l > r; goto comparison; + case OGE: i = l >= r; goto comparison; + case OLE: i = l <= r; goto comparison; + case OEQ: i = l == r; goto comparison; + case ONE: i = l != r; goto comparison; + default: return 0; + } + res->u.ld = f; + + DBG("FOLD f l=%llf %d r=%llf = %llf", l, op, r, f); + return 1; + +comparison: + res->u.i = i; + + DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i); + return 1; +} + +static int +folddouble(int op, Symbol *res, double l, double r) { double f; long long i; @@ -266,7 +309,7 @@ foldfloat(int op, Symbol *res, double l, double r) case ONE: i = l != r; goto comparison; default: return 0; } - res->u.f = f; + res->u.d = f; DBG("FOLD f l=%lf %d r=%lf = %lf", l, op, r, f); return 1; @@ -278,13 +321,59 @@ comparison: return 1; } +static int +foldfloat(int op, Symbol *res, float l, float r) +{ + float f; + long long i; + int (*validate)(double, double, Type *tp); + + switch (op) { + case OADD: validate = addf; break; + case OSUB: validate = subf; break; + case OMUL: validate = mulf; break; + case ODIV: validate = divf; break; + default: validate = NULL; break; + } + + if (validate && !(*validate)(l, r, res->type)) + return 0; + + switch (op) { + case OADD: f = l + r; break; + case OSUB: f = l - r; break; + case OMUL: f = l * r; break; + case ODIV: f = l / r; break; + case OLT: i = l < r; goto comparison; + case OGT: i = l > r; goto comparison; + case OGE: i = l >= r; goto comparison; + case OLE: i = l <= r; goto comparison; + case OEQ: i = l == r; goto comparison; + case ONE: i = l != r; goto comparison; + default: return 0; + } + res->u.f = f; + + DBG("FOLD f l=%f %d r=%f = %f", l, op, r, f); + return 1; + +comparison: + res->u.i = i; + + DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i); + return 1; +} + + static Node * foldconst(int type, int op, Type *tp, Symbol *ls, Symbol *rs) { Symbol *sym, aux; long long i; unsigned long long u; - double f; + float f; + double d; + long double ld; aux.type = tp; switch (type) { @@ -300,9 +389,19 @@ foldconst(int type, int op, Type *tp, Symbol *ls, Symbol *rs) return NULL; break; case FLOAT: - f = (rs) ? rs->u.f : 0.0; - if (!foldfloat(op, &aux, ls->u.f, f)) - return NULL; + if (tp == floattype) { + f = (rs) ? rs->u.f : 0.0; + if (!foldfloat(op, &aux, ls->u.f, f)) + return NULL; + } else if (tp == doubletype) { + d = (rs) ? rs->u.d : 0.0; + if (!folddouble(op, &aux, ls->u.d, d)) + return NULL; + } else { + ld = (rs) ? rs->u.ld : 0.0; + if (!foldldouble(op, &aux, ls->u.ld, ld)) + return NULL; + } break; default: abort();