Skip to content

[Embedded] Introduce a new linkage model for embedded Swift #83432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

DougGregor
Copy link
Member

@DougGregor DougGregor commented Jul 30, 2025

This linkage model gives symbols generated in Embedded Swift
LLVM's linkonce_odr linkage (which allows the linker to merge
duplicates) unless they specifically need to be emitted as strong
symbols in the object. That fits better with creating and using static
libraries with Embedded Swift, and essentially maps to the idea of
"header-only" libraries in C and C++.

Introduce the attribute @alwaysEmitIntoObjectFile that forces code for
the symbol to be generated into the generated object file as a
non-mergeable symbol. Anything it depends on will also be emitted into
the object file, most of which will be via mergeable symbols based on
the rule above. Again, as a C/C++ analogy, this is like putting the
code into a ".c" or ".cpp" file, which will then include any
header-only code it depends on as well.

@alwaysEmitIntoObjectFile also suppresses SIL serialization for that
symbol, completely hiding the definition of the function from clients
of the module. This provides a rudimentary form of implementation
hiding that is common in "Desktop" Swift but was not available in
Embedded Swift.

All of this is behind an experimental feature flag,
EmbeddedLinkageModel, but is intended to subsume the existing
linkage model for Embedded Swift (which emits everying as a
non-mergeable symbol, so it doesn't work for static libraries), the
"mergeable symbols" experimental feature that's the existing model but
with "weak_odr" LLVM linkage, and the "-emit-empty-object-file" flag
(which emits nothing to the object file, and only works for libraries
but has no control).

@rauhul rauhul added the embedded Embedded Swift label Jul 30, 2025
if (F->getModule().getASTContext().LangOpts.hasFeature(
Feature::EmbeddedLinkageModel) &&
F->getDeclRef().isEmittedToObjectFile())
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bypassing the SIL serialization model. Instead, can you just set the SILFunction's SerializedKind accordingly? Then, e.g. SIL verification can catch problems, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can certainly do that in addition, but I can't do it instead because it'll immediately be overridden by the -sil-serialize-all just below.

@rauhul rauhul moved this to Investigate in Embedded Swift Jul 30, 2025
@rauhul
Copy link
Member

rauhul commented Jul 30, 2025

Umbrella: #83433

@DougGregor DougGregor force-pushed the embedded-linkage-model branch from 17dcafe to 89ae741 Compare July 31, 2025 17:30
This linkage model gives symbols generated in Embedded Swift
LLVM's linkonce_odr linkage (which allows the linker to merge
duplicates) unless they specifically need to be emitted as strong
symbols in the object. That fits better with creating and using static
libraries with Embedded Swift, and essentially maps to the idea of
"header-only" libraries in C and C++.

Introduce the attribute @alwaysEmitIntoObjectFile that forces code for
the symbol to be generated into the generated object file as a
non-mergeable symbol. Anything it depends on will also be emitted into
the object file, most of which will be via mergeable symbols based on
the rule above. Again, as a C/C++ analogy, this is like putting the
code into a ".c" or ".cpp" file, which will then include any
header-only code it depends on as well.

@alwaysEmitIntoObjectFile also suppresses SIL serialization for that
symbol, completely hiding the definition of the function from clients
of the module. This provides a rudimentary form of implementation
hiding that is common in "Desktop" Swift but was not available in
Embedded Swift.

All of this is behind an experimental feature flag,
EmbeddedLinkageModel, but is intended to subsume the existing
linkage model for Embedded Swift (which emits everying as a
non-mergeable symbol, so it doesn't work for static libraries), the
"mergeable symbols" experimental feature that's the existing model but
with "weak_odr" LLVM linkage, and the "-emit-empty-object-file" flag
(which emits nothing to the object file, and only works for libraries
but has no control).
@DougGregor DougGregor force-pushed the embedded-linkage-model branch from 89ae741 to 14330e7 Compare July 31, 2025 17:33
Put the use of this attribute behind the `AlwaysEmitIntoObjectFile`
experimental feature for the moment.
EmbeddedLeafLibrary infers @alwaysEmitInObjectFile for all public and
open entities in the module to which it is applied. Anything else will
retain linkonce_odr (mergeable) semantics. This allows the module to
"seal off" the Swift code such that the resulting object file can be
linked along with normal C code.

With this are a number of important bug fixes to the core of the new
Embedded Swift linkages model, including:
* Definitions from imported modules always get linkonce_odr linkage,
because they're likely to end up being duplicated by different clients
of the imported module file.
* Global variables also get linkonce_odr linkage unless they are
@alwaysEmitInObjectFile.

Now, building a library with the new embedded linkage model, by
default, produces effectively no symbols in the object file other than
linkonce_odr global variables. Symbols that are marked with
@alwaysEmitInObjectFile, or that have it inferred via
EmbeddedLeafLibrary, have strong definitions. Everything they depend
on is pulled in as a linkonce_odr symbol.
The main entry point cannot be discarded. Always emit it as a non-weak
symbol.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
embedded Embedded Swift
Projects
Status: Investigate
Development

Successfully merging this pull request may close these issues.

3 participants