aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-01-27 14:56:33 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-01-27 14:56:33 -0200
commit5bd8d388de6704cc7f0eb60de33636a4dfcd61bd (patch)
treeb0d226562331d8667847908dc957a4e01f811dd5
parent28f215ecf8b8d987f0bf64f3154b0e2fbc5e5168 (diff)
downloadlua-5bd8d388de6704cc7f0eb60de33636a4dfcd61bd.tar.gz
lua-5bd8d388de6704cc7f0eb60de33636a4dfcd61bd.tar.bz2
lua-5bd8d388de6704cc7f0eb60de33636a4dfcd61bd.zip
OP_CONCAT does not move its result (to simplify its execution)
-rw-r--r--lcode.c84
-rw-r--r--lopcodes.h4
-rw-r--r--lvm.c24
3 files changed, 61 insertions, 51 deletions
diff --git a/lcode.c b/lcode.c
index e0620791..7e573f02 100644
--- a/lcode.c
+++ b/lcode.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lcode.c,v 2.149 2018/01/09 11:24:12 roberto Exp roberto $ 2** $Id: lcode.c,v 2.150 2018/01/18 16:24:31 roberto Exp roberto $
3** Code generator for Lua 3** Code generator for Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -60,27 +60,39 @@ static int tonumeral(const expdesc *e, TValue *v) {
60 60
61 61
62/* 62/*
63** Return the previous instruction of the current code. If there
64** may be a jump target between the current instruction and the
65** previous one, return an invalid instruction (to avoid wrong
66** optimizations).
67*/
68static Instruction *previousinstruction (FuncState *fs) {
69 static const Instruction invalidinstruction = -1;
70 if (fs->pc > fs->lasttarget)
71 return &fs->f->code[fs->pc - 1]; /* previous instruction */
72 else
73 return cast(Instruction*, &invalidinstruction);
74}
75
76
77/*
63** Create a OP_LOADNIL instruction, but try to optimize: if the previous 78** Create a OP_LOADNIL instruction, but try to optimize: if the previous
64** instruction is also OP_LOADNIL and ranges are compatible, adjust 79** instruction is also OP_LOADNIL and ranges are compatible, adjust
65** range of previous instruction instead of emitting a new one. (For 80** range of previous instruction instead of emitting a new one. (For
66** instance, 'local a; local b' will generate a single opcode.) 81** instance, 'local a; local b' will generate a single opcode.)
67*/ 82*/
68void luaK_nil (FuncState *fs, int from, int n) { 83void luaK_nil (FuncState *fs, int from, int n) {
69 Instruction *previous;
70 int l = from + n - 1; /* last register to set nil */ 84 int l = from + n - 1; /* last register to set nil */
71 if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ 85 Instruction *previous = previousinstruction(fs);
72 previous = &fs->f->code[fs->pc-1]; 86 if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
73 if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ 87 int pfrom = GETARG_A(*previous); /* get previous range */
74 int pfrom = GETARG_A(*previous); /* get previous range */ 88 int pl = pfrom + GETARG_B(*previous);
75 int pl = pfrom + GETARG_B(*previous); 89 if ((pfrom <= from && from <= pl + 1) ||
76 if ((pfrom <= from && from <= pl + 1) || 90 (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
77 (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ 91 if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
78 if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ 92 if (pl > l) l = pl; /* l = max(l, pl) */
79 if (pl > l) l = pl; /* l = max(l, pl) */ 93 SETARG_A(*previous, from);
80 SETARG_A(*previous, from); 94 SETARG_B(*previous, l - from);
81 SETARG_B(*previous, l - from); 95 return;
82 return;
83 }
84 } /* else go through */ 96 } /* else go through */
85 } 97 }
86 luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ 98 luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
@@ -1432,7 +1444,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
1432 break; 1444 break;
1433 } 1445 }
1434 case OPR_CONCAT: { 1446 case OPR_CONCAT: {
1435 luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ 1447 luaK_exp2nextreg(fs, v); /* operand must be on the stack */
1436 break; 1448 break;
1437 } 1449 }
1438 case OPR_ADD: case OPR_SUB: 1450 case OPR_ADD: case OPR_SUB:
@@ -1463,12 +1475,30 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
1463 } 1475 }
1464} 1476}
1465 1477
1478/*
1479** Create code for '(e1 .. e2)'.
1480** For '(e1 .. e2.1 .. e2.2)' (which is '(e1 .. (e2.1 .. e2.2))',
1481** because concatenation is right associative), merge both CONCATs.
1482*/
1483static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) {
1484 Instruction *ie2 = previousinstruction(fs);
1485 if (GET_OPCODE(*ie2) == OP_CONCAT) { /* is 'e2' a concatenation? */
1486 int n = GETARG_B(*ie2); /* # of elements concatenated in 'e2' */
1487 lua_assert(e1->u.info + 1 == GETARG_A(*ie2));
1488 freeexp(fs, e2);
1489 SETARG_A(*ie2, e1->u.info); /* correct first element ('e1') */
1490 SETARG_B(*ie2, n + 1); /* will concatenate one more element */
1491 }
1492 else { /* 'e2' is not a concatenation */
1493 luaK_codeABC(fs, OP_CONCAT, e1->u.info, 2, 0); /* new concat opcode */
1494 freeexp(fs, e2);
1495 luaK_fixline(fs, line);
1496 }
1497}
1498
1466 1499
1467/* 1500/*
1468** Finalize code for binary operation, after reading 2nd operand. 1501** Finalize code for binary operation, after reading 2nd operand.
1469** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
1470** concatenation is right associative), merge second CONCAT into first
1471** one.
1472*/ 1502*/
1473void luaK_posfix (FuncState *fs, BinOpr opr, 1503void luaK_posfix (FuncState *fs, BinOpr opr,
1474 expdesc *e1, expdesc *e2, int line) { 1504 expdesc *e1, expdesc *e2, int line) {
@@ -1487,19 +1517,9 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
1487 *e1 = *e2; 1517 *e1 = *e2;
1488 break; 1518 break;
1489 } 1519 }
1490 case OPR_CONCAT: { 1520 case OPR_CONCAT: { /* e1 .. e2 */
1491 luaK_exp2val(fs, e2); 1521 luaK_exp2nextreg(fs, e2);
1492 if (e2->k == VRELOC && 1522 codeconcat(fs, e1, e2, line);
1493 GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {
1494 lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1);
1495 freeexp(fs, e1);
1496 SETARG_B(getinstruction(fs, e2), e1->u.info);
1497 e1->k = VRELOC; e1->u.info = e2->u.info;
1498 }
1499 else {
1500 luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
1501 codebinexpval(fs, OP_CONCAT, e1, e2, line);
1502 }
1503 break; 1523 break;
1504 } 1524 }
1505 case OPR_ADD: case OPR_MUL: { 1525 case OPR_ADD: case OPR_MUL: {
diff --git a/lopcodes.h b/lopcodes.h
index 22de7a71..2f4a48fa 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lopcodes.h,v 1.182 2018/01/09 11:21:41 roberto Exp $ 2** $Id: lopcodes.h,v 1.182 2018/01/09 11:24:12 roberto Exp roberto $
3** Opcodes for Lua virtual machine 3** Opcodes for Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -248,7 +248,7 @@ OP_BNOT,/* A B R(A) := ~R(B) */
248OP_NOT,/* A B R(A) := not R(B) */ 248OP_NOT,/* A B R(A) := not R(B) */
249OP_LEN,/* A B R(A) := length of R(B) */ 249OP_LEN,/* A B R(A) := length of R(B) */
250 250
251OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ 251OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */
252 252
253OP_CLOSE,/* A close all upvalues >= R(A) */ 253OP_CLOSE,/* A close all upvalues >= R(A) */
254OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ 254OP_JMP,/* k sJ pc += sJ (k is used in code generation) */
diff --git a/lvm.c b/lvm.c
index 12597eb4..73256267 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 2.333 2018/01/10 19:19:27 roberto Exp roberto $ 2** $Id: lvm.c,v 2.334 2018/01/14 17:27:50 roberto Exp roberto $
3** Lua virtual machine 3** Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -717,15 +717,13 @@ void luaV_finishOp (lua_State *L) {
717 } 717 }
718 case OP_CONCAT: { 718 case OP_CONCAT: {
719 StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ 719 StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
720 int b = GETARG_B(inst); /* first element to concatenate */ 720 int a = GETARG_A(inst); /* first element to concatenate */
721 int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ 721 int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
722 setobjs2s(L, top - 2, top); /* put TM result in proper position */ 722 setobjs2s(L, top - 2, top); /* put TM result in proper position */
723 if (total > 1) { /* are there elements to concat? */ 723 if (total > 1) { /* are there elements to concat? */
724 L->top = top - 1; /* top is one after last element (at top-2) */ 724 L->top = top - 1; /* top is one after last element (at top-2) */
725 luaV_concat(L, total); /* concat them (may yield again) */ 725 luaV_concat(L, total); /* concat them (may yield again) */
726 } 726 }
727 /* move final result to final position */
728 setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1);
729 break; 727 break;
730 } 728 }
731 case OP_TFORCALL: case OP_CALL: case OP_TAILCALL: 729 case OP_TFORCALL: case OP_CALL: case OP_TAILCALL:
@@ -1376,18 +1374,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1376 vmbreak; 1374 vmbreak;
1377 } 1375 }
1378 vmcase(OP_CONCAT) { 1376 vmcase(OP_CONCAT) {
1379 int b = GETARG_B(i); 1377 int n = GETARG_B(i); /* number of elements to concatenate */
1380 int c = GETARG_C(i); 1378 L->top = ra + n; /* mark the end of concat operands */
1381 StkId rb; 1379 ProtectNT(luaV_concat(L, n));
1382 L->top = base + c + 1; /* mark the end of concat operands */ 1380 checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
1383 ProtectNT(luaV_concat(L, c - b + 1));
1384 if (trap) { /* 'luaV_concat' may move the stack */
1385 updatebase(ci);
1386 ra = RA(i);
1387 }
1388 rb = base + b;
1389 setobjs2s(L, ra, rb);
1390 checkGC(L, (ra >= rb ? ra + 1 : rb));
1391 vmbreak; 1381 vmbreak;
1392 } 1382 }
1393 vmcase(OP_CLOSE) { 1383 vmcase(OP_CLOSE) {