Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可能影响GCC/Clang/Intel ICPC XMM/YMM寄存器分配?_Gcc_Assembly_Clang_Intrinsics_Icc - Fatal编程技术网

是否可能影响GCC/Clang/Intel ICPC XMM/YMM寄存器分配?

是否可能影响GCC/Clang/Intel ICPC XMM/YMM寄存器分配?,gcc,assembly,clang,intrinsics,icc,Gcc,Assembly,Clang,Intrinsics,Icc,我有一个高度优化的函数,在内部循环中反复调用,使用SSE2/AVX2加速编写。经过一些改进,现在我接近理论上的最佳性能(基于指令延迟和吞吐量)。但是,性能不是很好移植。问题在于有16个以上的\uuuM128i/\uuuu256i变量。当然,其中只有16个可以在寄存器中分配,其余的可以在堆栈中分配。函数大致如下所示: void eval(size_t n, __m128i *rk /* other inputs */) { __m128i xmmk0 = rk[0]; // ...

我有一个高度优化的函数,在内部循环中反复调用,使用SSE2/AVX2加速编写。经过一些改进,现在我接近理论上的最佳性能(基于指令延迟和吞吐量)。但是,性能不是很好移植。问题在于有16个以上的
\uuuM128i
/
\uuuu256i
变量。当然,其中只有16个可以在寄存器中分配,其余的可以在堆栈中分配。函数大致如下所示:

void eval(size_t n, __m128i *rk /* other inputs */)
{
    __m128i xmmk0 = rk[0];
    // ...
    __m128i xmmk6 = rk[6];
    __m128i xmmk;

    __m128i xmmk[Rounds - 6];
    // copy rk[7] to r[Rounds] to xmmk

    while (n >= 8) {
        n -= 8;

        __m128i xmm0 = /* initialize state xmm0 */
        // do the same for xmm1 - xmm7

        // round 0
        xmm0 = /* a few instructions involving xmm0 and xmmk0 */;
        // do the same for xmm1 - xmm7

        // do the same for round 1 to 6, using xmmk1, ..., xmmk6

        // round 7, copy xmmk[0] to a temporary __m128i variable
        xmm0 = /* a few instructions involving xmm0 and xmmk[0] */;
        // do the same for xmm1 - xmm7

        // do the same for round 7 to Rounds, using xmmk[1], xmmk[Rounds - 7]
    }
}
涉及的变量超过16个。我能获得的最佳性能是,编译器将
xmm0
分配给
xmm7
,将
xmmk0
分配给
xmmk6
,将前7个循环常量分配到寄存器中,并将剩余的寄存器用作临时寄存器,为剩余的循环加载循环常量。当以与上述类似的方式编写时,GCC/clang正是这样做的,但Intel ICPC将一些
xmm0
分配给堆栈上的
xmm7
变量,并引入一些不必要的内存移动。如果相反,我写的方式与下面类似

__m128i xmmk[Rounds + 1]; // copy from input rk
// let compiler to figure out which of them are allocated on stack and which in registers,
然后GCC/ICPC在寄存器分配方面做得很好,而clang陷入了类似于前一个案例中ICPC的情况

当然,声明
\uuu m128i
类型的变量不会使其成为寄存器,在堆栈数组中声明也不会阻止编译器为其分配寄存器

我能够编写一个ASM实现,它完全符合我的要求。但是,实际函数涉及一些指定为模板策略的编译时常量。因此,在C++中用内联实现它们是更可取的。p>
我想知道的是,是否有办法影响这些编译器执行寄存器分配的方式。由于一级缓存速度快,通常性能上的差异只是几个周期。但是,当高度优化时,当内部循环只需要100个周期时,由于不必要的内存移动而产生的十几个周期差异将转化为20%的总体性能差异。据我所知,没有办法让编译器完全像手工编写的汇编一样工作。但如果我至少能给他们一些提示,那将是非常有帮助的。例如,我知道加载round常量的延迟可以被其他指令隐藏。因此,更希望在堆栈上分配它们,而不是将状态变量
xmm0
分配给
xmm7

您是否尝试过
注册
关键字?:)是的,这只是一个提示,编译器可能会忽略它。@Jester这是我第一次尝试的。我已经好几年没用过那个关键词了。但它根本不起作用,正如预期的那样。事实上,据我所知,这个
寄存器将在C++1z中删除。如果地址是常量,那么可能不是延迟(OOO隐藏的延迟),而是额外的UOP。您甚至可以尝试类似于
register\uuuu m128i foo asm(“xmm0”)。GNU扩展强制编译器在整个函数中为该变量使用该寄存器,这实际上可能会使情况变得更糟,因为在非交换操作结束后,需要MOVDQA将结果放回该寄存器,这样会更自然地将变量的当前值放在另一个寄存器中。我只是尝试过,在简单的情况下,它似乎并没有打败优化器:().@兖州,根据你使用的语言来标记C或C++可能是有用的。是的,更多的人看<代码> [C] < /C>标签,而不是<代码> [GCC ] < /C>或<代码> [汇编] < /Cord>。我可能会丢掉“内在论”的标签。