Browse Source

optimizations for "while 1", "until nil", and the like

Roberto Ierusalimschy 25 years ago
parent
commit
2e1b32d873
2 changed files with 102 additions and 54 deletions
  1. 101 52
      lcode.c
  2. 1 2
      lcode.h

+ 101 - 52
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 1.34 2000/06/05 14:56:18 roberto Exp roberto $
+** $Id: lcode.c,v 1.35 2000/06/12 13:52:05 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -268,20 +268,29 @@ void luaK_concat (FuncState *fs, int *l1, int l2) {
 
 
 static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
+  int prevpos;  /* position of last instruction */
   Instruction *previous;
-  int *golist = &v->u.l.f;
-  int *exitlist = &v->u.l.t;
-  if (invert) {  /* interchange `golist' and `exitlist' */
-    int *temp = golist; golist = exitlist; exitlist = temp;
+  int *golist, *exitlist;
+  if (!invert) {
+    golist = &v->u.l.f;    /* go if false */
+    exitlist = &v->u.l.t;  /* exit if true */
+  }
+  else {
+    golist = &v->u.l.t;    /* go if true */
+    exitlist = &v->u.l.f;  /* exit if false */
   }
   discharge1(fs, v);
-  previous = &fs->f->code[fs->pc-1];
-  LUA_ASSERT(L, GET_OPCODE(*previous) != OP_SETLINE, "bad place to set line");
+  prevpos = fs->pc-1;
+  previous = &fs->f->code[prevpos];
+  LUA_ASSERT(L, *previous==previous_instruction(fs), "no jump allowed here");
+  LUA_ASSERT(L, GET_OPCODE(*previous) != OP_SETLINE, "no setline allowed here");
   if (!ISJUMP(GET_OPCODE(*previous)))
-    luaK_code1(fs, jump, NO_JUMP);
-  else if (invert)
-    SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
-  luaK_concat(fs, exitlist, fs->pc-1);  /* insert last jump in `exitlist' */
+    prevpos = luaK_code1(fs, jump, NO_JUMP);
+  else {  /* last instruction is already a jump */
+    if (invert)
+      SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+  }
+  luaK_concat(fs, exitlist, prevpos);  /* insert last jump in `exitlist' */
   luaK_patchlist(fs, *golist, luaK_getlabel(fs));
   *golist = NO_JUMP;
 }
@@ -292,7 +301,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) {
 }
 
 
-void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) {
+static void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) {
   luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT);
 }
 
@@ -319,8 +328,8 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
       int j = NO_JUMP;  /*  eventual  jump over values */
       int p_nil = NO_JUMP;  /* position of an eventual PUSHNIL */
       int p_1 = NO_JUMP;  /* position of an eventual PUSHINT */
