[Embedded] Introduce DeferredCodeGen feature.

Introduce an experimental feature DeferredCodeGen, that defers the
generation of LLVM IR (and therefore object code) for all entities
within an Embedded Swift module unless they have explicitly requested
to not be emitted into the client (e.g., with
`@_neverEmitIntoClient`).

This feature is meant to generalize and subsume
-emit-empty-object-file, relying on lazy emission of entities rather
than abruptly ending the compilation pipeline before emitting any IR.

Part of rdar://158363967.
This commit is contained in:
Doug Gregor
2025-09-03 15:43:01 -07:00
parent 4f010f0fc7
commit ed93b46fa6
16 changed files with 97 additions and 24 deletions

View File

@@ -752,7 +752,7 @@ protected:
HasAnyUnavailableDuringLoweringValues : 1 HasAnyUnavailableDuringLoweringValues : 1
); );
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8, SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8,
/// If the module is compiled as static library. /// If the module is compiled as static library.
StaticLibrary : 1, StaticLibrary : 1,
@@ -821,7 +821,10 @@ protected:
SerializePackageEnabled : 1, SerializePackageEnabled : 1,
/// Whether this module has enabled strict memory safety checking. /// Whether this module has enabled strict memory safety checking.
StrictMemorySafety : 1 StrictMemorySafety : 1,
/// Whether this module uses deferred code generation in Embedded Swift.
DeferredCodeGen : 1
); );
SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2, SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,

View File

@@ -818,7 +818,7 @@ public:
Bits.ModuleDecl.IsConcurrencyChecked = value; Bits.ModuleDecl.IsConcurrencyChecked = value;
} }
/// Whether this module has enable strict memory safety checking. /// Whether this module has enabled strict memory safety checking.
bool strictMemorySafety() const { bool strictMemorySafety() const {
return Bits.ModuleDecl.StrictMemorySafety; return Bits.ModuleDecl.StrictMemorySafety;
} }
@@ -827,6 +827,15 @@ public:
Bits.ModuleDecl.StrictMemorySafety = value; Bits.ModuleDecl.StrictMemorySafety = value;
} }
/// Whether this module uses deferred code generation.
bool deferredCodeGen() const {
return Bits.ModuleDecl.DeferredCodeGen;
}
void setDeferredCodeGen(bool value = true) {
Bits.ModuleDecl.DeferredCodeGen = value;
}
bool isObjCNameLookupCachePopulated() const { bool isObjCNameLookupCachePopulated() const {
return Bits.ModuleDecl.ObjCNameLookupCachePopulated; return Bits.ModuleDecl.ObjCNameLookupCachePopulated;
} }

View File

@@ -324,6 +324,12 @@ EXPERIMENTAL_FEATURE(KeyPathWithMethodMembers, false)
// Whether to enable @_used and @_section attributes // Whether to enable @_used and @_section attributes
EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true) EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true)
// Whether to emit an Embedded Swift module with "deferred" code generation,
// meaning that the only code that will be emitted into the object file is
// code that was marked as "never emit into client". For everything else,
// Swift still store the SIL and emit it into the client only when used.
EXPERIMENTAL_FEATURE(DeferredCodeGen, true)
// Whether to compile scripts lazily in immediate mode // Whether to compile scripts lazily in immediate mode
EXPERIMENTAL_FEATURE(LazyImmediate, false) EXPERIMENTAL_FEATURE(LazyImmediate, false)

View File

@@ -147,6 +147,7 @@ class ExtendedValidationInfo {
unsigned AllowNonResilientAccess: 1; unsigned AllowNonResilientAccess: 1;
unsigned SerializePackageEnabled: 1; unsigned SerializePackageEnabled: 1;
unsigned StrictMemorySafety: 1; unsigned StrictMemorySafety: 1;
unsigned DeferredCodeGen: 1;
} Bits; } Bits;
public: public:
@@ -251,7 +252,14 @@ public:
void setStrictMemorySafety(bool val = true) { void setStrictMemorySafety(bool val = true) {
Bits.StrictMemorySafety = val; Bits.StrictMemorySafety = val;
} }
bool deferredCodeGen() const {
return Bits.DeferredCodeGen;
}
void setDeferredCodeGen(bool val = true) {
Bits.DeferredCodeGen = val;
}
bool hasCxxInteroperability() const { return Bits.HasCxxInteroperability; } bool hasCxxInteroperability() const { return Bits.HasCxxInteroperability; }
void setHasCxxInteroperability(bool val) { void setHasCxxInteroperability(bool val) {
Bits.HasCxxInteroperability = val; Bits.HasCxxInteroperability = val;

View File

@@ -84,6 +84,7 @@ UNINTERESTING_FEATURE(CodeItemMacros)
UNINTERESTING_FEATURE(PreambleMacros) UNINTERESTING_FEATURE(PreambleMacros)
UNINTERESTING_FEATURE(TupleConformances) UNINTERESTING_FEATURE(TupleConformances)
UNINTERESTING_FEATURE(SymbolLinkageMarkers) UNINTERESTING_FEATURE(SymbolLinkageMarkers)
UNINTERESTING_FEATURE(DeferredCodeGen)
UNINTERESTING_FEATURE(LazyImmediate) UNINTERESTING_FEATURE(LazyImmediate)
UNINTERESTING_FEATURE(MoveOnlyClasses) UNINTERESTING_FEATURE(MoveOnlyClasses)
UNINTERESTING_FEATURE(NoImplicitCopy) UNINTERESTING_FEATURE(NoImplicitCopy)

View File

@@ -784,6 +784,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
Bits.ModuleDecl.AllowNonResilientAccess = 0; Bits.ModuleDecl.AllowNonResilientAccess = 0;
Bits.ModuleDecl.SerializePackageEnabled = 0; Bits.ModuleDecl.SerializePackageEnabled = 0;
Bits.ModuleDecl.StrictMemorySafety = 0; Bits.ModuleDecl.StrictMemorySafety = 0;
Bits.ModuleDecl.DeferredCodeGen = 0;
// Populate the module's files. // Populate the module's files.
SmallVector<FileUnit *, 2> files; SmallVector<FileUnit *, 2> files;

View File

@@ -1511,6 +1511,9 @@ ModuleDecl *CompilerInstance::getMainModule() const {
MainModule->setSerializePackageEnabled(); MainModule->setSerializePackageEnabled();
if (Invocation.getLangOptions().hasFeature(Feature::StrictMemorySafety)) if (Invocation.getLangOptions().hasFeature(Feature::StrictMemorySafety))
MainModule->setStrictMemorySafety(true); MainModule->setStrictMemorySafety(true);
if (Invocation.getLangOptions().hasFeature(Feature::Embedded) &&
Invocation.getLangOptions().hasFeature(Feature::DeferredCodeGen))
MainModule->setDeferredCodeGen(true);
configureAvailabilityDomains(getASTContext(), configureAvailabilityDomains(getASTContext(),
Invocation.getFrontendOptions(), MainModule); Invocation.getFrontendOptions(), MainModule);

View File

@@ -1112,10 +1112,20 @@ bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) {
if (decl->isNeverEmittedIntoClient()) if (decl->isNeverEmittedIntoClient())
return false; return false;
// If the declaration is not from the main module, treat its definition as /// @_alwaysEmitIntoClient means that we have a non-unique definition.
// non-unique. if (decl->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
return true;
auto module = decl->getModuleContext(); auto module = decl->getModuleContext();
auto &ctx = module->getASTContext(); auto &ctx = module->getASTContext();
/// With deferred code generation, declarations are emitted as late as
/// possible, so they must have non-unique definitions.
if (module->deferredCodeGen())
return true;
// If the declaration is not from the main module, treat its definition as
// non-unique.
return module != ctx.MainModule && ctx.MainModule; return module != ctx.MainModule && ctx.MainModule;
} }

View File

@@ -710,6 +710,9 @@ public:
/// \c true if this module was built with strict memory safety. /// \c true if this module was built with strict memory safety.
bool strictMemorySafety() const { return Core->strictMemorySafety(); } bool strictMemorySafety() const { return Core->strictMemorySafety(); }
/// \c true if this module uses deferred code generation.
bool deferredCodeGen() const { return Core->deferredCodeGen(); }
/// Associates this module file with the AST node representing it. /// Associates this module file with the AST node representing it.
/// ///
/// Checks that the file is compatible with the AST module it's being loaded /// Checks that the file is compatible with the AST module it's being loaded

View File

@@ -226,6 +226,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
case options_block::STRICT_MEMORY_SAFETY: case options_block::STRICT_MEMORY_SAFETY:
extendedInfo.setStrictMemorySafety(true); extendedInfo.setStrictMemorySafety(true);
break; break;
case options_block::DEFERRED_CODE_GEN:
extendedInfo.setDeferredCodeGen(true);
break;
default: default:
// Unknown options record, possibly for use by a future version of the // Unknown options record, possibly for use by a future version of the
// module format. // module format.
@@ -1520,6 +1523,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
Bits.AllowNonResilientAccess = extInfo.allowNonResilientAccess(); Bits.AllowNonResilientAccess = extInfo.allowNonResilientAccess();
Bits.SerializePackageEnabled = extInfo.serializePackageEnabled(); Bits.SerializePackageEnabled = extInfo.serializePackageEnabled();
Bits.StrictMemorySafety = extInfo.strictMemorySafety(); Bits.StrictMemorySafety = extInfo.strictMemorySafety();
Bits.DeferredCodeGen = extInfo.deferredCodeGen();
MiscVersion = info.miscVersion; MiscVersion = info.miscVersion;
SDKVersion = info.sdkVersion; SDKVersion = info.sdkVersion;
ModuleABIName = extInfo.getModuleABIName(); ModuleABIName = extInfo.getModuleABIName();

View File

@@ -421,8 +421,11 @@ private:
/// Whether this module enabled strict memory safety. /// Whether this module enabled strict memory safety.
unsigned StrictMemorySafety : 1; unsigned StrictMemorySafety : 1;
/// Whether this module used deferred code generation.
unsigned DeferredCodeGen : 1;
// Explicitly pad out to the next word boundary. // Explicitly pad out to the next word boundary.
unsigned : 2; unsigned : 1;
} Bits = {}; } Bits = {};
static_assert(sizeof(ModuleBits) <= 8, "The bit set should be small"); static_assert(sizeof(ModuleBits) <= 8, "The bit set should be small");
@@ -696,6 +699,8 @@ public:
bool strictMemorySafety() const { return Bits.StrictMemorySafety; } bool strictMemorySafety() const { return Bits.StrictMemorySafety; }
bool deferredCodeGen() const { return Bits.DeferredCodeGen; }
/// How should \p dependency be loaded for a transitive import via \c this? /// How should \p dependency be loaded for a transitive import via \c this?
/// ///
/// If \p importNonPublicDependencies, more transitive dependencies /// If \p importNonPublicDependencies, more transitive dependencies

