SSE2指令集

SSE2指令集常用函数

// 数据加载
// 对齐加载
__m128i _mm_load_si128(const __m128i *mem_addr);    // 从对齐地址加载
__m128d _mm_load_pd(const double *mem_addr);        // 加载双精度浮点数
// 非对齐加载
__m128i _mm_loadu_si128(const __m128i *mem_addr);   // 从任意地址加载
__m128d _mm_loadu_pd(const double *mem_addr);       // 非对齐加载双精度

// 数据存储
// 对齐存储
void _mm_store_si128(__m128i *mem_addr, __m128i a);  // 存储到对齐地址
void _mm_store_pd(double *mem_addr, __m128d a);      // 存储双精度
// 非对齐存储
void _mm_storeu_si128(__m128i *mem_addr, __m128i a); // 存储到任意地址
void _mm_storeu_pd(double *mem_addr, __m128d a);     // 非对齐存储双精度

// 算术运算
// 加法
__m128i _mm_add_epi8(__m128i a, __m128i b);   // 8位整数加法
__m128i _mm_add_epi16(__m128i a, __m128i b);  // 16位整数加法
__m128i _mm_add_epi32(__m128i a, __m128i b);  // 32位整数加法
__m128i _mm_add_epi64(__m128i a, __m128i b);  // 64位整数加法
// 减法
__m128i _mm_sub_epi8(__m128i a, __m128i b);   // 8位整数减法
__m128i _mm_sub_epi16(__m128i a, __m128i b);  // 16位整数减法
__m128i _mm_sub_epi32(__m128i a, __m128i b);  // 32位整数减法
__m128i _mm_sub_epi64(__m128i a, __m128i b);  // 64位整数减法
// 浮点数
__m128d _mm_add_pd(__m128d a, __m128d b);     // 双精度加法
__m128d _mm_sub_pd(__m128d a, __m128d b);     // 双精度减法
__m128d _mm_mul_pd(__m128d a, __m128d b);     // 双精度乘法
__m128d _mm_div_pd(__m128d a, __m128d b);     // 双精度除法

// 逻辑运算
__m128i _mm_and_si128(__m128i a, __m128i b);   // 位与
__m128i _mm_or_si128(__m128i a, __m128i b);    // 位或
__m128i _mm_xor_si128(__m128i a, __m128i b);   // 位异或
__m128i _mm_andnot_si128(__m128i a, __m128i b); // 位与非

// 比较运算
// 整数
__m128i _mm_cmpeq_epi8(__m128i a, __m128i b);   // 8位相等比较
__m128i _mm_cmpeq_epi16(__m128i a, __m128i b);  // 16位相等比较
__m128i _mm_cmpeq_epi32(__m128i a, __m128i b);  // 32位相等比较
__m128i _mm_cmpgt_epi8(__m128i a, __m128i b);   // 8位大于比较
__m128i _mm_cmpgt_epi16(__m128i a, __m128i b);  // 16位大于比较
__m128i _mm_cmpgt_epi32(__m128i a, __m128i b);  // 32位大于比较
// 浮点数
__m128d _mm_cmpeq_pd(__m128d a, __m128d b);     // 双精度相等比较
__m128d _mm_cmpgt_pd(__m128d a, __m128d b);     // 双精度大于比较
__m128d _mm_cmplt_pd(__m128d a, __m128d b);     // 双精度小于比较

// 移位运算
// 逻辑位移
__m128i _mm_slli_epi16(__m128i a, int imm8);   // 16位左移
__m128i _mm_slli_epi32(__m128i a, int imm8);   // 32位左移
__m128i _mm_slli_epi64(__m128i a, int imm8);   // 64位左移
__m128i _mm_srli_epi16(__m128i a, int imm8);   // 16位右移
__m128i _mm_srli_epi32(__m128i a, int imm8);   // 32位右移
__m128i _mm_srli_epi64(__m128i a, int imm8);   // 64位右移
__m128i _mm_slli_si128(__m128i a, int imm8);   // 对 128 位数据进行字节级别的逻辑左移
// 算术位移
__m128i _mm_srai_epi16(__m128i a, int imm8);   // 16位算术右移
__m128i _mm_srai_epi32(__m128i a, int imm8);   // 32位算术右移

