aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-06-14 15:05:43 +0200
committerlemon <lsof@mailbox.org>2023-06-14 15:05:43 +0200
commit782d4e9df0363ca9f64d8b92a3d6952d552f13a5 (patch)
tree8c71e107a8c0b54f53c2c94d053ad4cc1b7a441d /amd64
parent8d8cf6584bf4081b54cd91fcaa42578cbd794440 (diff)
add spilling for function calls, misc fixes
Diffstat (limited to 'amd64')
-rw-r--r--amd64/emit.c24
-rw-r--r--amd64/isel.c18
2 files changed, 28 insertions, 14 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index 4f1a448..499b928 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -49,8 +49,12 @@ addmemoper(struct oper *mem, struct oper add)
if (add.t == OIMM) {
mem->disp += add.imm;
} else if (add.t == OREG) {
- assert(mem->index == NOINDEX);
- mem->index = add.reg;
+ if (mem->base == NOBASE)
+ mem->base = add.reg;
+ else if (mem->index == NOINDEX)
+ mem->index = add.reg;
+ else
+ assert(0);
}
}
@@ -146,6 +150,7 @@ enum operpat {
P1, /* imm = 1 */
PI8,
PI32,
+ PU32,
PMEM,
PSYM,
};
@@ -168,6 +173,7 @@ struct desc {
uchar operenc; /* enum operenc */
uchar ext; /* ModR/M.reg opc extension */
bool r8 : 1; /* uses 8bit register */
+ bool norexw : 1; /* do not use REX.W even if size is 64 bits */
};
/* match operand against pattern */
@@ -183,6 +189,7 @@ opermatch(enum operpat pat, struct oper oper)
case P1: return oper.t == OIMM && oper.imm == 1;
case PI8: return oper.t == OIMM && (uint)(oper.imm+128) < 256;
case PI32: return oper.t == OIMM;
+ case PU32: return oper.t == OIMM && oper.imm >= 0;
case PMEM: return in_range(oper.t, OMEM, OCONR);
case PSYM: return oper.t == OCONR;
}
@@ -219,6 +226,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, uint siz, struct oper ds
if (*opc == 0x66 || *opc == 0xF2 || *opc == 0xF3)
B(*opc++), --nopc;
rex = -(en->ptd != PFPR && en->pts != PFPR) & (siz == 8) << 3; /* REX.W */
+ if (en->norexw) rex = 0;
switch (en->operenc) {
case EN_RR: /* mod = 11; reg = dst; rm = src */
rex |= (dst.reg >> 3) << 2; /* REX.R */
@@ -325,7 +333,9 @@ DEFINSTR2(Xmov,
{4|8, PGPR, PGPR, "\x8B", EN_RR}, /* MOV r32/64, r32/64 */
{4|8, PMEM, PGPR, "\x89", EN_MR}, /* MOV m32/64, r32/64 */
{4|8, PGPR, PMEM, "\x8B", EN_RM}, /* MOV r32/64, m32/64 */
- {4|8, PGPR, PI32, "\xB8", EN_OI}, /* MOV r32/64, imm */
+ {4 , PGPR, PI32, "\xB8", EN_OI}, /* MOV r32, imm */
+ { 8, PGPR, PU32, "\xB8", EN_OI, .norexw=1}, /* MOV r64, uimm */
+ { 8, PGPR, PI32, "\xC7", EN_RI32}, /* MOV r64, imm */
{4, PFPR, PFPR, "\xF3\x0F\x10", EN_RR}, /* MOVSS xmm, xmm */
{8, PFPR, PFPR, "\xF2\x0F\x10", EN_RR}, /* MOVSD xmm, xmm */
{4, PFPR, PMEM, "\xF3\x0F\x10", EN_RM}, /* MOVSS xmm, m32 */
@@ -511,10 +521,10 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int ii, struct
if (ins->reg-1 == dst.reg) { /* two-address add */
Xadd(pcode, ksiz, dst, mkimmdatregoper(ins->r));
} else { /* three-address add (lea) */
- struct oper mem = { OMEM, .index = NOINDEX };
+ struct oper mem = { OMEM, .base = NOBASE, .index = NOINDEX };
dst = reg2oper(ins->reg-1);
- if (isregref(ins->r)) mem.base = mkregoper(ins->r).reg;
- else mem.disp = mkimmoper(ins->r).imm;
+ addmemoper(&mem, ref2oper(ins->l));
+ addmemoper(&mem, ref2oper(ins->r));
Xlea(pcode, ksiz, dst, mem);
}
break;
@@ -632,6 +642,8 @@ emitbin(struct function *fn)
void
amd64_emit(struct function *fn)
{
+ fn->stksiz = alignup(fn->stksiz, 16);
+ if (fn->stksiz > 1<<24) error(NULL, "'%s' stack frame too big", fn->name);
emitbin(fn);
}
diff --git a/amd64/isel.c b/amd64/isel.c
index 6d4c87e..ff0968c 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -71,21 +71,21 @@ ascale(struct addr *addr, union ref a, union ref b)
}
static bool
-aadd(struct addr *addr, union ref r, bool rec)
+aadd(struct addr *addr, union ref r)
{
if (r.t == RTMP) {
struct instr *ins = &instrtab[r.i];
if (ins->op == Oadd) {
- if (!aadd(addr, ins->l, rec)) return 0;
- if (!aadd(addr, ins->r, rec)) return 0;
+ if (!aadd(addr, ins->l)) goto Ref;
+ if (!aadd(addr, ins->r)) goto Ref;
ins->skip = 1;
} else if (ins->op == Oshl) {
- if (!ascale(addr, ins->l, ins->r)) return 0;
+ if (!ascale(addr, ins->l, ins->r)) goto Ref;
ins->skip = 1;
- } else if (!rec && ins->op == Ocopy && ins->l.t == RMORE) {
+ } else if (ins->op == Ocopy && ins->l.t == RMORE) {
struct addr save = *addr, *addr2 = &addrht[ins->l.i];
- if ((!addr2->base.t || aadd(addr, addr2->base, 1))
+ if ((!addr2->base.t || aadd(addr, addr2->base))
&& acon(addr, mkintcon(KI4, addr2->disp))
&& (!addr2->index.t || ascale(addr, addr2->index, mkref(RICON, addr2->shift))))
{
@@ -94,6 +94,9 @@ aadd(struct addr *addr, union ref r, bool rec)
*addr = save;
goto Ref;
}
+ } else if (ins->op == Ocopy) {
+ if (!aadd(addr, ins->l)) goto Ref;
+ ins->skip = 1;
} else goto Ref;
} else if (iscon(r)) {
return acon(addr, r);
@@ -117,7 +120,7 @@ fuseaddr(struct function *fn, union ref *r)
if (r->t == RMORE) return 1;
if (r->t != RTMP) return 0;
- if (!aadd(&addr, *r, 0)) return 0;
+ if (!aadd(&addr, *r)) return 0;
*r = mkaddr(addr);
return 1;
@@ -272,7 +275,6 @@ amd64_isel(struct function *fn)
sel(fn, &instrtab[blk->ins.p[i]], blk, &i);
}
} while ((blk = blk->lnext) != fn->entry);
- fn->stksiz = alignup(fn->stksiz, 16);
if (ccopt.dbg.i) {
efmt("<< After isel >>\n");