Engee 文档

LLVM用户通行证

该页面正在翻译中。

Julia中有许多自定义LLVM传递。 一般来说,它们可以分为需要执行以保持Julia语义的传递,以及利用Julia语义来优化LLVM的IR的传递。

语义段落

这些传递用于将LLVM IR转换为可在CPU上运行的代码。 它们的主要目的是在代码生成过程中创建更简单的IR表示,因此将在其他LLVM传递中执行常见模式的优化。

CPUFeatures

  • 文件名’llvm-cpufeatures。cpp`

  • 类名:`CPUFeaturesPass'

  • 优化名称’module(CPUFeatures)`

这个传递减少了内部函数’julia的值。cpu。have_fma。(f32/f64’为真或假,这取决于目标体系结构和功能中存在的目标特征。 这个内部函数通常用于确定算法在多大程度上依赖于快速操作。 https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation#Fused_multiply%E2%80%93add [组合乘法-加法]比使用不依赖于此类指令的标准算法更好。

DemoteFloat16

  • 文件名’llvm-demote-float16。cpp`

  • 类名:'DemoteFloat16Pass`

  • 优化名称’function(DemoteFloat16)`

此通道将替换操作https://en.wikipedia.org/wiki/Half-precision_floating-point_format [float16]由原生不支持float16操作的架构中的float32操作。 为此,请在任何float16操作周围插入`fpext`和`fptrunc`指令。 在支持本机float16操作的体系结构上,此传递不起作用。

[医]迟发性

  • 文件名’llvm-late-gc-lowering。cpp`

  • 类名:'LateLowerGCPass`

  • 优化名称’function(LateLowerGCFrame)`

这个传递完成了垃圾收集根所需的大部分工作,以跟踪垃圾收集安全点之间的指针。 它还在指令的相应变换之前降低了几个内部函数的级别,并且可能违反先前建立的非整数不变量(`pointer_from_objref`在此降低到`ptrpoint’指令)。 由于数据流算法最大限度地减少了位于任何安全点的对象数量,因此此传递通常比所有Julia用户传递持续时间更长。

[医]终结

  • 文件名’llvm-final-gc-lowering。cpp`

  • 类名:`FinalLowerGCPass'

  • 优化名称’module(FinalLowerGC)`

此通道将最后几个内部函数的级别降低到其最终版本,以libjulia库中的函数为目标。 将此通道与`LateGCLowering’分开允许其他后端(GPU编译)为这些内部函数提供自己的降级,以便Julia管道也可以在这些后端使用。

下岗工人

  • 文件名:'llvm-lower-handlers。cpp`

  • 类名:'LowerExcHandlersPass`

  • 优化名称’function(LowerExcHandlers)`

此传递将内部异常处理函数的级别降低为对在异常处理期间实际调用的运行时函数的调用。

诺维尼

  • 文件名’llvm-remove-ni。cpp`

  • 类名:'RemoveNIPass`

  • 优化名称’module(RemoveNI)`

此传输从模块的datalayout行中删除非整数地址空间。 在这种情况下,后端可以将所有用户地址空间的级别直接降低到机器代码中,而无需用指向地址空间0的指针对每个操作进行昂贵的重写。

辛德鲁普

  • 文件名’llvm-simdloop。cpp`

  • 类名:'LowerSIMDLoopPass`

  • 优化名称’loop(LowerSIMDLoop)`

这段话作为`@simd’注释的主要驱动因素。 代码生成插入标记`!llvm。loopid’进入循环的后分支,在本次传递中用于标识最初标记为`@simd’的循环。 然后,此过程查找形成reduce的浮点运算链,并添加快速数学的"contract"和"reassoc"标志以允许重新连接(因此也是矢量化)。 此传递不会保存有关循环或结论正确性的信息,因此可能会意外地违反Julia语义。 如果循环也已使用`ivdep’注释,则传递将其标记为没有循环生成的依赖项(如果用户注释不正确或应用于错误的循环,则结果行为将未定义)。

低点,低点

  • 文件名:'llvm-ptls。cpp`

  • 类名’LowerPTLSPass`

  • 优化名称’module(LowerPTLSPass)`

此传递将Julia内部函数的流本地级别降低为汇编指令。 Julia依赖于线程本地存储进行垃圾回收和多线程任务调度。 在编译系统映像和包映像的代码时,此过程使用加载期间初始化的全局变量中的加载替换对内部函数的调用。

如果在代码生成期间,使用`swiftself`参数和调用约定创建函数,则此传递假定’swiftself’参数是pgcstack,并用此参数替换内部函数。 这使您可以在访问线程本地存储速度较慢的体系结构中加快工作速度。

移除空间

  • 文件名:'llvm-remove-addrspaces。cpp`

  • 类名:'RemoveAddrspacesPass`

  • 优化名称’module(RemoveAddrspaces)`

此传递将一个地址空间中的指针重命名为另一个地址空间。 这用于从LLVM的IR中删除Julia相关的地址空间。

[医]脱去,脱去

  • 文件名:'llvm-remove-addrspaces。cpp`

  • 类名:'RemoveJuliaAddrspacesPass`

  • 优化名称’module(RemoveJuliaAddrspaces)`

此通道从LLVM的IR中删除Julia特定的地址空间。 它主要用于以更简单的格式显示LLVM IR。 在内部,此通道基于RemoveAddrspaces通道实现。

多重版本控制

  • 文件名:'llvm-multiversioning.cpp`

  • 类名’MultiVersioningPass`

  • 优化名称’module(JuliaMultiVersioning)`

