First version of OP_MMBIN opcodes

In arithmetic/bitwise operators, the call to metamethods is made
in a separate opcode following the main one. (The main
opcode skips this next one when the operation succeeds.) This
change reduces slightly the size of the binary and the complexity
of the arithmetic/bitwise opcodes. It also simplfies the treatment
of errors and yeld/resume in these operations, as there are much
fewer cases to consider. (Only OP_MMBIN/OP_MMBINI/OP_MMBINK,
instead of all variants of all arithmetic/bitwise operators.)
diff --git a/lcode.c b/lcode.c
index c2b5fc6..a1b27a0 100644
--- a/lcode.c
+++ b/lcode.c
@@ -1337,18 +1337,20 @@
 ** (everything but logical operators 'and'/'or' and comparison
 ** operators).
 ** Expression to produce final result will be encoded in 'e1'.
-** Because 'luaK_exp2anyreg' can free registers, its calls must be
-** in "stack order" (that is, first on 'e2', which may have more
-** recent registers to be released).
 */
 static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
-                             OpCode op, int v2, int k, int line) {
+                             OpCode op, int v2, int k, int line,
+                             OpCode mmop, TMS event) {
   int v1 = luaK_exp2anyreg(fs, e1);
   int pc = luaK_codeABCk(fs, op, 0, v1, v2, k);
   freeexps(fs, e1, e2);
   e1->u.info = pc;
   e1->k = VRELOC;  /* all those operations are relocatable */
   luaK_fixline(fs, line);
+if (event != TM_SHL && event != TM_SHR) {
+  luaK_codeABCk(fs, mmop, v1, v2, event, k);  /* to call metamethod */
+  luaK_fixline(fs, line);
+}
 }
 
 
@@ -1359,7 +1361,9 @@
 static void codebinexpval (FuncState *fs, OpCode op,
                            expdesc *e1, expdesc *e2, int line) {
   int v2 = luaK_exp2anyreg(fs, e2);  /* both operands are in registers */
-  finishbinexpval(fs, e1, e2, op, v2, 0, line);
+  lua_assert(OP_ADD <= op && op <= OP_SHR);
+  finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
+                  cast(TMS, (op - OP_ADD) + TM_ADD));
 }
 
 
@@ -1367,9 +1371,10 @@
 ** Code binary operators ('+', '-', ...) with immediate operands.
 */
 static void codebini (FuncState *fs, OpCode op,
-                       expdesc *e1, expdesc *e2, int k, int line) {
+                       expdesc *e1, expdesc *e2, int k, int line,
+                       TMS event) {
   int v2 = cast_int(e2->u.ival) + OFFSET_sC;  /* immediate operand */
-  finishbinexpval(fs, e1, e2, op, v2, k, line);
+  finishbinexpval(fs, e1, e2, op, v2, k, line, OP_MMBINI, event);
 }
 
 
@@ -1383,16 +1388,18 @@
 ** constant in the proper range, use variant opcodes with immediate
 ** operands or K operands.
 */
-static void codearith (FuncState *fs, OpCode op,
+static void codearith (FuncState *fs, BinOpr opr,
                        expdesc *e1, expdesc *e2, int flip, int line) {
+  TMS event = cast(TMS, opr + TM_ADD);
   if (isSCint(e2))  /* immediate operand? */
-    codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line);
+    codebini(fs, cast(OpCode, opr + OP_ADDI), e1, e2, flip, line, event);
   else if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) {  /* K operand? */
     int v2 = e2->u.info;  /* K index */
-    op = cast(OpCode, op - OP_ADD + OP_ADDK);
-    finishbinexpval(fs, e1, e2, op, v2, flip, line);
+    OpCode op = cast(OpCode, opr + OP_ADDK);
+    finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
   }
   else {  /* 'e2' is neither an immediate nor a K operand */
+    OpCode op = cast(OpCode, opr + OP_ADD);
     if (flip)
       swapexps(e1, e2);  /* back to original order */
     codebinexpval(fs, op, e1, e2, line);  /* use standard operators */
@@ -1405,7 +1412,7 @@
 ** numeric constant, change order of operands to try to use an
 ** immediate or K operator.
 */
-static void codecommutative (FuncState *fs, OpCode op,
+static void codecommutative (FuncState *fs, BinOpr op,
                              expdesc *e1, expdesc *e2, int line) {
   int flip = 0;
   if (tonumeral(e1, NULL)) {  /* is first operand a numeric constant? */
@@ -1430,14 +1437,15 @@
     inv = 1;
   }
   else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) {  /* no constants? */
-    op = cast(OpCode, opr - OPR_BAND + OP_BAND);
+    op = cast(OpCode, opr + OP_ADD);
     codebinexpval(fs, op, e1, e2, line);  /* all-register opcodes */
     return;
   }
   v2 = e2->u.info;  /* index in K array */
-  op = cast(OpCode, opr - OPR_BAND + OP_BANDK);
+  op = cast(OpCode, opr + OP_ADDK);
   lua_assert(ttisinteger(&fs->f->k[v2]));
-  finishbinexpval(fs, e1, e2, op, v2, inv, line);
+  finishbinexpval(fs, e1, e2, op, v2, inv, line, OP_MMBINK,
+                  cast(TMS, opr + TM_ADD));
 }
 
 
@@ -1453,7 +1461,7 @@
       changedir = 1;
       e2->u.ival = -(e2->u.ival);
     }
