LLVM IR 数据布局

LLVM程序模块,可以指定目标特定数据布局字符串,该字符串指定数据如何布置在内存中。数据布局的语法很简单:

target datalayout = "layout specification"

该布局规范包括规范用减号字符分隔(“-”)的列表中。每个规范都以字母开头,并可能在字母后包含其他信息以定义数据布局的某些方面。接受的规格如下:

  • E:
    指定目标以big-endian格式显示数据。也就是说,最重要的位具有最低的地址位置。
  • e:
    指定目标以little-endian形式显示数据。也就是说,具有最低重要性的位具有最低的地址位置。
  • S<size>:
    指定堆栈的自然对齐位数。堆栈变量的对齐提升仅限于自然堆栈对齐,以避免动态堆栈重新对齐。堆栈对齐必须是8位的倍数。如果省略,则自然堆栈对齐默认为“未指定”,这不会阻止任何对齐升级。
  • P<address space>:
    指定对应于程序内存的地址空间。哈佛(Harvard)体系结构可以使用它来指定LLVM应该在哪些空间放置诸如函数之类的东西。如果省略,程序存储器空间默认为默认地址空间0,这对应于具有相同空间中的代码和数据的冯诺依曼体系结构。
  • A<address space>:
    指定由’alloca‘创建的对象的地址空间。默认为默认地址空间0。
  • p[n]:<size>:<abi>:<pref>:<idx>:
    这将指定大小的指针和它的<abi><pref>错误的地址的空间对齐n。第四个参数<idx>是用于地址计算的索引大小。如果未指定,则默认索引大小等于指针大小。所有尺寸都是位。地址空间n是可选的,如果未指定,则表示默认地址空间0.值n必须在[1,2^23)范围内。
  • i<size>:<abi>:<pref>:
    这指定了给定<size>位的整数类型的对齐方式。值<size>必须在[1,2^23)范围内。
  • v<size>:<abi>:<pref>:
    这指定了给定<size>位的向量类型的对齐方式。
  • f<size>:<abi>:<pref>:
    这指定了给定<size>位的浮点类型的对齐方式。只有目标支持的<size>值才有效。所有目标都支持32(浮动)和64(双)。一些目标也支持80或128(不同长度的双重版本)。
  • a:<abi>:<pref>: 这指定了聚合类型对象的对齐方式。
  • F<type><abi>:这指定了函数指针的对齐方式。
    <type>的选项是:
    • i:函数指针的对齐与函数的对齐无关,是的倍数。
    • n:函数指针的对齐是函数指定的显式对齐的倍数,是的倍数。
  • m:<mangling>:
    如果存在,则指定llvm名称在输出中被损坏。以mangling转义字符作为前缀的符号\01直接传递给汇编器而不使用转义字符。mangling风格选项是
    • e:ELF mangling:专用符号获取.L前缀。
    • m:Mips mangling:私有符号获取$前缀。
    • o:Mach-O修改:专用符号获取L前缀。其他符号会得到一个_前缀。
    • x:Windows x86 COFF mangling:私有符号获取通常的前缀。普通的C符号会得到一个_前缀。带有__stdcall__fastcall,和__vectorcall的函数具有附加的自定义修剪(mangling),@N其中N是用于传递参数的字节数。以?开头的C++符号不会以任何方式的变形(mangling)。
    • w:Windows COFF mangling:类似于x,除了普通的C符号不接受_前缀。
  • n<size1>:<size2>:<size3>...:
    这为位目标CPU指定了一组本地整数宽度。例如,它可能包含32位PowerPC的n32,对于PowerPC 64是n32:64或对于X86-64是n8:16:32:64。这组元素被认为可以有效地支持大多数一般的算术运算。
  • ni:<address space0>:<address space1>:<address space2>...:
    这指定具有指定地址空间的指针类型作为非整体指针类型。该0地址空间不能被指定为非积分(non-integral)。

在每个采用的<abi>:<pref>规范上,指定<pref>对齐是可选的。如果省略,则前面的内容也应该省略,并且<pref>等于<abi>

在为给定目标构建数据布局时,LLVM从默认的一组规范开始,然后(可能)由datalayout关键字中的规范覆盖。默认规格在此列表中给出:

  • E – 大端
  • p:64:64:64 – 与64位对齐的64位指针。
  • p[n]:64:64:64 – 其他地址空间被假定为与默认地址空间相同。
  • S0 – 自然堆栈对齐未指定
  • i1:8:8 – i1是8位(字节)对齐
  • i8:8:8 – i8是8位(字节)对齐
  • i16:16:16 – i16是16位对齐的
  • i32:32:32 – i32是32位对齐的
  • i64:32:64 – i64具有32位的ABI对齐,但优选对齐64位
  • f16:16:16 – 一半是16位对齐的
  • f32:32:32 – 浮点数是32位对齐的
  • f64:64:64 – 双是64位对齐
  • f128:128:128 – 四位是128位对齐
  • v64:64:64 – 64位向量是64位对齐的
  • v128:128:128 – 128位向量是128位对齐的
  • a:0:64 – 聚合是64位对齐

当LLVM确定给定类型的对齐时,它使用以下规则:

  1. 如果所寻找的类型与其中一个规格完全匹配,则使用该规格。
  2. 如果未找到匹配项,并且所查找的类型是整数类型,则使用大于所查找类型的位宽的最小整数类型。如果没有任何规格大于位宽,则使用最大的整数类型。例如,给定上面的默认规格,i7类型将使用i8(次大)的对齐,而i65i256将使用i64(最大指定)的对齐。
  3. 如果找不到匹配,并且所寻找的类型是矢量类型,那么将使用小于所寻找的矢量类型的最大矢量类型作为回退。发生这种情况是因为<128 x double>可以用64 <2 x double>来实现,例如。

数据布局字符串的功能可能不是您所期望的。值得注意的是,这不是来自代码生成器应该使用的对齐前端(frontend)的规范。

相反,如果指定,则需要目标数据布局来匹配最终代码生成器所期望的内容。这个字符串被中级优化器用来改进代码,这只有在它与最终的代码生成器使用的匹配时才有效。没有办法生成IR,这并不会将这个特定于目标的细节嵌入到IR中。如果您未指定字符串,则将使用默认规格来生成数据布局,并且优化阶段将相应地运行,并针对这些默认规格向IR中引入目标特异性。