Explorar o código

constant folding optimizations

Roberto Ierusalimschy %!s(int64=20) %!d(string=hai) anos
pai
achega
e251e84e0f
Modificáronse 1 ficheiros con 134 adicións e 93 borrados
  1. 134 93
      lcode.c

+ 134 - 93
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.16 2005/08/29 20:49:21 roberto Exp roberto $
+** $Id: lcode.c,v 2.17 2005/09/30 14:23:33 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -27,6 +27,11 @@
 #define hasjumps(e)	((e)->t != (e)->f)
 
 
+static int isnumeral(FuncState *fs, expdesc *e)	{
+  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
+}
+
+
 void luaK_nil (FuncState *fs, int from, int n) {
   Instruction *previous;
   if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
@@ -213,7 +218,7 @@ static void freereg (FuncState *fs, int reg) {
 
 static void freeexp (FuncState *fs, expdesc *e) {
   if (e->k == VNONRELOC)
-    freereg(fs, e->info);
+    freereg(fs, e->u.s.info);
 }
 
 
@@ -283,7 +288,7 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
 void luaK_setoneret (FuncState *fs, expdesc *e) {
   if (e->k == VCALL) {  /* expression is an open function call? */
     e->k = VNONRELOC;
-    e->info = GETARG_A(getcode(fs, e));
+    e->u.s.info = GETARG_A(getcode(fs, e));
   }
   else if (e->k == VVARARG) {
     SETARG_B(getcode(fs, e), 2);
@@ -299,19 +304,19 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
       break;
     }
     case VUPVAL: {
-      e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0);
+      e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
       e->k = VRELOCABLE;
       break;
     }
     case VGLOBAL: {
-      e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info);
+      e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
       e->k = VRELOCABLE;
       break;
     }
     case VINDEXED: {
-      freereg(fs, e->aux);
-      freereg(fs, e->info);
-      e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux);
+      freereg(fs, e->u.s.aux);
+      freereg(fs, e->u.s.info);
+      e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
       e->k = VRELOCABLE;
       break;
     }
@@ -343,7 +348,11 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
       break;
     }
     case VK: {
-      luaK_codeABx(fs, OP_LOADK, reg, e->info);
+      luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
+      break;
+    }
+    case VKNUM: {
+      luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
       break;
     }
     case VRELOCABLE: {
@@ -352,8 +361,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
       break;
     }
     case VNONRELOC: {
-      if (reg != e->info)
-        luaK_codeABC(fs, OP_MOVE, reg, e->info, 0);
+      if (reg != e->u.s.info)
+        luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
       break;
     }
     default: {
@@ -361,7 +370,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
       return;  /* nothing to do... */
     }
   }
-  e->info = reg;
+  e->u.s.info = reg;
   e->k = VNONRELOC;
 }
 
@@ -377,7 +386,7 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) {
 static void exp2reg (FuncState *fs, expdesc *e, int reg) {
   discharge2reg(fs, e, reg);
   if (e->k == VJMP)
-    luaK_concat(fs, &e->t, e->info);  /* put this jump in `t' list */
+    luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */
   if (hasjumps(e)) {
     int final;  /* position after whole expression */
     int p_f = NO_JUMP;  /* position of an eventual LOAD false */
@@ -395,7 +404,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
     patchlistaux(fs, e->t, final, reg, p_t);
   }
   e->f = e->t = NO_JUMP;
-  e->info = reg;
+  e->u.s.info = reg;
   e->k = VNONRELOC;
 }
 
@@ -411,14 +420,14 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
 int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
   luaK_dischargevars(fs, e);
   if (e->k == VNONRELOC) {
-    if (!hasjumps(e)) return e->info;  /* exp is already in a register */ 
-    if (e->info >= fs->nactvar) {  /* reg. is not a local? */
-      exp2reg(fs, e, e->info);  /* put value on it */
-      return e->info;
+    if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */
+    if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */
+      exp2reg(fs, e, e->u.s.info);  /* put value on it */
+      return e->u.s.info;
     }
   }
   luaK_exp2nextreg(fs, e);  /* default */
-  return e->info;
+  return e->u.s.info;
 }
 
 
