在x86_64上使用gcc 4.4.5(是的......我知道它已经老了).出于兼容性原因,仅限于SSE2(或更早)的说明.
我认为应该是一个教科书案例,以获得预取的巨大好处.我有一个32位元素的数组("A"),它不是(也可能不是)按顺序排列的.这些32位元素是__m128i数据的较大数据数组("D")的索引.为"A"的各要素,我需要在"d"从适当的位置取__m128i数据,在其上执行的操作,并且将其存储回在"d"的相同位置.实际上D中的每个"条目"都是"SOME_CONST"__m128i的大.因此,如果A中的值为"1",则D中的索引为D [1*SOME_CONST].
由于"A"中的连续元素几乎不会指向"D"中的连续位置,因此我倾向于认为硬件预取器将会挣扎或无法完成任何有用的操作.
但是,我可以很容易地预测下一个我将要访问的位置,只需在"A"中向前看即可.足够的措辞......这里有一些代码.我对数据执行的操作是取__m128i的低64位并将其克隆到相同的高64位.首先是基本循环,没有多余的装饰......
// SOME_CONST is either 3 or 4, but this "operation" only needs to happen for 3
for ( i=0; i<arraySize; ++i )
{
register __m128i *dPtr = D + (A[i] * SOME_CONST);
dPtr[0] = _mm_shuffle_epi32( dPtr[0], 0 | (1<<2) | (0<<4) | (1<<6) );
dPtr[1] = _mm_shuffle_epi32( dPtr[1], 0 | (1<<2) | (0<<4) | (1<<6) );
dPtr[2] = _mm_shuffle_epi32( dPtr[2], 0 | (1<<2) | (0<<4) | (1<<6) );
// The immediate operand selects:
// …Run Code Online (Sandbox Code Playgroud) 我有一个例程,主要想用汇编语言编写,但我需要调用 C 函数来获取处理所需的一些数据。在某些情况下,我可以预先消化数据并加载带有指向它的指针的寄存器,但在其他情况下,我必须调用完整的函数,因为可能的数据集太大。这些函数无法修改,因为它们是别人的代码,并且其接口需要与其他代码保持相同。其中一些驻留在共享库中,尽管有些是通过头文件的内联函数(我无法更改)。
我可以使用 asm 构造将局部变量分配给寄存器:
register int myReg asm( "%r13" );
Run Code Online (Sandbox Code Playgroud)
恐怕如果我直接在汇编中操作 %r13,调用 C 函数并返回,它将需要从内存中刷新,或者更糟糕的是被完全覆盖。对于某些 ABI,我自己直接推送/弹出寄存器也不安全,对吗?我在 Linux 上使用 x86-64 工作。
我现在正在做的事情似乎正在使用 -g -O0,但我担心当我打开 C 代码的优化时,它将开始触及我希望受到保护的寄存器。
一般来说,我的代码流程如下:
asm( "movq %[src], %%r13" : : [src] "m" (myVariablePointer) : "r13" );
localVariable1 = callSomeCfunction( stuff );
storageLocation = index * sizeof( longTermStorageItem );
longTermStorage[storageLocation] = localVariable1;
// some intermediate registers need to be used here for dereferences and math
switch ( localVariable1 )
{
case CONSTANT_VAL_A:
C_MACRO_LOOP_CONSTRUCT
{
asm( "movdqa (%r13), %xmm0\n" …Run Code Online (Sandbox Code Playgroud)