【问题标题】:Arm GNU Compiler: Assembly generated from ternary optimized by superfluous castArm GNU 编译器:通过多余的演员优化从三元生成的程序集
【发布时间】:2018-07-14 21:59:55
【问题描述】:

(更新删除 decltype 并替换为 static_cast,结果相同)

在代码示例中,在宏 MAX 中添加强制转换,代码执行得更快。我不知道为什么它似乎应该是相同的。这发生在两个不同的 ARM 编译器 GCC(和更大代码库中的 armclang)中。对此的任何想法都会非常有帮助。

在下面的代码中,当定义 WITH_CAST 时,编译结果得到了显着改善(在我更大的代码库中结果相同)。表演的演员似乎是多余的。我在 Keil 5.25pre2 中运行它(仅作为模拟器)。我使用 Keil 模拟器来检查性能速度,通过查看 t1 计时器显示的微秒数。

代码片段:

#if defined (WITH_CAST)
#define MAX(a,b) (((a) > (b)) ? (static_cast<mytype>(a)) : (static_cast<mytype>(b)))
#else
#define MAX(a,b) (((a) > (b)) ? ((a)) : ((b)))
#endif

GNU Arm Tools Embedded v. 7 2017-q4-major。

编译器选项: -c -mcpu=cortex-m4 -mthumb -gdwarf-2 -MD -Wall -O -mapcs-frame -mthumb-interwork -std=c++14 -Ofast -I./RTE/_Target_1 -IC:/Keil_v525pre/ ARM/PACK/ARM/CMSIS/5.2.0/CMSIS/包含-IC:/Keil_v525pre/ARM/PACK/ARM/CMSIS/5.2.0/Device/ARM/ARMCM4/包含-I"C:/Program Files (x86 )/GNU Tools ARM Embedded/7 2017-q4-major/arm-none-eabi/include"-I"C:/Program Files (x86)/GNU Tools ARM Embedded/7 2017-q4-major/lib/gcc/ arm-none-eabi/7.2.1/include"-I"C:/Program Files (x86)/GNU Tools ARM Embedded/7 2017-q4-major/arm-none-eabi/include/c++/7.2.1" -I"C:/Program Files (x86)/GNU Tools ARM Embedded/7 2017-q4-major/arm-none-eabi/include/c++/7.2.1/arm-none-eabi" -D__UVISION_VERSION="525" -D__GCC -D__GCC_VERSION="721" -D_RTE_ -DARMCM4 -Wa,-alhms="*.lst" -o *.o

汇编器选项: -mcpu=cortex-m4 -mthumb --gdwarf-2 -mthumb-interwork --MD .d -I./RTE/_Target_1 -IC:/Keil_v525pre/ARM/PACK/ARM/CMSIS/5.2.0/ CMSIS/Include -IC:/Keil_v525pre/ARM/PACK/ARM/CMSIS/5.2.0/Device/ARM/ARMCM4/Include -I"C:/Program Files (x86)/GNU Tools ARM Embedded/7 2017-q4- major/arm-none-eabi/include" -I"C:/Program Files (x86)/GNU Tools ARM Embedded/7 2017-q4-major/lib/gcc/arm-none-eabi/7.2.1/include" -I"C:/Program Files (x86)/GNU Tools ARM Embedded/7 2017-q4-major/arm-none-eabi/include/c++/7.2.1" -I"C:/Program Files (x86)/ GNU 工具 ARM Embedded/7 2017-q4-major/arm-none-eabi/include/c++/7.2.1/arm-none-eabi" -alhms=".lst" -o *.o

链接器选项: -T ./RTE/Device/ARMCM4/gcc_arm.ld -mcpu=cortex-m4 -mthumb -mthumb-interwork -Wl,-Map="./Optimization.map" -o 优化.elf *.o -lm

#include <cstdlib>
#include <cstring>
#include <cstdint>

#define WITH_CAST
struct mytype {
 uint32_t value;
 __attribute__((const, always_inline)) constexpr friend bool operator>(const mytype & t, const mytype & a) {
  return t.value > a.value;
 }
};
static mytype output_buf [32];
static mytype * output_memory_ptr = output_buf;
static mytype * volatile * output_memory_tmpp = &output_memory_ptr;
static mytype input_buf [32];
static mytype * input_memory_ptr = input_buf;
static mytype * volatile * input_memory_tmpp = &input_memory_ptr;
#if defined (WITH_CAST)
#define MAX(a,b) (((a) > (b)) ? (static_cast<mytype>(a)) : (static_cast<mytype>(b)))
#else
#define MAX(a,b) (((a) > (b)) ? ((a)) : ((b)))
#endif
int main (void) {
 const mytype * input = *input_memory_tmpp;
 mytype * output = *output_memory_tmpp;
 mytype p = input[0];
 mytype c = input[1];
 mytype pc = MAX(p, c);
 output[0] = pc;
 for (int i = 1; i < 31; i ++) {
  mytype n = input[i + 1];
  mytype cn = MAX(c, n);
  output[i] = MAX(pc, cn);
  p = c;
  c = n;
  pc = cn;
 }
 output[31] = pc;
}

【问题讨论】:

  • 强制转换不是多余的——它是对非引用类型的强制转换,这意味着现在?: 的结果不是左值。没有那个演员 ?: 的结果是左值。现在,为什么它让你的代码更快是另一回事了......
  • 这导致了某个地方。将 static_cast 更改为 static_cast 会产生相同的次优结果,当然,由于您指出的左值,尝试分配给 MAX 的结果仅适用于 mytype&。仍然无法弄清楚为什么编译器无法识别和优化变量的使用方式。
  • @AnT 添加您的评论作为答案,我会接受。它解释了发生了什么——当然不是为什么,但这似乎是编译器编写者的问题。

标签: c++ gcc assembly


【解决方案1】:

引用自 C++0x 规范:

decltype(e)表​​示的类型定义如下:

——如果 e 是无括号的 id 表达式或类成员访问 (5.2.5),则 decltype(e) 是由 e 命名的实体的类型。如果没有这样的实体,或者如果 e 命名了一组重载函数,则程序是非良构的;

— 否则,如果 e 是函数调用 (5.2.2) 或重载运算符的调用(忽略 e 周围的括号),则 decltype(e) 是静态选择函数的返回类型;

——否则,如果 e 是左值,则 decltype(e) 是 T&,其中 T 是 e 的类型;

——否则,decltype(e) 是 e 的类型。

我想引用 (T&) 的使用会提高效率。

来自WANT SPEED? DON’T (ALWAYS) PASS BY VALUE.的讨论结果

仅涉及左值,在没有移动语义的情况下,“按值传递”版本会通过复制构造创建一个额外的对象。

因此,使用“decltype”,即“通过引用”提高了代码的效率。

【讨论】:

  • 不过,引用类型在这里没有任何意义,所以如果这个答案是正确的,那么自然的后续问题就是为什么会这样。
  • @hvd,谢谢。你是对的,我忘记了这个问题的重要内容。我通过添加参考更新了我的答案。
  • 嗯...但是您提供的报价清楚地表明 decltype 在这种情况下将代表 non-reference 类型。第一个项目符号适用。那么,您所说的“使用参考使其更有效率”是什么意思呢? decltype 在这种情况下实际上 抑制 引用(左值)并且显然使代码更快。
  • 我已更新代码以使用 static_cast 而不是 decltype。结果是一样的。
猜你喜欢
  • 2014-06-05
  • 2011-12-29
  • 2011-07-13
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
相关资源
最近更新 更多