mirror of https://github.com/rusefi/lua.git
OP_CONCAT does not move its result (to simplify its execution)
This commit is contained in:
parent
28f215ecf8
commit
5bd8d388de
84
lcode.c
84
lcode.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lcode.c,v 2.149 2018/01/09 11:24:12 roberto Exp roberto $
|
** $Id: lcode.c,v 2.150 2018/01/18 16:24:31 roberto Exp roberto $
|
||||||
** Code generator for Lua
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -59,6 +59,21 @@ static int tonumeral(const expdesc *e, TValue *v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the previous instruction of the current code. If there
|
||||||
|
** may be a jump target between the current instruction and the
|
||||||
|
** previous one, return an invalid instruction (to avoid wrong
|
||||||
|
** optimizations).
|
||||||
|
*/
|
||||||
|
static Instruction *previousinstruction (FuncState *fs) {
|
||||||
|
static const Instruction invalidinstruction = -1;
|
||||||
|
if (fs->pc > fs->lasttarget)
|
||||||
|
return &fs->f->code[fs->pc - 1]; /* previous instruction */
|
||||||
|
else
|
||||||
|
return cast(Instruction*, &invalidinstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Create a OP_LOADNIL instruction, but try to optimize: if the previous
|
** Create a OP_LOADNIL instruction, but try to optimize: if the previous
|
||||||
** instruction is also OP_LOADNIL and ranges are compatible, adjust
|
** instruction is also OP_LOADNIL and ranges are compatible, adjust
|
||||||
|
@ -66,21 +81,18 @@ static int tonumeral(const expdesc *e, TValue *v) {
|
||||||
** instance, 'local a; local b' will generate a single opcode.)
|
** instance, 'local a; local b' will generate a single opcode.)
|
||||||
*/
|
*/
|
||||||
void luaK_nil (FuncState *fs, int from, int n) {
|
void luaK_nil (FuncState *fs, int from, int n) {
|
||||||
Instruction *previous;
|
|
||||||
int l = from + n - 1; /* last register to set nil */
|
int l = from + n - 1; /* last register to set nil */
|
||||||
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
|
Instruction *previous = previousinstruction(fs);
|
||||||
previous = &fs->f->code[fs->pc-1];
|
if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
|
||||||
if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
|
int pfrom = GETARG_A(*previous); /* get previous range */
|
||||||
int pfrom = GETARG_A(*previous); /* get previous range */
|
int pl = pfrom + GETARG_B(*previous);
|
||||||
int pl = pfrom + GETARG_B(*previous);
|
if ((pfrom <= from && from <= pl + 1) ||
|
||||||
if ((pfrom <= from && from <= pl + 1) ||
|
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
|
||||||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
|
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
|
||||||
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
|
if (pl > l) l = pl; /* l = max(l, pl) */
|
||||||
if (pl > l) l = pl; /* l = max(l, pl) */
|
SETARG_A(*previous, from);
|
||||||
SETARG_A(*previous, from);
|
SETARG_B(*previous, l - from);
|
||||||
SETARG_B(*previous, l - from);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
} /* else go through */
|
} /* else go through */
|
||||||
}
|
}
|
||||||
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
|
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
|
||||||
|
@ -1432,7 +1444,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_CONCAT: {
|
case OPR_CONCAT: {
|
||||||
luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */
|
luaK_exp2nextreg(fs, v); /* operand must be on the stack */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_ADD: case OPR_SUB:
|
case OPR_ADD: case OPR_SUB:
|
||||||
|
@ -1463,12 +1475,30 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Create code for '(e1 .. e2)'.
|
||||||
|
** For '(e1 .. e2.1 .. e2.2)' (which is '(e1 .. (e2.1 .. e2.2))',
|
||||||
|
** because concatenation is right associative), merge both CONCATs.
|
||||||
|
*/
|
||||||
|
static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) {
|
||||||
|
Instruction *ie2 = previousinstruction(fs);
|
||||||
|
if (GET_OPCODE(*ie2) == OP_CONCAT) { /* is 'e2' a concatenation? */
|
||||||
|
int n = GETARG_B(*ie2); /* # of elements concatenated in 'e2' */
|
||||||
|
lua_assert(e1->u.info + 1 == GETARG_A(*ie2));
|
||||||
|
freeexp(fs, e2);
|
||||||
|
SETARG_A(*ie2, e1->u.info); /* correct first element ('e1') */
|
||||||
|
SETARG_B(*ie2, n + 1); /* will concatenate one more element */
|
||||||
|
}
|
||||||
|
else { /* 'e2' is not a concatenation */
|
||||||
|
luaK_codeABC(fs, OP_CONCAT, e1->u.info, 2, 0); /* new concat opcode */
|
||||||
|
freeexp(fs, e2);
|
||||||
|
luaK_fixline(fs, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Finalize code for binary operation, after reading 2nd operand.
|
** Finalize code for binary operation, after reading 2nd operand.
|
||||||
** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
|
|
||||||
** concatenation is right associative), merge second CONCAT into first
|
|
||||||
** one.
|
|
||||||
*/
|
*/
|
||||||
void luaK_posfix (FuncState *fs, BinOpr opr,
|
void luaK_posfix (FuncState *fs, BinOpr opr,
|
||||||
expdesc *e1, expdesc *e2, int line) {
|
expdesc *e1, expdesc *e2, int line) {
|
||||||
|
@ -1487,19 +1517,9 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
|
||||||
*e1 = *e2;
|
*e1 = *e2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_CONCAT: {
|
case OPR_CONCAT: { /* e1 .. e2 */
|
||||||
luaK_exp2val(fs, e2);
|
luaK_exp2nextreg(fs, e2);
|
||||||
if (e2->k == VRELOC &&
|
codeconcat(fs, e1, e2, line);
|
||||||
GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {
|
|
||||||
lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1);
|
|
||||||
freeexp(fs, e1);
|
|
||||||
SETARG_B(getinstruction(fs, e2), e1->u.info);
|
|
||||||
e1->k = VRELOC; e1->u.info = e2->u.info;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
|
|
||||||
codebinexpval(fs, OP_CONCAT, e1, e2, line);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_ADD: case OPR_MUL: {
|
case OPR_ADD: case OPR_MUL: {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lopcodes.h,v 1.182 2018/01/09 11:21:41 roberto Exp $
|
** $Id: lopcodes.h,v 1.182 2018/01/09 11:24:12 roberto Exp roberto $
|
||||||
** Opcodes for Lua virtual machine
|
** Opcodes for Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -248,7 +248,7 @@ OP_BNOT,/* A B R(A) := ~R(B) */
|
||||||
OP_NOT,/* A B R(A) := not R(B) */
|
OP_NOT,/* A B R(A) := not R(B) */
|
||||||
OP_LEN,/* A B R(A) := length of R(B) */
|
OP_LEN,/* A B R(A) := length of R(B) */
|
||||||
|
|
||||||
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
|
OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */
|
||||||
|
|
||||||
OP_CLOSE,/* A close all upvalues >= R(A) */
|
OP_CLOSE,/* A close all upvalues >= R(A) */
|
||||||
OP_JMP,/* k sJ pc += sJ (k is used in code generation) */
|
OP_JMP,/* k sJ pc += sJ (k is used in code generation) */
|
||||||
|
|
24
lvm.c
24
lvm.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lvm.c,v 2.333 2018/01/10 19:19:27 roberto Exp roberto $
|
** $Id: lvm.c,v 2.334 2018/01/14 17:27:50 roberto Exp roberto $
|
||||||
** Lua virtual machine
|
** Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -717,15 +717,13 @@ void luaV_finishOp (lua_State *L) {
|
||||||
}
|
}
|
||||||
case OP_CONCAT: {
|
case OP_CONCAT: {
|
||||||
StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
|
StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
|
||||||
int b = GETARG_B(inst); /* first element to concatenate */
|
int a = GETARG_A(inst); /* first element to concatenate */
|
||||||
int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */
|
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
|
||||||
setobjs2s(L, top - 2, top); /* put TM result in proper position */
|
setobjs2s(L, top - 2, top); /* put TM result in proper position */
|
||||||
if (total > 1) { /* are there elements to concat? */
|
if (total > 1) { /* are there elements to concat? */
|
||||||
L->top = top - 1; /* top is one after last element (at top-2) */
|
L->top = top - 1; /* top is one after last element (at top-2) */
|
||||||
luaV_concat(L, total); /* concat them (may yield again) */
|
luaV_concat(L, total); /* concat them (may yield again) */
|
||||||
}
|
}
|
||||||
/* move final result to final position */
|
|
||||||
setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_TFORCALL: case OP_CALL: case OP_TAILCALL:
|
case OP_TFORCALL: case OP_CALL: case OP_TAILCALL:
|
||||||
|
@ -1376,18 +1374,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_CONCAT) {
|
vmcase(OP_CONCAT) {
|
||||||
int b = GETARG_B(i);
|
int n = GETARG_B(i); /* number of elements to concatenate */
|
||||||
int c = GETARG_C(i);
|
L->top = ra + n; /* mark the end of concat operands */
|
||||||
StkId rb;
|
ProtectNT(luaV_concat(L, n));
|
||||||
L->top = base + c + 1; /* mark the end of concat operands */
|
checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
|
||||||
ProtectNT(luaV_concat(L, c - b + 1));
|
|
||||||
if (trap) { /* 'luaV_concat' may move the stack */
|
|
||||||
updatebase(ci);
|
|
||||||
ra = RA(i);
|
|
||||||
}
|
|
||||||
rb = base + b;
|
|
||||||
setobjs2s(L, ra, rb);
|
|
||||||
checkGC(L, (ra >= rb ? ra + 1 : rb));
|
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_CLOSE) {
|
vmcase(OP_CLOSE) {
|
||||||
|
|
Loading…
Reference in New Issue