Does guard hint the optimiser that this is the unlikely branch

For performance, the standard library seems to annotate branches with _slowPath(...) and _fastPath(...) to hint the optimiser which of the branches is the fast path. That then presumably tells LLVM how to lay out the code.

My question is, does guard someCondition else { ... } have the same effect as guard _slowPath(someCondition) else { ... } so implicitly gives a hint that this is the unlikely path?

Not today. I'd be reluctant to assume that, too; "guard" to me means that the condition must be satisfied for the rest of the function to make sense, but not necessarily that it's the common case.

(IIRC, it's also unclear how often _slowPath and _fastPath really make a difference, even in the standard library where such things can matter.)

4 Likes

They're not "exposed" in the generated API docs, but you can use them today, and I have, and I did notice a small difference. Something like 2-3% if memory serves.

You can't use them with if let, but we do have _onFastPath() which can work there. It would be nice to have an _onSlowPath(), too:

guard let value = anOptional else { _onSlowPath(); continue }

Of course you can do the same thing with _onFastPath() on the other branch...

(BTW, that isn't a real example. The compiler would probably catch that; I ended up re-writing that algorithm entirely due to other changes in the project and didn't bother to put optimiser hints in the new version... yet?)

Branch hints primarily affect instruction ordering in the generated assembly. Since guard is intended primarily for early-exit kinds of filters, it would make sense to me to hint the early-exit path so that it's moved out-of-line and the happy path remains contiguous. If we aren't already SILGen-ing guard blocks in that order to begin with, we should do that too.

5 Likes