关于函数mm_shuffle_ps的实现

该函数在C++里是:   __m128  __mm_shuffle_ps(__m128 v1,__m128 v2,UINT32 i);

该功能的实现依赖于一条SSE指令,SHUFPS XMM,XMM/M,IMM,第3个参数必须是立即数,这个该死的指令讲使得

mm_shuffle_ps(v1,v2:XVECTOR;ui:UINT32) return XVECTOR 实现起来相当困难。

        首先我们想到使用GNU汇编,但却很遗憾的无法完成这样的任务,因为汇编模板中指令:SHUFPS $imm,%xmm1,%xmm1 语句中必须是立即数!我们取ui'img行不行?看起来办法不错!可编译器报告:模板必须是静态的!不可以这样!

        接着,我们想到先创建一个汇编文档,再进行导入,这种方法是首先创建一个文档,根据第三个参数来创建该函数的汇编函数实现,接着导入,这的确是个可行的方法,但却导致程序每次运行都先创建文档一次,并非完美!

        我们最后想到一个更加完美的办法,我们将汇编程序的二进制机器码作为数据结构,然后修改数据结构的特定位置的字节,然后执行它!先贴汇编码。

# function __mm_shuffle_ps(v1,v2:__m128;i:uint) return __m128;
.file  "XDSP_SHUFFLES.s"
.text
.globl _mm_shuffle_ps;
.globl __mm_shuffle_ps;
.def _mm_shuffle_ps; .Scl 2; .type 32; .endef;
.def __mm_shuffle_ps; .Scl 2; .type 32; .endef;
_mm_shuffle_ps:
__mm_shuffle_ps:
pushl %ebp;
movl %esp,%ebp;
movl 12(%ebp),%edx;
movaps (%edx),%xmm0;
movl 16(%ebp),%edx;
movaps (%edx),%xmm1;
shufps $255, %xmm1, %xmm0;
movl 8(%ebp),%eax;
movaps %xmm0,(%eax);
leave;
ret;

我们来定义一个结构(此结构就是上述汇编的二进制形式,我们可以网上查找汇编码转机器码工具来获取机器码):

   type SHUFMCS is record
      PUSH_EBP:BYTE:=16#55#;
      MOVL_ESP_EBP:BYTE_Array(0..1):=(16#8b#,16#Ec#);
      MOVL_12EBP_EDX:BYTE_Array(0..2):=(16#8b#,16#55#,16#0c#);
      MOVAPS_EDXREF_XMM0:BYTE_Array(0..2):=(16#0f#,16#28#,16#02#);
      MOVL_16EBP_EDX:BYTE_Array(0..2):=(16#8b#,16#55#,16#10#);
      MOVAPS_EDXREF_XMM1:BYTE_array(0..2):=(16#0f#,16#28#,16#0a#);
      SHUFPS_XMM0_XMM1_BYTE:BYTE_ARRAY(0..3):=(16#0f#,16#c6#,16#c1#,16#00#);
      MOVL_8EBP_EAX:BYTE_Array(0..2):=(16#8b#,16#45#,16#08#);
      MOVAPS_XMM0_EAXREF:BYTE_Array(0..2):=(16#0f#,16#29#,16#00#);
      LEAVE:BYTE:=16#C9#;
      RET:BYTE:=16#C3#;
   end record with Pack;

   type LPSHUFMCS is access all SHUFMCS;

   procedure Free is new Ada.unchecked_deallocation(SHUFMCS,LPSHUFMCS);

再来定义一个结构:

   type LP_MM_SHUFFLE_PS is access function(v1,v2:XVECTOR;u:uint) return XVECTOR;
   
   type XPF(i:Integer:=0) is record
      case i is
         when 0=>
            ps:access SHUFMCS;
         when 1=>
            pf:LP_MM_SHUFFLE_PS;
         when others=>
            NULL;
      end case;
   end record WITH Unchecked_Union,Pack,size=>32;

使用变体记录(C中的共用体)来使函数指针与机器码指针等同,最终调用函数,非常简洁。


   function MM_SHUFFLE_PS(v1,v2:XVECTOR;u8:UINT) return XVECTOR is
      v3:XVECTOR;
      PF:XPF;
   begin
      PF.PS:=new SHUFMCS;
      PF.PS.SHUFPS_XMM0_XMM1_BYTE(3):=BYTE(u8);
      V3:=PF.PF.ALL(V1,V2,U8);
      Free(PF.PS);
      return V3; 
   end;

 注意:以上的实现必须把结构放到堆中,不可以放到栈中。

 

你可能感兴趣的:(Ada)