// 数据重排
// 洗牌
__m128i _mm_shuffle_epi32(__m128i a, int imm8); // 32位元素重排
__m128d _mm_shuffle_pd(__m128d a, __m128d b, int imm8); // 双精度重排
// 解包
__m128i _mm_unpackhi_epi8(__m128i a, __m128i b);  // 高位解包8位
__m128i _mm_unpacklo_epi8(__m128i a, __m128i b);  // 低位解包8位
__m128i _mm_unpackhi_epi16(__m128i a, __m128i b); // 高位解包16位
__m128i _mm_unpacklo_epi16(__m128i a, __m128i b); // 低位解包16位

// 设置常量
__m128i _mm_setzero_si128(void);                    // 设置全零
__m128i _mm_set1_epi8(char a);                      // 设置所有8位元素
__m128i _mm_set1_epi16(short a);                    // 设置所有16位元素
__m128i _mm_set1_epi32(int a);                      // 设置所有32位元素
__m128i _mm_set_epi8(char e15, ..., char e0);       // 设置16个8位元素
__m128i _mm_set_epi32(int e3, int e2, int e1, int e0); // 设置4个32位元素

1. 简单案例

#include <emmintrin.h>  // SSE2 指令集头文件

void example() {
    // 1. 初始化源数据数组
    int data[4] = {1, 2, 3, 4};

    // 2. 从内存加载数据到 SSE 寄存器
    // _mm_loadu_si128 从非对齐内存地址加载 128 位数据
    __m128i vec = _mm_loadu_si128((__m128i*)data);

    // 3. 执行 SSE 操作
    // _mm_set1_epi32(10) 创建包含4个10的128位向量:{10, 10, 10, 10}
    // _mm_add_epi32 执行4个32位整数的并行加法
    vec = _mm_add_epi32(vec, _mm_set1_epi32(10));

    // 4. 将结果存储回内存
    int result[4];
    _mm_storeu_si128((__m128i*)result, vec);

    // 5. 结果:result 现在包含 {11, 12, 13, 14}
}

2. 完整案例

#include <emmintrin.h>
#include <stdio.h>
#include <stdalign.h>  // 用于内存对齐
#include <stdbool.h>

// 打印 __m128i 变量的内容(32位整数)
void print_m128i_epi32(__m128i value, const char* name) {
    alignas(16) int result[4];
    _mm_store_si128((__m128i*)result, value);
    printf("%s: {%d, %d, %d, %d}\n", name, result[0], result[1], result[2], result[3]);
}

// 基本示例:向量加法
void basic_example() {
    printf("=== 基本示例:向量加法 ===\n");

    // 源数据
    int data[4] = {1, 2, 3, 4};
    printf("原始数据: {%d, %d, %d, %d}\n", data[0], data[1], data[2], data[3]);

    // 加载到 SSE 寄存器
    __m128i vec = _mm_loadu_si128((__m128i*)data);
    print_m128i_epi32(vec, "加载后的向量");

    // 创建常量向量 {10, 10, 10, 10}
    __m128i constant = _mm_set1_epi32(10);
    print_m128i_epi32(constant, "常量向量");

    // 执行向量加法
    __m128i result_vec = _mm_add_epi32(vec, constant);
    print_m128i_epi32(result_vec, "加法结果");

    // 存储回内存
    int result[4];
    _mm_storeu_si128((__m128i*)result, result_vec);
    printf("最终结果: {%d, %d, %d, %d}\n", result[0], result[1], result[2], result[3]);
}

// 进阶示例:多种 SSE2 操作
void advanced_example() {
    printf("\n=== 进阶示例:多种 SSE2 操作 ===\n");

    int a[4] = {10, 20, 30, 40};
    int b[4] = {5, 6, 7, 8};

    __m128i vec_a = _mm_loadu_si128((__m128i*)a);
    __m128i vec_b = _mm_loadu_si128((__m128i*)b);

    printf("向量 A: {%d, %d, %d, %d}\n", a[0], a[1], a[2], a[3]);
    printf("向量 B: {%d, %d, %d, %d}\n", b[0], b[1], b[2], b[3]);

    // 加法
    __m128i add_result = _mm_add_epi32(vec_a, vec_b);
    print_m128i_epi32(add_result, "A + B");

    // 减法
    __m128i sub_result = _mm_sub_epi32(vec_a, vec_b);
    print_m128i_epi32(sub_result, "A - B");

    // 乘法(注意:没有直接的32位整数乘法,这里使用16位演示)
    __m128i mul_result = _mm_mullo_epi16(
        _mm_set_epi16(10, 20, 30, 40, 50, 60, 70, 80),
        _mm_set_epi16(2, 3, 4, 5, 6, 7, 8, 9)
    );

    // 位运算
    __m128i and_result = _mm_and_si128(vec_a, vec_b);
    print_m128i_epi32(and_result, "A & B (位与)");

    __m128i or_result = _mm_or_si128(vec_a, vec_b);
    print_m128i_epi32(or_result, "A | B (位或)");
}

