Browse Source

new opcodes 'FORLOOP1'/'FORPREP1' for "basic for" (integer variable
with increment of 1)

Roberto Ierusalimschy 7 years ago
parent
commit
d388c165ef
4 changed files with 73 additions and 18 deletions
  1. 5 1
      lopcodes.c
  2. 5 1
      lopcodes.h
  3. 36 15
      lparser.c
  4. 27 1
      lvm.c

+ 5 - 1
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.72 2017/12/04 17:41:30 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.73 2017/12/13 18:32:09 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -82,6 +82,8 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
   "RETURN",
   "RETURN0",
   "RETURN1",
+  "FORLOOP1",
+  "FORPREP1",
   "FORLOOP",
   "FORPREP",
   "TFORCALL",
@@ -160,6 +162,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0, 0, iABC)		/* OP_RETURN */
  ,opmode(0, 0, iABC)		/* OP_RETURN0 */
  ,opmode(0, 0, iABC)		/* OP_RETURN1 */
+ ,opmode(0, 1, iABx)		/* OP_FORLOOP1 */
+ ,opmode(0, 1, iABx)		/* OP_FORPREP1 */
  ,opmode(0, 1, iABx)		/* OP_FORLOOP */
  ,opmode(0, 1, iABx)		/* OP_FORPREP */
  ,opmode(0, 0, iABC)		/* OP_TFORCALL */

+ 5 - 1
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.178 2017/12/15 18:35:22 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.179 2017/12/15 18:53:48 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -267,6 +267,10 @@ OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
 OP_RETURN0,/*	  	return 						*/
 OP_RETURN1,/*	A 	return R(A)					*/
 
+OP_FORLOOP1,/*	A Bx	R(A)++;
+			if R(A) <= R(A+1) then { pc-=Bx; R(A+3)=R(A) }	*/
+OP_FORPREP1,/*	A Bx	R(A)--; pc+=Bx					*/
+
 OP_FORLOOP,/*	A Bx	R(A)+=R(A+2);
 			if R(A) <?= R(A+1) then { pc-=Bx; R(A+3)=R(A) }	*/
 OP_FORPREP,/*	A Bx	R(A)-=R(A+2); pc+=Bx				*/

+ 36 - 15
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.172 2017/12/15 13:07:10 roberto Exp roberto $
+** $Id: lparser.c,v 2.173 2017/12/18 12:33:54 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -1313,11 +1313,20 @@ static void repeatstat (LexState *ls, int line) {
 }
 
 
-static void exp1 (LexState *ls) {
+/*
+** Read an expression and generate code to put its results in next
+** stack slot. Return true if expression is a constant integer and,
+** if 'i' is not-zero, its value is equal to 'i'.
+**
+*/
+static int exp1 (LexState *ls, int i) {
   expdesc e;
+  int res;
   expr(ls, &e);
+  res = luaK_isKint(&e) && (i == 0 || i == e.u.ival);
   luaK_exp2nextreg(ls->fs, &e);
   lua_assert(e.k == VNONRELOC);
+  return res;
 }
 
 
@@ -1337,29 +1346,37 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) {
 }
 
 
