aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-01 12:42:31 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-01 12:42:31 -0300
commit8eca21c2e85625390a2a3b08c231e75e315980b0 (patch)
tree47106e7a62cf00091594302629c7157fed81f738
parent924bed7297d5ea16a78ec07e7acc64afad951aa8 (diff)
downloadlua-8eca21c2e85625390a2a3b08c231e75e315980b0.tar.gz
lua-8eca21c2e85625390a2a3b08c231e75e315980b0.tar.bz2
lua-8eca21c2e85625390a2a3b08c231e75e315980b0.zip
First take on constant propagation
-rw-r--r--lcode.c62
-rw-r--r--lcode.h1
-rw-r--r--lparser.c34
-rw-r--r--lparser.h2
4 files changed, 73 insertions, 26 deletions
diff --git a/lcode.c b/lcode.c
index eccb8380..1005f1b7 100644
--- a/lcode.c
+++ b/lcode.c
@@ -52,7 +52,7 @@ l_noret luaK_semerror (LexState *ls, const char *msg) {
52** If expression is a numeric constant, fills 'v' with its value 52** If expression is a numeric constant, fills 'v' with its value
53** and returns 1. Otherwise, returns 0. 53** and returns 1. Otherwise, returns 0.
54*/ 54*/
55static int tonumeral(const expdesc *e, TValue *v) { 55int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v) {
56 if (hasjumps(e)) 56 if (hasjumps(e))
57 return 0; /* not a numeral */ 57 return 0; /* not a numeral */
58 switch (e->k) { 58 switch (e->k) {
@@ -62,12 +62,42 @@ static int tonumeral(const expdesc *e, TValue *v) {
62 case VKFLT: 62 case VKFLT:
63 if (v) setfltvalue(v, e->u.nval); 63 if (v) setfltvalue(v, e->u.nval);
64 return 1; 64 return 1;
65 case VUPVAL: { /* may be a constant */
66 Vardesc *vd = luaY_getvardesc(&fs, e);
67 if (v && vd && !ttisnil(&vd->val)) {
68 setobj(fs->ls->L, v, &vd->val);
69 return 1;
70 } /* else */
71 } /* FALLTHROUGH */
65 default: return 0; 72 default: return 0;
66 } 73 }
67} 74}
68 75
69 76
70/* 77/*
78** If expression 'e' is a constant, change 'e' to represent
79** the constant value.
80*/
81static int const2exp (FuncState *fs, expdesc *e) {
82 Vardesc *vd = luaY_getvardesc(&fs, e);
83 if (vd) {
84 TValue *v = &vd->val;
85 switch (ttypetag(v)) {
86 case LUA_TNUMINT:
87 e->k = VKINT;
88 e->u.ival = ivalue(v);
89 return 1;
90 case LUA_TNUMFLT:
91 e->k = VKFLT;
92 e->u.nval = fltvalue(v);
93 return 1;
94 }
95 }
96 return 0;
97}
98
99
100/*
71** Return the previous instruction of the current code. If there 101** Return the previous instruction of the current code. If there
72** may be a jump target between the current instruction and the 102** may be a jump target between the current instruction and the
73** previous one, return an invalid instruction (to avoid wrong 103** previous one, return an invalid instruction (to avoid wrong
@@ -683,8 +713,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
683 break; 713 break;
684 } 714 }
685 case VUPVAL: { /* move value to some (pending) register */ 715 case VUPVAL: { /* move value to some (pending) register */
686 e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0); 716 if (!const2exp(fs, e)) {
687 e->k = VRELOC; 717 e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0);
718 e->k = VRELOC;
719 }
688 break; 720 break;
689 } 721 }
690 case VINDEXUP: { 722 case VINDEXUP: {
@@ -1218,9 +1250,11 @@ static int validop (int op, TValue *v1, TValue *v2) {
1218** (In this case, 'e1' has the final result.) 1250** (In this case, 'e1' has the final result.)
1219*/ 1251*/
1220static int constfolding (FuncState *fs, int op, expdesc *e1, 1252static int constfolding (FuncState *fs, int op, expdesc *e1,
1221 const expdesc *e2) { 1253 const expdesc *e2) {
1222 TValue v1, v2, res; 1254 TValue v1, v2, res;
1223 if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) 1255 if (!luaK_tonumeral(fs, e1, &v1) ||
1256 !luaK_tonumeral(fs, e2, &v2) ||
1257 !validop(op, &v1, &v2))
1224 return 0; /* non-numeric operands or not safe to fold */ 1258 return 0; /* non-numeric operands or not safe to fold */
1225 luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ 1259 luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */
1226 if (ttisinteger(&res)) { 1260 if (ttisinteger(&res)) {
@@ -1307,7 +1341,7 @@ static void codearith (FuncState *fs, OpCode op,
1307 expdesc *e1, expdesc *e2, int flip, int line) { 1341 expdesc *e1, expdesc *e2, int flip, int line) {
1308 if (isSCint(e2)) /* immediate operand? */ 1342 if (isSCint(e2)) /* immediate operand? */
1309 codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line); 1343 codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line);
1310 else if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ 1344 else if (luaK_tonumeral(fs, e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
1311 int v2 = e2->u.info; /* K index */ 1345 int v2 = e2->u.info; /* K index */
1312 op = cast(OpCode, op - OP_ADD + OP_ADDK); 1346 op = cast(OpCode, op - OP_ADD + OP_ADDK);
1313 finishbinexpval(fs, e1, e2, op, v2, flip, line); 1347 finishbinexpval(fs, e1, e2, op, v2, flip, line);
@@ -1328,7 +1362,7 @@ static void codearith (FuncState *fs, OpCode op,
1328static void codecommutative (FuncState *fs, OpCode op, 1362static void codecommutative (FuncState *fs, OpCode op,
1329 expdesc *e1, expdesc *e2, int line) { 1363 expdesc *e1, expdesc *e2, int line) {
1330 int flip = 0; 1364 int flip = 0;
1331 if (tonumeral(e1, NULL)) { /* is first operand a numeric constant? */ 1365 if (luaK_tonumeral(fs, e1, NULL)) { /* is first operand a numeric constant? */
1332 swapexps(e1, e2); /* change order */ 1366 swapexps(e1, e2); /* change order */
1333 flip = 1; 1367 flip = 1;
1334 } 1368 }
@@ -1451,7 +1485,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
1451 case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ 1485 case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
1452 if (constfolding(fs, op + LUA_OPUNM, e, &ef)) 1486 if (constfolding(fs, op + LUA_OPUNM, e, &ef))
1453 break; 1487 break;
1454 /* FALLTHROUGH */ 1488 /* else */ /* FALLTHROUGH */
1455 case OPR_LEN: 1489 case OPR_LEN:
1456 codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); 1490 codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
1457 break; 1491 break;
@@ -1466,6 +1500,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
1466** 2nd operand. 1500** 2nd operand.
1467*/ 1501*/
1468void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { 1502void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
1503 luaK_dischargevars(fs, v);
1469 switch (op) { 1504 switch (op) {
1470 case OPR_AND: { 1505 case OPR_AND: {
1471 luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ 1506 luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */
@@ -1484,13 +1519,13 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
1484 case OPR_MOD: case OPR_POW: 1519 case OPR_MOD: case OPR_POW:
1485 case OPR_BAND: case OPR_BOR: case OPR_BXOR: 1520 case OPR_BAND: case OPR_BOR: case OPR_BXOR:
1486 case OPR_SHL: case OPR_SHR: { 1521 case OPR_SHL: case OPR_SHR: {
1487 if (!tonumeral(v, NULL)) 1522 if (!luaK_tonumeral(fs, v, NULL))
1488 luaK_exp2anyreg(fs, v); 1523 luaK_exp2anyreg(fs, v);
1489 /* else keep numeral, which may be folded with 2nd operand */ 1524 /* else keep numeral, which may be folded with 2nd operand */
1490 break; 1525 break;
1491 } 1526 }
1492 case OPR_EQ: case OPR_NE: { 1527 case OPR_EQ: case OPR_NE: {
1493 if (!tonumeral(v, NULL)) 1528 if (!luaK_tonumeral(fs, v, NULL))
1494 luaK_exp2RK(fs, v); 1529 luaK_exp2RK(fs, v);
1495 /* else keep numeral, which may be an immediate operand */ 1530 /* else keep numeral, which may be an immediate operand */
1496 break; 1531 break;
@@ -1535,17 +1570,16 @@ static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) {
1535*/ 1570*/
1536void luaK_posfix (FuncState *fs, BinOpr opr, 1571void luaK_posfix (FuncState *fs, BinOpr opr,
1537 expdesc *e1, expdesc *e2, int line) { 1572 expdesc *e1, expdesc *e2, int line) {
1573 luaK_dischargevars(fs, e2);
1538 switch (opr) { 1574 switch (opr) {
1539 case OPR_AND: { 1575 case OPR_AND: {
1540 lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ 1576 lua_assert(e1->t == NO_JUMP); /* list closed by 'luaK_infix' */
1541 luaK_dischargevars(fs, e2);
1542 luaK_concat(fs, &e2->f, e1->f); 1577 luaK_concat(fs, &e2->f, e1->f);
1543 *e1 = *e2; 1578 *e1 = *e2;
1544 break; 1579 break;
1545 } 1580 }
1546 case OPR_OR: { 1581 case OPR_OR: {
1547 lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ 1582 lua_assert(e1->f == NO_JUMP); /* list closed by 'luaK_infix' */
1548 luaK_dischargevars(fs, e2);
1549 luaK_concat(fs, &e2->t, e1->t); 1583 luaK_concat(fs, &e2->t, e1->t);
1550 *e1 = *e2; 1584 *e1 = *e2;
1551 break; 1585 break;
diff --git a/lcode.h b/lcode.h
index 0758f88d..c4953295 100644
--- a/lcode.h
+++ b/lcode.h
@@ -51,6 +51,7 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
51 51
52#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) 52#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
53 53
54LUAI_FUNC int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v);
54LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); 55LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
55LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); 56LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
56LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, 57LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
diff --git a/lparser.c b/lparser.c
index 3c68f2d7..875f7d04 100644
--- a/lparser.c
+++ b/lparser.c
@@ -206,6 +206,7 @@ static Vardesc *new_localvar (LexState *ls, TString *name) {
206 var = &dyd->actvar.arr[dyd->actvar.n++]; 206 var = &dyd->actvar.arr[dyd->actvar.n++];
207 var->idx = cast(short, reg); 207 var->idx = cast(short, reg);
208 var->ro = 0; 208 var->ro = 0;
209 setnilvalue(&var->val);
209 return var; 210 return var;
210} 211}
211 212
@@ -238,7 +239,7 @@ static LocVar *getlocvar (FuncState *fs, int i) {
238** where that variable was defined. Return NULL if expression 239** where that variable was defined. Return NULL if expression
239** is neither a local variable nor an upvalue. 240** is neither a local variable nor an upvalue.
240*/ 241*/
241static Vardesc *getvardesc (FuncState **fs, expdesc *e) { 242Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e) {
242 if (e->k == VLOCAL) 243 if (e->k == VLOCAL)
243 return getlocalvardesc(*fs, e->u.var.idx); 244 return getlocalvardesc(*fs, e->u.var.idx);
244 else if (e->k != VUPVAL) 245 else if (e->k != VUPVAL)
@@ -261,7 +262,7 @@ static Vardesc *getvardesc (FuncState **fs, expdesc *e) {
261 262
262static void check_readonly (LexState *ls, expdesc *e) { 263static void check_readonly (LexState *ls, expdesc *e) {
263 FuncState *fs = ls->fs; 264 FuncState *fs = ls->fs;
264 Vardesc *vardesc = getvardesc(&fs, e); 265 Vardesc *vardesc = luaY_getvardesc(&fs, e);
265 if (vardesc && vardesc->ro) { /* is variable local and const? */ 266 if (vardesc && vardesc->ro) { /* is variable local and const? */
266 const char *msg = luaO_pushfstring(ls->L, 267 const char *msg = luaO_pushfstring(ls->L,
267 "attempt to assign to const variable '%s'", 268 "attempt to assign to const variable '%s'",
@@ -1678,20 +1679,13 @@ static void commonlocalstat (LexState *ls) {
1678static void tocloselocalstat (LexState *ls, Vardesc *var) { 1679static void tocloselocalstat (LexState *ls, Vardesc *var) {
1679 FuncState *fs = ls->fs; 1680 FuncState *fs = ls->fs;
1680 var->ro = 1; /* to-be-closed variables are always read-only */ 1681 var->ro = 1; /* to-be-closed variables are always read-only */
1681 markupval(fs, fs->nactvar); 1682 markupval(fs, fs->nactvar + 1);
1682 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ 1683 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1683 luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); 1684 luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0);
1684} 1685}
1685 1686
1686 1687
1687static void attriblocalstat (LexState *ls) { 1688static void checkattrib (LexState *ls, TString *attr, Vardesc *var) {
1688 Vardesc *var;
1689 TString *attr = str_checkname(ls);
1690 testnext(ls, '>');
1691 var = new_localvar(ls, str_checkname(ls));
1692 checknext(ls, '=');
1693 exp1(ls);
1694 adjustlocalvars(ls, 1);
1695 if (strcmp(getstr(attr), "const") == 0) 1689 if (strcmp(getstr(attr), "const") == 0)
1696 var->ro = 1; /* set variable as read-only */ 1690 var->ro = 1; /* set variable as read-only */
1697 else if (strcmp(getstr(attr), "toclose") == 0) 1691 else if (strcmp(getstr(attr), "toclose") == 0)
@@ -1702,6 +1696,22 @@ static void attriblocalstat (LexState *ls) {
1702} 1696}
1703 1697
1704 1698
1699static void attriblocalstat (LexState *ls) {
1700 FuncState *fs = ls->fs;
1701 Vardesc *var;
1702 expdesc e;
1703 TString *attr = str_checkname(ls);
1704 testnext(ls, '>');
1705 var = new_localvar(ls, str_checkname(ls));
1706 checknext(ls, '=');
1707 expr(ls, &e);
1708 checkattrib(ls, attr, var);
1709 luaK_tonumeral(fs, &e, &var->val);
1710 luaK_exp2nextreg(fs, &e);
1711 adjustlocalvars(ls, 1);
1712}
1713
1714
1705static void localstat (LexState *ls) { 1715static void localstat (LexState *ls) {
1706 /* stat -> LOCAL NAME {',' NAME} ['=' explist] 1716 /* stat -> LOCAL NAME {',' NAME} ['=' explist]
1707 | LOCAL *toclose NAME '=' exp */ 1717 | LOCAL *toclose NAME '=' exp */
diff --git a/lparser.h b/lparser.h
index 228d4a5c..b708de25 100644
--- a/lparser.h
+++ b/lparser.h
@@ -81,6 +81,7 @@ typedef struct expdesc {
81 81
82/* description of an active local variable */ 82/* description of an active local variable */
83typedef struct Vardesc { 83typedef struct Vardesc {
84 TValue val; /* constant value (if variable is 'const') */
84 short idx; /* index of the variable in the Proto's 'locvars' array */ 85 short idx; /* index of the variable in the Proto's 'locvars' array */
85 lu_byte ro; /* true if variable is 'const' */ 86 lu_byte ro; /* true if variable is 'const' */
86} Vardesc; 87} Vardesc;
@@ -143,6 +144,7 @@ typedef struct FuncState {
143} FuncState; 144} FuncState;
144 145
145 146
147LUAI_FUNC Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e);
146LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 148LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
147 Dyndata *dyd, const char *name, int firstchar); 149 Dyndata *dyd, const char *name, int firstchar);
148 150