diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-09-24 14:34:52 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-09-24 14:34:52 -0300 |
commit | 6ef366644f7c3c21cfb17434835edf4ebf970d6d (patch) | |
tree | d41df5b79bea32675f740a52d39c0b5ec37eb92b | |
parent | 03cde80b58ea7f112f1b7a35c037893093b59f2e (diff) | |
download | lua-6ef366644f7c3c21cfb17434835edf4ebf970d6d.tar.gz lua-6ef366644f7c3c21cfb17434835edf4ebf970d6d.tar.bz2 lua-6ef366644f7c3c21cfb17434835edf4ebf970d6d.zip |
Subtraction of small constant integers optimized with OP_ADDI
-rw-r--r-- | lcode.c | 68 | ||||
-rw-r--r-- | testes/bitwise.lua | 6 | ||||
-rw-r--r-- | testes/code.lua | 1 | ||||
-rw-r--r-- | testes/locals.lua | 2 |
4 files changed, 46 insertions, 31 deletions
@@ -1213,6 +1213,15 @@ static int isSCint (expdesc *e) { | |||
1213 | 1213 | ||
1214 | 1214 | ||
1215 | /* | 1215 | /* |
1216 | ** Check whether expression 'e' and its negation are literal integers | ||
1217 | ** in proper range to fit in register sC | ||
1218 | */ | ||
1219 | static int isSCintN (expdesc *e) { | ||
1220 | return luaK_isKint(e) && fitsC(e->u.ival) && fitsC(-e->u.ival); | ||
1221 | } | ||
1222 | |||
1223 | |||
1224 | /* | ||
1216 | ** Check whether expression 'e' is a literal integer or float in | 1225 | ** Check whether expression 'e' is a literal integer or float in |
1217 | ** proper range to fit in a register (sB or sC). | 1226 | ** proper range to fit in a register (sB or sC). |
1218 | */ | 1227 | */ |
@@ -1373,6 +1382,18 @@ static void codebini (FuncState *fs, OpCode op, | |||
1373 | } | 1382 | } |
1374 | 1383 | ||
1375 | 1384 | ||
1385 | /* Code binary operators negating the immediate operand for the | ||
1386 | ** opcode. For the metamethod, 'v2' must keep its original value. | ||
1387 | */ | ||
1388 | static void finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, | ||
1389 | OpCode op, int line, TMS event) { | ||
1390 | int v2 = cast_int(e2->u.ival); | ||
1391 | finishbinexpval(fs, e1, e2, op, int2sC(-v2), 0, line, OP_MMBINI, event); | ||
1392 | /* correct metamethod argument */ | ||
1393 | SETARG_B(fs->f->code[fs->pc - 1], int2sC(v2)); | ||
1394 | } | ||
1395 | |||
1396 | |||
1376 | static void swapexps (expdesc *e1, expdesc *e2) { | 1397 | static void swapexps (expdesc *e1, expdesc *e2) { |
1377 | expdesc temp = *e1; *e1 = *e2; *e2 = temp; /* swap 'e1' and 'e2' */ | 1398 | expdesc temp = *e1; *e1 = *e2; *e2 = temp; /* swap 'e1' and 'e2' */ |
1378 | } | 1399 | } |
@@ -1445,27 +1466,6 @@ static void codebitwise (FuncState *fs, BinOpr opr, | |||
1445 | 1466 | ||
1446 | 1467 | ||
1447 | /* | 1468 | /* |
1448 | ** Code shift operators. If second operand is constant, use immediate | ||
1449 | ** operand (negating it if shift is in the other direction). | ||
1450 | */ | ||
1451 | static void codeshift (FuncState *fs, OpCode op, | ||
1452 | expdesc *e1, expdesc *e2, int line) { | ||
1453 | if (isSCint(e2)) { | ||
1454 | if (op == OP_SHR) | ||
1455 | codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); | ||
1456 | else { | ||
1457 | int offset = cast_int(e2->u.ival); | ||
1458 | finishbinexpval(fs, e1, e2, OP_SHRI, int2sC(offset), | ||
1459 | 0, line, OP_MMBINI, TM_SHL); | ||
1460 | SETARG_C(fs->f->code[fs->pc - 2], int2sC(-offset)); | ||
1461 | } | ||
1462 | } | ||
1463 | else | ||
1464 | codebinexpval(fs, op, e1, e2, line); | ||
1465 | } | ||
1466 | |||
1467 | |||
1468 | /* | ||
1469 | ** Emit code for order comparisons. When using an immediate operand, | 1469 | ** Emit code for order comparisons. When using an immediate operand, |
1470 | ** 'isfloat' tells whether the original value was a float. | 1470 | ** 'isfloat' tells whether the original value was a float. |
1471 | */ | 1471 | */ |
@@ -1646,8 +1646,15 @@ void luaK_posfix (FuncState *fs, BinOpr opr, | |||
1646 | codecommutative(fs, opr, e1, e2, line); | 1646 | codecommutative(fs, opr, e1, e2, line); |
1647 | break; | 1647 | break; |
1648 | } | 1648 | } |
1649 | case OPR_SUB: case OPR_DIV: | 1649 | case OPR_SUB: { |
1650 | case OPR_IDIV: case OPR_MOD: case OPR_POW: { | 1650 | if (isSCintN(e2)) { /* subtracting a small integer constant? */ |
1651 | /* code it as (r1 + -I) */ | ||
1652 | finishbinexpneg(fs, e1, e2, OP_ADDI, line, TM_SUB); | ||
1653 | break; | ||
1654 | } | ||
1655 | /* ELSE *//* FALLTHROUGH */ | ||
1656 | } | ||
1657 | case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: { | ||
1651 | codearith(fs, opr, e1, e2, 0, line); | 1658 | codearith(fs, opr, e1, e2, 0, line); |
1652 | break; | 1659 | break; |
1653 | } | 1660 | } |
@@ -1658,14 +1665,21 @@ void luaK_posfix (FuncState *fs, BinOpr opr, | |||
1658 | case OPR_SHL: { | 1665 | case OPR_SHL: { |
1659 | if (isSCint(e1)) { | 1666 | if (isSCint(e1)) { |
1660 | swapexps(e1, e2); | 1667 | swapexps(e1, e2); |
1661 | codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL); | 1668 | codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL); /* I << r2 */ |
1669 | } | ||
1670 | else if (isSCintN(e2)) { /* shifting by a small integer constant? */ | ||
1671 | /* code it as (r1 >> -I) */ | ||
1672 | finishbinexpneg(fs, e1, e2, OP_SHRI, line, TM_SHL); | ||
1662 | } | 1673 | } |
1663 | else | 1674 | else /* regular case (two registers) */ |
1664 | codeshift(fs, OP_SHL, e1, e2, line); | 1675 | codebinexpval(fs, OP_SHL, e1, e2, line); |
1665 | break; | 1676 | break; |
1666 | } | 1677 | } |
1667 | case OPR_SHR: { | 1678 | case OPR_SHR: { |
1668 | codeshift(fs, OP_SHR, e1, e2, line); | 1679 | if (isSCintN(e2)) |
1680 | codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ | ||
1681 | else /* regular case (two registers) */ | ||
1682 | codebinexpval(fs, OP_SHR, e1, e2, line); | ||
1669 | break; | 1683 | break; |
1670 | } | 1684 | } |
1671 | case OPR_EQ: case OPR_NE: { | 1685 | 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) | |||
60 | assert("0xffff.0" ~ "0xAAAA" == 0x5555) | 60 | assert("0xffff.0" ~ "0xAAAA" == 0x5555) |
61 | assert(~"0x0.000p4" == -1) | 61 | assert(~"0x0.000p4" == -1) |
62 | 62 | ||
63 | assert("7" .. 3 << 1 == 146) | 63 | assert(("7" .. 3) << 1 == 146) |
64 | assert(10 >> 1 .. "9" == 0) | 64 | assert(0xffffffff >> (1 .. "9") == 0x1fff) |
65 | assert(10 | 1 .. "9" == 27) | 65 | assert(10 | (1 .. "9") == 27) |
66 | 66 | ||
67 | do | 67 | do |
68 | local st, msg = pcall(function () return 4 & "a" end) | 68 | 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)) | |||
293 | 293 | ||
294 | -- immediate operands | 294 | -- immediate operands |
295 | checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'MMBINI', 'RETURN1') | 295 | checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'MMBINI', 'RETURN1') |
296 | checkR(function (x) return x - 127 end, 10, -117, 'ADDI', 'MMBINI', 'RETURN1') | ||
296 | checkR(function (x) return 128 + x end, 0.0, 128.0, | 297 | checkR(function (x) return 128 + x end, 0.0, 128.0, |
297 | 'ADDI', 'MMBINI', 'RETURN1') | 298 | 'ADDI', 'MMBINI', 'RETURN1') |
298 | checkR(function (x) return x * -127 end, -1.0, 127.0, | 299 | 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) | |||
82 | f() | 82 | f() |
83 | assert(c.a == 3) | 83 | assert(c.a == 3) |
84 | 84 | ||
85 | -- old test for limits for special instructions (now just a generic test) | 85 | -- old test for limits for special instructions |
86 | do | 86 | do |
87 | local i = 2 | 87 | local i = 2 |
88 | local p = 4 -- p == 2^i | 88 | local p = 4 -- p == 2^i |