6

Specifically, I have some Swift 3.0 logging functions that wrap all of their statements in an if that only executes when an operation on two static const values bridged in from ObjC has a nonzero result.

func logStuff(_ message: @autoclosure () -> String) {
    if a & b != 0 {
        // log stuff here...
    }
}

Variables a and b are declared in my bridging header like this:

static const NSUInteger a = <some literal>;
static const NSUInteger b = <some literal>;

Will the compiler elide the entire call to logStuff() when the result of a & b is zero and whole module optimization is enabled?

A specific answer to this question would be appreciated, but a way to easily see what optimizations are actually applied by LLVM in any situation would be ideal.

jbelkins
  • 470
  • 3
  • 15
  • You can kind of short circuit this question entirely: why not just use an established logging framework? – Alexander Nov 03 '16 at 16:37
  • Already using CocoaLumberjack. Trying to replicate the "fine-grained logging" described [here](https://github.com/CocoaLumberjack/CocoaLumberjack/blob/master/Documentation/FineGrainedLogging.md) for ObjC without incurring a performance hit in production. – jbelkins Nov 03 '16 at 16:41
  • The compiler has a few switches that will give you the results after various stages, e.g. `-emit-assembly`. – jscs Nov 03 '16 at 18:36

1 Answers1

0

If you build your own Swift compiler using your own LLVM compiled with instrumentation, you should be able to dump that info as described in the LLVM documentation Writing an LLVM Pass.

But optimization passes interact, can be run several times, and might not always do what you expect them to do. So you'd do better to check the specific cases you're concerned about experimentally and then inspecting the resulting binary.

Since it's a logging function and probably can be readily triggered dynamically, a (probably simpler) alternative to static inspection of the compiler output would be to run the executable under a debugger, set breakpoint on the function that you expect should not be called, and then carry out an action in the executable that would trigger a call if the call had not been optimized out.

Then, repeat the verification throughout the lifetime of the app, because the compiler and the source code continue to change. (Or decide that it's not a significant concern worth that degree of diligence.)

Jeremy W. Sherman
  • 35,901
  • 5
  • 77
  • 111