MSVC编译器单函数禁用优化的pragma为何未生效?
MSVC下BENCHMARK_DONT_OPTIMIZE宏失效问题排查
我有一个能在GCC和Clang下正常工作的宏:
#if defined(__clang__) #define BENCHMARK_DONT_OPTIMIZE [[clang::optnone]] #elif defined(__GNUC__) || defined(__GNUG__) #define BENCHMARK_DONT_OPTIMIZE [[gnu::optimize(0)]] #elif defined(_WIN32) #define BENCHMARK_DONT_OPTIMIZE __pragma(optimize("",off)) #else #define BENCHMARK_DONT_OPTIMIZE #endif
但针对MSVC,我尝试了__pragma(optimize("",off))和#pragma optimize("",off)的各种组合都无效——MSVC虽接受两种语法,但并未按文档描述生效。
在以下测试代码中,GCC和Clang会把Sum的实现优化为N(N-1)/2的数学公式,而MSVC生成的Sum和SumNoOpt汇编完全相同,循环并未被保留:
template< typename SumType > struct Sum { SumType operator() ( SumType size ) { SumType sum = 0; for ( SumType j=0; j<size; ++j ) { sum += j; } return sum; } }; template< typename SumType > struct SumNoOpt : public Sum<SumType> { BENCHMARK_DONT_OPTIMIZE SumType operator() ( SumType size ) { SumType sum = 0; for ( SumType j=0; j<size; ++j ) { sum += j; } return sum; } }; template struct Sum<size_t>; template struct SumNoOpt<size_t>;
问题原因
MSVC的optimize编译指示是作用于代码段的,而非GCC/Clang那样的函数属性。将__pragma放在函数声明前时,其作用范围无法正确覆盖模板函数的函数体,导致优化禁用未生效。
解决方案
方案1:使用MSVC专属属性(VS2019 16.10+)
MSVC从VS2019 16.10版本开始支持[[msvc::no_optimize]]属性,可直接修饰函数,用法和GCC/Clang的属性一致,修改宏定义即可:
#if defined(__clang__) #define BENCHMARK_DONT_OPTIMIZE [[clang::optnone]] #elif defined(__GNUC__) || defined(__GNUG__) #define BENCHMARK_DONT_OPTIMIZE [[gnu::optimize(0)]] #elif defined(_MSC_VER) #define BENCHMARK_DONT_OPTIMIZE [[msvc::no_optimize]] #else #define BENCHMARK_DONT_OPTIMIZE #endif
方案2:兼容旧版MSVC
对于不支持msvc::no_optimize的旧版MSVC,需要将__pragma放在函数体内部,确保作用范围覆盖循环代码:
template< typename SumType > struct SumNoOpt : public Sum<SumType> { SumType operator() ( SumType size ) { __pragma(optimize("", off)) SumType sum = 0; for ( SumType j=0; j<size; ++j ) { sum += j; } return sum; } };
同时建议将宏中的_WIN32替换为_MSC_VER,避免MinGW等Windows下的其他编译器误触发MSVC分支。
内容的提问来源于stack exchange,提问作者Henrique Bucher
相关产品推荐
相关产品推荐

