Explorar o código

FFI: Record 64 bit integer divide and modulo.

Mike Pall %!s(int64=14) %!d(string=hai) anos
pai
achega
a1e0f991d8
Modificáronse 6 ficheiros con 86 adicións e 34 borrados
  1. 26 5
      src/lj_asm.c
  2. 35 20
      src/lj_carith.c
  3. 4 0
      src/lj_carith.h
  4. 0 2
      src/lj_crecord.c
  5. 11 7
      src/lj_ir.h
  6. 10 0
      src/lj_opt_split.c

+ 26 - 5
src/lj_asm.c

@@ -3988,7 +3988,23 @@ static void asm_ir(ASMState *as, IRIns *ir)
     else
     else
       asm_intarith(as, ir, XOg_X_IMUL);
       asm_intarith(as, ir, XOg_X_IMUL);
     break;
     break;
-  case IR_DIV: asm_fparith(as, ir, XO_DIVSD); break;
+  case IR_DIV:
+#if LJ_64 && LJ_HASFFI
+    if (!irt_isnum(ir->t))
+      asm_arith64(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_divi64 :
+					     IRCALL_lj_carith_divu64);
+    else
+#endif
+      asm_fparith(as, ir, XO_DIVSD);
+    break;
+  case IR_MOD:
+#if LJ_64 && LJ_HASFFI
+    asm_arith64(as, ir, irt_isi64(ir->t) ? IRCALL_lj_carith_modi64 :
+					   IRCALL_lj_carith_modu64);
+#else
+    lua_assert(0);
+#endif
+    break;
 
 
   case IR_NEG:
   case IR_NEG:
     if (irt_isnum(ir->t))
     if (irt_isnum(ir->t))
@@ -4168,6 +4184,14 @@ static void asm_setup_regsp(ASMState *as, GCtrace *T)
 	as->modset = RSET_SCRATCH;
 	as->modset = RSET_SCRATCH;
       break;
       break;
     case IR_POWI:
     case IR_POWI:
+      if (irt_isnum(ir->t)) {
+	ir->prev = REGSP_HINT(RID_XMM0);
+	if (inloop)
+	  as->modset |= RSET_RANGE(RID_XMM0, RID_XMM1+1)|RID2RSET(RID_EAX);
+	continue;
+      }
+      /* fallthrough */
+    case IR_DIV: case IR_MOD:
 #if LJ_64 && LJ_HASFFI
 #if LJ_64 && LJ_HASFFI
       if (!irt_isnum(ir->t)) {
       if (!irt_isnum(ir->t)) {
 	ir->prev = REGSP_HINT(RID_RET);
 	ir->prev = REGSP_HINT(RID_RET);
@@ -4176,10 +4200,7 @@ static void asm_setup_regsp(ASMState *as, GCtrace *T)
 	continue;
 	continue;
       }
       }
 #endif
 #endif