@@ -433,19 +442,22 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
 int luaK_exp2RK (FuncState *fs, expdesc *e) {
   luaK_exp2val(fs, e);
   switch (e->k) {
+    case VKNUM:
     case VTRUE:
     case VFALSE:
     case VNIL: {
       if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
-        e->info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
+        e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
+                      (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
+                                        boolK(fs, (e->k == VTRUE));
         e->k = VK;
-        return RKASK(e->info);
+        return RKASK(e->u.s.info);
       }
       else break;
     }
     case VK: {
-      if (e->info <= MAXINDEXRK)  /* constant fit in argC? */
-        return RKASK(e->info);
+      if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */
+        return RKASK(e->u.s.info);
       else break;
     }
     default: break;
@@ -459,22 +471,22 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
   switch (var->k) {
     case VLOCAL: {
       freeexp(fs, ex);
-      exp2reg(fs, ex, var->info);
+      exp2reg(fs, ex, var->u.s.info);
       return;
     }
     case VUPVAL: {
       int e = luaK_exp2anyreg(fs, ex);
-      luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0);
+      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
       break;
     }
     case VGLOBAL: {
       int e = luaK_exp2anyreg(fs, ex);
-      luaK_codeABx(fs, OP_SETGLOBAL, e, var->info);
+      luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
       break;
     }
     case VINDEXED: {
       int e = luaK_exp2RK(fs, ex);
-      luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e);
+      luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
       break;
     }
     default: {
@@ -492,15 +504,15 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
   freeexp(fs, e);
   func = fs->freereg;
   luaK_reserveregs(fs, 2);
-  luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key));
+  luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
   freeexp(fs, key);
-  e->info = func;
+  e->u.s.info = func;
   e->k = VNONRELOC;
 }
 
 
 static void invertjump (FuncState *fs, expdesc *e) {
-  Instruction *pc = getjumpcontrol(fs, e->info);
+  Instruction *pc = getjumpcontrol(fs, e->u.s.info);
   lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
                                            GET_OPCODE(*pc) != OP_TEST);
   SETARG_A(*pc, !(GETARG_A(*pc)));
@@ -518,7 +530,7 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
   }
   discharge2anyreg(fs, e);
   freeexp(fs, e);
-  return condjump(fs, OP_TESTSET, NO_REG, e->info, cond);
+  return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
 }
 
 
@@ -526,7 +538,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
   int pc;  /* pc of last jump */
   luaK_dischargevars(fs, e);
   switch (e->k) {
-    case VK: case VTRUE: {
+    case VK: case VKNUM: case VTRUE: {
       pc = NO_JUMP;  /* always true; do nothing */
       break;
     }
@@ -536,7 +548,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
     }
     case VJMP: {
       invertjump(fs, e);
-      pc = e->info;
+      pc = e->u.s.info;
       break;
     }
     default: {
@@ -563,7 +575,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
       break;
     }
     case VJMP: {
-      pc = e->info;
+      pc = e->u.s.info;
       break;
     }
     default: {
@@ -584,7 +596,7 @@ static void codenot (FuncState *fs, expdesc *e) {
       e->k = VTRUE;
       break;
     }
-    case VK: case VTRUE: {
+    case VK: case VKNUM: case VTRUE: {
       e->k = VFALSE;
       break;
     }
@@ -596,7 +608,7 @@ static void codenot (FuncState *fs, expdesc *e) {
     case VNONRELOC: {
       discharge2anyreg(fs, e);
       freeexp(fs, e);
-      e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0);
+      e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
       e->k = VRELOCABLE;
       break;
     }
@@ -613,34 +625,79 @@ static void codenot (FuncState *fs, expdesc *e) {
 
 
 void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
-  t->aux = luaK_exp2RK(fs, k);
+  t->u.s.aux = luaK_exp2RK(fs, k);
   t->k = VINDEXED;
 }
 
 
+static int constfolding (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+  lua_Number v1, v2, r;
+  if (!isnumeral(fs, e1) || !isnumeral(fs, e2)) return 0;
+  v1 = e1->u.nval;
+  v2 = e2->u.nval;
+  switch (op) {
+    case OP_ADD: r = luai_numadd(fs->L, v1, v2); break;
+    case OP_SUB: r = luai_numsub(fs->L, v1, v2); break;
+    case OP_MUL: r = luai_nummul(fs->L, v1, v2); break;
+    case OP_DIV:
+      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
+      r = luai_numdiv(fs->L, v1, v2); break;
+    case OP_MOD: r = luai_nummod(fs->L, v1, v2); break;
+    case OP_POW: r = luai_numpow(fs->L, v1, v2); break;
+    case OP_UNM: r = luai_numunm(fs->L, v1); break;
+    case OP_LEN: return 0;  /* no constant folding for 'len' */
+    default: lua_assert(0); r = 0; break;
+  }
+  if (r != r) return 0;  /* do not attempt to produce NaN */
+  e1->u.nval = r;
+  return 1;
+}
+
+
+static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+  if (constfolding(fs, op, e1, e2))
+    return;
+  else {
+    int o1 = luaK_exp2RK(fs, e1);
+    int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
+    freeexp(fs, e2);
+    freeexp(fs, e1);
+    e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
+    e1->k = VRELOCABLE;
+  }
+}
+
+
+static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
+                                                          expdesc *e2) {
+  int o1 = luaK_exp2RK(fs, e1);
+  int o2 = luaK_exp2RK(fs, e2);
+  freeexp(fs, e2);
+  freeexp(fs, e1);
+  if (cond == 0 && op != OP_EQ) {
+    int temp;  /* exchange args to replace by `<' or `<=' */
+    temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
+    cond = 1;
+  }
+  e1->u.s.info = condjump(fs, op, cond, o1, o2);
+  e1->k = VJMP;
+}
+
+
 void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+  expdesc e2;
+  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
   switch (op) {
     case OPR_MINUS: {
-      luaK_exp2val(fs, e);
-      if (e->k == VK && ttisnumber(&fs->f->k[e->info]))
-        e->info = luaK_numberK(fs, luai_numunm(L, nvalue(&fs->f->k[e->info])));
-      else {
-        luaK_exp2anyreg(fs, e);
-        freeexp(fs, e);
-        e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0);
-        e->k = VRELOCABLE;
-      }
-      break;
-    }
-    case OPR_NOT: {
-      codenot(fs, e);
+      if (e->k == VK)
+        luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
+      codearith(fs, OP_UNM, e, &e2);
       break;
     }
+    case OPR_NOT: codenot(fs, e); break;
     case OPR_LEN: {
-      luaK_exp2anyreg(fs, e);
-      freeexp(fs, e);
-      e->info = luaK_codeABC(fs, OP_LEN, 0, e->info, 0);
-      e->k = VRELOCABLE;
+      luaK_exp2anyreg(fs, e);  /* cannot operate on constants */
+      codearith(fs, OP_LEN, e, &e2);
       break;
     }
     default: lua_assert(0);
@@ -663,74 +720,58 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
       break;
     }
     default: {
-      luaK_exp2RK(fs, v);
+      if (!isnumeral(fs, v)) luaK_exp2RK(fs, v);
       break;
     }
   }
 }
 
 
