diff options
| author | 2023-06-14 15:05:43 +0200 | |
|---|---|---|
| committer | 2023-06-14 15:05:43 +0200 | |
| commit | 782d4e9df0363ca9f64d8b92a3d6952d552f13a5 (patch) | |
| tree | 8c71e107a8c0b54f53c2c94d053ad4cc1b7a441d /amd64 | |
| parent | 8d8cf6584bf4081b54cd91fcaa42578cbd794440 (diff) | |
add spilling for function calls, misc fixes
Diffstat (limited to 'amd64')
| -rw-r--r-- | amd64/emit.c | 24 | ||||
| -rw-r--r-- | amd64/isel.c | 18 |
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"); |