summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-08-11 19:37:26 -0400
committerQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-09-15 23:01:31 -0400
commitd37db3970f06e46d1ea9b55084e065e799b09576 (patch)
tree42cf4d60e57b7f74a99f3c941c5511117e25e6ee
parent0edafe814fee9147b4ce850d80cc9e3b60b15b89 (diff)
downloadroux-d37db3970f06e46d1ea9b55084e065e799b09576.tar.gz
support for large constants
It was not as simple as I thought. All constants used in 32b context get truncated to 32 bits. All constants in 64b contexts can either remain as immutables are have to be evicted in a register, this choice is taken in noimm(). The case of the comparison needs to be documented since the context is not clearly 32 or 64 bits. I am still unsure if this is fully correct.
-rw-r--r--lisc/isel.c86
1 files changed, 64 insertions, 22 deletions
diff --git a/lisc/isel.c b/lisc/isel.c
index e33c11e..7670eff 100644
--- a/lisc/isel.c
+++ b/lisc/isel.c
@@ -1,4 +1,5 @@
#include "lisc.h"
+#include <limits.h>
/* For x86_64, we have to:
*
@@ -24,7 +25,7 @@ emit(short op, Ref to, Ref arg0, Ref arg1)
*--curi = (Ins){op, to, {arg0, arg1}};
}
-static int
+static Ref
newtmp(int type, Fn *fn)
{
static int n;
@@ -36,7 +37,29 @@ newtmp(int type, Fn *fn)
diag("isel: out of memory");
fn->tmp[t] = (Tmp){.type = type};
sprintf(fn->tmp[t].name, "isel%d", ++n);
- return t;
+ return TMP(t);
+}
+
+static int
+noimm(Ref r, Fn *fn)
+{
+ int64_t val;
+
+ assert(rtype(r) == RCon);
+ switch (fn->con[r.val].type) {
+ default:
+ diag("isel: invalid constant");
+ case CAddr:
+ /* we only support the 'small'
+ * code model of the ABI, this
+ * means that we can always
+ * address data with 32bits
+ */
+ return 0;
+ case CNum:
+ val = fn->con[r.val].val;
+ return (val < INT32_MIN || val > INT32_MAX);
+ }
}
static int
@@ -49,34 +72,34 @@ static void
selcmp(Ref arg[2], Fn *fn)
{
Ref r;
- int t;
+ int con, lng;
- t = -1;
+ con = 0;
if (rtype(arg[0]) == RCon) {
r = arg[1];
arg[1] = arg[0];
arg[0] = r;
if (rtype(r) == RCon) {
- /* todo, use the constant
- * size to dimension the
- * constant */
- t = newtmp(TWord, fn);
- arg[0] = TMP(t);
+ con = 1;
+ arg[0] = newtmp(TWord, fn);
}
}
- if (islong(arg[0], fn) || islong(arg[1], fn))
- emit(OXCmpl, R, arg[1], arg[0]);
- else
- emit(OXCmpw, R, arg[1], arg[0]);
- if (t != -1)
- emit(OCopy, TMP(t), r, R);
+ lng = islong(arg[0], fn) || islong(arg[1], fn);
+ emit(lng ? OXCmpl : OXCmpw, R, arg[1], arg[0]);
+ if (con)
+ emit(OCopy, arg[0], r, R);
+ r = arg[0];
+ if (lng && rtype(r) == RCon && noimm(r, fn)) {
+ curi->arg[0] = newtmp(TLong, fn);
+ emit(OCopy, curi->arg[0], r, R);
+ }
}
static void
sel(Ins i, Fn *fn)
{
Ref r0, r1, ra, rd;
- int t, ty, c;
+ int n, ty, c;
switch (i.op) {
case ODiv:
@@ -102,8 +125,7 @@ sel(Ins i, Fn *fn)
/* immediates not allowed for
* divisions in x86
*/
- t = newtmp(ty, fn);
- r0 = TMP(t);
+ r0 = newtmp(ty, fn);
} else
r0 = i.arg[1];
emit(OXDiv, R, r0, R);
@@ -112,10 +134,19 @@ sel(Ins i, Fn *fn)
if (rtype(i.arg[1]) == RCon)
emit(OCopy, r0, i.arg[1], R);
break;
+ case ONop:
+ break;
case OAdd:
case OSub:
case OCopy:
+ if (fn->tmp[i.to.val].type == TLong)
+ n = 2;
+ else
+ n = 0;
+ goto Emit;
case OStorel:
+ n = 1;
+ goto Emit;
case OStorew:
case OStoreb:
case OStores:
@@ -124,9 +155,20 @@ sel(Ins i, Fn *fn)
case OLoadus:
case OLoadsb:
case OLoadub:
+ n = 0;
+Emit:
emit(i.op, i.to, i.arg[0], i.arg[1]);
- break;
- case ONop:
+ while (n--) {
+ /* load constants that do not fit in
+ * a 32bit signed integer into a
+ * long temporary
+ */
+ r0 = i.arg[n];
+ if (rtype(r0) == RCon && noimm(r0, fn)) {
+ curi->arg[n] = newtmp(TLong, fn);
+ emit(OCopy, curi->arg[n], r0, R);
+ }
+ }
break;
default:
if (OCmp <= i.op && i.op <= OCmp1) {
@@ -150,10 +192,10 @@ flagi(Ins *i0, Ins *i)
if (OCmp <= i->op && i->op <= OCmp1)
return i;
return 0;
- case OAdd: /* <arch> flag-setting */
+ case OAdd: /* flag-setting */
case OSub:
return i;
- case OCopy: /* <arch> flag-transparent */
+ case OCopy: /* flag-transparent */
case OStorel:
case OStorew:
case OStoreb: