SSE内在函数检查零标志

时间:2016-11-12 14:02:00

标签: c++ intrinsics

我想知道是否可以通过英特尔的SSE内部函数来检查处理器的标志寄存器?

例如:

int idx = _mm_cmpistri(mmrange, mmstr, 0x14);
int zero = _mm_cmpistrz(mmrange, mmstr, 0x14);

在此示例中,编译器能够将这两个内在函数优化为单个指令(pcmpistri)并通过跳转指令(jz)检查标志寄存器。

但是在以下示例中,编译器无法正确优化代码:

__m128i mmmask = _mm_cmpistrm(mmoldchar, mmstr, 0x40);
int zero = _mm_cmpistrz(mmoldchar, mmstr, 0x40);

这里,编译器生成pcmpistrmpcmpistri指令。但是,在我看来,第二条指令是冗余的,因为pcmpistrm以与pcmistri相同的方式设置处理器标志寄存器中的标志。

那么,回到我的问题,有没有办法直接读取标志寄存器或指示编译器只生成pcmpistrm指令?

2 个答案:

答案 0 :(得分:1)

看起来只是一个MSVC漏洞优化错误,而不是任何固有的错误。

gcc6.2和icc17成功使用了我在zero结果(on the Godbolt compiler explorer)上编写分支的测试函数中的一个PCMPISTRM的结果:

#include <immintrin.h>
__m128i foo(__m128i mmoldchar, __m128i mmstr)
{      
  __m128i mmmask = _mm_cmpistrm(mmoldchar, mmstr, 0x40);
  int zero = _mm_cmpistrz(mmoldchar, mmstr, 0x40);
  if(zero)
    return mmmask;
  else
    return _mm_setzero_si128();
}

    ##gcc6.2 -O3 -march=nehalem
    pcmpistrm       xmm0, xmm1, 64
    je      .L5
    pxor    xmm0, xmm0
    ret
.L5:
    ret

OTOH,clang3.9未通过CSE,并使用PCMPISTRI。

foo:
    movdqa  xmm2, xmm0
    pcmpistri       xmm2, xmm1, 64
    pxor    xmm0, xmm0
    jne     .LBB0_2
    pcmpistrm       xmm2, xmm1, 64
.LBB0_2:
    ret

请注意,根据Agner Fog's instruction tables,PCMPISTRM具有良好的吞吐量但是具有高延迟,因此如果延迟是瓶颈,则有很多空间可以并行执行两个操作。像使用__readflags()一样跳过篮球可能实际上更糟糕。

答案 1 :(得分:0)

我自己找到了解决方案。

有一个函数可以读取名为__readeflags()的标志寄存器。它包含了pushfpushfq在x64平台上)指令。

现在代码如下:

__m128i mmmask = _mm_cmpistrm(mmoldchar, mmstr, 0x40);
int zero = __readeflags() & 0x40; //0x40 is the mask for the zero flag (bit 6)

这个解决方案不是最优的,但它可以解决问题。