-    codebini(fs, OP_SHRI, e1, e2, changedir, line);
+    codebini(fs, OP_SHRI, e1, e2, changedir, line, TM_SHL);
   }
   else
     codebinexpval(fs, op, e1, e2, line);
@@ -1638,13 +1646,13 @@
     }
     case OPR_ADD: case OPR_MUL: {
       if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
-        codecommutative(fs, cast(OpCode, opr + OP_ADD), e1, e2, line);
+        codecommutative(fs, opr, e1, e2, line);
       break;
     }
     case OPR_SUB: case OPR_DIV:
     case OPR_IDIV: case OPR_MOD: case OPR_POW: {
       if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
-        codearith(fs, cast(OpCode, opr + OP_ADD), e1, e2, 0, line);
+        codearith(fs, opr, e1, e2, 0, line);
       break;
     }
     case OPR_BAND: case OPR_BOR: case OPR_BXOR: {
@@ -1656,7 +1664,7 @@
       if (!constfolding(fs, LUA_OPSHL, e1, e2)) {
         if (isSCint(e1)) {
           swapexps(e1, e2);
-          codebini(fs, OP_SHLI, e1, e2, 1, line);
+          codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL);
         }
         else
           codeshift(fs, OP_SHL, e1, e2, line);
diff --git a/ldebug.c b/ldebug.c
index 9593039..4e1dc6b 100644
--- a/ldebug.c
+++ b/ldebug.c
@@ -471,6 +471,10 @@
   int pc;
   int setreg = -1;  /* keep last instruction that changed 'reg' */
   int jmptarget = 0;  /* any code before this address is conditional */
+  if (GET_OPCODE(p->code[lastpc]) == OP_MMBIN ||
+      GET_OPCODE(p->code[lastpc]) == OP_MMBINI ||
+      GET_OPCODE(p->code[lastpc]) == OP_MMBINK)
+    lastpc--;
   for (pc = 0; pc < lastpc; pc++) {
     Instruction i = p->code[pc];
     OpCode op = GET_OPCODE(i);
@@ -620,22 +624,11 @@
     case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD:
       tm = TM_NEWINDEX;
       break;
-    case OP_ADDI: case OP_SUBI: case OP_MULI: case OP_MODI:
-    case OP_POWI: case OP_DIVI: case OP_IDIVI: {
-      int offset = GET_OPCODE(i) - OP_ADDI;  /* ORDER OP */
-      tm = cast(TMS, offset + TM_ADD);  /* ORDER TM */
+    case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
+      tm = cast(TMS, GETARG_C(i));
       break;
     }
-    case OP_ADDK: case OP_SUBK: case OP_MULK: case OP_MODK:
-    case OP_POWK: case OP_DIVK: case OP_IDIVK:
-    case OP_BANDK: case OP_BORK: case OP_BXORK: {
-      int offset = GET_OPCODE(i) - OP_ADDK;  /* ORDER OP */
-      tm = cast(TMS, offset + TM_ADD);  /* ORDER TM */
-      break;
-    }
-    case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:
-    case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND:
-    case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: {
+    case OP_SHL: case OP_SHR: {
       int offset = GET_OPCODE(i) - OP_ADD;  /* ORDER OP */
       tm = cast(TMS, offset + TM_ADD);  /* ORDER TM */
       break;
diff --git a/ljumptab.h b/ljumptab.h
index 2d4cf28..1832c80 100644
--- a/ljumptab.h
+++ b/ljumptab.h
@@ -75,6 +75,9 @@
 &&L_OP_BXOR,
 &&L_OP_SHL,
 &&L_OP_SHR,
+&&L_OP_MMBIN,
+&&L_OP_MMBINI,
+&&L_OP_MMBINK,
 &&L_OP_UNM,
 &&L_OP_BNOT,
 &&L_OP_NOT,
diff --git a/lopcodes.c b/lopcodes.c
index ee79578..aede93a 100644
--- a/lopcodes.c
+++ b/lopcodes.c
@@ -69,6 +69,9 @@
  ,opmode(0, 0, 0, 1, iABC)		/* OP_BXOR */
  ,opmode(0, 0, 0, 1, iABC)		/* OP_SHL */
  ,opmode(0, 0, 0, 1, iABC)		/* OP_SHR */
+ ,opmode(0, 0, 0, 0, iABC)		/* OP_MMBIN */
+ ,opmode(0, 0, 0, 0, iABC)		/* OP_MMBINI*/
+ ,opmode(0, 0, 0, 0, iABC)		/* OP_MMBINK*/
  ,opmode(0, 0, 0, 1, iABC)		/* OP_UNM */
  ,opmode(0, 0, 0, 1, iABC)		/* OP_BNOT */
  ,opmode(0, 0, 0, 1, iABC)		/* OP_NOT */
diff --git a/lopcodes.h b/lopcodes.h
index 26b1850..fd578c6 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -255,6 +255,10 @@
 OP_SHL,/*	A B C	R(A) := R(B) << R(C)				*/
 OP_SHR,/*	A B C	R(A) := R(B) >> R(C)				*/
 
+OP_MMBIN,/*	A B C	call B metamethod for previous bin. operation	*/
+OP_MMBINI,/*	A B C	call B metamethod for previous binI. operation	*/
+OP_MMBINK,/*	A B C	call B metamethod for previous binK. operation	*/
+
 OP_UNM,/*	A B	R(A) := -R(B)					*/
 OP_BNOT,/*	A B	R(A) := ~R(B)					*/
 OP_NOT,/*	A B	R(A) := not R(B)				*/
diff --git a/lopnames.h b/lopnames.h
index 28535fe..0fc1da1 100644
--- a/lopnames.h
+++ b/lopnames.h
@@ -60,6 +60,9 @@
   "BXOR",
   "SHL",
   "SHR",
+  "MMBIN",
+  "MMBINI",
+  "MMBINK",
   "UNM",
   "BNOT",
   "NOT",
diff --git a/ltm.c b/ltm.c
index 19233a8..991e62c 100644
--- a/ltm.c
+++ b/ltm.c
@@ -173,7 +173,7 @@
 
 
 void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2,
-                                       StkId res, int flip, TMS event) {
+                                       int flip, StkId res, TMS event) {
   if (flip)
     luaT_trybinTM(L, p2, p1, res, event);
   else
@@ -185,7 +185,7 @@
                                    int flip, StkId res, TMS event) {
   TValue aux;
   setivalue(&aux, i2);
-  luaT_trybinassocTM(L, p1, &aux, res, flip, event);
+  luaT_trybinassocTM(L, p1, &aux, flip, res, event);
 }
 
 
diff --git a/ltm.h b/ltm.h
index 51dfe79..9621e68 100644
--- a/ltm.h
+++ b/ltm.h
@@ -77,7 +77,7 @@
                               StkId res, TMS event);
 LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
 LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1,
-       const TValue *p2, StkId res, int inv, TMS event);
+       const TValue *p2, int inv, StkId res, TMS event);
 LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
                                int inv, StkId res, TMS event);
 LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
