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?
jrose
(Jordan Rose)
2
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
Karl
(👑🦆)
3
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?)
Joe_Groff
(Joe Groff)
4
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