diff --git a/lcode.c b/lcode.c index c34c9648..30593c27 100644 --- a/lcode.c +++ b/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); } }