-      if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF) ||
-                              need_value(fs, v->u.l.t, OP_JMPONT)) {
+      if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
+                           || need_value(fs, v->u.l.t, OP_JMPONT)) {
         /* expression needs values */
         if (ISJUMP(previous))
           luaK_concat(fs, &v->u.l.t, fs->pc-1);  /* put `previous' in t. list */
@@ -425,34 +434,33 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
   int delta = luaK_opproperties[o].delta;
   int optm = 0;  /* 1 when there is an optimization */
   switch (o) {
-
-    case OP_CLOSURE:
+    case OP_CLOSURE: {
       delta = -arg2+1;
       break;
-
-    case OP_SETTABLE:
+    }
+    case OP_SETTABLE: {
       delta = -arg2;
       break;
-
-    case OP_SETLIST:
+    }
+    case OP_SETLIST: {
       if (arg2 == 0) return NO_JUMP;  /* nothing to do */
       delta = -arg2;
       break;
-
-    case OP_SETMAP:
+    }
+    case OP_SETMAP: {
       if (arg1 == 0) return NO_JUMP;  /* nothing to do */
       delta = -2*arg1;
       break;
-
-    case OP_RETURN:
+    }
+    case OP_RETURN: {
       if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) {
         SET_OPCODE(i, OP_TAILCALL);
         SETARG_B(i, arg1);
         optm = 1;
       }
       break;
-
-    case OP_PUSHNIL:
+    }
+    case OP_PUSHNIL: {
       if (arg1 == 0) return NO_JUMP;  /* nothing to do */
       delta = arg1;
       switch(GET_OPCODE(i)) {
@@ -460,8 +468,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
         default: break;
       }
       break;
-
-    case OP_POP:
+    }
+    case OP_POP: {
       if (arg1 == 0) return NO_JUMP;  /* nothing to do */
       delta = -arg1;
       switch(GET_OPCODE(i)) {
@@ -469,8 +477,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
         default: break;
       }
       break;
-
-    case OP_GETTABLE:
+    }
+    case OP_GETTABLE: {
       switch(GET_OPCODE(i)) {
         case OP_PUSHSTRING:  /* `t.x' */
           SET_OPCODE(i, OP_GETDOTTED);
@@ -483,15 +491,15 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
         default: break;
       }
       break;
-
-    case OP_ADD:
+    }
+    case OP_ADD: {
       switch(GET_OPCODE(i)) {
         case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break;  /* `a+k' */
         default: break;
       }
       break;
-
-    case OP_SUB:
+    }
+    case OP_SUB: {
       switch(GET_OPCODE(i)) {
         case OP_PUSHINT:  /* `a-k' */
           i = CREATE_S(OP_ADDI, -GETARG_S(i));
@@ -500,8 +508,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
         default: break;
       }
       break;
-
-    case OP_CONCAT:
+    }
+    case OP_CONCAT: {
       delta = -arg1+1;
       switch(GET_OPCODE(i)) {
         case OP_CONCAT:  /* `a..b..c' */
@@ -511,8 +519,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
         default: break;
       }
       break;
-
-    case OP_MINUS:
+    }
+    case OP_MINUS: {
       switch(GET_OPCODE(i)) {
         case OP_PUSHINT:  /* `-k' */
           SETARG_S(i, -GETARG_S(i));
@@ -525,50 +533,91 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
         default: break;
       }
       break;
-
-    case OP_JMPNE:
+    }
+    case OP_JMPNE: {
       if (i == CREATE_U(OP_PUSHNIL, 1)) {  /* `a~=nil' */
         i = CREATE_S(OP_JMPT, NO_JUMP);
         optm = 1;
       }
       break;
-
-    case OP_JMPEQ:
+    }
+    case OP_JMPEQ: {
       if (i == CREATE_U(OP_PUSHNIL, 1)) {  /* `a==nil' */
         i = CREATE_0(OP_NOT);
         delta = -1;  /* just undo effect of previous PUSHNIL */
         optm = 1;
       }
       break;
-
+    }
     case OP_JMPT:
+    case OP_JMPONT: {
+      switch (GET_OPCODE(i)) {
+        case OP_NOT: {
+          i = CREATE_S(OP_JMPF, NO_JUMP);
+          optm = 1;
+          break;
+        }
+        case OP_PUSHINT: {
+          if (o == OP_JMPT) {  /* JMPONT must keep original integer value */
+            i = CREATE_S(OP_JMP, NO_JUMP);
+            optm = 1;
+          }
+          break;
+        }
+        case OP_PUSHNIL: {
+          if (GETARG_U(i) == 1) {
+            fs->pc--;  /* erase previous instruction */
+            luaK_deltastack(fs, -1);  /* correct stack */
+            return NO_JUMP; 
+          }
+          break;
+        }
+        default: break;
+      }
+      break;
+    }
     case OP_JMPF:
-    case OP_JMPONT:
-    case OP_JMPONF:
+    case OP_JMPONF: {
       switch (GET_OPCODE(i)) {
-        case OP_NOT: i = CREATE_S(invertjump(o), NO_JUMP); optm = 1; break;
+        case OP_NOT: {
+          i = CREATE_S(OP_JMPT, NO_JUMP);
+          optm = 1;
+          break;
+        }
+        case OP_PUSHINT: {  /* `while 1 do ...' */
+          fs->pc--;  /* erase previous instruction */
+          luaK_deltastack(fs, -1);  /* correct stack */
+          return NO_JUMP; 
+        }
+        case OP_PUSHNIL: {  /* `repeat ... until nil' */
+          if (GETARG_U(i) == 1) {
+            i = CREATE_S(OP_JMP, NO_JUMP);
+            optm = 1;
+          }
+          break;
+        }
         default: break;
       }
       break;
-
+    }
     case OP_GETDOTTED:
     case OP_GETINDEXED:
     case OP_TAILCALL:
-    case OP_ADDI:
+    case OP_ADDI: {
       LUA_INTERNALERROR(L, "instruction used only for optimizations");
       break;
-
-    default:
+    }
+    default: {
       LUA_ASSERT(L, delta != VD, "invalid delta");
       break;
-
+    }
   }
   luaK_deltastack(fs, delta);
   if (optm) {  /* optimize: put instruction in place of last one */
       fs->f->code[fs->pc-1] = i;  /* change previous instruction */
       return fs->pc-1;  /* do not generate new instruction */
   }
-  /* build new instruction */
+  /* else build new instruction */
   switch ((enum Mode)luaK_opproperties[o].mode) {
     case iO: i = CREATE_0(o); break;
     case iU: i = CREATE_U(o, arg1); break;

+ 1 - 2
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.12 2000/04/12 18:47:03 roberto Exp roberto $
+** $Id: lcode.h,v 1.13 2000/05/22 18:44:46 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -36,7 +36,6 @@ int luaK_jump (FuncState *fs);
 void luaK_patchlist (FuncState *fs, int list, int target);
 void luaK_concat (FuncState *fs, int *l1, int l2);
 void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
-void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue);
 int luaK_getlabel (FuncState *fs);
 void luaK_deltastack (FuncState *fs, int delta);
 void luaK_kstr (LexState *ls, int c);