What is the advantage of saying your function should never be inlined?
Asked Answered
L

0

6

I understand Swift's inlining well. I know the nuances between the four function-inlining attributes. I use @inline(__always) a lot, especially when I'm just making sugary APIs like this:

public extension String {
    @inline(__always)
    var length: Int { count }
}

I do this because there's not really a cost involved in inlining it, but there would be the cost of an extra stack frame if it weren't inlined. For less-obvious sugar, I'll lean toward @inlinable andor @usableFromInline as needed.

However, one distinction vexes me. The two possible arguments to @inline are never and __always. Despite the lack of actual documentation, this choice of spelling here acts as a sort of self-documentation, implying that if you are going to use one of these, you should lean toward never, and __always is discouraged.

But why is this the direction the Swift language designers encourage? As far as I know, if no attribute is applied at all, then this is the behavior:

  • If a function (et al) is used within the module in which it's declared, the compiler might choose to inline it or not, depending on which would produce better code (by some measure)
  • If that function (et al) is used outside the module, its implementation is not exposed in a way that allows it to be inlined, so it is never inlined.

So, it seems most of the time, not-inlining is the default. That's fine and dandy, I have no problem with that on the surface; don't bloat the executable any more than you need to.

But then, I've never had a reason to think @inline(never) is useful. From what I understand, the only reason I would use @inline(never) is if I've noticed that the Swift compiler is choosing to inline a non-annotated function too much, and it's bloating my executable. This seems like a super-niche occurrence:

  1. My software is running fine
  2. The Swift compiler's algorithm for deciding whether to inline something is not making the right choice for my code
  3. I care about the size of the binary so much that I'm inspecting it closely enough to discover that a function is being inlined automatically too much
  4. The problem is only in code that I've written into my own module; not code I'm using from some other module

Or, as Rob said in the comments, if you're going through some disassembly and automatic inlining makes it hard to read.

I can't imagine that these are the use cases which the Swift language designers had in mind when designing this attribute. Especially since Swift is not meant for embedded systems, binary size (and the (dis)assembly in general) isn't really that much of a concern. I've never seen an unreasonably-large Swift binary anyway (>50MB).

So why is never encouraged more than __always? I often run into reasons why I should force a function to be inlined, but I've not yet seen a reason to force a function to be stacked, at least in my own work.

Luxate answered 12/3, 2020 at 20:24 Comment(4)
There might be other reasons for non-inlinable (e.g., SE-0260 contemplates it re ABI stability). Second, while one might have code that can't be inlined, it's less obvious that we’d have code that must be inlined, even when not optimized or when optimized “for size” rather than “for speed”. Regardless, the docs seem to only contemplate @inlinable, not suggesting either never or __always.Truckle
That's a great point about ABI stability. I skimmed the document you linked and didn't see it mention how inline code might be bad for stability (in fact, it seems to encourage it?). Most of your other points, I tried to elucidate in my question; nice to see them rephrased so others can understand too 🙂Luxate
FWIW, I stumbled across another use case for @inline(never). I was going through some disassembly recently, and all that automatic inlining made it much harder to read. Adding @inline(never) to some called functions replaced a lot of noise with a single call.Truckle
I'll add that to the reasons. Still doesn't explain why never is plain and __always is double-underscore-discouragedLuxate

© 2022 - 2024 — McMap. All rights reserved.