为何vbroadcastsd指令中%xmm3寄存器未使用第四个double参数?
汇编SIMD函数中广播第四个double参数异常的问题
问题概述
我正在实现一个基于SIMD向量指令的汇编函数,函数签名为:
void map_poly_double_vec(double* input, double* output, uint64_t length, double a, double b, double c, double d);
执行vbroadcastsd %xmm3, %ymm6指令试图将第四个参数d广播到%ymm6的所有字段时,程序错误地将第一个参数a存入了%ymm6。其余vbroadcastsd指令均正常工作,仅最后一条出现问题,已通过GDB调试确认该指令确实使用了第一个double参数而非第四个。
汇编函数代码(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 }
问题原因与解决方案
原因
根据x86-64 System V调用约定,前8个浮点参数依次存储在%xmm0至%xmm7中,因此a对应%xmm0,d对应%xmm3。但第一条广播指令vbroadcastsd %xmm0, %ymm3会将整个%ymm3寄存器(包含低64位的%xmm3)覆盖为a的广播值,导致原本存储d的%xmm3被冲掉。后续执行vbroadcastsd %xmm3, %ymm6时,%xmm3已经是a的值,而非原始的d。
解决方案
调整广播指令的顺序,先处理d的广播,再覆盖%ymm3:
map_poly_double_vec: mov $0, %rcx vbroadcastsd %xmm3, %ymm6 #d 先处理d,避免%xmm3被覆盖 vbroadcastsd %xmm0, %ymm3 #a vbroadcastsd %xmm1, %ymm4 #b vbroadcastsd %xmm2, %ymm5 #c
这样d的原始值会先被广播到%ymm6,之后覆盖%ymm3就不会影响d的使用,执行后输出将符合预期。
内容的提问来源于stack exchange,提问作者Gyro
相关产品推荐
相关产品推荐

