[英]Can the optimizer elide assignment from 64bit to 32bit integer types?
鉴于这种:
uint64_t truncate(uint64_t num) {
uint32_t lessBits = static_cast<uint32_t>(num);
return static_cast<uint64_t>(lessBits);
}
编译器是否允许优化静态转换并保留完整的 64 位值,还是必须保留 32 位“截断”?
做一个快速的godbold检查,它会出现一个mov
eax
, ...
被使用,这意味着 32 位“截断”没有被优化掉。
语言如何涵盖这种情况? 我目前的猜测是这只是整数转换被完全定义并且编译器观察到这一点的情况,所以它不能省略分配/32位转换。
由于优化绝不能影响已定义的程序行为的原则,以及为了允许优化,标准必须将其行为可能影响的所有操作表征为未定义行为的推论,没有定义的情况下标准将允许实现进行您描述的那种替换。 如果一个实现作为“符合语言扩展”的一种形式,指定除除法/余数之外的整数计算永远不会产生任何副作用,除了产生可能会或可能不会在其正常范围内的可能被截断的值类型,然后使用 32 位int
和 64 位long
这样的实现,给出如下内容:
long test(int *arr, int count)
{
long total = 0;
int subtotal = 0;
for (int i=0; i<count; i++)
{
subtotal += arr[i];
total += subtotal;
}
return total;
}
可能会在闲暇时将小计保持为 32 位int
并在每次循环时将其符号扩展到 64 位,然后再将其添加到total
,或者它可以在从arr[i]
加载时对其进行符号扩展内存并将subtotal
保持为 64 位值,并且在溢出的情况下可能会观察到这种行为差异,因为实现的“符合语言扩展”。
请注意,遗憾的是没有办法邀请编译器对小于int
类型执行此类优化,因为实现需要记录有关如何将int
和unsigned
转换为较小有符号类型的一致规则,因此不允许简单地存储较小的类型在 32 位寄存器中输入类型而不截断并允许读取它们的整个值,即使这样做比截断更有效。
在 C 语言中,整数类型之间的转换是强制性的(除了 as-if 规则,这意味着编译器可以做任何它喜欢的事情,如果它没有任何区别。所以如果函数的每个返回值都被忽略或分配给 32 位整数,则允许编译器不进行转换。)
浮点类型之间的转换可能不是强制性的; 编译器可以自由使用比要求更高的精度。 但是,由于强制转换而导致的转换或由于对变量赋值而导致的转换是强制性的。 此外,还有一些预定义的宏可以让您检测编译器的作用。
所以
float x = 3.1;
float y = 3.2;
double d = x * y;
double e = (float) (x * y);
float z = x * y;
必须将 3.1f 和 3.2f 分配给 x 和 y。 x * y 可以以浮点或双精度计算,因此 d 可能有不同的结果。 e 和 z 不能。 (这是因为 double 的尾数位是浮点数的两倍以上,因此以无限精度计算 x*y,先舍入为 double 再舍入浮点数,产生的结果与仅舍入为浮点数相同。如果涉及 long double,事情可能会有所不同)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.