aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-11-05 13:56:54 +0100
committerlemon <lsof@mailbox.org>2025-11-05 19:02:44 +0100
commit13471741b538baa45cd53a521cf7d52087f3200f (patch)
tree15624e0f3a2e8a11f2c114f8309af6e3207193c0
parent088c3c1ce51de82ef317592bae766ad20f82208d (diff)
amd64: fix aggregate abi stuff;; ir: fold, peephole optimizing constructors
-rw-r--r--Makefile2
-rw-r--r--amd64/isel.c3
-rw-r--r--amd64/sysv.c44
-rw-r--r--c/c.c198
-rw-r--r--c/eval.c6
-rw-r--r--common.h6
-rw-r--r--ir/builder.c217
-rw-r--r--ir/fold.c119
-rw-r--r--ir/ir.c95
-rw-r--r--ir/ir.h12
-rw-r--r--ir/optmem.c14
-rw-r--r--ir/regalloc.c19
12 files changed, 522 insertions, 213 deletions
diff --git a/Makefile b/Makefile
index 8565d2d..2a39644 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-SRC=main.c io.c mem.c c/c.c c/lex.c c/eval.c type.c targ.c ir/ir.c ir/dump.c ir/ssa.c ir/cfg.c \
+SRC=main.c io.c mem.c c/c.c c/lex.c c/eval.c type.c targ.c ir/ir.c ir/builder.c ir/fold.c ir/dump.c ir/ssa.c ir/cfg.c \
ir/intrin.c ir/abi0.c ir/optmem.c ir/regalloc.c amd64/sysv.c amd64/isel.c amd64/emit.c obj/obj.c obj/elf.c \
embedfilesdir.c
CFLAGS=-Wall -std=c11 -pedantic
diff --git a/amd64/isel.c b/amd64/isel.c
index 133868e..c250ec0 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -137,7 +137,6 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi)
}
#define isimm32(r) (concls(r) == KI4)
-#define rswap(a,b) do { union ref _t = (a); (a) = (b); (b) = _t; } while (0)
static bool
acon(struct addr *addr, union ref r)
@@ -248,7 +247,7 @@ fuseaddr(union ref *r, struct block *blk, int *curi)
if (!addr.base.bits) {
/* absolute int address in disp */
- assert(!addr.index.bits);
+ if (addr.index.bits) return 0;
addr.base = mkintcon(KPTR, addr.disp);
addr.disp = 0;
}
diff --git a/amd64/sysv.c b/amd64/sysv.c
index 43ecd3c..334be26 100644
--- a/amd64/sysv.c
+++ b/amd64/sysv.c
@@ -1,6 +1,24 @@
#include "all.h"
static int classify(uchar cls[2], const struct typedata *td, uint off);
+
+static void
+clsscalar(uchar cls[2], uint off, union type ty)
+{
+ enum irclass k = type2cls[scalartypet(ty)];
+ uchar *fcls = &cls[off/8];
+ if (isflt(ty)) { /* SSE */
+ if (!*fcls || (*fcls == KF4 && k > *fcls))
+ *fcls = k;
+ } else { /* INTEGER */
+ assert(isint(ty) || ty.t == TYPTR);
+ if (cls2siz[*fcls] < cls2siz[k])
+ *fcls = k;
+ }
+ if (off % 8 >= 4 && cls2siz[*fcls] < 8)
+ *fcls = kisint(*fcls) ? KI8 : KF8;
+}
+
static int
classifyarr(uchar cls[2], union type ty, uint off)
{
@@ -15,12 +33,8 @@ classifyarr(uchar cls[2], union type ty, uint off)
} else if (chld.t == TYARRAY) {
if (!classifyarr(cls, chld, offx))
return cls[0] = cls[1] = 0;
- } else if (isflt(chld)) { /* SSE */
- if (!cls[offx/8])
- cls[offx/8] = KF8;
- } else { /* INTEGER */
- assert(isint(chld) || chld.t == TYPTR);
- cls[offx/8] = KI8;
+ } else {
+ clsscalar(cls, offx, chld);
}
}
return !!cls[0] + !!cls[1];
@@ -28,7 +42,7 @@ classifyarr(uchar cls[2], union type ty, uint off)
static int
classify(uchar cls[2], const struct typedata *td, uint off)
{
- uint siz = alignup(td->siz, 8);
+ uint siz = alignup(td->siz, 4);
if (siz > 16) /* MEMORY */
return 0;
for (int i = 0; i < td->nmemb; ++i) {
@@ -43,12 +57,8 @@ classify(uchar cls[2], const struct typedata *td, uint off)
if (isincomplete(fld->t)) continue;
if (!classifyarr(cls, fld->t, off + fld->off))
return cls[0] = cls[1] = 0;
- } else if (isflt(fld->t)) { /* SSE */
- if (!cls[(fld->off + off)/8])
- cls[(fld->off + off)/8] = KF8;
- } else { /* INTEGER */
- assert(isint(fld->t) || fld->t.t == TYPTR);
- cls[(fld->off + off)/8] = KI8;
+ } else {
+ clsscalar(cls, fld->off + off, fld->t);
}
}
return !!cls[0] + !!cls[1];
@@ -84,9 +94,9 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ)
ni_save = *ni, nf_save = *nf;
for (int i = 0; i < ret; ++i) {
assert(cls[i]);
- if (cls[i] == KF8 && *nf < NFLT)
+ if (kisflt(cls[i]) && *nf < NFLT)
r[i] = XMM0 + (*nf)++;
- else if (cls[i] == KI8 && *ni < NINT)
+ else if (kisint(cls[i]) && *ni < NINT)
r[i] = intregs[(*ni)++];
else { /* MEMORY */
*ni = ni_save, *nf = nf_save;
@@ -121,9 +131,9 @@ abiret(short r[2], uchar cls[2], int *ni, union irtype typ)
assert(ret <= 2);
for (int i = 0, ni = 0, nf = 0; i < ret; ++i) {
assert(cls[i]);
- if (cls[i] == KF8) /* SSE (XMM0, XMM1) */
+ if (kisflt(cls[i])) /* SSE (XMM0, XMM1) */
r[i] = XMM0 + nf++;
- else if (cls[i] == KI8) /* INTEGER (RAX, RDX) */
+ else if (kisint(cls[i])) /* INTEGER (RAX, RDX) */
r[i] = ni++ == 0 ? RAX : RDX;
else assert(0);
}
diff --git a/c/c.c b/c/c.c
index d37bd6b..2c3aea0 100644
--- a/c/c.c
+++ b/c/c.c
@@ -1980,7 +1980,7 @@ ptypeof(struct comp *cm)
return ty;
}
-static void
+static bool
declspec(struct declstate *st, struct comp *cm)
{
struct token tk;
@@ -2139,11 +2139,16 @@ End:
else
goto Bad;
st->base = mktype(t ? t : TYINT);
- } else if (!st->base.t && ccopt.cstd < STDC23) {
- warn(&span, "type implicitly declared as int");
- st->base = mktype(TYINT);
- } else if (!st->base.t)
- fatal(&span, "expected declaration type specifier");
+ } else if (!st->base.t) {
+ if (ccopt.cstd < STDC23) {
+ warn(&span, "type implicitly declared as int");
+ st->base = mktype(TYINT);
+ } else {
+ fatal(&span, "expected declaration type specifier");
+ }
+ return 0;
+ }
+ return 1;
}
/* circular doubly linked list used to parse declarators */
@@ -2493,7 +2498,11 @@ pdecl(struct declstate *st, struct comp *cm) {
error(&tk.span, "this storage class is not allowed in this context");
st->scls &= allowed;
}
- declspec(st, cm);
+ peek(cm, &tk);
+ if (!declspec(st, cm) && st->kind != DTOPLEVEL) {
+ lex(cm, &tk);
+ error(&tk.span, "unknown type name %'s", tk.s);
+ }
}
if (st->scls == SCTYPEDEF) iniallowed = 0;
@@ -2584,7 +2593,6 @@ expraddr(struct function *fn, const struct expr *ex)
{
struct decl *decl;
union ref r;
- struct instr ins = {0};
switch (ex->t) {
case ESYM:
@@ -2613,12 +2621,7 @@ expraddr(struct function *fn, const struct expr *ex)
case EGETF:
r = expraddr(fn, ex->sub);
assert(ex->fld.bitsiz == 0);
- if (ex->fld.off == 0) return r;
- ins.cls = KPTR;
- ins.op = Oadd;
- ins.l = r;
- ins.r = mkintcon(KI4, ex->fld.off);
- return addinstr(fn, ins);
+ return irbinop(fn, Oadd, KPTR, r, mkintcon(KI4, ex->fld.off));
case ESET:
assert(isagg(ex->ty));
r = expraddr(fn, &ex->sub[1]);
@@ -2711,7 +2714,7 @@ geninit(struct function *fn, union type t, union ref dst, const struct expr *src
if (bscount(azero, arraylength(azero)) < 32) {
/* write individual zeros at non initialized gaps */
for (uint i = 0; bsiter(&i, azero, arraylength(azero)) && i < siz; i += align) {
- adr = i == 0 ? dst : addinstr(fn, mkinstr(Oadd, KPTR, dst, mkref(RICON, i)));
+ adr = irbinop(fn, Oadd, KPTR, dst, mkref(RICON, i));
addinstr(fn, mkinstr(Ostore1 + ilog2(align), 0, .l = adr, .r = ZEROREF));
}
} else {
@@ -2731,7 +2734,7 @@ geninit(struct function *fn, union type t, union ref dst, const struct expr *src
for (struct initval *val = ini->vals; val; val = val->next) {
uint off = val->off;
struct expr *ex = &val->ex;
- adr = off == 0 ? dst : addinstr(fn, mkinstr(Oadd, KPTR, dst, mkref(RICON, off)));
+ adr = irbinop(fn, Oadd, KPTR, dst, mkref(RICON, off));
if (ex->t == EINIT || ex->t == ESTRLIT) {
geninit(fn, ex->ty, adr, ex);
} else if (isagg(ex->ty)) {
@@ -2754,83 +2757,115 @@ geninit(struct function *fn, union type t, union ref dst, const struct expr *src
genstore(fn, ctyp, adr, mkref(RICON, src->s.w16[i]));
else
genstore(fn, ctyp, adr, mkintcon(KI4, src->s.w32[i]));
- adr = addinstr(fn, mkinstr(Oadd, KPTR, dst, mkref(RICON, (i+1)*csiz)));
+ adr = irbinop(fn, Oadd, KPTR, dst, mkref(RICON, (i+1)*csiz));
}
genstore(fn, ctyp, adr, ZEROREF); /* null term */
} else assert(0);
}
+static bool
+isboollike(struct function *fn, union ref r)
+{
+ struct instr *ins;
+ if (r.t == RICON && (r.i == 0 || r.i == 1)) return 1;
+ if (r.t != RTMP) return 0;
+ ins = &instrtab[r.i];
+ if (oiscmp(ins->op)) /* these instrs already have output range of [0,1] */
+ return 1;
+ if (ins->op == Ophi) { /* check if all the phi args are boollike */
+ struct block *blk;
+ union ref *phi = NULL;
+ for (blk = fn->curblk; phi == NULL; blk = blk->lprev) {
+ /* find blk that defines phi */
+ assert(blk != fn->entry);
+ for (int i = 0; i < blk->phi.n; ++i){
+ if (blk->phi.p[i] == r.i) {
+ phi = phitab.p[ins->l.i];
+ break;
+ }
+ }
+ }
+ for (int i = 0; i < blk->npred; ++i) {
+ if (!isboollike(fn, phi[i])) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ if (in_range(ins->op, Oand, Oxor))
+ return isboollike(fn, ins->l) && isboollike(fn, ins->r);
+ if (ins->op == Ocopy || in_range(ins->op, Oexts1, Oextu4))
+ return isboollike(fn, ins->l);
+ if (ins->op == Oparam)
+ return typedata[fn->fnty.dat].param[ins->l.i].t == TYBOOL;
+ return 0;
+}
+
static union ref
cvt(struct function *fn, union type to, union type from, union ref ref)
{
enum irclass kto = type2cls[scalartypet(to)], kfrom = type2cls[scalartypet(from)];
- struct instr ins = {0};
+ enum op op;
if (to.bits == from.bits) return ref;
assert(kto && kfrom);
if (kto == kfrom && to.t != TYBOOL) return ref;
if (ref.t == RICON && kto < KF4) return ref;
- ins.cls = kto;
- ins.l = ref;
if (kisflt(kto) || kisflt(kfrom)) {
if (ref.t == RICON) {
assert(kisflt(kto) && kisint(kfrom));
return mkfltcon(kto, kto == KF4 ? (float)ref.i : (double)ref.i);
}
- if (kisflt(kto) && kfrom == KI4) ins.op = issigned(from) ? Ocvts4f : Ocvtu4f;
- else if (to.t == TYBOOL && kisflt(kfrom)) ins.op = Oneq, ins.r = mkfltcon(kfrom, 0.0);
- else if (kisflt(kto) && kfrom == KI8) ins.op = issigned(from) ? Ocvts8f : Ocvtu8f;
- else if (kto == KF8 && kfrom == KF4) ins.op = Ocvtf4f8;
- else if (kto == KF4 && kfrom == KF8) ins.op = Ocvtf8f4;
- else if (kfrom == KF4) ins.op = issigned(to) ? Ocvtf4s : Ocvtf4u;
- else if (kfrom == KF8) ins.op = issigned(to) ? Ocvtf8s : Ocvtf8u;
+ if (kisflt(kto) && kfrom == KI4) op = issigned(from) ? Ocvts4f : Ocvtu4f;
+ else if (to.t == TYBOOL && kisflt(kfrom)) return irbinop(fn, Oneq, kfrom, ref, mkfltcon(kfrom, 0.0));
+ else if (kisflt(kto) && kfrom == KI8) op = issigned(from) ? Ocvts8f : Ocvtu8f;
+ else if (kto == KF8 && kfrom == KF4) op = Ocvtf4f8;
+ else if (kto == KF4 && kfrom == KF8) op = Ocvtf8f4;
+ else if (kfrom == KF4) op = issigned(to) ? Ocvtf4s : Ocvtf4u;
+ else if (kfrom == KF8) op = issigned(to) ? Ocvtf8s : Ocvtf8u;
else assert(0);
} else {
if (to.t == TYBOOL) {
if (from.t == TYBOOL) return ref;
- if (ref.t == RTMP)
- /* these instrs already have output range of [0,1] */
- if (oiscmp(instrtab[ref.i].op))
- return ref;
- ins.op = Oneq, ins.r = ZEROREF;
+ if (isboollike(fn, ref))
+ return kfrom == KI4 ? ref : cvt(fn, mktype(TYINT), from, ref);
+ return irbinop(fn, Oneq, kfrom, ref, ZEROREF);
}
- else if (kfrom == KI4 && issigned(from)) ins.op = Oexts4;
- else if (kfrom == KI4) ins.op = Oextu4;
+ else if (kfrom == KI4 && issigned(from)) op = Oexts4;
+ else if (kfrom == KI4) op = Oextu4;
else if (kto == KI4 && isintcon(ref))
return issigned(to) ? mkintcon(kto, (int)intconval(ref)) : mkintcon(kto, (uint)intconval(ref));
- else ins.op = Ocopy;
+ else op = Ocopy;
}
- return addinstr(fn, ins);
+ return irunop(fn, op, kto, ref);
}
static union ref
narrow(struct function *fn, enum irclass to, union type t, union ref ref, uint bitsiz)
{
- struct instr ins = {0};
enum typetag tt = scalartypet(t);
assert(isscalar(t));
if (targ_primsizes[tt] < cls2siz[to]) {
- ins.cls = to;
+ enum op op;
if (isfltt(tt)) {
assert(to == KF4 && tt >= TYDOUBLE);
- ins.op = Ocvtf8f4;
+ op = Ocvtf8f4;
} else {
static const enum op ext[5][2] = {
[1] = {Oextu1, Oexts1}, [2] = {Oextu2, Oexts2}, [4] = {Oextu4, Oexts4}
};
- ins.op = ext[targ_primsizes[tt]][issignedt(tt)];
+ op = ext[targ_primsizes[tt]][issignedt(tt)];
}
- ins.l = ref;
- ref = addinstr(fn, ins);
+ ref = irunop(fn, op, to, ref);
}
if (bitsiz) {
assert(kisint(to) && isintt(tt) && bitsiz < 8*targ_primsizes[tt]);
if (!issignedt(tt)) {
- ref = addinstr(fn, mkinstr(Oand, to, .l = ref, .r = mkintcon(to, (1ull<<bitsiz)-1)));
+ ref = irbinop(fn, Oand, to, ref, mkintcon(to, (1ull<<bitsiz)-1));
} else {
uint sh = 8*cls2siz[to] - bitsiz;
- ref = addinstr(fn, mkinstr(Oshl, to, .l = ref, .r = mkref(RICON, sh)));
- ref = addinstr(fn, mkinstr(Osar, to, .l = ref, .r = mkref(RICON, sh)));
+ ref = irbinop(fn, Oshl, to, ref, mkref(RICON, sh));
+ ref = irbinop(fn, Osar, to, ref, mkref(RICON, sh));
}
}
return ref;
@@ -2849,14 +2884,11 @@ genptroff(struct function *fn, enum op op, uint siz, union ref ptr,
else if (idx.t == RICON) {
if (op == Osub) op = Oadd, idx.i = -idx.i;
off = mkintcon(cls, idx.i * (int)siz);
- } else if (ispo2(siz))
- off = addinstr(fn,
- mkinstr(Oshl, cls, .l = idx, .r = mkintcon(cls, ilog2(siz))));
- else
- off = addinstr(fn,
- mkinstr(Omul, cls, .l = idx, .r = mkintcon(cls, siz)));
+ } else {
+ off = irbinop(fn, Omul, cls, idx, mkintcon(cls, siz));
+ }
assert(in_range(op, Oadd, Osub));
- return addinstr(fn, mkinstr(op, KPTR, .l = ptr, .r = off));
+ return irbinop(fn, op, KPTR, ptr, off);
}
union ref
@@ -2864,12 +2896,12 @@ genptrdiff(struct function *fn, uint siz, union ref a, union ref b)
{
uint cls = type2cls[targ_ptrdifftype];
assert(siz > 0);
- a = addinstr(fn, mkinstr(Osub, cls, .l = a, .r = b));
+ a = irbinop(fn, Osub, cls, a, b);
if (siz == 1) return a;
- else if ((siz & (siz-1)) == 0) /* is power of 2 */
- return addinstr(fn, mkinstr(Osar, cls, a, mkintcon(cls, ilog2(siz))));
+ else if (ispo2(siz))
+ return irbinop(fn, Osar, cls, a, mkintcon(cls, ilog2(siz)));
else
- return addinstr(fn, mkinstr(Odiv, cls, a, mkintcon(cls, siz)));
+ return irbinop(fn, Odiv, cls, a, mkintcon(cls, siz));
}
/* used to emit the jumps in an in if (), while (), etc condition */
@@ -3042,25 +3074,21 @@ genbitfload(struct function *fn, const union type ty, union ref *addr, const str
uvlong mask;
assert(k);
- if (off > 0)
- *addr = addinstr(fn, mkinstr(Oadd, KPTR, .l = *addr, .r = mkintcon(KI4, off)));
+ *addr = irbinop(fn, Oadd, KPTR, *addr, mkintcon(KI4, off));
tmp = genload(fn, ty, *addr, volatyl);
if (!issigned(ty)) {
/* shift right and mask */
- if (bitoff > 0)
- tmp = addinstr(fn, mkinstr(Oslr, k, .l = tmp, .r = mkref(RICON, bitoff)));
+ tmp = irbinop(fn, Oslr, k, tmp, mkref(RICON, bitoff));
if (bitsiz < 8*typesize(ty)) {
mask = bitsiz == 64 ? -1ull : (1ull << bitsiz) - 1;
- tmp = addinstr(fn, mkinstr(Oand, k, .l = tmp, .r = mkintcon(k, mask)));
+ tmp = irbinop(fn, Oand, k, tmp, mkintcon(k, mask));
}
} else {
/* shift left and shift right arithmetic to propagate sign bit */
int sh = 8*cls2siz[k] - bitsiz - bitoff;
- if (sh)
- tmp = addinstr(fn, mkinstr(Oshl, k, .l = tmp, .r = mkref(RICON, sh)));
+ tmp = irbinop(fn, Oshl, k, tmp, mkref(RICON, sh));
sh += bitoff;
- if (sh)
- tmp = addinstr(fn, mkinstr(Osar, k, .l = tmp, .r = mkref(RICON, sh)));
+ tmp = irbinop(fn, Osar, k, tmp, mkref(RICON, sh));
}
return tmp;
}
@@ -3076,27 +3104,25 @@ genbitfstore(struct function *fn, const union type ty, union ref addr,
assert(k);
if (!tmp.bits) {
- if (off > 0)
- addr = addinstr(fn, mkinstr(Oadd, KPTR, .l = addr, .r = mkintcon(KI4, off)));
+ addr = irbinop(fn, Oadd, KPTR, addr, mkintcon(KPTR, off));
tmp = genload(fn, ty, addr, 0);
}
mask = (bitsiz == 64 ? -1ull : (1ull << bitsiz) - 1) << bitoff;
/* mask out bits in existing container */
- tmp = addinstr(fn, mkinstr(Oand, k, .l = tmp, .r = mkintcon(k, ~mask)));
+ tmp = irbinop(fn, Oand, k, tmp, mkintcon(k, ~mask));
/* shift and mask source value */
if (isintcon(val)) {
val = mkintcon(k, ((uvlong)intconval(val) << bitoff) & mask);
} else {
- if (bitoff)
- val = addinstr(fn, mkinstr(Oshl, k, .l = val, .r = mkref(RICON, bitoff)));
+ val = irbinop(fn, Oshl, k, val, mkref(RICON, bitoff));
if (bitsiz < bittypesize)
- val = addinstr(fn, mkinstr(Oand, k, .l = val, .r = mkintcon(k, mask)));
+ val = irbinop(fn, Oand, k, val, mkintcon(k, mask));
}
/* combine and write */
if (bitsiz < bittypesize)
- val = addinstr(fn, mkinstr(Oior, k, .l = tmp, .r = val));
+ val = irbinop(fn, Oior, k, tmp, val);
genstore(fn, ty, addr, val);
}
@@ -3111,7 +3137,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
int swp = 0;
struct expr *sub;
- eval((struct expr *)ex, EVFOLD);
+ //eval((struct expr *)ex, EVFOLD);
sub = ex->sub;
if (ex->ty.t != TYVOID && !isscalar(ex->ty))
@@ -3155,7 +3181,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
if (discard) return NOREF;
ins.l = cvt(fn, ex->ty, sub->ty, ins.l);
ins.cls = cls;
- return addinstr(fn, ins);
+ return irunop(fn, ins.op, ins.cls, ins.l);
case ELOGNOT:
for (; sub->t == ELOGNOT; ex = sub, sub = sub->sub)
swp ^= 1;
@@ -3165,7 +3191,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
ins.l = cvt(fn, ex->ty, sub->ty, ins.l);
ins.r = mkintcon(cls, 0);
ins.cls = cls;
- return addinstr(fn, ins);
+ return irbinop(fn, ins.op, ins.cls, ins.l, ins.r);
case EDEREF:
discard &= (ex->qual & QVOLATILE) == 0;
r = compileexpr(fn, sub, discard);
@@ -3219,7 +3245,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
return genptroff(fn, ins.op, typesize(typechild(sub[0].ty)), ins.l, sub[1].ty, ins.r);
}
ins.cls = cls;
- return addinstr(fn, ins);
+ return irbinop(fn, ins.op, ins.cls, ins.l, ins.r);
case EPOSTINC:
case EPOSTDEC:
ins.op = ex->t == EPOSTINC ? Oadd : Osub;
@@ -3230,7 +3256,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
ins.r = mkintcon(KI4, typesize(typechild(ex->ty)));
else
ins.r = mkref(RICON, 1);
- genstore(fn, sub->ty, r, addinstr(fn, ins));
+ genstore(fn, sub->ty, r, irbinop(fn, ins.op, ins.cls, ins.l, ins.r));
return ins.l;
case EPREINC:
case EPREDEC:
@@ -3242,7 +3268,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
ins.r = mkintcon(KI4, typesize(typechild(ex->ty)));
else
ins.r = mkref(RICON, 1);
- q = addinstr(fn, ins);
+ q = irbinop(fn, ins.op, ins.cls, ins.l, ins.r);
genstore(fn, sub->ty, r, q);
if (discard) return NOREF;
return narrow(fn, cls, ex->ty, q, 0);
@@ -3274,7 +3300,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
ins.l = cvt(fn, ty, sub[0].ty, ins.l);
ins.r = cvt(fn, ty, sub[1].ty, ins.r);
ins.cls = type2cls[ty.t];
- return addinstr(fn, ins);
+ return irbinop(fn, ins.op, ins.cls, ins.l, ins.r);
case ESET:
assert(isscalar(ex->ty));
q = cvt(fn, sub[0].ty, sub[1].ty, exprvalue(fn, &sub[1]));
@@ -3327,7 +3353,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
/* bit-field */
r = expraddr(fn, &sub[0].sub[0]);
ins.l = genbitfload(fn, sub[0].ty, &r, &sub[0].fld, sub[0].qual & QVOLATILE);
- q = addinstr(fn, ins);
+ q = irbinop(fn, ins.op, ins.cls, ins.l, ins.r);
genbitfstore(fn, sub[0].ty, r, &sub[0].fld, ins.l, q);
} else {
bitsiz = 0;
@@ -3336,7 +3362,7 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard)
if ((ins.op != Oadd && ins.op != Osub) || cls != KPTR) {
ins.l = cvt(fn, ty, sub[0].ty, ins.l);
ins.r = cvt(fn, ex->ty, sub[1].ty, ins.r);
- q = addinstr(fn, ins);
+ q = irbinop(fn, ins.op, ins.cls, ins.l, ins.r);
} else {
q = genptroff(fn, ins.op, typesize(typechild(ex->ty)), ins.l, sub[1].ty, ins.r);
}
@@ -3513,7 +3539,7 @@ genswitch(struct comp *cm, struct function *fn, const struct expr *ex)
struct swcase c = st.cases.p[i];
EMITS {
struct block *next = i < st.cases.n - 1 ? newblk(fn) : st.bdefault;
- putcondbranch(fn, addinstr(fn, mkinstr(Oequ, k, .l = sel, .r = mkintcon(k, c.val))), c.blk, next);
+ putcondbranch(fn, irbinop(fn, Oequ, k, sel, mkintcon(k, c.val)), c.blk, next);
if (next != st.bdefault) useblk(fn, next);
}
}
@@ -4101,11 +4127,9 @@ docomp(struct comp *cm)
int nerr = nerror;
struct decl decl = pdecl(&st, cm);
- if (nerror != nerr) {
- if (st.varini) {
- (void)expr(cm);
- pdecl(&st, cm);
- }
+ if (nerror != nerr && st.varini) {
+ (void)expr(cm);
+ pdecl(&st, cm);
continue;
}
if (st.empty) break;
diff --git a/c/eval.c b/c/eval.c
index 1f61a7f..7e6e43e 100644
--- a/c/eval.c
+++ b/c/eval.c
@@ -29,6 +29,7 @@ numcast(union type ty, struct expr *dst, const struct expr *src)
struct expr tmp;
enum typetag td = targ2hosttype(ty.t);
enum typetag ts = targ2hosttype(src->ty.t == TYENUM ? src->ty.backing : src->ty.t);
+ vlong isrc;
if (src == dst) tmp = *src, src = &tmp;
assert(src->t == ENUMLIT);
@@ -45,11 +46,12 @@ numcast(union type ty, struct expr *dst, const struct expr *src)
else if (td == TYDOUBLE) dst->f = (double) src->i;
else if (TF(TYUVLONG)) dst->u = src->f;
else if (TF(TYBOOL)) dst->i = (bool) src->f;
- else if (isfltt(ts)) { dst->i = src->f; goto Narrow; }
+ else if (isfltt(ts)) { isrc = src->f; goto Narrow; }
else {
+ isrc = src->i;
Narrow:
switch (td) {
-#define I(Ty, Tag) case Tag: dst->i = (Ty) src->i; break;
+#define I(Ty, Tag) case Tag: dst->i = (Ty) isrc; break;
I(bool, TYBOOL)
I(signed char, TYSCHAR)
I(unsigned char, TYUCHAR)
diff --git a/common.h b/common.h
index a4b82cc..c2f95d6 100644
--- a/common.h
+++ b/common.h
@@ -78,7 +78,7 @@ ispo2(uvlong x) {
return (x != 0) & ((x & (x - 1)) == 0);
}
static inline uint
-ilog2(uint x) { /* assumes x is a power of 2 */
+ilog2(uvlong x) { /* assumes x is a power of 2 */
#if HAS_BUILTIN(ctz)
return __builtin_ctz(x);
#else
@@ -280,12 +280,12 @@ extern const char *ttypenames[/*id*/];
#define tdqualsiz(nmemb) ((nmemb)/4 + ((nmemb)%4 != 0))
static inline int
-tdgetqual(const uchar *pqual, int idx)
+tdgetqual(const uchar *pqual, uint idx)
{
return pqual ? pqual[idx/4] >> 2*(idx%4) & 3 : 0;
}
static inline void
-tdsetqual(uchar *pqual, int idx, int qual)
+tdsetqual(uchar *pqual, uint idx, int qual)
{
assert(pqual);
pqual[idx/4] &= ~(3 << (2*(idx%4)));
diff --git a/ir/builder.c b/ir/builder.c
new file mode 100644
index 0000000..213a491
--- /dev/null
+++ b/ir/builder.c
@@ -0,0 +1,217 @@
+#include "ir.h"
+
+/* binary arithmetic builder with peephole optimizations */
+union ref
+irbinop(struct function *fn, enum op op, enum irclass k, union ref l, union ref r)
+{
+ static const union ref ONE = {.t=RICON, .i=1};
+ vlong iv;
+ union ref c;
+
+ if (foldbinop(&c, op, k, l, r))
+ return c;
+
+ switch (op) {
+ case Oadd:
+ if (l.bits == ZEROREF.bits) return r; /* 0 + x ==> x */
+ /* fallthru */
+ case Osub:
+ if (r.bits == ZEROREF.bits) return l; /* x +/- 0 ==> x */
+ break;
+ case Omul: case Oumul:
+ if (iscon(l)) rswap(l, r); /* put const in rhs */
+ if (r.bits == ZEROREF.bits) /* x * 0 ==> 0 */
+ return ZEROREF;
+ if (r.bits == ONE.bits) /* x * 1 ==> x */
+ return l;
+ if (isintcon(r) && ispo2(iv = intconval(r))) {
+ /* x * 2^y ==> x << y */
+ op = Oshl;
+ r = mkintcon(k, ilog2(iv));
+ }
+ break;
+ case Odiv:
+ break;
+ case Oudiv:
+ if (isintcon(r) && ispo2(iv = intconval(r))) {
+ /* x / 2^y ==> x >> y */
+ op = Oslr;
+ r = mkintcon(k, ilog2(iv));
+ }
+ break;
+ case Orem:
+ break;
+ case Ourem:
+ if (isintcon(r) && ispo2(iv = intconval(r))) {
+ /* x % 2^y ==> x & 2^y-1 */
+ op = Oand;
+ r = mkintcon(k, iv - 1);
+ }
+ break;
+ case Oand:
+ if (iscon(l)) rswap(l, r); /* put const in rhs */
+ if (r.bits == ZEROREF.bits) /* x & 0 ==> 0 */
+ return ZEROREF;
+ break;
+ case Oior:
+ if (iscon(l)) rswap(l, r); /* put const in rhs */
+ if (r.bits == ZEROREF.bits) /* x | 0 ==> x */
+ return l;
+ case Oxor:
+ if (iscon(l)) rswap(l, r); /* put const in rhs */
+ if (r.bits == ZEROREF.bits) /* x ^ 0 ==> x */
+ return l;
+ case Oshl: case Osar: case Oslr:
+ if (r.bits == ZEROREF.bits) /* x shift 0 ==> x */
+ return l;
+ break;
+ case Oequ:
+ if (r.bits == l.bits && kisint(k))
+ return ONE;
+ break;
+ case Oneq:
+ if (r.bits == l.bits && kisint(k))
+ return ZEROREF;
+ break;
+ case Olth:
+ break;
+ case Ogth:
+ break;
+ case Olte:
+ break;
+ case Ogte:
+ break;
+ case Oulth:
+ break;
+ case Ougth:
+ break;
+ case Oulte:
+ break;
+ case Ougte:
+ break;
+ default:
+ assert(!"binop?");
+ }
+ return addinstr(fn, mkinstr(op, k, l, r));
+}
+
+union ref
+irunop(struct function *fn, enum op op, enum irclass k, union ref a)
+{
+ union ref c;
+ struct instr *ins = NULL;
+ if (foldunop(&c, op, k, a))
+ return c;
+ if (a.t == RTMP) ins = &instrtab[a.i];
+ switch (op) {
+ case Oneg:
+ if (ins && ins->op == Oneg) /* -(-x) ==> x */
+ return ins->l;
+ break;
+ case Onot:
+ if (ins && ins->op == Onot) /* ~(~x) ==> x */
+ return ins->l;
+ break;
+ case Ocvtf4s: case Ocvtf4u: case Ocvtf4f8: case Ocvtf8s:
+ case Ocvtf8u: case Ocvtf8f4: case Ocvts4f: case Ocvtu4f:
+ case Ocvts8f: case Ocvtu8f:
+ case Oexts1: case Oextu1: case Oexts2: case Oextu2:
+ case Oexts4: case Oextu4:
+ case Ocopy:
+ break;
+ default: assert(!"unop?");
+ }
+ return addinstr(fn, mkinstr(op, k, a));
+}
+
+int newinstr(void);
+
+union ref
+addinstr(struct function *fn, struct instr ins)
+{
+ int new = newinstr();
+ assert(fn->curblk != NULL);
+ instrtab[new] = ins;
+ adduse(fn->curblk, new, ins.l);
+ adduse(fn->curblk, new, ins.r);
+ vpush(&fn->curblk->ins, new);
+ return mkref(RTMP, new);
+}
+
+void
+useblk(struct function *fn, struct block *blk)
+{
+ extern int nerror;
+ if (fn->curblk && nerror == 0) assert(fn->curblk->jmp.t && "never finished block");
+ if (blk) assert(!blk->jmp.t && "reusing built block");
+ if (!blk->lprev) { /* initialize */
+ blk->lnext = fn->entry;
+ blk->lprev = fn->entry->lprev;
+ blk->lprev->lnext = blk;
+ blk->id = blk->lprev->id + 1;
+ ++fn->nblk;
+ fn->entry->lprev = blk;
+ }
+ fn->curblk = blk;
+}
+
+union ref
+addphi(struct function *fn, enum irclass cls, union ref *r)
+{
+ int new;
+ struct instr ins = { Ophi, cls };
+ union ref *refs = NULL;
+
+ xbgrow(&refs, fn->curblk->npred);
+ memcpy(refs, r, fn->curblk->npred * sizeof *r);
+ vpush(&phitab, refs);
+ ins.l = mkref(RXXX, phitab.n-1);
+
+ assert(fn->curblk != NULL);
+ assert(fn->curblk->ins.n == 0);
+ new = newinstr();
+ instrtab[new] = ins;
+ for (int i = 0; i < fn->curblk->npred; ++i) {
+ adduse(fn->curblk, new, r[i]);
+ }
+ vpush(&fn->curblk->phi, new);
+ return mkref(RTMP, new);
+}
+
+#define putjump(fn, j, arg0, arg1, T, F) \
+ fn->curblk->jmp.t = j; \
+ fn->curblk->jmp.arg[0] = arg0; \
+ fn->curblk->jmp.arg[1] = arg1; \
+ fn->curblk->s1 = T; \
+ fn->curblk->s2 = F; \
+ fn->curblk = NULL;
+
+void
+putbranch(struct function *fn, struct block *blk)
+{
+ assert(fn->curblk && blk);
+ addpred(blk, fn->curblk);
+ putjump(fn, Jb, NOREF, NOREF, blk, NULL);
+}
+
+void
+putcondbranch(struct function *fn, union ref arg, struct block *t, struct block *f)
+{
+ assert(fn->curblk && t && f);
+ adduse(fn->curblk, USERJUMP, arg);
+ addpred(t, fn->curblk);
+ addpred(f, fn->curblk);
+ putjump(fn, Jb, arg, NOREF, t, f);
+}
+
+void
+putreturn(struct function *fn, union ref r0, union ref r1)
+{
+ adduse(fn->curblk, USERJUMP, r0);
+ adduse(fn->curblk, USERJUMP, r1);
+ putjump(fn, Jret, r0, r1, NULL, NULL);
+}
+
+#undef putjump
+
+/* vim:set ts=3 sw=3 expandtab: */
diff --git a/ir/fold.c b/ir/fold.c
new file mode 100644
index 0000000..fd6076e
--- /dev/null
+++ b/ir/fold.c
@@ -0,0 +1,119 @@
+#include "ir.h"
+
+static union ref
+foldint(enum op op, enum irclass k, union ref lr, union ref rr)
+{
+ vlong x;
+ union {
+ vlong s;
+ uvlong u;
+ } l = {.s = intconval(lr)}, r = {.s = intconval(rr)};
+ bool w = cls2siz[k] == 8;
+ if (in_range(op, Odiv, Ourem)) assert(r.u != 0);
+ switch (op) {
+ case Ocopy: x = l.s; break;
+ case Oneg: x = -l.s; break;
+ case Onot: x = ~l.s; break;
+ case Ocvtf4s: x = (int)(float)fltconval(lr); break;
+ case Ocvtf4u: x = (uint)(float)fltconval(lr); break;
+ case Ocvtf8s: x = (vlong)fltconval(lr); break;
+ case Ocvtf8u: x = (uvlong)fltconval(lr); break;
+ case Oexts1: x = (schar)l.s; break;
+ case Oextu1: x = (uchar)l.s; break;
+ case Oexts2: x = (short)l.s; break;
+ case Oextu2: x = (ushort)l.s; break;
+ case Oexts4: x = (int)l.s; break;
+ case Oextu4: x = (uint)l.s; break;
+ case Oadd: x = l.u + r.u; break;
+ case Osub: x = l.u - r.u; break;
+ case Omul: x = l.u * r.u; break;
+ case Oumul: x = l.u * r.u; break;
+ case Odiv: x = w ? l.s / r.s : (int)l.s / (int)r.s; break;
+ case Oudiv: x = w ? l.u / r.u : (uint)l.u / (uint)r.u; break;
+ case Orem: x = w ? l.s % r.s : (int)l.s % (int)r.s; break;
+ case Ourem: x = w ? l.u % r.u : (uint)l.u % (uint)r.u; break;
+ case Oand: x = l.u & r.u; break;
+ case Oior: x = l.u | r.u; break;
+ case Oxor: x = l.u ^ r.u; break;
+ case Oshl: x = l.u << (r.u & (w ? 63 : 31)); break;
+ case Oslr: x = w ? l.u >> (r.u&63) : (int)l.s >> (r.u&31); break;
+ case Osar: x = w ? l.s >> (r.u&63) : (int)l.s >> (r.u&31); break;
+ case Oequ: x = l.s == r.s; break;
+ case Oneq: x = l.s != r.s; break;
+ case Olth: x = l.s < r.s; break;
+ case Ogth: x = l.s > r.s; break;
+ case Olte: x = l.s <= r.s; break;
+ case Ogte: x = l.s >= r.s; break;
+ case Oulth: x = l.u < r.u; break;
+ case Ougth: x = l.u > r.u; break;
+ case Oulte: x = l.u <= r.u; break;
+ case Ougte: x = l.u >= r.u; break;
+ default: assert(0);
+ }
+ return mkintcon(k, x);
+}
+
+static union ref
+foldflt(enum op op, enum irclass k, union ref lr, union ref rr)
+{
+ int xi;
+ double x, l = fltconval(lr), r = fltconval(rr);
+ bool w = k == KF8;
+ if (in_range(op, Odiv, Ourem)) assert(r != 0.0);
+ switch (op) {
+ case Ocopy: x = l; break;
+ case Oneg: x = -l; break;
+ case Ocvtf4f8: x = (float)l; break;
+ case Ocvtf8f4: x = (float)l; break;
+ case Ocvts4f: x = (int)intconval(lr); break;
+ case Ocvtu4f: x = (int)intconval(lr); break;
+ case Ocvts8f: x = (vlong)intconval(lr); break;
+ case Ocvtu8f: x = (uvlong)intconval(lr); break;
+ case Oadd: x = l + r; break;
+ case Osub: x = l - r; break;
+ case Omul: x = l * r; break;
+ case Odiv: x = l / r; break;
+ case Oequ: xi = l == r; break;
+ case Oneq: xi = l != r; break;
+ case Olth: xi = l < r; break;
+ case Ogth: xi = l > r; break;
+ case Olte: xi = l <= r; break;
+ case Ogte: xi = l >= r; break;
+ default: assert(0);
+ }
+ if (oiscmp(op)) return mkref(RICON, xi);
+ if (!w) x = (float)x;
+ return mkfltcon(k, x);
+}
+
+bool
+foldbinop(union ref *to, enum op op, enum irclass k, union ref l, union ref r)
+{
+ if (!iscon(l) || !iscon(r)) return 0;
+ if (in_range(op, Odiv, Ourem) && (kisint(k) ? intconval(r) == 0 : fltconval(r) == 0))
+ return 0;
+ if (!oisarith(op))
+ return 0;
+ to->t = oiscmp(op) ? KI4 : k;
+ if (kisint(k))
+ *to = foldint(op, k, l, r);
+ else
+ *to = foldflt(op, k, l, r);
+ return 1;
+}
+
+bool
+foldunop(union ref *to, enum op op, enum irclass k, union ref a)
+{
+ if (!iscon(a)) return 0;
+ if (op != Ocopy && !oisarith(op))
+ return 0;
+ to->t = k;
+ if (kisint(k))
+ *to = foldint(op, k, a, ZEROREF);
+ else
+ *to = foldflt(op, k, a, ZEROREF);
+ return 1;
+}
+
+/* vim:set ts=3 sw=3 expandtab: */
diff --git a/ir/ir.c b/ir/ir.c
index 49d8d5e..2a5cde6 100644
--- a/ir/ir.c
+++ b/ir/ir.c
@@ -297,7 +297,7 @@ insertblk(struct function *fn, struct block *pred, struct block *subst)
assert(0);
}
-static int
+int
newinstr(void)
{
int t;
@@ -383,8 +383,7 @@ insertphi(struct block *blk, enum irclass cls)
int new = newinstr();
union ref *refs = NULL;
assert(blk->npred > 0);
- xbgrow(&refs, blk->npred);
- memset(refs, 0, blk->npred * sizeof *refs);
+ xbgrowz(&refs, blk->npred);
vpush(&phitab, refs);
instrtab[new] = mkinstr(Ophi, cls, mkref(RXXX, phitab.n - 1));
vpush(&blk->phi, new);
@@ -506,96 +505,6 @@ fillblkids(struct function *fn)
do blk->id = i++; while ((blk = blk->lnext) != fn->entry);
}
-/** IR builders **/
-
-void
-useblk(struct function *fn, struct block *blk)
-{
- extern int nerror;
- if (fn->curblk && nerror == 0) assert(fn->curblk->jmp.t && "never finished block");
- if (blk) assert(!blk->jmp.t && "reusing built block");
- if (!blk->lprev) { /* initialize */
- blk->lnext = fn->entry;
- blk->lprev = fn->entry->lprev;
- blk->lprev->lnext = blk;
- blk->id = blk->lprev->id + 1;
- ++fn->nblk;
- fn->entry->lprev = blk;
- }
- fn->curblk = blk;
-}
-
-union ref
-addinstr(struct function *fn, struct instr ins)
-{
- int new = newinstr();
- assert(fn->curblk != NULL);
- instrtab[new] = ins;
- adduse(fn->curblk, new, ins.l);
- adduse(fn->curblk, new, ins.r);
- vpush(&fn->curblk->ins, new);
- return mkref(RTMP, new);
-}
-
-union ref
-addphi(struct function *fn, enum irclass cls, union ref *r)
-{
- int new;
- struct instr ins = { Ophi, cls };
- union ref *refs = NULL;
-
- xbgrow(&refs, fn->curblk->npred);
- memcpy(refs, r, fn->curblk->npred * sizeof *r);
- vpush(&phitab, refs);
- ins.l = mkref(RXXX, phitab.n-1);
-
- assert(fn->curblk != NULL);
- assert(fn->curblk->ins.n == 0);
- new = newinstr();
- instrtab[new] = ins;
- for (int i = 0; i < fn->curblk->npred; ++i) {
- adduse(fn->curblk, new, r[i]);
- }
- vpush(&fn->curblk->phi, new);
- return mkref(RTMP, new);
-}
-
-#define putjump(fn, j, arg0, arg1, T, F) \
- fn->curblk->jmp.t = j; \
- fn->curblk->jmp.arg[0] = arg0; \
- fn->curblk->jmp.arg[1] = arg1; \
- fn->curblk->s1 = T; \
- fn->curblk->s2 = F; \
- fn->curblk = NULL;
-
-void
-putbranch(struct function *fn, struct block *blk)
-{
- assert(fn->curblk && blk);
- addpred(blk, fn->curblk);
- putjump(fn, Jb, NOREF, NOREF, blk, NULL);
-}
-
-void
-putcondbranch(struct function *fn, union ref arg, struct block *t, struct block *f)
-{
- assert(fn->curblk && t && f);
- adduse(fn->curblk, USERJUMP, arg);
- addpred(t, fn->curblk);
- addpred(f, fn->curblk);
- putjump(fn, Jb, arg, NOREF, t, f);
-}
-
-void
-putreturn(struct function *fn, union ref r0, union ref r1)
-{
- adduse(fn->curblk, USERJUMP, r0);
- adduse(fn->curblk, USERJUMP, r1);
- putjump(fn, Jret, r0, r1, NULL, NULL);
-}
-
-#undef putjump
-
/** Misc **/
static void
diff --git a/ir/ir.h b/ir/ir.h
index a49432d..149a74b 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -77,6 +77,7 @@ struct addr {
#define mkref(t, x) ((union ref) {{ (t), (x) }})
#define mktyperef(t) ((union ref) {{ RTYPE, (t).bits }})
#define ref2type(r) ((union irtype) {.bits = (r).i})
+#define rswap(a,b) do { union ref _t = (a); (a) = (b); (b) = _t; } while (0)
enum op {
Oxxx,
@@ -86,6 +87,7 @@ enum op {
};
#define oiscmp(o) in_range(o, Oequ, Ougte)
+#define oisarith(o) in_range(o, Oneg, Ougte)
#define oisalloca(o) in_range(o, Oalloca1, Oalloca16)
#define oisstore(o) in_range(o, Ostore1, Ostore8)
#define oisload(o) in_range(o, Oloads1, Oloadf8)
@@ -219,7 +221,7 @@ union ref mkfltcon(enum irclass, double);
#define isnumcon(r) ((r).t == RICON || ((r).t == RXCON && conht[(r).i].cls))
#define isaddrcon(r) ((r).t == RXCON && !conht[(r).i].cls && !conht[(r).i].deref)
#define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i)
-#define fltconval(r) (conht[(r).i].f)
+#define fltconval(r) ((r).t == RICON ? (r).i : conht[(r).i].f)
union ref mksymref(const char *);
union ref mkdatref(const char *name, uint siz, uint align, const void *, uint n, bool deref);
const char *xcon2sym(int ref);
@@ -247,7 +249,9 @@ void fillblkids(struct function *);
#define markvisited(blk) ((blk)->visit = visitmark)
void numberinstrs(struct function *);
-/* IR builder functions */
+/** builder.c **/
+union ref irbinop(struct function *, enum op, enum irclass, union ref lhs, union ref rhs);
+union ref irunop(struct function *, enum op, enum irclass, union ref);
union ref addinstr(struct function *, struct instr);
union ref addphi(struct function *, enum irclass, union ref []);
void useblk(struct function *, struct block *);
@@ -255,6 +259,10 @@ void putbranch(struct function *, struct block *);
void putcondbranch(struct function *, union ref arg, struct block *t, struct block *f);
void putreturn(struct function *, union ref r0, union ref r1);
+/** fold.c **/
+bool foldbinop(union ref *to, enum op, enum irclass, union ref l, union ref r);
+bool foldunop(union ref *to, enum op, enum irclass, union ref);
+
/** irdump.c **/
void irdump(struct function *);
diff --git a/ir/optmem.c b/ir/optmem.c
index 471f11c..9b71c8d 100644
--- a/ir/optmem.c
+++ b/ir/optmem.c
@@ -246,6 +246,20 @@ mem2reg(struct function *fn)
k, mkref(RREG, mctarg->bpr));
} else {
adduse(use->blk, use->u, val);
+ if (isintcon(val) && ext != Ocopy) {
+ vlong x = intconval(val);
+ switch (ext) {
+ case Oexts1: x = (schar)x; break;
+ case Oextu1: x = (uchar)x; break;
+ case Oexts2: x = (short)x; break;
+ case Oextu2: x = (ushort)x; break;
+ case Oexts4: x = (int)x; break;
+ case Oextu4: x = (uint)x; break;
+ default: assert(0);
+ }
+ val = mkintcon(k, x);
+ ext = Ocopy;
+ }
*m = mkinstr(ext, k, val);
}
}
diff --git a/ir/regalloc.c b/ir/regalloc.c
index fae1a61..f43bcc7 100644
--- a/ir/regalloc.c
+++ b/ir/regalloc.c
@@ -2,7 +2,7 @@
/** Implements linear scan register allocation **/
-#if 0
+#if 1
#define DBG(...) if(ccopt.dbg.r) efmt(__VA_ARGS__)
#else
#define DBG(...) ((void)0)
@@ -1000,12 +1000,19 @@ devirt(struct rega *ra, struct block *blk)
bool dosave;
/* pick scratch register, or any register that doesn't conflict with this instr's srcs/dst */
if (nspill > 0) {
- for (reg = kisflt(ld.cls) ? mctarg->fpr0 : mctarg->gpr0;; ++reg) {
- if (reg == ins->reg-1) continue;
- for (int j = 0; j < i; ++j)
- if (argref[j]->t == RREG && argref[j]->i == reg) continue;
- break;
+ regset avail = kisflt(ld.cls) ? fpregset : gpregset;
+ if (ins->reg) rsclr(&avail, ins->reg-1);
+ for (int j = 0; j < nargref; ++j) {
+ struct interval *it;
+ if (argref[j]->t == RREG) rsclr(&avail, argref[j]->i);
+ else if (argref[j]->t == RTMP) {
+ it = &ra->intervals.temps[argref[j]->i];
+ if (it->alloc.t == AREG) rsclr(&avail, it->alloc.a);
+ }
}
+ assert(avail != 0);
+ if (reg &~ (fn->regusage | mctarg->rcallee)) reg &= ~(fn->regusage | mctarg->rcallee);
+ reg = lowestsetbit(avail);
/* if not the designated scratch register, we need to save+restore */
if ((dosave = rstest(fn->regusage, reg) || rstest(mctarg->rcallee, reg))) {
insertinstr(blk, curi++, mkinstr(Oxsave, 0, .l = mkref(RREG, reg)));