diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-01-27 14:56:33 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-01-27 14:56:33 -0200 |
| commit | 5bd8d388de6704cc7f0eb60de33636a4dfcd61bd (patch) | |
| tree | b0d226562331d8667847908dc957a4e01f811dd5 | |
| parent | 28f215ecf8b8d987f0bf64f3154b0e2fbc5e5168 (diff) | |
| download | lua-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.c | 84 | ||||
| -rw-r--r-- | lopcodes.h | 4 | ||||
| -rw-r--r-- | lvm.c | 24 |
3 files changed, 61 insertions, 51 deletions
| @@ -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 | */ | ||
| 68 | static 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 | */ |
| 68 | void luaK_nil (FuncState *fs, int from, int n) { | 83 | void 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 | */ | ||
| 1483 | static 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 | */ |
| 1473 | void luaK_posfix (FuncState *fs, BinOpr opr, | 1503 | void 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: { |
| @@ -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) */ | |||
| 248 | OP_NOT,/* A B R(A) := not R(B) */ | 248 | OP_NOT,/* A B R(A) := not R(B) */ |
| 249 | OP_LEN,/* A B R(A) := length of R(B) */ | 249 | OP_LEN,/* A B R(A) := length of R(B) */ |
| 250 | 250 | ||
| 251 | OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ | 251 | OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */ |
| 252 | 252 | ||
| 253 | OP_CLOSE,/* A close all upvalues >= R(A) */ | 253 | OP_CLOSE,/* A close all upvalues >= R(A) */ |
| 254 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ | 254 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ |
| @@ -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) { |
