该函数在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;
注意:以上的实现必须把结构放到堆中,不可以放到栈中。