vfmlalq_low_f16 和 vfmlalq_high_f16 未将其第一个操作数设置为结果

问题描述 投票:0回答:1

我正在尝试使用

vfmlalq_low_f16
vfmlalq_high_f16
内在函数(对应于 FMLAL 和 FMLAL2 指令),但我观察到的行为似乎没有意义。

需要一个

float32x4
和两个
float16x8
寄存器,从文档中他们应该从两个 fp16 寄存器中选择低 4 个值或高 4 个值,将它们隐藏到 fp32,按组件相乘并累加结果在 fp32 寄存器中。

因此,调用

vfmlalq_low_f16(r, a, b)
应该使用 fp32 为
r[i] += a[i] * b[i]
计算
0 < i < 4
;高版本应该做
r[i] += a[i + 4] * b[i + 4]

我的问题是,无论我在开始时放入三个寄存器中,结果向量中的值绝对没有变化。

根据我的理解,在我的 Macbook M1 上编译并运行以下代码应该可以工作:

int main(void) {
    float32x4_t l = vdupq_n_f32(1);
    float32x4_t h = vdupq_n_f32(1);
    float16x8_t a = vdupq_n_f16(2);
    float16x8_t b = vdupq_n_f16(3);

    dump_f32("l", l);
    dump_f32("h", h);
    dump_f16("a", a);
    dump_f16("b", b);

    vfmlalq_low_f16 (l, a, b);
    vfmlalq_high_f16(h, a, b);

    dump_f32("l", l);
    dump_f32("h", h);
}

运行时显示:

l = [ 1.000000 1.000000 1.000000 1.000000 ]
h = [ 1.000000 1.000000 1.000000 1.000000 ]
a = [ 2.000000 2.000000 2.000000 2.000000 2.000000 2.000000 2.000000 2.000000 ]
b = [ 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 ]
l = [ 1.000000 1.000000 1.000000 1.000000 ]
h = [ 1.000000 1.000000 1.000000 1.000000 ]

无论我对

a
b
输入尝试什么,l 和 h 中的值都不会改变。我是否错误地理解了说明?

arm intrinsics neon
1个回答
0
投票

内在函数返回一个结果,您需要将其分配给变量。
在 C 术语中,源操作数是按值,而不是像

&h
那样按引用。

  h = vfmlalq_high_f16(h, a, b);

与 asm 指令不同,

vfmlalq_high_f16
的第一个源操作数是只读的,因为如果您想不修改
mov
并将结果分配到其他地方,高级语言编译器可以为您发明
h
指令。

机器指令在机器代码中的寄存器编号空间有限,因此 3 输入指令通常重用第一个输入作为输出。 但这对于高级语言来说不是问题,因此您总是有一个返回值和按值而不是按引用获取的只读源操作数。 所以他们可以在 C 和 C++ 中工作,而无需编写

vfmlalq_high_f16( &h, a, b);

(某些 32 位模式 ARM NEON 洗牌会写入两个向量结果,例如

vzip
。ARM 通过让 内在 返回
int32x4x2_t
(一对向量)来处理该结果。因此,即使在那里,它们也会避免获取输入操作数参考。)


换句话说,你写了相当于

的东西
h + a*b;

而不是

h += a*b;
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.