简体   繁体   English

GNU内置函数`__builtin_unreachable`如何在这段代码中起作用?

[英]How the GNU builtin function `__builtin_unreachable ` works in this code snippet?

I have a code snippet in my project in which the __builtin_unreachable function has been used but I don't know why it is needed here. 我的项目中有一个代码片段,其中使用了__builtin_unreachable函数,但我不知道为什么需要它。

And I read from GNU __builtin_unreachable , it seems that the __builtin_unreachable function is used to inform the compiler this line will never be reached during the CPU run time, so that a lot of complains in compilation can be prevented in advance. 我从GNU __builtin_unreachable中读到,似乎__builtin_unreachable函数用于通知编译器在CPU运行时期间永远不会到达此行,因此可以提前阻止编译中的大量抱怨。 But I am not understood why this feature is needed in this code snippet, it seems nothing will happen by removing the __builtin_unreachable . 但是我不明白为什么在这段代码片段中需要这个功能,似乎没有任何事情会通过删除__builtin_unreachable

# define ATHCONTAINERS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while(0)


inline
void*
AuxVectorData::Cache::getDataArray (SG::auxid_t auxid,
                                    AuxVectorData& parent)
{
  // This function is important for performance.
  // Be careful when changing it.

  void* ptr = cachePtr (auxid);
  if (ATHCONTAINERS_UNLIKELY (ptr == 0)) {
    // We don't have the variable cached.
    // Call the out-of-line routine to get it cached.
    ptr = parent.getDataOol (auxid, false);

    // These inform the compiler of what the previous call did.
    // They tell the optimizer that it can now assume that this cache
    // entry is valid.
    ATHCONTAINERS_ASSUME (ptr != 0); 
    ATHCONTAINERS_ASSUME (cachePtr (auxid) != 0); 
    ATHCONTAINERS_ASSUME (cachePtr (auxid) == ptr);
  }
  return ptr;
}

ATHCONTAINERS_ASSUME tells the compiler that its argument x cannot be false. ATHCONTAINERS_ASSUME告诉编译器它的参数x不能为false。 This relieves the compiler from having to generate any code to accommodate the possibility that x is false. 这使编译器不必生成任何代码以适应x为假的可能性。 For example, when the compiler sees ATHCONTAINERS_ASSUME (ptr != 0) it can assume ptr is not null, and any code which contradicts that assumption can be optimized away, as it would be undefined behavior. 例如,当编译器看到ATHCONTAINERS_ASSUME (ptr != 0)它可以假设ptr不为空,并且任何与该假设相矛盾的代码都可以被优化掉,因为它将是未定义的行为。

For example, since getDataArray() is inline , the compiler can know at every call site that the returned pointer will never be null. 例如,由于getDataArray()inline ,编译器可以在每个调用站点知道返回的指针永远不会为null。 So if a caller does this: 所以如果调用者这样做:

if (void* p = cache.getDataArray(aux, parent))
    memcpy(p, "OK", 2);

The compiler can generate code which directly writes "OK" without performing the null check. 编译器可以生成直接写入“OK”而不执行空检查的代码。

That's pretty interesting, and new to me. 这很有趣,对我来说很新。

My best understanding, from the documentation you linked to which says: 我最好的理解,从您链接到的文档说:

If control flow reaches the point of the __builtin_unreachable() , the program is undefined. 如果控制流到达__builtin_unreachable()的点,则程序未定义。

So basically the macro reaches undefined behavior if the condition is false. 因此,如果条件为false,宏基本上会达到未定义的行为。 Thus, the compiler is assumed to be able to optimize based on the assumption that that doesn't happen, ie the conditions are not false. 因此,假设编译器能够基于不发生的假设进行优化,即条件不是假的。

I'd be interested in comparing the result from building the code with and without those macros, to further understand what actual difference it makes. 我有兴趣比较使用和不使用这些宏来构建代码的结果,以进一步了解它所产生的实际差异。

Relying on this to get some kind of optimization to happen seems kind of "brittle" to me, since it assumes a lot about the internal functioning of the compiler. 依靠这个来实现某种优化对我来说似乎有些“脆弱”,因为它假定了很多关于编译器的内部功能。

As the code comment indicates, it tells stories to the optimizer. 正如代码注释所示,它向优化器讲述故事。

The first thing this tells, is that the compiler can assume that the return value is not a null pointer. 这告诉我的第一件事是编译器可以假设返回值不是空指针。 It would probably improve the readability of the code if another gcc extension would be used instead, namely __attribute__((__returns_nonnull__)) . 如果将使用另一个gcc扩展名,即__attribute__((__returns_nonnull__)) ,它可能会提高代码的可读性。 Adding this to the interface of getDataArray would also guarantee that property, even if the the compiler decides that he can't inline it for whatever reason. 将此添加到getDataArray的接口也可以保证该属性,即使编译器决定不能出于任何原因内联它。

But it is telling more than that. 但它告诉的不止于此。 It also tells (or tries to tell) that future calls to cachePtr with the same parameter will return the same result. 它还告诉(或试图告诉)将来使用相同参数调用cachePtr将返回相同的结果。

All these properties would probably better be guaranteed by removing the unused parent parameter (to avoid aliasing analysis) and by also adding __attribute__((__const__)) to getDataArray . 通过删除未使用的parent参数(以避免别名分析)以及将__attribute__((__const__))getDataArray可以更好地保证所有这些属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM