LLVM IR(三)——IR类型体系(Type System)

可以转载,请注明出处!

对于type system,官方文档中并没有列举太多的例子,就只是说了一下他的结构,要想明白,还是要在工作与学习中反复练习,才能彻底掌握。对于有c基础的,理解起来相对会很轻松一点,比如指针和结构体,在以后的使用过程中,细品llvm的指针和c的指针有什么异同!

3.1 Void Type

Void类型不代表任何值,也没有大小。跟c、java中的void一样,在需要的地方起占位作用。

3.2 函数类型(Function Type)

Function 类型可以看做是函数的签名,它包括了函数的返回类型和形参列表。

语法:

<returntype> (<parameter list>)
  • returntype是函数的返回类型,必须是一个void类型或者first class类型(不包含labelmetadata类型)。
  • Parameter list是参数列表,多个参数之间用逗号分开。

例如:
i32 (i32) 接受一个i32类型,返回一个i32类型
float (i16, i32 *) * 函数指针(注意指针函数和函数指针的区别),该函数接受一个i16类型和一个指向i32的指针,返回一个float类型
i32 (i8*, ...) 一个可变参数函数,至少有一个指向i8 (对应C语言中的char)的指针,它返回一个i32。这是LLVM中printf函数的签名
{i32, i32} (i32) 接受一个i32,返回一个结构体

3.3 一级类型(First Class Type)

first class type是IR中最最最重要的类型,所有的指令都只能产生这个类型的值。First class type包含下面五种类型。

3.3.1 单值类型(Single Value Types)

1)整型类型(Integer Type)

语法结构为iN,其中N为表示所需整数大小的位宽,能表示的大小范围是1~(2的23次方)-1i32就是整数位宽为32位,即占用大小为4个字节,对应C语言中的int类型。

2)浮点类型(Floating-Point Types)
half	16位浮点值
float	32位浮点值
double	64位浮点值
fp128	128位浮点值(112位尾数)
x86_fp80	80位浮点值(X87)
ppc_fp128	128位浮点值(两个64位)
half	16位浮点值
float	32位浮点值

其中halffloatdoublefp128的二进制格式分别对应于binary16binary32binary64binary128的IEEE-754-2008规范。

3)X86_mmx Type

x86_mmx类型表示在x86机器上的MMX寄存器中保存的值。允许的操作相当有限:作为参数和返回值,loadstore以及bitcast指令操作。用户指定的MMX指令表示为具有参数and/or此类型结果的内部调用或asm调用。没有这种类型的数组、向量或常量。

4)指针类型(Pointer Type)

指针类型用于指定内存位置,通常用于引用内存中的对象。指针类型可以有一个可选的地址空间属性,用于定义指向对象所在的编号地址空间。默认地址空间为0,非零地址空间的语义是特定于目标的。需要注意的是,没有指向voidlabel类型的指针,即不存在void*label*,使用i8*代替。

【注】 这里的指针同C语言中的指针还是有区别,在llvm里,值是值,指针是指针,值存到指针里就store,从指针取值就load,从值是取不到指针的(个人理解)。

5)向量类型(Vector Type)

向量类型是表示向量元素的简单派生类型,当使用单个指令(SIMD)并行操作多个原始数据(primitive data)时,将使用向量类型。向量类型由一个表示元素数量的整数值和一个原始数据类型组成,在不确切知道编译环境的硬件长度时,需要用vscale去表示向量具有可扩展性(感觉我对可扩展向量理解的不到位,最好是自己看一下文档)。

语法:

< <# elements> x <elementtype> >          ; 定长向量
< vscale x <# elements> x <elementtype> > ; 可扩展向量
  • elements表示向量元素的数量,取值要大于0。
  • elementtype表示向量元素的基本类型,可以是整数、浮点、指针类型。

这是对可扩展向量的解释,我怕我解释错。For scalable vectors, the total number of elements is a constant multiple (called vscale) of the specified number of elements; vscale is a positive integer that is unknown at compile time and the same hardware-dependent constant for all scalable vectors at run time. The size of a specific scalable vector type is thus constant within IR, even if the exact size in bytes cannot be determined until run time.

例如:

