Browse Source

optimization for `while' (first version)

Roberto Ierusalimschy 23 years ago
parent
commit
b487975344
3 changed files with 64 additions and 15 deletions
  1. 17 10
      lcode.c
  2. 4 1
      lcode.h
  3. 43 4
      lparser.c

+ 17 - 10
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 1.99 2002/05/07 17:36:56 roberto Exp roberto $
+** $Id: lcode.c,v 1.100 2002/05/09 14:14:34 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -39,6 +39,13 @@ void luaK_nil (FuncState *fs, int from, int n) {
 }
 
 
+void luaK_moveexp (expdesc *e, int offset) {
+  if (e->t != NO_JUMP) e->t += offset;
+  if (e->f != NO_JUMP) e->f += offset;
+  if (e->k == VRELOCABLE || e->k == VJMP) e->info += offset;
+}
+
+
 int luaK_jump (FuncState *fs) {
   int j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
   if (j == fs->lasttarget) {  /* possible jumps to this jump? */
@@ -515,12 +522,10 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
     }
   }
   luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
-  luaK_patchtohere(fs, e->t);
-  e->t = NO_JUMP;
 }
 
 
-static void luaK_goiffalse (FuncState *fs, expdesc *e) {
+void luaK_goiffalse (FuncState *fs, expdesc *e) {
   int pc;  /* pc of last jump */
   luaK_dischargevars(fs, e);
   switch (e->k) {
@@ -542,8 +547,6 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) {
     }
   }
   luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
-  luaK_patchtohere(fs, e->f);
-  e->f = NO_JUMP;
 }
 
 
@@ -607,10 +610,14 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
   switch (op) {
     case OPR_AND: {
       luaK_goiftrue(fs, v);
+      luaK_patchtohere(fs, v->t);
+      v->t = NO_JUMP;
       break;
     }
     case OPR_OR: {
       luaK_goiffalse(fs, v);
+      luaK_patchtohere(fs, v->f);
+      v->f = NO_JUMP;
       break;
     }
     case OPR_CONCAT: {
@@ -727,7 +734,7 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
 }
 
 
-static int luaK_code (FuncState *fs, Instruction i) {
+int luaK_code (FuncState *fs, Instruction i, int line) {
   Proto *f = fs->f;
   int oldsize = f->sizecode;
   /* put new instruction in code array */
@@ -736,19 +743,19 @@ static int luaK_code (FuncState *fs, Instruction i) {
   f->code[fs->pc] = i;
   if (f->sizecode != oldsize)
     luaM_reallocvector(fs->L, f->lineinfo, oldsize, f->sizecode, int);
-  f->lineinfo[fs->pc] = fs->ls->lastline;
+  f->lineinfo[fs->pc] = line;
   return fs->pc++;
 }
 
 
 int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
   lua_assert(getOpMode(o) == iABC);
-  return luaK_code(fs, CREATE_ABC(o, a, b, c));
+  return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
 }
 
 
 int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
   lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
-  return luaK_code(fs, CREATE_ABx(o, a, bc));
+  return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
 }
 

+ 4 - 1
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.32 2002/04/24 20:07:46 roberto Exp roberto $
+** $Id: lcode.h,v 1.33 2002/05/07 17:36:56 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -41,6 +41,7 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
 
 #define luaK_codeAsBx(fs,o,A,sBx)	luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
 
+int luaK_code (FuncState *fs, Instruction i, int line);
 int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
 int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
 void luaK_nil (FuncState *fs, int from, int n);
@@ -54,7 +55,9 @@ void luaK_exp2val (FuncState *fs, expdesc *e);
 int luaK_exp2RK (FuncState *fs, expdesc *e);
 void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
 void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
+void luaK_moveexp (expdesc *e, int offset);
 void luaK_goiftrue (FuncState *fs, expdesc *e);
+void luaK_goiffalse (FuncState *fs, expdesc *e);
 void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
 void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
 int luaK_jump (FuncState *fs);

+ 43 - 4
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 1.178 2002/04/24 20:07:46 roberto Exp roberto $
+** $Id: lparser.c,v 1.179 2002/05/07 17:36:56 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -946,22 +946,61 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
 static void cond (LexState *ls, expdesc *v) {
   /* cond -> exp */
   expr(ls, v);  /* read condition */
+  if (v->k == VNIL) v->k = VFALSE;  /* `falses' are all equal here */
   luaK_goiftrue(ls->fs, v);
+  luaK_patchtohere(ls->fs, v->t);
 }
 
 
+/*
+** The while statement optimizes its code by coding the condition
+** after its body (and thus avoiding one jump in the loop).
+*/
+
+/*
+** maximum size of expressions for optimizing `while' code
+*/
+#ifndef MAXEXPWHILE
+#define MAXEXPWHILE	100
+#endif
+
+/*
+** the call `luaK_goiffalse' may grow the size of an expression by
+** at most this:
+*/
+#define EXTRAEXP	5
+
 static void whilestat (LexState *ls, int line) {
   /* whilestat -> WHILE cond DO block END */
+  Instruction codeexp[MAXEXPWHILE + EXTRAEXP];
+  int lineexp = 0;
+  int i;
+  int sizeexp;
   FuncState *fs = ls->fs;
   int while_init = luaK_getlabel(fs);
   expdesc v;
   BlockCnt bl;
-  enterblock(fs, &bl, 1);
   next(ls);
-  cond(ls, &v);
+  expr(ls, &v);
+  if (v.k == VK) v.k = VTRUE;  /* `trues' are all equal here */
+  lineexp = ls->linenumber;
+  luaK_goiffalse(fs, &v);
+  sizeexp = fs->pc - while_init;
+  if (sizeexp > MAXEXPWHILE) 
+    luaX_syntaxerror(ls, "while condition too complex");
+  fs->pc = while_init;  /* remove `exp' code */
+  luaK_getlabel(fs);
+  for (i = 0; i < sizeexp; i++)  /* save `exp' code */
+    codeexp[i] = fs->f->code[while_init + i];
+  luaK_jump(fs);
+  enterblock(fs, &bl, 1);
   check(ls, TK_DO);
   block(ls);
-  luaK_patchlist(fs, luaK_jump(fs), while_init);
+  luaK_patchtohere(fs, while_init);  /* initial jump jumps to here */
+  luaK_moveexp(&v, fs->pc - while_init);  /* correct pointers */
+  for (i=0; i<sizeexp; i++)
+    luaK_code(fs, codeexp[i], lineexp);
+  luaK_patchlist(fs, v.t, while_init+1);
   luaK_patchtohere(fs, v.f);
   check_match(ls, TK_END, TK_WHILE, line);
   leaveblock(fs);