我正在寻找一种方法,使用CPU寄存器从函数返回我的结构的一个(第一个)字段,而不在堆栈上分配它。 假设我们有一个返回它的结构和函数:
template <typename T>
struct Pair {
int code;
T value;
};
Pair<int> FuncInt(bool const flag) {
return {flag ? 0 : 1, 42};
}
Pair<std::string> FuncString(bool const flag) {
return {flag ? 0 : 1, "DEADBEEF"};
}
auto UseInt(bool const flag) {
if (auto const rv = FuncInt(flag); !rv.code) {
return rv.value;
}
}
auto UseString(bool const flag) {
if (auto const rv = FuncString(flag); !rv.code) {
return rv.value;
}
}
我希望code
通过CPU寄存器返回(理想情况下);第二个成员value
可以使用堆栈。它适用于FuncInt
,但不适用于FuncString
。我的编译器(gcc-7.2)一直生成这个:
call FuncString[abi:cxx11](bool)
cmp DWORD PTR [rsp], 0
比较放置在堆栈上的code
。我的目的是避免从内存中冗余读取并使用寄存器,例如使用FuncInt
:
call FuncInt(bool)
test eax, eax
有没有办法告诉gcc(或clang)Pair
的实例应该(或至少可以)分成两个独立的变量并以最有效的方式返回?
我相信,它对导出的函数和多个目标文件根本不起作用,尽管FuncInt
仅适用于寄存器。但我仍然对单个目标文件案件感到好奇。
以下是一个示例:https://godbolt.org/g/ZXYn8z
换句话说,我希望Pair<std::string> FuncString(bool const flag)
表现得像int UseString(bool const flag, std::string &value)
那样利用C ++ 17的表现力,包括“结构化绑定”。
据我所知,这个问题非常类似于“标量替换聚合”,但是使用gcc优化器的选项并没有给我任何结果或见解。
更新:
除了必须是x86之外,我对目标操作系统和体系结构没有任何具体要求。如果有可能以一般方式完成它:我会很高兴知道;如果它只在非常特殊的环境中起作用:仍然很高兴知道。正如在这里的评论中提到的那样,如果用户需要,编译器不应该限制自己进行优化。
我通过了ABI规范,看起来这样的技巧只适用于std::pair<std::uint32_t, std::uint32_t>
之类的小结构,而且在我上面的示例中它确实适用于UseInt
函数。
问题是我的第二个参数大于寄存器的大小。但是,我希望让编译器使用copy elision,在调用者中分配值对象(我的样本中的std::string
),并将其作为参考传递,这应该符合寄存器大小。