<4 x i32>	4个i32类型值的向量
<8 x float>	8float类型值的向量
<4 x i64*>	4个i64类型指针值的向量
<vscale x 4 x i32>	4个i32类型值整数倍的向量(8个、12个、16)

3.3.2 标签类型(Label Type)

官方文档对这个的解释特别简单,就一句表示代码的标签,没了。我觉得更确切的解释应该是,表示basicblock进入的标签。

语法:

label %变量名

例如:

 %cmp = icmp eq i32 %rem, 0	;icmp是比较指令,这里比较%rem与0是否相等
							;br指令是跳转指令,这里根据上一步比较出来的变量%cmp的值决定跳转到那个分支
							;label类型的作用就体现在这里
  br i1 %cmp, label %if.then, label %if.else
if.then:                                          ; preds = %entry
  store i32 0, i32* %retval, align 4
  br label %return
if.else:                                          ; preds = %entry
  store i32 1, i32* %retval, align 4
  br label %return

从上面的用例中可以看出,跳转指令中声明的label类型变量,并不参与计算,而是作为一个代码块(basicblock)的开始标签。声明时label后面的变量名可以随便起,但是必须要一一对应上,如label %if.then要和if.then: 对应。

3.3.3 (标记类型)Token Type

当一个值与一条指令相关联时便可采取token类型,但是这个值不能试图去反思(introspect)或模糊(obscure)它。所以具有phiselect指令的token类型是不合适的。

语法:

token

后续对这个类型掌握的比较好了再来补!

3.3.4 元数据类型(Metadata Type)

元数据类型表示嵌入的元数据。除函数参数外,不得从元数据创建派生类型。

语法:

metadata

3.3.5 聚合类型(Aggregate Types)

1)数组类型(ArrayType)

在内存中砍了一块空间,将元素按顺序放进去。一个数组类型需要表示元素数量的值和基础数据类型两个属性。

语法:

[<# elements> x <elementtype>]
  • elements整型常量值,即constant integer value。
  • elementtype可以是任何类型

例如:

[40 x i32]40个i32值组成的数组
[12 x [10 x float]]	12x10 的二维数组,基础类型是float
[2 x [3 x [4 x i16]]]	2x3x4 的三维数组,基础类型是i16

下面这句话没有理解,只读了个大概意思,说是llvm中可以有一维的变长数组,比如说这样就是一个变长数组[0 x float]
There is no restriction on indexing beyond the end of the array implied by a static type (though there are restrictions on indexing beyond the bounds of an allocated object in some cases). This means that single-dimension ‘variable sized array’ addressing can be implemented in LLVM with a zero length array type. An implementation of ‘pascal style arrays’ in LLVM could use the type “{ i32, [0 x float]}”, for example.

2)结构体(Structure Type)

结构体类型用于表示内存中的数据成员集合,结构体的元素可以是任何具有大小的类型。通过使用“getelementptr”指令获取一个指向字段的指针,使用“load”和“store”访问内存中的结构体。使用“extractvalue”和“insertvalue”指令访问寄存器中的结构体。

结构体可以选择压缩(packed)结构,这表示结构的对齐方式是一个字节,并且元素之间没有填充。在非压缩(non-packed)结构体中,字段类型之间的填充将按照模块(module)中DataLayout字符串的定义插入,且该模块需要与基础代码生成器的预期相匹配。

结构体可以是字面量(literal)或标识符(identified)。字面量结构与其他类型(例如{i32, i32}*)一起定义,而标识符类型始终在顶层使用名称定义。字面量类型被其内容所独占,因为没有办法写入(write)它们,所以永远不会递归或不透明。标识符的类型可以是递归的,可以是不透明的,并且永远不会被分离。

语法:

%T1 = type { <type list> }     ; 普通标识符结构类型
%T2 = type <{ <type list> }>   ; 压缩(packed)标识符结构类型

例如:

{ i32, i32, i32 }	3个i32值的结构体
{ float, i32 (i32) * }	第一个元素是float,第二个元素是一个指向函数的指针,该函数接受一个i32,返回一个i32
<{ i8, i32 }>	一个已知为5字节大小的压缩结构
3)不透明结构(Opaque Structure Types)

不透明结构类型用于表示没有指定主体的命名结构类型,可以用于向前声明尚不可用的类型。

语法:

%X = type opaque
%52 = type opaque
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yelvens

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值