LLVM类型系统是中间表示的最重要的特征之一。类型化使得可以直接对中间表示执行许多优化,而不必在转换之前在侧面进行额外的分析。强大的类型系统使读取生成的代码变得更加容易,并且支持新的分析和转换,这些分析和转换在普通的三个地址代码表示上不可行。
void类型
概述:void类型不代表任何值并且没有大小。
Syntax: void
函数类型
概述:
函数类型可以被认为是函数签名。它由一个返回类型和一个形式参数类型列表组成。函数类型的返回类型是void类型或第一类类型
– 标签和元数据类型除外。
Syntax:<returntype> (<parameter list>)
…其中<parameter list>
是逗号分隔的类型说明符列表。可选地,参数列表可以包括类型…,该类型指示该函数采用可变数目的参数。变量参数函数可以通过处理内部函数的变量参数来访问它们的参数。<returntype>
是除标签和元数据之外的任何类型。
例如:
实例 | 说明 |
---|---|
i32 (i32) | 函数接受i32,返回一个i32 |
float (i16, i32 *) * | 指针,以接受一个函数i16和一个i32指针来返回float。 |
i32 (i8*, …) | 可变参数函数,它有至少一个指针到i8(在C中是char),它返回一个整数。LLVM中这是printf的签名。 |
{i32, i32} (i32) | 一个函数i32,返回一个包含两个i32值的结构 |
第一类类型(First Class Types)
第一类的类型可能是最重要的。这些类型的值是唯一可以通过指令产生的类型。
单值类型
这些是从CodeGen的角度来看在寄存器中有效的类型。
整数类型
概述:
整数类型是一个非常简单的类型,它简单地为所需的整数类型指定一个任意的位宽。可以指定从1位到223-1(约8百万)的任何位宽。
Syntax:
iN
整数将占据的位数由该N
值指定。
例子:i1
一个单位整数。i32
一个32位整数。i1942652
一个超过100万位的大整数。
浮点类型
类型 | 描述 |
---|---|
half | 16位浮点值 |
float | 32位浮点值 |
double | 64位浮点值 |
fp128 | 128位浮点值(112位尾数) |
x86_fp80 | 80位浮点值(X87) |
ppc_fp128 | 128位浮点值(两个64位) |
half,float,double和fp128的二进制格式分别对应于binary16,binary32,binary64和binary128的IEEE-754-2008规范。
X86_mmx类型
概述:
x86_mmx类型表示在x86机器上的MMX寄存器中保存的值。允许的操作相当有限:参数和返回值,load和store以及bitcast。用户指定的MMX
指令表示为具有参数and/or
此类型结果的内部调用或asm调用。没有这种类型的数组、向量或常量。
Syntax:
x86_mmx
指针类型
概述: 指针类型用于指定内存位置。指针通常用于引用内存中的对象。
指针类型可能有一个可选的地址空间属性,用于定义指向对象所在的编号地址空间。默认地址空间是数字零。非零地址空间的语义是特定于目标的。
请注意,LLVM不允许指向void(void*)
的指针,也不允许指向标签(label*)
的指针。改为使用i8*
。
Syntax:
<type> *
例子:
[4 x i32]*
4个的i32值数组的指针。i32 (i32*) *
函数指针,它接受一个i32*
,并返回i32。i32 addrspace(5)*
i32值的指针,驻留在地址空间#5
中的值。
矢量类型
概述:
矢量类型是表示元素矢量的简单派生类型。当使用单个指令(SIMD)并行操作多个原始数据时,使用矢量类型。矢量类型需要大小(元素数量)和基础原始数据类型。矢量类型被认为是第一类。
Syntax:
< <# elements> x <elementtype> >
元素的数量是一个大于0的常数整数值; elementtype
可以是任何整数、浮点或指针类型。大小为零的矢量是不允许的。
例子:
<4 x i32>
4个32位整数值的向量。<8 x float>
8个32位浮点值的向量。<2 x i64>
2个64位整数值的向量。<4 x i64*>
4个64位整数值指针的向量。
标签类型
概述: 标签类型代表代码标签。
Syntax:
label
令牌(token)类型
概述:
当值与指令相关联时使用token类型,但该值的所有用法不得试图反思或模糊它。因此,具有phi或select类型令牌是不合适的。
Syntax:
token
元数据类型
概述:
元数据类型表示嵌入的元数据。除函数参数外,不得从元数据创建派生类型。
句法:
metadata
聚合类型
聚合类型是派生类型的一个子集,可以包含多个成员类型。数组和结构是聚合类型。向量不被视为聚合类型。
数组类型
概述:
数组类型是一种非常简单的派生类型,它将元素按顺序排列在内存中。数组类型需要大小(元素数量)和基础数据类型。
Syntax: [<# elements> x
<elementtype>]
元素的数量是一个常数整数值; elementtype
可以是任何尺寸的类型。
例子:[40 x i32]
包含40个32位整数值的数组。[41 x i32]
41个32位整数值的数组。[4 x i8]
包含4个8位整数值的数组。
以下是多维数组的一些示例:[3 x [4 x i32]]
3×4 32位整数值数组。[12 x [10 x float]]
单精度浮点值的12×10数组。[2 x [3 x [4 x i16]]]
2x3x4的16位整数值数组。
除了静态类型隐含的数组末尾之外,没有对索引的限制(尽管在某些情况下索引超出了分配对象的范围)。这意味着可以在零长度数组类型的LLVM中实现单维“可变大小数组”。例如,在LLVM中实现“pascal样式数组”可以使用类型“{ i32, [0 x float]}
”。
结构类型
概述:
结构类型用于在内存中一起表示数据成员的集合。结构的元素可以是任何具有大小的类型。
使用’load
‘和’store
‘通过使用’getelementptr
‘指令获取指向字段的指针来访问内存中的结构。使用’extractvalue
‘和’insertvalue
‘指令访问寄存器中的结构。
结构可以选择是“压缩”结构,其指示结构的对齐是一个字节,并且元素之间没有填充。在非压缩结构中,字段类型之间的填充按照DataLayout字符串在模块中定义的方式插入,该模块需要与基础代码生成器的预期匹配。
结构可以是“文字”或“识别符”。字面结构与其他类型(例如{i32, i32}*
)内联定义,而标识类型始终在顶层使用名称定义。文字类型被其内容所独占,因为没有办法编写它们,所以永远不会递归或不透明。识别符的类型可以是递归的,可以是不透明的,并且永远不会被分离。
Syntax:
%T1 = type { <type list> } ; Identified normal struct type
%T2 = type <{ <type list> }> ; Identified packed struct type
例子:{ i32, i32, i32 }
三个i32值的结构{ float, i32 (i32) * }
一对,其中第一个元素是a
float,第二个元素是一个指向函数的指针,该函数接受一个i32返回值i32。<{ i8, i32 }>
一个已知为5字节大小的打包结构。
不透明结构类型
概述:
不透明结构类型用于表示没有指定主体的命名结构类型。这符合(例如)正向声明结构的C概念。
Syntax:
%X = type opaque
%52 = type opaque
例子:opaque
一种不透明的类型。