第一代:x87浮点指令集

特征

  • 使用80位浮点协处理器处理浮点运算
  • 浮点协处理器内部为栈结构

    运算过程

指令

  • 这里只介绍部分指令,详细的参考Intel / AMD 开发手册
;入栈
fld st(i)               ;将st(i)的值压入栈顶
fld mem32/mem64/mem80   ;将浮点数压栈 交给st(0) 同时原st(0)交给st(1)

;加法
fadd st(0),st(i)        ;st(0)和st(i)作加法 结果放在st(0)
fadd st(i),st(0)        ;st(i)和st(0)作加法 结果放在st(0)

fadd mem32/mem64        ;st(0)与32或64位地址内存上的值相加,结果放在st(0)

faddp                   ;st(1)和st(0)相加,结果放在st(1),并弹出栈顶值
faddp st(i),st(0)       ;st(i)和st(0)相加,结果放在st(i),并弹出栈顶值

fiadd mem32/mem64       ;st(0)与16位或32位的整型值相加,结果放在st(0)

;出栈
fst st(i)               ;将st(0)值拷贝到st(i)
fst mem32/mem64         ;将st(0)值拷贝到指定内存地址处,不改变栈顶

fstp st(i)              ;将st(0)值拷贝到st(i),同时弹出栈顶
fstp mem32/mem64        ;将st(0)值拷贝到指定内存地址处,同时弹出栈顶
  • 代码示例
int main()
{
    double f1 = 1.0f;
    double f2 = 2.0f;
    float ret;

    __asm
    {
        fld f1;
        fld f2;
        faddp st(1), st(0);          //加完值放在栈顶
        fstp ret;                    //将栈顶值弹出到指定内存中
    }

    return 0;
}

zynq 浮点运算 单元 浮点运算指令_zynq 浮点运算 单元

第二代:多媒体指令集(MMX)

特征

1.使用64位浮点协处理器处理浮点运算
2.寄存器可以拆分后做同时运算,极大提升了运算效率

  • 可以拆分为8个单字节同时作运算
  • 可以拆分为2个float同时作运算

3.不再使用栈结构,对比x87性能得到极大提升(差不多在10倍左右)
4.寄存器在拆分做独立运算时有两种模式

  • 环绕模式: 255+1 = 0 (溢出)
  • 饱和模式: 255+1 = 255 (不溢出)

指令

  • 汇编语法,这里只介绍部分语法,详细的参考Intel / AMD 开发手册
