aboutsummaryrefslogtreecommitdiff
path: root/lparser.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-12 11:38:42 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-12 11:38:42 -0300
commitf6aab3ec1f111cd8d968bdcb7ca800e93b819d24 (patch)
tree4c36c418ecc9062e6d95de73457198b38b0afce9 /lparser.c
parentbe8445d7e4b6122620c428877b51a27d464253d5 (diff)
downloadlua-f6aab3ec1f111cd8d968bdcb7ca800e93b819d24.tar.gz
lua-f6aab3ec1f111cd8d968bdcb7ca800e93b819d24.tar.bz2
lua-f6aab3ec1f111cd8d968bdcb7ca800e93b819d24.zip
First implementation of constant propagation
Local constant variables initialized with compile-time constants are optimized away from the code.
Diffstat (limited to 'lparser.c')
-rw-r--r--lparser.c113
1 files changed, 64 insertions, 49 deletions
diff --git a/lparser.c b/lparser.c
index 7f282bf9..79df0217 100644
--- a/lparser.c
+++ b/lparser.c
@@ -170,15 +170,16 @@ static void codename (LexState *ls, expdesc *e) {
170** Register a new local variable in the active 'Proto' (for debug 170** Register a new local variable in the active 'Proto' (for debug
171** information). 171** information).
172*/ 172*/
173static int registerlocalvar (lua_State *L, FuncState *fs, TString *varname) { 173static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) {
174 Proto *f = fs->f; 174 Proto *f = fs->f;
175 int oldsize = f->sizelocvars; 175 int oldsize = f->sizelocvars;
176 luaM_growvector(L, f->locvars, fs->ndebugvars, f->sizelocvars, 176 luaM_growvector(ls->L, f->locvars, fs->ndebugvars, f->sizelocvars,
177 LocVar, SHRT_MAX, "local variables"); 177 LocVar, SHRT_MAX, "local variables");
178 while (oldsize < f->sizelocvars) 178 while (oldsize < f->sizelocvars)
179 f->locvars[oldsize++].varname = NULL; 179 f->locvars[oldsize++].varname = NULL;
180 f->locvars[fs->ndebugvars].varname = varname; 180 f->locvars[fs->ndebugvars].varname = varname;
181 luaC_objbarrier(L, f, varname); 181 f->locvars[fs->ndebugvars].startpc = fs->pc;
182 luaC_objbarrier(ls->L, f, varname);
182 return fs->ndebugvars++; 183 return fs->ndebugvars++;
183} 184}
184 185
@@ -191,16 +192,13 @@ static Vardesc *new_localvar (LexState *ls, TString *name) {
191 FuncState *fs = ls->fs; 192 FuncState *fs = ls->fs;
192 Dyndata *dyd = ls->dyd; 193 Dyndata *dyd = ls->dyd;
193 Vardesc *var; 194 Vardesc *var;
194 int reg = registerlocalvar(L, fs, name);
195 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, 195 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
196 MAXVARS, "local variables"); 196 MAXVARS, "local variables");
197 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, 197 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
198 dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); 198 dyd->actvar.size, Vardesc, USHRT_MAX, "local variables");
199 var = &dyd->actvar.arr[dyd->actvar.n++]; 199 var = &dyd->actvar.arr[dyd->actvar.n++];
200 var->pidx = cast(short, reg); 200 var->vd.kind = VDKREG; /* default is a regular variable */
201 var->ro = 0; 201 var->vd.name = name;
202 var->name = name;
203 setnilvalue(var);
204 return var; 202 return var;
205} 203}
206 204
@@ -225,8 +223,8 @@ static Vardesc *getlocalvardesc (FuncState *fs, int i) {
225static int stacklevel (FuncState *fs, int nvar) { 223static int stacklevel (FuncState *fs, int nvar) {
226 while (nvar > 0) { 224 while (nvar > 0) {
227 Vardesc *vd = getlocalvardesc(fs, nvar - 1); 225 Vardesc *vd = getlocalvardesc(fs, nvar - 1);
228 if (vdinstack(vd)) /* is in the stack? */ 226 if (vd->vd.kind != RDKCTC) /* is in the stack? */
229 return vd->sidx + 1; 227 return vd->vd.sidx + 1;
230 else 228 else
231 nvar--; /* try previous variable */ 229 nvar--; /* try previous variable */
232 } 230 }
@@ -247,10 +245,10 @@ int luaY_nvarstack (FuncState *fs) {
247*/ 245*/
248static LocVar *localdebuginfo (FuncState *fs, int i) { 246static LocVar *localdebuginfo (FuncState *fs, int i) {
249 Vardesc *vd = getlocalvardesc(fs, i); 247 Vardesc *vd = getlocalvardesc(fs, i);
250 if (!vdinstack(vd)) 248 if (vd->vd.kind == RDKCTC)
251 return NULL; /* no debug info. for constants */ 249 return NULL; /* no debug info. for constants */
252 else { 250 else {
253 int idx = vd->pidx; 251 int idx = vd->vd.pidx;
254 lua_assert(idx < fs->ndebugvars); 252 lua_assert(idx < fs->ndebugvars);
255 return &fs->f->locvars[idx]; 253 return &fs->f->locvars[idx];
256 } 254 }
@@ -261,7 +259,7 @@ static void init_var (FuncState *fs, expdesc *e, int i) {
261 e->f = e->t = NO_JUMP; 259 e->f = e->t = NO_JUMP;
262 e->k = VLOCAL; 260 e->k = VLOCAL;
263 e->u.var.vidx = i; 261 e->u.var.vidx = i;
264 e->u.var.sidx = getlocalvardesc(fs, i)->sidx; 262 e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx;
265} 263}
266 264
267 265
@@ -269,15 +267,19 @@ static void check_readonly (LexState *ls, expdesc *e) {
269 FuncState *fs = ls->fs; 267 FuncState *fs = ls->fs;
270 TString *varname = NULL; /* to be set if variable is const */ 268 TString *varname = NULL; /* to be set if variable is const */
271 switch (e->k) { 269 switch (e->k) {
270 case VCONST: {
271 varname = ls->dyd->actvar.arr[e->u.info].vd.name;
272 break;
273 }
272 case VLOCAL: { 274 case VLOCAL: {
273 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); 275 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
274 if (vardesc->ro) 276 if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
275 varname = vardesc->name; 277 varname = vardesc->vd.name;
276 break; 278 break;
277 } 279 }
278 case VUPVAL: { 280 case VUPVAL: {
279 Upvaldesc *up = &fs->f->upvalues[e->u.info]; 281 Upvaldesc *up = &fs->f->upvalues[e->u.info];
280 if (up->ro) 282 if (up->kind != VDKREG)
281 varname = up->name; 283 varname = up->name;
282 break; 284 break;
283 } 285 }
@@ -302,8 +304,8 @@ static void adjustlocalvars (LexState *ls, int nvars) {
302 for (i = 0; i < nvars; i++) { 304 for (i = 0; i < nvars; i++) {
303 int varidx = fs->nactvar++; 305 int varidx = fs->nactvar++;
304 Vardesc *var = getlocalvardesc(fs, varidx); 306 Vardesc *var = getlocalvardesc(fs, varidx);
305 var->sidx = stklevel++; 307 var->vd.sidx = stklevel++;
306 fs->f->locvars[var->pidx].startpc = fs->pc; 308 var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
307 } 309 }
308} 310}
309 311
@@ -354,13 +356,13 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
354 if (v->k == VLOCAL) { 356 if (v->k == VLOCAL) {
355 up->instack = 1; 357 up->instack = 1;
356 up->idx = v->u.var.sidx; 358 up->idx = v->u.var.sidx;
357 up->ro = getlocalvardesc(prev, v->u.var.vidx)->ro; 359 up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
358 lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->name)); 360 lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
359 } 361 }
360 else { 362 else {
361 up->instack = 0; 363 up->instack = 0;
362 up->idx = cast_byte(v->u.info); 364 up->idx = cast_byte(v->u.info);
363 up->ro = prev->f->upvalues[v->u.info].ro; 365 up->kind = prev->f->upvalues[v->u.info].kind;
364 lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name)); 366 lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name));
365 } 367 }
366 up->name = name; 368 up->name = name;
@@ -373,11 +375,17 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
373** Look for an active local variable with the name 'n' in the 375** Look for an active local variable with the name 'n' in the
374** function 'fs'. 376** function 'fs'.
375*/ 377*/
376static int searchvar (FuncState *fs, TString *n) { 378static int searchvar (FuncState *fs, TString *n, expdesc *var) {
377 int i; 379 int i;
378 for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { 380 for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
379 if (eqstr(n, getlocalvardesc(fs, i)->name)) 381 Vardesc *vd = getlocalvardesc(fs, i);
380 return i; 382 if (eqstr(n, vd->vd.name)) { /* found? */
383 if (vd->vd.kind == RDKCTC) /* compile-time constant? */
384 init_exp(var, VCONST, fs->firstlocal + i);
385 else /* real variable */
386 init_var(fs, var, i);
387 return var->k;
388 }
381 } 389 }
382 return -1; /* not found */ 390 return -1; /* not found */
383} 391}
@@ -405,20 +413,19 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
405 if (fs == NULL) /* no more levels? */ 413 if (fs == NULL) /* no more levels? */
406 init_exp(var, VVOID, 0); /* default is global */ 414 init_exp(var, VVOID, 0); /* default is global */
407 else { 415 else {
408 int v = searchvar(fs, n); /* look up locals at current level */ 416 int v = searchvar(fs, n, var); /* look up locals at current level */
409 if (v >= 0) { /* found? */ 417 if (v >= 0) { /* found? */
410 init_var(fs, var, v); /* variable is local */ 418 if (v == VLOCAL && !base)
411 if (!base)
412 markupval(fs, var->u.var.vidx); /* local will be used as an upval */ 419 markupval(fs, var->u.var.vidx); /* local will be used as an upval */
413 } 420 }
414 else { /* not found as local at current level; try upvalues */ 421 else { /* not found as local at current level; try upvalues */
415 int idx = searchupvalue(fs, n); /* try existing upvalues */ 422 int idx = searchupvalue(fs, n); /* try existing upvalues */
416 if (idx < 0) { /* not found? */ 423 if (idx < 0) { /* not found? */
417 singlevaraux(fs->prev, n, var, 0); /* try upper levels */ 424 singlevaraux(fs->prev, n, var, 0); /* try upper levels */
418 if (var->k == VVOID) /* not found? */ 425 if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */
419 return; /* it is a global */ 426 idx = newupvalue(fs, n, var); /* will be a new upvalue */
420 /* else was LOCAL or UPVAL */ 427 else /* it is a global or a constant */
421 idx = newupvalue(fs, n, var); /* will be a new upvalue */ 428 return; /* don't need to do anything at this level */
422 } 429 }
423 init_exp(var, VUPVAL, idx); /* new or old upvalue */ 430 init_exp(var, VUPVAL, idx); /* new or old upvalue */
424 } 431 }
@@ -483,7 +490,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
483** local variable. 490** local variable.
484*/ 491*/
485static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { 492static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
486 const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->name); 493 const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->vd.name);
487 const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; 494 const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'";
488 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); 495 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname);
489 luaK_semerror(ls, msg); /* raise the error */ 496 luaK_semerror(ls, msg); /* raise the error */
@@ -1710,21 +1717,20 @@ static int getlocalattribute (LexState *ls) {
1710 const char *attr = getstr(str_checkname(ls)); 1717 const char *attr = getstr(str_checkname(ls));
1711 checknext(ls, '>'); 1718 checknext(ls, '>');
1712 if (strcmp(attr, "const") == 0) 1719 if (strcmp(attr, "const") == 0)
1713 return 1; /* read-only variable */ 1720 return RDKCONST; /* read-only variable */
1714 else if (strcmp(attr, "toclose") == 0) 1721 else if (strcmp(attr, "toclose") == 0)
1715 return 2; /* to-be-closed variable */ 1722 return RDKTOCLOSE; /* to-be-closed variable */
1716 else 1723 else
1717 luaK_semerror(ls, 1724 luaK_semerror(ls,
1718 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); 1725 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
1719 } 1726 }
1720 return 0; 1727 return VDKREG;
1721} 1728}
1722 1729
1723 1730
1724static void checktoclose (LexState *ls, int toclose) { 1731static void checktoclose (LexState *ls, int level) {
1725 if (toclose != -1) { /* is there a to-be-closed variable? */ 1732 if (level != -1) { /* is there a to-be-closed variable? */
1726 FuncState *fs = ls->fs; 1733 FuncState *fs = ls->fs;
1727 int level = luaY_nvarstack(fs) + toclose;
1728 markupval(fs, level + 1); 1734 markupval(fs, level + 1);
1729 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ 1735 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1730 luaK_codeABC(fs, OP_TBC, level, 0, 0); 1736 luaK_codeABC(fs, OP_TBC, level, 0, 0);
@@ -1734,20 +1740,20 @@ static void checktoclose (LexState *ls, int toclose) {
1734 1740
1735static void localstat (LexState *ls) { 1741static void localstat (LexState *ls) {
1736 /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */ 1742 /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */
1743 FuncState *fs = ls->fs;
1737 int toclose = -1; /* index of to-be-closed variable (if any) */ 1744 int toclose = -1; /* index of to-be-closed variable (if any) */
1745 Vardesc *var; /* last variable */
1738 int nvars = 0; 1746 int nvars = 0;
1739 int nexps; 1747 int nexps;
1740 expdesc e; 1748 expdesc e;
1741 do { 1749 do {
1742 int kind = getlocalattribute(ls); 1750 int kind = getlocalattribute(ls);
1743 Vardesc *var = new_localvar(ls, str_checkname(ls)); 1751 var = new_localvar(ls, str_checkname(ls));
1744 if (kind != 0) { /* is there an attribute? */ 1752 var->vd.kind = kind;
1745 var->ro = 1; /* all attributes make variable read-only */ 1753 if (kind == RDKTOCLOSE) { /* to-be-closed? */
1746 if (kind == 2) { /* to-be-closed? */ 1754 if (toclose != -1) /* one already present? */
1747 if (toclose != -1) /* one already present? */ 1755 luaK_semerror(ls, "multiple to-be-closed variables in local list");
1748 luaK_semerror(ls, "multiple to-be-closed variables in local list"); 1756 toclose = luaY_nvarstack(fs) + nvars;
1749 toclose = nvars;
1750 }
1751 } 1757 }
1752 nvars++; 1758 nvars++;
1753 } while (testnext(ls, ',')); 1759 } while (testnext(ls, ','));
@@ -1757,9 +1763,18 @@ static void localstat (LexState *ls) {
1757 e.k = VVOID; 1763 e.k = VVOID;
1758 nexps = 0; 1764 nexps = 0;
1759 } 1765 }
1760 adjust_assign(ls, nvars, nexps, &e); 1766 if (nvars == nexps && /* no adjustments? */
1767 var->vd.kind == RDKCONST && /* last variable is const? */
1768 luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */
1769 var->vd.kind = RDKCTC; /* variable is a compile-time constant */
1770 adjustlocalvars(ls, nvars - 1); /* exclude last variable */
1771 fs->nactvar++; /* but count it */
1772 }
1773 else {
1774 adjust_assign(ls, nvars, nexps, &e);
1775 adjustlocalvars(ls, nvars);
1776 }
1761 checktoclose(ls, toclose); 1777 checktoclose(ls, toclose);
1762 adjustlocalvars(ls, nvars);
1763} 1778}
1764 1779
1765 1780
@@ -1925,7 +1940,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
1925 env = allocupvalue(fs); /* ...set environment upvalue */ 1940 env = allocupvalue(fs); /* ...set environment upvalue */
1926 env->instack = 1; 1941 env->instack = 1;
1927 env->idx = 0; 1942 env->idx = 0;
1928 env->ro = 0; 1943 env->kind = VDKREG;
1929 env->name = ls->envn; 1944 env->name = ls->envn;
1930 luaX_next(ls); /* read first token */ 1945 luaX_next(ls); /* read first token */
1931 statlist(ls); /* parse main body */ 1946 statlist(ls); /* parse main body */