-      ir->prev = REGSP_HINT(RID_XMM0);
-      if (inloop)
-	as->modset |= RSET_RANGE(RID_XMM0, RID_XMM1+1)|RID2RSET(RID_EAX);
-      continue;
+      break;
     case IR_FPMATH:
     case IR_FPMATH:
       if (ir->op2 == IRFPM_EXP2) {  /* May be joined to lj_vm_pow_sse. */
       if (ir->op2 == IRFPM_EXP2) {  /* May be joined to lj_vm_pow_sse. */
 	ir->prev = REGSP_HINT(RID_XMM0);
 	ir->prev = REGSP_HINT(RID_XMM0);

+ 35 - 20
src/lj_carith.c

@@ -148,21 +148,6 @@ static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
       setboolV(L->top-1,
       setboolV(L->top-1,
 	       id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
 	       id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
       return 1;
       return 1;
-    case MM_div: case MM_mod:
-      if (u1 == 0) {  /* Division by zero. */
-	if (u0 == 0)
-	  setnanV(L->top-1);
-	else if (id == CTID_INT64 && (int64_t)u0 < 0)
-	  setminfV(L->top-1);
-	else
-	  setpinfV(L->top-1);
-	return 1;
-      } else if (id == CTID_INT64 && (int64_t)u1 == -1 &&
-		 u0 == U64x(80000000,00000000)) {  /* MIN64 / -1. */
-	if (mm == MM_div) id = CTID_UINT64; else u0 = 0;
-	mm = MM_unm;  /* Result is 0x8000000000000000ULL or 0LL. */
-      }
-      break;
     default: break;
     default: break;
     }
     }
     cd = lj_cdata_new(cts, id, 8);
     cd = lj_cdata_new(cts, id, 8);
@@ -174,15 +159,15 @@ static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
     case MM_mul: *up = u0 * u1; break;
     case MM_mul: *up = u0 * u1; break;
     case MM_div:
     case MM_div:
       if (id == CTID_INT64)
       if (id == CTID_INT64)
-	*up = (uint64_t)((int64_t)u0 / (int64_t)u1);
+	*up = (uint64_t)lj_carith_divi64((int64_t)u0, (int64_t)u1);
       else
       else
-	*up = u0 / u1;
+	*up = lj_carith_divu64(u0, u1);
       break;
       break;
     case MM_mod:
     case MM_mod:
       if (id == CTID_INT64)
       if (id == CTID_INT64)
-	*up = (uint64_t)((int64_t)u0 % (int64_t)u1);
+	*up = (uint64_t)lj_carith_modi64((int64_t)u0, (int64_t)u1);
       else
       else
-	*up = u0 % u1;
+	*up = lj_carith_modu64(u0, u1);
       break;
       break;
     case MM_pow:
     case MM_pow:
       if (id == CTID_INT64)
       if (id == CTID_INT64)
@@ -231,13 +216,43 @@ int lj_carith_op(lua_State *L, MMS mm)
 /* -- 64 bit integer arithmetic helpers ----------------------------------- */
 /* -- 64 bit integer arithmetic helpers ----------------------------------- */
 
 
 #if LJ_32
 #if LJ_32
-/* Signed/unsigned 64 bit multiply. */
+/* Signed/unsigned 64 bit multiplication. */
 int64_t lj_carith_mul64(int64_t a, int64_t b)
 int64_t lj_carith_mul64(int64_t a, int64_t b)
 {
 {
   return a * b;
   return a * b;
 }
 }
 #endif
 #endif
 
 
+/* Unsigned 64 bit division. */
+uint64_t lj_carith_divu64(uint64_t a, uint64_t b)
+{
+  if (b == 0) return U64x(80000000,00000000);
+  return a / b;
+}
+
+/* Signed 64 bit division. */
+int64_t lj_carith_divi64(int64_t a, int64_t b)
+{
+  if (b == 0 || (a == (int64_t)U64x(80000000,00000000) && b == -1))
+    return U64x(80000000,00000000);
+  return a / b;
+}
+
+/* Unsigned 64 bit modulo. */
+uint64_t lj_carith_modu64(uint64_t a, uint64_t b)
+{
+  if (b == 0) return U64x(80000000,00000000);
+  return a % b;
+}
+
+/* Signed 64 bit modulo. */
+int64_t lj_carith_modi64(int64_t a, int64_t b)
+{
+  if (b == 0) return U64x(80000000,00000000);
+  if (a == (int64_t)U64x(80000000,00000000) && b == -1) return 0;
+  return a % b;
+}
+
 /* Unsigned 64 bit x^k. */
 /* Unsigned 64 bit x^k. */
 uint64_t lj_carith_powu64(uint64_t x, uint64_t k)
 uint64_t lj_carith_powu64(uint64_t x, uint64_t k)
 {
 {

+ 4 - 0
src/lj_carith.h

@@ -15,6 +15,10 @@ LJ_FUNC int lj_carith_op(lua_State *L, MMS mm);
 #if LJ_32
 #if LJ_32
 LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k);
 LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k);
 #endif
 #endif
+LJ_FUNC uint64_t lj_carith_divu64(uint64_t a, uint64_t b);
+LJ_FUNC int64_t lj_carith_divi64(int64_t a, int64_t b);
+LJ_FUNC uint64_t lj_carith_modu64(uint64_t a, uint64_t b);
+LJ_FUNC int64_t lj_carith_modi64(int64_t a, int64_t b);
 LJ_FUNC uint64_t lj_carith_powu64(uint64_t x, uint64_t k);
 LJ_FUNC uint64_t lj_carith_powu64(uint64_t x, uint64_t k);
 LJ_FUNC int64_t lj_carith_powi64(int64_t x, int64_t k);
 LJ_FUNC int64_t lj_carith_powi64(int64_t x, int64_t k);
 
 

+ 0 - 2
src/lj_crecord.c

@@ -700,8 +700,6 @@ static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
       J->postproc = LJ_POST_FIXGUARD;
       J->postproc = LJ_POST_FIXGUARD;
       return TREF_TRUE;
       return TREF_TRUE;
     } else {
     } else {
-      if (mm == MM_div || mm == MM_mod)
-	return 0;  /* NYI: integer div, mod. */
       tr = emitir(IRT(mm+(int)IR_ADD-(int)MM_add, dt), sp[0], sp[1]);
       tr = emitir(IRT(mm+(int)IR_ADD-(int)MM_add, dt), sp[0], sp[1]);
     }
     }
     dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, id), TREF_NIL);
     dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, id), TREF_NIL);

+ 11 - 7
src/lj_ir.h

@@ -10,7 +10,7 @@
 
 
 /* -- IR instructions ----------------------------------------------------- */
 /* -- IR instructions ----------------------------------------------------- */
 
 
-/* IR instruction definition. Order matters, see below. */
+/* IR instruction definition. Order matters, see below. ORDER IR */
 #define IRDEF(_) \
 #define IRDEF(_) \
   /* Guarded assertions. */ \
   /* Guarded assertions. */ \
   /* Must be properly aligned to flip opposites (^1) and (un)ordered (^4). */ \
   /* Must be properly aligned to flip opposites (^1) and (un)ordered (^4). */ \
@@ -61,21 +61,21 @@
   _(BROL,	N , ref, ref) \
   _(BROL,	N , ref, ref) \
   _(BROR,	N , ref, ref) \
   _(BROR,	N , ref, ref) \
   \
   \
