diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-11-28 10:58:18 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-11-28 10:58:18 -0200 |
commit | ff5fe5104413cf2a5156f86479d4b9b130bad7a6 (patch) | |
tree | 7ab4b89eafe1d39962c1aca42d47b40159416854 | |
parent | dfd188ba12f22db8d31cb80426d568e97345e1e2 (diff) | |
download | lua-github-ff5fe5104413cf2a5156f86479d4b9b130bad7a6.tar.gz |
using register 'k' for conditions in tests (we only need one bit there)
-rw-r--r-- | lcode.c | 94 | ||||
-rw-r--r-- | lopcodes.h | 30 | ||||
-rw-r--r-- | lvm.c | 88 |
3 files changed, 120 insertions, 92 deletions
@@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.135 2017/11/22 19:15:44 roberto Exp roberto $ +** $Id: lcode.c,v 2.136 2017/11/23 19:29:04 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -160,8 +160,8 @@ void luaK_ret (FuncState *fs, int first, int nret) { ** Code a "conditional jump", that is, a test or comparison opcode ** followed by a jump. Return jump position. */ -static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { - luaK_codeABC(fs, op, A, B, C); +static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) { + luaK_codeABCk(fs, op, A, B, C, k); return luaK_jump(fs); } @@ -206,7 +206,7 @@ static int patchtestreg (FuncState *fs, int node, int reg) { else { /* no register to put value or register already has the value; change instruction to simple test */ - *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i), 0); + *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, 0, GETARG_k(*i)); } return 1; } @@ -969,7 +969,7 @@ static void negatecondition (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); - SETARG_B(*pc, !(GETARG_B(*pc))); + SETARG_k(*pc, (GETARG_k(*pc) ^ 1)); } @@ -984,13 +984,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { Instruction ie = getinstruction(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + return condjump(fs, OP_TEST, GETARG_B(ie), 0, 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, 0, cond); } @@ -1276,25 +1276,37 @@ static void codecommutative (FuncState *fs, OpCode op, /* ** Emit code for order comparisons. -** 'e1' was already put in register by 'luaK_infix'. +** When the first operand is an integral value in the proper range, +** change (A < B) to (!(B <= A)) and (A <= B) to (!(B < A)) so that +** it can use an immediate operand. In this case, C indicates this +** change, for cases that cannot assume a total order (NaN and +** metamethods). */ -static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { - int rk1 = check_exp(e1->k == VNONRELOC, e1->u.info); - int rk2 = luaK_exp2anyreg(fs, e2); - freeexps(fs, e1, e2); - switch (opr) { - 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, rk2, 1, rk1); /* invert operands */ - break; - } - default: { /* '==', '<', '<=' use their own opcodes */ - OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); - e1->u.info = condjump(fs, op, rk1, 1, rk2); - break; - } +static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { + int r1, r2; + int cond = 1; + int C = 0; + lua_Integer im; + if (isSCnumber(e2, &im)) { + /* use immediate operand */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = cast_int(im); + op = cast(OpCode, (op - OP_LT) + OP_LTI); + } + else if (isSCnumber(e1, &im)) { + /* transform (A < B) to (!(B <= A)) and (A <= B) to (!(B < A)) */ + r1 = luaK_exp2anyreg(fs, e2); + r2 = cast_int(im); + op = (op == OP_LT) ? OP_LEI : OP_LTI; + cond = 0; /* negate original test */ + C = 1; /* indication that it used the transformations */ } + else { /* regular case, compare two registers */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = luaK_exp2anyreg(fs, e2); + } + freeexps(fs, e1, e2); + e1->u.info = condjump(fs, op, r1, r2, C, cond); e1->k = VJMP; } @@ -1325,7 +1337,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { r2 = luaK_exp2anyreg(fs, e2); } freeexps(fs, e1, e2); - e1->u.info = condjump(fs, op, r1, (opr == OPR_EQ), r2); + e1->u.info = condjump(fs, op, r1, r2, 0, (opr == OPR_EQ)); e1->k = VJMP; } @@ -1385,7 +1397,10 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } case OPR_LT: case OPR_LE: case OPR_GT: case OPR_GE: { - luaK_exp2anyreg(fs, v); + lua_Integer dummy; + if (!isSCnumber(v, &dummy)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be an immediate operand */ break; } default: lua_assert(0); @@ -1399,9 +1414,9 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { ** concatenation is right associative), merge second CONCAT into first ** one. */ -void luaK_posfix (FuncState *fs, BinOpr op, +void luaK_posfix (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2, int line) { - switch (op) { + switch (opr) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); @@ -1432,28 +1447,35 @@ void luaK_posfix (FuncState *fs, BinOpr op, break; } case OPR_ADD: case OPR_MUL: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codecommutative(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + if (!constfolding(fs, opr + LUA_OPADD, e1, e2)) + codecommutative(fs, cast(OpCode, opr + OP_ADD), e1, e2, line); break; } case OPR_SUB: case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codearith(fs, cast(OpCode, op + OP_ADD), e1, e2, 0, line); + if (!constfolding(fs, opr + LUA_OPADD, e1, e2)) + codearith(fs, cast(OpCode, opr + OP_ADD), e1, e2, 0, line); break; } case OPR_BAND: case OPR_BOR: case OPR_BXOR: case OPR_SHL: case OPR_SHR: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + if (!constfolding(fs, opr + LUA_OPADD, e1, e2)) + codebinexpval(fs, cast(OpCode, opr + OP_ADD), e1, e2, line); break; } case OPR_EQ: case OPR_NE: { - codeeq(fs, op, e1, e2); + codeeq(fs, opr, e1, e2); + break; + } + case OPR_LT: case OPR_LE: { + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + codeorder(fs, op, e1, e2); break; } - case OPR_LT: case OPR_LE: case OPR_GT: case OPR_GE: { + /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + swapexps(e1, e2); codeorder(fs, op, e1, e2); break; } @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.170 2017/11/22 19:15:44 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.171 2017/11/27 17:44:31 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -114,13 +114,15 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ #define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) #define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B)) +#define GETARG_sB(i) (GETARG_B(i) - MAXARG_sC) #define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) #define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C)) #define GETARG_sC(i) (GETARG_C(i) - MAXARG_sC) #define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) -#define GETARG_k(i) (cast(int, ((i) & (1 << POS_k)))) +#define TESTARG_k(i) (cast(int, ((i) & (1 << POS_k)))) +#define GETARG_k(i) getarg(i, POS_k, 1) #define SETARG_k(i,v) setarg(i, v, POS_k, 1) #define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx)) @@ -236,17 +238,17 @@ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ OP_CLOSE,/* A close all upvalues >= R(A) */ OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ -OP_EQ,/* A B C if ((R(A) == R(C)) ~= B) then pc++ */ -OP_LT,/* A B C if ((R(A) < R(C)) ~= B) then pc++ */ -OP_LE,/* A B C if ((R(A) <= R(C)) ~= B) then pc++ */ +OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */ +OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */ +OP_LE,/* A B if ((R(A) <= R(B)) ~= k) then pc++ */ -OP_EQK,/* A B C if ((R(A) == K(C)) ~= B) then pc++ */ -OP_EQI,/* A B C if ((R(A) == C) ~= B) then pc++ */ -OP_LTI,/* A B C if ((R(A) < C) ~= B) then pc++ */ -OP_LEI,/* A B C if ((R(A) <= C) ~= B) then pc++ */ +OP_EQK,/* A B if ((R(A) == K(B)) ~= k) then pc++ */ +OP_EQI,/* A sB if ((R(A) == sB) ~= k) then pc++ */ +OP_LTI,/* A sB if ((R(A) < sB) ~= k) then pc++ */ +OP_LEI,/* A sB if ((R(A) <= sB) ~= k) then pc++ */ -OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ -OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ +OP_TEST,/* A if (not R(A) == k) then pc++ */ +OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -289,9 +291,13 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. - (*) For comparisons, A specifies what condition the test should accept + (*) For comparisons, k specifies what condition the test should accept (true or false). + (*) For OP_LTI/OP_LEI, C indicates that the transformations + (A<B) => (!(B<=A)) or (A<=B) => (!(B<A)) were used to put the + constant operator on the right side. + (*) All 'skips' (pc++) assume that next instruction is a jump. ===========================================================================*/ @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.317 2017/11/23 19:18:10 roberto Exp roberto $ +** $Id: lvm.c,v 2.318 2017/11/27 17:44:31 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -702,14 +702,14 @@ void luaV_finishOp (lua_State *L) { L->top--; if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ lua_assert(op == OP_LE || - (op == OP_LEI && !(GETARG_B(inst) & 2)) || - (op == OP_LTI && GETARG_B(inst) & 2)); + (op == OP_LTI && GETARG_C(inst)) || + (op == OP_LEI && !GETARG_C(inst))); ci->callstatus ^= CIST_LEQ; /* clear mark */ res = !res; /* negate result */ } lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); - if (GETARG_B(inst) & 2) res = !res; - if (res != (GETARG_B(inst) & 1)) /* condition failed? */ + if (GETARG_C(inst)) res = !res; + if (res != GETARG_k(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ break; } @@ -766,7 +766,7 @@ void luaV_finishOp (lua_State *L) { #define RC(i) (base+GETARG_C(i)) #define vRC(i) s2v(RC(i)) #define KC(i) (k+GETARG_C(i)) -#define RKC(i) ((GETARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i))) +#define RKC(i) ((TESTARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i))) @@ -1326,59 +1326,59 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_EQ) { - TValue *rc = vRC(i); + TValue *rb = vRB(i); int res; - Protect(res = luaV_equalobj(L, s2v(ra), rc)); - if (res != GETARG_B(i)) + Protect(res = luaV_equalobj(L, s2v(ra), rb)); + if (res != GETARG_k(i)) pc++; else donextjump(ci); vmbreak; } vmcase(OP_LT) { - TValue *rc = vRC(i); + TValue *rb = vRB(i); int res; - if (ttisinteger(s2v(ra)) && ttisinteger(rc)) - res = (ivalue(s2v(ra)) < ivalue(rc)); - else if (ttisnumber(s2v(ra)) && ttisnumber(rc)) - res = LTnum(s2v(ra), rc); + if (ttisinteger(s2v(ra)) && ttisinteger(rb)) + res = (ivalue(s2v(ra)) < ivalue(rb)); + else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) + res = LTnum(s2v(ra), rb); else - Protect(res = lessthanothers(L, s2v(ra), rc)); - if (res != GETARG_B(i)) + Protect(res = lessthanothers(L, s2v(ra), rb)); + if (res != GETARG_k(i)) pc++; else donextjump(ci); vmbreak; } vmcase(OP_LE) { - TValue *rc = vRC(i); + TValue *rb = vRB(i); int res; - if (ttisinteger(s2v(ra)) && ttisinteger(rc)) - res = (ivalue(s2v(ra)) <= ivalue(rc)); - else if (ttisnumber(s2v(ra)) && ttisnumber(rc)) - res = LEnum(s2v(ra), rc); + if (ttisinteger(s2v(ra)) && ttisinteger(rb)) + res = (ivalue(s2v(ra)) <= ivalue(rb)); + else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) + res = LEnum(s2v(ra), rb); else - Protect(res = lessequalothers(L, s2v(ra), rc)); - if (res != GETARG_B(i)) + Protect(res = lessequalothers(L, s2v(ra), rb)); + if (res != GETARG_k(i)) pc++; else donextjump(ci); vmbreak; } vmcase(OP_EQK) { - TValue *rc = KC(i); + TValue *rb = KB(i); /* basic types do not use '__eq'; we can use raw equality */ - if (luaV_equalobj(NULL, s2v(ra), rc) != GETARG_B(i)) + if (luaV_equalobj(NULL, s2v(ra), rb) != GETARG_k(i)) pc++; else donextjump(ci); vmbreak; } vmcase(OP_EQI) { - int ic = GETARG_sC(i); - if ((ttisinteger(s2v(ra)) ? (ivalue(s2v(ra)) == ic) - :ttisfloat(s2v(ra)) ? luai_numeq(fltvalue(s2v(ra)), cast_num(ic)) - : 0) != GETARG_B(i)) + int im = GETARG_sB(i); + if ((ttisinteger(s2v(ra)) ? (ivalue(s2v(ra)) == im) + :ttisfloat(s2v(ra)) ? luai_numeq(fltvalue(s2v(ra)), cast_num(im)) + : 0) != GETARG_k(i)) pc++; else donextjump(ci); @@ -1386,17 +1386,17 @@ void luaV_execute (lua_State *L) { } vmcase(OP_LTI) { int res; - int ic = GETARG_sC(i); + int im = GETARG_sB(i); if (ttisinteger(s2v(ra))) - res = (ivalue(s2v(ra)) < ic); + res = (ivalue(s2v(ra)) < im); else if (ttisfloat(s2v(ra))) { lua_Number f = fltvalue(s2v(ra)); - res = (!luai_numisnan(f)) ? luai_numlt(f, cast_num(ic)) - : GETARG_B(i) >> 1; /* NaN? */ + res = (!luai_numisnan(f)) ? luai_numlt(f, cast_num(im)) + : GETARG_C(i); /* NaN? */ } else - Protect(res = luaT_callorderiTM(L, s2v(ra), ic, GETARG_B(i) >> 1, TM_LT)); - if (res != (GETARG_B(i) & 1)) + Protect(res = luaT_callorderiTM(L, s2v(ra), im, GETARG_C(i), TM_LT)); + if (res != GETARG_k(i)) pc++; else donextjump(ci); @@ -1404,32 +1404,32 @@ void luaV_execute (lua_State *L) { } vmcase(OP_LEI) { int res; - int ic = GETARG_sC(i); + int im = GETARG_sB(i); if (ttisinteger(s2v(ra))) - res = (ivalue(s2v(ra)) <= ic); + res = (ivalue(s2v(ra)) <= im); else if (ttisfloat(s2v(ra))) { lua_Number f = fltvalue(s2v(ra)); - res = (!luai_numisnan(f)) ? luai_numle(f, cast_num(ic)) - : GETARG_B(i) >> 1; /* NaN? */ + res = (!luai_numisnan(f)) ? luai_numle(f, cast_num(im)) + : GETARG_C(i); /* NaN? */ } else - Protect(res = luaT_callorderiTM(L, s2v(ra), ic, GETARG_B(i) >> 1, TM_LE)); - if (res != (GETARG_B(i) & 1)) + Protect(res = luaT_callorderiTM(L, s2v(ra), im, GETARG_C(i), TM_LE)); + if (res != GETARG_k(i)) pc++; else donextjump(ci); vmbreak; } vmcase(OP_TEST) { - if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra))) + if (l_isfalse(s2v(ra)) == GETARG_k(i)) pc++; else - donextjump(ci); + donextjump(ci); vmbreak; } vmcase(OP_TESTSET) { TValue *rb = vRB(i); - if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + if (l_isfalse(rb) == GETARG_k(i)) pc++; else { setobj2s(L, ra, rb); |