int main()
{
    char ary1[] = { 255, 2, 3, 4, 5, 6, 7, 8 };
    char ary2[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    char ary3[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    __asm
    {
        movq  MM0, ary1         //相当于mov指令,64位(8字节)传送
        movq  MM1, ary2
        paddb MM0, MM1          //环绕模式加法,允许溢出
        paddusb MM0, MM1        //饱和模式加法,不允许溢出
        movq  ary3, MM0
    }
    
    return 0
  • 高级语法
#include <iostream>
#include <time.h>
#include <mmintrin.h>      //MMX指令集对应的头文件

void x87_add(char *ary, int size)
{
  for (int i = 0; i < size; i++)
    ary[i] += 1;
}

void mmx_add(char *ary, int size)
{
  __m64 sum;//64位联合体
  sum.m64_i64 = 0x0101010101010101L;

  __m64 *p = (__m64 *)ary;
  for (int i = 0; i < size; i++)
    _m_paddb(p[i], sum);                 //打包加法,相当于每次给 8个字节的char同时加 1
}


int main()
{
  //x87
  int size = 100000000;
  char* ary = (char*)malloc(sizeof(char) * size);
  for (int i = 0; i < size; i++)
    ary[i] = 1;

  time_t start = clock();
  x87_add(ary, size);
  printf("x87_add time:%d\n", clock() - start);

  start = clock();
  mmx_add(ary, size / 8);
  printf("mmx_add time:%d\n", clock() - start);

  free(ary);
  
  return 0;
  
}

第三代:多媒体指令集(SSE)

特征

1.采用128位位浮点协处理器处理浮点运算
2.寄存器可以拆分后做同时运算,极大提升了运算效率,广泛应用于3D游戏开发

  • 可以拆分为16个单字节同时作运算
  • 可以拆分为4个float同时作运算
  • SSE2.0以后支持拆分为2个double同时作运算

指令

  • 汇编语法(这里只介绍部分语法,详细的参考Intel / AMD 开发手册)
int main()
{
    char ary1[] = { 255, 2, 3, 4, 5, 6, 7, 8, 255, 2, 3, 4, 5, 6, 7, 8 };
    char ary2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
    char ary3[] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
    __asm
    {
        movdqu  xmm0, ary1                 //相当于mov指令,这里mov的是128位(16字节),movdqu(移动非对齐的双四字),movdqa(移动对齐的双四字)
        movdqu  xmm1, ary2
        paddq xmm0, xmm1                    //环绕模式加法,允许溢出
        //paddusb xmm0, xmm1                //饱和模式加法,不允许溢出
        movdqu  ary3, xmm0
    }

    return 0;
}
  • 高级语法
#include <iostream>
#include <time.h>
#include <xmmintrin.h> //SSE  float+float  int+int
#include <emmintrin.h> //SSE2
#include <intrin.h>    //all 


float x87_add(float *ary, int size)
{
  float sum = 0.0f;
  for (int i = 0; i < size; i++)
    sum += ary[i];

  return sum;
}


float sse_add(float *ary, int size)
{
  __m128 sum = { 0.0f, 0.0f, 0.0f, 0.0f };//128位联合体
  __m128 *p = (__m128*)ary;
  for (int i = 0; i < size; i++)
    sum = _mm_add_ps(sum, p[i]); //打包加法,相当于每次给4个浮点作运算

  return sum.m128_f32[0] + sum.m128_f32[1] + sum.m128_f32[2] + sum.m128_f32[3];
}


int main()
{
    //SSE: MOVSS ADDSS ADDSD  ADDPS  ADDPD

    int size = 200000000;
    float sum;
    float* ary = (float*)malloc(sizeof(float) * size);
    for (int i = 0; i < size; i++)
      ary[i] = 1.0f;

    time_t start = clock();
    sum = x87_add(ary, size);
    printf("x87_add sum:%f time:%d\n", sum, clock() - start);

    start = clock();
    sum = sse_add(ary, size / 4);
    printf("sse_add sum:%f time:%d\n", sum, clock() - start);
    

    free(ary);

    return 0;
}

第四代:AVS浮点指令集

特征

1.采用256位位浮点协处理器处理浮点运算
2.寄存器可以拆分后做同时运算,极大提升了运算效率,广泛应用于3D游戏开发

  • 可以拆分为32个单字节同时作运算
  • 可以拆分为8个float同时作运算
  • SSE2.0以后支持拆分为4个double同时作运算

3.对比SSE指令集,做8个float同时运算时效率提升2倍(但实际提升不大,因为3D游戏坐标最多只需3个float同时作运算即可)
指令

  • 汇编语法(这里只介绍部分语法,详细的参考Intel / AMD 开发手册) ,相对于SSE的语法,前缀加V即可
int main()
{
    char ary1[] = { 255, 2, 3, 4, 5, 6, 7, 8, 255, 2, 3, 4, 5, 6, 7, 8 };
    char ary2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
    char ary3[] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
    __asm
    {
        vmovdqu  xmm0, ary1                   //相当于mov指令,这里mov的是128字节
        //vmovdqu  ymm0, ary1                 //相当于mov指令,这里寄存器是ymm0,对应mov的是256字节
        vmovdqu  xmm1, ary2
        vpaddq xmm0, xmm1                    //环绕模式加法,允许溢出
        //vpaddusb xmm0, xmm1                //饱和模式加法,不允许溢出
        vmovdqu  ary3, xmm0
    }

    return 0;
}
  • 高级语法
#include <iostream>
#include <time.h>
#include <intrin.h>     //all 
#include <immintrin.h>  //avx

//版本迭代:SSE SSE1  SSE2  SSE3 SSE4 SSE4.1 SSE4.2 SSE5.0(AVX)  AVX2

float x87_add(float *ary, int size)
{
  float sum = 0.0f;
  for (int i = 0; i < size; i++)
    sum += ary[i];

  return sum;
}


float avx_add(float *ary, int size)
{
  __m256 sum = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
  __m256 *p = (__m256*)ary;
  for (int i = 0; i < size; i++)
    sum = _mm256_add_ps(sum, p[i]);             //一次可同时对8个float作加法 性能极大提升

  return sum.m256_f32[0];
}


int main()
{
  	//AVX: VMOVSS VADDSS .....

    int size = 200000000;
    float sum;
    float* ary = (float*)malloc(sizeof(float) * size);
    for (int i = 0; i < size; i++)
      ary[i] = 1.0f;

    time_t start = clock();
    sum = x87_add(ary, size);
    printf("x87_add sum:%f time:%d\n", sum, clock() - start);

    start = clock();
    sum = avx_add(ary, size / 8);
    printf("avx_add sum:%f time:%d\n", sum, clock() - start);

    free(ary);

    return 0;
}

vs中设置默认浮点指令集位置

zynq 浮点运算 单元 浮点运算指令_zynq 浮点运算 单元_02