-static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
+/*
+** Generate code for a 'for' loop. 'kind' can be zero (a common for
+** loop), one (a basic for loop, with integer values and increment of
+** 1), or two (a generic for loop).
+*/
+static void forbody (LexState *ls, int base, int line, int nvars, int kind) {
   /* forbody -> DO block */
   BlockCnt bl;
   FuncState *fs = ls->fs;
   int prep, endfor;
   adjustlocalvars(ls, 3);  /* control variables */
   checknext(ls, TK_DO);
-  prep = isnum ? luaK_codeABx(fs, OP_FORPREP, base, 0) : luaK_jump(fs);
+  prep = (kind == 0) ? luaK_codeABx(fs, OP_FORPREP, base, 0)
+       : (kind == 1) ? luaK_codeABx(fs, OP_FORPREP1, base, 0)
+       : luaK_jump(fs);
   enterblock(fs, &bl, 0);  /* scope for declared variables */
   adjustlocalvars(ls, nvars);
   luaK_reserveregs(fs, nvars);
   block(ls);
   leaveblock(fs);  /* end of scope for declared variables */
-  if (isnum) {  /* numeric for? */
-    fixforjump(fs, prep, luaK_getlabel(fs), 0);
-    endfor = luaK_codeABx(fs, OP_FORLOOP, base, 0);
-  }
-  else {  /* generic for */
+  if (kind == 2) {  /* generic for? */
     luaK_patchtohere(fs, prep);
     luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
     luaK_fixline(fs, line);
     endfor = luaK_codeABx(fs, OP_TFORLOOP, base + 2, 0);
   }
+  else {
+    fixforjump(fs, prep, luaK_getlabel(fs), 0);
+    endfor = (kind == 0) ? luaK_codeABx(fs, OP_FORLOOP, base, 0)
+                         : luaK_codeABx(fs, OP_FORLOOP1, base, 0);
+  }
   fixforjump(fs, endfor, prep + 1, 1);
   luaK_fixline(fs, line);
 }
@@ -1369,21 +1386,25 @@ static void fornum (LexState *ls, TString *varname, int line) {
   /* fornum -> NAME = exp,exp[,exp] forbody */
   FuncState *fs = ls->fs;
   int base = fs->freereg;
+  int basicfor = 1;  /* true if it is a "basic" 'for' (integer + 1) */
   new_localvarliteral(ls, "(for index)");
   new_localvarliteral(ls, "(for limit)");
   new_localvarliteral(ls, "(for step)");
   new_localvar(ls, varname);
   checknext(ls, '=');
-  exp1(ls);  /* initial value */
+  if (!exp1(ls, 0))  /* initial value not an integer? */
+    basicfor = 0;  /* not a basic 'for' */
   checknext(ls, ',');
-  exp1(ls);  /* limit */
-  if (testnext(ls, ','))
-    exp1(ls);  /* optional step */
+  exp1(ls, 0);  /* limit */
+  if (testnext(ls, ',')) {
+    if (!exp1(ls, 1))  /* optional step not 1? */
+      basicfor = 0;  /* not a basic 'for' */
+  }
   else {  /* default step = 1 */
     luaK_int(fs, fs->freereg, 1);
     luaK_reserveregs(fs, 1);
   }
-  forbody(ls, base, line, 1, 1);
+  forbody(ls, base, line, 1, basicfor);
 }
 
 
@@ -1408,7 +1429,7 @@ static void forlist (LexState *ls, TString *indexname) {
   line = ls->linenumber;
   adjust_assign(ls, 3, explist(ls, &e), &e);
   luaK_checkstack(fs, 3);  /* extra space to call generator */
-  forbody(ls, base, line, nvars - 3, 0);
+  forbody(ls, base, line, nvars - 3, 2);
 }
 
 

+ 27 - 1
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.324 2017/12/04 17:41:30 roberto Exp roberto $
+** $Id: lvm.c,v 2.326 2017/12/18 17:49:31 roberto Exp $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -1564,6 +1564,32 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         }
         return;
       }
+      vmcase(OP_FORLOOP1) {
+        lua_Integer idx = intop(+, ivalue(vra), 1); /* increment index */
+        lua_Integer limit = ivalue(s2v(ra + 1));
+        if (idx <= limit) {
+          pc -= GETARG_Bx(i);  /* jump back */
+          chgivalue(vra, idx);  /* update internal index... */
+          setivalue(s2v(ra + 3), idx);  /* ...and external index */
+        }
+        updatetrap(ci);
+        vmbreak;
+      }
+      vmcase(OP_FORPREP1) {
+        TValue *init = vra;
+        TValue *plimit = s2v(ra + 1);
+        lua_Integer ilimit, initv;
+        int stopnow;
+        if (!forlimit(plimit, &ilimit, 1, &stopnow)) {
+            savepc(L);  /* for the error message */
+            luaG_runerror(L, "'for' limit must be a number");
+        }
+        initv = (stopnow ? 0 : ivalue(init));
+        setivalue(plimit, ilimit);
+        setivalue(init, intop(-, initv, 1));
+        pc += GETARG_Bx(i);
+        vmbreak;
+      }
       vmcase(OP_FORLOOP) {
         if (ttisinteger(vra)) {  /* integer loop? */
           lua_Integer step = ivalue(s2v(ra + 2));