diff --git a/lvm.c b/lvm.c
index 907417e..a9e8455 100644
--- a/lvm.c
+++ b/lvm.c
@@ -717,18 +717,11 @@
   Instruction inst = *(ci->u.l.savedpc - 1);  /* interrupted instruction */
   OpCode op = GET_OPCODE(inst);
   switch (op) {  /* finish its execution */
-    case OP_ADDI: case OP_SUBI:
-    case OP_MULI: case OP_DIVI: case OP_IDIVI:
-    case OP_MODI: case OP_POWI:
-    case OP_ADDK: case OP_SUBK:
-    case OP_MULK: case OP_DIVK: case OP_IDIVK:
-    case OP_MODK: case OP_POWK:
-    case OP_ADD: case OP_SUB:
-    case OP_MUL: case OP_DIV: case OP_IDIV:
-    case OP_BANDK: case OP_BORK: case OP_BXORK:
-    case OP_BAND: case OP_BOR: case OP_BXOR:
+    case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
+      setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
+      break;
+    }
     case OP_SHLI: case OP_SHRI: case OP_SHL: case OP_SHR:
-    case OP_MOD: case OP_POW:
     case OP_UNM: case OP_BNOT: case OP_LEN:
     case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
     case OP_GETFIELD: case OP_SELF: {
@@ -804,10 +797,8 @@
   lua_Number nb;  \
   if (tonumberns(v1, nb)) {  \
     lua_Number fimm = cast_num(imm);  \
-    setfltvalue(s2v(ra), fop(L, nb, fimm));  \
-  }  \
-  else  \
-    ProtectNT(luaT_trybiniTM(L, v1, imm, flip, ra, tm)); }
+    pc++; setfltvalue(s2v(ra), fop(L, nb, fimm));  \
+  }}
 
 
 /*
@@ -827,7 +818,7 @@
   int imm = GETARG_sC(i);  \
   if (ttisinteger(v1)) {  \
     lua_Integer iv1 = ivalue(v1);  \
-    setivalue(s2v(ra), iop(L, iv1, imm));  \
+    pc++; setivalue(s2v(ra), iop(L, iv1, imm));  \
   }  \
   else op_arithfI_aux(L, v1, imm, fop, tm, flip); }
 
@@ -839,10 +830,8 @@
 #define op_arithf_aux(L,v1,v2,fop,tm) {  \
   lua_Number n1; lua_Number n2;  \
   if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-    setfltvalue(s2v(ra), fop(L, n1, n2));  \
-  }  \
-  else  \
-    ProtectNT(luaT_trybinTM(L, v1, v2, ra, tm)); }
+    pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
+  }}
 
 
 /*
@@ -862,7 +851,7 @@
   TValue *v2 = vRC(i);  \
   if (ttisinteger(v1) && ttisinteger(v2)) {  \
     lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
-    setivalue(s2v(ra), iop(L, i1, i2));  \
+    pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
   }  \
   else op_arithf_aux(L, v1, v2, fop, tm); }
 
@@ -875,15 +864,13 @@
   TValue *v2 = KC(i);  \
   if (ttisinteger(v1) && ttisinteger(v2)) {  \
     lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
-    setivalue(s2v(ra), iop(L, i1, i2));  \
+    pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
   }  \
   else { \
     lua_Number n1; lua_Number n2;  \
     if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-      setfltvalue(s2v(ra), fop(L, n1, n2));  \
-    }  \
-    else  \
-      ProtectNT(luaT_trybinassocTM(L, v1, v2, ra, flip, tm)); } }
+      pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
+    }}}
 
 
 /*
@@ -894,10 +881,8 @@
   TValue *v2 = KC(i);  \
   lua_Number n1; lua_Number n2;  \
   if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-    setfltvalue(s2v(ra), fop(L, n1, n2));  \
-  }  \
-  else  \
-    ProtectNT(luaT_trybinTM(L, v1, v2, ra, tm)); }
+    pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
+  }}
 
 
 /*
@@ -909,10 +894,8 @@
   lua_Integer i1;  \
   lua_Integer i2 = ivalue(v2);  \
   if (tointegerns(v1, &i1)) {  \
-    setivalue(s2v(ra), op(L, i1, i2));  \
-  }  \
-  else  \
-    ProtectNT(luaT_trybiniTM(L, v1, i2, TESTARG_k(i), ra, tm)); }
+    pc++; setivalue(s2v(ra), op(L, i1, i2));  \
+  }}
 
 
 /*
@@ -923,10 +906,8 @@
   TValue *v2 = vRC(i);  \
   lua_Integer i1; lua_Integer i2;  \
   if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) {  \
-    setivalue(s2v(ra), op(L, i1, i2));  \
-  }  \
-  else  \
-    ProtectNT(luaT_trybinTM(L, v1, v2, ra, tm)); }
+    pc++; setivalue(s2v(ra), op(L, i1, i2));  \
+  }}
 
 
 /*
@@ -1443,6 +1424,33 @@
           ProtectNT(luaT_trybinTM(L, rb, rc, ra, TM_SHL));
         vmbreak;
       }
+      vmcase(OP_MMBIN) {
+        Instruction pi = *(pc - 2);  /* original arith. expression */
+        TValue *rb = vRB(i);
+        TMS tm = (TMS)GETARG_C(i);
+        StkId result = RA(pi);
+        lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR);
+        ProtectNT(luaT_trybinTM(L, s2v(ra), rb, result, tm));
+        vmbreak;
+      }
+      vmcase(OP_MMBINI) {
+        Instruction pi = *(pc - 2);  /* original arith. expression */
+        int imm = GETARG_sB(i);
+        TMS tm = (TMS)GETARG_C(i);
+        int flip = GETARG_k(i);
+        StkId result = RA(pi);
+        ProtectNT(luaT_trybiniTM(L, s2v(ra), imm, flip, result, tm));
+        vmbreak;
+      }
+      vmcase(OP_MMBINK) {
+        Instruction pi = *(pc - 2);  /* original arith. expression */
+        TValue *imm = KB(i);
+        TMS tm = (TMS)GETARG_C(i);
+        int flip = GETARG_k(i);
+        StkId result = RA(pi);
+        ProtectNT(luaT_trybinassocTM(L, s2v(ra), imm, flip, result, tm));
+        vmbreak;
+      }
       vmcase(OP_UNM) {
         TValue *rb = vRB(i);
         lua_Number nb;
@@ -1826,4 +1834,3 @@
 }
 
 /* }================================================================== */
