Browse Source

using register 'k' for conditions in tests (we only need one bit there)

Roberto Ierusalimschy 7 years ago
parent
commit
ff5fe51044
3 changed files with 120 additions and 92 deletions
  1. 58 36
      lcode.c
  2. 18 12
      lopcodes.h
  3. 44 44
      lvm.c

+ 58 - 36
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.135 2017/11/22 19:15:44 roberto Exp roberto $
+** $Id: lcode.c,v 2.136 2017/11/23 19:29:04 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -160,8 +160,8 @@ void luaK_ret (FuncState *fs, int first, int nret) {
 ** Code a "conditional jump", that is, a test or comparison opcode
 ** followed by a jump. Return jump position.
 */
-static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
-  luaK_codeABC(fs, op, A, B, C);
+static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) {
+  luaK_codeABCk(fs, op, A, B, C, k);
   return luaK_jump(fs);
 }
 
@@ -206,7 +206,7 @@ static int patchtestreg (FuncState *fs, int node, int reg) {
   else {
      /* no register to put value or register already has the value;
         change instruction to simple test */
-    *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i), 0);
+    *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, 0, GETARG_k(*i));
   }
   return 1;
 }
@@ -969,7 +969,7 @@ static void negatecondition (FuncState *fs, expdesc *e) {
   Instruction *pc = getjumpcontrol(fs, e->u.info);
   lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
                                            GET_OPCODE(*pc) != OP_TEST);
-  SETARG_B(*pc, !(GETARG_B(*pc)));
+  SETARG_k(*pc, (GETARG_k(*pc) ^ 1));
 }
 
 
@@ -984,13 +984,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
     Instruction ie = getinstruction(fs, e);
     if (GET_OPCODE(ie) == OP_NOT) {
       fs->pc--;  /* remove previous OP_NOT */
-      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
+      return condjump(fs, OP_TEST, GETARG_B(ie), 0, 0, !cond);
     }
     /* else go through */
   }
   discharge2anyreg(fs, e);
   freeexp(fs, e);
-  return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
+  return condjump(fs, OP_TESTSET, NO_REG, e->u.info, 0, cond);
 }
 
 
@@ -1276,25 +1276,37 @@ static void codecommutative (FuncState *fs, OpCode op,
 
 /*
 ** Emit code for order comparisons.
-** 'e1' was already put in register by 'luaK_infix'.
+** When the first operand is an integral value in the proper range,
+** change (A < B) to (!(B <= A)) and (A <= B) to (!(B < A)) so that
+** it can use an immediate operand. In this case, C indicates this
+** change, for cases that cannot assume a total order (NaN and 
+** metamethods).
 */
-static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
-  int rk1 = check_exp(e1->k == VNONRELOC, e1->u.info);
-  int rk2 = luaK_exp2anyreg(fs, e2);
-  freeexps(fs, e1, e2);
-  switch (opr) {
-    case OPR_GT: case OPR_GE: {
-      /* '(a > b)' ==> '(b < a)';  '(a >= b)' ==> '(b <= a)' */
-      OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
-      e1->u.info = condjump(fs, op, rk2, 1, rk1);  /* invert operands */
-      break;
-    }
-    default: {  /* '==', '<', '<=' use their own opcodes */
-      OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
-      e1->u.info = condjump(fs, op, rk1, 1, rk2);
-      break;
-    }
+static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+  int r1, r2;
+  int cond = 1;
+  int C = 0;
+  lua_Integer im;
+  if (isSCnumber(e2, &im)) {
+    /* use immediate operand */
+    r1 = luaK_exp2anyreg(fs, e1);
+    r2 = cast_int(im);
+    op = cast(OpCode, (op - OP_LT) + OP_LTI);
+  }
+  else if (isSCnumber(e1, &im)) {
+    /* transform (A < B) to (!(B <= A)) and (A <= B) to (!(B < A)) */
+    r1 = luaK_exp2anyreg(fs, e2);
+    r2 = cast_int(im);
+    op = (op == OP_LT) ? OP_LEI : OP_LTI;
+    cond = 0;  /* negate original test */
+    C = 1;  /* indication that it used the transformations */
   }
+  else {  /* regular case, compare two registers */
+    r1 = luaK_exp2anyreg(fs, e1);
+    r2 = luaK_exp2anyreg(fs, e2);
+  }
+  freeexps(fs, e1, e2);
+  e1->u.info = condjump(fs, op, r1, r2, C, cond);
   e1->k = VJMP;
 }
 
@@ -1325,7 +1337,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
     r2 = luaK_exp2anyreg(fs, e2);
   }
   freeexps(fs, e1, e2);
