是否有可能使编译器将函数的返回结构值拆分为寄存器?

时间:2018-01-21 01:59:49

标签: c++ gcc optimization clang

我正在寻找一种方法,使用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),并将其作为参考传递,这应该符合寄存器大小。

0 个答案:

没有答案