ube error: _mm_aeskeygenassist_si128 intrinsic requires at least -xarch=aes

ube error: _mm_aeskeygenassist_si128 intrinsic requires at least -xarch=aes

我在 SunOS 5.11 (Solaris 11.3) 上的 Sun Studio 12.3 下工作。它提供了一个我不太明白的编译错误:

$ /opt/solarisstudio12.3/bin/CC -xarch=sse2 -xarch=aes -xarch=sse4_2 -c test.cxx 
"test.cxx", line 11: ube: error: _mm_aeskeygenassist_si128 intrinsic requires at least -xarch=aes.
CC: ube failed for test.cxx

添加 -m64 产生相同的错误。

测试程序内容不多。它只是执行一个 SSE2 内在函数和一个 AES 内在函数:

$ cat test.cxx
#include <stdint.h>
#include <wmmintrin.h>
#include <emmintrin.h>
int main(int argc, char* argv[])
{
  // SSE2
  int64_t x[2];
  __m128i y = _mm_loadu_si128((__m128i*)x);

  // AES
  __m128i z = _mm_aeskeygenassist_si128(y,0);

  return 0;
}

我一直在尝试阅读手册并了解如何指定多个 cpu 架构功能,例如 SSE2、SSSE3、AES 和 SSE4。但我似乎无法确定如何指定多个。这是我找到的更完整的页面之一:Oracle Man Page CC.1,但我显然遗漏了一些关于 -xarch.

的内容

我做错了什么,我该如何解决?

这个命令行

$ /opt/solarisstudio12.3/bin/CC -xarch=sse2 -xarch=aes -xarch=sse4_2 -c test.cxx 

将使用 -xarch=sse2 -xarch=aes -xarch=sse4_2 的最后一个并导致编译器发出 sse4_2 兼容的二进制文件。

这在 Chapter 3 of the C++ User's Guide 中有记录:

3.2 General Guidelines

Some general guidelines for the C++ compiler options are:

  • The-llib option links with library liblib.a (or liblib.so). It is always safer to put-llib after the source and object files to ensure the order in which libraries are searched.

  • In general, processing of the compiler options is from left to right (with the exception that-U options are processed after all-D options), allowing selective overriding of macro options (options that include other options). This rule does not apply to linker options.

  • The -features, -I -l, -L, -library, -pti, -R, -staticlib, -U, -verbose, and -xprefetch options accumulate, they do not override.

  • The -D option accumulates. However, multiple -D options for the same name override each other.

Source files, object files, and libraries are compiled and linked in the order in which they appear on the command line.

这样做是为了让您可以做一些事情,例如覆盖 -fast, which expands to about 10 separate arguments.

等参数的扩展

您应该使用 -xarch=aes 标志 - 最后一个或作为唯一的 -xarch=... 选项。

我要给来自 GCC 的人一个答案。在 GCC 世界中,我们做 -march=native 并且 GCC 定义宏,如 -D__SSE2__-D__SSE4_1__-D__SSE4_2__-D__AES__-D__AVX__-D__BMI__,等等

SunCC 不像 GCC 那样做。它不提供像 __SSE2__ 这样的定义;它也不提供 -xarch 的值。

以下是相关 Sun Studio 手册和 -xarch options/instructions 设置选项的参考:

以下是我们如何确定可以使用哪些标志,然后将它们转换为 GCC 预处理器宏。太糟糕了,但我不知道如何以其他方式生成代码。

CC=...
EGREP=...

X86_CPU_FLAGS=$(isainfo -v 2>/dev/null)
SUNCC_510_OR_ABOVE=$("$CXX" -V 2>&1 | "$EGREP" -c "CC: (Sun|Studio) .* (5\.1[0-9]|5\.[2-9]|[6-9]\.)")
SUNCC_511_OR_ABOVE=$("$CXX" -V 2>&1 | "$EGREP" -c "CC: (Sun|Studio) .* (5\.1[1-9]|5\.[2-9]|[6-9]\.)")
SUNCC_512_OR_ABOVE=$("$CXX" -V 2>&1 | "$EGREP" -c "CC: (Sun|Studio) .* (5\.1[2-9]|5\.[2-9]|[6-9]\.)")
SUNCC_513_OR_ABOVE=$("$CXX" -V 2>&1 | "$EGREP" -c "CC: (Sun|Studio) .* (5\.1[3-9]|5\.[2-9]|[6-9]\.)")

SUNCC_XARCH=
if [[ ("$SUNCC_511_OR_ABOVE" -ne "0") ]]; then
    if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "sse2") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__SSE2__"); SUNCC_XARCH=sse2; fi
        if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "sse3") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__SSE3__"); SUNCC_XARCH=ssse3; fi
        if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "ssse3") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__SSSE3__"); SUNCC_XARCH=ssse3; fi
        if [[ ("$SUNCC_512_OR_ABOVE" -ne "0") ]]; then
            if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "sse4.1") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__SSE4_1__"); SUNCC_XARCH=ssse4_1; fi
            if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "sse4.2") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__SSE4_2__"); SUNCC_XARCH=ssse4_2; fi
            if [[ ("$SUNCC_513_OR_ABOVE" -ne "0") ]]; then
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "aes") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__AES__"); SUNCC_XARCH=aes; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "pclmulqdq") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__PCLMUL__"); SUNCC_XARCH=aes; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "rdrand") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__RDRND__"); SUNCC_XARCH=avx_i; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "rdseed") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__RDSEED__"); SUNCC_XARCH=avx_i; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "avx") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__AVX__"); SUNCC_XARCH=avx; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "avx2") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__AVX2__"); SUNCC_XARCH=avx2; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "bmi") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__BMI__"); SUNCC_XARCH=avx2; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "bmi2") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__BMI2__"); SUNCC_XARCH=avx2; fi
                if [[ ($(echo -n "$X86_CPU_FLAGS" | "$GREP" -c "adx") -ne "0") ]]; then PLATFORM_CXXFLAGS+=("-D__ADX__"); SUNCC_XARCH=avx2_i; fi        
            fi
        fi
    fi
fi
PLATFORM_CXXFLAGS+=("-xarch=$SUNCC_XARCH")

上面的旋转允许我们做这样的事情(除了我们需要 SSE2 though ADX)。

#if (_MSC_VER >= 1700) || defined(__RDRND__)
    uint64_t val;
    if(_rdrand64_step(&val))
    {
        // Use RDRAND value
    }
#endif

在使用内联汇编和内在函数进行测试期间,如果没有回转,我们会不断使 12.1 到 12.3 编译器崩溃。

脚本 运行 的结果为我们提供了 CFLAGSCXXFLAGS 的配方。下面是第 4 代 Core i5。 XEON 和第 5 代 Core i5 产生不同的结果。例如,第 5 代 Core i5 将具有 ADX 并使用 -xarch=avx_i.

Pathname: /opt/solstudio12.2/bin/CC (symlinked)
CXXFLAGS: -D__SSE2__ -D__SSE3__ -D__SSSE3__ -xarch=ssse3

/opt/solarisstudio12.3/bin/CC (symlinked)
CXXFLAGS: -D__SSE2__ -D__SSE3__ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -xarch=ssse4_2

Pathname: /opt/solarisstudio12.4/bin/CC
CXXFLAGS: -D__SSE2__ -D__SSE3__ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__AVX__ -xarch=avx

...