From 0ecdff43e80dcd1d489c3daca0077dbfae9042b6 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 27 Sep 2012 14:16:18 +0200 Subject: [PATCH] x86: Fix register allocation for calls returning register pair. --- src/lj_asm.c | 6 +++++- src/lj_asm_x86.h | 8 ++++++-- src/lj_target_x86.h | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lj_asm.c b/src/lj_asm.c index 79097759..6afc70a0 100644 --- a/src/lj_asm.c +++ b/src/lj_asm.c @@ -719,7 +719,7 @@ static void ra_leftov(ASMState *as, Reg dest, IRRef lref) } #endif -#if !LJ_TARGET_X86ORX64 +#if !LJ_64 /* Force a RID_RETLO/RID_RETHI destination register pair (marked as free). */ static void ra_destpair(ASMState *as, IRIns *ir) { @@ -747,9 +747,13 @@ static void ra_destpair(ASMState *as, IRIns *ir) /* Check for conflicts and shuffle the registers as needed. */ if (destlo == RID_RETHI) { if (desthi == RID_RETLO) { +#if LJ_TARGET_X86 + *--as->mcp = XI_XCHGa + RID_RETHI; +#else emit_movrr(as, ir, RID_RETHI, RID_TMP); emit_movrr(as, ir, RID_RETLO, RID_RETHI); emit_movrr(as, ir, RID_TMP, RID_RETLO); +#endif } else { emit_movrr(as, ir, RID_RETHI, RID_RETLO); if (desthi != RID_RETHI) emit_movrr(as, ir, desthi, RID_RETHI); diff --git a/src/lj_asm_x86.h b/src/lj_asm_x86.h index da4cf7e2..7288d72a 100644 --- a/src/lj_asm_x86.h +++ b/src/lj_asm_x86.h @@ -510,10 +510,13 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) { RegSet drop = RSET_SCRATCH; + int hiop = (LJ_32 && (ir+1)->o == IR_HIOP); if ((ci->flags & CCI_NOFPRCLOBBER)) drop &= ~RSET_FPR; if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); /* Dest reg handled below. */ + if (hiop && ra_hasreg((ir+1)->r)) + rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ ra_evictset(as, drop); /* Evictions must be performed first. */ if (ra_used(ir)) { if (irt_isfp(ir->t)) { @@ -547,6 +550,8 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) irt_isnum(ir->t) ? XOg_FSTPq : XOg_FSTPd, RID_ESP, ofs); } #endif + } else if (hiop) { + ra_destpair(as, ir); } else { lua_assert(!irt_ispri(ir->t)); ra_destreg(as, ir, RID_RET); @@ -2288,9 +2293,8 @@ static void asm_hiop(ASMState *as, IRIns *ir) } case IR_CALLN: case IR_CALLXS: - ra_destreg(as, ir, RID_RETHI); if (!uselo) - ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark call as used. */ + ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ break; case IR_CNEWI: /* Nothing to do here. Handled by CNEWI itself. */ diff --git a/src/lj_target_x86.h b/src/lj_target_x86.h index cc15490b..c718bdb5 100644 --- a/src/lj_target_x86.h +++ b/src/lj_target_x86.h @@ -191,6 +191,7 @@ typedef struct { typedef enum { /* Fixed length opcodes. XI_* prefix. */ XI_NOP = 0x90, + XI_XCHGa = 0x90, XI_CALL = 0xe8, XI_JMP = 0xe9, XI_JMPs = 0xeb,