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:
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();