-
diff --git a/testes/code.lua b/testes/code.lua
index 3b768f3..fcb5c30 100644
--- a/testes/code.lua
+++ b/testes/code.lua
@@ -156,9 +156,9 @@
   c.x, a[b] = -((a + d/b - a[b]) ^ a.x), b
 end,
   'LOADNIL',
-  'MUL',
-  'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETFIELD', 'POW',
-    'UNM', 'SETTABLE', 'SETFIELD', 'RETURN0')
+  'MUL', 'MMBIN',
+  'DIV', 'MMBIN', 'ADD', 'MMBIN', 'GETTABLE', 'SUB', 'MMBIN',
+  'GETFIELD', 'POW', 'MMBIN', 'UNM', 'SETTABLE', 'SETFIELD', 'RETURN0')
 
 
 -- direct access to constants
@@ -188,7 +188,7 @@
   b = a/a
   b = 5-4
 end,
-  'LOADNIL', 'SUB', 'DIV', 'LOADI', 'RETURN0')
+  'LOADNIL', 'SUB', 'MMBIN', 'DIV', 'MMBIN', 'LOADI', 'RETURN0')
 
 check(function ()
   local a,b
@@ -292,38 +292,45 @@
 
 
 -- immediate operands
-checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'RETURN1')
-checkR(function (x) return 128 + x end, 0.0, 128.0, 'ADDI', 'RETURN1')
-checkR(function (x) return x * -127 end, -1.0, 127.0, 'MULI', 'RETURN1')
-checkR(function (x) return 20 * x end, 2, 40, 'MULI', 'RETURN1')
-checkR(function (x) return x ^ -2 end, 2, 0.25, 'POWI', 'RETURN1')
-checkR(function (x) return x / 40 end, 40, 1.0, 'DIVI', 'RETURN1')
-checkR(function (x) return x // 1 end, 10.0, 10.0, 'IDIVI', 'RETURN1')
-checkR(function (x) return x % (100 - 10) end, 91, 1, 'MODI', 'RETURN1')
+checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'MMBINI', 'RETURN1')
+checkR(function (x) return 128 + x end, 0.0, 128.0,
+         'ADDI', 'MMBINI', 'RETURN1')
+checkR(function (x) return x * -127 end, -1.0, 127.0,
+         'MULI', 'MMBINI', 'RETURN1')
+checkR(function (x) return 20 * x end, 2, 40, 'MULI', 'MMBINI', 'RETURN1')
+checkR(function (x) return x ^ -2 end, 2, 0.25, 'POWI', 'MMBINI', 'RETURN1')
+checkR(function (x) return x / 40 end, 40, 1.0, 'DIVI', 'MMBINI', 'RETURN1')
+checkR(function (x) return x // 1 end, 10.0, 10.0,
+         'IDIVI', 'MMBINI', 'RETURN1')
+checkR(function (x) return x % (100 - 10) end, 91, 1,
+         'MODI', 'MMBINI', 'RETURN1')
 checkR(function (x) return k1 << x end, 3, 8, 'SHLI', 'RETURN1')
 checkR(function (x) return x << 2 end, 10, 40, 'SHRI', 'RETURN1')
 checkR(function (x) return x >> 2 end, 8, 2, 'SHRI', 'RETURN1')
-checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'RETURN1')
-checkR(function (x) return 10 | x end, 1, 11, 'BORK', 'RETURN1')
-checkR(function (x) return -10 ~ x end, -1, 9, 'BXORK', 'RETURN1')
+checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'MMBINK', 'RETURN1')
+checkR(function (x) return 10 | x end, 1, 11, 'BORK', 'MMBINK', 'RETURN1')
+checkR(function (x) return -10 ~ x end, -1, 9, 'BXORK', 'MMBINK', 'RETURN1')
 
 -- K operands in arithmetic operations
-checkR(function (x) return x + 0.0 end, 1, 1.0, 'ADDK', 'RETURN1')
---  check(function (x) return 128 + x end, 'ADDK', 'RETURN1')
-checkR(function (x) return x * -10000 end, 2, -20000, 'MULK', 'RETURN1')
---  check(function (x) return 20 * x end, 'MULK', 'RETURN1')
-checkR(function (x) return x ^ 0.5 end, 4, 2.0, 'POWK', 'RETURN1')
-checkR(function (x) return x / 2.0 end, 4, 2.0, 'DIVK', 'RETURN1')
-checkR(function (x) return x // 10000 end, 10000, 1, 'IDIVK', 'RETURN1')
-checkR(function (x) return x % (100.0 - 10) end, 91, 1.0, 'MODK', 'RETURN1')
+checkR(function (x) return x + 0.0 end, 1, 1.0, 'ADDK', 'MMBINK', 'RETURN1')
+--  check(function (x) return 128 + x end, 'ADDK', 'MMBINK', 'RETURN1')
+checkR(function (x) return x * -10000 end, 2, -20000,
+         'MULK', 'MMBINK', 'RETURN1')
+--  check(function (x) return 20 * x end, 'MULK', 'MMBINK', 'RETURN1')
+checkR(function (x) return x ^ 0.5 end, 4, 2.0, 'POWK', 'MMBINK', 'RETURN1')
+checkR(function (x) return x / 2.0 end, 4, 2.0, 'DIVK', 'MMBINK', 'RETURN1')
+checkR(function (x) return x // 10000 end, 10000, 1,
+         'IDIVK', 'MMBINK', 'RETURN1')
+checkR(function (x) return x % (100.0 - 10) end, 91, 1.0,
+         'MODK', 'MMBINK', 'RETURN1')
 
 -- no foldings (and immediate operands)
 check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1')
-check(function () return k3/0 end, 'LOADI', 'DIVI', 'RETURN1')
-check(function () return 0%0 end, 'LOADI', 'MODI', 'RETURN1')
-check(function () return -4//0 end, 'LOADI', 'IDIVI', 'RETURN1')
+check(function () return k3/0 end, 'LOADI', 'DIVI', 'MMBINI', 'RETURN1')
+check(function () return 0%0 end, 'LOADI', 'MODI', 'MMBINI', 'RETURN1')
+check(function () return -4//0 end, 'LOADI', 'IDIVI', 'MMBINI', 'RETURN1')
 check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'RETURN1')
-check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'RETURN1')
+check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'MMBIN', 'RETURN1')
 
 -- basic 'for' loops
 check(function () for i = -10, 10.5 do end end,
@@ -379,7 +386,7 @@
           if b then break else a = a + 1 end
         end
       end,
-'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'JMP', 'RETURN0')
+'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0')
 
 checkequal(
 function (a) while a < 10 do a = a + 1 end end,
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
index 48f4c5b..81d848a 100644
--- a/testes/coroutine.lua
+++ b/testes/coroutine.lua
@@ -751,7 +751,7 @@
 assert(run(function () return 1 >> a end, {"shr"}) == 1 >> 10)
 assert(run(function () return a << 2 end, {"shl"}) == 10 << 2)
 assert(run(function () return 1 << a end, {"shl"}) == 1 << 10)
-assert(run(function () return a ~ 2 end, {"bxor"}) == 10 ~ 2)
+assert(run(function () return 2 ~ a end, {"bxor"}) == 2 ~ 10)
 
 
 assert(run(function () return a..b end, {"concat"}) == "1012")