]> git.ipfire.org Git - thirdparty/LuaJIT.git/commitdiff
Refactoring of conversion ops, part 1: add IR_CONV.
authorMike Pall <mike>
Tue, 28 Dec 2010 21:05:40 +0000 (22:05 +0100)
committerMike Pall <mike>
Wed, 29 Dec 2010 23:35:32 +0000 (00:35 +0100)
lib/dump.lua
src/lj_asm.c
src/lj_ir.h
src/lj_opt_fold.c
src/lj_target_x86.h

index 08df4e3f3b4a5d3666548c93c7830de458fa84a3..3436536021bfbc6bcff7002ed139b1ff05d2439c 100644 (file)
@@ -236,6 +236,15 @@ local litname = {
     return s
   end}),
   ["XLOAD "] = { [0] = "", "R", "U", "RU", },
+  ["CONV  "] = setmetatable({}, { __index = function(t, mode)
+    local s = irtype[band(mode, 31)]
+    if band(mode, 0x100) ~= 0 then s = s.." trunc"
+    elseif band(mode, 0x200) ~= 0 then s = s.." sext" end
+    local c = shr(mode, 10)
+    if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end
+    t[mode] = s
+    return s
+  end}),
   ["TOINT "] = tointname,
   ["TOI64 "] = tointname,
   ["FLOAD "] = vmdef.irfield,
index 687363e15fa8935f6591ab971dc2eaa0f5e1e698..d75858f84ebaabdd696e8c0934e9542d895ae84e 100644 (file)
@@ -1654,6 +1654,99 @@ static void asm_toi64(ASMState *as, IRIns *ir)
   }
 }
 
+static void asm_conv(ASMState *as, IRIns *ir)
+{
+  IRType st = (IRType)(ir->op2 & 0x1f);
+  int st64 = (st == IRT_I64 || st == IRT_U64 || (LJ_64 && st == IRT_P64));
+  int stfp = (st == IRT_NUM || st == IRT_FLOAT);
+  IRRef lref = ir->op1;
+  lua_assert(irt_type(ir->t) != st);
+  if (irt_isnum(ir->t) || irt_isfloat(ir->t)) {
+    Reg dest = ra_dest(as, ir, RSET_FPR);
+    if (stfp) {  /* FP to FP conversion. */
+      Reg left = asm_fuseload(as, lref, RSET_FPR);
+      emit_mrm(as, st == IRT_NUM ? XO_CVTSD2SS : XO_CVTSS2SD, dest, left);
+      if (left == dest) return;  /* Avoid the XO_XORPS. */
+#if LJ_32
+    } else if (st >= IRT_U32) {
+      /* NYI: 64 bit integer or uint32_t to number conversion. */
+      setintV(&as->J->errinfo, ir->o);
+      lj_trace_err_info(as->J, LJ_TRERR_NYIIR);
+      return;
+#endif
+    } else {  /* Integer to FP conversion. */
+      Reg left = (LJ_64 && st == IRT_U32) ? ra_allocref(as, lref, RSET_GPR) :
+                                           asm_fuseload(as, lref, RSET_GPR);
+      emit_mrm(as, irt_isnum(ir->t) ? XO_CVTSI2SD : XO_CVTSI2SS,
+              dest|((LJ_64 && (st64 || st == IRT_U32)) ? REX_64 : 0), left);
+    }
+    if (!(as->flags & JIT_F_SPLIT_XMM))
+      emit_rr(as, XO_XORPS, dest, dest);  /* Avoid partial register stall. */
+  } else if (stfp) {  /* FP to integer conversion. */
+    if (irt_isguard(ir->t)) {
+      lua_assert(!irt_is64(ir->t));  /* No support for checked 64 bit conv. */
+      asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR));
+#if LJ_32
+    } else if (irt_isi64(ir->t) || irt_isu64(ir->t) || irt_isu32(ir->t)) {
+      /* NYI: number to 64 bit integer or uint32_t conversion. */
+      setintV(&as->J->errinfo, ir->o);
+      lj_trace_err_info(as->J, LJ_TRERR_NYIIR);
+#else
+    } else if (irt_isu64(ir->t)) {
+      /* NYI: number to uint64_t conversion. */
+      setintV(&as->J->errinfo, ir->o);
+      lj_trace_err_info(as->J, LJ_TRERR_NYIIR);
+#endif
+    } else {
+      Reg dest = ra_dest(as, ir, RSET_GPR);
+      Reg left = asm_fuseload(as, ir->op1, RSET_FPR);
+      x86Op op = st == IRT_NUM ?
+                ((ir->op2 & IRCONV_TRUNC) ? XO_CVTTSD2SI : XO_CVTSD2SI) :
+                ((ir->op2 & IRCONV_TRUNC) ? XO_CVTTSS2SI : XO_CVTSS2SI);
+      if (LJ_64 && irt_isu32(ir->t))
+       emit_rr(as, XO_MOV, dest, dest);  /* Zero upper 32 bits. */
+      emit_mrm(as, op,
+              dest|((LJ_64 &&
+                     (irt_is64(ir->t) || irt_isu32(ir->t))) ? REX_64 : 0),
+              left);
+    }
+  } else {  /* Integer to integer conversion. Only need 32/64 bit variants. */
+    if (irt_is64(ir->t)) {
+#if LJ_32
+      /* NYI: conversion to 64 bit integers. */
+      setintV(&as->J->errinfo, ir->o);
+      lj_trace_err_info(as->J, LJ_TRERR_NYIIR);
+#else
+      Reg dest = ra_dest(as, ir, RSET_GPR);
+      if (st64 || !(ir->op2 & IRCONV_SEXT)) {
+       /* 64/64 bit no-op (cast) or 32 to 64 bit zero extension. */
+       ra_left(as, dest, lref);  /* Do nothing, but may need to move regs. */
+      } else {  /* 32 to 64 bit sign extension. */
+       Reg left = asm_fuseload(as, lref, RSET_GPR);
+       emit_mrm(as, XO_MOVSXd, dest|REX_64, left);
+      }
+#endif
+    } else {
+      Reg dest = ra_dest(as, ir, RSET_GPR);
+      if (st64) {
+#if LJ_32
+       /* NYI: conversion from 64 bit integers. */
+       setintV(&as->J->errinfo, ir->o);
+       lj_trace_err_info(as->J, LJ_TRERR_NYIIR);
+#else
+       Reg left = asm_fuseload(as, lref, RSET_GPR);
+       /* This is either a 32 bit reg/reg mov which zeroes the hi-32 bits
+       ** or a load of the lower 32 bits from a 64 bit address.
+       */
+       emit_mrm(as, XO_MOV, dest, left);
+#endif
+      } else {  /* 32/32 bit no-op (cast). */
+       ra_left(as, dest, lref);  /* Do nothing, but may need to move regs. */
+      }
+    }
+  }
+}
+
 static void asm_strto(ASMState *as, IRIns *ir)
 {
   /* Force a spill slot for the destination register (if any). */
@@ -3666,6 +3759,7 @@ static void asm_ir(ASMState *as, IRIns *ir)
     break;
   case IR_TOBIT: asm_tobit(as, ir); break;
   case IR_TOI64: asm_toi64(as, ir); break;
+  case IR_CONV: asm_conv(as, ir); break;
   case IR_TOSTR: asm_tostr(as, ir); break;
   case IR_STRTO: asm_strto(as, ir); break;
 
@@ -3808,7 +3902,7 @@ static void asm_setup_regsp(ASMState *as, GCtrace *T)
       }
       break;
     /* Do not propagate hints across type conversions. */
-    case IR_TONUM: case IR_TOINT: case IR_TOBIT:
+    case IR_CONV: case IR_TONUM: case IR_TOINT: case IR_TOBIT:
       break;
     default:
       /* Propagate hints across likely 'op reg, imm' or 'op reg'. */
index bdedaddd45966749ff97cffd754cc022a0289098..8154949c7f794dc2012d990945ea01d1e9439449 100644 (file)
   _(OBAR,      S , ref, ref) \
   \
   /* Type conversions. */ \
+  _(CONV,      N , ref, lit) \
   _(TONUM,     N , ref, ___) \
   _(TOINT,     N , ref, lit) \
   _(TOBIT,     N , ref, ref) \
@@ -218,6 +219,16 @@ IRFLDEF(FLENUM)
 #define IRTOINT_TRUNCI64       5       /* Truncate number to int64_t. */
 #define IRTOINT_TOBIT          6       /* Cache only: TOBIT conversion. */
 
+/* CONV mode, stored in op2. Lowest 8 bits is the IRType of the source. */
+#define IRCONV_TRUNC           0x100   /* Truncate number to integer. */
+#define IRCONV_SEXT            0x200   /* Sign-extend integer to integer. */
+#define IRCONV_CSH             10
+/* Number to integer conversion mode. Ordered by strength of the checks. */
+#define IRCONV_TOBIT  (0<<IRCONV_CSH)  /* None. Cache only: TOBIT conv. */
+#define IRCONV_ANY    (1<<IRCONV_CSH)  /* Any FP number is ok. */
+#define IRCONV_INDEX  (2<<IRCONV_CSH)  /* Check + special backprop rules. */
+#define IRCONV_CHECK  (3<<IRCONV_CSH)  /* Number checked for integerness. */
+
 /* C call info for CALL* instructions. */
 typedef struct CCallInfo {
   ASMFunction func;            /* Function pointer. */
index d2c20546642d90a91d45ebc5763f295f13bd9cb0..8f05e7c8473cb2e2243bf248481ada950d6f9955 100644 (file)
@@ -771,6 +771,28 @@ LJFOLDF(cse_toint)
   return EMITFOLD;  /* No fallthrough to regular CSE. */
 }
 
+/* Special CSE rule for CONV. */
+LJFOLD(CONV any any)
+LJFOLDF(cse_conv)
+{
+  if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) {
+    IRRef op1 = fins->op1, op2 = (fins->op2 & IRCONV_MODEMASK);
+    uint8_t guard = irt_isguard(fins->t);
+    IRRef ref = J->chain[IR_CONV];
+    while (ref > op1) {
+      IRIns *ir = IR(ref);
+      /* CSE also depends on the target type!
+      ** OTOH commoning with stronger checks is ok, too.
+      */
+      if (ir->op1 == op1 && irt_sametype(ir->t, fins->t) &&
+         (ir->op2 & IRCONV_MODEMASK) == op2 && irt_isguard(ir->t) >= guard)
+       return ref;
+      ref = ir->prev;
+    }
+  }
+  return EMITFOLD;  /* No fallthrough to regular CSE. */
+}
+
 /* -- Strength reduction of widening -------------------------------------- */
 
 LJFOLD(TOI64 any 3)  /* IRTOINT_ZEXT64 */
index bf58d67c3221b3f3205698cd826ff8bc7a4e6037..67590eb325c998c4f9e9d6024fd0185586a087a0 100644 (file)
@@ -251,6 +251,11 @@ typedef enum {
   XO_CVTSI2SD =        XO_f20f(2a),
   XO_CVTSD2SI =        XO_f20f(2d),
   XO_CVTTSD2SI=        XO_f20f(2c),
+  XO_CVTSI2SS =        XO_f30f(2a),
+  XO_CVTSS2SI =        XO_f30f(2d),
+  XO_CVTTSS2SI=        XO_f30f(2c),
+  XO_CVTSS2SD =        XO_f30f(5a),
+  XO_CVTSD2SS =        XO_f20f(5a),
   XO_MOVD =    XO_660f(6e),
   XO_MOVDto =  XO_660f(7e),