此过程引入了对模块的更改,以创建优化为在不同体系结构中工作的函数(有关更多信息,请参阅sysimg.md 和pkgimg.md )。 在实现方面,它克隆功能并将各种特定于平台的属性应用于它们,以便优化器可以利用高级功能,例如针对给定平台的矢量化和指令调度。 它还创建了一个特定的基础结构,允许Julia映像加载器选择要调用的函数的适当版本,具体取决于此加载器运行的体系结构。 特定于目标对象的属性由模块标志`julia.mv.specs`控制,该标志在编译期间从环境变量中提取。 'JULIA_CPU_TARGET'。 要激活传递,请将模块标志`julia.mv.enable`设置为1。

使用具有多个版本控制的llvmcall是危险的。 llvmcall允许您访问Julia Api通常不提供的函数,因此通常不会在所有体系结构上提供。 如果启用了多个版本控制,并且请求为不支持表达式`llvmcall’所要求的功能的目标体系结构生成代码,则LLVM中可能会出现错误,最有可能是关机和消息:LLVM错误:.

Gcinvariant验证器

  • 文件名:'llvm-gc-invariant-verifier。cpp`

  • 类名:'GCInvariantVerifierPass`

  • 优化名称’module(GCInvariantVerifier)`

此通道用于验证Julia相对于LLVM的IR的不变量。 这包括,例如,不存在’ptrpoint’在https://llvm.org/docs/LangRef.html#non-integral-pointer-type [非整数地址空间]Julia脚注:nislides[https://llvm.org/devmtg/2015-02/slides/chisnall-pointers-not-int.pdf ""]并且仅存在批准的nislides指令(跟踪->派生,0->跟踪等。). 它不执行任何转换为IR。

优化通过

这些传递用于在LLVM的IR中执行LLVM不会自行实现的转换,例如用于数学标志的快速传播,逃逸分析和Julia特定内部函数的优化。 为了执行这些优化,他们使用了有关Julia语义的知识。

组合,组合

  • 文件名’llvm-muladd。cpp`

  • 类名:'CombineMulAddPass`

  • 优化名称’function(CombineMulAdd)`

该通道用于将具有快速函数`fadd`的常规函数`fmul`优化为具有快速函数`fadd`的压缩函数`fmul’的特定组合。 随后,后端将此选项优化为指令。 https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation#Fused_multiply%E2%80%93add [组合乘法-加法]以更多的代价显着加快运算速度https://simonbyrne …​github.io/notes/fastmath /[不可预测的语义]。

只有当`fmul’具有单一用途时,才会发生这种优化,这是一个快速的`fadd`功能。

分配,分配

  • 文件名’llvm-alloc-opt。cpp`

  • 类名:'AllocOptPass`

  • 优化名称’function(AllocOpt)`

在Julia中,没有软件堆栈作为分配可变对象的地方的概念。 但是,在堆栈上分配对象会减少垃圾回收的负载,并且对于Gpu上的编译非常重要。 因此,AllocOpt为对象执行从堆到堆栈的转换,正如它可以证明的那样,这些对象不是https://en.wikipedia.org/wiki/Escape_analysis [退出]当前功能。 它还执行许多其他分配优化,例如删除从不使用的选择,优化对新分配对象的typeof调用,以及删除立即复盖的选择的保存。 转义分析的实现在文件`llvm-alloc-helpers中。cpp'。 目前,此通行证不使用来自EscapeAnalysis的信息。jl,但这种情况可能会在未来发生变化。

传播,传播

  • 文件名:'llvm-propagate-addrspaces。cpp`

  • 类名’PropagateJuliaAddrspacesPass`

  • 优化名称’function(PropagateJuliaAddrspaces)`

此传递用于在指针操作期间分发Julia相关的地址空间。 LLVM无法使用优化插入或删除addrspacecast指令,因此此传递通过将操作替换为Julia地址空间中的对应操作来消除冗余addrspacecast指令。 有关Julia地址空间的更多信息,请参阅(TODO link to llvm.md )。

[医]朱利亚

  • 文件名’llvm-julia-licm。cpp`

  • 类名``JuliaLICMPass'

  • 优化名称’loop(Licm)`

该通道用于从循环输出Julia相关的内部函数。 特别是,它执行以下转换。

  1. 如果正在保存的对象是循环,则从循环推断`gc_preserve_begin`和`gc_preserve_end` -不变。.. 由于循环中保存的对象可能会在整个循环中持续存在,因此此转换可以减少IR中`gc_preserve_begin`/'gc_preserve_end’对的数量。 因此LateLowerGCPass可以轻松确定特定对象的存储位置。

  2. 具有不变对象的记录障碍的输出。

  3. 这里我们假设一个对象只能属于两代。 鉴于这一点,写入屏障应该对任何一对相同的对象只执行一次。 因此,如果被写入的对象是循环不变的,我们可以从循环中消除写入障碍。

  4. 如果不退出循环,则从循环中获取分布

    1. 在这里,我们使用非常保守的输出定义,与`AllocOptPass’中的定义相同。 这种转换允许您减少IR中的选择数量,即使选择完全超出功能。

此过程是保存LLVM分析所必需的。 https://llvm.org/docs/MemorySSA.html [MemorySSA](https://www.youtube.com/watch?v=bdxWmryoHak [短片剪辑],https://www.youtube.com/watch?v=1e5y6WDbXCQ [长视频剪辑])和https://baziotis.cs.illinois.edu/compilers/introduction-to-scalar-evolution.html [标量卷积](https://llvm.org/devmtg/2018-04/slides/Absar-ScalarEvolution.pdf [新幻灯片]https://llvm.org/devmtg/2009-10/ScalarEvolutionAndLoopOptimization.pdf [旧幻灯片])。