【问题标题】:How can I work around GCC optimization-miss bug 90271?如何解决 GCC optimization-miss 错误 90271?
【发布时间】:2019-04-29 20:00:45
【问题描述】:

2019 年 5 月之前(可能更晚)发布的 GCC 版本未能优化这段代码:

// Replace the k'th byte within an int
int replace_byte(int v1 ,char v2, size_t k) 
{
   memcpy( (void*) (((char*)&v1)+k) , &v2 , sizeof(v2) );
   return v1;
}

可以看到here (GodBolt):clang 正确优化了这段代码 GCC 和 MSVC 没有。这是GCC bug 90271,它会在某个时候得到修复。但是 - 对于今天发布的 GCC 版本,它不会被修复,我想今天写这段代码......

那么:有没有一种变通方法可以让 GCC 为这个函数生成与 clang 相同的代码,或者至少 - 性能相当的代码,将数据保存在寄存器中而不使用指针和堆栈?

注意事项:

  • 我将其标记为 C,因为代码 sn-p 在 C 中。我假设一种解决方法,如果存在,也可以在 C 中实现。
  • 我对优化非内联函数和内联版本都很感兴趣。
  • 此问题与this one有关,但仅涉及GCC和此处代码中的具体方法;并且使用 C 而不是 C++。

【问题讨论】:

  • 为什么不直接做((char*)&v1)[k] = v2?这里不需要memcpy(注意:这并不能解决goldbolt显示的优化错误,所以我删除了我的答案)
  • 即使使用宏也会触发错误/不优化:#define replace_bytes_4(v1 ,v2, k) ((char*)&v1)[k] = v2
  • 只有在你考虑常量的情况下才能替换它。如果您使用实变量,则不会以这种方式进行优化。 IMO 在实际编程中无用的优化。我敢打赌没有人会浪费时间用它做点什么。
  • 它只替换一个字节;为什么叫replace_bytes?
  • @Jasen:因为在the question where this came up 我有兴趣替换多个字节。

标签: c gcc compiler-optimization


【解决方案1】:

这使得非内联版本更长一些,但内联版本针对所有三个编译器进行了优化:

int replace_bytes(int v1 ,char v2, size_t k)
{
    return (v1 & ~(0xFF << k * 8)) | ((unsigned char)v2 << k * 8);
}

如果char 是有符号类型,则需要在移位之前将v2 转换为unsigned char。在这种情况下,如果没有大小写,v2 将被符号扩展为整数,这将导致结果中不需要的位被设置为 1。

【讨论】:

  • 请注意,原始函数将根据机器的字节序返回不同的值,而这个不会。我不确定这是否是原始代码中的预期行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 2021-12-29
相关资源
最近更新 更多