2

我正在开发一个多平台、多编译器库。该库具有以下宏:

#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 和 Intel 下驯服优化器的部分。

编辑:内联程序集不会驯服 Clang 上的优化器,即使 Clang 通过定义__GNUC__. 请参阅LLVM 错误 15495 - 死存储传递忽略内存破坏 asm 语句

宏的使用是一个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++ 中未定义的行为(请参阅已批准的避免左值转换警告和错误的方法?)。

内存屏障是否驯服了 Microsoft 平台上的优化器?

4

2 回答 2

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 编译器下做类似的技巧。

于 2015-08-01T21:59:11.133 回答
0

ffmpeg(用 C 语言编写,而不是 C++ 编写)通过使用for 的包装器解决了这个问题,该包装器free将指针 清零

在新代码中,他们更av_free(&ptr)喜欢av_free(ptr).

如果存在释放后使用条件,我猜编译器将无法证明它是一个死存储并消除它。如果允许编译器假定对析构函数中成员变量的写入是死存储,这在 C++ 中可能不起作用。

我知道这不能证明任何事情,但是您是否见过编译器优化掉这些指针归零存储的情况?

于 2015-08-03T01:29:46.067 回答