C++ Arm GNU编译器:由三元代码生成的程序集,通过多余的强制转换进行优化

C++ Arm GNU编译器:由三元代码生成的程序集,通过多余的强制转换进行优化,c++,gcc,assembly,C++,Gcc,Assembly,(更新以删除decltype并替换为static_cast,结果相同) 在代码示例中,在宏MAX中添加强制转换,代码执行得更快。我不明白为什么,因为看起来应该是一样的。这发生在两个不同的ARM编译器GCC(和更大的代码库中的armclang)上。对此有任何想法都会很有帮助 在下面的代码中,当使用_CAST定义时,编译的结果会得到显著改进(在我更大的代码库中有相同的结果)。演出的演员阵容似乎是多余的。我在Keil 5.25pre2中运行这个程序(仅作为模拟器)。我使用Keil模拟器检查性能速度,通

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

在代码示例中,在宏MAX中添加强制转换,代码执行得更快。我不明白为什么,因为看起来应该是一样的。这发生在两个不同的ARM编译器GCC(和更大的代码库中的armclang)上。对此有任何想法都会很有帮助

在下面的代码中,当使用_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
#如果已定义(使用_CAST)
#定义最大值(a,b)((a)>(b))?(静态施法(a)):(静态施法(b)))
#否则
#定义最大值(a,b)((a)>(b))?((a)):((b)))
#恩迪夫
GNU Arm工具嵌入式v。7 2017年第四季度-主要

编译器选项: -c-mcpu=cortex-m4-mthumb-gdwarf-2-MD-Wall-O-mapcs框架-mthumb互通-std=c++14-Ofast-I./RTE/_-Target_1-IC:/Keil_V525; pre/ARM/PACK/ARM/CMSIS/5.2.0/CMSIS/Include-IC:/Keil_V525; pre/ARM/ARM/PACK/ARM/CMSIS/5.2.0/Device/ARM/ARM/ARM/ARM/ARM/CMSIS/5.2.0/Include-I“c:/c:/Program文件(x86)/GNU工具ARM嵌入式/7-2017-q4-major/ARM-“C:/ProgramFiles(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/GNU Tools ARM none eabi/include/C++/7.2.1/ARM none eabi-D\U UVISION\u VERSION=“525“-D_ugcc-D_ugcc_VERSION=“721”-D_RTE_u-DARMCM4-Wa,-alhms=“*.lst”-o*.o”

汇编程序选项: -mcpu=cortex-m4-mthumb-gdwarf-2-mthumb互通——MD.d-I/RTE/U Target\U 1-IC:/Keil_V525; pre/ARM/PACK/ARM/CMSIS/5.2.0/CMSIS/Include-IC:/Keil_v525pre/ARM/PACK/ARM/CMSIS/5.2.0/Device/ARM/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/7-q4-C/ARM none-eabi/include/C++/7.2.1/ARM none-eabi“--alhms=“.lst”-=.lst”-o*.o

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

#包括
#包括
#包括
#用_CAST定义
结构mytype{
uint32_t值;
__属性(const,总是内联)constexpr friend bool操作符>(const mytype&t,const mytype&a){
返回t.value>a.value;
}
};
静态mytype输出_buf[32];
静态mytype*output\u memory\u ptr=output\u buf;
静态mytype*易失性*输出\内存\ tmpp=&输出\内存\ ptr;
静态mytype输入_buf[32];
静态mytype*input\u memory\u ptr=input\u buf;
静态mytype*易失性*输入\内存\ tmpp=&输入\内存\ ptr;
#如果已定义(带_CAST)
#定义最大值(a,b)((a)>(b))?(静态施法(a)):(静态施法(b)))
#否则
#定义最大值(a,b)((a)>(b))?((a)):((b)))
#恩迪夫
内部主(空){
常量mytype*input=*input\u memory\u tmpp;
mytype*输出=*输出\内存\ tmpp;
mytype p=输入[0];
mytype c=输入[1];
mytype pc=最大值(p,c);
输出[0]=pc;
对于(int i=1;i<31;i++){
mytype n=输入[i+1];
mytype cn=最大值(c,n);
输出[i]=MAX(pc,cn);
p=c;
c=n;
pc=cn;
}
输出[31]=个人计算机;
}

引用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&)的使用会使它更有效

从讨论结果来看

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


因此,使用'decltype',即'passbyreference',提高了代码的效率。

引自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&)的使用会使它更有效

从讨论结果来看

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


因此,使用'decltype',即'passbyreference',可以提高代码的效率。

但是,引用类型在这里没有任何意义,因此,如果这个答案正确,自然要问的是为什么会这样。@hvd,谢谢。你说得对,我忘了一些重要的东西
#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;
}