diff options
Diffstat (limited to 'lisc/isel.c')
-rw-r--r-- | lisc/isel.c | 129 |
1 files changed, 107 insertions, 22 deletions
diff --git a/lisc/isel.c b/lisc/isel.c index 31de291..db5cb92 100644 --- a/lisc/isel.c +++ b/lisc/isel.c @@ -40,12 +40,53 @@ newtmp(int type, Fn *fn) } static int +cneg(int cmp) +{ + switch (cmp) { + default: diag("cneg: unhandled comparison"); + case Ceq: return Cne; + case Csle: return Csgt; + case Cslt: return Csge; + case Csgt: return Csle; + case Csge: return Cslt; + case Cne: return Ceq; + } +} + +static int islong(Ref r, Fn *fn) { return rtype(r) == RTmp && fn->tmp[r.val].type == TLong; } static void +selcmp(Ref arg[2], Fn *fn) +{ + Ref r; + int t; + + t = -1; + 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); + } + } + 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); +} + +static void sel(Ins i, Fn *fn) { Ref r0, r1, ra, rd; @@ -92,35 +133,78 @@ sel(Ins i, Fn *fn) break; default: if (OCmp <= i.op && i.op <= OCmp1) { - t = -1; - r0 = i.arg[0]; c = i.op - OCmp; - if (rtype(i.arg[0]) == RCon) { - if (rtype(i.arg[1]) == RCon) { - /* todo, use the constant - * size to dimension the - * constant */ - t = newtmp(TWord, fn); - r0 = TMP(t); - } else { - r0 = i.arg[1]; - i.arg[1] = i.arg[0]; - c = COP(c); - } - } + if (rtype(i.arg[0]) == RCon) + c = COP(c); emit(OXSet+c, i.to, R, R); - if (islong(r0, fn) || islong(i.arg[1], fn)) - emit(OXCmpl, R, i.arg[1], r0); - else - emit(OXCmpw, R, i.arg[1], r0); - if (t != -1) - emit(OCopy, r0, i.arg[0], R); + selcmp(i.arg, fn); break; } diag("isel: non-exhaustive implementation"); } } +static Ins * +flagi(Ins *i0, Ins *i) +{ + while (i>i0) + switch ((--i)->op) { + default: + return i; + case OCopy: + case OStore: + case OLoad:; + } + return 0; +} + +static Ins * +seljmp(Blk *b, Fn *fn) +{ + Ref r; + int c; + Ins *fi; + + fi = &b->ins[b->nins]; + if (b->jmp.type != JJez) + return fi; + r = b->jmp.arg; + b->jmp.arg = R; + assert(!req(r, R)); + if (rtype(r) == RCon) { + b->jmp.type = JJmp; + if (!req(r, CON_Z)) + b->s1 = b->s2; + b->s2 = 0; + return fi; + } + fi = flagi(b->ins, fi); + if (fi && req(fi->to, r)) { + assert(1 == fn->tmp[r.val].nuse); + if (fn->tmp[r.val].nuse == 1 + && OCmp <= fi->op && fi->op <= OCmp1) { + c = fi->op - OCmp; + if (rtype(fi->arg[0]) == RCon) + c = COP(c); + b->jmp.type = JXJc + cneg(c); + selcmp(fi->arg, fn); + return fi; + } + /* what if it is a comparison + * that is used more than once? + * !!! + */ + b->jmp.type = JXJc + Ceq; + return fi+1; + } + if (islong(r, fn)) + emit(OXCmpl, R, CON_Z, r); + else + emit(OXCmpw, R, CON_Z, r); + b->jmp.type = JXJc + Ceq; + return &b->ins[b->nins]; +} + /* instruction selection * requires use counts (as given by parsing) */ @@ -133,7 +217,8 @@ isel(Fn *fn) for (b=fn->start; b; b=b->link) { curi = &insb[NIns]; - for (i=&b->ins[b->nins]; i!=b->ins;) { + i = seljmp(b, fn); + while (i>b->ins) { sel(*--i, fn); } nins = &insb[NIns] - curi; |