【发布时间】:2014-03-05 14:16:14
【问题描述】:
这是一个已知错误,已在错误 ID #16040090
下提交给 bugreporter.apple.com注意:此问题只能在 64 位 (A7) iOS 设备上重现。如果在模拟器或 32 位设备上运行,它可以正常工作。
请注意:此错误似乎已在 LLVM 5.1 中修复,这是 Xcode 5.1 的默认编译器(目前处于测试阶段)。
我有一个方法-pointValue(见下文),它在优化级别设置为-O0 的情况下运行良好,但使用-Os(Release 构建的默认值)编译器会优化设置的行变量point。 point 用作返回值,因此任何其他调用它的方法都会获得随机值。
可以通过将points 变量声明为volatile 来解决此问题。但是,为什么编译器认为它可以删除行设置points?和我写方法有关系吗?
- (CGPoint)pointValue
{
ULongLong encodedPoint = [self unsignedLongLongValue];
ULongLong *values = [self splitEncodedInteger:encodedPoint withShift:SHIFT];
//volatile is required to prevent optimising out
volatile CGPoint point = CGPointMake(values[0], values[1]);
free(values); //clean up
return point;
}
注意: -splitEncodedInteger:withShift: 使用 malloc() 创建一个 2 元素数组,该数组被重新调整,然后此内存由被调用者 free'd。
根据要求,-splitEncodedInteger:withShift:的代码
- (ULongLong *)splitEncodedInteger:(ULongLong)encocedInteger withShift:(int)shiftValue
{
ULongLong *splitFloats = malloc(sizeof(ULongLong) * 2);
splitFloats[0] = (encocedInteger >> shiftValue);
splitFloats[1] = encocedInteger - ((encocedInteger >> shiftValue) << shiftValue);
return splitFloats;
}
编码类别的完整source code可以是found on GitHub。
示例项目
应几位评论者的要求,我创建了一个simple test project。 但是,即使在将所有构建设置设置为与原始项目匹配之后,我自己无法重现该问题。该错误仅显示在设备上。
我唯一能看到不同的是,当项目在完全优化的情况下运行时,LLDB 可以读取一些变量,并尝试将它们打印到控制台我得到这个:
(CGSize) size = <no location, value may have been optimized out>
这正是我在失败项目中得到的结果,但在这种情况下,传递这些“优化”变量之一只会给出随机数据(导致创建大量视图 [或创建失败])。
以下是分别使用 -O0 和 -Ofast 运行的示例应用的屏幕截图。
使用 -O0 运行的示例应用(无优化),您可以查看有关变量的信息
使用 -Ofast 运行的示例应用(完全优化),您无法查看有关变量的信息
在设备上运行
这是在 优化关闭的情况下运行 ton 设备时的输出:
2014-02-10 11:36:00.771 optimisation-bug[461:60b] *** Compiling with no optmisations, the code should work as expected ***
2014-02-10 11:36:00.773 optimisation-bug[461:60b] encodedRect: 50332672
2014-02-10 11:36:00.774 optimisation-bug[461:60b] encodedSize: 45089712
2014-02-10 11:36:00.775 optimisation-bug[461:60b] encodePoint: 2621480
2014-02-10 11:36:05.629 optimisation-bug[461:60b] rect: {{0, 0}, {768, 1024}}
2014-02-10 11:36:06.099 optimisation-bug[461:60b] size: {688, 944}
2014-02-10 11:36:06.101 optimisation-bug[461:60b] point: 40.000000, 40.000000
2014-02-10 11:36:06.103 optimisation-bug[461:60b] DONE
这是在具有全面优化的设备上运行时的输出:
2014-02-10 11:44:53.975 optimisation-bug[471:60b] >>> Compiling with -Os optmisations, the code should *NOT* work as expected <<<
2014-02-10 11:44:53.977 optimisation-bug[471:60b] encodedRect: 50332672
2014-02-10 11:44:53.977 optimisation-bug[471:60b] encodedSize: 45089712
2014-02-10 11:44:53.978 optimisation-bug[471:60b] encodePoint: 2621480
2014-02-10 11:44:58.176 optimisation-bug[471:60b] rect: {{1.3464973428307575e+19, 6174053600}, {1.3464973428307575e+19, 1.2554206452792682e+58}}
2014-02-10 11:44:58.178 optimisation-bug[471:60b] size: {1.3464973428307575e+19, 6174053568}
2014-02-10 11:44:58.180 optimisation-bug[471:60b] point: 13464973428307574784.000000, 6174053568.000000
2014-02-10 11:44:58.182 optimisation-bug[471:60b] DONE
【问题讨论】:
-
你对比过生成的程序集吗?你在这里所做的看起来没问题。问题可能不是你想的那样。否则,在我看来,它就像一个编译器错误。
-
@rjstelling - 在 10.8 上使用 Xcode 5.0.2,您的代码在没有 volatile 的情况下运行良好。调试器无法显示所有值,但这并不少见,但
NSLog确实如此。所以其他东西似乎会导致你的问题。顺便说一句,我建议您最好使用uint64作为您的类型,而不是假设unsigned long long是 64 位。还可以使用包含两个字段的struct,而不是mallocing 和freeing 两个元素的数组 -structs 是按值传递的,您不需要内存管理。 -
@rjstelling 您的问题的标题是“为什么 LLVM 会优化变量...”,在我看来,我链接的帖子中的答案给出了发生这种情况的各种情况,另外他们指出优化后的变量进入寄存器,因此仍然是一个值。 “优化出来”不破坏价值!因此,我的“重复”建议旨在暗示问题可能是其他问题,优化/易失性是一个红鲱鱼。
-
正如@CRD 所指出的,我试图用你的类别重现这个,但到目前为止我还没有看到它,无论是在输出中还是在程序集中。你有一个失败的明确测试用例吗?它是否可能仅在 32 位操作系统上失败? (CRD 和我正在 64 位操作系统上进行测试。)
-
@RobNapier 经Mike Ash 确认仅是 64 位问题。
标签: objective-c xcode arm llvm compiler-optimization