New instruction format for SETLIST/NEWTABLE

New instruction format 'ivABC' (a variant of iABC where parameter vC has
10 bits) allows constructors of up to 1024 elements to be coded without
EXTRAARG.
This commit is contained in:
Roberto Ierusalimschy 2024-06-28 11:18:14 -03:00
parent 6ac7219da3
commit c403e456b6
7 changed files with 97 additions and 47 deletions

59
lcode.c
View file

@ -390,32 +390,40 @@ int luaK_code (FuncState *fs, Instruction i) {
** Format and emit an 'iABC' instruction. (Assertions check consistency
** of parameters versus opcode.)
*/
int luaK_codeABCk (FuncState *fs, OpCode o, int a, int b, int c, int k) {
int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C, int k) {
lua_assert(getOpMode(o) == iABC);
lua_assert(a <= MAXARG_A && b <= MAXARG_B &&
c <= MAXARG_C && (k & ~1) == 0);
return luaK_code(fs, CREATE_ABCk(o, a, b, c, k));
lua_assert(A <= MAXARG_A && B <= MAXARG_B &&
C <= MAXARG_C && (k & ~1) == 0);
return luaK_code(fs, CREATE_ABCk(o, A, B, C, k));
}
int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C, int k) {
lua_assert(getOpMode(o) == ivABC);
lua_assert(A <= MAXARG_A && B <= MAXARG_vB &&
C <= MAXARG_vC && (k & ~1) == 0);
return luaK_code(fs, CREATE_vABCk(o, A, B, C, k));
}
/*
** Format and emit an 'iABx' instruction.
*/
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bc) {
lua_assert(getOpMode(o) == iABx);
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, a, bc));
lua_assert(A <= MAXARG_A && Bc <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, A, Bc));
}
/*
** Format and emit an 'iAsBx' instruction.
*/
static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
unsigned int b = bc + OFFSET_sBx;
static int codeAsBx (FuncState *fs, OpCode o, int A, int Bc) {
unsigned int b = cast_uint(Bc) + OFFSET_sBx;
lua_assert(getOpMode(o) == iAsBx);
lua_assert(a <= MAXARG_A && b <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, a, b));
lua_assert(A <= MAXARG_A && b <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, A, b));
}
@ -423,7 +431,7 @@ static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
** Format and emit an 'isJ' instruction.
*/
static int codesJ (FuncState *fs, OpCode o, int sj, int k) {
unsigned int j = sj + OFFSET_sJ;
unsigned int j = cast_uint(sj) + OFFSET_sJ;
lua_assert(getOpMode(o) == isJ);
lua_assert(j <= MAXARG_sJ && (k & ~1) == 0);
return luaK_code(fs, CREATE_sJ(o, j, k));
@ -433,9 +441,9 @@ static int codesJ (FuncState *fs, OpCode o, int sj, int k) {
/*
** Emit an "extra argument" instruction (format 'iAx')
*/
static int codeextraarg (FuncState *fs, int a) {
lua_assert(a <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
static int codeextraarg (FuncState *fs, int A) {
lua_assert(A <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, A));
}
@ -1032,10 +1040,10 @@ static int exp2RK (FuncState *fs, expdesc *e) {
}
static void codeABRK (FuncState *fs, OpCode o, int a, int b,
static void codeABRK (FuncState *fs, OpCode o, int A, int B,
expdesc *ec) {
int k = exp2RK(fs, ec);
luaK_codeABCk(fs, o, a, b, ec->u.info, k);
luaK_codeABCk(fs, o, A, B, ec->u.info, k);
}
@ -1788,10 +1796,10 @@ void luaK_fixline (FuncState *fs, int line) {
void luaK_settablesize (FuncState *fs, int pc, int ra, int asize, int hsize) {
Instruction *inst = &fs->f->code[pc];
int rb = (hsize != 0) ? luaO_ceillog2(hsize) + 1 : 0; /* hash size */
int extra = asize / (MAXARG_C + 1); /* higher bits of array size */
int rc = asize % (MAXARG_C + 1); /* lower bits of array size */
int extra = asize / (MAXARG_vC + 1); /* higher bits of array size */
int rc = asize % (MAXARG_vC + 1); /* lower bits of array size */
int k = (extra > 0); /* true iff needs extra argument */
*inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k);
*inst = CREATE_vABCk(OP_NEWTABLE, ra, rb, rc, k);
*(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra);
}
@ -1807,12 +1815,12 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
lua_assert(tostore != 0);
if (tostore == LUA_MULTRET)
tostore = 0;
if (nelems <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, tostore, nelems);
if (nelems <= MAXARG_vC)
luaK_codevABCk(fs, OP_SETLIST, base, tostore, nelems, 0);
else {
int extra = nelems / (MAXARG_C + 1);
nelems %= (MAXARG_C + 1);
luaK_codeABCk(fs, OP_SETLIST, base, tostore, nelems, 1);
int extra = nelems / (MAXARG_vC + 1);
nelems %= (MAXARG_vC + 1);
luaK_codevABCk(fs, OP_SETLIST, base, tostore, nelems, 1);
codeextraarg(fs, extra);
}
fs->freereg = base + 1; /* free registers with list values */
@ -1839,6 +1847,7 @@ static int finaltarget (Instruction *code, int i) {
** Do a final pass over the code of a function, doing small peephole
** optimizations and adjustments.
*/
#include "lopnames.h"
void luaK_finish (FuncState *fs) {
int i;
Proto *p = fs->f;

View file

@ -61,8 +61,10 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned Bx);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
int B, int C, int k);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C,
int k);
LUAI_FUNC int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C,
int k);
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);

View file

@ -40,7 +40,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */
,opmode(0, 0, 0, 0, 1, ivABC) /* OP_NEWTABLE */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */
@ -99,7 +99,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */
,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
@ -127,6 +127,12 @@ int luaP_isOT (Instruction i) {
** it accepts multiple results.
*/
int luaP_isIT (Instruction i) {
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_SETLIST:
return testITMode(GET_OPCODE(i)) && GETARG_vB(i) == 0;
default:
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
}
}

View file

@ -19,25 +19,30 @@
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
iABC C(8) | B(8) |k| A(8) | Op(7) |
ivABC vC(10) | vB(6) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
isJ sJ (signed)(25) | Op(7) |
('v' stands for "variant", 's' for "signed", 'x' for "extended".)
A signed argument is represented in excess K: The represented value is
the written unsigned value minus K, where K is half (rounded down) the
maximum value for the corresponding unsigned argument.
===========================================================================*/
enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
/* basic instruction formats */
enum OpMode {iABC, ivABC, iABx, iAsBx, iAx, isJ};
/*
** size and position of opcode arguments.
*/
#define SIZE_C 8
#define SIZE_vC 10
#define SIZE_B 8
#define SIZE_vB 6
#define SIZE_Bx (SIZE_C + SIZE_B + 1)
#define SIZE_A 8
#define SIZE_Ax (SIZE_Bx + SIZE_A)
@ -50,7 +55,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
#define POS_A (POS_OP + SIZE_OP)
#define POS_k (POS_A + SIZE_A)
#define POS_B (POS_k + 1)
#define POS_vB (POS_k + 1)
#define POS_C (POS_B + SIZE_B)
#define POS_vC (POS_vB + SIZE_vB)
#define POS_Bx POS_k
@ -95,7 +102,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
#define MAXARG_A ((1<<SIZE_A)-1)
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_vB ((1<<SIZE_vB)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
#define MAXARG_vC ((1<<SIZE_vC)-1)
#define OFFSET_sC (MAXARG_C >> 1)
#define int2sC(i) ((i) + OFFSET_sC)
@ -126,16 +135,24 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
#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_B(i) \
check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
#define GETARG_vB(i) \
check_exp(checkopm(i, ivABC), getarg(i, POS_vB, SIZE_vB))
#define GETARG_sB(i) sC2int(GETARG_B(i))
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
#define SETARG_vB(i,v) setarg(i, v, POS_vB, SIZE_vB)
#define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
#define GETARG_C(i) \
check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
#define GETARG_vC(i) \
check_exp(checkopm(i, ivABC), getarg(i, POS_vC, SIZE_vC))
#define GETARG_sC(i) sC2int(GETARG_C(i))
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
#define SETARG_vC(i,v) setarg(i, v, POS_vC, SIZE_vC)
#define TESTARG_k(i) check_exp(checkopm(i, iABC), (cast_int(((i) & (1u << POS_k)))))
#define GETARG_k(i) check_exp(checkopm(i, iABC), getarg(i, POS_k, 1))
#define TESTARG_k(i) (cast_int(((i) & (1u << 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))
@ -160,6 +177,12 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
| (cast(Instruction, c)<<POS_C) \
| (cast(Instruction, k)<<POS_k))
#define CREATE_vABCk(o,a,b,c,k) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, b)<<POS_vB) \
| (cast(Instruction, c)<<POS_vC) \
| (cast(Instruction, k)<<POS_k))
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, bc)<<POS_Bx))
@ -306,7 +329,7 @@ OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
OP_SETLIST,/* A vB vC k R[A][vC+i] := R[A+i], 1 <= i <= vB */
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */

View file

@ -952,7 +952,7 @@ static void constructor (LexState *ls, expdesc *t) {
sep -> ',' | ';' */
FuncState *fs = ls->fs;
int line = ls->linenumber;
int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
int pc = luaK_codevABCk(fs, OP_NEWTABLE, 0, 0, 0, 0);
ConsControl cc;
luaK_code(fs, 0); /* space for extra arg. */
cc.na = cc.nh = cc.tostore = 0;

View file

@ -697,6 +697,11 @@ static char *buildop (Proto *p, int pc, char *buff) {
GETARG_A(i), GETARG_B(i), GETARG_C(i),
GETARG_k(i) ? " (k)" : "");
break;
case ivABC:
sprintf(buff, "%-12s%4d %4d %4d%s", name,
GETARG_A(i), GETARG_vB(i), GETARG_vC(i),
GETARG_k(i) ? " (k)" : "");
break;
case iABx:
sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i));
break;

25
lvm.c
View file

@ -1359,14 +1359,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
int b = GETARG_vB(i); /* log2(hash size) + 1 */
int c = GETARG_vC(i); /* array size */
Table *t;
if (b > 0)
b = 1 << (b - 1); /* size is 2^(b - 1) */
lua_assert((!TESTARG_k(i)) == (GETARG_Ax(*pc) == 0));
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
b = 1 << (b - 1); /* hash size is 2^(b - 1) */
if (TESTARG_k(i)) { /* non-zero extra argument? */
lua_assert(GETARG_Ax(*pc) != 0);
c += GETARG_Ax(*pc) * (MAXARG_vC + 1); /* add it to array size */
}
pc++; /* skip extra argument */
L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
@ -1850,8 +1851,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}}
vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
int n = GETARG_vB(i);
unsigned int last = GETARG_vC(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
n = cast_int(L->top.p - ra) - 1; /* get up to the top */
@ -1859,11 +1860,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
last += GETARG_Ax(*pc) * (MAXARG_vC + 1);
pc++;
}
if (last > luaH_realasize(h)) /* needs more space? */
/* when 'n' is known, table should have proper size */
if (last > luaH_realasize(h)) { /* needs more space? */
/* fixed-size sets should have space preallocated */
lua_assert(GETARG_vB(i) == 0);
luaH_resizearray(L, h, last); /* preallocate it at once */
}
for (; n > 0; n--) {
TValue *val = s2v(ra + n);
obj2arr(h, last - 1, val);