-  e1->u.info = condjump(fs, op, r1, (opr == OPR_EQ), r2);
+  e1->u.info = condjump(fs, op, r1, r2, 0, (opr == OPR_EQ));
   e1->k = VJMP;
 }
 
@@ -1385,7 +1397,10 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
     }
     case OPR_LT: case OPR_LE:
     case OPR_GT: case OPR_GE: {
-      luaK_exp2anyreg(fs, v);
+      lua_Integer dummy;
+      if (!isSCnumber(v, &dummy))
+        luaK_exp2RK(fs, v);
+      /* else keep numeral, which may be an immediate operand */
       break;
     }
     default: lua_assert(0);
@@ -1399,9 +1414,9 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
 ** concatenation is right associative), merge second CONCAT into first
 ** one.
 */
-void luaK_posfix (FuncState *fs, BinOpr op,
+void luaK_posfix (FuncState *fs, BinOpr opr,
                   expdesc *e1, expdesc *e2, int line) {
-  switch (op) {
+  switch (opr) {
     case OPR_AND: {
       lua_assert(e1->t == NO_JUMP);  /* list closed by 'luK_infix' */
       luaK_dischargevars(fs, e2);
@@ -1432,28 +1447,35 @@ void luaK_posfix (FuncState *fs, BinOpr op,
       break;
     }
     case OPR_ADD: case OPR_MUL: {
-      if (!constfolding(fs, op + LUA_OPADD, e1, e2))
-        codecommutative(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
+      if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
+        codecommutative(fs, cast(OpCode, opr + OP_ADD), e1, e2, line);
       break;
     }
     case OPR_SUB: case OPR_DIV:
     case OPR_IDIV: case OPR_MOD: case OPR_POW: {
-      if (!constfolding(fs, op + LUA_OPADD, e1, e2))
-        codearith(fs, cast(OpCode, op + OP_ADD), e1, e2, 0, line);
+      if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
+        codearith(fs, cast(OpCode, opr + OP_ADD), e1, e2, 0, line);
       break;
     }
     case OPR_BAND: case OPR_BOR: case OPR_BXOR:
     case OPR_SHL: case OPR_SHR: {
-      if (!constfolding(fs, op + LUA_OPADD, e1, e2))
-        codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
+      if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
+        codebinexpval(fs, cast(OpCode, opr + OP_ADD), e1, e2, line);
       break;
     }
     case OPR_EQ: case OPR_NE: {
-      codeeq(fs, op, e1, e2);
+      codeeq(fs, opr, e1, e2);
+      break;
+    }
+    case OPR_LT: case OPR_LE: {
+      OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
+      codeorder(fs, op, e1, e2);
       break;
     }
-    case OPR_LT: case OPR_LE:
     case OPR_GT: case OPR_GE: {
+      /* '(a > b)' <=> '(b < a)';  '(a >= b)' <=> '(b <= a)' */
+      OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
+      swapexps(e1, e2);
       codeorder(fs, op, e1, e2);
       break;
     }

+ 18 - 12
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.170 2017/11/22 19:15:44 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.171 2017/11/27 17:44:31 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -114,13 +114,15 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ};  /* basic instruction formats */
 #define SETARG_A(i,v)	setarg(i, v, POS_A, SIZE_A)
 
 #define GETARG_B(i)	check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
+#define GETARG_sB(i)	(GETARG_B(i) - MAXARG_sC)
 #define SETARG_B(i,v)	setarg(i, v, POS_B, SIZE_B)
 
 #define GETARG_C(i)	check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
 #define GETARG_sC(i)	(GETARG_C(i) - MAXARG_sC)
 #define SETARG_C(i,v)	setarg(i, v, POS_C, SIZE_C)
 
-#define GETARG_k(i)	(cast(int, ((i) & (1 << POS_k))))
+#define TESTARG_k(i)	(cast(int, ((i) & (1 << POS_k))))
+#define GETARG_k(i)	getarg(i, POS_k, 1)
 #define SETARG_k(i,v)	setarg(i, v, POS_k, 1)
 
 #define GETARG_Bx(i)	check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
@@ -236,17 +238,17 @@ OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
 
 OP_CLOSE,/*	A	close all upvalues >= R(A)			*/
 OP_JMP,/*	k sJ	pc += sJ  (k is used in code generation)	*/
-OP_EQ,/*	A B C	if ((R(A) == R(C)) ~= B) then pc++		*/
-OP_LT,/*	A B C	if ((R(A) <  R(C)) ~= B) then pc++		*/
-OP_LE,/*	A B C	if ((R(A) <= R(C)) ~= B) then pc++		*/
+OP_EQ,/*	A B	if ((R(A) == R(B)) ~= k) then pc++		*/
+OP_LT,/*	A B	if ((R(A) <  R(B)) ~= k) then pc++		*/
+OP_LE,/*	A B	if ((R(A) <= R(B)) ~= k) then pc++		*/
 
-OP_EQK,/*	A B C	if ((R(A) == K(C)) ~= B) then pc++		*/
-OP_EQI,/*	A B C	if ((R(A) == C) ~= B) then pc++			*/
-OP_LTI,/*	A B C	if ((R(A) < C) ~= B) then pc++			*/
-OP_LEI,/*	A B C	if ((R(A) <= C) ~= B) then pc++			*/
+OP_EQK,/*	A B	if ((R(A) == K(B)) ~= k) then pc++		*/
+OP_EQI,/*	A sB	if ((R(A) == sB) ~= k) then pc++		*/
+OP_LTI,/*	A sB	if ((R(A) < sB) ~= k) then pc++			*/
+OP_LEI,/*	A sB	if ((R(A) <= sB) ~= k) then pc++		*/
 
-OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/
-OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/
+OP_TEST,/*	A 	if (not R(A) == k) then pc++			*/
+OP_TESTSET,/*	A B	if (not R(B) == k) then R(A) := R(B) else pc++	*/
 
 OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
 OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
@@ -289,9 +291,13 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 
   (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
 
-  (*) For comparisons, A specifies what condition the test should accept
+  (*) For comparisons, k specifies what condition the test should accept
   (true or false).
 
+  (*) For OP_LTI/OP_LEI, C indicates that the transformations
+  (A<B) => (!(B<=A)) or (A<=B) => (!(B<A)) were used to put the
+  constant operator on the right side.
+
   (*) All 'skips' (pc++) assume that next instruction is a jump.
 
 ===========================================================================*/

+ 44 - 44
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.317 2017/11/23 19:18:10 roberto Exp roberto $
+** $Id: lvm.c,v 2.318 2017/11/27 17:44:31 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -702,14 +702,14 @@ void luaV_finishOp (lua_State *L) {
       L->top--;
       if (ci->callstatus & CIST_LEQ) {  /* "<=" using "<" instead? */
         lua_assert(op == OP_LE ||
-                  (op == OP_LEI && !(GETARG_B(inst) & 2)) ||
-                  (op == OP_LTI && GETARG_B(inst) & 2));
+                  (op == OP_LTI && GETARG_C(inst)) ||
+                  (op == OP_LEI && !GETARG_C(inst)));
         ci->callstatus ^= CIST_LEQ;  /* clear mark */
         res = !res;  /* negate result */
       }
       lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
-      if (GETARG_B(inst) & 2) res = !res;
-      if (res != (GETARG_B(inst) & 1))  /* condition failed? */
+      if (GETARG_C(inst)) res = !res;
+      if (res != GETARG_k(inst))  /* condition failed? */
         ci->u.l.savedpc++;  /* skip jump instruction */
       break;
     }
@@ -766,7 +766,7 @@ void luaV_finishOp (lua_State *L) {
 #define RC(i)	(base+GETARG_C(i))
 #define vRC(i)	s2v(RC(i))
 #define KC(i)	(k+GETARG_C(i))
-#define RKC(i)	((GETARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i)))
+#define RKC(i)	((TESTARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i)))
 
 
 
@@ -1326,59 +1326,59 @@ void luaV_execute (lua_State *L) {
         vmbreak;
       }
       vmcase(OP_EQ) {
-        TValue *rc = vRC(i);
+        TValue *rb = vRB(i);
         int res;
-        Protect(res = luaV_equalobj(L, s2v(ra), rc));
-        if (res != GETARG_B(i))
+        Protect(res = luaV_equalobj(L, s2v(ra), rb));
+        if (res != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
         vmbreak;
       }
       vmcase(OP_LT) {
-        TValue *rc = vRC(i);
+        TValue *rb = vRB(i);
         int res;
-        if (ttisinteger(s2v(ra)) && ttisinteger(rc))
-          res = (ivalue(s2v(ra)) < ivalue(rc));
-        else if (ttisnumber(s2v(ra)) && ttisnumber(rc))
-          res = LTnum(s2v(ra), rc);
+        if (ttisinteger(s2v(ra)) && ttisinteger(rb))
+          res = (ivalue(s2v(ra)) < ivalue(rb));
+        else if (ttisnumber(s2v(ra)) && ttisnumber(rb))
+          res = LTnum(s2v(ra), rb);
         else
-          Protect(res = lessthanothers(L, s2v(ra), rc));
-        if (res != GETARG_B(i))
+          Protect(res = lessthanothers(L, s2v(ra), rb));
+        if (res != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
         vmbreak;
       }
       vmcase(OP_LE) {
-        TValue *rc = vRC(i);
+        TValue *rb = vRB(i);
         int res;
-        if (ttisinteger(s2v(ra)) && ttisinteger(rc))
-          res = (ivalue(s2v(ra)) <= ivalue(rc));
-        else if (ttisnumber(s2v(ra)) && ttisnumber(rc))
-          res = LEnum(s2v(ra), rc);
+        if (ttisinteger(s2v(ra)) && ttisinteger(rb))
+          res = (ivalue(s2v(ra)) <= ivalue(rb));
+        else if (ttisnumber(s2v(ra)) && ttisnumber(rb))
+          res = LEnum(s2v(ra), rb);
         else
-          Protect(res = lessequalothers(L, s2v(ra), rc));
-        if (res != GETARG_B(i))
+          Protect(res = lessequalothers(L, s2v(ra), rb));
+        if (res != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
         vmbreak;
       }
       vmcase(OP_EQK) {
-        TValue *rc = KC(i);
+        TValue *rb = KB(i);
         /* basic types do not use '__eq'; we can use raw equality */
-        if (luaV_equalobj(NULL, s2v(ra), rc) != GETARG_B(i))
+        if (luaV_equalobj(NULL, s2v(ra), rb) != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
         vmbreak;
       }
       vmcase(OP_EQI) {
-        int ic = GETARG_sC(i);
-        if ((ttisinteger(s2v(ra)) ? (ivalue(s2v(ra)) == ic)
-            :ttisfloat(s2v(ra)) ? luai_numeq(fltvalue(s2v(ra)), cast_num(ic))
-            : 0) != GETARG_B(i))
+        int im = GETARG_sB(i);
+        if ((ttisinteger(s2v(ra)) ? (ivalue(s2v(ra)) == im)
+            :ttisfloat(s2v(ra)) ? luai_numeq(fltvalue(s2v(ra)), cast_num(im))
+            : 0) != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
@@ -1386,17 +1386,17 @@ void luaV_execute (lua_State *L) {
       }
       vmcase(OP_LTI) {
         int res;
-        int ic = GETARG_sC(i);
+        int im = GETARG_sB(i);
         if (ttisinteger(s2v(ra)))
-          res = (ivalue(s2v(ra)) < ic);
+          res = (ivalue(s2v(ra)) < im);
         else if (ttisfloat(s2v(ra))) {
           lua_Number f = fltvalue(s2v(ra));
-          res = (!luai_numisnan(f)) ? luai_numlt(f, cast_num(ic))
-                                    : GETARG_B(i) >> 1;  /* NaN? */
+          res = (!luai_numisnan(f)) ? luai_numlt(f, cast_num(im))
+                                    : GETARG_C(i);  /* NaN? */
         }
         else
-          Protect(res = luaT_callorderiTM(L, s2v(ra), ic, GETARG_B(i) >> 1, TM_LT));
-        if (res != (GETARG_B(i) & 1))
+          Protect(res = luaT_callorderiTM(L, s2v(ra), im, GETARG_C(i), TM_LT));
+        if (res != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
@@ -1404,32 +1404,32 @@ void luaV_execute (lua_State *L) {
       }
       vmcase(OP_LEI) {
         int res;
-        int ic = GETARG_sC(i);
+        int im = GETARG_sB(i);
         if (ttisinteger(s2v(ra)))
-          res = (ivalue(s2v(ra)) <= ic);
+          res = (ivalue(s2v(ra)) <= im);
         else if (ttisfloat(s2v(ra))) {
           lua_Number f = fltvalue(s2v(ra));
-          res = (!luai_numisnan(f)) ? luai_numle(f, cast_num(ic))
-                                    : GETARG_B(i) >> 1;  /* NaN? */
+          res = (!luai_numisnan(f)) ? luai_numle(f, cast_num(im))
+                                    : GETARG_C(i);  /* NaN? */
         }
         else
-          Protect(res = luaT_callorderiTM(L, s2v(ra), ic, GETARG_B(i) >> 1, TM_LE));
-        if (res != (GETARG_B(i) & 1))
+          Protect(res = luaT_callorderiTM(L, s2v(ra), im, GETARG_C(i), TM_LE));
+        if (res != GETARG_k(i))
           pc++;
         else
           donextjump(ci);
         vmbreak;
       }
       vmcase(OP_TEST) {
-        if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra)))
+        if (l_isfalse(s2v(ra)) == GETARG_k(i))
             pc++;
           else
-          donextjump(ci);
+            donextjump(ci);
         vmbreak;
       }
       vmcase(OP_TESTSET) {
         TValue *rb = vRB(i);
-        if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
+        if (l_isfalse(rb) == GETARG_k(i))
           pc++;
         else {
           setobj2s(L, ra, rb);