Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does inlining work with external libraries? (Swift)

Tags:

ios

swift

llvm

The attribute @inline(__always) forces the compiler to inline a particular function. How is code provided by external libraries inlined in one's project? Does the compiler actually copy code segments from the library's executable?

like image 918
Vatsal Manot Avatar asked Feb 01 '16 10:02

Vatsal Manot


1 Answers

As far as I'm aware, @inline(__always) means that the function (or similar) is always inlined, no matter what. That means that its symbols are exposed in the compiled module so they can be inlined by projects consuming that module. Hence the "always".

This is largely an undocumented attribute, with the only official references I can find being in some stdlib devs' internal  documentation, not even describing its behavior directly. The best unofficial documentation I can find is Vandad Nahavandipoor's disassembly-confirmed investigation into its behavior, which doesn't attempt to confirm the cross-module use case you are concerned with.


In Swift 4.2, @inlinable and @usableFromInline were introduced to finish this story.

My understanding:

  • @inline(__always) forces functions (et al) to be inlined every time no matter where they're declared or used
  • @inlinable allows functions (et al) in a module to be inlined into calling code in that module, or calling code using that module, if the compiler deems it necessary
  • @usableFromInline allows functions (et al) internal to a module to be inlined into @inlinable calling code that's also in that module, if the compiler deems it necessary. Unlike @inlinable, these must be internal; they cannot be public

According to Swift.org:

inlinable

Apply this attribute to a function, method, computed property, subscript, convenience initializer, or deinitializer declaration to expose that declaration’s implementation as part of the module’s public interface. The compiler is allowed to replace calls to an inlinable symbol with a copy of the symbol’s implementation at the call site.

Inlinable code can interact with public symbols declared in any module, and it can interact with internal symbols declared in the same module that are marked with the usableFromInline attribute. Inlinable code can’t interact with private or fileprivate symbols.

This attribute can’t be applied to declarations that are nested inside functions or to fileprivate or private declarations. Functions and closures that are defined inside an inlinable function are implicitly inlinable, even though they can’t be marked with this attribute.

usableFromInline

Apply this attribute to a function, method, computed property, subscript, initializer, or deinitializer declaration to allow that symbol to be used in inlinable code that’s defined in the same module as the declaration. The declaration must have the internal access level modifier. A structure or class marked usableFromInline can use only types that are public or usableFromInline for its properties. An enumeration marked usableFromInline can use only types that are public or usableFromInline for the raw values and associated values of its cases.

Like the public access level modifier, this attribute exposes the declaration as part of the module’s public interface. Unlike public, the compiler doesn’t allow declarations marked with usableFromInline to be referenced by name in code outside the module, even though the declaration’s symbol is exported. However, code outside the module might still be able to interact with the declaration’s symbol by using runtime behavior.

Declarations marked with the inlinable attribute are implicitly usable from inlinable code. Although either inlinable or usableFromInline can be applied to internal declarations, applying both attributes is an error.

like image 168
Ky. Avatar answered Oct 28 '22 15:10

Ky.