View File

@@ -987,7 +987,8 @@ namespace options_block {
CXX_STDLIB_KIND, CXX_STDLIB_KIND,
PUBLIC_MODULE_NAME, PUBLIC_MODULE_NAME,
SWIFT_INTERFACE_COMPILER_VERSION, SWIFT_INTERFACE_COMPILER_VERSION,
STRICT_MEMORY_SAFETY STRICT_MEMORY_SAFETY,
DEFERRED_CODE_GEN,
}; };
using SDKPathLayout = BCRecordLayout< using SDKPathLayout = BCRecordLayout<
@@ -1088,6 +1089,10 @@ namespace options_block {
STRICT_MEMORY_SAFETY STRICT_MEMORY_SAFETY
>; >;
using DeferredCodeGenLayout = BCRecordLayout<
DEFERRED_CODE_GEN
>;
using PublicModuleNameLayout = BCRecordLayout< using PublicModuleNameLayout = BCRecordLayout<
PUBLIC_MODULE_NAME, PUBLIC_MODULE_NAME,
BCBlob BCBlob

View File

@@ -864,6 +864,7 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(options_block, ALLOW_NON_RESILIENT_ACCESS); BLOCK_RECORD(options_block, ALLOW_NON_RESILIENT_ACCESS);
BLOCK_RECORD(options_block, SERIALIZE_PACKAGE_ENABLED); BLOCK_RECORD(options_block, SERIALIZE_PACKAGE_ENABLED);
BLOCK_RECORD(options_block, STRICT_MEMORY_SAFETY); BLOCK_RECORD(options_block, STRICT_MEMORY_SAFETY);
BLOCK_RECORD(options_block, DEFERRED_CODE_GEN);
BLOCK_RECORD(options_block, CXX_STDLIB_KIND); BLOCK_RECORD(options_block, CXX_STDLIB_KIND);
BLOCK_RECORD(options_block, PUBLIC_MODULE_NAME); BLOCK_RECORD(options_block, PUBLIC_MODULE_NAME);
BLOCK_RECORD(options_block, SWIFT_INTERFACE_COMPILER_VERSION); BLOCK_RECORD(options_block, SWIFT_INTERFACE_COMPILER_VERSION);
@@ -1177,6 +1178,11 @@ void Serializer::writeHeader() {
StrictMemorySafety.emit(ScratchRecord); StrictMemorySafety.emit(ScratchRecord);
} }
if (M->deferredCodeGen()) {
options_block::DeferredCodeGenLayout DeferredCodeGen(Out);
DeferredCodeGen.emit(ScratchRecord);
}
if (M->hasCxxInteroperability()) { if (M->hasCxxInteroperability()) {
options_block::HasCxxInteroperabilityEnabledLayout options_block::HasCxxInteroperabilityEnabledLayout
CxxInteroperabilityEnabled(Out); CxxInteroperabilityEnabled(Out);

View File

@@ -976,6 +976,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
M.setIsConcurrencyChecked(); M.setIsConcurrencyChecked();
if (loadedModuleFile->strictMemorySafety()) if (loadedModuleFile->strictMemorySafety())
M.setStrictMemorySafety(); M.setStrictMemorySafety();
if (loadedModuleFile->deferredCodeGen())
M.setDeferredCodeGen();
if (loadedModuleFile->hasCxxInteroperability()) { if (loadedModuleFile->hasCxxInteroperability()) {
M.setHasCxxInteroperability(); M.setHasCxxInteroperability();
M.setCXXStdlibKind(loadedModuleFile->getCXXStdlibKind()); M.setCXXStdlibKind(loadedModuleFile->getCXXStdlibKind());

View File

@@ -32,7 +32,7 @@
// RUN: %target-run %t/Application | %FileCheck %s // RUN: %target-run %t/Application | %FileCheck %s
// Test #2: Root is an "intermediate" library for everything // Test #2: Root is an "intermediate" library for everything
// RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -parse-as-library
@@ -41,26 +41,26 @@
// Test #3: ClientA as an "intermediate" library // Test #3: ClientA as an "intermediate" library
// RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-clang %target-clang-resource-dir-opt %t/Root.o %t/ClientA.o %t/ClientB.o %t/Application.o -o %t/Application // RUN: %target-clang %target-clang-resource-dir-opt %t/Root.o %t/ClientA.o %t/ClientB.o %t/Application.o -o %t/Application
// RUN: %target-run %t/Application | %FileCheck %s // RUN: %target-run %t/Application | %FileCheck %s
// Test #4: Root and ClientA as "intermediate" libraries // Test #4: Root and ClientA as "intermediate" libraries
// RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -parse-as-library
// RUN: %target-clang %target-clang-resource-dir-opt %t/Root.o %t/ClientA.o %t/ClientB.o %t/Application.o -o %t/Application // RUN: %target-clang %target-clang-resource-dir-opt %t/Root.o %t/ClientA.o %t/ClientB.o %t/Application.o -o %t/Application
// RUN: %target-run %t/Application | %FileCheck %s // RUN: %target-run %t/Application | %FileCheck %s
// Test #%: All "intermediate", all the time. Main drives code generation // Test #%: All "intermediate", all the time. Main drives code generation
// TODO: This requires -emit-empty-object-file to still emit the main symbol. // TODO: @main needs to drive the generation of code here.
// RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -emit-module -o %t/Root.o %t/Root.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientA.o %t/ClientA.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/ClientB.o %t/ClientB.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -emit-empty-object-file -parse-as-library // RUN: %target-swift-frontend -c -I %t -emit-module -o %t/Application.o %t/Application.swift -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library
// RUN-TODO: %target-clang %target-clang-resource-dir-opt %t/Root.o %t/ClientA.o %t/ClientB.o %t/Application.o -o %t/Application // RUN-TODO: %target-clang %target-clang-resource-dir-opt %t/Root.o %t/ClientA.o %t/ClientB.o %t/Application.o -o %t/Application
// RUN-TODO: %target-run %t/Application | %FileCheck %s // RUN-TODO: %target-run %t/Application | %FileCheck %s
@@ -68,6 +68,7 @@
// REQUIRES: swift_in_compiler // REQUIRES: swift_in_compiler
// REQUIRES: executable_test // REQUIRES: executable_test
// REQUIRES: swift_feature_Embedded // REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_DeferredCodeGen
//--- Root.swift //--- Root.swift
struct Point { struct Point {

View File

@@ -4,10 +4,10 @@
// Library module // Library module
// SIL checking // SIL checking
// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -emit-empty-object-file -emit-sil -emit-module-path %t/Modules/Library.swiftmodule -o - | %FileCheck -check-prefix LIBRARY-SIL %s // RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -emit-sil -emit-module-path %t/Modules/Library.swiftmodule -o - | %FileCheck -check-prefix LIBRARY-SIL %s
// IR checking to ensure we get the right weak symbols. // IR checking to ensure we get the right weak symbols.
// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -emit-empty-object-file -emit-ir -o - | %FileCheck -check-prefix LIBRARY-IR --dump-input-filter all %s // RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -emit-ir -o - | %FileCheck -check-prefix LIBRARY-IR --dump-input-filter all %s
// Application module // Application module
@@ -17,12 +17,14 @@
// REQUIRES: swift_in_compiler // REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_Embedded // REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_DeferredCodeGen
//--- Library.swift //--- Library.swift
// TODO: These are expected once "emit empty object file" becomes "be lazy". // TODO: Once global variables can be emitted lazily, these should be -NOT
// LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = linkonce_odr {{(protected |dllexport )?}}global // again, then show up in the application binary if we use them.
// LIBRARY-IR-NOT: @"$es16_emptyBoxStorageSi_Sitvp" = linkonce_odr {{(protected |dllexport )?}}global // LIBRARY-IR: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = weak_odr {{(protected |dllexport )?}}global
// LIBRARY-IR: @"$es16_emptyBoxStorageSi_Sitvp" = weak_odr {{(protected |dllexport )?}}global
// LIBRARY-IR-NOT: define {{.*}}@"$e7Library5helloSaySiGyF"() // LIBRARY-IR-NOT: define {{.*}}@"$e7Library5helloSaySiGyF"()
public func hello() -> [Int] { public func hello() -> [Int] {
@@ -47,13 +49,17 @@ private func throughPrivate() -> [Int] {
// LIBRARY-IR-NOT: unnecessary // LIBRARY-IR-NOT: unnecessary
public func unnecessary() -> Int64 { 5 } public func unnecessary() -> Int64 { 5 }
// LIBRARY-IR: define {{.*}} @"$e7Library14unusedYetThere
@_neverEmitIntoClient
public func unusedYetThere() -> Int64 { 5 }
// LIBRARY-IR-NOT: define swiftcc // LIBRARY-IR-NOT: define swiftcc
// LIBRARY-IR-NOT: define hidden swiftcc // LIBRARY-IR-NOT: define hidden swiftcc
// LIBRARY-IR-NOT: define {{.*}} @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5" // LIBRARY-IR-NOT: define {{.*}} @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5"
// LIBRARY-SIL: sil [ossa] @$e7Library5helloSaySiGyF // LIBRARY-SIL: sil @$e7Library5helloSaySiGyF
// LIBRARY-SIL: sil [ossa] @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array<Int> { // LIBRARY-SIL: sil @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array<Int> {
//--- Application.swift //--- Application.swift
import Library import Library