// 性能对比示例:标量 vs 向量运算
void performance_example() {
    printf("\n=== 性能对比示例(修正版) ===\n");

    const int SIZE = 10000;  // 减小数据量用于演示
    const int VECTOR_SIZE = SIZE + 3; // 确保是4的倍数

    // 使用动态内存分配并手动对齐
    int* array1 = (int*)aligned_alloc(16, VECTOR_SIZE * sizeof(int));
    int* array2 = (int*)aligned_alloc(16, VECTOR_SIZE * sizeof(int));
    int* result_scalar = (int*)aligned_alloc(16, VECTOR_SIZE * sizeof(int));
    int* result_vector = (int*)aligned_alloc(16, VECTOR_SIZE * sizeof(int));

    if (!array1 || !array2 || !result_scalar || !result_vector) {
        printf("内存分配失败!\n");
        free(array1);
        free(array2);
        free(result_scalar);
        free(result_vector);
        return;
    }

    // 初始化数据
    for (int i = 0; i < VECTOR_SIZE; i++) {
        array1[i] = i;
        array2[i] = i * 2;
        result_scalar[i] = 0;
        result_vector[i] = 0;
    }

    printf("数据初始化完成,开始计算...\n");

    // 标量版本(传统循环)
    for (int i = 0; i < SIZE; i++) {
        result_scalar[i] = array1[i] + array2[i];
    }

    // 向量版本(SSE2)- 使用对齐加载
    for (int i = 0; i < SIZE; i += 4) {
        __m128i vec1 = _mm_load_si128((__m128i*)(array1 + i));
        __m128i vec2 = _mm_load_si128((__m128i*)(array2 + i));
        __m128i vec_result = _mm_add_epi32(vec1, vec2);
        _mm_store_si128((__m128i*)(result_vector + i), vec_result);
    }

    // 验证结果
    bool correct = true;
    for (int i = 0; i < SIZE; i++) {
        if (result_scalar[i] != result_vector[i]) {
            printf("结果不匹配在索引 %d: 标量=%d, 向量=%d\n", 
                   i, result_scalar[i], result_vector[i]);
            correct = false;
            break;
        }
    }

    printf("向量化结果验证: %s\n", correct ? "正确" : "错误");

    // 显示前几个结果
    printf("前8个结果:\n");
    printf("索引\t标量\t向量\n");
    for (int i = 0; i < 8; i++) {
        printf("%d\t%d\t%d\n", i, result_scalar[i], result_vector[i]);
    }

    // 释放内存
    free(array1);
    free(array2);
    free(result_scalar);
    free(result_vector);
}

// 内存对齐示例
void alignment_example() {
    printf("\n=== 内存对齐示例 ===\n");

    // 对齐的内存(16字节对齐)
    alignas(16) int aligned_data[4] = {100, 200, 300, 400};

    // 非对齐的内存
    int unaligned_data[5] = {1, 2, 3, 4, 5};
    int* unaligned_ptr = &unaligned_data[1];  // 故意不对齐,指向的是1号元素

    // 对齐加载/存储(更快)
    __m128i aligned_vec = _mm_load_si128((__m128i*)aligned_data);

    // 非对齐加载/存储(更灵活)
    __m128i unaligned_vec = _mm_loadu_si128((__m128i*)unaligned_ptr);

    print_m128i_epi32(aligned_vec, "对齐数据");
    print_m128i_epi32(unaligned_vec, "非对齐数据");
}

int main() {
    printf("SSE2 指令集示例程序\n");
    printf("==================\n");

    basic_example();
    advanced_example();
    performance_example();
    alignment_example();

    return 0;
}
© phdlisl all right reserved,powered by GitbookUpdate in 2025-10-12

results matching ""

    No results matching ""