Visual c++ &引用;“逃避”;及;“重击”;MSVC中的等价物

Visual c++ &引用;“逃避”;及;“重击”;MSVC中的等价物,visual-c++,benchmarking,microbenchmark,Visual C++,Benchmarking,Microbenchmark,在中,他介绍了两个神奇的功能,可以在没有任何额外性能损失的情况下击败优化器 以下是函数(使用GNU样式的内联汇编)供参考: 它适用于任何支持GNU风格内联汇编的编译器(GCC、Clang、英特尔编译器,可能还有其他编译器)。然而,他提到它在MSVC中不起作用 通过检查,他们似乎使用了对volatile const char&的重新解释转换,并将其传递给非gcc/clang编译器上隐藏在不同翻译单元中的函数 template <class Tp> inline BENCHMARK_AL

在中,他介绍了两个神奇的功能,可以在没有任何额外性能损失的情况下击败优化器

以下是函数(使用GNU样式的内联汇编)供参考:

它适用于任何支持GNU风格内联汇编的编译器(GCC、Clang、英特尔编译器,可能还有其他编译器)。然而,他提到它在MSVC中不起作用

通过检查,他们似乎使用了对
volatile const char&
的重新解释转换,并将其传递给非gcc/clang编译器上隐藏在不同翻译单元中的函数

template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
    internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
}

// some other translation unit
void UseCharPointer(char const volatile*) {}
模板
内联基准\u始终\u内联无效未优化(Tp常量和值){
内部::UseCharPointer(&reinterpret_cast(值));
}
//其他翻译单位
void UseCharPointer(字符常量volatile*){}
然而,我对此有两个担忧:

  • 我可能会引起函数调用
  • “聪明”的链接时间优化器可能会识别UseCharPointer很小,将其内联,然后丢弃我想要保留的所有代码,或者“聪明”的优化器可能被允许执行我不希望它执行的其他重新排序

  • MSVC中是否有任何与GNU风格的汇编函数相对应的低级功能?或者这是MSVC上最好的功能了?

    虽然我不知道MSVC有类似的组装技巧,但Facebook在其愚蠢基准库中使用了以下功能:

    /**
     * Call doNotOptimizeAway(var) against variables that you use for
     * benchmarking but otherwise are useless. The compiler tends to do a
     * good job at eliminating unused variables, and this function fools
     * it into thinking var is in fact needed.
     */
    #ifdef _MSC_VER
    
    #pragma optimize("", off)
    
    template <class T>
    void doNotOptimizeAway(T&& datum) {
      datum = datum;
    }
    
    #pragma optimize("", on)
    
    #elif defined(__clang__)
    
    template <class T>
    __attribute__((__optnone__)) void doNotOptimizeAway(T&& /* datum */) {}
    
    #else
    
    template <class T>
    void doNotOptimizeAway(T&& datum) {
      asm volatile("" : "+r" (datum));
    }
    
    #endif
    
    /**
    *针对您所使用的变量调用doNotOptimizeAway(var)
    *基准测试在其他方面都是无用的。编译器倾向于执行
    *在消除未使用的变量方面做得很好,这个函数很愚蠢
    *事实上,我们需要它来思考var。
    */
    #ifdef硕士学位
    #pragma优化(“,关闭)
    模板
    void dono优化中途(T&基准){
    基准=基准;
    }
    #pragma优化(“,打开)
    #已定义的elif(_-clang__;)
    模板
    __属性uu((uuu optnone_uuuuu))void不优化(T&&/*datum*/){}
    #否则
    模板
    void dono优化中途(T&基准){
    asm volatile(“:”+r(基准));
    }
    #恩迪夫
    

    我正在寻找一种方法,在我自己的小基准库中实现完全相同的功能。 MSVC令人沮丧的是,针对x64不允许使用asm技巧,而x86允许使用

    经过几次尝试后,我重新使用了谷歌的解决方案,没有引起额外的呼叫! 很好的一点是,该解决方案可以与MSVC(/Ox)和GCC(-O3)一起使用

    生成的ASM()


    MSVC风格的asm{}无论如何也不会特别有用;它没有任何类似GNU C inline asm的输入/输出约束,让您告诉编译器,asm的空块实际上读取或读取写入了一个C变量,以迫使编译器在寄存器中具体化该变量。易失性负载迫使编译器在内存中具体化它,而不仅仅是
    mov edx,10
    什么的。但至少编译器仍然知道var只是在被读取,所以
    返回一个仍然可以编译到存储/重新加载之间的
    mov eax,10
    。但是,这看起来仍然会在使用它的地方引入2条指令,除非var已经存在于内存中,否则您只会得到一个加载。因此,在不太干扰编译器生成的代码的情况下,这可能很有用,但绝对不是免费的。对于窄类型(
    sizeof(T)Related):询问原始GNU C内联asm版本的真正功能。
    
    /**
     * Call doNotOptimizeAway(var) against variables that you use for
     * benchmarking but otherwise are useless. The compiler tends to do a
     * good job at eliminating unused variables, and this function fools
     * it into thinking var is in fact needed.
     */
    #ifdef _MSC_VER
    
    #pragma optimize("", off)
    
    template <class T>
    void doNotOptimizeAway(T&& datum) {
      datum = datum;
    }
    
    #pragma optimize("", on)
    
    #elif defined(__clang__)
    
    template <class T>
    __attribute__((__optnone__)) void doNotOptimizeAway(T&& /* datum */) {}
    
    #else
    
    template <class T>
    void doNotOptimizeAway(T&& datum) {
      asm volatile("" : "+r" (datum));
    }
    
    #endif
    
    template <class T>
    inline auto doNotOptimizeAway(T const& datum) {
        return reinterpret_cast<char const volatile&>(datum);
    }
    
    int main()
    {
        int a{10};
        doNotOptimizeAway(a);
        return 0;
    }
    
    a$ = 8
    main    PROC
            mov     DWORD PTR a$[rsp], 10
            movzx   eax, BYTE PTR a$[rsp]
            xor     eax, eax
            ret     0
    main    ENDP