验证矢量化防锈重新审视

2021-05-16 17:46:41

研究的特点是允许自己犯错误:表演实验;得出结论;后来,意识到你的体验不够,你弄错了;再次和练习。我们认为我们知道如何应对矢量化生锈:告诉编译器不自动矢量化代码;告诉CompiLernot使用矢量说明;并使用现有的条件编译方法标志来禁用手矢量化代码.不幸的是,这三个想法中的两个不起作用 - 但我们认为我们现在有可用的方法。

这些想法中的第一个可能有效:您可以告诉编译器不是传达的代码。如果您使用的是货物,您可以使用RustFlags控制它;如果您使用RustC直接使用,可以在调用Rustc时直接拒绝武容式化。而且,如果您的程序调用C代码(orus调用C代码的箱子)并使用CC-RS Crate编译代码,那么您可以轻松地将标志传递给C编译器以禁用自动矢量化。(如果您的程序调用C代码未使用CC-RS Crate编译,YouWill需要修改C代码的构建系统 - 这有点工作。)

告诉编译器不使用载体指令的原因不应禁忌,是不可能关闭x86架构的sse2instructions而不会破坏浮点。我们最近意识到--ctarget-feature = -sse2标志转向SSE2矢量指令和对IEEE浮点的支持。与IEEE浮点禁用,LLVM尝试使用旧的80位X87浮点单元,然后在此时进行断言简而言之,你不能使用-sse2标志与rust.这需要一段时间才能识别我们不能只禁用SSE2,因为我们使用的技术在标准库中禁用SSE2才能做任何事情。我们认为我们可以使用环境变量rustflags_sse_not_0来禁用sse2(和其他x86向量扩展)在编译theStandard库时.alas,此环境变量已重命名,因此我们尝试禁用SSE2Was被忽略。

最后,使用现有条件编译功能flagsto禁用手矢量化代码的原因是没有单个特征标志。在某些箱子中,Miri标志用于禁用矢量化,但与您一样,Miri标志有其他效果。在其他箱子中,有一种明确的方式来禁用传感器特定的传感器特定的功能标志。在其他箱子中,无法禁用Vecsionization.it可能是具有标准功能标志的好主意禁用禁用矢量化代码,但至少暂时尝试禁用手动矢量化代码需要不同的方法您要使用的句柄箱。

在我描述了这个问题的新解决方案之前,值得询问吗?如果您的验证方法是使用职能合同,可以将您目前正在处理的功能的工作范围,但是根本无关紧要。另一方面,如果您的目标就像我们在没有指定每个函数的开销的情况下的那样,那么这可能很重要,因为即使您写的代码不使用矢量指令,您的代码很高ona crate,取决于使用Regex / Aho-corasick,hashbrown或std :: collections :: hashmap的箱子的箱子 - 所有这些都使用vector increstions。因此,如果您有兴趣验证整个程序,则可以使用一种方法来处理矢量指令。唉,没有我们知道实际支持的rustrified工具,我们知道了向量指令:它们会失败,并通过关于不受支持的指令的消息。

我们处理矢量指令的新方法是仿真矢量图,而不是尝试消除它们。这是我们需要一个Simdemulation库,然后我们需要安排验证工具在遇到仿真库时遇到矢量指令而不是报销他们找到了不受支持的指令。

我们的SIMD仿真库实现了特定于处理器的SIMD IntrinsicSthat,我们已经在RUST程序生成的LLVM位代码中找到。(如果您的付款工具基于MIR,这可能是您需要的内在的子集。我们很乐意添加额外的InstinsicsIF其他验证工具需要它们。)

SIMD指令集通常相当大:有很多义的标记来支持,但有三个功能的SIMD指令,可将所需仿真库所需的努力减少。

几乎所有SIMD指令都适用于三种模式之一:映射曲线标记,例如矢量添加,加工矢量彼此相互依赖;折叠式指令,将卷向量组合以提供较短的向量或标量值;和重新排列矢量元素的融合局。

几乎所有SIMD指令都基于将大型寄存器缩小到8,16,32或64位的元素中,除了ARM的SVE之外,寄存器尺寸和数量是两个固定功率。

几乎所有SIMD指令都有两个向量参数或矢量参数和标量参数。

这些观察允许我们在编写仿真库时非常有效地利用Rust的宏andrust的FN特征。

例如,x86架构具有一个名为psrlithat的指令系列,该指令组合了一个标量标量的向量。向量参数的分离元素由thescalar参数指定的距离转移。

每个矢量元素的动作可以通过标量函数来描述按标量移量移位标量值。例如,对于32位元素,该函数看起来像这样。

///逻辑转移到右8位立即(0如果移位距离太大)Pub Fn Srl_immed_u32_u8(x:u32,imm8:u8) - > U32 {如果Imm8> 31 {0}否则{x>> IMM8}}

要实现相应的向量功能,我们“提升”标量功能,它在向量上运行.Since这个模式非常常见,我们通过定义诸如在四个ElementSto的矢量上运行的实现诸如此之外的化学函数来实现这一点一个矢量参数和一个标量参数。

//通过向量和标量PUB FN Lift4_VS_V升降二进制操作。 F,A,B,R>; (f:f,a:a :: vec,b:b) - > R :: VEC其中F:Fn(a,b) - > R,A:Vector4,B:复制,R:Vector4,{Let R0 = F(A :: Get0(& a),b);让R1 = F(A :: Get1(& a),b);让R2 = F(A :: Get2(& a),b);让R3 = F(a :: get3(& a),b); R :: New(R0,R1,R2,R3)}

现在可以轻松地组合这些功能来模拟32位版本的ThePsRLI指令。

#[no_mangle]不安全extern" c" fn llvm_x86_sse2_psrli_d(a:u32x4,imm8:i32) - > U32x4 {升降机4_vs_v(scalar :: srl_immed_u32_u8,a,imm8为u8)}

请注意,u32x4类型是表示四32位值的向量的生锈类型。本类型实现了升力4_vs_v定义中使用的特征矢量4。

并且,通过定义特征Vector2,Vector4,Vector8,Vector16和Vector32,以及相关的提升功能,我们可以非常快速地实现SSE2 PSRLI指令的其他版本。

#[no_mangle]不安全extern" c" fn llvm_x86_sse2_psrli_b(a:u8x16,imm8:i32) - > U8X16 {升降机16_VS_V(Scalar :: srl_immed_u8_u8,a,imm8为u8)}#[no_mangle]不安全extern" c" fn llvm_x86_sse2_psrli_w(a:u16x8,imm8:i32) - > U16x8 {升降机8_vs_v(scalar :: srl_immed_u16_u8,a,imm8为u8)}#[no_mangle]不安全extern" c" fn llvm_x86_sse2_psrli_q(a:u64x2,imm8:i32) - > U64x2 {升降机2_vs_v(scalar :: srl_immed_u64_u8,a,imm8为u8)}

没有编译器标志将导致RustC或LLVM使用我们的Simdemulation库,以便我们的验证工具是使用MIR还是LLVM IR,编译器的输出将包含对SIMD仿真库的官方SIMD内部机构的呼叫。

使用SIMD仿真库的一个选项将是修改备伪工具以识别对SIMD内部内部的调用,而是将它们视为对仿真功能的调用。

但是,我们的项目目标之一就是能够尽可能多的不同操作工具,而且我们不想修改多重ools.so,相反,我们将我们写信的后处理器RVT-Patch-LLVM扩展initializers和命令行ArgumentSto将所有呼叫替换为SIMD内部内部的呼叫与我们的Simdemulation库进行调用。 (修补程序的代码在这里。)

虽然它最初似乎是有效的,但我们意识到我们对消除传染媒介内在的方法不起作用。这使我们迫使我们“咬子弹”并写出部分SIMD仿真库。这令人伤心比我们担心更容易,因为SIMD指令集是arehuge,它们包含大量规律性。

我们的仿真图书馆符合我们的需求,但我们认为它也会对开发其他生锈验证工具的团队肆无忌惮。我们将与其他生锈验证团队合作,以创建一个符合每个人需求的单一辛格测量库。