我正在开发一个多平台,多编译器库。该库具有以下宏:
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
# pragma intrinsic(_ReadWriteBarrier)
# define MEMORY_BARRIER() _ReadWriteBarrier()
#elif ...
#elif defined(__GNUC__)
# define MEMORY_BARRIER() __asm__ __volatile__ ("" ::: "memory")
#else
# define MEMORY_BARRIER()
#endif
在GCC下,上面的代码可以用来驯服优化器。
虽然该函数名为MEMORY_BARRIER
,但重要的部分是标记为volatile
的内联汇编。这是在GCC,Clang和英特尔下驯服优化器的部分。
编辑 :内联汇编并没有驯服Clang上的优化器,即使Clang声称是通过定义__GNUC__
是GCC。请参阅LLVM Bug 15495 - dead store pass ignores memory clobbering asm statement。
宏的使用是handle
类。 handle
提供了一个级别和间接,我们试图引出一个NULL指针解除引用来帮助定位错误(一些手放弃)。为了实现我们的目标,我们需要确保优化器不会删除死存储(m_p = NULL;
):
template <class T> handle<T>::~handle()
{
delete m_p;
m_p = NULL;
MEMORY_BARRIER();
}
我不想使用volatile
强制转换,因为(1)我不相信它正确使用限定符(取自与Clang和GCC开发者的交互),以及(2)它似乎volatile
强制转换在C ++中是未定义的行为(参见Approved way to avoid lvalue cast warnings and errors?)。
内存障碍是否驯服了Microsoft平台上的优化器?
答案 0 :(得分:2)
在GCC编译器下,您可以使用编译器指令手动关闭所选函数的优化,如下例所示。
#pragma GCC push_options
#pragma GCC optimize ("O0")
static inline void MEMORY_BARRIER() {
// your code
}
#pragma GCC pop_options
在VC编译器下,您可以使用编译器指令手动关闭所选函数的优化,如下例所示。
#pragma optimize( "", off )
static inline void MEMORY_BARRIER() {
// your code
}
#pragma optimize( "", on )
也许你可以用这个技巧来得到你想要的东西?
不幸的是,我现在不知道如何在clang / llvm或Intel Compiler下做类似的技巧。
答案 1 :(得分:0)
ffmpeg(用C编写,而不是C ++)通过a wrapper for free
, which zeroes the pointer来解决这个问题。
在新代码中,他们更喜欢av_free(&ptr)
而不是av_free(ptr)
。
如果存在释放后使用状态,编译器将无法证明它是一个死存储并消除它,我想。如果允许编译器假定对析构函数中的成员变量的写入是死存储,那么这可能在C ++中不起作用。
我知道它不能证明什么,但你看过编译器优化掉这些指针归零存储的情况吗?