SIMD

CPU采用SIMD技术大大提高计算速度,特别是在矩阵运算上。Intel和AMD都在不同程度上实现了这样的技术,Intel拥有从最早的MMX,到SSE,SSE2;AMD是3D NOW!和3D NOW PRO,作为程序员学习下也挺好,说不定哪天优化代码的时候就用上了。

    SIMD全称是Single Instruction Multiple Data,就是单个指令能够处理多个数据包。我的理解是,在SIMD之前,寄存器在对数组中各元素做加减的时候,必须按次序取出,放入相应寄存器,然后再相加,举个例子:
    有两个数组 a[2] = {2,3}, b[2] = {3,4},然后
    MOV ESI , a                                                                    MOV ESI , a+1      
    MOV EDI , b                                                                    MOV EDI , b+1
    MOV EAX , [ESI]                                                              MOV EAX , [ESI]
    MOV EBX , [EDI]                                                              MOV EBX , [EDI]
    ADD EAX ,EBX ;完成了数组中a[0]和b[0]的相加运算                     ADD EBX , EAX; 完成数组中a[1]和b[1]的相加运算
    一共进行了两组运算,假如运用SIMD进行运算的话
    MOV ESI a
    MOV EDI b
    MOVAPS MMX0 [ESI]
    MOVAPS MMX1 [EDI] 
    PADDD MMX0 MMX1 ;一组指令就行了。
   
   MMX 允许一次向MMX寄存器中存储最大64bits的数据,比如一个vector,数据值必须是整数,而且占用的是FPU运算单元。
   3DNOW 比MMX好的一点是可以运用浮点数运算。
   SSE 从PentiumIII开始新加入了8个寄存器,可以存储最大到128bits的一组数据,能够迅速进行vector4运算
   3DNOW PRO基本等于SSE
   SSE2从名字上看比SSE更强大了,具体怎么个强大没去想,先放着了。
 
   怎样测试自己的CPU支持哪种SIMD功能呢?这需要用到CPUID这条指令。还是先定义一个数组准备接受测试的结果
   typedef struct CPUINFO_TYP {
       bool bSSE;
       bool bSSE2;
       bool b3DNOW;
       bool bMMX;
       char name[48];    //cpu name
       bool bEXT;         //扩展功能
       bool MMXEX;      //AMD的扩展
       bool 3DNOW;      //Intel的扩展
       char vendor[12];  //vendor name
    }CPUINFO;
 
   检测时候,只需要喂给EAX一个值,然后调用CPUID指令,相应结果就会返回。比如,我向EAX送去0,CPUID指令就会返回不超过12个字的制造商名称,分别向EBX,EDX,ECX返回4个字;如果向EAX送去1,CPUID会返回CPU功能的一个列表,并且,如果CPU属于Intel,则返回brandID到EBX,如果是AMD,则返回brandID到EAX。如果送入的值是Ox80,那么即将检查的是CPU有无扩展功能,送入0x80到EAX后,CPUID会返回一个值回到EAX,如果该值大于0x80,那就再送出0x80000001到EAX再执行CPUID,我们就可以得到这些扩展功能的描述。如果是IntelCPU,就没必要找扩展功能了,如果是AMD,可以注意下有没有extended MMX和enhanced 3D NOW.
   好!那么现在就写个函数来实现这些繁琐的不知道有没钱赚的功能吧!!!(TMD>_____< TMD)
   CPUINFO  GetCPUInfo() {
          CPUINFO info;
          char* pStr = info.vendor;
          int n=1;
          int* pn = &n;
         
          memset(&info, 0, sizeof(CPUINFO));
        
          //1:Vendor name, SSE2, SSE, MMX support
         _try{
               _asm{
                      mov eax, 0       //送入零取得vendor name
                      CPUID
                      mov esi,   pStr
                      mov [esi], ebx  //前四个字符
                      mov [esi+4], edx //再4个
                      mov [esi+8], ecx //最后4个
 
                      mov eax, 1       //功能表
                      CPUID
                    
                      test edx, 04000000h  //test SSE2
                      jz  _NOSSE2            
                      mov [info.bSSE2], 1  //true
 
       _NOSSE2: test edx, 02000000h  //test SSE
                      jz  _NOSSE
                      mov [info.bSSE], 1   //true 
      
       _NOSSE:  test edx, 00800000h  //test MMX
                     jz  _EXIT1
                     mov [info.bMMX], 1  //true
       _EXIT1:  //done
                 }
           }_except(EXCEPTION_EXECUTE_HANDLER) {
               if(_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
                      return info;
               retrun info;
           }
 
       //检测CPU的扩展功能
       _asm {
               mov eax, 80000000h        //有扩展功能吗?
               CPUID
               cmp eax, 80000000h       //>0x80吗?
               jbe  _EXIT2                   //没有扩展,跳出
               mov [info.bEXT], 1         //有扩展
 
               mov eax, 80000001h
               CPUID
               test edx, 80000000h      //检测有没有3DNOW 功能
               jz  _EXIT2
               mov [info.b3DNOW], 1
       _EXIT2:
               }
               //开始测试CPU属于Intel系还是AMD系
               if((strncmp(info.vendor, "GenuineIntel" , 12)==0) && info.bEXT) {
                      _asm {
                               mov eax,1
                               CPUID
                               mov esi, pn       //得到brand-id
                               mov [esi], ebx
                             }
                         int m = 0;
                         memcpy(&m, pn, sizeof(char)) //只拷贝低8位
                         n = m;
                       }
                    else if (( strncmp( info.vendor, "AuthenticAMD",12)==0 && info.bEXT)
                    {
                         _asm{
                                mov eax, 1
                                CPUID
                                mov esi, pn
                                mov [esi], eax
                               
                                mov eax, 0x80000001  //取得扩展功能描述
                                CPUID
                                test edx, 0x40000000   //extended 3DNOW
                                jz _AMD1
                                mov [info.b3DNOWEX], 1
                   _AMD1:  test edx, 0x00400000    //extended MMX
                               jz _AMD2
                               mov  [info.bMMXEX], 1
                   _AMD2:
                               }
                        }
                  else{
                         if (info.bEXT)
                            //不知道是哪个系的
                         else
                           //没扩展功能
                         }
                      info.vendor[13] = '/0';
                      GetCPUName(info.name, n, info.vendor);
                      return info;
              }
      不短,逻辑还算清楚,留着了。。。
      
      参考书: << 3d game engine programming-2004>> 作者Stefan Zerbst & Oliver Duvel
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值