aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--amd64/emit.c8
-rw-r--r--amd64/isel.c81
-rw-r--r--c/c.c2
-rw-r--r--ir/ir.h2
4 files changed, 64 insertions, 29 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index 3cae23f..df735e1 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -135,7 +135,7 @@ mkmemoper(union ref r)
addmemoper(&mem, mkoper(OIMM, .imm = addr->disp));
return mem;
}
- if (isaddrcon(addr->base)) {
+ if (isaddrcon(addr->base,0)) {
return mkoper(OSYM, .con = addr->base.i,
.cindex = addr->index.bits ? mkregoper(addr->index).reg : NOINDEX,
.cshift = addr->shift,
@@ -146,7 +146,7 @@ mkmemoper(union ref r)
.index = addr->index.bits ? mkregoper(addr->index).reg : NOINDEX,
.disp = intconval(addr->base),
.shift = addr->shift);
- } else if (isaddrcon(addr->index)) {
+ } else if (isaddrcon(addr->index,0)) {
assert(!addr->shift);
return mkoper(OSYM, .con = addr->index.i,
.cindex = addr->base.bits ? mkregoper(addr->base).reg : NOINDEX,
@@ -857,7 +857,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope
}
/* normal (not 2-address) case */
Lea:
- if (isaddrcon(addr->base) && ccopt.pic) {
+ if (isaddrcon(addr->base,0) && ccopt.pic) {
assert(!addr->disp && !addr->index.bits);
val = addr->base;
goto GOTLoad;
@@ -866,7 +866,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope
} else if (val.bits == ZEROREF.bits && dst.t == OREG && (kisflt(cls) || !flagslivep(blk, curi))) {
/* dst = 0 -> xor dst, dst; but only if it is ok to clobber flags */
Xxor(pcode, kisint(cls) ? KI4 : cls, dst, dst);
- } else if (isaddrcon(val)) {
+ } else if (isaddrcon(val,0)) {
if (ccopt.pic) GOTLoad:
/* for mov reg, [rip(sym@GOTPCREL)] */
Xmov(pcode, cls, dst, mkoper(OSYM, .con = val.i, .cindex = NOINDEX));
diff --git a/amd64/isel.c b/amd64/isel.c
index a010b90..649c393 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -44,10 +44,16 @@ static int iflagsrc = -1;
static void
picfixsym(union ref *r, struct block *blk, int *curi)
{
- if (!ccopt.pic || !isaddrcon(*r)) return;
+ if (!ccopt.pic || !isaddrcon(*r,0)) return;
*r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, .l = *r));
}
+/* map alloca tmp -> stack frame displacement (0 if not alloca) */
+static ushort *stkslots;
+static uint nstkslots;
+
+#define isstkslot(r) ((r).t == RTMP && (r).i < nstkslots && stkslots[(r).i])
+
static void
fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi)
{
@@ -100,6 +106,12 @@ fixarg(union ref *r, struct instr *ins, struct block *blk, int *curi)
sh = r->i;
ShiftImm: /* shift immediate is always 8bit */
*r = mkref(RICON, sh & 255);
+ } else if (isstkslot(*r)) {
+ struct instr adr = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkintcon(KI4, -stkslots[r->i]));
+ if (in_range(op, Ocopy, Omove))
+ *ins = adr;
+ else
+ *r = insertinstr(blk, (*curi)++, adr);
}
picfixsym(r, blk, curi);
}
@@ -150,7 +162,19 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi)
}
}
-#define isimm32(r) (concls(r) == KI4)
+#define isimm32(r) (iscon(r) && concls(r) == KI4)
+
+static bool
+aimm(struct addr *addr, int disp)
+{
+ vlong a = addr->disp;
+ a += disp;
+ if ((int)a == a) {
+ addr->disp = a;
+ return 1;
+ }
+ return 0;
+}
static bool
acon(struct addr *addr, union ref r)
@@ -196,22 +220,24 @@ ascale(struct addr *addr, union ref a, union ref b)
}
static bool
-aadd(struct addr *addr, union ref r)
+aadd(struct addr *addr, struct block *blk, int *curi, union ref r)
{
- if (r.t == RTMP) {
+ if (isstkslot(r)) {
+ if (addr->base.bits || !aimm(addr, -stkslots[r.i])) goto Ref;
+ addr->base = mkref(RREG, RBP);
+ } else if (r.t == RTMP) {
struct instr *ins = &instrtab[r.i];
-
if (ins->op == Oadd) {
- if (!aadd(addr, ins->l)) goto Ref;
- if (!aadd(addr, ins->r)) goto Ref;
+ if (!aadd(addr, blk, curi, ins->l)) goto Ref;
+ if (!aadd(addr, blk, curi, ins->r)) goto Ref;
ins->skip = 1;
} else if (ins->op == Oshl) {
if (!ascale(addr, ins->l, ins->r)) goto Ref;
ins->skip = 1;
} else if (ins->op == Ocopy && ins->l.t == RADDR) {
struct addr save = *addr, *addr2 = &addrht[ins->l.i];
- if ((!addr2->base.bits || aadd(addr, addr2->base))
- && acon(addr, mkintcon(KI4, addr2->disp))
+ if ((!addr2->base.bits || aadd(addr, blk, curi, addr2->base))
+ && aimm(addr, addr2->disp)
&& (!addr2->index.bits || ascale(addr, addr2->index, mkref(RICON, addr2->shift))))
{
ins->skip = 1;
@@ -220,19 +246,22 @@ aadd(struct addr *addr, union ref r)
goto Ref;
}
} else if (ins->op == Ocopy) {
- if (!aadd(addr, ins->l)) goto Ref;
+ if (!aadd(addr, blk, curi, ins->l)) goto Ref;
ins->skip = 1;
} else goto Ref;
} else if (isnumcon(r)) {
return acon(addr, r);
- } else if (isaddrcon(r)) {
- if (!addr->base.bits && !isaddrcon(addr->index)) addr->base = r;
+ } else if (isaddrcon(r,1)) {
+ if (!addr->base.bits && !isaddrcon(addr->index,1)) addr->base = r;
else return 0;
} else if (r.t == RREG) {
/* temporaries are single assignment, but register aren't, so they can't be *
* safely hoisted into an address value, unless they have global lifetime */
if (!rstest(mctarg->rglob, r.i)) return 0;
Ref:
+ if (isstkslot(r) && (addr->base.bits || addr->index.bits)) {
+ r = insertinstr(blk, (*curi)++, mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -stkslots[r.i])));
+ }
if (!addr->base.bits) addr->base = r;
else if (!addr->index.bits) addr->index = r;
else return 0;
@@ -245,20 +274,20 @@ fuseaddr(union ref *r, struct block *blk, int *curi)
{
struct addr addr = { 0 };
- if (isaddrcon(*r)) return 1;
+ if (isaddrcon(*r,1)) return 1;
if (r->t == RADDR) {
const struct addr *a0 = &addrht[r->i];
- if (aadd(&addr, a0->base)
+ if (aadd(&addr, blk, curi, a0->base)
&& (!addr.index.bits || ascale(&addr, a0->index, mkref(RICON, a0->shift)))
- && aadd(&addr, mkintcon(KPTR, a0->disp))) {
+ && aadd(&addr, blk, curi, mkintcon(KPTR, a0->disp))) {
*r = mkaddr(addr);
}
return 1;
}
if (r->t != RTMP) return 0;
- if (!aadd(&addr, *r)) return 0;
+ if (!aadd(&addr, blk, curi, *r)) return 0;
- if (isaddrcon(addr.base) && (ccopt.pic || (ccopt.pie && addr.index.bits))) {
+ if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits))) {
/* pic needs to load from GOT */
/* pie cannot encode RIP-relative address with index register */
/* first load symbol address into a temp register */
@@ -285,6 +314,7 @@ addarg4addrp(union ref r)
struct instr *ins;
if (r.t == RXCON && !conht[r.i].cls && !conht[r.i].deref) return 1; /* sym or dat ref */
if (r.t != RTMP) return 0;
+ if (isstkslot(r)) return 1;
ins = &instrtab[r.i];
return ins->op == Oshl || (ins->op == Ocopy && ins->l.t == RADDR) || ins->op == Oadd;
}
@@ -318,7 +348,7 @@ static void
sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
{
uint siz, alignlog2;
- int t;
+ int t = ins - instrtab;
struct instr temp = {0};
enum op op = ins->op;
@@ -336,8 +366,9 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
siz = ins->l.i << alignlog2;
fn->stksiz += siz;
fn->stksiz = alignup(fn->stksiz, 1 << alignlog2);
- if (fn->stksiz > 1<<24) error(NULL, "'%s' stack frame too big", fn->name);
- *ins = mkinstr(Oadd, KPTR, mkref(RREG, RBP), mkref(RICON, -fn->stksiz));
+ if (fn->stksiz > (1<<16)-1) error(NULL, "'%s' stack frame too big", fn->name);
+ stkslots[t] = fn->stksiz;
+ *ins = mkinstr(Onop,0,);
break;
case Oparam:
assert(ins->l.t == RICON && ins->l.i < fn->nabiarg);
@@ -418,7 +449,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
if ((addarg4addrp(ins->l) || addarg4addrp(ins->r))) {
temp.op = Ocopy;
temp.cls = ins->cls;
- temp.l = mkref(RTMP, ins - instrtab);
+ temp.l = mkref(RTMP, t);
if (fuseaddr(&temp.l, blk, curi)) {
*ins = temp;
break;
@@ -451,6 +482,8 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
if (ins->r.bits)
case Omove:
fixarg(&ins->r, ins, blk, curi);
+ if (op == Oadd && isaddrcon(ins->r,1)) /* no 3-address add if rhs is mem */
+ ins->inplace = 1;
break;
case Oloads1: case Oloadu1: case Oloads2: case Oloadu2:
case Oloads4: case Oloadu4: case Oloadi8: case Oloadf4: case Oloadf8:
@@ -458,7 +491,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
break;
case Ostore1: case Ostore2: case Ostore4: case Ostore8:
loadstoreaddr(blk, &ins->l, curi);
- if (isaddrcon(ins->r))
+ if (isaddrcon(ins->r,1) || ins->r.t == RADDR)
ins->r = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->r));
else
fixarg(&ins->r, ins, blk, curi);
@@ -554,10 +587,11 @@ seljmp(struct function *fn, struct block *blk)
void
amd64_isel(struct function *fn)
{
+ extern int ninstr;
struct block *blk = fn->entry;
fn->stksiz = 0;
-
+ stkslots = xcalloc((nstkslots = ninstr) * sizeof *stkslots);
do {
int i;
for (i = 0; i < blk->phi.n; ++i) {
@@ -579,6 +613,7 @@ amd64_isel(struct function *fn)
}
seljmp(fn, blk);
} while ((blk = blk->lnext) != fn->entry);
+ free(stkslots);
if (ccopt.dbg.i) {
bfmt(ccopt.dbgout, "<< After isel >>\n");
diff --git a/c/c.c b/c/c.c
index 6714cab..c7cfc50 100644
--- a/c/c.c
+++ b/c/c.c
@@ -4221,7 +4221,7 @@ docomp(struct comp *cm)
}
decl.isdef = st.varini;
if (st.funcdef) {
- const struct typedata *td = &typedata[decl.ty.dat];
+ const struct typedata *td = &typedata[decl.ty.dat];
struct function fn = { &cm->fnarena, decl.name, .globl = decl.scls != SCSTATIC };
fn.fnty = decl.ty;
if (td->ret.t != TYVOID && isincomplete(td->ret))
diff --git a/ir/ir.h b/ir/ir.h
index aa91f6b..1e9e578 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -237,7 +237,7 @@ union ref mkfltcon(enum irclass, double);
#define isintcon(r) (iscon(r) && kisint(concls(r)))
#define isfltcon(r) ((r).t == RXCON && kisflt(conht[(r).i].cls))
#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 isaddrcon(r,derefok) ((r).t == RXCON && !conht[(r).i].cls && (derefok || !conht[(r).i].deref))
#define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i)
#define fltconval(r) ((r).t == RICON ? (r).i : conht[(r).i].f)
union ref mksymref(const char *);