mirror of
https://github.com/lua/lua
synced 2024-11-22 12:51:30 +03:00
constant folding optimizations
This commit is contained in:
parent
e6bfbc38b5
commit
e251e84e0f
227
lcode.c
227
lcode.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lcode.c,v 2.16 2005/08/29 20:49:21 roberto Exp roberto $
|
||||
** $Id: lcode.c,v 2.17 2005/09/30 14:23:33 roberto Exp roberto $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -27,6 +27,11 @@
|
||||
#define hasjumps(e) ((e)->t != (e)->f)
|
||||
|
||||
|
||||
static int isnumeral(FuncState *fs, expdesc *e) {
|
||||
return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
|
||||
}
|
||||
|
||||
|
||||
void luaK_nil (FuncState *fs, int from, int n) {
|
||||
Instruction *previous;
|
||||
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
|
||||
@ -213,7 +218,7 @@ static void freereg (FuncState *fs, int reg) {
|
||||
|
||||
static void freeexp (FuncState *fs, expdesc *e) {
|
||||
if (e->k == VNONRELOC)
|
||||
freereg(fs, e->info);
|
||||
freereg(fs, e->u.s.info);
|
||||
}
|
||||
|
||||
|
||||
@ -283,7 +288,7 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
|
||||
void luaK_setoneret (FuncState *fs, expdesc *e) {
|
||||
if (e->k == VCALL) { /* expression is an open function call? */
|
||||
e->k = VNONRELOC;
|
||||
e->info = GETARG_A(getcode(fs, e));
|
||||
e->u.s.info = GETARG_A(getcode(fs, e));
|
||||
}
|
||||
else if (e->k == VVARARG) {
|
||||
SETARG_B(getcode(fs, e), 2);
|
||||
@ -299,19 +304,19 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
||||
break;
|
||||
}
|
||||
case VUPVAL: {
|
||||
e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0);
|
||||
e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VGLOBAL: {
|
||||
e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info);
|
||||
e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VINDEXED: {
|
||||
freereg(fs, e->aux);
|
||||
freereg(fs, e->info);
|
||||
e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux);
|
||||
freereg(fs, e->u.s.aux);
|
||||
freereg(fs, e->u.s.info);
|
||||
e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
@ -343,7 +348,11 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
break;
|
||||
}
|
||||
case VK: {
|
||||
luaK_codeABx(fs, OP_LOADK, reg, e->info);
|
||||
luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
|
||||
break;
|
||||
}
|
||||
case VKNUM: {
|
||||
luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
|
||||
break;
|
||||
}
|
||||
case VRELOCABLE: {
|
||||
@ -352,8 +361,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
break;
|
||||
}
|
||||
case VNONRELOC: {
|
||||
if (reg != e->info)
|
||||
luaK_codeABC(fs, OP_MOVE, reg, e->info, 0);
|
||||
if (reg != e->u.s.info)
|
||||
luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -361,7 +370,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
return; /* nothing to do... */
|
||||
}
|
||||
}
|
||||
e->info = reg;
|
||||
e->u.s.info = reg;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
@ -377,7 +386,7 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) {
|
||||
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
discharge2reg(fs, e, reg);
|
||||
if (e->k == VJMP)
|
||||
luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */
|
||||
luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */
|
||||
if (hasjumps(e)) {
|
||||
int final; /* position after whole expression */
|
||||
int p_f = NO_JUMP; /* position of an eventual LOAD false */
|
||||
@ -395,7 +404,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
patchlistaux(fs, e->t, final, reg, p_t);
|
||||
}
|
||||
e->f = e->t = NO_JUMP;
|
||||
e->info = reg;
|
||||
e->u.s.info = reg;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
@ -411,14 +420,14 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
|
||||
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
if (e->k == VNONRELOC) {
|
||||
if (!hasjumps(e)) return e->info; /* exp is already in a register */
|
||||
if (e->info >= fs->nactvar) { /* reg. is not a local? */
|
||||
exp2reg(fs, e, e->info); /* put value on it */
|
||||
return e->info;
|
||||
if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */
|
||||
if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */
|
||||
exp2reg(fs, e, e->u.s.info); /* put value on it */
|
||||
return e->u.s.info;
|
||||
}
|
||||
}
|
||||
luaK_exp2nextreg(fs, e); /* default */
|
||||
return e->info;
|
||||
return e->u.s.info;
|
||||
}
|
||||
|
||||
|
||||
@ -433,19 +442,22 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
|
||||
int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
||||
luaK_exp2val(fs, e);
|
||||
switch (e->k) {
|
||||
case VKNUM:
|
||||
case VTRUE:
|
||||
case VFALSE:
|
||||
case VNIL: {
|
||||
if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */
|
||||
e->info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
|
||||
e->u.s.info = (e->k == VNIL) ? nilK(fs) :
|
||||
(e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
|
||||
boolK(fs, (e->k == VTRUE));
|
||||
e->k = VK;
|
||||
return RKASK(e->info);
|
||||
return RKASK(e->u.s.info);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
case VK: {
|
||||
if (e->info <= MAXINDEXRK) /* constant fit in argC? */
|
||||
return RKASK(e->info);
|
||||
if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */
|
||||
return RKASK(e->u.s.info);
|
||||
else break;
|
||||
}
|
||||
default: break;
|
||||
@ -459,22 +471,22 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
|
||||
switch (var->k) {
|
||||
case VLOCAL: {
|
||||
freeexp(fs, ex);
|
||||
exp2reg(fs, ex, var->info);
|
||||
exp2reg(fs, ex, var->u.s.info);
|
||||
return;
|
||||
}
|
||||
case VUPVAL: {
|
||||
int e = luaK_exp2anyreg(fs, ex);
|
||||
luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0);
|
||||
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
|
||||
break;
|
||||
}
|
||||
case VGLOBAL: {
|
||||
int e = luaK_exp2anyreg(fs, ex);
|
||||
luaK_codeABx(fs, OP_SETGLOBAL, e, var->info);
|
||||
luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
|
||||
break;
|
||||
}
|
||||
case VINDEXED: {
|
||||
int e = luaK_exp2RK(fs, ex);
|
||||
luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e);
|
||||
luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -492,15 +504,15 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
|
||||
freeexp(fs, e);
|
||||
func = fs->freereg;
|
||||
luaK_reserveregs(fs, 2);
|
||||
luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key));
|
||||
luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
|
||||
freeexp(fs, key);
|
||||
e->info = func;
|
||||
e->u.s.info = func;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
|
||||
static void invertjump (FuncState *fs, expdesc *e) {
|
||||
Instruction *pc = getjumpcontrol(fs, e->info);
|
||||
Instruction *pc = getjumpcontrol(fs, e->u.s.info);
|
||||
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
|
||||
GET_OPCODE(*pc) != OP_TEST);
|
||||
SETARG_A(*pc, !(GETARG_A(*pc)));
|
||||
@ -518,7 +530,7 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
|
||||
}
|
||||
discharge2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
return condjump(fs, OP_TESTSET, NO_REG, e->info, cond);
|
||||
return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
|
||||
}
|
||||
|
||||
|
||||
@ -526,7 +538,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
||||
int pc; /* pc of last jump */
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VK: case VTRUE: {
|
||||
case VK: case VKNUM: case VTRUE: {
|
||||
pc = NO_JUMP; /* always true; do nothing */
|
||||
break;
|
||||
}
|
||||
@ -536,7 +548,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
||||
}
|
||||
case VJMP: {
|
||||
invertjump(fs, e);
|
||||
pc = e->info;
|
||||
pc = e->u.s.info;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -563,7 +575,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
||||
break;
|
||||
}
|
||||
case VJMP: {
|
||||
pc = e->info;
|
||||
pc = e->u.s.info;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -584,7 +596,7 @@ static void codenot (FuncState *fs, expdesc *e) {
|
||||
e->k = VTRUE;
|
||||
break;
|
||||
}
|
||||
case VK: case VTRUE: {
|
||||
case VK: case VKNUM: case VTRUE: {
|
||||
e->k = VFALSE;
|
||||
break;
|
||||
}
|
||||
@ -596,7 +608,7 @@ static void codenot (FuncState *fs, expdesc *e) {
|
||||
case VNONRELOC: {
|
||||
discharge2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0);
|
||||
e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
@ -613,34 +625,79 @@ static void codenot (FuncState *fs, expdesc *e) {
|
||||
|
||||
|
||||
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
||||
t->aux = luaK_exp2RK(fs, k);
|
||||
t->u.s.aux = luaK_exp2RK(fs, k);
|
||||
t->k = VINDEXED;
|
||||
}
|
||||
|
||||
|
||||
static int constfolding (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
|
||||
lua_Number v1, v2, r;
|
||||
if (!isnumeral(fs, e1) || !isnumeral(fs, e2)) return 0;
|
||||
v1 = e1->u.nval;
|
||||
v2 = e2->u.nval;
|
||||
switch (op) {
|
||||
case OP_ADD: r = luai_numadd(fs->L, v1, v2); break;
|
||||
case OP_SUB: r = luai_numsub(fs->L, v1, v2); break;
|
||||
case OP_MUL: r = luai_nummul(fs->L, v1, v2); break;
|
||||
case OP_DIV:
|
||||
if (v2 == 0) return 0; /* do not attempt to divide by 0 */
|
||||
r = luai_numdiv(fs->L, v1, v2); break;
|
||||
case OP_MOD: r = luai_nummod(fs->L, v1, v2); break;
|
||||
case OP_POW: r = luai_numpow(fs->L, v1, v2); break;
|
||||
case OP_UNM: r = luai_numunm(fs->L, v1); break;
|
||||
case OP_LEN: return 0; /* no constant folding for 'len' */
|
||||
default: lua_assert(0); r = 0; break;
|
||||
}
|
||||
if (r != r) return 0; /* do not attempt to produce NaN */
|
||||
e1->u.nval = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
|
||||
if (constfolding(fs, op, e1, e2))
|
||||
return;
|
||||
else {
|
||||
int o1 = luaK_exp2RK(fs, e1);
|
||||
int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
|
||||
e1->k = VRELOCABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
|
||||
expdesc *e2) {
|
||||
int o1 = luaK_exp2RK(fs, e1);
|
||||
int o2 = luaK_exp2RK(fs, e2);
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
if (cond == 0 && op != OP_EQ) {
|
||||
int temp; /* exchange args to replace by `<' or `<=' */
|
||||
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
|
||||
cond = 1;
|
||||
}
|
||||
e1->u.s.info = condjump(fs, op, cond, o1, o2);
|
||||
e1->k = VJMP;
|
||||
}
|
||||
|
||||
|
||||
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
|
||||
expdesc e2;
|
||||
e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
|
||||
switch (op) {
|
||||
case OPR_MINUS: {
|
||||
luaK_exp2val(fs, e);
|
||||
if (e->k == VK && ttisnumber(&fs->f->k[e->info]))
|
||||
e->info = luaK_numberK(fs, luai_numunm(L, nvalue(&fs->f->k[e->info])));
|
||||
else {
|
||||
luaK_exp2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPR_NOT: {
|
||||
codenot(fs, e);
|
||||
if (e->k == VK)
|
||||
luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */
|
||||
codearith(fs, OP_UNM, e, &e2);
|
||||
break;
|
||||
}
|
||||
case OPR_NOT: codenot(fs, e); break;
|
||||
case OPR_LEN: {
|
||||
luaK_exp2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
e->info = luaK_codeABC(fs, OP_LEN, 0, e->info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
luaK_exp2anyreg(fs, e); /* cannot operate on constants */
|
||||
codearith(fs, OP_LEN, e, &e2);
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
@ -663,74 +720,58 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
luaK_exp2RK(fs, v);
|
||||
if (!isnumeral(fs, v)) luaK_exp2RK(fs, v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void codebinop (FuncState *fs, expdesc *res, BinOpr op,
|
||||
int o1, int o2) {
|
||||
if (op <= OPR_POW) { /* arithmetic operator? */
|
||||
OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */
|
||||
res->info = luaK_codeABC(fs, opc, 0, o1, o2);
|
||||
res->k = VRELOCABLE;
|
||||
}
|
||||
else { /* test operator */
|
||||
static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE};
|
||||
int cond = 1;
|
||||
if (op >= OPR_GT) { /* `>' or `>='? */
|
||||
int temp; /* exchange args and replace by `<' or `<=' */
|
||||
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
|
||||
}
|
||||
else if (op == OPR_NE) cond = 0;
|
||||
res->info = condjump(fs, ops[op - OPR_NE], cond, o1, o2);
|
||||
res->k = VJMP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
|
||||
switch (op) {
|
||||
case OPR_AND: {
|
||||
lua_assert(e1->t == NO_JUMP); /* list must be closed */
|
||||
luaK_dischargevars(fs, e2);
|
||||
luaK_concat(fs, &e1->f, e2->f);
|
||||
e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t;
|
||||
e1->k = e2->k; e1->u.s.info = e2->u.s.info;
|
||||
e1->u.s.aux = e2->u.s.aux; e1->t = e2->t;
|
||||
break;
|
||||
}
|
||||
case OPR_OR: {
|
||||
lua_assert(e1->f == NO_JUMP); /* list must be closed */
|
||||
luaK_dischargevars(fs, e2);
|
||||
luaK_concat(fs, &e1->t, e2->t);
|
||||
e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f;
|
||||
e1->k = e2->k; e1->u.s.info = e2->u.s.info;
|
||||
e1->u.s.aux = e2->u.s.aux; e1->f = e2->f;
|
||||
break;
|
||||
}
|
||||
case OPR_CONCAT: {
|
||||
luaK_exp2val(fs, e2);
|
||||
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
|
||||
lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1);
|
||||
lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
|
||||
freeexp(fs, e1);
|
||||
SETARG_B(getcode(fs, e2), e1->info);
|
||||
e1->k = e2->k; e1->info = e2->info;
|
||||
SETARG_B(getcode(fs, e2), e1->u.s.info);
|
||||
e1->k = e2->k; e1->u.s.info = e2->u.s.info;
|
||||
}
|
||||
else {
|
||||
luaK_exp2nextreg(fs, e2);
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info);
|
||||
e1->k = VRELOCABLE;
|
||||
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
|
||||
codearith(fs, OP_CONCAT, e1, e2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
int o1 = luaK_exp2RK(fs, e1);
|
||||
int o2 = luaK_exp2RK(fs, e2);
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
codebinop(fs, e1, op, o1, o2);
|
||||
}
|
||||
case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
|
||||
case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
|
||||
case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
|
||||
case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
|
||||
case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
|
||||
case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
|
||||
case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
|
||||
case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
|
||||
case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
|
||||
case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
|
||||
case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
|
||||
case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user