more refactoring

This commit is contained in:
Roberto Ierusalimschy
2016-01-04 11:40:57 -02:00
parent 7cd7c2e0a1
commit b12b635a90

189
lcode.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lcode.c,v 2.103 2015/11/19 19:16:22 roberto Exp roberto $ ** $Id: lcode.c,v 2.106 2015/12/18 13:53:36 roberto Exp roberto $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -400,6 +400,24 @@ static void freeexp (FuncState *fs, expdesc *e) {
} }
/*
** Free registers used by expressions 'e1' and 'e2' (if any) in proper
** order.
*/
static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1;
int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1;
if (r1 > r2) {
freereg(fs, r1);
freereg(fs, r2);
}
else {
freereg(fs, r2);
freereg(fs, r1);
}
}
/* /*
** Add constant 'v' to prototype's list of constants (field 'k'). ** Add constant 'v' to prototype's list of constants (field 'k').
** Use scanner's table to cache position of constants in constant list ** Use scanner's table to cache position of constants in constant list
@@ -531,33 +549,35 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
/* /*
** Ensure that expression 'e' has a value somewhere (either it ** Ensure that expression 'e' is not a variable.
** is a constant or result is in a register).
*/ */
void luaK_dischargevars (FuncState *fs, expdesc *e) { void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) { switch (e->k) {
case VLOCAL: { case VLOCAL: { /* already in a register */
e->k = VNONRELOC; /* becomes a non-relocatable value */ e->k = VNONRELOC; /* becomes a non-relocatable value */
break; break;
} }
case VUPVAL: { case VUPVAL: { /* move value to some (pending) register */
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE; e->k = VRELOCABLE;
break; break;
} }
case VINDEXED: { case VINDEXED: {
OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ OpCode op;
freereg(fs, e->u.ind.idx); freereg(fs, e->u.ind.idx);
if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */
freereg(fs, e->u.ind.t); freereg(fs, e->u.ind.t);
op = OP_GETTABLE; op = OP_GETTABLE;
} }
else {
lua_assert(e->u.ind.vt == VUPVAL);
op = OP_GETTABUP; /* 't' is in an upvalue */
}
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE; e->k = VRELOCABLE;
break; break;
} }
case VVARARG: case VVARARG: case VCALL: {
case VCALL: {
luaK_setoneret(fs, e); luaK_setoneret(fs, e);
break; break;
} }
@@ -731,36 +751,22 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
** Ensures final expression result is in a valid R/K index ** Ensures final expression result is in a valid R/K index
** (that is, it is either in a register or in 'k' with an index ** (that is, it is either in a register or in 'k' with an index
** in the range of R/K indices). ** in the range of R/K indices).
** Returns R/K index.
*/ */
int luaK_exp2RK (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e); luaK_exp2val(fs, e);
switch (e->k) { /* handle constants */ switch (e->k) { /* move constants to 'k' */
case VTRUE: case VTRUE: e->u.info = boolK(fs, 1); goto vk;
case VFALSE: case VFALSE: e->u.info = boolK(fs, 0); goto vk;
case VNIL: { case VNIL: e->u.info = nilK(fs); goto vk;
if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk;
e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk;
e->k = VK; case VK:
return RKASK(e->u.info);
}
else break;
}
case VKINT: {
e->u.info = luaK_intK(fs, e->u.ival);
e->k = VK;
goto vk;
}
case VKFLT: {
e->u.info = luaK_numberK(fs, e->u.nval);
e->k = VK;
}
/* FALLTHROUGH */
case VK: {
vk: vk:
e->k = VK;
if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */
return RKASK(e->u.info); return RKASK(e->u.info);
else break; else break;
}
default: break; default: break;
} }
/* not a constant in the right range: put it in a register */ /* not a constant in the right range: put it in a register */
@@ -988,65 +994,62 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
/* /*
** Emit code for binary and unary expressions that "produce values" ** Emit code for unary expressions that "produce values"
** (everything but logical operators 'and', 'or' and comparison ** (everything but 'not').
** operators). ** Expression to produce final result will be encoded in 'e'.
** First try to do constant folding (only for numeric [arithmetic and
** bitwise] operations, which is what 'lua_arith' accepts). Expression
** to produce final result will be encoded in 'e1'.
** (The "free registers in proper order" reason is tricky: because
** expression evaluation can be delayed, the final numbering for
** registers in 'e1' and 'e2' depends on how each one was delayed.)
*/ */
static void codeexpval (FuncState *fs, OpCode op, static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
expdesc *e1, expdesc *e2, int line) { int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
lua_assert(OP_ADD <= op && op <= OP_CONCAT); freeexp(fs, e);
if (op <= OP_BNOT && constfolding(fs, (op - OP_ADD) + LUA_OPADD, e1, e2)) e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
return; /* result has been folded */ e->k = VRELOCABLE; /* all those operations are relocatable */
else {
int o1, o2;
/* move operands to registers (if needed) */
if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */
o2 = 0; /* no second expression */
o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */
}
else { /* regular case (binary operators) */
o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
o1 = luaK_exp2RK(fs, e1);
}
if (o1 > o2) { /* free registers in proper order */
freeexp(fs, e1);
freeexp(fs, e2);
}
else {
freeexp(fs, e2);
freeexp(fs, e1);
}
e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */
e1->k = VRELOCABLE; /* all those operations are relocatable */
luaK_fixline(fs, line); luaK_fixline(fs, line);
} }
/*
** Emit code for binary expressions that "produce values"
** (everything but logical operators 'and'/'or' and comparison
** operators).
** Expression to produce final result will be encoded in 'e1'.
*/
static void codebinexpval (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */
int rk2 = luaK_exp2RK(fs, e2);
freeexps(fs, e1, e2);
e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */
e1->k = VRELOCABLE; /* all those operations are relocatable */
luaK_fixline(fs, line);
} }
/* /*
** Emit code for comparisons. ** Emit code for comparisons.
** Code will jump if result equals 'cond' ('cond' true <=> code will ** 'e1' was already put in R/K form by 'luaK_infix'.
** jump if result is true).
*/ */
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
expdesc *e2) { int rk1 = (e1->k == VK) ? RKASK(e1->u.info)
int o1 = luaK_exp2RK(fs, e1); : check_exp(e1->k == VNONRELOC, e1->u.info);
int o2 = luaK_exp2RK(fs, e2); int rk2 = luaK_exp2RK(fs, e2);
lua_assert(OP_EQ <= op && op <= OP_LE); /* comparison operation */ freeexps(fs, e1, e2);
freeexp(fs, e2); switch (opr) {
freeexp(fs, e1); case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */
if (cond == 0 && op != OP_EQ) { e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2);
int temp; /* exchange args to replace by '<' or '<=' */ break;
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ }
cond = 1; case OPR_GT: case OPR_GE: {
/* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */
break;
}
default: { /* '==', '<', '<=' use their own opcodes */
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
e1->u.info = condjump(fs, op, 1, rk1, rk2);
break;
}
} }
e1->u.info = condjump(fs, op, cond, o1, o2);
e1->k = VJMP; e1->k = VJMP;
} }
@@ -1055,13 +1058,15 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
** Aplly prefix operation 'op' to expression 'e'. ** Aplly prefix operation 'op' to expression 'e'.
*/ */
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
expdesc e2; /* fake 2nd operand */ static expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; /* fake 2nd operand */
e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
switch (op) { switch (op) {
case OPR_MINUS: case OPR_BNOT: case OPR_LEN: { case OPR_MINUS: case OPR_BNOT:
codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line); if (constfolding(fs, op + LUA_OPUNM, e, &ef))
break;
/* else go through */
case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
break; break;
}
case OPR_NOT: codenot(fs, e); break; case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0); default: lua_assert(0);
} }
@@ -1137,7 +1142,7 @@ void luaK_posfix (FuncState *fs, BinOpr op,
} }
else { else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
codeexpval(fs, OP_CONCAT, e1, e2, line); codebinexpval(fs, OP_CONCAT, e1, e2, line);
} }
break; break;
} }
@@ -1145,15 +1150,13 @@ void luaK_posfix (FuncState *fs, BinOpr op,
case OPR_IDIV: case OPR_MOD: case OPR_POW: case OPR_IDIV: case OPR_MOD: case OPR_POW:
case OPR_BAND: case OPR_BOR: case OPR_BXOR: case OPR_BAND: case OPR_BOR: case OPR_BXOR:
case OPR_SHL: case OPR_SHR: { case OPR_SHL: case OPR_SHR: {
codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line); if (!constfolding(fs, op + LUA_OPADD, e1, e2))
break; codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
}
case OPR_EQ: case OPR_LT: case OPR_LE: {
codecomp(fs, cast(OpCode, (op - OPR_EQ) + OP_EQ), 1, e1, e2);
break; break;
} }
case OPR_EQ: case OPR_LT: case OPR_LE:
case OPR_NE: case OPR_GT: case OPR_GE: { case OPR_NE: case OPR_GT: case OPR_GE: {
codecomp(fs, cast(OpCode, (op - OPR_NE) + OP_EQ), 0, e1, e2); codecomp(fs, op, e1, e2);
break; break;
} }
default: lua_assert(0); default: lua_assert(0);