Browse Source

integer handling for order comparisons, power, and modulo operations

Roberto Ierusalimschy 12 years ago
parent
commit
e381c582de
2 changed files with 83 additions and 6 deletions
  1. 79 5
      lvm.c
  2. 4 1
      lvm.h

+ 79 - 5
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.159 2013/04/25 15:59:42 roberto Exp roberto $
+** $Id: lvm.c,v 2.160 2013/04/25 16:07:52 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -150,7 +150,9 @@ static int l_strcmp (const TString *ls, const TString *rs) {
 
 int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
   int res;
-  if (ttisnumber(l) && ttisnumber(r))
+  if (ttisinteger(l) && ttisinteger(r))
+    return (ivalue(l) < ivalue(r));
+  else if (ttisnumber(l) && ttisnumber(r))
     return luai_numlt(L, nvalue(l), nvalue(r));
   else if (ttisstring(l) && ttisstring(r))
     return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
@@ -162,7 +164,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
 
 int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
   int res;
-  if (ttisnumber(l) && ttisnumber(r))
+  if (ttisinteger(l) && ttisinteger(r))
+    return (ivalue(l) <= ivalue(r));
+  else if (ttisnumber(l) && ttisnumber(r))
     return luai_numle(L, nvalue(l), nvalue(r));
   else if (ttisstring(l) && ttisstring(r))
     return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
@@ -283,6 +287,54 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
 }
 
 
+lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y) {
+  if (cast_unsigned(y) + 1 <= 1U) {  /* special cases: -1 or 0 */
+    if (y == 0)
+      luaG_runerror(L, "attempt to divide by zero");
+    else  /* -1 */
+      return -x;   /* avoid overflow with 0x80000... */
+  }
+  else {
+    lua_Integer d = x / y;  /* perform division */
+    if ((x ^ y) >= 0 || x % y == 0)   /* same signal or no rest? */
+      return d;
+    else
+      return d - 1;  /* correct 'div' for negative case */
+  }
+}
+
+
+lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y) {
+  if (cast_unsigned(y) + 1 <= 1U) {  /* special cases: -1 or 0 */
+    if (y == 0)
+      luaG_runerror(L, "attempt to divide by zero (in '%%')");
+    else  /* -1 */
+      return 0;   /* avoid overflow with 0x80000... */
+  }
+  else {
+    lua_Integer r = x % y;
+    if (r == 0 || (x ^ y) >= 0)
+      return r;
+    else
+      return r + y;  /* correct 'mod' for negative case */
+  }
+}
+
+
+lua_Integer luaV_pow (lua_Integer x, lua_Integer y) {
+  lua_Integer r = 1;
+  lua_assert(y >= 0);
+  if (y == 0) return r;
+  for (; y > 1; y >>= 1) {
+    if (y & 1)
+      r = cast_integer(cast_unsigned(r) * cast_unsigned(x));
+    x = cast_integer(cast_unsigned(x) * cast_unsigned(x));
+  }
+  r = cast_integer(cast_unsigned(r) * cast_unsigned(x));
+  return r;
+}
+
+
 void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
                  const TValue *rc, TMS op) {
   TValue tempb, tempc;
@@ -589,10 +641,32 @@ void luaV_execute (lua_State *L) {
         else { Protect(luaV_arith(L, ra, rb, rc, TM_DIV)); }
       )
       vmcase(OP_MOD,
-        arith_op(luai_nummod, TM_MOD);
+        TValue *rb = RKB(i);
+        TValue *rc = RKC(i);
+        if (ttisinteger(rb) && ttisinteger(rc)) {
+          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+          setivalue(ra, luaV_mod(L, ib, ic));
+        }
+        else if (ttisnumber(rb) && ttisnumber(rc)) {
+          lua_Number nb = nvalue(rb); lua_Number nc = nvalue(rc);
+          setnvalue(ra, luai_nummod(L, nb, nc));
+        }
+        else { Protect(luaV_arith(L, ra, rb, rc, TM_MOD)); }
       )
       vmcase(OP_POW,
-        arith_op(luai_numpow, TM_POW);
+        TValue *rb = RKB(i);
+        TValue *rc = RKC(i);
+        lua_Integer ic;
+        if (ttisinteger(rb) && ttisinteger(rc) &&
+            (ic = ivalue(rc)) >= 0) {
+          lua_Integer ib = ivalue(rb);
+          setivalue(ra, luaV_pow(ib, ic));
+        }
+        else if (ttisnumber(rb) && ttisnumber(rc)) {
+          lua_Number nb = nvalue(rb); lua_Number nc = nvalue(rc);
+          setnvalue(ra, luai_numpow(L, nb, nc));
+        }
+        else { Protect(luaV_arith(L, ra, rb, rc, TM_POW)); }
       )
       vmcase(OP_UNM,
         TValue *rb = RB(i);

+ 4 - 1
lvm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $
+** $Id: lvm.h,v 2.19 2013/04/15 15:44:46 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -33,6 +33,9 @@ LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
 LUAI_FUNC void luaV_finishOp (lua_State *L);
 LUAI_FUNC void luaV_execute (lua_State *L);
 LUAI_FUNC void luaV_concat (lua_State *L, int total);
+LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_pow (lua_Integer x, lua_Integer y);
 LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
                            const TValue *rc, TMS op);
 LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);