aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/c_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/c_eval.c')
-rw-r--r--src/c_eval.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/c_eval.c b/src/c_eval.c
index 8518b91..8b68a4b 100644
--- a/src/c_eval.c
+++ b/src/c_eval.c
@@ -1,5 +1,7 @@
#include "c.h"
#include "ir.h"
+#include "obj.h"
+#include "u_endian.h"
#include <limits.h>
static int
@@ -397,6 +399,42 @@ binop(Expr *ex, enum evalmode mode)
return numcast(ex->ty, ex, a);
}
+static bool
+tryreadconst(Expr *ex)
+{
+ assert(ex->t == ESYM);
+ const struct Decl *decl = &declsbuf.p[ex->decl];
+ assert(decl->ty.bits == ex->ty.bits && isarith(ex->ty));
+ uint off;
+ const uchar *dat;
+ switch (objhassym(decl->sym, &off)) {
+ default: return 0;
+ case Stext:
+ dat = objout.textbegin + off;
+ break;
+ case Srodata:
+ dat = objout.rodata.p + off;
+ break;
+ }
+ int siz = targ_primsizes[scalartypet(decl->ty)];
+ ex->t = ENUMLIT;
+ enum { F = 1 << 6, S = 1 << 5 };
+ switch (isflt(ex->ty)*F | issigned(ex->ty)*S | siz) {
+ case S|1: ex->i = *(schar *)dat; break;
+ case 1: ex->u = *(uchar *)dat; break;
+ case S|2: ex->i = rd16targ(dat); break;
+ case 2: ex->u = rd16targ(dat); break;
+ case S|4: ex->i = rd32targ(dat); break;
+ case 4: ex->u = rd32targ(dat); break;
+ case S|8:
+ case 8: ex->u = rd64targ(dat); break;
+ case F|4: ex->f = rdf32targ(dat); break;
+ case F|8: ex->f = rdf64targ(dat); break;
+ default: assert(!"nyi");
+ }
+ return 1;
+}
+
bool
eval(Expr *ex, enum evalmode mode)
{
@@ -433,6 +471,8 @@ eval(Expr *ex, enum evalmode mode)
ex->ty = ty;
return 1;
}
+ } else if (mode == EVFOLD && isarith(ex->ty)) {
+ return tryreadconst(ex);
}
return 0;
case ESTRLIT: case ESSYMREF: