lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


David Manura wrote:
> On Mon, Nov 2, 2009 at 6:39 PM, Mark Hamburg wrote:
> > To what extent did you change the instruction set v to what extent did you
> > change the encoding of the instruction set? (I'm thinking about whether a
> > bytecode translator is even reasonable to consider.)
> 
> Here's a test of running Lua 5.1 bytecodes on LuaJIT2 via LuLu [1]

Well, but that's a different issue. Bytecode->bytecode translation
ought to be a lot more efficient (if it worked) than running a
nested interpreter.

> (BTW, for whatever reason, a compiled life.lua runs under lulu under
> Lua 5.1 but not under LuaJIT2.)

Ok, four hours later and it has revealed three wildly different
bugs. This is really a goldmine of a test case, due to the unique
style this is written in. Thanks for digging it out!

Interim patches are attached. Now it works with life.lua. Here's
the runtime in seconds (lower is better):

           native   via LuLu
LJ2          1.1      7.9
LJ2 interp   1.4     28.9
Lua 5.1      2.2    114.5

Ok, so LJ2 doesn't like life.lua that much due to the NYI string
concatenations (60% interpreted, 35% GC, 5% compiled). That's why
the native speedup of 2x is kind of disappointing.

But more interesting is that LJ2 runs LuLu 14.5x faster and spends
almost 80% of the time in compiled code. That's despite that it
fails to compile quite a bit of it due to various NYI issues.

Generating good code for the main loop of an interpreter is known
to be one of the worst cases for a compiler. In this case the
inner loop has 38 comparisons in a row. The trace compiler turns
this into an interesting maze of traces (*), probably resembling a
decision tree -- nice. :-) This would work even better if the
comparisons were sorted by frequency (letting the compiler do that
is tricky).

(*) If anyone has some time left, here's an interesting project:
Write a compiler plugin that gathers the traces (start with a copy
of lib/v.lua) and convert the link info to graphviz input. This
should generate some pretty wallpapers (or a nice term paper).

--Mike
--- a/src/lj_opt_loop.c
+++ b/src/lj_opt_loop.c
@@ -286,7 +286,7 @@ static void loop_unroll(jit_State *J)
 	if (!irt_sametype(t, irr->t)) {
 	  if (irt_isnum(t) && irt_isinteger(irr->t))  /* Fix int->num case. */
 	    subst[ins] = tref_ref(emitir(IRTN(IR_TONUM), ref, 0));
-	  else
+	  else if (!(irt_isinteger(t) && irt_isinteger(irr->t)))
 	    lj_trace_err(J, LJ_TRERR_TYPEINS);
 	}
       }
--- a/src/lj_opt_mem.c
+++ b/src/lj_opt_mem.c
@@ -519,8 +519,8 @@ int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref)
     } else if (irt_isnil(store->t)) {  /* Must check any nil store. */
       IRRef skref = IR(store->op1)->op2;
       IRRef xkref = IR(xref)->op2;
-      /* Same key type MAY alias. */
-      if (irt_sametype(IR(skref)->t, IR(xkref)->t)) {
+      /* Same key type MAY alias. Need ALOAD check due to multiple int types. */
+      if (loadop == IR_ALOAD || irt_sametype(IR(skref)->t, IR(xkref)->t)) {
 	if (skref == xkref || !irref_isk(skref) || !irref_isk(xkref))
 	  return 0;  /* A nil store with same const key or var key MAY alias. */
 	/* Different const keys CANNOT alias. */
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -168,8 +168,8 @@ static int rec_objcmp(jit_State *J, TRef a, TRef b, cTValue *av, cTValue *bv)
 {
   int diff = !lj_obj_equal(av, bv);
   if (!tref_isk2(a, b)) {  /* Shortcut, also handles primitives. */
-    IRType ta = tref_type(a);
-    IRType tb = tref_type(b);
+    IRType ta = tref_isinteger(a) ? IRT_INT : tref_type(a);
+    IRType tb = tref_isinteger(b) ? IRT_INT : tref_type(b);
     if (ta != tb) {
       /* Widen mixed number/int comparisons to number/number comparison. */
       if (ta == IRT_INT && tb == IRT_NUM) {
@@ -447,7 +447,7 @@ static int rec_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm)
     mix.tab = lj_ir_ktab(J, mt);
     goto nocheck;
   }
-  ix->mt = mix.tab;
+  ix->mt = mt ? mix.tab : TREF_NIL;
   emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mix.tab, lj_ir_knull(J, IRT_TAB));
 nocheck:
   if (mt) {
@@ -1670,8 +1670,8 @@ void lj_record_ins(jit_State *J)
   case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
     /* Emit nothing for two numeric or string consts. */
     if (!(tref_isk2(ra,rc) && tref_isnumber_str(ra) && tref_isnumber_str(rc))) {
-      IRType ta = tref_type(ra);
-      IRType tc = tref_type(rc);
+      IRType ta = tref_isinteger(ra) ? IRT_INT : tref_type(ra);
+      IRType tc = tref_isinteger(rc) ? IRT_INT : tref_type(rc);
       int irop;
       if (ta != tc) {
 	/* Widen mixed number/int comparisons to number/number comparison. */
--- a/src/lj_tab.c
+++ b/src/lj_tab.c
@@ -191,8 +191,8 @@ GCtab *lj_tab_dup(lua_State *L, const GCtab *kt)
       Node *kn = &knode[i];
       Node *n = &node[i];
       Node *next = nextnode(kn);
-      copyTV(L, &n->val, &kn->val);
-      copyTV(L, &n->key, &kn->key);
+      /* Don't use copyTV here, since it asserts on a copy of a DEADKEY. */
+      n->val = kn->val; n->key = kn->key;
       setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
     }
   }