optimizations for "while 1", "until nil", and the like

This commit is contained in:
Roberto Ierusalimschy 2000-06-16 14:51:40 -03:00
parent 89a3ec08f3
commit 2e1b32d873
2 changed files with 103 additions and 55 deletions

155
lcode.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lcode.c,v 1.34 2000/06/05 14:56:18 roberto Exp roberto $ ** $Id: lcode.c,v 1.35 2000/06/12 13:52:05 roberto Exp roberto $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -268,20 +268,29 @@ void luaK_concat (FuncState *fs, int *l1, int l2) {
static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) { static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
int prevpos; /* position of last instruction */
Instruction *previous; Instruction *previous;
int *golist = &v->u.l.f; int *golist, *exitlist;
int *exitlist = &v->u.l.t; if (!invert) {
if (invert) { /* interchange `golist' and `exitlist' */ golist = &v->u.l.f; /* go if false */
int *temp = golist; golist = exitlist; exitlist = temp; exitlist = &v->u.l.t; /* exit if true */
}
else {
golist = &v->u.l.t; /* go if true */
exitlist = &v->u.l.f; /* exit if false */
} }
discharge1(fs, v); discharge1(fs, v);
previous = &fs->f->code[fs->pc-1]; prevpos = fs->pc-1;
LUA_ASSERT(L, GET_OPCODE(*previous) != OP_SETLINE, "bad place to set line"); previous = &fs->f->code[prevpos];
LUA_ASSERT(L, *previous==previous_instruction(fs), "no jump allowed here");
LUA_ASSERT(L, GET_OPCODE(*previous) != OP_SETLINE, "no setline allowed here");
if (!ISJUMP(GET_OPCODE(*previous))) if (!ISJUMP(GET_OPCODE(*previous)))
luaK_code1(fs, jump, NO_JUMP); prevpos = luaK_code1(fs, jump, NO_JUMP);
else if (invert) else { /* last instruction is already a jump */
SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); if (invert)
luaK_concat(fs, exitlist, fs->pc-1); /* insert last jump in `exitlist' */ SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
}
luaK_concat(fs, exitlist, prevpos); /* insert last jump in `exitlist' */
luaK_patchlist(fs, *golist, luaK_getlabel(fs)); luaK_patchlist(fs, *golist, luaK_getlabel(fs));
*golist = NO_JUMP; *golist = NO_JUMP;
} }
@ -292,7 +301,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) {
} }
void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) { static void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) {
luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT); luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT);
} }
@ -319,8 +328,8 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
int j = NO_JUMP; /* eventual jump over values */ int j = NO_JUMP; /* eventual jump over values */
int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */ int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */
int p_1 = NO_JUMP; /* position of an eventual PUSHINT */ int p_1 = NO_JUMP; /* position of an eventual PUSHINT */
if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF) || if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
need_value(fs, v->u.l.t, OP_JMPONT)) { || need_value(fs, v->u.l.t, OP_JMPONT)) {
/* expression needs values */ /* expression needs values */
if (ISJUMP(previous)) if (ISJUMP(previous))
luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */ luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */
@ -425,34 +434,33 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
int delta = luaK_opproperties[o].delta; int delta = luaK_opproperties[o].delta;
int optm = 0; /* 1 when there is an optimization */ int optm = 0; /* 1 when there is an optimization */
switch (o) { switch (o) {
case OP_CLOSURE: {
case OP_CLOSURE:
delta = -arg2+1; delta = -arg2+1;
break; break;
}
case OP_SETTABLE: case OP_SETTABLE: {
delta = -arg2; delta = -arg2;
break; break;
}
case OP_SETLIST: case OP_SETLIST: {
if (arg2 == 0) return NO_JUMP; /* nothing to do */ if (arg2 == 0) return NO_JUMP; /* nothing to do */
delta = -arg2; delta = -arg2;
break; break;
}
case OP_SETMAP: case OP_SETMAP: {
if (arg1 == 0) return NO_JUMP; /* nothing to do */ if (arg1 == 0) return NO_JUMP; /* nothing to do */
delta = -2*arg1; delta = -2*arg1;
break; break;
}
case OP_RETURN: case OP_RETURN: {
if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) {
SET_OPCODE(i, OP_TAILCALL); SET_OPCODE(i, OP_TAILCALL);
SETARG_B(i, arg1); SETARG_B(i, arg1);
optm = 1; optm = 1;
} }
break; break;
}
case OP_PUSHNIL: case OP_PUSHNIL: {
if (arg1 == 0) return NO_JUMP; /* nothing to do */ if (arg1 == 0) return NO_JUMP; /* nothing to do */
delta = arg1; delta = arg1;
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
@ -460,8 +468,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
default: break; default: break;
} }
break; break;
}
case OP_POP: case OP_POP: {
if (arg1 == 0) return NO_JUMP; /* nothing to do */ if (arg1 == 0) return NO_JUMP; /* nothing to do */
delta = -arg1; delta = -arg1;
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
@ -469,8 +477,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
default: break; default: break;
} }
break; break;
}
case OP_GETTABLE: case OP_GETTABLE: {
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
case OP_PUSHSTRING: /* `t.x' */ case OP_PUSHSTRING: /* `t.x' */
SET_OPCODE(i, OP_GETDOTTED); SET_OPCODE(i, OP_GETDOTTED);
@ -483,15 +491,15 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
default: break; default: break;
} }
break; break;
}
case OP_ADD: case OP_ADD: {
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */ case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */
default: break; default: break;
} }
break; break;
}
case OP_SUB: case OP_SUB: {
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
case OP_PUSHINT: /* `a-k' */ case OP_PUSHINT: /* `a-k' */
i = CREATE_S(OP_ADDI, -GETARG_S(i)); i = CREATE_S(OP_ADDI, -GETARG_S(i));
@ -500,8 +508,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
default: break; default: break;
} }
break; break;
}
case OP_CONCAT: case OP_CONCAT: {
delta = -arg1+1; delta = -arg1+1;
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
case OP_CONCAT: /* `a..b..c' */ case OP_CONCAT: /* `a..b..c' */
@ -511,8 +519,8 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
default: break; default: break;
} }
break; break;
}
case OP_MINUS: case OP_MINUS: {
switch(GET_OPCODE(i)) { switch(GET_OPCODE(i)) {
case OP_PUSHINT: /* `-k' */ case OP_PUSHINT: /* `-k' */
SETARG_S(i, -GETARG_S(i)); SETARG_S(i, -GETARG_S(i));
@ -525,50 +533,91 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
default: break; default: break;
} }
break; break;
}
case OP_JMPNE: case OP_JMPNE: {
if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */ if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */
i = CREATE_S(OP_JMPT, NO_JUMP); i = CREATE_S(OP_JMPT, NO_JUMP);
optm = 1; optm = 1;
} }
break; break;
}
case OP_JMPEQ: case OP_JMPEQ: {
if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */ if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */
i = CREATE_0(OP_NOT); i = CREATE_0(OP_NOT);
delta = -1; /* just undo effect of previous PUSHNIL */ delta = -1; /* just undo effect of previous PUSHNIL */
optm = 1; optm = 1;
} }
break; break;
}
case OP_JMPT: case OP_JMPT:
case OP_JMPF: case OP_JMPONT: {
case OP_JMPONT:
case OP_JMPONF:
switch (GET_OPCODE(i)) { switch (GET_OPCODE(i)) {
case OP_NOT: i = CREATE_S(invertjump(o), NO_JUMP); optm = 1; break; case OP_NOT: {
i = CREATE_S(OP_JMPF, NO_JUMP);
optm = 1;
break;
}
case OP_PUSHINT: {
if (o == OP_JMPT) { /* JMPONT must keep original integer value */
i = CREATE_S(OP_JMP, NO_JUMP);
optm = 1;
}
break;
}
case OP_PUSHNIL: {
if (GETARG_U(i) == 1) {
fs->pc--; /* erase previous instruction */
luaK_deltastack(fs, -1); /* correct stack */
return NO_JUMP;
}
break;
}
default: break; default: break;
} }
break; break;
}
case OP_JMPF:
case OP_JMPONF: {
switch (GET_OPCODE(i)) {
case OP_NOT: {
i = CREATE_S(OP_JMPT, NO_JUMP);
optm = 1;
break;
}
case OP_PUSHINT: { /* `while 1 do ...' */
fs->pc--; /* erase previous instruction */
luaK_deltastack(fs, -1); /* correct stack */
return NO_JUMP;
}
case OP_PUSHNIL: { /* `repeat ... until nil' */
if (GETARG_U(i) == 1) {
i = CREATE_S(OP_JMP, NO_JUMP);
optm = 1;
}
break;
}
default: break;
}
break;
}
case OP_GETDOTTED: case OP_GETDOTTED:
case OP_GETINDEXED: case OP_GETINDEXED:
case OP_TAILCALL: case OP_TAILCALL:
case OP_ADDI: case OP_ADDI: {
LUA_INTERNALERROR(L, "instruction used only for optimizations"); LUA_INTERNALERROR(L, "instruction used only for optimizations");
break; break;
}
default: default: {
LUA_ASSERT(L, delta != VD, "invalid delta"); LUA_ASSERT(L, delta != VD, "invalid delta");
break; break;
}
} }
luaK_deltastack(fs, delta); luaK_deltastack(fs, delta);
if (optm) { /* optimize: put instruction in place of last one */ if (optm) { /* optimize: put instruction in place of last one */
fs->f->code[fs->pc-1] = i; /* change previous instruction */ fs->f->code[fs->pc-1] = i; /* change previous instruction */
return fs->pc-1; /* do not generate new instruction */ return fs->pc-1; /* do not generate new instruction */
} }
/* build new instruction */ /* else build new instruction */
switch ((enum Mode)luaK_opproperties[o].mode) { switch ((enum Mode)luaK_opproperties[o].mode) {
case iO: i = CREATE_0(o); break; case iO: i = CREATE_0(o); break;
case iU: i = CREATE_U(o, arg1); break; case iU: i = CREATE_U(o, arg1); break;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lcode.h,v 1.12 2000/04/12 18:47:03 roberto Exp roberto $ ** $Id: lcode.h,v 1.13 2000/05/22 18:44:46 roberto Exp roberto $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -36,7 +36,6 @@ int luaK_jump (FuncState *fs);
void luaK_patchlist (FuncState *fs, int list, int target); void luaK_patchlist (FuncState *fs, int list, int target);
void luaK_concat (FuncState *fs, int *l1, int l2); void luaK_concat (FuncState *fs, int *l1, int l2);
void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue); void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue);
int luaK_getlabel (FuncState *fs); int luaK_getlabel (FuncState *fs);
void luaK_deltastack (FuncState *fs, int delta); void luaK_deltastack (FuncState *fs, int delta);
void luaK_kstr (LexState *ls, int c); void luaK_kstr (LexState *ls, int c);