文档库 最新最全的文档下载
当前位置:文档库 › SSE自动向量化用户手册

SSE自动向量化用户手册

SSE自动向量化用户手册
SSE自动向量化用户手册

使用并行化:向量化

向量化概述

向量优化单元(vectorizer)是Intel编译器中用来生成SIMD指令的,它会用到MMX?, Intel? Streaming SIMD 扩展 (Intel? SSE, SSE2, SSE3 and SSE4) 和附加Streaming SIMD 扩展 (SSSE3)等指令集. 向量优化单元检测到程序中可以被并行的操作后,就根据数据类型,转化成一系列的操作,例如一条可以同时并行处理2、4、8,最多16个元素的SIMD指令。

自动向量化支持IA-32和Intel? 64 架构。

本章将讨论如下内容:

?较高层面地讨论用来控制和影响向量化的编译器选项

?C++语言中控制向量化的功能说明

?向量化程度的讨论和一般原则:

?自动向量化

?用户介入的向量化(也称作自动向量化提示)

?演示典型的向量化问题,和对应解决方法的范例程序

Intel编译器支持许多种类的自动向量化提示和用户指定的编译指示(pragma/directive),它们可以帮助编译器有效地生成向量指令。

参考“The Software Vectorization Handbook. Applying Multimedia Extensions for Maximum Performance, A.J.C. Bik. Intel Press, June, 2004”, 可以得到如何使用Intel?编译器向量化代码的详细讨论。

向量化选项快速索引

如下选项支持IA-32和Intel? 64架构 .

Linux* OS and Mac OS* X Windows*

OS 说明

-x /Qx 生成特定的二进制代码,只能运行在被扩展名指定的处理器上.

查看Targeting IA-32 and Intel? 64 Architecture

Processors Automatically获得更多关于使用此选项的信

息。

-ax /Qax 同时生成能够运行在被扩展名指定的处理器,和通用的IA-32

架构上的二进制代码。通用的二进制代码运行速度一般较慢.

查看Targeting Multiple IA-32 and Intel? 64

Architecture Processors for Run-time Performance获得

更多关于使用此选项的信息。

Linux* OS and Mac OS* X Windows*

OS 说明

-vec /Qvec 开启或者关闭向量化和对应的转换。缺省向量化是开启的。只

支持IA-32 and Intel? 64 架构.

-vec-report /Qvec-

report

控制向量化子输出的调试消息。参考Vectorization Report.

-simd /Qsimd 允许用户指定的向量化

Intel编译器提供的向量化依赖于编译器的能力来消除内存引用二义性。这些选项或许能帮助编译器更好地实现向量化

语言支持和编译指示

本节讨论特定的C++和Fortran语言功能,可以更好地帮助向量化代码.

__declspec(align(n))声明能够使得你克服硬件对齐的限制. restrict修饰词和自动向量化提示解决了由于作用范围、数据依赖和二义性等产生的问题。SIMD编译指示使得最内层的循环能够被向量化。

功能说明

__declspec(align(n))指导编译器将变量按照n字节对齐。变量的地址是

address mod n=0.

__declspec(align(n,off))指导编译器将变量按照n字节再加上off字节的偏移量进

行对齐。变量的地址是address mod n=off.

restrict 允许消除别名假定中存在的二义性,从而能够更大程度地

向量化.

__assume_aligned(a,n)当编译器无法获得对齐信息时, 则假定数组a已按照n字

节对齐

自动向量化提示

#pragma ivdep告诉编译器忽略可能存在的向量依赖关系

#pragma vector

{aligned|unaligned|always}

指定循环向量化的方式

#pragma novector 指定循环不被向量化

用户指定的编译指示

#pragma simd

!DIR$ SIMD

强制向量化最内层循环

用户指定的向量化

用户指定的向量化是自动向量化的补充,类似于OpenMP并行化是自动并行化的补充。下图描述了这种相互关系。用户指定的向量化是通过一个叫做SIMD的功能来实现的,也被称作SIMD向量化

存在着多种不同的方式生成向量代码来挖掘向量硬件的能力。下图展示了SIMD向量化在这些方式中所处的位置。直观上看,用SIMD向量化编写的程序非常接近于使用自动向量化提示。使用SIMD向量化,你只需要最小程度地改动代码。

SIMD向量化使用#pragma simd/!DIR$ SIMD编译指示来有效地实现循环向量化。你必须添加这类编译指示到循环处,使用新的选项–Qsimd [在Windows*操作系统] 或者–simd [在Linux*操作系统] 重新编译,然后循环就会被向量化了。

这里是一个C++的范例,其中函数add_floats()使用了太多未知的指针,对于编译器自动运行时引入的独立性检测优化来说。你可以通过使用#pragma ivdep自动向量化提示来给出一个数据依赖性的声明,然后让编译器决定是否使用自动向量化。现在你也可以使用#pragma simd 强制向量化这个循环,并且避免了运行时检测的额外开销。

[D:/simd] cat example1.c

void add_floats(float *a, float *b, float *c, float *d, float *e, int n){

int i;

for (i=0; i

a[i] = a[i] + b[i] + c[i] + d[i] + e[i];

}

}

[D:/simd] icl example1.c –nologo -Qvec-report2

example1.c

D:\simd\example1.c(3): (col. 3) remark: loop was not vectorized: existence of vector dependence.

[D:/simd] cat example1.c

void add_floats(float *a, float *b, float *c, float *d, float *e, int n){

int i;

#pragma simd

for (i=0; i

a[i] = a[i] + b[i] + c[i] + d[i] + e[i];

}

}