-  /* Arithmetic ops. ORDER ARITH (FPMATH/POWI take the space for MOD/POW). */ \
+  /* Arithmetic ops. ORDER ARITH */ \
   _(ADD,	C , ref, ref) \
   _(ADD,	C , ref, ref) \
   _(SUB,	N , ref, ref) \
   _(SUB,	N , ref, ref) \
   _(MUL,	C , ref, ref) \
   _(MUL,	C , ref, ref) \
   _(DIV,	N , ref, ref) \
   _(DIV,	N , ref, ref) \
-  \
-  _(FPMATH,	N , ref, lit) \
+  _(MOD,	N , ref, ref) \
   _(POWI,	N , ref, ref) \
   _(POWI,	N , ref, ref) \
-  \
   _(NEG,	N , ref, ref) \
   _(NEG,	N , ref, ref) \
+  \
   _(ABS,	N , ref, ref) \
   _(ABS,	N , ref, ref) \
   _(ATAN2,	N , ref, ref) \
   _(ATAN2,	N , ref, ref) \
   _(LDEXP,	N , ref, ref) \
   _(LDEXP,	N , ref, ref) \
   _(MIN,	C , ref, ref) \
   _(MIN,	C , ref, ref) \
   _(MAX,	C , ref, ref) \
   _(MAX,	C , ref, ref) \
+  _(FPMATH,	N , ref, lit) \
   \
   \
   /* Overflow-checking arithmetic ops. */ \
   /* Overflow-checking arithmetic ops. */ \
   _(ADDOV,	C , ref, ref) \
   _(ADDOV,	C , ref, ref) \
@@ -266,6 +266,10 @@ typedef struct CCallInfo {
 #endif
 #endif
 #define IRCALLDEF_FFI(_) \
 #define IRCALLDEF_FFI(_) \
   IRCALLDEF_FFI32(_) \
   IRCALLDEF_FFI32(_) \
+  _(lj_carith_divi64,	ARG2_64,   N, I64, CCI_NOFPRCLOBBER) \
+  _(lj_carith_divu64,	ARG2_64,   N, U64, CCI_NOFPRCLOBBER) \
+  _(lj_carith_modi64,	ARG2_64,   N, I64, CCI_NOFPRCLOBBER) \
+  _(lj_carith_modu64,	ARG2_64,   N, U64, CCI_NOFPRCLOBBER) \
   _(lj_carith_powi64,	ARG2_64,   N, I64, CCI_NOFPRCLOBBER) \
   _(lj_carith_powi64,	ARG2_64,   N, I64, CCI_NOFPRCLOBBER) \
   _(lj_carith_powu64,	ARG2_64,   N, U64, CCI_NOFPRCLOBBER)
   _(lj_carith_powu64,	ARG2_64,   N, U64, CCI_NOFPRCLOBBER)
 #else
 #else
@@ -584,12 +588,12 @@ typedef union IRIns {
 #define ir_kptr(ir) \
 #define ir_kptr(ir) \
   check_exp((ir)->o == IR_KPTR || (ir)->o == IR_KKPTR, mref((ir)->ptr, void))
   check_exp((ir)->o == IR_KPTR || (ir)->o == IR_KKPTR, mref((ir)->ptr, void))
 
 
-LJ_STATIC_ASSERT((int)IRT_GUARD == (int)IRM_W);
-
 /* A store or any other op with a non-weak guard has a side-effect. */
 /* A store or any other op with a non-weak guard has a side-effect. */
 static LJ_AINLINE int ir_sideeff(IRIns *ir)
 static LJ_AINLINE int ir_sideeff(IRIns *ir)
 {
 {
   return (((ir->t.irt | ~IRT_GUARD) & lj_ir_mode[ir->o]) >= IRM_S);
   return (((ir->t.irt | ~IRT_GUARD) & lj_ir_mode[ir->o]) >= IRM_S);
 }
 }
 
 
+LJ_STATIC_ASSERT((int)IRT_GUARD == (int)IRM_W);
+
 #endif
 #endif

+ 10 - 0
src/lj_opt_split.c

@@ -197,6 +197,16 @@ static void split_ir(jit_State *J)
       case IR_MUL:
       case IR_MUL:
 	hi = split_call64(J, hisubst, oir, ir, IRCALL_lj_carith_mul64);
 	hi = split_call64(J, hisubst, oir, ir, IRCALL_lj_carith_mul64);
 	break;
 	break;
+      case IR_DIV:
+	hi = split_call64(J, hisubst, oir, ir,
+			  irt_isi64(ir->t) ? IRCALL_lj_carith_divi64 :
+					     IRCALL_lj_carith_divu64);
+	break;
+      case IR_MOD:
+	hi = split_call64(J, hisubst, oir, ir,
+			  irt_isi64(ir->t) ? IRCALL_lj_carith_modi64 :
+					     IRCALL_lj_carith_modu64);
+	break;
       case IR_POWI:
       case IR_POWI:
 	hi = split_call64(J, hisubst, oir, ir,
 	hi = split_call64(J, hisubst, oir, ir,
 			  irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 :
 			  irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 :