源码路径
llvm\include\llvm\IR\Type.h
llvm\include\llvm\IR\DerivedTypes.h
llvm类型系统
llvm类型系统是llvm IR最重要的特性之一,是llvm IR和普通的三地址码的重要区别,是一系列的基于IR的优化的基础。以下面的源代码为例:
// type.cpp
int add1(int a, int b) {
return a + b;
}
使用命令"clang -S -emit-llvm type.cpp -o type.ll",可以生成对应的llvm IR,可以看到llvm的IR中会使用类型i32来修饰操作数。
; ModuleID = 'type.cpp'
source_filename = "type.cpp"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-windows-gnu"
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @_Z4add1ii(i32 %a, i32 %b) #0 {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
%0 = load i32, i32* %a.addr, align 4
%1 = load i32, i32* %b.addr, align 4
%add = add nsw i32 %0, %1
ret i32 %add
}
llvm Type class
在llvm中,使用Type类来实现llvm类型系统,Type的所有类型如下列枚举定义,其中PrimitiveTypes是没有子类的类型,没有子类的原因是因为不需要。
enum TypeID {
// PrimitiveTypes - make sure LastPrimitiveTyID stays up to date.
VoidTyID = 0, ///< 0: type with no size
HalfTyID, ///< 1: 16-bit floating point type
FloatTyID, ///< 2: 32-bit floating point type
DoubleTyID, ///< 3: 64-bit floating point type
X86_FP80TyID, ///< 4: 80-bit floating point type (X87)
FP128TyID, ///< 5: 128-bit floating point type (112-bit mantissa)
PPC_FP128TyID, ///< 6: 128-bit floating point type (two 64-bits, PowerPC)
LabelTyID, ///< 7: Labels
MetadataTyID, ///< 8: Metadata
X86_MMXTyID, ///< 9: MMX vectors (64 bits, X86 specific)
TokenTyID, ///< 10: Tokens
// Derived types... see DerivedTypes.h file.
// Make sure FirstDerivedTyID stays up to date!
IntegerTyID, ///< 11: Arbitrary bit width integers
FunctionTyID, ///< 12: Functions
StructTyID, ///< 13: Structures
ArrayTyID, ///< 14: Arrays
PointerTyID, ///< 15: Pointers
VectorTyID ///< 16: SIMD 'packed' format, or other vector type
};
Type类的继承树如下图所示:
llvm::Type
所有Type类型的父类,由于构造函数被声明为protected,所以不能被直接实例化。
llvm::IntegerType
任意位宽的integer类型。位宽的范围为[IntegerType::MIN_INT_BITS
(1) ,IntegerType::MAX_INT_BITS]。
llvm::FunctionType
函数签名,包含了1个返回值类型和1个参数类型列表。
语法:<returntype> (<parameter list>)
示例:
i32 (i32) | 传入1个i32 , 返回i32 |
float (i16, i32 *) * | 函数指针类型,传入1个i16和1个 i32的指针 , 返回float . |
i32 (i8*, ...) | 变长函数,至少传入1个i8 的指针, 放回i32,既llvm中printf的函数签名。 |
{i32, i32} (i32) | 传入1个i32 , 返回1个由2个i32组成的结构体 |
llvm::PointerType
引用内存中的对象,表示Memory Location。PointerType有1个可选的address space属性,默认为0,非0的address space的语义是实现自定义的(target-specific)的。
语法:
<type> *
ptr
示例:
[4 x i32]* | 长度为4的i32数组指针 |
i32 (i32*) * | 函数指针,传入1个i32* , 返回i32 . |
i32 addrspace(5)* | address space 5中的指向i32的指针 |
ptr | 不透明指针. |
ptr addrspace(5) | address space 5中的不透明指针 |
llvm::StructureType
内存中数据成员的集合,数据成员必须是有size属性的Type。
内存中的Structure访问:通过"getelementptr"指令获取数据成员指针,再对指针使用load和store指令。
寄存器中的Structure访问:使用extractvalue和insertvalue指令
Structure可以是"packed" Structure,按照1byte对齐;也可以是"no-packed" Structure,数据成员间的padding由module中的DataLayout字符串决定。
Structure可以是"literal"的,既使用inline的形式定义,例如:{i32, i32}*;也可以是"identified"的,既使用名字进行定义,例如:
%T1 = type { <type list> } ; 定义no-packed identified structure T1 %T2 = type <{ <type list> }> ; 定义packed identified structure T2
Structure也可以是不透明的,通常用于前置声明,语法如下:
%X = type opaque ; 定义有名字的opaque structure X %52 = type opaque ; 定义没有名字的opaque structure 52
llvm::ArrayType
ArrayType是1种将元素在内存中顺序排列的类型,有2个属性:size和元素类型。
语法:
[<# elements> x <elementtype>]
其中elementtype是任意有size属性的Type。
示例:
[40 x i32] | 长度为40的32位整数Array |
[41 x i32] | 长度为41的32位整数Array |
[4 x i8] | 长度为4的8位整数Array |
[3 x [4 x i32]] | 3x4的32位整数Array |
[12 x [10 x float]] | 12x10的单精度浮点Array |
[2 x [3 x [4 x i16]]] | 2x3x4的16位整数Array |
llvm::VectorType
VectorType表示元素的矢量,用于SIMD(单指令多数据),有3个属性:size,元素类型(必须是primitive类型),是否可扩展(scalable)。如果VectorType是可扩展的,则Vector的实际长度 = N * size。
当VectorType的长度以byte为单位时,VectorType在内存中的排布和ArrayType相同。当VectorType的长度不以byte为单位时,需要使用bitcase指令完成VectorType到IntegerType的相互转换,示例如下(大端):
%val = bitcast <4 x i4> <i4 1, i4 2, i4 3, i4 5> to i16
; Bitcasting from a vector to an integral type can be seen as
; concatenating the values:
; %val now has the hexadecimal value 0x1235.
store i16 %val, i16* %ptr
; In memory the content will be (8-bit addressing):
;
; [%ptr + 0]: 00010010 (0x12)
; [%ptr + 1]: 00110101 (0x35)
语法:
< <# elements> x <elementtype> > ; Fixed-length vector < vscale x <# elements> x <elementtype> > ; Scalable vector
其中elementtype只能是整数,浮点数,指针。
示例:
<4 x i32> | 长度为4的32位整数Vector |
<8 x float> | 长度为8的32位单精度浮点数Vector |
<2 x i64> | 长度为2的64位整数Vector |
<4 x i64*> | 长度为2的64位整数指针Vector |
<vscale x 4 x i32> | 长度为4的整数倍的32位整数Vector |
参考材料
LLVM Language Reference Manual — LLVM 15.0.0git documentation