Browse Source

Subtraction of small constant integers optimized with OP_ADDI

Roberto Ierusalimschy 5 years ago
parent
commit
6ef366644f
4 changed files with 46 additions and 31 deletions
  1. 41 27
      lcode.c
  2. 3 3
      testes/bitwise.lua
  3. 1 0
      testes/code.lua
  4. 1 1
      testes/locals.lua

+ 41 - 27
lcode.c

@@ -1212,6 +1212,15 @@ static int isSCint (expdesc *e) {
 }
 
 
+/*
+** Check whether expression 'e' and its negation are literal integers
+** in proper range to fit in register sC
+*/
+static int isSCintN (expdesc *e) {
+  return luaK_isKint(e) && fitsC(e->u.ival) && fitsC(-e->u.ival);
+}
+
+
 /*
 ** Check whether expression 'e' is a literal integer or float in
 ** proper range to fit in a register (sB or sC).
@@ -1373,6 +1382,18 @@ static void codebini (FuncState *fs, OpCode op,
 }
 
 
+/* Code binary operators negating the immediate operand for the
+** opcode. For the metamethod, 'v2' must keep its original value.
+*/
+static void finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2,
+                             OpCode op, int line, TMS event) {
+  int v2 = cast_int(e2->u.ival);
+  finishbinexpval(fs, e1, e2, op, int2sC(-v2), 0, line, OP_MMBINI, event);
+  /* correct metamethod argument */
+  SETARG_B(fs->f->code[fs->pc - 1], int2sC(v2));
+}
+
+
 static void swapexps (expdesc *e1, expdesc *e2) {
   expdesc temp = *e1; *e1 = *e2; *e2 = temp;  /* swap 'e1' and 'e2' */
 }
@@ -1444,27 +1465,6 @@ static void codebitwise (FuncState *fs, BinOpr opr,
 }
 
 
-/*
-** Code shift operators. If second operand is constant, use immediate
-** operand (negating it if shift is in the other direction).
-*/
-static void codeshift (FuncState *fs, OpCode op,
-                       expdesc *e1, expdesc *e2, int line) {
-  if (isSCint(e2)) {
-    if (op == OP_SHR)
-      codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR);
-    else {
-      int offset = cast_int(e2->u.ival);
-      finishbinexpval(fs, e1, e2, OP_SHRI, int2sC(offset),
-                      0, line, OP_MMBINI, TM_SHL);
-      SETARG_C(fs->f->code[fs->pc - 2], int2sC(-offset));
-    }
-  }
-  else
-    codebinexpval(fs, op, e1, e2, line);
-}
-
-
 /*
 ** Emit code for order comparisons. When using an immediate operand,
 ** 'isfloat' tells whether the original value was a float.
@@ -1646,8 +1646,15 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
       codecommutative(fs, opr, e1, e2, line);
       break;
     }
-    case OPR_SUB: case OPR_DIV:
-    case OPR_IDIV: case OPR_MOD: case OPR_POW: {
+    case OPR_SUB: {
+      if (isSCintN(e2)) {  /* subtracting a small integer constant? */
+        /* code it as (r1 + -I) */
+        finishbinexpneg(fs, e1, e2, OP_ADDI, line, TM_SUB);
+        break;
+      }
+      /* ELSE *//* FALLTHROUGH */
+    }
+    case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: {
       codearith(fs, opr, e1, e2, 0, line);
       break;
     }
@@ -1658,14 +1665,21 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
     case OPR_SHL: {
       if (isSCint(e1)) {
         swapexps(e1, e2);
-        codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL);
+        codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL);  /* I << r2 */
+      }
+      else if (isSCintN(e2)) {  /* shifting by a small integer constant? */
+        /* code it as (r1 >> -I) */
+        finishbinexpneg(fs, e1, e2, OP_SHRI, line, TM_SHL);
       }
-      else
-        codeshift(fs, OP_SHL, e1, e2, line);
+      else  /* regular case (two registers) */
+       codebinexpval(fs, OP_SHL, e1, e2, line);
       break;
     }
     case OPR_SHR: {
-      codeshift(fs, OP_SHR, e1, e2, line);
+      if (isSCintN(e2))
+        codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR);  /* r1 >> I */
+      else  /* regular case (two registers) */
+        codebinexpval(fs, OP_SHR, e1, e2, line);
       break;
     }
     case OPR_EQ: case OPR_NE: {

+ 3 - 3
testes/bitwise.lua

@@ -60,9 +60,9 @@ assert("1234.0" << "5.0" == 1234 * 32)
 assert("0xffff.0" ~ "0xAAAA" == 0x5555)
 assert(~"0x0.000p4" == -1)
 
-assert("7" .. 3 << 1 == 146)
-assert(10 >> 1 .. "9" == 0)
-assert(10 | 1 .. "9" == 27)
+assert(("7" .. 3) << 1 == 146)
+assert(0xffffffff >> (1 .. "9") == 0x1fff)
+assert(10 | (1 .. "9") == 27)
 
 do
   local st, msg = pcall(function () return 4 & "a" end)

+ 1 - 0
testes/code.lua

@@ -293,6 +293,7 @@ checkK(function () return -(border + 1) end, -(sbx + 1.0))
 
 -- immediate operands
 checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'MMBINI', 'RETURN1')
+checkR(function (x) return x - 127 end, 10, -117, 'ADDI', 'MMBINI', 'RETURN1')
 checkR(function (x) return 128 + x end, 0.0, 128.0,
          'ADDI', 'MMBINI', 'RETURN1')
 checkR(function (x) return x * -127 end, -1.0, 127.0,

+ 1 - 1
testes/locals.lua

@@ -82,7 +82,7 @@ assert(c.a == nil)
 f()
 assert(c.a == 3)
 
--- old test for limits for special instructions (now just a generic test)
+-- old test for limits for special instructions
 do
   local i = 2
   local p = 4    -- p == 2^i