-static void codebinop (FuncState *fs, expdesc *res, BinOpr op,
-                       int o1, int o2) {
-  if (op <= OPR_POW) {  /* arithmetic operator? */
-    OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD);  /* ORDER OP */
-    res->info = luaK_codeABC(fs, opc, 0, o1, o2);
-    res->k = VRELOCABLE;
-  }
-  else {  /* test operator */
-    static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE};
-    int cond = 1;
-    if (op >= OPR_GT) {  /* `>' or `>='? */
-      int temp;  /* exchange args and replace by `<' or `<=' */
-      temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
-    }
-    else if (op == OPR_NE) cond = 0;
-    res->info = condjump(fs, ops[op - OPR_NE], cond, o1, o2);
-    res->k = VJMP;
-  }
-}
-
-
 void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
   switch (op) {
     case OPR_AND: {
       lua_assert(e1->t == NO_JUMP);  /* list must be closed */
       luaK_dischargevars(fs, e2);
       luaK_concat(fs, &e1->f, e2->f);
-      e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t;
+      e1->k = e2->k; e1->u.s.info = e2->u.s.info;
+      e1->u.s.aux = e2->u.s.aux; e1->t = e2->t;
       break;
     }
     case OPR_OR: {
       lua_assert(e1->f == NO_JUMP);  /* list must be closed */
       luaK_dischargevars(fs, e2);
       luaK_concat(fs, &e1->t, e2->t);
-      e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f;
+      e1->k = e2->k; e1->u.s.info = e2->u.s.info;
+      e1->u.s.aux = e2->u.s.aux; e1->f = e2->f;
       break;
     }
     case OPR_CONCAT: {
       luaK_exp2val(fs, e2);
       if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
-        lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1);
+        lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
         freeexp(fs, e1);
-        SETARG_B(getcode(fs, e2), e1->info);
-        e1->k = e2->k; e1->info = e2->info;
+        SETARG_B(getcode(fs, e2), e1->u.s.info);
+        e1->k = e2->k; e1->u.s.info = e2->u.s.info;
       }
       else {
-        luaK_exp2nextreg(fs, e2);
-        freeexp(fs, e2);
-        freeexp(fs, e1);
-        e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info);
-        e1->k = VRELOCABLE;
+        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
+        codearith(fs, OP_CONCAT, e1, e2);
       }
       break;
     }
-    default: {
-      int o1 = luaK_exp2RK(fs, e1);
-      int o2 = luaK_exp2RK(fs, e2);
-      freeexp(fs, e2);
-      freeexp(fs, e1);
-      codebinop(fs, e1, op, o1, o2);
-    }
+    case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
+    case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
+    case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
+    case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
+    case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
+    case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
+    case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
+    case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
+    case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
+    case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
+    case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
+    case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
+    default: lua_assert(0);
   }
 }