Next: GIMPLE instruction set, Up: GIMPLE
GIMPLE指令为可变大小的元组,并由两部分组成:一个描述指令和位置的头,一个具有所有操作数的可变长度的身体。元组被组织成一个层次结构,并有3个主要类别。
gimple_statement_base
(gsbase)这是层次结构的根,其存放了大多GIMPLE语句所需要的基本信息。有一些域并不与所有的GIMPLE语句相关,但是被挪到基础结构中是为了利用其它域剩下的空位(从而使得结构体更加紧凑)。结构体在64位主机上占用4个字(32个字节 ):
Field | Size (bits)
|
code | 8
|
subcode | 16
|
no_warning | 1
|
visited | 1
|
nontemporal_move | 1
|
plf | 2
|
modified | 1
|
has_volatile_ops | 1
|
references_memory_p | 1
|
uid | 32
|
location | 32
|
num_ops | 32
|
bb | 64
|
block | 63
|
Total size | 32 bytes
|
code
GIMPLE指令的主要标识
subcode
用来区分相同基本指令的不同变体,或者提供使用于给定代码的标记。subcode
标记域具有不同的用法,并取决于指令的代码,但是其主要是用来区分相同家族的指令。该域最突出的用法是在赋值中,其子代码指出了在赋值的右手边所进行的操作。例如,a = b + c被编码为GIMPLE_ASSIGN <PLUS_EXPR, a, b, c>
。
no_warning
位标记,用来指出是否在该语句上已经产生了一个警告。
visited
通用目的的“访问”标记 。由每个编译过程根据需要来设置和清除。
nontemporal_move
位标记,用在赋值中,用来表示非临时的移动。虽然该位标记只用于赋值,但其被放到这里是为了利用先前域所剩下的空位。
plf
编译过程局部标记。该2个位的掩码可以由任何编译过程用作通用的标记。编译过程负责相应的清除和设置这两个标记。
modified
位标记,用来指出语句是否被修改。主要由操作数扫描器来使用,用来确定什么时候重新扫描一条语句的操作数。
has_volatile_ops
位标记,用来指出语句是否包含被标记为volatile的操作数。
references_memory_p
位标记,用来指出语句是否包含内存引用(即,其操作数为全局变量,或者指针解引用,或者任何必须在内存中的)。
uid
为无符号整数,由想要为每条语句分配ID的编译过程使用。这些ID必须由每个编译过程来分配和使用。
location
为一个location_t
标识符,用来指定该语句的源代码位置。其从前端继承下来。
num_ops
该语句具有的操作数个数。这描述了元组中嵌套的操作数向量的大小。只在一些元组中使用,但其声明在基础元组中是为了利用先前语所剩下的32位空位。
bb
包含该语句的基本块。
block
包含该语句的词法块。还用于调试信息的生成。
gimple_statement_with_ops
该元组实际分成两部分:gimple_statement_with_ops_base
和 gimple_statement_with_ops
。这是为了适应操作数向量的分配方法。操作数向量被定义为有1个元素的数组。所以,要分配动态数目的操作数,内存分配器(gimple_alloc
)只是简单的分配足够的内存来存放结构体本身,以及在结构体尾部加上N - 1
个操作数。例如,要为有3个操作数的元组分配空间,gimple_alloc
预留了sizeof (struct gimple_statement_with_ops) + 2 * sizeof (tree)
个字节。
另一方面,该元组中的一些域需要与gimple_statement_with_memory_ops
元组共享。所以,这些公共域被放在gimple_statement_with_ops_base
中,然后由其它两个元组来继承。
gsbase | 256
|
addresses_taken | 64
|
def_ops | 64
|
use_ops | 64
|
op | num_ops * 64
|
Total size | 56 + 8 * num_ops bytes
|
gsbase
继承自struct gimple_statement_base
。
def_ops
指针数组,指向操作数数组,指出该包含语句写入的变量的所有插槽。该数组还用于立即使用链。注意,是可以不依赖该数组的,但是这种实现会很具有入侵性。
use_ops
类似于def_ops
,不过是针对语句读取的变量。
op
具有num_ops
插槽的tree数组。
gimple_statement_with_memory_ops
该元组本质上等同于gimple_statement_with_ops
,除了其包含4个额外的域,来存放与内存存储和加载相关的向量。类似于先前的情况,结构体被分成两部分,用来容纳操作数向量(gimple_statement_with_memory_ops_base
和gimple_statement_with_memory_ops
)。
Field | Size (bits)
|
gsbase | 256
|
addresses_taken | 64
|
def_ops | 64
|
use_ops | 64
|
vdef_ops | 64
|
vuse_ops | 64
|
stores | 64
|
loads | 64
|
op | num_ops * 64
|
Total size | 88 + 8 * num_ops bytes
|
vdef_ops
类似于def_ops
,不过用于VDEF
操作符。这是该语句写入的内存符号的一个实体。这用于维护内存SSA use-def和def-def链。
vuse_ops
类似于use_ops
,不过用于VUSE
操作数。这是该语句加载的内存符号的一个实体。这用于维护内存SSA use-def链。
stores
位集合,该语句写入的符号的所有UID。这与vdef_ops
不同之处是,所有被影响的符号都在该集合中被提到。如果开启了内存划分,则vdef_ops
向量将指向内存划分。而且,该集合中不存放SSA信息。
loads
类似于stores
,不过用于内存加载。(注意,这里有一些冗余,应该可以通过移除这些集合来减少内存使用)。
所有其它元组按照这三个基本元组来定义。每个元组会增加一些域。gimple类型被定义成所有这些结构体的联合体(为了清晰,省略掉了GTY
标记):
union gimple_statement_d { struct gimple_statement_base gsbase; struct gimple_statement_with_ops gsops; struct gimple_statement_with_memory_ops gsmem; struct gimple_statement_omp omp; struct gimple_statement_bind gimple_bind; struct gimple_statement_catch gimple_catch; struct gimple_statement_eh_filter gimple_eh_filter; struct gimple_statement_phi gimple_phi; struct gimple_statement_resx gimple_resx; struct gimple_statement_try gimple_try; struct gimple_statement_wce gimple_wce; struct gimple_statement_asm gimple_asm; struct gimple_statement_omp_critical gimple_omp_critical; struct gimple_statement_omp_for gimple_omp_for; struct gimple_statement_omp_parallel gimple_omp_parallel; struct gimple_statement_omp_task gimple_omp_task; struct gimple_statement_omp_sections gimple_omp_sections; struct gimple_statement_omp_single gimple_omp_single; struct gimple_statement_omp_continue gimple_omp_continue; struct gimple_statement_omp_atomic_load gimple_omp_atomic_load; struct gimple_statement_omp_atomic_store gimple_omp_atomic_store; };