定位您的应用程序 - 小端和大端 IBM XL Fortran 编译器的差异对您意味着什么(2)
- UID
- 1066743
|
定位您的应用程序 - 小端和大端 IBM XL Fortran 编译器的差异对您意味着什么(2)
矢量内部过程 vec_xl、vec_xst、vec_mergeh 和 vec_mergel 考虑了矢量元素顺序。换句话说,当在一个小端平台上用 -qaltivec=le 编译该程序时:- vec_xl 使用一个 Vector Scalar eXtension (VSX) 加载指令,该指令总是按大端元素顺序进行加载。然后,使用一个矢量排列指令来反转寄存器中的矢量,改用小端元素顺序。
- vec_xst 假定在寄存器中的矢量使用小端矢量元素顺序,所以它使用一个矢量排列指令,将矢量元素反转为大端矢量元素顺序。然后,它使用一个 VSX 存储指令将矢量存储回内存中,该指令总是按大端元素顺序进行存储。
- vec_mergeh 知道矢量元素是从右侧开始的。矢量寄存器包含 v1 和 v2,如下所示:
1
2
| v1 4.0 3.0 2.0 1.0
v2 -4.0 -3.0 -2.0 -1.0
|
因为 vec_mergeh 是从右侧开始算起的,它正确地使用 1.0 和 2.0 作为 vec_mergeh(v1, v2) 的结果的元素 0 和 2。
- vec_mergel 也同样知道矢量元素是从右侧开始的。因此,它正确地使用 -1.0 和 -2.0 作为 vec_mergel(v1, v2) 的结果的元素 1 和 3。
在大端平台或在小端平台上用 -qaltivec=be 编译该程序时:
- vec_xl 使用了一个 VSX 加载指令,该指令总是按大端元素顺序进行加载。不需要矢量排列。
- vec_xst 假定在寄存器中的矢量使用的是大端矢量元素顺序。因此,它直接使用一个 VSX 存储指令将矢量存储回内存中,该指令总是按大端元素顺序进行存储。
- vec_mergeh 知道矢量元素是从左侧开始的。矢量寄存器包含 v1 和 v2,如下所示:
1
2
| v1 1.0 2.0 3.0 4.0
v2 -1.0 -2.0 -3.0 -4.0
|
因为 vec_mergeh 是从左侧开始算起的,它正确地使用 1.0 和 2.0 作为 vec_mergeh(v1, v2) 的结果的元素 0 和 2。
vec_mergel 也同样知道矢量元素是从左侧开始的。因此,它正确地使用 -1.0 和 -2.0 作为 vec_mergel(v1, v2) 的结果的元素 1 和 3。
对于不使用 EQUIVALENCE 的程序,可以使用 –qaltivec=be 选项将代码从大端移植到小端。
POWER8 加密内部过程要求其输入矢量采用大端矢量元素顺序。实现这一要求有两种方法,使用 -qaltivec=be,或使用 vec_xl_be 和 vec_xst_be 内部过程来加载和存储。这些矢量加载和存储函数将在下一部分中介绍。
新的矢量加载和存储内部过程添加了新的矢量加载和存储内部过程,它们使用了 VSX 指令。您可以在 XL Fortran 编译器参考(XL Fortran for Linux 文档库)中找到这些内部过程。
VEC_XL(ARG1,ARG2)
这个函数从由位移 ARG1 和 ARG2 的地址指定的内存地址加载一个 16 字节的矢量,使用与平台相应的元素顺序和 -qaltivec 选项。
ARG1 是一个 INTENT(IN) 整数。
ARG2 是以下任意类型的 INTENT(IN):
- REAL(4) 或 REAL(8)
- INTEGER(1)、INTEGER(2)、INTEGER(4) 或 INTEGER(8)
- VECTOR
VEC_XL_BE(ARG1,ARG2)
这个函数从由位移 ARG1 和 ARG2 的地址指定的内存地址加载一个 16 字节的矢量,无论在什么平台上,都使用大端顺序或 -qaltivec 选项。
ARG1 是一个 INTENT(IN) 整数。
ARG2 是以下任意类型的 INTENT(IN):
- REAL(4) 或 REAL(8)
- INTEGER(1)、INTEGER(2)、INTEGER(4) 或 INTEGER(8)
- VECTOR
VEC_XST(ARG1,ARG2,ARG3)
此函数将由 ARG1 指定的 16 字节矢量的元素存储到一个给定的内存地址中。该地址的计算方法是,将 ARG2 指定的位移添加到由 ARG3 指定的内存地址,使用与平台相应的元素顺序和 -qaltivec 选项。
ARG1 是一个 INTENT(IN) 矢量。
ARG2 是一个 INTENT(IN) 整数。
ARG3 是 INTENT(OUT),并且必须是矢量或如下的整数或实数类型:
- 如果 ARG3 是一个矢量,那么它必须与 ARG1 的类型相同。
- 如果 ARG3 不是一个矢量,而且 ARG1 是一个整数矢量或一个无符号矢量,那么 ARG3 必须是 INTEGER 类型,而且与 ARG1 的元素具有同一种类型的参数。
- 如果 ARG3 不是一个矢量,而且 ARG1 是一个实数矢量,那么 ARG3 必须与 ARG1 的元素具有相同的类型和种类。
- 如果 ARG3 不是一个矢量,而且 ARG1 是一个像素矢量,那么 ARG3 的类型必须是 INTEGER(2)。
VEC_XST_BE(ARG1,ARG2,ARG3)
此函数将由 ARG1 指定的 16 字节矢量的元素存储到一个给定的内存地址中。该地址的计算方法是,将 ARG2 指定的位移添加到由 ARG3 指定的内存地址,无论在什么平台上,都使用大端顺序或 -qaltivec 选项。
ARG1 是一个 INTENT(IN) 矢量。
ARG2 是一个 INTENT(IN) 整数。
ARG3 是 INTENT(OUT),而且必须是矢量或如下的整数或实数类型:
- 如果 ARG3 是一个矢量,那么它必须与 ARG1 的类型相同。
- 如果 ARG3 不是一个矢量,而且 ARG1 是一个整数矢量或一个无符号矢量,那么 ARG3 必须是 INTEGER 类型,并且与 ARG1 的元素具有同一种类型的参数。
- 如果 ARG3 不是一个矢量,而且 ARG1 是一个实数矢量,那么 ARG3 必须与 ARG1 的元素具有相同的类型和种类。
- 如果 ARG3 不是一个矢量,而且 ARG1 是一个像素矢量,那么 ARG3 的类型必须是 INTEGER(2)。
应用程序二进制接口 (ABI)面向小端 Linux on Power Systems 的 XL Fortran 使用了新的 IBM Power Architecture® 64 位 ELF V2 ABI 规范。这种新的 ABI 完善了某些方面,其中包括函数调用。不过,这意味着,针对旧 ABI 的程序集文件必须移植到新的 ABI。遵循各自的语言标准的 Fortran、C 和 C ++ 程序不需要移植到新的 ABI。包含非标准扩展的程序需要进行 ABI 敏感性审查。在 Fortran 中的一个例子是,程序调用带有变量参数列表的 C 函数。
从 Fortran 调用带有变量参数列表的 C 函数C 语言允许函数带有变量参数列表。使用省略号(...)指示。例如,printf 有下面的 C 原型:
1
| int printf(const char *restrict format, ...);
|
ELF V2 ABI 要求对带有变量参数列表的函数的调用者在堆栈上建立参数保存区域。因此,对带有变量参数列表的函数的调用必须有准确的原型。
然而,Fortran 标准将带有变量参数列表的 C 函数视为不可互操作的,在 Fortran 中没有为它们提供编写接口的方式。某些程序添加了一个显式接口(其中包含它们计划使用的最大数量的参数),试图解决这个问题。例如:
1
2
3
4
5
6
7
8
9
| interface
function printf1int(format, a) bind(c, name='printf')
use, intrinsic :: iso_c_binding, only: c_int
implicit none
integer(c_int) printf1int
character, intent(in) :: format(*)
integer(c_int), value :: a
end function
end interface
|
使用上述接口调用 printf1int 可能会由于缺少参数保存区而导致新 ABI 的堆栈损坏。要让 XL Fortran 知道变量参数列表,可以将 procedure_attribute(varargs) 指令添加到接口。
1
2
3
4
5
6
7
8
9
10
| interface
function printf1int(format, a) bind(c, name='printf')
use, intrinsic :: iso_c_binding, only: c_int
implicit none
integer(c_int) printf1int
character, intent(in) :: format(*)
integer(c_int), value :: a
!ibm* procedure_attribute(varargs)
end function
end interface
|
|
|
|
|
|
|