summaryrefslogtreecommitdiff
path: root/src/lcode.c
diff options
context:
space:
mode:
authorLua Team <team@lua.org>2005-11-18 12:00:00 +0000
committerrepogen <>2005-11-18 12:00:00 +0000
commitb3196343ba1a5dfe10e68eb9c61dc0ad5bb961a8 (patch)
treed3efede68270d3986c0f78101e55d17577a62666 /src/lcode.c
parentbd80c4ee9b6d9464cf9f3ff4ee41890d8b3ca9e6 (diff)
downloadlua-github-b3196343ba1a5dfe10e68eb9c61dc0ad5bb961a8.tar.gz
Lua 5.1-beta5.1-beta
Diffstat (limited to 'src/lcode.c')
-rw-r--r--src/lcode.c279
1 files changed, 161 insertions, 118 deletions
diff --git a/src/lcode.c b/src/lcode.c
index 04838f33..ecda5cbf 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.16 2005/08/29 20:49:21 roberto Exp $
+** $Id: lcode.c,v 2.22 2005/11/16 11:55:27 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -27,16 +27,24 @@
#define hasjumps(e) ((e)->t != (e)->f)
+static int isnumeral(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? */
- GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) {
- int pfrom = GETARG_A(*previous);
- int pto = GETARG_B(*previous);
- if (pfrom <= from && from <= pto+1) { /* can connect both? */
- if (from+n-1 > pto)
- SETARG_B(*previous, from+n-1);
- return;
+ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
+ if (fs->pc == 0) /* function start? */
+ return; /* positions are already clean */
+ if (GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) {
+ int pfrom = GETARG_A(*previous);
+ int pto = GETARG_B(*previous);
+ if (pfrom <= from && from <= pto+1) { /* can connect both? */
+ if (from+n-1 > pto)
+ SETARG_B(*previous, from+n-1);
+ return;
+ }
}
}
luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
@@ -115,20 +123,22 @@ static int need_value (FuncState *fs, int list) {
}
-static void patchtestreg (Instruction *i, int reg) {
- if (reg != NO_REG)
+static int patchtestreg (FuncState *fs, int node, int reg) {
+ Instruction *i = getjumpcontrol(fs, node);
+ if (GET_OPCODE(*i) != OP_TESTSET)
+ return 0; /* cannot patch other instructions */
+ if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
- else /* no register to put value; change TESTSET to TEST */
+ else /* no register to put value or register already has the value */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
+
+ return 1;
}
static void removevalues (FuncState *fs, int list) {
- for (; list != NO_JUMP; list = getjump(fs, list)) {
- Instruction *i = getjumpcontrol(fs, list);
- if (GET_OPCODE(*i) == OP_TESTSET)
- patchtestreg(i, NO_REG);
- }
+ for (; list != NO_JUMP; list = getjump(fs, list))
+ patchtestreg(fs, list, NO_REG);
}
@@ -136,11 +146,8 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
int dtarget) {
while (list != NO_JUMP) {
int next = getjump(fs, list);
- Instruction *i = getjumpcontrol(fs, list);
- if (GET_OPCODE(*i) == OP_TESTSET) {
- patchtestreg(i, reg);
+ if (patchtestreg(fs, list, reg))
fixjump(fs, list, vtarget);
- }
else
fixjump(fs, list, dtarget); /* jump to default target */
list = next;
@@ -210,7 +217,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);
}
@@ -280,7 +287,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);
@@ -296,19 +303,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;
}
@@ -340,7 +347,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: {
@@ -349,8 +360,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: {
@@ -358,7 +369,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;
}
@@ -374,15 +385,13 @@ 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 */
int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) {
- int fj = NO_JUMP; /* first jump (over LOAD ops.) */
- if (e->k != VJMP)
- fj = luaK_jump(fs);
+ int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
p_f = code_label(fs, reg, 0, 1);
p_t = code_label(fs, reg, 1, 0);
luaK_patchtohere(fs, fj);
@@ -392,7 +401,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;
}
@@ -408,14 +417,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;
}
@@ -430,19 +439,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;
@@ -456,22 +468,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: {
@@ -489,15 +501,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)));
@@ -515,7 +527,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);
}
@@ -523,7 +535,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;
}
@@ -533,7 +545,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
}
case VJMP: {
invertjump(fs, e);
- pc = e->info;
+ pc = e->u.s.info;
break;
}
default: {
@@ -547,7 +559,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
}
-void luaK_goiffalse (FuncState *fs, expdesc *e) {
+static void luaK_goiffalse (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
@@ -560,7 +572,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
break;
}
case VJMP: {
- pc = e->info;
+ pc = e->u.s.info;
break;
}
default: {
@@ -581,7 +593,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;
}
@@ -593,7 +605,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;
}
@@ -610,34 +622,81 @@ 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 (OpCode op, expdesc *e1, expdesc *e2) {
+ lua_Number v1, v2, r;
+ if (!isnumeral(e1) || !isnumeral(e2)) return 0;
+ v1 = e1->u.nval;
+ v2 = e2->u.nval;
+ switch (op) {
+ case OP_ADD: r = luai_numadd(v1, v2); break;
+ case OP_SUB: r = luai_numsub(v1, v2); break;
+ case OP_MUL: r = luai_nummul(v1, v2); break;
+ case OP_DIV:
+ if (v2 == 0) return 0; /* do not attempt to divide by 0 */
+ r = luai_numdiv(v1, v2); break;
+ case OP_MOD:
+ if (v2 == 0) return 0; /* do not attempt to divide by 0 */
+ r = luai_nummod(v1, v2); break;
+ case OP_POW: r = luai_numpow(v1, v2); break;
+ case OP_UNM: r = luai_numunm(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(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);
@@ -660,74 +719,58 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
break;
}
default: {
- luaK_exp2RK(fs, v);
+ if (!isnumeral(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);
}
}
@@ -737,7 +780,7 @@ void luaK_fixline (FuncState *fs, int line) {
}
-int luaK_code (FuncState *fs, Instruction i, int line) {
+static int luaK_code (FuncState *fs, Instruction i, int line) {
Proto *f = fs->f;
dischargejpc(fs); /* `pc' will change */
/* put new instruction in code array */