2
0
Эх сурвалжийг харах

x86: Fix register allocation for calls returning register pair.

Mike Pall 13 жил өмнө
parent
commit
0ecdff43e8

+ 5 - 1
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);

+ 6 - 2
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. */

+ 1 - 0
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,