编译器将 cpu 寄存器中这样的结构传递给函数是否有意义?
-
26-09-2019 - |
题
我想知道某种结构是否包含多个原语,但其总大小小于或等于单个 cpu 寄存器(如 4 字节寄存器)的大小,编译器将其放入是否有意义当通过值或对函数的引用传递它时,在这些 4 字节寄存器之一中,而不是在被调用者堆栈上复制它或传递指向它的指针,并且通常在将多个原语传递给函数时,例如传入CPU寄存器的数组或结构会派上用场吗?
这种结构的示例:
struct sample{
public:
char char1;
char char2;
};
将结构传递给函数的示例:
void someFunc(const sample input){
//whatever
}
void someFunc(sample input){
//whatever
}
void someFunc(sample & input){
//whatever
}
void someFunc(const sample & input){
//whatever
}
解决方案
是的。许多编译器都有一个特殊的关键字或类型属性,您可以使用它们来指定应该在寄存器中而不是在堆栈上传递结构。它在具有许多寄存器和深度管道的处理器(例如 PowerPC)上更为常见,并且可以在将值写入内存然后立即将其读回导致管道停顿的架构中实现巨大的性能改进。
通常,您只会将它用于与本机寄存器大小相同的结构。特别是,它对于具有宽 SIMD 寄存器(一次可以传递 16 个字节或更多)的处理器非常有用。这将让您在一个寄存器上传递(例如)一个 4 维向量(四个浮点数)。 AMD 的系统 V 是允许这样做的 x86 ABI 的示例。
一个不同的例子是 GCC 的 d64_abi 类型属性,它告诉 PowerPC 在可能的情况下在寄存器上传递结构,而不是在堆栈上。(这是 达尔文阿比).
typedef struct {
int a;
float f;
char c;
} __attribute__ ((d64_abi)) Thingy;
Thingy foo( Thingy t );
在上面的例子中,对 Foo 的调用会将 Thingy 传递到一个浮点寄存器和两个 int 寄存器上,而不是将其写入堆栈并再次读取。返回值以相同的方式返回到寄存器。
我从未见过编译器可以自动执行此操作,而无需您告知,但可能存在这样的编译器。
其他提示
这在应用程序二进制接口(ABI)的你的执行环境来定义。该标准不说关于处理器寄存器任何当一个函数被调用,因此它是合法的创建,其中小结构被打包成一个单一的处理器寄存器的环境。
有关的基准部,它们极有可能作为指针传递无论如何,因为所调用的函数内的参考的地址被服用时,它必须解析为被引用的对象的地址。
在某些平台上(如i386的,我知道这是古老的,但是这就是我长大了;)这当然是有道理的它传递在寄存器中,因为推从堆栈中弹出采取了很多(3间说-6倍以上)的CPU周期由寄存器传递。所以编译器会做好优化这一点。
我能想象还有其他的架构相比较也没关系。或者,如果寄存器是在使用其产生更多的改善等的优化,它没有意义的,将它们用于此。
什么架构是您使用/目标,或者是你在一般要求?
我觉得有编译器将通过荚寄存器,即使他们是struct
s。