我正在尝试在汇编中实现一个函数,该函数使用 SIMD 向量指令和寄存器进行一些基本计算。函数签名是
void map_poly_double_vec(double* input, double* output, uint64_t length, double a, double b, double c, double d);
出于某种原因,当我使用
vbroadcastsd %xmm3, %ymm6
将 double d
参数放入 %ymm6
的所有字段中时,程序会将 double a
参数插入其中。除了最后一个之外,其他 vbroadcastsd
指令都可以正常工作。我已经使用 GDB 尝试找出原因,但指令只是运行并使用第一个双参数而不是第四个。
这是我的汇编函数(AT&T 语法):
map_poly_double_vec:
mov $0, %rcx
vbroadcastsd %xmm0, %ymm3 #a
vbroadcastsd %xmm1, %ymm4 #b
vbroadcastsd %xmm2, %ymm5 #c
vbroadcastsd %xmm3, %ymm6 #d
mpdv_loop:
cmp %rdx, %rcx
je mpdv_end
vmovupd (%rdi, %rcx, 8), %ymm0
vmovupd %ymm0, %ymm1
vfmadd132pd %ymm3, %ymm4, %ymm1
vfmadd132pd %ymm0, %ymm5, %ymm1
vfmadd132pd %ymm1, %ymm6, %ymm0
vmovupd %ymm0, (%rsi, %rcx, 8)
add $4, %rcx
jmp mpdv_loop
mpdv_end:
ret
这就是我用来测试功能的。
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "lab11.h"
double* create_array(uint64_t length) {
double* array = (double*)malloc(length * sizeof(double));
if (array == NULL) {
return NULL;
}
for (uint64_t i = 0; i < length; i++) {
array[i] = ((double)rand() / RAND_MAX - 0.25);
}
return array;
}
void print_double_array(double* array, uint64_t length) {
printf("{ ");
for (uint64_t i = 0; i < length; i++) {
printf("%.6g ", array[i]);
}
printf("}\n");
}
int main(void) {
uint64_t length = 16;
double* doubles1 = create_array(length);
double* double_out = (double*)malloc(length * sizeof(double));
printf("map_poly_double_vec result:\n");
memset(double_out, 0, length * sizeof(double));
map_poly_double_vec(doubles1, double_out, length, 4, 5, 6, 7);
print_double_array(double_out, length);
free(doubles1);
free(double_out);
return 0;
}
我应该得到什么:
{ 13.105 7.98257 12.2256 12.4544 14.3174 6.69849 7.55013 12.0089 7.17059 9.39815 8.66996 10.2085 7.76063 9.0004 15.0642 14.3989 }
我的功能得到了什么:
map_poly_double_vec result:
{ 10.105 4.98257 9.22559 9.45443 11.3174 3.69849 4.55013 9.00889 4.17059 6.39815 5.66996 7.20848 4.76063 6.0004 12.0642 11.3989 }
请看第一期广播:
vbroadcastsd %xmm0, %ymm3 #a <----
vbroadcastsd %xmm1, %ymm4 #b
vbroadcastsd %xmm2, %ymm5 #c
vbroadcastsd %xmm3, %ymm6 #d
现在,曾经保存参数
ymm3
的d
已被参数a
覆盖(已广播)。
所以
vbroadcastsd %xmm3, %ymm6
再次拿起论点a
。
如果这是混乱的根源:
xmm
寄存器扩展到AVX中的ymm
寄存器,ymm
寄存器不是一组独立的新寄存器。每个256位ymm
寄存器可以看作是两个128位的块,底部128位是对应的xmm
寄存器,例如xmm3
是ymm3
的底部128位。