文章目录

  • 一、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 codeByte codeSSA 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 integernum类型指的是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.hsrc/lj_obj.h中。需要查询指令语法时请阅读官方文档 IR Types。

常量:

常量指令只用于常数操作,IR常量是interned(去重),并且只能通过查看它们的引用(IRref)来比较它们的相等性。常量指令不会出现在转储(dump)中,因为-jdump只显示内联到引用指令中的实际常量值,如0005 > int LE 0004 +1000
32位整数或指针值占用左右两边(共32位)各16位操作数的空间,64位值在一个全局常量表中,并由32位指针间接引用(通过IRref)。

常量指令总共有9条,需要查询指令语法时请阅读官方文档 Constants,Constants中有对部分常量(KPRIKPTRKKPTRKSLOTHREFK)的解释,遇到后可自己查看。

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。

算数运算:

算数运算需要注意的则是数据溢出,ADDOVSUBOVMULOV指令均可以在运算时做溢出检查,有符号整数溢出一旦被检查到,就会推出trace。

浮点运算只有一条指令FPMATH ref #fpmref就是操作数,fpm则是被调函数fpmath(ref),被调函数总共有12个。算数运算指令总共有16条,需要查询指令语法时请阅读官方文档 Arithmetic Ops。

1.6)内存引用和分配

内存引用:

内存引用(Memory references)会生成一个指针值,供各自对应的load和store使用,为了保留更高级别的语义并简化别名分析,内存引用不会分解为较低级别的操作(如 XLOAD 引用),其中一部分可以融合到load或store指令的操作数中。

  • AREFHREFK 指令的左操作数由FLOAD指令产生的table的array(tab.array)或hash(tab.hash),AREF右操作数是index(int类型),HREFK 右操作数可能是SLOAD指令从stack中取出的str,也可能是str字面量;AREF产生的值则供ALOADASTORE使用,HREFK产生的值则供HLOADHSTORE使用,如:

    0038    p64  FLOAD  0037  tab.array
    0039    p64  AREF   0038  +1
    0040    str  ASTORE 0039  0035。
    
  • HREFNEWREF则直接使用table(可能是FLOAD指令产生的table.node,也可能是SLOAD指令从stack中取出的table,也可能是其他table)作为左操作数;HREFNEWREF的右操作数为一个str常量,这个常量可能是slot中取出的值(SLOAD从stack中取出),也可能是字符串字面量。

内存引用指令总共有8条,需要查询指令语法时请阅读官方文档Memory References。

内存分配:

SNEW仅适应于不会变化的数据,如字符串常量,这允许在字符串对象不使用的情况下消除分配(它的数据可能仍然被使用)。

CNEWCNEWI分配的cdata对象的大小是从ctypeid操作数推断出来的,对于变长cdata,其大小由size操作数显式给出,否则size操作数为REF_NIL。

内存分配的指令总共有6条,需要查询指令语法时请阅读官方文档Allocations。

1.7)Loads and Stores

loads和stores对内存引用进行操作,load一个值(指令的结果)或store一个值(右操作数),为了保持较高层次的语义并简化别名分析,它们没有统一或分解为较低层次的操作。loads和stores很重要,这里详细解释以下:

  • a)FLOADSLOAD内嵌它们的内存引用(dump对比这两条指令与其他指令的区别),其他所有的load和的store都有一个内存引用作为它们的左操作数。除了FLOADXLOAD之外,其他所有load都处理tagged values ,且都具有guarded assertion功能,检查load出来的数据的类型,如果类型检查不匹配,则退出trace并恢复到最近的快照。
  • b)ALOADASTORE指令用于load或store一个array,左操作数是内存引用AREF指令产生的p64指针值。
  • c)HLOADHSTORE用于load或store一个hash,左操作数是内存引用HREFK产生的p64指针值。
  • d)ULOADUSTORE用于load或store一个upvalue,左操作数是内存引用UREFC产生的p64指针值。
  • e)FLOADFSTORE访问复合类型对象中的指定字段,左操作数是复合类型对象的IRref,右操作数是字段id(str字面量或stack slot number)。
  • f)XLOAD 适用于较低级别的类型,内存引用要么是 STRREF,要么分解为较低级别的操作,要么是一个ADDMULBSHL指针、偏移量或索引的组合。
  • g)SLOAD 的slot number与trace的起始栈帧(frame)相关,其中#0表示闭包/帧槽(frame slot),#1表示第一个可变slot(对应bytecode的slot 0)。RETFBASE 向下移动,随后的 SLOAD 指令指的是较低帧的插槽。
  • h)stack slots和vararg slots不支持存储操作,也就是只能load不能store。 All stores to stack slots are effectively sunk into exits or side traces.

loadsstores的指令总共有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寄存器),就会生成RENAMERENAME指令保存了在给定快照下用于引用的寄存器,相同的引用值可能会有不同的寄存器,如0012 => r14, 0012 => r15,最初引用的指令保存着上面使用的最高快照(如果有的话)的寄存器。

