Why is Xcode/LLVM optimising out the variable this method returns when compiling for ARM64
arm, compiler-optimization, llvm, objective-c, xcode
Solution
This issues seems to be a bug in the arm64 compiler; armv7(s) and x86 (Simulator) run the code without issue.
- (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;
}
What seems to be happening is the `free(values)` line is being reordered in the optimisation phase and run before `CGPointMake(...)` causing `pointer` to return with garbage values.
Thanks to Mike Ash, CRD and Rob Napier.
Problem
This is a known bug and is has been submitted to bugreporter.apple.com under bug id #16040090 NB: This issue only reproducible on a 64-bit (A7) iOS device. If run in the simulator or on a 32-bit device it works fine. Please note: This bug seems to be fixed in LLVM 5.1, this is the default compiler for Xcode 5.1 (currently in beta). I have a method `-pointValue` (see below), it works fine when compiled with the optimisation level set to `-O0`, but using `-Os` (the default for Release builds) the compiler optimises out the line that sets the variable `point`. `point` is used as the return value so any other method calling this gets random values. The issue can be fixed by declaring the `points` variable as `volatile`. However, why does the compiler think it can remove the line setting `points`? Is it something to do with how I have written the method? ``` - (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; } ``` NB: `-splitEncodedInteger:withShift:` uses malloc() to create a 2 element array that is retuned and then this memory is `free`'d by the callee. As requested, the code for `-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; } ``` Full source code of the encode categories can be found on GitHub. Example project As requested by several commenters I have created a simple test project. However, even after setting all the build settings to match the original project I myself cannot reproduce the issue. The bug only shows up on device. The only thing I can see different is when the project is run with full optimisation on, LLDB can read some of the variables, and trying to print them to the console I get this: ``` (CGSize) size = <no location, value may have been optimized out> ``` This is exactly what I get with my failing project but in that instance passing around one of these "optimised out" variables just gives random data (resulting in massive views being created [or failing to be created]). Below are screen shots of the example app running with -O0 and -Ofast respectively. Example app running with -O0 (no optimisations), you can see info on the variables Example app running with -Ofast (full optimisations), you cannot see info on the variables Running on device This is the output when running ton device with optimisations off: ``` 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 ``` This is the output when running on device with full optimisations: ``` 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 ```