LuaJIT SSA IR介绍
文章目录
- 一、IR基本语法
- 1.1 IR 概要
- 1.2 Example IR Dump
- 1.3 IR类型和常量
- 1.4 Guarded Assertions
- 1.5 位运算和算数运算
- 1.6)内存引用和分配
- 1.7)Loads and Stores
- 1.8)类型转换和Calls
- 1.9)其他
- 二、IR在luaJit源码中的定义
- 1)IR instructions(操作码)
- 2)Named IR literals(IR使用到的一些name字面量,比如某个字面值代表那个函数等)
- 3)IR operands,IR 操作数
- 4)IR instruction types,IR 指令类型
- 5)IR references
- 6)IR format
一、IR基本语法
1.1 IR 概要
LuaJIT资料挺少,可以一手学习的基本上只有官方文档:http://wiki.luajit.org/SSA-IR-2.0,但是目前这个文档的介绍被作者删了。在文档被删之前,我按照自己的理解,对官网上的部分内容做了记录。等后面我想优化了,再把这一块内容好好优化一些,毕竟写这边文章的时候,我刚接触LuaJIT,对LuaJIT掌握的还不深入。
LuaJIT的JIT模式下使用的IR具有以下特点:
- 1)IR是SSA(静态单赋值,是一种变量的命名约定,这玩意主要为了方便IR优化而提出的)形式,每条指令都会定义一值(一般都是指令的结果值),多条指令构成数据流图,循环数据流用
PHI
指令表示。 - 2)IR指令都可以通过其在线性数组中的位置被唯一引用(IRRef),biased IR可以快速确定const或非const的IRRef(biased IR references allow fast const vs. non-const decisions.)。
- 3)IR指令都有一个操作码opcode,一个或两个操作数operands。
- 4)IR指令都有用于定义指令结果值的类型。
- 5)IR指令可使用操作码和出现过的指令链接,这样则可以反向查找一条指令依赖的所有指令而无需遍历,也方便IR优化。
- 6)IR一条指令占
64
位,指令间彼此相邻,这种布局缓存高效,索引和遍历快速。
- 7)IR 存放指令的数组是双向增长的:常量向下增长,所有其他指令向上增长。
- 8)IR快照,快照捕获bytecode执行栈中modified slots和frames的引用(IRref),每个快照都保存一个特定的bytecod执行状态,以后可以在跟踪退出时恢复。快照也提供了IR和字节码域之间的链接。
1.2 Example IR Dump
在使用LuaJIT时,加上参数-jdump
,便可以出现如下格式的代码,下面代码分别是source code
,Byte code
,SSA IR
,以及目标机器对应的MCode
,此时的目标机器架构是LoongArch:
loongson@loongson-pc:~/workspace$ luajit-2.1.0-beta3 -jdump
LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2021 Mike Pall. https://luajit.org/
JIT: ON MIPS64R2 fold cse dce fwd dse narrow loop abc sink fuse
> local x = 1.2 for i=1,1e3 do x = x * -3 end
---- TRACE 1 start stdin:1 //
0006 MULVN 0 0 1 ; -3
0007 FORL 1 => 0006
---- TRACE 1 IR
0001 int SLOAD #3 I
0002 > num SLOAD #2 T
0003 + num MUL 0002 -3
0004 + int ADD 0001 +1
0005 > int LE 0004 +1000
0006 ------ LOOP ------------
0007 + num MUL 0003 -3
0008 + int ADD 0004 +1
0009 > int LE 0008 +1000
0010 int PHI 0004 0008
0011 num PHI 0003 0007
---- TRACE 1 mcode 80
555558bbff80 lui ra, 49160
555558bbff84 dsll32 ra, ra, 0
555558bbff88 dmtc1 ra, f0
555558bbff8c lw r23, 8(r16)
555558bbff90 ld ra, 0(r16)
555558bbff94 dsra32 ra, ra, 15
555558bbff98 ldc1 f1, 0(r16)
555558bbff9c sltiu ra, ra, -14
555558bbffa0 beqz ra, 0x555558bbffd4 ->exit
555558bbffa4 li ra, 0
555558bbffa8 mul.d f31, f1, f0
555558bbffac addiu r23, r23, 1
555558bbffb0 slti ra, r23, 1001
555558bbffb4 beqz ra, 0x555558bbffd4 ->exit
555558bbffb8 li ra, 1
->LOOP:
555558bbffbc mul.d f31, f31, f0
555558bbffc0 addiu r23, r23, 1
555558bbffc4 slti ra, r23, 1001
555558bbffc8 bnez ra, 0x555558bbffbc ->LOOP
555558bbffcc li ra, 3
---- TRACE 1 stop -> loop
针对上面SSA IR
作如下解释,其中“文档”指的是官方文档:
第1列:IR指令编号,可以作为SSA ref,也就是说,若有指令想要获取当前指令产生的值(如PHI指令),就可以直接ref当前指令的编号到其opt。
第2列:指令标志:
">"
(IRT_GUARD = 0x80
指令标志)有该标志的指令可以理解为是一个分叉指令,可能会是trace路径的出口。该标志一般在关系运算指令前面(见文档Guarded Assertions
)。
"+"
(IRT_ISPHI = 0x40
指令标志)有该标志的指令可能会是PHI指令的左或右操作数。PHI指令在循环trace的末尾,有两个操作数,分别引用同一变量在循环期间不同时间段的值,左操作数是对初始值的引用,右操作数是对每次循环迭代后该值的引用第3列:IR类型:
int
类型指的是32 bit signed integer
,num
类型指的是double
(见文档IR Types
)。第4列:IR操作码,主要有以下分类(见文档各种操作码)
Constants Guarded Assertions Bit Ops(位操作) Arithmetic Ops(算数操作) Memory References(内存引用,返回一个指针,供Loads and Stores操作使用) Loads and Stores Allocations Barriers Type Conversions(类型转换) Calls(函数调用操作码) Miscellaneous Ops(其他操作码)
第5/6列:IR操作数(SSA ref或字面量)
'#'+数字
,表示该数字是一个stack slot number,可以理解成为对指定栈内存的引用,被用于SLOAD指令的做操作数。
#0
,函数栈帧。
#1
,is the first slot in the first frame (register 0 in the bytecode)。
'[+-]'+字面量
,表示字面量的正负值。
'[0x%d+]'
和NULL
是内存地址。
’”……“
是字符串。
'@'
prefixes indicate slots (what is this?).
Other possible values:"bias" (number 2^52+2^51 ?)
,"userdata:%p"
,
"userdata:%p"
(table)–when do these occur?.
1.3 IR类型和常量
IR类型:
IR的每条指令都有用于定义指令结果值的类型,总共有23
个,这些类型对应Lua的数据类型或low-level(更适合目标机器的低级类型)类型,源码中关于类型的定义在src/lj_ir.h
和src/lj_obj.h
中。需要查询指令语法时请阅读官方文档 IR Types。
常量:
常量指令只用于常数操作,IR常量是interned(去重),并且只能通过查看它们的引用(IRref)来比较它们的相等性。常量指令不会出现在转储(dump)中,因为-jdump
只显示内联到引用指令中的实际常量值,如0005 > int LE 0004 +1000
。
32
位整数或指针值占用左右两边(共32
位)各16
位操作数的空间,64
位值在一个全局常量表中,并由32
位指针间接引用(通过IRref)。
常量指令总共有9
条,需要查询指令语法时请阅读官方文档 Constants,Constants中有对部分常量(KPRI
、KPTR
、KKPTR
、KSLOT
、HREFK
)的解释,遇到后可自己查看。
1.4 Guarded Assertions
Guarded assertions也就是条件判断指令,有两个作用:
- a.提供有关其操作数的断言,编译器可以使用该断言来优化同一跟踪中的所有后续指令。
- b.被后端用来作为分支比较的发射(emit),比较结果若为true,则继续执行后续指令;结果若为
false
,则退出trace并恢复到最近的快照。
RETF
指令返回的原型(prototype)位于跟踪所覆盖的调用图之下,因此RETF
需要锚定(anchor)原型以防止GC回收PC。Guarded assertions指令总共有12
条,需要查询指令语法时请阅读官方文档 Guarded assertions。
1.5 位运算和算数运算
位运算:
位运算中需要注意的有一个循环左移(left rotate)和循环右移(right rotate),如循环右移:BROR abcdefg 3 => efgabcde
。
位运算指令总共有10
条,需要查询指令语法时请阅读官方文档 Bit Ops。
算数运算:
算数运算需要注意的则是数据溢出,ADDOV
、SUBOV
、MULOV
指令均可以在运算时做溢出检查,有符号整数溢出一旦被检查到,就会推出trace。
浮点运算只有一条指令FPMATH ref #fpm
,ref
就是操作数,fpm
则是被调函数fpmath(ref)
,被调函数总共有12
个。算数运算指令总共有16
条,需要查询指令语法时请阅读官方文档 Arithmetic Ops。
1.6)内存引用和分配
内存引用:
内存引用(Memory references)会生成一个指针值,供各自对应的load和store使用,为了保留更高级别的语义并简化别名分析,内存引用不会分解为较低级别的操作(如 XLOAD 引用),其中一部分可以融合到load或store指令的操作数中。
AREF
和HREFK
指令的左操作数由FLOAD
指令产生的table的array(tab.array
)或hash(tab.hash
),AREF
右操作数是index(int类型),HREFK
右操作数可能是SLOAD
指令从stack中取出的str,也可能是str字面量;AREF
产生的值则供ALOAD
或ASTORE
使用,HREFK
产生的值则供HLOAD
或HSTORE
使用,如:0038 p64 FLOAD 0037 tab.array 0039 p64 AREF 0038 +1 0040 str ASTORE 0039 0035。
HREF
和NEWREF
则直接使用table(可能是FLOAD指令产生的table.node
,也可能是SLOAD
指令从stack中取出的table,也可能是其他table)作为左操作数;HREF
和NEWREF
的右操作数为一个str常量,这个常量可能是slot中取出的值(SLOAD
从stack中取出),也可能是字符串字面量。
内存引用指令总共有8
条,需要查询指令语法时请阅读官方文档Memory References。
内存分配:
SNEW
仅适应于不会变化的数据,如字符串常量,这允许在字符串对象不使用的情况下消除分配(它的数据可能仍然被使用)。
CNEW
和CNEWI
分配的cdata对象的大小是从ctypeid操作数推断出来的,对于变长cdata,其大小由size操作数显式给出,否则size操作数为REF_NIL。
内存分配的指令总共有6
条,需要查询指令语法时请阅读官方文档Allocations。
1.7)Loads and Stores
loads和stores对内存引用进行操作,load一个值(指令的结果)或store一个值(右操作数),为了保持较高层次的语义并简化别名分析,它们没有统一或分解为较低层次的操作。loads和stores很重要,这里详细解释以下:
- a)
FLOAD
和SLOAD
内嵌它们的内存引用(dump对比这两条指令与其他指令的区别),其他所有的load和的store都有一个内存引用作为它们的左操作数。除了FLOAD
和XLOAD
之外,其他所有load都处理tagged values ,且都具有guarded assertion功能,检查load出来的数据的类型,如果类型检查不匹配,则退出trace并恢复到最近的快照。 - b)
ALOAD
和ASTORE
指令用于load或store一个array
,左操作数是内存引用AREF指令产生的p64
指针值。 - c)
HLOAD
和HSTORE
用于load或store一个hash
,左操作数是内存引用HREFK产生的p64
指针值。 - d)
ULOAD
和USTORE
用于load或store一个upvalue
,左操作数是内存引用UREFC
产生的p64
指针值。 - e)
FLOAD
和FSTORE
访问复合类型对象中的指定字段,左操作数是复合类型对象的IRref
,右操作数是字段id
(str字面量或stack slot number)。 - f)
XLOAD
适用于较低级别的类型,内存引用要么是STRREF
,要么分解为较低级别的操作,要么是一个ADD
、MUL
、BSHL
指针、偏移量或索引的组合。 - g)
SLOAD
的slot number与trace的起始栈帧(frame)相关,其中#0
表示闭包/帧槽(frame slot),#1
表示第一个可变slot(对应bytecode的slot 0)。RETF
将BASE
向下移动,随后的SLOAD
指令指的是较低帧的插槽。 - h)stack slots和vararg slots不支持存储操作,也就是只能load不能store。 All stores to stack slots are effectively sunk into exits or side traces.
loads
和stores
的指令总共有12
条,需要查询指令语法时请阅读官方文档Loads and Stores。
1.8)类型转换和Calls
类型转换:
数据类型转化主要有整数和浮点数之间,及数字与字符串之间转换,共有4
条,需要查询指令语法时请阅读官方文档 Type Conversions。
Calls:
对内部函数的调用分为几类:
- a)被调函数比较简单,只是简单的算数运算,可消除调用,用
CALLN
。 - b)对于执行load的调用,编译器会检查其中的store,用
CALLL
。 - c)对于执行store的调用,不会被消除,用
CALLS
。 - d)
ffi
调用使用CALLXS
。
Dump的代码如下,第一个操作数是函数名,第二个操作数是参数列表:
int CALLN lj_str_cmp (0019 0022)
p64 CALLL lj_strfmt_putfnum (0006 +53 0004)
num CALLS lj_prng_u64d ([0xfff6b1b7d8])
p64 CALLXS [0xfff6bbf6c0](0012 +32 )
函数调用总共5
条指令,需要查询指令语法时请阅读官方文档 Calls。
1.9)其他
这部分指令有几条很重要,需要理解,源码中经常出现:
- a)
BASE
是位于REF_BASE
的一条固定指令,用于保存BASE
指针,被一些指令隐式引用,比如SLOAD
。 - b)
PHI
指令位于一个循环trace的末端,左操作数保存对初始值的引用,右操作数保存对每次循环迭代后的值的引用。PHI
就是为了解决SSA带来的麻烦的,看如下IR代码:---- TRACE 1 IR 0001 > int SLOAD #3 T 0002 > int SLOAD #2 T 0003 >+ int ADDOV 0002 0001 0004 >+ int SUBOV 0002 +1 0005 > int GT 0004 +1 0006 ------ LOOP ------------ 0007 >+ int ADDOV 0004 0003 0008 >+ int SUBOV 0004 +1 0009 > int GT 0008 +1 0010 int PHI 0003 0007 0011 int PHI 0004 0008
可以将上述代码段划分为
3
个部分:循环之前必须执行的部分,循环部分,以及PHI
部分。如果循环部分没有执行,则0010 = 0003; 0011 = 0004;
,如果循环部分执行,则0010= 0007; 0011 = 0008;
。可参考LLVM IR PHI指令理解。 - c)
HIOP
指令在支持64
位的32
位机器上会使用到,拆分64
位为hiword和lowrd,在soft-fp(软浮点)好像也会用到。 - d)
LOOP
指令,只是起到了分隔循环体和循环之前内容的作用。 - e)当寄存器分配器想要为一个value重命名一个寄存器时(为了提高效率或保留PHI寄存器),就会生成
RENAME
。RENAME
指令保存了在给定快照下用于引用的寄存器,相同的引用值可能会有不同的寄存器,如0012 => r14, 0012 => r15
,最初引用的指令保存着上面使用的最高快照(如果有的话)的寄存器。
这部分指令总共有9
条,选经常遇到的解释一下,需要查询指令语法时请阅读官方文档 Miscellaneous Ops。
二、IR在luaJit源码中的定义
luaJit对于IR结构的定义主要在 lj_ir.h
、 lj_ircall.h
这两个个文件,IR emitter
主要在 lj_ir.c
文件。以下是lj_ir.h
文件,IR基本指令的定义:
1)IR instructions(操作码)
151 /* IR opcodes (max. 256). */
152 typedef enum {153 #define IRENUM(name, m, m1, m2) IR_##name,
154 IRDEF(IRENUM)
155 #undef IRENUM
156 IR__MAX
157 } IROp;
IROp是对IR操作码的枚举定义,需要注意的是每个操作码的枚举顺序很重要(顺序决定了其值),如IR_EQ
的值为8
,IR_NE
的值为9
,这样则可以通过表达式 (int)IR_EQ^1) == (int)IR_NE
在两者之间相互转换,类似的表达式还有如下:
162 LJ_STATIC_ASSERT(((int)IR_EQ^1) == (int)IR_NE);
163 LJ_STATIC_ASSERT(((int)IR_LT^1) == (int)IR_GE);
164 LJ_STATIC_ASSERT(((int)IR_LE^1) == (int)IR_GT);
165 LJ_STATIC_ASSERT(((int)IR_LT^3) == (int)IR_GT);
166 LJ_STATIC_ASSERT(((int)IR_LT^4) == (int)IR_ULT);
167
168 /* Delta between xLOAD and xSTORE. */
169 #define IRDELTA_L2S ((int)IR_ASTORE - (int)IR_ALOAD)
170
171 LJ_STATIC_ASSERT((int)IR_HLOAD + IRDELTA_L2S == (int)IR_HSTORE);
172 LJ_STATIC_ASSERT((int)IR_ULOAD + IRDELTA_L2S == (int)IR_USTORE);
173 LJ_STATIC_ASSERT((int)IR_FLOAD + IRDELTA_L2S == (int)IR_FSTORE);
174 LJ_STATIC_ASSERT((int)IR_XLOAD + IRDELTA_L2S == (int)IR_XSTORE);
2)Named IR literals(IR使用到的一些name字面量,比如某个字面值代表那个函数等)
184 typedef enum {
185 #define FPMENUM(name) IRFPM_##name,
186 IRFPMDEF(FPMENUM)
187 #undef FPMENUM
188 IRFPM__MAX
189 } IRFPMathOp;
IRFPMathOp
是对 FPMATH
操作码 操作数的定义,FPMATH
操作码操作码被用来一元浮点运算,其中的浮点运算对应关系如下:
OP | Description |
---|---|
FPM_FLOOR | floor(ref) |
FPM_CEIL | ceil(ref) |
FPM_TRUNC | trunc(ref) |
FPM_SQRT | sqrt(ref) |
FPM_EXP | exp(ref) |
FPM_EXP2 | exp2(ref) |
FPM_LOG | log(ref) |
FPM_LOG2 | log2(ref) |
FPM_LOG10 | log10(ref) |
FPM_SIN | sin(ref) |
FPM_COS | cos(ref) |
FPM_TAN | tan(ref) |
IRFieldID
是对 FLOAD
、FREF
操作码 的fields
的定义:
213 typedef enum {214 #define FLENUM(name, ofs) IRFL_##name,
215 IRFLDEF(FLENUM)
216 #undef FLENUM
217 IRFL__MAX
218 } IRFieldID;
下面这些定义分别对应的是表格中操作码的#flags
,如下:
220 /* SLOAD mode bits, stored in op2. */
221 #define IRSLOAD_PARENT 0x01 /* Coalesce with parent trace. */
222 #define IRSLOAD_FRAME 0x02 /* Load 32 bits of ftsz. */
223 #define IRSLOAD_TYPECHECK 0x04 /* Needs type check. */
224 #define IRSLOAD_CONVERT 0x08 /* Number to integer conversion. */
225 #define IRSLOAD_READONLY 0x10 /* Read-only, omit slot store. */
226 #define IRSLOAD_INHERIT 0x20 /* Inherited by exits/side traces. */
227
228 /* XLOAD mode, stored in op2. */
229 #define IRXLOAD_READONLY 1 /* Load from read-only data. */
230 #define IRXLOAD_VOLATILE 2 /* Load from volatile data. */
231 #define IRXLOAD_UNALIGNED 4 /* Unaligned load. */237 /* CONV mode, stored in op2. */
238 #define IRCONV_SRCMASK 0x001f /* Source IRType. */
239 #define IRCONV_DSTMASK 0x03e0 /* Dest. IRType (also in ir->t). */
240 #define IRCONV_DSH 5
241 #define IRCONV_NUM_INT ((IRT_NUM<<IRCONV_DSH)|IRT_INT)
242 #define IRCONV_INT_NUM ((IRT_INT<<IRCONV_DSH)|IRT_NUM)
243 #define IRCONV_SEXT 0x0800 /* Sign-extend integer to integer. */
244 #define IRCONV_MODEMASK 0x0fff
245 #define IRCONV_CONVMASK 0xf000
246 #define IRCONV_CSH 12
247 /* Number to integer conversion mode. Ordered by strength of the checks. */
248 #define IRCONV_TOBIT (0<<IRCONV_CSH) /* None. Cache only: TOBIT conv. */
249 #define IRCONV_ANY (1<<IRCONV_CSH) /* Any FP number is ok. */
250 #define IRCONV_INDEX (2<<IRCONV_CSH) /* Check + special backprop rules. */
251 #define IRCONV_CHECK (3<<IRCONV_CSH) /* Number checked for integerness. */
OP | Left | Right | Description |
---|---|---|---|
XLOAD | xref | #flags | Extended load |
SLOAD | #slot | #flags | Stack slot load |
CONV | src | #flags | Generic type conversion |
还有少许其他特殊操作码的定义,可以自行查找对应。
3)IR operands,IR 操作数
以下是对IR操作数的定义,其中IRMode
为操作数的kind
,分为了四种:
260 /* IR operand mode (2 bit). */
261 typedef enum {262 IRMref, /* IR reference. */
263 IRMlit, /* 16 bit unsigned literal. */
264 IRMcst, /* Constant literal: i, gcr or ptr. */
265 IRMnone /* Unused operand. */
266 } IRMode;
267 #define IRM___ IRMnone
4)IR instruction types,IR 指令类型
每个IR指令的都有一个输出结果的类型,IRType
则是对其的定义(8 bit)
:
314 /* IR result type and flags (8 bit). */
315 typedef enum {316 #define IRTENUM(name, size) IRT_##name,
317 IRTDEF(IRTENUM)
318 #undef IRTENUM
319 IRT__MAX,
320
321 /* Native pointer type and the corresponding integer type. */
322 IRT_PTR = LJ_64 ? IRT_P64 : IRT_P32,
323 IRT_PGC = LJ_GC64 ? IRT_P64 : IRT_P32,
324 IRT_IGC = LJ_GC64 ? IRT_I64 : IRT_INT,
325 IRT_INTP = LJ_64 ? IRT_I64 : IRT_INT,
326 IRT_UINTP = LJ_64 ? IRT_U64 : IRT_U32,
327
328 /* Additional flags. */
329 IRT_MARK = 0x20, /* Marker for misc. purposes. */
330 IRT_ISPHI = 0x40, /* Instruction is left or right PHI operand. */
331 IRT_GUARD = 0x80, /* Instruction is a guard. */
332
333 /* Masks. */
334 IRT_TYPE = 0x1f,
335 IRT_T = 0xff
336 } IRType;
这里还定义了两个函数,itype
和TValue
见lj_obj.h
:
itype2irt
:将itype
转成IRType
irt_toitype_
:IRType
转成itype
5)IR references
Tagged IR references
都有一个IRType
,也就是下面的irt
,这样方便快速IR type checks。irt is 8 bit
,flags is 8 bit
,ref is 16 bit
:
446 /* Fixed references. */
447 enum {448 REF_BIAS = 0x8000,
449 REF_TRUE = REF_BIAS-3,
450 REF_FALSE = REF_BIAS-2,
451 REF_NIL = REF_BIAS-1, /* \--- Constants grow downwards. */
452 REF_BASE = REF_BIAS, /* /--- IR grows upwards. */
453 REF_FIRST = REF_BIAS+1,
454 REF_DROP = 0xffff
455 };
456 471 /* Tagged IR references (32 bit).
472 **
473 ** +-------+-------+---------------+
474 ** | irt | flags | ref |
475 ** +-------+-------+---------------+
476 */
6)IR format
524 /* IR instruction format (64 bit).
525 **
526 ** 16 16 8 8 8 8
527 ** +-------+-------+---+---+---+---+
528 ** | op1 | op2 | t | o | r | s |
529 ** +-------+-------+---+---+---+---+
530 ** | op12/i/gco32 | ot | prev | (alternative fields in union)
531 ** +-------+-------+---+---+---+---+
532 ** | TValue/gco64 | (2nd IR slot for 64 bit constants)
533 ** +---------------+-------+-------+
534 ** 32 16 16
535 **
536 ** prev is only valid prior to register allocation and then reused for r + s.
537 */539 typedef union IRIns {540 struct {541 LJ_ENDIAN_LOHI(
542 IRRef1 op1; /* IR operand 1. */
543 , IRRef1 op2; /* IR operand 2. */
544 )
545 IROpT ot; /* IR opcode and type (overlaps t and o). */
546 IRRef1 prev; /* Previous ins in same chain (overlaps r and s). */
547 };
548 struct {549 IRRef2 op12; /* IR operand 1 and 2 (overlaps op1 and op2). */
550 LJ_ENDIAN_LOHI(
551 IRType1 t; /* IR type. */
552 , IROp1 o; /* IR opcode. */
553 )
554 LJ_ENDIAN_LOHI(
555 uint8_t r; /* Register allocation (overlaps prev). */
556 , uint8_t s; /* Spill slot allocation (overlaps prev). */
557 )
558 };
559 int32_t i; /* 32 bit signed integer literal (overlaps op12). */
560 GCRef gcr; /* GCobj constant (overlaps op12 or entire slot). */
561 MRef ptr; /* Pointer constant (overlaps op12 or entire slot). */
562 TValue tv; /* TValue constant (overlaps entire slot). */
563 } IRIns;
LuaJIT SSA IR介绍相关推荐
- TVM学习笔记二.relay IR介绍
relay是一种功能多样的编程语言,用于机器学习系统表达的中间表示.relay支持代数数据类型,闭包,控制流和递归,从而可以直接表示比基于计算图的IR更复杂的模型.relay还包括一种使用类型关系的依 ...
- luajit开发文档wiki中文版(四) LuaJIT 内部结构
2022年6月10日15:15:22 luajit开发文档中文版(一)下载和安装 luajit开发文档中文版(二)LuaJIT扩展 luajit开发文档中文版(三)FAQ 常见问题 luajit开发文 ...
- LuaJIT Bytecode介绍
文章目录 一.Introduction 二.Comparison.Test and Copy.JMP 三.Unary and Binary ops 四.Upvalue and function ops ...
- 即时编译器的中间表达形式(IR)
原文链接:https://www.520mwx.com/view/36709 一.中间表达形式(IR) 在编译原理课程中,我们通常将编译器分为前端和后端.其中,前端会对所输入的程序进行词法分析.语法分 ...
- luajit集成篇/平台相关篇 | 合理用好lua+unity,更省性能的方案整理
luajit集成篇 大家都知道luajit比原生lua快,快在jit这三个字上. 但实际情况是,luajit的行为十分复杂.尤其jit并不是一个简单的把代码翻译成机器码的机制,背后有很多会影响性能的因 ...
- 一文入门Go静态单赋值(SSA)
在上一篇文章<通过实例理解Go内联优化>[1]中,我们探讨了Go编译器在编译中端进行的内联优化.内联优化基于IR中间表示进行,不过Go编译过程不止有一种IR表示,这点和龙书<编译原理 ...
- luajit开发文档wiki中文版(一) 目录
2022年6月9日09:22:53 官方地址:http://luajit.org/ 官方wiki地址:http://wiki.luajit.org/Home 推荐书籍: OpenResty 最佳实践: ...
- 用好Lua+Unity,让性能飞起来—LuaJIT性能坑详解
原文链接:https://blog.uwa4d.com/archives/usparkle_luajit.html 导语:大家都知道LuaJIT比原生Lua快,快在JIT这三个字上.但实际情况是,Lu ...
- LuaJIT源码结构梳理
源码代码结构 1.luaJit使用到的一些内嵌库,如基础库.math库.IO库等. lib_aux.c lib_base.c lib_bit.c lib_buffer.c lib_debug.c li ...
最新文章
- Win/Linux常用命令
- 深度学习原理—代码分析线性分类与神经网络分类的区别
- python有道翻译法语-使用python2爬取有道翻译
- Servlet中使用RequestDispatcher调派请求--include
- 打开指定大小的新窗口
- 使用maven构建的Spring boot项目在开始搭建的时候出的一些错误
- 高精度人脸表情识别(附GitHub地址)
- 【leetcode刷题笔记】Merge k Sorted Lists
- Java 算法 质数的后代
- UITextField加间隔符号格式化
- 在线工具-程序员的工具箱-在线Cron表达式生成器
- linux之我常用的20条命令(之二)
- python windows 消息通讯_如何使用python與windows中的事件/消息掛鈎
- Atlassian JIRA 插件开发之二 安装和创建项目
- android SDK安装以及环境变量配置(windows)
- ANSYS网格划分标准及方法
- 小白教程系列——MultiDesk连接服务器
- 前端常用PS技巧总结之更换图片背景颜色
- gerrit 将代码从一个分支合并到另外一个分支 Cherry Pick的使用
- 推荐一款清爽的实时监控大屏附安装教程
热门文章
- 引用 oem 和主板bios修改方法
- HP OEM XP的BIOS破解方法
- IBM X3850服务器数据恢复成功案例
- 企业电子招标采购系统源码Spring Cloud + Spring Boot + MybatisPlus + Redis + Layui + 前后端分离 + 二次开发
- 【人工智能行业大师访谈】1. 吴恩达采访 Yoshua Bengio
- “华为天才少年”自制百大Up奖杯,网友:技术难度不高侮辱性极强
- Linux下C编程入门和总结
- swoft自定义进程
- 区块链革命 - 推荐序二 区块链已成为金融科技的底层技术
- 一般充电宝买多少毫安?充电宝多少毫安最好