这部分指令总共有9条,选经常遇到的解释一下,需要查询指令语法时请阅读官方文档 Miscellaneous Ops。

二、IR在luaJit源码中的定义

luaJit对于IR结构的定义主要在 lj_ir.hlj_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的值为8IR_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是对 FLOADFREF操作码 的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;

这里还定义了两个函数,itypeTValuelj_obj.h

  • itype2irt :将itype转成IRType
  • irt_toitype_IRType转成itype

5)IR references

Tagged IR references都有一个IRType,也就是下面的irt,这样方便快速IR type checks。irt is 8 bitflags is 8 bitref 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介绍相关推荐

  1. TVM学习笔记二.relay IR介绍

    relay是一种功能多样的编程语言,用于机器学习系统表达的中间表示.relay支持代数数据类型,闭包,控制流和递归,从而可以直接表示比基于计算图的IR更复杂的模型.relay还包括一种使用类型关系的依 ...

  2. luajit开发文档wiki中文版(四) LuaJIT 内部结构

    2022年6月10日15:15:22 luajit开发文档中文版(一)下载和安装 luajit开发文档中文版(二)LuaJIT扩展 luajit开发文档中文版(三)FAQ 常见问题 luajit开发文 ...

  3. LuaJIT Bytecode介绍

    文章目录 一.Introduction 二.Comparison.Test and Copy.JMP 三.Unary and Binary ops 四.Upvalue and function ops ...

  4. 即时编译器的中间表达形式(IR)

    原文链接:https://www.520mwx.com/view/36709 一.中间表达形式(IR) 在编译原理课程中,我们通常将编译器分为前端和后端.其中,前端会对所输入的程序进行词法分析.语法分 ...

  5. luajit集成篇/平台相关篇 | 合理用好lua+unity,更省性能的方案整理

    luajit集成篇 大家都知道luajit比原生lua快,快在jit这三个字上. 但实际情况是,luajit的行为十分复杂.尤其jit并不是一个简单的把代码翻译成机器码的机制,背后有很多会影响性能的因 ...

  6. 一文入门Go静态单赋值(SSA)

    在上一篇文章<通过实例理解Go内联优化>[1]中,我们探讨了Go编译器在编译中端进行的内联优化.内联优化基于IR中间表示进行,不过Go编译过程不止有一种IR表示,这点和龙书<编译原理 ...

  7. luajit开发文档wiki中文版(一) 目录

    2022年6月9日09:22:53 官方地址:http://luajit.org/ 官方wiki地址:http://wiki.luajit.org/Home 推荐书籍: OpenResty 最佳实践: ...

  8. 用好Lua+Unity,让性能飞起来—LuaJIT性能坑详解

    原文链接:https://blog.uwa4d.com/archives/usparkle_luajit.html 导语:大家都知道LuaJIT比原生Lua快,快在JIT这三个字上.但实际情况是,Lu ...

  9. LuaJIT源码结构梳理

    源码代码结构 1.luaJit使用到的一些内嵌库,如基础库.math库.IO库等. lib_aux.c lib_base.c lib_bit.c lib_buffer.c lib_debug.c li ...

最新文章

  1. Win/Linux常用命令
  2. 深度学习原理—代码分析线性分类与神经网络分类的区别
  3. python有道翻译法语-使用python2爬取有道翻译
  4. Servlet中使用RequestDispatcher调派请求--include
  5. 打开指定大小的新窗口
  6. 使用maven构建的Spring boot项目在开始搭建的时候出的一些错误
  7. 高精度人脸表情识别(附GitHub地址)
  8. 【leetcode刷题笔记】Merge k Sorted Lists
  9. Java 算法 质数的后代
  10. UITextField加间隔符号格式化
  11. 在线工具-程序员的工具箱-在线Cron表达式生成器
  12. linux之我常用的20条命令(之二)
  13. python windows 消息通讯_如何使用python與windows中的事件/消息掛鈎
  14. Atlassian JIRA 插件开发之二 安装和创建项目
  15. android SDK安装以及环境变量配置(windows)
  16. ANSYS网格划分标准及方法
  17. 小白教程系列——MultiDesk连接服务器
  18. 前端常用PS技巧总结之更换图片背景颜色
  19. gerrit 将代码从一个分支合并到另外一个分支 Cherry Pick的使用
  20. 推荐一款清爽的实时监控大屏附安装教程

热门文章

  1. 引用 oem 和主板bios修改方法
  2. HP OEM XP的BIOS破解方法
  3. IBM X3850服务器数据恢复成功案例
  4. 企业电子招标采购系统源码Spring Cloud + Spring Boot + MybatisPlus + Redis + Layui + 前后端分离 + 二次开发
  5. 【人工智能行业大师访谈】1. 吴恩达采访 Yoshua Bengio
  6. “华为天才少年”自制百大Up奖杯,网友:技术难度不高侮辱性极强
  7. Linux下C编程入门和总结
  8. swoft自定义进程
  9. 区块链革命 - 推荐序二 区块链已成为金融科技的底层技术
  10. 一般充电宝买多少毫安?充电宝多少毫安最好