gpt4 book ai didi

c++ - 为什么使用三元运算符返回字符串会生成与在等效的 if/else block 中返回的代码截然不同的代码?

转载 作者:行者123 更新时间:2023-12-01 08:23:30 24 4
gpt4 key购买 nike

我正在使用编译器资源管理器,在使用类似这样的东西时,我偶然发现了三元运算符的一个有趣行为:

std::string get_string(bool b)
{
return b ? "Hello" : "Stack-overflow";
}
编译器为此生成的代码(clang trunk,带 -O3)是这样的:
get_string[abi:cxx11](bool):                 # @get_string[abi:cxx11](bool)
push r15
push r14
push rbx
mov rbx, rdi
mov ecx, offset .L.str
mov eax, offset .L.str.1
test esi, esi
cmovne rax, rcx
add rdi, 16 #< Why is the compiler storing the length of the string
mov qword ptr [rbx], rdi
xor sil, 1
movzx ecx, sil
lea r15, [rcx + 8*rcx]
lea r14, [rcx + 8*rcx]
add r14, 5 #< I also think this is the length of "Hello" (but not sure)
mov rsi, rax
mov rdx, r14
call memcpy #< Why is there a call to memcpy
mov qword ptr [rbx + 8], r14
mov byte ptr [rbx + r15 + 21], 0
mov rax, rbx
pop rbx
pop r14
pop r15
ret
.L.str:
.asciz "Hello"

.L.str.1:
.asciz "Stack-Overflow"
但是,编译器为以下代码段生成的代码要小得多,而且没有调用 memcpy ,并且不关心同时知道两个字符串的长度。它跳转到 2 个不同的标签
std::string better_string(bool b)
{
if (b)
{
return "Hello";
}
else
{
return "Stack-Overflow";
}
}
编译器为上述片段(带有 -O3 的 clang trunk)生成的代码是这样的:
better_string[abi:cxx11](bool):              # @better_string[abi:cxx11](bool)
mov rax, rdi
lea rcx, [rdi + 16]
mov qword ptr [rdi], rcx
test sil, sil
je .LBB0_2
mov dword ptr [rcx], 1819043144
mov word ptr [rcx + 4], 111
mov ecx, 5
mov qword ptr [rax + 8], rcx
ret
.LBB0_2:
movabs rdx, 8606216600190023247
mov qword ptr [rcx + 6], rdx
movabs rdx, 8525082558887720019
mov qword ptr [rcx], rdx
mov byte ptr [rax + 30], 0
mov ecx, 14
mov qword ptr [rax + 8], rcx
ret
相同的结果是当我使用三元运算符时:
std::string get_string(bool b)
{
return b ? std::string("Hello") : std::string("Stack-Overflow");
}
我想知道为什么第一个示例中的三元运算符会生成该编译器代码。我相信罪魁祸首在 const char[] .
P.S:GCC 会调用 strlen在第一个示例中,但 Clang 没有。
链接到编译器资源管理器示例: https://godbolt.org/z/Exqs6G
谢谢你的时间!
抱歉代码墙

最佳答案

这里的主要区别是第一个版本是 无分支 .
16 不是这里任何字符串的长度(较长的字符串,带 NUL,只有 15 个字节长);这是一个 偏移进入返回对象(其地址在RDI中传递以支持RVO),用于表示正在使用小字符串优化(注意缺少分配)。长度为5或5+1+8存放在R14中,存放在std::string中以及传递给 memcpy (连同 CMOVNE 选择的指针)加载实际的字符串字节。
另一个版本有一个明显的分支(尽管 std::string 结构的一部分已被提升到它上面)并且实际上确实明确地有 5 和 14,但是由于字符串字节已被包含为立即值(表示为整数)各种大小。
至于为什么这三个等效函数会产生两个不同版本的生成代码,我所能提供的只是优化器是迭代的和启发式 算法;他们无法独立于起点可靠地找到相同的“最佳” assembly 。

关于c++ - 为什么使用三元运算符返回字符串会生成与在等效的 if/else block 中返回的代码截然不同的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63327288/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com