gcc on raspberry half precision floating point (binary16, alternative, __fp16) 使用库函数

gcc on raspberry half precision floating point (binary16, alternative, __fp16) uses library function

我在 raspberry pi 3 上使用了一些基于机器学习的算法,具有大量存储系数,不需要完整的 float32 精度。

我尝试使用半精度浮点来存储此数据以减少程序内存(可能还有内存带宽)占用空间。

算法的其余部分保持不变。

比较 float32 和 float16 版本我在使用 __fp16 时得到了(重要的:我的测试程序运行时间增加了 33%)性能损失,尽管 cpu 应该支持转换.

我查看了 asembler 输出并创建了一个简单的函数,它只读取一个 __fp16 值和 returns 一个它作为 float 似乎一些库函数call 用于转换。 (调用了与实际代码相同的函数)

rapspberry 的 cpu 应该有半精度硬件支持,所以我希望看到一些指令加载数据并且不会看到任何性能影响(或看到由于减少内存带宽要求而有所改进)

我正在使用以下编译器标志:

-O3 -mfp16-format=alternative -mfpu=neon-fp16 -mtune=cortex-a53 -mfpu=neon

这里是小测试函数的一小段代码和汇编程序输出:

const float test(const Coeff *i_data, int i ){
  return (float)(i_data[i]);
}

float 用于 Coeff:

    .align  2
    .global test
    .syntax unified
    .arm
    .fpu neon
    .type   test, %function
test:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    add r1, r0, r1, lsl #2  @ tmp118, i_data, i,
    vldr.32 s0, [r1]    @, *_5
    bx  lr  @

__fp16 用于 Coeff (-mfp16-format=alternative):

    .align  2
    .global test
    .syntax unified
    .arm
    .fpu neon
    .type   test, %function
test:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    lsl r1, r1, #1  @ tmp118, i,
    push    {r4, lr}    @
    ldrh    r0, [r0, r1]    @ __fp16    @, *_5
    bl  __gnu_h2f_alternative   @
    vmov    s0, r0  @,
    pop {r4, pc}    @

Coeff 使用 __fp16 (-mfp16-format=ieee):

    .align  2
    .global test
    .syntax unified
    .arm
    .fpu neon
    .type   test, %function
test:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    lsl r1, r1, #1  @ tmp118, i,
    push    {r4, lr}    @
    ldrh    r0, [r0, r1]    @ __fp16    @, *_5
    bl  __gnu_h2f_ieee  @
    vmov    s0, r0  @,
    pop {r4, pc}    @

我是不是漏掉了什么?

在 ARM 的网站上:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0774d/chr1421838476257.html

备注 __fp16 类型只是一种存储格式。出于算术和其他运算的目的,C 或 C++ 表达式中的 __fp16 值会自动提升为浮点数。

编译器标志 -mfpu=neon 覆盖了之前的 -mfpu=neon-fp16,因为 -mfpu= 只能指定一次。

设置两次是错误的(在Makefile的不同地方添加的)。

但由于 raspberry 3 的 vfpv4 始终支持 fp16,因此最佳规格是 -mfpu=neon-vfpv4

在这种情况下,编译器不会为转换生成任何库调用。

编辑:根据这个ghist -mfpu=neon-fp-armv8 -mneon-for-64bits 可用于 Raspberry 3。