You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:04:51