diff --git a/lcode.c b/lcode.c index 053b66b2..bc86793a 100644 --- a/lcode.c +++ b/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 - codeshift(fs, OP_SHL, e1, e2, line); + 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 /* 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: { diff --git a/testes/bitwise.lua b/testes/bitwise.lua index af542e7f..59781f5d 100644 --- a/testes/bitwise.lua +++ b/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) diff --git a/testes/code.lua b/testes/code.lua index 642dfa68..ab531fa8 100644 --- a/testes/code.lua +++ b/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, diff --git a/testes/locals.lua b/testes/locals.lua index 58ad18cc..b769575f 100644 --- a/testes/locals.lua +++ b/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