lua中复杂表达式的寄存器分配

一、代码中输入的由来

这个来源通常有三个:upvalue、const、local。除了local变量天然对应寄存器之外,另外的const和upvalue在使用的时候都需要专门的指令来加载到寄存器中,因为大部分的机器操作都是基于寄存器实现。这一点在lua-5.3.4srclopcodes.h可以看到。当需要使用一个非寄存器变量时,需要先通过luaK_dischargevars来保证它是“万事俱备,只欠寄存器分配”,在luaK_dischargevars函数中,如果变量是在upvalue中,则需要先生成从up列表中加载该变量的机器指令,但是并没有分配寄存器,也即是它的结果可以放在任意寄存器中,之后该表达式的类型为VRELOCABLE
void luaK_dischargevars (FuncState *fs, expdesc *e) {
……
case VUPVAL: { /* move value to some (pending) register */
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
……
}

二、复杂表达式的指令生成

以下面表达式为例:
a + b * c
,假设b和c都是upvalue,则首先
对于表达式,当需要使用的时候,在subexpr函数中首先根据算符优先级获得子子表达式,然后调用codebinexpval函数:
static void codebinexpval (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
int rk1 = luaK_exp2RK(fs, e1);
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);
}
对于a+b*c,则codebinexpval函数开始的e1和e2分别表示b和c,所以luaK_exp2RK会为它们分配upvalue的加载和寄存器分配,并且discharge2reg函数会修正之前生成的up加载指令中使用的寄存器。函数codebinexpval之后,b*c作为一个VRELOCABLE类型,重复这个过程。

三、看下代码

tsecer@harry: cat reg.discharge.lua
a = b + c * d
tsecer@harry: ../src/luac -l -l reg.discharge.lua

main <reg.discharge.lua:0,0> (7 instructions at 0x926a70)
0+ params, 3 slots, 1 upvalue, 0 locals, 4 constants, 0 functions
1 [1] GETTABUP 0 0 -2 ; _ENV "b"
2 [1] GETTABUP 1 0 -3 ; _ENV "c"
3 [1] GETTABUP 2 0 -4 ; _ENV "d"
4 [1] MUL 1 1 2
5 [1] ADD 0 0 1
6 [1] SETTABUP 0 -1 0 ; _ENV "a"
7 [1] RETURN 0 1
constants (4) for 0x926a70:
1 "a"
2 "b"
3 "c"
4 "d"
locals (0) for 0x926a70:
upvalues (1) for 0x926a70:
0 _ENV 1 0
tsecer@harry:

原文地址:https://www.cnblogs.com/tsecer/p/11502266.html