【问题标题】:Detect the availability of SSE/SSE2 instruction set in Visual Studio在 Visual Studio 中检测 SSE/SSE2 指令集的可用性
【发布时间】:2013-09-01 23:38:39
【问题描述】:

如何在代码中检查 Visual Studio 编译器是否启用了 SSE/SSE2?

我尝试了#ifdef __SSE__,但没有成功。

【问题讨论】:

    标签: c++ visual-studio x86 sse sse2


    【解决方案1】:

    关于_M_IX86_FP 的一些附加信息。

    _M_IX86_FP 仅针对 32 位代码定义。 64 位 x86 代码至少具有 SSE2。您可以使用 _M_AMD64 或 _M_X64 来确定代码是否为 64 位。

    #ifdef __AVX2__
    //AVX2
    #elif defined ( __AVX__ )
    //AVX
    #elif (defined(_M_AMD64) || defined(_M_X64))
    //SSE2 x64
    #elif _M_IX86_FP == 2
    //SSE2 x32
    #elif _M_IX86_FP == 1
    //SSE x32
    #else
    //nothing
    #endif
    

    【讨论】:

      【解决方案2】:

      相关的预处理器宏在每一端都有两个下划线:

      #ifdef __SSE__
      
      #ifdef __SSE2__
      
      #ifdef __SSE3__
      
      #ifdef __SSE4_1__
      
      #ifdef __AVX__
      
      ...etc...
      

      更新:显然,在使用 Visual Studio 时,上述宏不会自动为您预定义(即使它们在我曾经使用过的所有其他 x86 编译器中),所以您可能需要如果您想要 gcc、clang、ICC、et al...

      的可移植性,请自行定义它们

      【讨论】:

      • 根据他们的文档 (msdn.microsoft.com/en-us/library/b0084kay.aspx),Visual Studio 没有设置 __SSEn__ 宏(但他们确实设置了 __AVX____AVX2__)。
      • 典型的,我想 - 其他人都定义了 __SSEn__ 宏,但微软没有。
      【解决方案3】:

      来自the documentation

      _M_IX86_FP

      扩展为一个值,指示使用了哪个 /arch 编译器选项:

      • 如果使用了 /arch:IA32,则为 0。
      • 如果使用了 /arch:SSE,则为 1。
      • 2 如果使用了 /arch:SSE2。如果未指定 /arch,则此值为默认值。

      我没有看到任何提及_SSE_

      【讨论】:

        【解决方案4】:

        这是一个较晚的答案,但在 MSDN 上你可以找到一篇关于 __cpuid 和 __cpuidex 的文章。我把这个类重新编写成一个函数,它检查 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1 的支持。 https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=vs-2019

        [[nodiscard]] bool CheckSimdSupport() noexcept
        {
            std::array<int, 4> cpui;
            int nIds_{};
            std::bitset<32> f_1_ECX_{};
            std::bitset<32> f_1_EDX_{};
            std::vector<std::array<int, 4>> data_;
        
            __cpuid(cpui.data(), 0);
            nIds_ = cpui[0];
        
            for (int i = 0; i <= 1; ++i)
            {
                __cpuid(cpui.data(), i);
                data_.push_back(cpui);
            }
        
            if (nIds_ >= 1)
            {
                f_1_ECX_ = data_[1][2];
                f_1_EDX_ = data_[1][3];
            }
            // f_1_ECX_[0] - SSE3
            // f_1_ECX_[9] - SSSE3
            // f_1_ECX_[19] - SSE4.1
            // f_1_EDX_[23] - MMX
            // f_1_EDX_[25] - SSE
            // f_1_EDX_[26] - SSE2
            return f_1_ECX_[0] && f_1_ECX_[9] && f_1_ECX_[19] && f_1_EDX_[23] && f_1_EDX_[25] && f_1_EDX_[26];
        }
        

        【讨论】:

        • 在运行时检查以找出目标 CPU 支持的内容。它不会告诉您使用编译器选项启用了哪些基线级别,以便编译器自行发出。 (这两件事可能对不同的目的/用例有用。)
        • 这种事情可能是 OP 真正想到的; “在目标上启用”是对该措辞的合理解释,与其他答案的解释方式不同。 MSVC 允许您将内在函数用于您没有告诉编译器它可以使用的指令集,并且它没有 gcc -O3 -march=native 等效的 AFAIK,它实际上在编译时检测构建主机 CPU。
        猜你喜欢
        • 2010-12-01
        • 2013-06-11
        • 1970-01-01
        • 1970-01-01
        • 2011-10-17
        • 2017-04-07
        • 2012-11-25
        • 2012-02-27
        • 1970-01-01
        相关资源
        最近更新 更多