Explorar o código

Add "context" test

Hugo Musso Gualandi %!s(int64=3) %!d(string=hai) anos
pai
achega
f2a33b7e8f
Modificáronse 4 ficheiros con 805 adicións e 3 borrados
  1. 1 0
      .gitignore
  2. 1 1
      scripts/bench-run.lua
  3. 12 2
      src/Makefile
  4. 791 0
      src/luaot_context.c

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@ src/luac
 src/luaot
 src/luaot-trampoline
 src/luaot-functions
+src/luaot-context
 
 experiments/*.c
 experiments/*.so

+ 1 - 1
scripts/bench-run.lua

@@ -45,7 +45,7 @@ local impls = {
     { name = "aot", suffix = "_aot", interpreter = "../src/lua",    compile = "../src/luaot"           },
     { name = "trm", suffix = "_trm", interpreter = "../src/lua",    compile = "../src/luaot-trampoline"},
     { name = "fun", suffix = "_fun", interpreter = "../src/lua",    compile = "../src/luaot-functions" },
-    --{ name = "ctx", suffix = "_ctx", interpreter = "../src/lua",    compile = "../src/luaot-context" },
+    { name = "ctx", suffix = "_ctx", interpreter = "../src/lua",    compile = "../src/luaot-context"   },
 }
 
 --

+ 12 - 2
src/Makefile

@@ -52,8 +52,11 @@ AOT2_O=	luaot-trampoline.o
 AOT3_T=	luaot-functions
 AOT3_O=	luaot-functions.o
 
-ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O) $(AOT_O) $(AOT2_O) $(AOT3_O)
-ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(AOT_T) $(AOT2_T) $(AOT3_T)
+AOT4_T=	luaot-context
+AOT4_O=	luaot-context.o
+
+ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O) $(AOT_O) $(AOT2_O) $(AOT3_O) $(AOT4_O)
+ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(AOT_T) $(AOT2_T) $(AOT3_T) $(AOT4_T)
 ALL_A= $(LUA_A)
 
 # Targets start here.
@@ -84,6 +87,9 @@ $(AOT2_T): $(AOT2_O) $(LUA_A)
 $(AOT3_T): $(AOT3_O) $(LUA_A)
 	$(CC) -o $@ $(LDFLAGS) $(AOT3_O) $(LUA_A) $(LIBS)
 
+$(AOT4_T): $(AOT4_O) $(LUA_A)
+	$(CC) -o $@ $(LDFLAGS) $(AOT4_O) $(LUA_A) $(LIBS)
+
 test:
 	./$(LUA_T) -v
 
@@ -185,6 +191,10 @@ luaot-functions.o: luaot.c luaot_functions.c \
  lua.h lauxlib.h ldebug.h lobject.h lopcodes.h lopnames.h lstate.h lundump.h
 	$(CC) $(CFLAGS) -c $< -o $@ -DLUAOT_USE_FUNCTIONS
 
+luaot-context.o: luaot.c luaot_context.c \
+ lua.h lauxlib.h ldebug.h lobject.h lopcodes.h lopnames.h lstate.h lundump.h
+	$(CC) $(CFLAGS) -c $< -o $@ -DLUAOT_USE_FUNCTIONS
+	
 # DO NOT DELETE
 
 lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \

+ 791 - 0
src/luaot_context.c

@@ -0,0 +1,791 @@
+
+//
+// The compiler part of the compiler
+// ---------------------------------
+// This is the version that ports the inner interpreter to using a context struct.
+// It's the function port, without the functions.
+
+static
+int jump_target(Proto *f, int pc)
+{
+    Instruction instr = f->code[pc];
+    if (GET_OPCODE(instr) != OP_JMP) { fatal_error("instruction is not a jump"); }
+    return (pc+1) + GETARG_sJ(instr);
+}
+
+static
+void println_goto_ret()
+{
+    // This is the piece of code that is after the "ret" label.
+    // It should be used in the places that do "goto ret;"
+    println("    if (ctx->ci->callstatus & CIST_FRESH)");
+    println("        return NULL;  /* end this frame */");
+    println("    else {");
+    println("        ctx->ci = ctx->ci->previous;");
+    println("        return ctx->ci;");
+    println("    }");
+}
+
+///
+static
+void create_function(Proto *f)
+{
+    int func_id = nfunctions++;
+
+    println("// source = %s", getstr(f->source));
+    if (f->linedefined == 0) {
+        println("// main function");
+    } else {
+        println("// lines: %d - %d", f->linedefined, f->lastlinedefined);
+    }
+
+    println("static");
+    println("CallInfo *magic_implementation_%02d(lua_State *L, CallInfo *ci0)", func_id);
+    println("{");
+    println("  LuaotExecuteState ctx_;");
+    println("  LuaotExecuteState *ctx = &ctx_;");
+    printnl();    
+    println("  ctx->ci = ci0;");
+    println("  ctx->trap = L->hookmask;");
+    println("  ctx->cl = clLvalue(s2v(ctx->ci->func));");
+    println("  ctx->k = ctx->cl->p->k;");
+    println("  const Instruction *pc = ctx->ci->u.l.savedpc;");
+    println("  if (l_unlikely(ctx->trap)) {");
+    println("    if (pc == ctx->cl->p->code) {  /* first instruction (not resuming)? */");
+    println("      if (ctx->cl->p->is_vararg)");
+    println("        ctx->trap = 0;  /* hooks will start after VARARGPREP instruction */");
+    println("      else  /* check 'call' hook */");
+    println("        luaD_hookcall(L, ctx->ci);");
+    println("    }");
+    println("    ctx->ci->u.l.trap = 1;  /* assume trap is on, for now */");
+    println("  }");
+    println("  ctx->base = ctx->ci->func + 1;");
+    println("  /* main loop of interpreter */");
+    println("  Instruction *code = ctx->cl->p->code;"); // (!!!)
+    println("  Instruction i;");
+    println("  StkId ra;");
+    printnl();
+
+    // If we are returning from another function, or resuming a coroutine,
+    // jump back to where left.
+    println("  switch (pc - code) {");
+    for (int pc = 0; pc < f->sizecode; pc++) {
+        println("    case %d: goto label_%02d;", pc, pc);
+    }
+    println("  }");
+    printnl();
+
+    for (int pc = 0; pc < f->sizecode; pc++) {
+        Instruction instr = f->code[pc];
+        OpCode op = GET_OPCODE(instr);
+
+        luaot_PrintOpcodeComment(f, pc);
+
+        int next = pc + 1;
+        println("  #undef  LUAOT_NEXT_JUMP");
+        if (next < f->sizecode && GET_OPCODE(f->code[next]) == OP_JMP) {
+            println("  #define LUAOT_NEXT_JUMP label_%02d", jump_target(f, next));
+        }
+
+        int skip1 = pc + 2;
+        println("  #undef  LUAOT_SKIP1");
+        if (skip1 < f->sizecode) {
+            println("  #define LUAOT_SKIP1 label_%02d", skip1);
+        }
+
+        println("  label_%02d: {", pc);
+        // While an instruction is executing, the program counter typically
+        // points towards the next instruction. There are some corner cases
+        // where the program counter getss adjusted mid-instruction, but I
+        // am not breaking anything because of those...
+        println("  pc = (code + %d);", pc+1);
+
+        println("    aot_vmfetch(0x%08x);", instr);
+
+        switch (op) {
+            case OP_MOVE: {
+                println("    setobjs2s(L, ra, RB(i));");
+                break;
+            }
+            case OP_LOADI: {
+                println("    lua_Integer b = GETARG_sBx(i);");
+                println("    setivalue(s2v(ra), b);");
+                break;
+            }
+            case OP_LOADF: {
+                println("    int b = GETARG_sBx(i);");
+                println("    setfltvalue(s2v(ra), cast_num(b));");
+                break;
+            }
+            case OP_LOADK: {
+                println("    TValue *rb = ctx->k + GETARG_Bx(i);");
+                println("    setobj2s(L, ra, rb);");
+                break;
+            }
+            case OP_LOADKX: {
+                println("    TValue *rb;");
+                println("    rb = ctx->k + GETARG_Ax(0x%08x);", f->code[pc+1]);
+                println("    setobj2s(L, ra, rb);");
+                println("    goto LUAOT_SKIP1;"); //(!)
+                break;
+            }
+            case OP_LOADFALSE: {
+                println("    setbfvalue(s2v(ra));");
+                break;
+            }
+            case OP_LFALSESKIP: {
+                println("    setbfvalue(s2v(ra));");
+                println("    goto LUAOT_SKIP1;"); //(!)
+                break;
+            }
+            case OP_LOADTRUE: {
+                println("    setbtvalue(s2v(ra));");
+                break;
+            }
+            case OP_LOADNIL: {
+                println("    int b = GETARG_B(i);");
+                println("    do {");
+                println("      setnilvalue(s2v(ra++));");
+                println("    } while (b--);");
+                break;
+            }
+            case OP_GETUPVAL: {
+                println("    int b = GETARG_B(i);");
+                println("    setobj2s(L, ra, ctx->cl->upvals[b]->v);");
+                break;
+            }
+            case OP_SETUPVAL: {
+                println("    UpVal *uv = ctx->cl->upvals[GETARG_B(i)];");
+                println("    setobj(L, uv->v, s2v(ra));");
+                println("    luaC_barrier(L, uv, s2v(ra));");
+                break;
+            }
+            case OP_GETTABUP: {
+                println("    const TValue *slot;");
+                println("    TValue *upval = ctx->cl->upvals[GETARG_B(i)]->v;");
+                println("    TValue *rc = KC(i);");
+                println("    TString *key = tsvalue(rc);  /* key must be a string */");
+                println("    if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {");
+                println("      setobj2s(L, ra, slot);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishget(L, upval, rc, ra, slot));");
+                break;
+            }
+            case OP_GETTABLE: {
+                println("    const TValue *slot;");
+                println("    TValue *rb = vRB(i);");
+                println("    TValue *rc = vRC(i);");
+                println("    lua_Unsigned n;");
+                println("    if (ttisinteger(rc)  /* fast track for integers? */");
+                println("        ? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot))");
+                println("        : luaV_fastget(L, rb, rc, slot, luaH_get)) {");
+                println("      setobj2s(L, ra, slot);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishget(L, rb, rc, ra, slot));");
+                break;
+            }
+            case OP_GETI: {
+                println("    const TValue *slot;");
+                println("    TValue *rb = vRB(i);");
+                println("    int c = GETARG_C(i);");
+                println("    if (luaV_fastgeti(L, rb, c, slot)) {");
+                println("      setobj2s(L, ra, slot);");
+                println("    }");
+                println("    else {");
+                println("      TValue key;");
+                println("      setivalue(&key, c);");
+                println("      Protect(luaV_finishget(L, rb, &key, ra, slot));");
+                println("    }");
+                break;
+            }
+            case OP_GETFIELD: {
+                println("    const TValue *slot;");
+                println("    TValue *rb = vRB(i);");
+                println("    TValue *rc = KC(i);");
+                println("    TString *key = tsvalue(rc);  /* key must be a string */");
+                println("    if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) {");
+                println("      setobj2s(L, ra, slot);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishget(L, rb, rc, ra, slot));");
+                break;
+            }
+            case OP_SETTABUP: {
+                println("    const TValue *slot;");
+                println("    TValue *upval = ctx->cl->upvals[GETARG_A(i)]->v;");
+                println("    TValue *rb = KB(i);");
+                println("    TValue *rc = RKC(i);");
+                println("    TString *key = tsvalue(rb);  /* key must be a string */");
+                println("    if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {");
+                println("      luaV_finishfastset(L, upval, slot, rc);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishset(L, upval, rb, rc, slot));");
+                break;
+            }
+            case OP_SETTABLE: {
+                println("    const TValue *slot;");
+                println("    TValue *rb = vRB(i);  /* key (table is in 'ra') */");
+                println("    TValue *rc = RKC(i);  /* value */");
+                println("    lua_Unsigned n;");
+                println("    if (ttisinteger(rb)  /* fast track for integers? */");
+                println("        ? (cast_void(n = ivalue(rb)), luaV_fastgeti(L, s2v(ra), n, slot))");
+                println("        : luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) {");
+                println("      luaV_finishfastset(L, s2v(ra), slot, rc);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishset(L, s2v(ra), rb, rc, slot));");
+                break;
+            }
+            case OP_SETI: {
+                println("    const TValue *slot;");
+                println("    int c = GETARG_B(i);");
+                println("    TValue *rc = RKC(i);");
+                println("    if (luaV_fastgeti(L, s2v(ra), c, slot)) {");
+                println("      luaV_finishfastset(L, s2v(ra), slot, rc);");
+                println("    }");
+                println("    else {");
+                println("      TValue key;");
+                println("      setivalue(&key, c);");
+                println("      Protect(luaV_finishset(L, s2v(ra), &key, rc, slot));");
+                println("    }");
+                break;
+            }
+            case OP_SETFIELD: {
+                println("    const TValue *slot;");
+                println("    TValue *rb = KB(i);");
+                println("    TValue *rc = RKC(i);");
+                println("    TString *key = tsvalue(rb);  /* key must be a string */");
+                println("    if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) {");
+                println("      luaV_finishfastset(L, s2v(ra), slot, rc);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishset(L, s2v(ra), rb, rc, slot));");
+                break;
+            }
+            case OP_NEWTABLE: {
+                println("    int b = GETARG_B(i);  /* log2(hash size) + 1 */");
+                println("    int c = GETARG_C(i);  /* array size */");
+                println("    Table *t;");
+                println("    if (b > 0)");
+                println("      b = 1 << (b - 1);  /* size is 2^(b - 1) */");
+                println("    lua_assert((!TESTARG_k(i)) == (GETARG_Ax(0x%08x) == 0));", f->code[pc+1]);
+                println("    if (TESTARG_k(i))");
+                println("      c += GETARG_Ax(0x%08x) * (MAXARG_C + 1);", f->code[pc+1]);
+                println("    /* skip extra argument */"); // (!)
+                println("    L->top = ra + 1;  /* correct top in case of emergency GC */");
+                println("    t = luaH_new(L);  /* memory allocation */");
+                println("    sethvalue2s(L, ra, t);");
+                println("    if (b != 0 || c != 0)");
+                println("      luaH_resize(L, t, c, b);  /* idem */");
+                println("    checkGC(L, ra + 1);");
+                println("    goto LUAOT_SKIP1;"); // (!)
+                break;
+            }
+            case OP_SELF: {
+                println("    const TValue *slot;");
+                println("    TValue *rb = vRB(i);");
+                println("    TValue *rc = RKC(i);");
+                println("    TString *key = tsvalue(rc);  /* key must be a string */");
+                println("    setobj2s(L, ra + 1, rb);");
+                println("    if (luaV_fastget(L, rb, key, slot, luaH_getstr)) {");
+                println("      setobj2s(L, ra, slot);");
+                println("    }");
+                println("    else");
+                println("      Protect(luaV_finishget(L, rb, rc, ra, slot));");
+                break;
+            }
+            case OP_ADDI: {
+                println("    op_arithI(L, l_addi, luai_numadd);");
+                break;
+            }
+            case OP_ADDK: {
+                println("    op_arithK(L, l_addi, luai_numadd);");
+                break;
+            }
+            case OP_SUBK: {
+                println("    op_arithK(L, l_subi, luai_numsub);");
+                break;
+            }
+            case OP_MULK: {
+                println("    op_arithK(L, l_muli, luai_nummul);");
+                break;
+            }
+            case OP_MODK: {
+                println("    op_arithK(L, luaV_mod, luaV_modf);");
+                break;
+            }
+            case OP_POWK: {
+                println("    op_arithfK(L, luai_numpow);");
+                break;
+            }
+            case OP_DIVK: {
+                println("    op_arithfK(L, luai_numdiv);");
+                break;
+            }
+            case OP_IDIVK: {
+                println("    op_arithK(L, luaV_idiv, luai_numidiv);");
+                break;
+            }
+            case OP_BANDK: {
+                println("    op_bitwiseK(L, l_band);");
+                break;
+            }
+            case OP_BORK: {
+                println("    op_bitwiseK(L, l_bor);");
+                break;
+            }
+            case OP_BXORK: {
+                println("    op_bitwiseK(L, l_bxor);");
+                break;
+            }
+            case OP_SHRI: {
+                println("    TValue *rb = vRB(i);");
+                println("    int ic = GETARG_sC(i);");
+                println("    lua_Integer ib;");
+                println("    if (tointegerns(rb, &ib)) {");
+                println("       setivalue(s2v(ra), luaV_shiftl(ib, -ic));");
+                println("       goto LUAOT_SKIP1;"); // (!)
+                println("    }");
+                break;
+            }
+            case OP_SHLI: {
+                println("    TValue *rb = vRB(i);");
+                println("    int ic = GETARG_sC(i);");
+                println("    lua_Integer ib;");
+                println("    if (tointegerns(rb, &ib)) {");
+                println("       setivalue(s2v(ra), luaV_shiftl(ic, ib));");
+                println("       goto LUAOT_SKIP1;"); // (!)
+                println("    }");
+                break;
+            }
+            case OP_ADD: {
+                println("    op_arith(L, l_addi, luai_numadd);");
+                break;
+            }
+            case OP_SUB: {
+                println("    op_arith(L, l_subi, luai_numsub);");
+                break;
+            }
+            case OP_MUL: {
+                println("    op_arith(L, l_muli, luai_nummul);");
+                break;
+            }
+            case OP_MOD: {
+                println("    op_arith(L, luaV_mod, luaV_modf);");
+                break;
+            }
+            case OP_POW: {
+                println("    op_arithf(L, luai_numpow);");
+                break;
+            }
+            case OP_DIV: {  /* float division (always with floats: */
+                println("    op_arithf(L, luai_numdiv);");
+                break;
+            }
+            case OP_IDIV: {  /* floor division */
+                println("    op_arith(L, luaV_idiv, luai_numidiv);");
+                break;
+            }
+            case OP_BAND: {
+                println("    op_bitwise(L, l_band);");
+                break;
+            }
+            case OP_BOR: {
+                println("    op_bitwise(L, l_bor);");
+                break;
+            }
+            case OP_BXOR: {
+                println("    op_bitwise(L, l_bxor);");
+                break;
+            }
+            case OP_SHR: {
+                println("    op_bitwise(L, luaV_shiftr);");
+                break;
+            }
+            case OP_SHL: {
+                println("    op_bitwise(L, luaV_shiftl);");
+                break;
+            }
+            case OP_MMBIN: {
+                println("    Instruction pi = 0x%08x; /* original arith. expression */", f->code[pc-1]);
+                println("    TValue *rb = vRB(i);");
+                println("    TMS tm = (TMS)GETARG_C(i);");
+                println("    StkId result = RA(pi);");
+                println("    lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR);");
+                println("    Protect(luaT_trybinTM(L, s2v(ra), rb, result, tm));");
+                break;
+            }
+            case OP_MMBINI: {
+                println("    Instruction pi = 0x%0x;  /* original arith. expression */", f->code[pc-1]);
+                println("    int imm = GETARG_sB(i);");
+                println("    TMS tm = (TMS)GETARG_C(i);");
+                println("    int flip = GETARG_k(i);");
+                println("    StkId result = RA(pi);");
+                println("    Protect(luaT_trybiniTM(L, s2v(ra), imm, flip, result, tm));");
+                break;
+            }
+            case OP_MMBINK: {
+                println("    Instruction pi = 0x%08x;  /* original arith. expression */", f->code[pc-1]);
+                println("    TValue *imm = KB(i);");
+                println("    TMS tm = (TMS)GETARG_C(i);");
+                println("    int flip = GETARG_k(i);");
+                println("    StkId result = RA(pi);");
+                println("    Protect(luaT_trybinassocTM(L, s2v(ra), imm, flip, result, tm));");
+                break;
+            }
+            case OP_UNM: {
+                println("    TValue *rb = vRB(i);");
+                println("    lua_Number nb;");
+                println("    if (ttisinteger(rb)) {");
+                println("      lua_Integer ib = ivalue(rb);");
+                println("      setivalue(s2v(ra), intop(-, 0, ib));");
+                println("    }");
+                println("    else if (tonumberns(rb, nb)) {");
+                println("      setfltvalue(s2v(ra), luai_numunm(L, nb));");
+                println("    }");
+                println("    else");
+                println("      Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));");
+                break;
+            }
+            case OP_BNOT: {
+                println("    TValue *rb = vRB(i);");
+                println("    lua_Integer ib;");
+                println("    if (tointegerns(rb, &ib)) {");
+                println("      setivalue(s2v(ra), intop(^, ~l_castS2U(0), ib));");
+                println("    }");
+                println("    else");
+                println("      Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));");
+                break;
+            }
+            case OP_NOT: {
+                println("    TValue *rb = vRB(i);");
+                println("    if (l_isfalse(rb))");
+                println("      setbtvalue(s2v(ra));");
+                println("    else");
+                println("      setbfvalue(s2v(ra));");
+                break;
+            }
+            case OP_LEN: {
+                println("    Protect(luaV_objlen(L, ra, vRB(i)));");
+                break;
+            }
+            case OP_CONCAT: {
+                println("    int n = GETARG_B(i);  /* number of elements to concatenate */");
+                println("    L->top = ra + n;  /* mark the end of concat operands */");
+                println("    ProtectNT(luaV_concat(L, n));");
+                println("    checkGC(L, L->top); /* 'luaV_concat' ensures correct top */");
+                break;
+            }
+            case OP_CLOSE: {
+                println("Protect(luaF_close(L, ra, LUA_OK, 1));");
+                break;
+            }
+            case OP_TBC: {
+                println("    /* create new to-be-closed upvalue */");
+                println("    halfProtect(luaF_newtbcupval(L, ra));");
+                break;
+            }
+            case OP_JMP: {
+                println("    updatetrap(ctx->ci);");
+                println("    goto label_%02d;", jump_target(f, pc));//(!)
+                break;
+            }
+            case OP_EQ: {
+                println("    int cond;");
+                println("    TValue *rb = vRB(i);");
+                println("    Protect(cond = luaV_equalobj(L, s2v(ra), rb));");
+                println("    docondjump();");
+                break;
+            }
+            case OP_LT: {
+                println("    op_order(L, l_lti, LTnum, lessthanothers);");
+                break;
+            }
+            case OP_LE: {
+                println("    op_order(L, l_lei, LEnum, lessequalothers);");
+                break;
+            }
+            case OP_EQK: {
+                println("    TValue *rb = KB(i);");
+                println("    /* basic types do not use '__eq'; we can use raw equality */");
+                println("    int cond = luaV_equalobj(NULL, s2v(ra), rb);");
+                println("    docondjump();");
+                break;
+            }
+            case OP_EQI: {
+                println("    int cond;");
+                println("    int im = GETARG_sB(i);");
+                println("    if (ttisinteger(s2v(ra)))");
+                println("      cond = (ivalue(s2v(ra)) == im);");
+                println("    else if (ttisfloat(s2v(ra)))");
+                println("      cond = luai_numeq(fltvalue(s2v(ra)), cast_num(im));");
+                println("    else");
+                println("      cond = 0;  /* other types cannot be equal to a number */");
+                println("    docondjump();");
+                break;
+            }
+            case OP_LTI: {
+                println("    op_orderI(L, l_lti, luai_numlt, 0, TM_LT);");
+                break;
+            }
+            case OP_LEI: {
+                println("    op_orderI(L, l_lei, luai_numle, 0, TM_LE);");
+                break;
+            }
+            case OP_GTI: {
+                println("    op_orderI(L, l_gti, luai_numgt, 1, TM_LT);");
+                break;
+            }
+            case OP_GEI: {
+                println("    op_orderI(L, l_gei, luai_numge, 1, TM_LE);");
+                break;
+            }
+            case OP_TEST: {
+                println("    int cond = !l_isfalse(s2v(ra));");
+                println("    docondjump();");
+                break;
+            }
+            case OP_TESTSET: {
+                println("    TValue *rb = vRB(i);");
+                println("    if (l_isfalse(rb) == GETARG_k(i))");
+                println("      goto LUAOT_SKIP1;"); // (!)
+                println("    else {");
+                println("      setobj2s(L, ra, rb);");
+                println("      donextjump(ctx->ci);");
+                println("    }");
+                break;
+            }
+            case OP_CALL: {
+                println("    CallInfo *newci;");
+                println("    int b = GETARG_B(i);");
+                println("    int nresults = GETARG_C(i) - 1;");
+                println("    if (b != 0)  /* fixed number of arguments? */");
+                println("        L->top = ra + b;  /* top signals number of arguments */");
+                println("    /* else previous instruction set top */");
+                println("    savepc(L);  /* in case of errors */");
+                println("    if ((newci = luaD_precall(L, ra, nresults)) == NULL)");
+                println("        updatetrap(ctx->ci);  /* C call; nothing else to be done */");
+                println("    else {");
+                println("        ctx->ci = newci;");
+                println("        ctx->ci->callstatus = 0;  /* call re-uses 'luaV_execute' */");
+                println("        return ctx->ci;");
+                println("    }");
+                break;
+            }
+            case OP_TAILCALL: {
+                println("    int b = GETARG_B(i);  /* number of arguments + 1 (function) */");
+                println("    int nparams1 = GETARG_C(i);");
+                println("    /* delta is virtual 'func' - real 'func' (vararg functions) */");
+                println("    int delta = (nparams1) ? ctx->ci->u.l.nextraargs + nparams1 : 0;");
+                println("    if (b != 0)");
+                println("      L->top = ra + b;");
+                println("    else  /* previous instruction set top */");
+                println("      b = cast_int(L->top - ra);");
+                println("    savepc(ctx->ci);  /* several calls here can raise errors */");
+                println("    if (TESTARG_k(i)) {");
+                println("      luaF_closeupval(L, ctx->base);  /* close upvalues from current call */");
+                println("      lua_assert(L->tbclist < ctx->base);  /* no pending tbc variables */");
+                println("      lua_assert(ctx->base == ctx->ci->func + 1);");
+                println("    }");
+                println("    while (!ttisfunction(s2v(ra))) {  /* not a function? */");
+                println("      luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */");
+                println("      b++;  /* there is now one extra argument */");
+                println("      checkstackGCp(L, 1, ra);");
+                println("    }");
+                println("    if (!ttisLclosure(s2v(ra))) {  /* C function? */");
+                println("      luaD_precall(L, ra, LUA_MULTRET);  /* call it */");
+                println("      updatetrap(ctx->ci);");
+                println("      updatestack(ctx->ci);  /* stack may have been relocated */");
+                println("      ctx->ci->func -= delta;  /* restore 'func' (if vararg) */");
+                println("      luaD_poscall(L, ctx->ci, cast_int(L->top - ra));  /* finish caller */");
+                println("      updatetrap(ctx->ci);  /* 'luaD_poscall' can change hooks */");
+                println_goto_ret(); // (!)
+                println("    }");
+                println("    ctx->ci->func -= delta;  /* restore 'func' (if vararg) */");
+                println("    luaD_pretailcall(L, ctx->ci, ra, b);  /* prepare call frame */");
+                println("    return ctx->ci;");
+                break;
+            }
+            case OP_RETURN: {
+                println("    int n = GETARG_B(i) - 1;  /* number of results */");
+                println("    int nparams1 = GETARG_C(i);");
+                println("    if (n < 0)  /* not fixed? */");
+                println("      n = cast_int(L->top - ra);  /* get what is available */");
+                println("    savepc(ctx->ci);");
+                println("    if (TESTARG_k(i)) {  /* may there be open upvalues? */");
+                println("      if (L->top < ctx->ci->top)");
+                println("        L->top = ctx->ci->top;");
+                println("      luaF_close(L, ctx->base, CLOSEKTOP, 1);");
+                println("      updatetrap(ctx->ci);");
+                println("      updatestack(ctx->ci);");
+                println("    }");
+                println("    if (nparams1)  /* vararg function? */");
+                println("      ctx->ci->func -= ctx->ci->u.l.nextraargs + nparams1;");
+                println("    L->top = ra + n;  /* set call for 'luaD_poscall' */");
+                println("    luaD_poscall(L, ctx->ci, n);");
+                println("    updatetrap(ctx->ci);  /* 'luaD_poscall' can change hooks */");
+                println_goto_ret();
+                break;
+            }
+            case OP_RETURN0: {
+                println("    if (l_unlikely(L->hookmask)) {");
+                println("      L->top = ra;");
+                println("      savepc(ctx->ci);");
+                println("      luaD_poscall(L, ctx->ci, 0);  /* no hurry... */");
+                println("      ctx->trap = 1;");
+                println("    }");
+                println("    else {  /* do the 'poscall' here */");
+                println("      int nres;");
+                println("      L->ci = ctx->ci->previous;  /* back to caller */");
+                println("      L->top = ctx->base - 1;");
+                println("      for (nres = ctx->ci->nresults; l_unlikely(nres > 0); nres--)");
+                println("        setnilvalue(s2v(L->top++));  /* all results are nil */");
+                println("    }");
+                println_goto_ret();
+                break;
+            }
+            case OP_RETURN1: {
+                println("    if (l_unlikely(L->hookmask)) {");
+                println("      L->top = ra + 1;");
+                println("      savepc(ctx->ci);");
+                println("      luaD_poscall(L, ctx->ci, 1);  /* no hurry... */");
+                println("      ctx->trap = 1;");
+                println("    }");
+                println("    else {  /* do the 'poscall' here */");
+                println("      int nres = ctx->ci->nresults;");
+                println("      L->ci = ctx->ci->previous;  /* back to caller */");
+                println("      if (nres == 0)");
+                println("        L->top = ctx->base - 1;  /* asked for no results */");
+                println("      else {");
+                println("        setobjs2s(L, ctx->base - 1, ra);  /* at least this result */");
+                println("        L->top = ctx->base;");
+                println("        for (; l_unlikely(nres > 1); nres--)");
+                println("          setnilvalue(s2v(L->top++));");
+                println("      }");
+                println("    }");
+                println_goto_ret();
+                break;
+            }
+            case OP_FORLOOP: {
+                println("    if (ttisinteger(s2v(ra + 2))) {  /* integer loop? */");
+                println("      lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));");
+                println("      if (count > 0) {  /* still more iterations? */");
+                println("        lua_Integer step = ivalue(s2v(ra + 2));");
+                println("        lua_Integer idx = ivalue(s2v(ra));  /* internal index */");
+                println("        chgivalue(s2v(ra + 1), count - 1);  /* update counter */");
+                println("        idx = intop(+, idx, step);  /* add step to index */");
+                println("        chgivalue(s2v(ra), idx);  /* update internal index */");
+                println("        setivalue(s2v(ra + 3), idx);  /* and control variable */");
+                println("        goto label_%02d; /* jump back */", ((pc+1) - GETARG_Bx(instr))); //(!)
+                println("      }");
+                println("    }");
+                println("    else if (floatforloop(ra)) /* float loop */");
+                println("      goto label_%02d; /* jump back */", ((pc+1) - GETARG_Bx(instr))); //(!)
+                println("    updatetrap(ctx->ci);  /* allows a signal to break the loop */");
+                break;
+            }
+            case OP_FORPREP: {
+                println("    savestate(L, ctx->ci);  /* in case of errors */");
+                println("    if (forprep(L, ra))");
+                println("      goto label_%02d; /* skip the loop */", ((pc+1) + GETARG_Bx(instr) + 1)); //(!)
+                break;
+            }
+            case OP_TFORPREP: {
+                println("    /* create to-be-closed upvalue (if needed) */");
+                println("    halfProtect(luaF_newtbcupval(L, ra + 3));");
+                println("    goto label_%02d;", ((pc+1) + GETARG_Bx(instr))); //(!)
+                break;
+            }
+            case OP_TFORCALL: {
+                println("    /* 'ra' has the iterator function, 'ra + 1' has the state,");
+                println("       'ra + 2' has the control variable, and 'ra + 3' has the");
+                println("       to-be-closed variable. The call will use the stack after");
+                println("       these values (starting at 'ra + 4')");
+                println("    */");
+                println("    /* push function, state, and control variable */");
+                println("    memcpy(ra + 4, ra, 3 * sizeof(*ra));");
+                println("    L->top = ra + 4 + 3;");
+                println("    ProtectNT(luaD_call(L, ra + 4, GETARG_C(i)));  /* do the call */");
+                println("    updatestack(ctx->ci);  /* stack may have changed */");
+                // (!) Going to the next instruction is a no-op
+                break;
+            }
+            case OP_TFORLOOP: {
+                println("    if (!ttisnil(s2v(ra + 4))) {  /* continue loop? */");
+                println("      setobjs2s(L, ra + 2, ra + 4);  /* save control variable */");
+                println("      goto label_%02d; /* jump back */", ((pc+1) - GETARG_Bx(instr))); //(!)
+                println("    }");
+                break;
+            }
+            case OP_SETLIST: {
+                // We should take care to only generate code for the extra argument if it actually exists.
+                // In a previous version of this compiler, we were putting the "if" in the generated code
+                // instead of in the code generator and that resulted in compile-time warnings from gcc.
+                // Sometimes, the last += GETARG_Ax" line would overflow and the C compiler would naturally
+                // complain (even though the offending line was never executed).
+                int has_extra_arg = TESTARG_k(instr);
+                println("        int n = GETARG_B(i);");
+                println("        unsigned int last = GETARG_C(i);");
+                println("        Table *h = hvalue(s2v(ra));");
+                println("        if (n == 0)");
+                println("          n = cast_int(L->top - ra) - 1;  /* get up to the top */");
+                println("        else");
+                println("          L->top = ctx->ci->top;  /* correct top in case of emergency GC */");
+                println("        last += n;");
+                if (has_extra_arg) {
+                 println("        last += GETARG_Ax(0x%08x) * (MAXARG_C + 1);", f->code[pc+1]); // (!)
+                }
+                println("        if (last > luaH_realasize(h))  /* needs more space? */");
+                println("          luaH_resizearray(L, h, last);  /* preallocate it at once */");
+                println("        for (; n > 0; n--) {");
+                println("          TValue *val = s2v(ra + n);");
+                println("          setobj2t(L, &h->array[last - 1], val);");
+                println("          last--;");
+                println("          luaC_barrierback(L, obj2gco(h), val);");
+                println("        }");
+                if (has_extra_arg) {
+                 println("        goto LUAOT_SKIP1;"); // (!)
+                }
+                break;
+            }
+            case OP_CLOSURE: {
+                println("    Proto *p = ctx->cl->p->p[GETARG_Bx(i)];");
+                println("    halfProtect(pushclosure(L, p, ctx->cl->upvals, ctx->base, ra));");
+                println("    checkGC(L, ra + 1);");
+                break;
+            }
+            case OP_VARARG: {
+                println("    int n = GETARG_C(i) - 1;  /* required results */");
+                println("    Protect(luaT_getvarargs(L, ctx->ci, ra, n));");
+                break;
+            }
+            case OP_VARARGPREP: {
+                println("    ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ctx->ci, ctx->cl->p));");
+                println("    if (l_unlikely(ctx->trap)) {  /* previous \"Protect\" updated trap */");
+                println("      luaD_hookcall(L, ctx->ci);");
+                println("      L->oldpc = 1;  /* next opcode will be seen as a \"new\" line */");
+                println("    }");
+                println("    updatebase(ctx->ci);  /* function has new base after adjustment */");
+                break;
+            }
+            case OP_EXTRAARG: {
+                println("    lua_assert(0);");
+                break;
+            }
+            default: {
+                char msg[64];
+                sprintf(msg, "%s is not implemented yet", opnames[op]);
+                fatal_error(msg);
+                break;
+            }
+        }
+        println("  }");
+        printnl();
+    }
+
+    println("}");
+    printnl();
+}