[D:/simd] icl example1.c -nologo -Qvec-report2 -Qsimd

example1.c

D:\simd\example1.c(4): (col. 3) remark: LOOP WAS VECTORIZED.

这里是一个Fortran程序的范例,因为存在未知的数据依赖“X”,编译器无法自动向量化循环。你可以使用自动向量化提示!DIR$ IVDEP,来使得编译器决定是否向量化该循环,或者你可以使用!DIR$ SIMD来强制向量化。

[D:/simd] cat example1.f

subroutine add(A, N, X)

integer N, X

real A(N)

DO I=X+1, N

A(I) = A(I) + A(I-X)

ENDDO

end

[D:/simd] ifort example1.f -nologo -Qvec-report2

D:\simd\example1.f(6): (col. 9) remark: loop was not vectorized: existence of vector dependence.

[D:/simd] cat example1.f

subroutine add(A, N, X)

integer N, X

real A(N)

!DIR$ SIMD

DO I=X+1, N

A(I) = A(I) + A(I-X)

ENDDO

end

[D:/simd] ifort example1.f -nologo -Qvec-report2 -Qsimd

D:\simd\example1.f(7): (col. 9) remark: LOOP WAS VECTORIZED.

使用SIMD编译指示和自动向量化提示的最大的区别是,一旦使用SIMD编译指示,当编译器无法向量化循环时会生成一个错误。而使用自动向量化提示,实际的向量化仍然由编译器决定,即使你使用了 #pragma vector always/!DIR$ VECTOR ALWAYS 提示.

使用SIMD编译指示的循环向量化

SIMD 编译指示有五个可供选择的子句来指导编译器执行何种向量化。恰当地使用这些子句,会让编译器获得足够的信息来产生正确的向量化代码。

?vectorlength(num1, num2, …, numN)

指导向量优化单元可以从指定的若干向量长度(VL)num1, num2, … , numN中选择来向量化循环。对于选定的VL,向量循环的每一次执行的计算工作相当于原来标量循环VL次执行的计算工作。多个向量长度子句会合并成一个集合。

?private(expr1, expr2, …, exprN)

指导向量优化单元使得这些左值(L-value)表达式expr1, exper2, ..., exprN对于每

一次循环都是私有的。多个private子句会合并成一个集合。左值表达式的初值将被广播到所有的私有子句,除非编译器能够判定初值未在循环体内使用;左值表达式的终值也会被从最后一次执行的循环体复制出来, 除非编译器能够判定终值未在循环后被使用?linear(var1:step1, var2:step2, …, varN:st epN)

指导编译器每一次标量循环的执行时,var1的值增加step1, var2 的值增加step2, 依此类推。相应地,每次向量循环的执行,使得这些变量的值分别增加VL*step1,

VL*step2, …, VL*stepN。多个linear子句会被合并成一个集合。如果var 被赋予两个或多个step值,会产生一个编译错误。

?reduction(oper:var1,var2,…,varN)

指导编译器对于变量var1, var2, …, varN执行向量化规约操作oper。一个SIMD编译指示可以有多个归约子句,执行相同或者不同的操作。如果一个变量var 与两个或多个不同的归约操作oper有关, 会产生一个编译错误。

?[no]assert

指导编译器当向量化失败时是否报错,缺省是不报错。一个SIMD编译指令不应该存在多个该子句,否则会产生一个编译错误。

额外的语义

?一个变量最多可以属于private, linear, 或 reduction子句中的某一个 (或者不属于任何一个).

?在向量循环中,如果一个表达式在SIMD的编译指示private, linear, reduction子句中被声明, 或者它的子表达式已经是一个向量值,那么它会被当作是一个向量进行计算。除

此之外,它会当作一个标量处理(广播相同的值给每一次的循环执行体)。标量值不一定是循环不变量,虽然大多数情况下的确如此。

?一个向量值不可以赋值给一个标量。否则会产生一个错误.

注意:一些自动向量化循环不一定存在能使用SIMD编译指示的方法来描述其向量语义,或者你可能很难用SIMD编译指示来描述这些自动向量化循环。一个例子是C语言中的MIN/MAX归约,因为C语言本身没有MIN/MAX操作符。

限制

?一个可以计算执行次数的循环使用SIMD编译指示,必须遵循for-loop (C/C++) 或者DO-loop (FORTRAN) 类型,适用于 OpenMP* worksharing 循环构造。参考

https://www.wendangku.net/doc/cc18681633.html,/mp-documents/spec30.pdf (Section 2.5.1)。额外地,循环控制变量必须是signed或者unsigned整型,或是一个指针类型。

?使用SIMD的循环必须去除C++ exception handling代码。

?使用SIMD向量化的循环中会采用快速浮点模式(FP model fast),否则向量优化单元不得不放弃向量化这个循环。

?向量的值必须是如下几种数据类型:signed/unsigned 8/16/32/64位整型, 单/双精度浮点,或者单/双精度的复数。

?一个使用SIMD向量化的循环不能包含另外一个内置循环。(换言之,用户强制的向量化只可以用于最内层循环).

注意:C++ inlining可能会创建这样一个内嵌循环,从而导致产生一个错误。通常这种情况在代码层面不易发现。

?使用SIMD向量化的循环会不加限制地进行内存访问。因此,所有计算地址必须具有有效的内存地址,即是这些地址在循环串行执行时可能不会被访问到。虽然看上去非常严格,这个要求和使用自动向量化提示!DIR$ IVDEP时是相同的。

相关文档