最近我看到了一种编译器是如何将一个类的两个32位整数属性值合并并存储为64位整数的。我的问题是,为什么要这样做?在合并整数时有什么优势吗?
例如,如果我们有以下的类属性:
class FooBar {
int x = 1;
int y = 100;
}
所以,与其
i32 = 00000001
i32 = 01100100
我们得到:
i64 = 0000000101100100
为什么要将它们结合起来?
最近我看到了一种编译器是如何将一个类的两个32位整数属性值合并并存储为64位整数的。我的问题是,为什么要这样做?在合并整数时有什么优势吗?
例如,如果我们有以下的类属性:
class FooBar {
int x = 1;
int y = 100;
}
i32 = 00000001
i32 = 01100100
我们得到:
i64 = 0000000101100100
为什么要将它们结合起来?
现有的回答和评论,虽然部分正确,但错失了这种优化的重点。它是用一条指令(使用64位数据)替换两条指令(使用32位数据)。这将导致代码大小略微减小,并可能减少执行时间。
编译器使用一条64位指令初始化两个变量(因为它们共享连续的内存地址)。这些变量是独立的,将分别访问。不需要移位或掩码。
在构造函数中经常看到这种情况,当多个成员被初始化时。一个常见的情况是零初始化,在这种情况下,编译器将清零一个寄存器,然后使用该值来初始化多个成员,通过一次更大的写操作将连续的内存地址组合在一起(例如,通过写入16位短零值而不是两个8位字节)。
我认为你正在观察一种优化。英特尔指令(例如PADDSW
)假设有多个打包的操作数。
https://en.wikipedia.org/wiki/X86_instruction_listings
在64位架构缓存中,只使用1个条目也有好处。
如果您只想要其中一个值,则解包会产生成本,但我怀疑运行的任何代码优化器都会估计到通过打包值可以获得更好的节省。
以前,将C结构的所有成员都对齐到字边界是很正常的。也就是说,单个char
和一个int
不会被打包,而是对齐到机器的字大小。因此,struct { char, int}
的 sizeof(..)
将为8字节。我猜这种情况发生了改变?
非常有趣。
PAD...
指令用于SIMD。打包的值都是相同类型的。解包没有成本,因为单个值仍然具有正常地址。 - JDługosz