Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译器优化:将变量从堆栈移动到寄存器_C++_Gcc_Clang_Language Lawyer_Compiler Optimization - Fatal编程技术网

C++ 编译器优化:将变量从堆栈移动到寄存器

C++ 编译器优化:将变量从堆栈移动到寄存器,c++,gcc,clang,language-lawyer,compiler-optimization,C++,Gcc,Clang,Language Lawyer,Compiler Optimization,代码如下: #包括 #包括 #包括 uint64_t uint5korr(常量标准::字节*p) { uint64_t结果=0; 标准::memcpy(和结果,第5页); 返回结果; } 这里的clang将结果优化为寄存器,而gcc则没有。 我怀疑这可能与我获取一个变量的地址有关,因为不能获取寄存器的地址 这仅仅是gcc中缺少的优化,还是clang以某种方式违反了标准?是的,此优化是合法的。从正确的地址读取5个字节(不是8个);不需要再存储它们,只需读取它们的返回、地址或否。我同意Micha

代码如下:

#包括
#包括
#包括
uint64_t uint5korr(常量标准::字节*p)
{
uint64_t结果=0;
标准::memcpy(和结果,第5页);
返回结果;
}

这里的clang将
结果
优化为寄存器,而gcc则没有。 我怀疑这可能与我获取一个变量的地址有关,因为不能获取寄存器的地址


这仅仅是gcc中缺少的优化,还是clang以某种方式违反了标准?

是的,此优化是合法的。从正确的地址读取5个字节(不是8个);不需要再存储它们,只需读取它们的返回、地址或否。我同意Michael Kenzel的怀疑,即这已经定义了行为,但这只能巩固优化的有效性。

不是答案

虽然GCC中似乎确实缺少优化本身,但使用部分
memcpy
ed值IIUC是一种未定义的行为。我会向GCC提交一个bug,以获得关于该主题的明确响应

GCC/Clang/MSVC完美优化的加载40位宽度整数的方式:

std::uint64_t load_u40(const std::byte *p)
{
  std::uint8_t lo = 0;
  std::memcpy(&lo, p, 1);
  std::uint32_t hi = 0;
  std::memcpy(&hi, p + 1, 4);
  return (static_cast<std::uint64_t>(hi) << 8) | lo;
}
std::uint64\u t load\u u40(const std::byte*p)
{
标准:uint8_t lo=0;
标准::memcpy(&lo,p,1);
标准:uint32_t hi=0;
std::memcpy(&hi,p+1,4);

返回(静态_转换(hi)很明显,如果没有基准测试,在堆栈上放置一个变量的速度会慢一些。基本上,我希望这段代码通过gcc进行优化,我想知道这是否正确。我很确定标准中没有关于如何优化的要求,只要它们工作正常。但我没有任何东西可以引用来支持我除非这段代码以每秒数十万次的速度在一个非常紧密的循环中运行,否则我怀疑你是否能够测量出任何有意义的性能差异。那么,为什么真的要在意呢?最好单击“克隆编译器”按钮,这样我们就可以比较同一窗口中的版本。为什么你在这里只复制5个字节?我没有请用标准检查一下,但在我看来,这很可能是未定义的行为。
std::uint64\t
是一种可复制的类型,但您没有在这里复制整个对象表示形式……这是一个GCC错误吗?谢谢您的回答!这是我在GCC错误跟踪器@aschepler missing opt中关于这个主题的记录imization opportunity/次优代码生成被认为是一个bug。编写对象表示的一部分不是UB。Endianness是实现定义的;依赖它的代码可能不可移植,但不是UB。此外,
uint64\u t
是一种固定宽度类型,保证没有填充位或陷阱表示;这如果使用
unsigned long
,s也不会是UB,但如果使用该值,它可能会比您预期的更奇怪。请注意,您的版本也是endian敏感的。@PeterCordes我没有说写入对象的一部分是UB,但读取之后的对象不是标准所定义的。仅涵盖cop对整个对象进行填充(包括填充)。可以说它包含在中,但我不相信,而且实现定义的行为没有那么好,因为它可能因编译器而异。endian敏感度在注释中受到质疑,并被作者标记为不是问题。
uint64\u t
保证是固定宽度的64位类型,没有填充位。Its对象表示是纯二进制位值。写入其对象表示的低5字节不是UB,但endianness取决于实现。即,在任何给定的实现上,它必须对所有调用方一致工作。