diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-12 11:38:42 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-12 11:38:42 -0300 |
commit | f6aab3ec1f111cd8d968bdcb7ca800e93b819d24 (patch) | |
tree | 4c36c418ecc9062e6d95de73457198b38b0afce9 /lparser.c | |
parent | be8445d7e4b6122620c428877b51a27d464253d5 (diff) | |
download | lua-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.c | 113 |
1 files changed, 64 insertions, 49 deletions
@@ -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 | */ |
173 | static int registerlocalvar (lua_State *L, FuncState *fs, TString *varname) { | 173 | static 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) { | |||
225 | static int stacklevel (FuncState *fs, int nvar) { | 223 | static 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 | */ |
248 | static LocVar *localdebuginfo (FuncState *fs, int i) { | 246 | static 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 | */ |
376 | static int searchvar (FuncState *fs, TString *n) { | 378 | static 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 | */ |
485 | static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { | 492 | static 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 | ||
1724 | static void checktoclose (LexState *ls, int toclose) { | 1731 | static 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 | ||
1735 | static void localstat (LexState *ls) { | 1741 | static 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 */ |