mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Embedded] Emit weak definitions for imported symbols
When Embedded Swift emits a symbol that was imported from another module, ensure that the symbol is emitted as a weak definition. This way, importing the same module (and using its symbol) into several different modules doesn't cause duplicate-symbol errors at link time. Rather, the linker will merge the different symbol definitions. This makes Embedded Swift libraries work without resorting to `-mergeable-symbols` or `-emit-empty-object-file`.
This commit is contained in:
@@ -1850,6 +1850,14 @@ public:
|
||||
bool isTypeKind() const { return isTypeKind(getKind()); }
|
||||
|
||||
bool isAlwaysSharedLinkage() const;
|
||||
|
||||
/// Whether the link entity's definitions must be considered non-unique.
|
||||
///
|
||||
/// This applies only in the Embedded Swift linkage model, and is used for
|
||||
/// any symbols that have not been explicitly requested to have unique
|
||||
/// definitions (e.g., with @_used).
|
||||
bool hasNonUniqueDefinition() const;
|
||||
|
||||
#undef LINKENTITY_GET_FIELD
|
||||
#undef LINKENTITY_SET_FIELD
|
||||
|
||||
|
||||
@@ -399,6 +399,14 @@ struct SILDeclRef {
|
||||
/// True if the function has the @backDeployed attribute.
|
||||
bool isBackDeployed() const;
|
||||
|
||||
/// True if this entity should have a non-unique definition based on the
|
||||
/// embedded linkage model.
|
||||
bool hasNonUniqueDefinition() const;
|
||||
|
||||
/// True if the declaration should have a non-unique definition based on the
|
||||
/// embedded linkage model.
|
||||
static bool declHasNonUniqueDefinition(const ValueDecl *decl);
|
||||
|
||||
/// Return the expected linkage for a definition of this declaration.
|
||||
SILLinkage getDefinitionLinkage() const;
|
||||
|
||||
|
||||
@@ -659,6 +659,10 @@ public:
|
||||
|
||||
bool isNoReturnFunction(TypeExpansionContext context) const;
|
||||
|
||||
/// True if this function should have a non-unique definition based on the
|
||||
/// embedded linkage model.
|
||||
bool hasNonUniqueDefinition() const;
|
||||
|
||||
/// Unsafely rewrite the lowered type of this function.
|
||||
///
|
||||
/// This routine does not touch the entry block arguments
|
||||
@@ -916,6 +920,10 @@ public:
|
||||
return swift::isAvailableExternally(getLinkage());
|
||||
}
|
||||
|
||||
/// Helper method that determines whether this SILFunction is a Swift runtime
|
||||
/// function, such as swift_retain.
|
||||
bool isSwiftRuntimeFunction() const;
|
||||
|
||||
/// Helper method which returns true if the linkage of the SILFunction
|
||||
/// indicates that the object's definition might be required outside the
|
||||
/// current SILModule.
|
||||
|
||||
@@ -151,6 +151,10 @@ public:
|
||||
/// might be referenced from outside the current compilation unit.
|
||||
bool isPossiblyUsedExternally() const;
|
||||
|
||||
/// True if this variable should have a non-unique definition based on the
|
||||
/// embedded linkage model.
|
||||
bool hasNonUniqueDefinition() const;
|
||||
|
||||
/// Returns true if this global variable should be preserved so it can
|
||||
/// potentially be inspected by the debugger.
|
||||
bool shouldBePreservedForDebugger() const;
|
||||
|
||||
@@ -1156,9 +1156,17 @@ static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
|
||||
f.getLoweredFunctionType()->getSubstGenericSignature()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (f.isPossiblyUsedExternally())
|
||||
|
||||
if (f.isPossiblyUsedExternally()) {
|
||||
// Under the embedded linkage model, if it has a non-unique definition,
|
||||
// treat it lazily.
|
||||
if (f.hasNonUniqueDefinition() && !f.isSwiftRuntimeFunction()
|
||||
&& !f.markedAsUsed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.getDynamicallyReplacedFunction())
|
||||
return false;
|
||||
@@ -2244,7 +2252,8 @@ void IRGenerator::emitEntryPointInfo() {
|
||||
static IRLinkage
|
||||
getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
|
||||
SILLinkage linkage, ForDefinition_t isDefinition,
|
||||
bool isWeakImported, bool isKnownLocal = false) {
|
||||
bool isWeakImported, bool isKnownLocal,
|
||||
bool hasNonUniqueDefinition) {
|
||||
#define RESULT(LINKAGE, VISIBILITY, DLL_STORAGE) \
|
||||
IRLinkage{llvm::GlobalValue::LINKAGE##Linkage, \
|
||||
llvm::GlobalValue::VISIBILITY##Visibility, \
|
||||
@@ -2275,7 +2284,9 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
|
||||
case SILLinkage::Package: {
|
||||
auto linkage = llvm::GlobalValue::ExternalLinkage;
|
||||
|
||||
if (info.MergeableSymbols)
|
||||
if (hasNonUniqueDefinition)
|
||||
linkage = llvm::GlobalValue::WeakODRLinkage;
|
||||
else if (info.MergeableSymbols)
|
||||
linkage = llvm::GlobalValue::WeakODRLinkage;
|
||||
|
||||
return {linkage, PublicDefinitionVisibility,
|
||||
@@ -2293,6 +2304,8 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
|
||||
: RESULT(External, Hidden, Default);
|
||||
|
||||
case SILLinkage::Hidden:
|
||||
if (hasNonUniqueDefinition)
|
||||
return RESULT(WeakODR, Hidden, Default);
|
||||
if (info.MergeableSymbols)
|
||||
return RESULT(WeakODR, Hidden, Default);
|
||||
|
||||
@@ -2301,7 +2314,7 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
|
||||
case SILLinkage::Private: {
|
||||
if (info.forcePublicDecls() && !isDefinition)
|
||||
return getIRLinkage(name, info, SILLinkage::PublicExternal, isDefinition,
|
||||
isWeakImported, isKnownLocal);
|
||||
isWeakImported, isKnownLocal, hasNonUniqueDefinition);
|
||||
|
||||
auto linkage = info.needLinkerToMergeDuplicateSymbols()
|
||||
? llvm::GlobalValue::LinkOnceODRLinkage
|
||||
@@ -2357,7 +2370,8 @@ void irgen::updateLinkageForDefinition(IRGenModule &IGM,
|
||||
auto IRL =
|
||||
getIRLinkage(global->hasName() ? global->getName() : StringRef(),
|
||||
linkInfo, entity.getLinkage(ForDefinition), ForDefinition,
|
||||
weakImported, isKnownLocal);
|
||||
weakImported, isKnownLocal,
|
||||
entity.hasNonUniqueDefinition());
|
||||
ApplyIRLinkage(IRL).to(global);
|
||||
|
||||
LinkInfo link = LinkInfo::get(IGM, entity, ForDefinition);
|
||||
@@ -2410,7 +2424,8 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo,
|
||||
bool weakImported = entity.isWeakImported(swiftModule);
|
||||
result.IRL = getIRLinkage(result.Name, linkInfo,
|
||||
entity.getLinkage(isDefinition), isDefinition,
|
||||
weakImported, isKnownLocal);
|
||||
weakImported, isKnownLocal,
|
||||
entity.hasNonUniqueDefinition());
|
||||
result.ForDefinition = isDefinition;
|
||||
return result;
|
||||
}
|
||||
@@ -2421,7 +2436,8 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, StringRef name,
|
||||
LinkInfo result;
|
||||
result.Name += name;
|
||||
result.IRL = getIRLinkage(name, linkInfo, linkage, isDefinition,
|
||||
isWeakImported, linkInfo.Internalize);
|
||||
isWeakImported, linkInfo.Internalize,
|
||||
/*hasNonUniqueDefinition=*/false);
|
||||
result.ForDefinition = isDefinition;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1734,3 +1734,31 @@ bool LinkEntity::isAlwaysSharedLinkage() const {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LinkEntity::hasNonUniqueDefinition() const {
|
||||
if (isDeclKind(getKind())) {
|
||||
auto decl = getDecl();
|
||||
return SILDeclRef::declHasNonUniqueDefinition(decl);
|
||||
}
|
||||
|
||||
if (hasSILFunction()) {
|
||||
return getSILFunction()->hasNonUniqueDefinition();
|
||||
}
|
||||
|
||||
if (getKind() == Kind::SILGlobalVariable ||
|
||||
getKind() == Kind::ReadOnlyGlobalObject)
|
||||
return getSILGlobalVariable()->hasNonUniqueDefinition();
|
||||
|
||||
if (getKind() == Kind::TypeMetadata) {
|
||||
// For a nominal type, check its declaration.
|
||||
CanType type = getType();
|
||||
if (auto nominal = type->getAnyNominal()) {
|
||||
return SILDeclRef::declHasNonUniqueDefinition(nominal);
|
||||
}
|
||||
|
||||
// All other type metadata is nonuniqued.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -571,6 +571,7 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) {
|
||||
case Kind::AsyncEntryPoint:
|
||||
llvm_unreachable("Already handled");
|
||||
}
|
||||
|
||||
return Limit::None;
|
||||
}
|
||||
|
||||
@@ -1089,6 +1090,25 @@ bool SILDeclRef::isBackDeployed() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SILDeclRef::hasNonUniqueDefinition() const {
|
||||
if (auto decl = getDecl())
|
||||
return declHasNonUniqueDefinition(decl);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) {
|
||||
// This function only forces the issue in embedded.
|
||||
if (!decl->getASTContext().LangOpts.hasFeature(Feature::Embedded))
|
||||
return false;
|
||||
|
||||
// If the declaration is not from the main module, treat its definition as
|
||||
// non-unique.
|
||||
auto module = decl->getModuleContext();
|
||||
auto &ctx = module->getASTContext();
|
||||
return module != ctx.MainModule && ctx.MainModule;
|
||||
}
|
||||
|
||||
bool SILDeclRef::isForeignToNativeThunk() const {
|
||||
// If this isn't a native entry-point, it's not a foreign-to-native thunk.
|
||||
if (isForeign)
|
||||
|
||||
@@ -553,6 +553,24 @@ bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {
|
||||
.isNoReturnFunction(getModule(), context);
|
||||
}
|
||||
|
||||
bool SILFunction::hasNonUniqueDefinition() const {
|
||||
// Non-uniqueness is a property of the Embedded linkage model.
|
||||
if (!getASTContext().LangOpts.hasFeature(Feature::Embedded))
|
||||
return false;
|
||||
|
||||
// If this is for a declaration, ask it.
|
||||
if (auto declRef = getDeclRef()) {
|
||||
return declRef.hasNonUniqueDefinition();
|
||||
}
|
||||
|
||||
// If this function is from a different module than the one we are emitting
|
||||
// code for, then it must have a non-unique definition.
|
||||
if (getParentModule() != getModule().getSwiftModule())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ResilienceExpansion SILFunction::getResilienceExpansion() const {
|
||||
// If a function definition is in another module, and
|
||||
// it was serialized due to package serialization opt,
|
||||
@@ -1016,6 +1034,17 @@ bool SILFunction::hasValidLinkageForFragileRef(SerializedKind_t callerSerialized
|
||||
return hasPublicOrPackageVisibility(getLinkage(), /*includePackage*/ true);
|
||||
}
|
||||
|
||||
bool SILFunction::isSwiftRuntimeFunction() const {
|
||||
if (!getName().starts_with("swift_") &&
|
||||
!getName().starts_with("_swift_"))
|
||||
return false;
|
||||
|
||||
auto module = getParentModule();
|
||||
return !module ||
|
||||
module->getName().str() == "Swift" ||
|
||||
module->getName().str() == "_Concurrency";
|
||||
}
|
||||
|
||||
bool
|
||||
SILFunction::isPossiblyUsedExternally() const {
|
||||
auto linkage = getLinkage();
|
||||
@@ -1046,6 +1075,11 @@ SILFunction::isPossiblyUsedExternally() const {
|
||||
hasOpaqueResultTypeWithAvailabilityConditions())
|
||||
return true;
|
||||
|
||||
// All Swift runtime functions can be used externally.
|
||||
if (getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
|
||||
isSwiftRuntimeFunction())
|
||||
return true;
|
||||
|
||||
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,14 @@ bool SILGlobalVariable::isPossiblyUsedExternally() const {
|
||||
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
|
||||
}
|
||||
|
||||
bool SILGlobalVariable::hasNonUniqueDefinition() const {
|
||||
auto decl = getDecl();
|
||||
if (!decl)
|
||||
return false;
|
||||
|
||||
return SILDeclRef::declHasNonUniqueDefinition(decl);
|
||||
}
|
||||
|
||||
bool SILGlobalVariable::shouldBePreservedForDebugger() const {
|
||||
if (getModule().getOptions().OptMode != OptimizationMode::NoOptimization)
|
||||
return false;
|
||||
|
||||
@@ -950,7 +950,9 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
|
||||
}
|
||||
serializeFunction(callee, canSerializeFlags);
|
||||
assert(isSerializedWithRightKind(M, callee) ||
|
||||
isPackageOrPublic(callee->getLinkage()));
|
||||
isPackageOrPublic(callee->getLinkage()) ||
|
||||
M.getSwiftModule()->getASTContext().LangOpts.hasFeature(
|
||||
Feature::Embedded));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1005,7 +1007,10 @@ void CrossModuleOptimization::keepMethodAlive(SILDeclRef method) {
|
||||
void CrossModuleOptimization::makeFunctionUsableFromInline(SILFunction *function) {
|
||||
assert(canUseFromInline(function));
|
||||
if (!isAvailableExternally(function->getLinkage()) &&
|
||||
!isPackageOrPublic(function->getLinkage())) {
|
||||
!isPackageOrPublic(function->getLinkage()) &&
|
||||
!(function->getLinkage() == SILLinkage::Shared &&
|
||||
M.getSwiftModule()->getASTContext().LangOpts.hasFeature(
|
||||
Feature::Embedded))) {
|
||||
function->setLinkage(SILLinkage::Public);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,11 +124,13 @@ class IRGenPrepare : public SILFunctionTransform {
|
||||
SILFunction *F = getFunction();
|
||||
|
||||
if (getOptions().EmbeddedSwift) {
|
||||
// In embedded swift all the code is generated in the top-level module.
|
||||
// Even de-serialized functions must be code-gen'd.
|
||||
// In Embedded Swift, code for a module can be generated into the clients
|
||||
// that import that module (based on the de-serialized representation).
|
||||
// When the model has a non-unique definition, use shared linkage for
|
||||
// such definitions so they will be de-duplicated by the linker.
|
||||
SILLinkage linkage = F->getLinkage();
|
||||
if (isAvailableExternally(linkage)) {
|
||||
F->setLinkage(SILLinkage::Hidden);
|
||||
if (isAvailableExternally(linkage) && F->hasNonUniqueDefinition()) {
|
||||
F->setLinkage(SILLinkage::Shared);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
// SIL: @_used @_hasStorage @_hasInitialValue var g2: Bool { get set }
|
||||
// SIL: @_used func foo()
|
||||
|
||||
// SIL: sil_global hidden @$s4used2g0Sivp : $Int
|
||||
// SIL: sil_global hidden @$s4used2g1Si_Sitvp : $(Int, Int)
|
||||
// SIL: sil_global hidden @$s4used2g2Sbvp : $Bool
|
||||
// SIL: sil_global hidden [used] @$s4used2g0Sivp : $Int
|
||||
// SIL: sil_global hidden [used] @$s4used2g1Si_Sitvp : $(Int, Int)
|
||||
// SIL: sil_global hidden [used] @$s4used2g2Sbvp : $Bool
|
||||
|
||||
// SIL: sil hidden [used] @$s4used3fooyyF : $@convention(thin)
|
||||
|
||||
|
||||
@@ -45,6 +45,6 @@ actor MyActor {
|
||||
|
||||
// CHECK-IR-NOT: $e4main7MyActorC12thisIsUnusedyyYaF
|
||||
|
||||
// CHECK-IR: define {{swifttailcc|swiftcc}} void @swift_deletedAsyncMethodError(ptr swiftasync %0)
|
||||
// CHECK-IR: define weak_odr {{swifttailcc|swiftcc}} void @swift_deletedAsyncMethodError(ptr swiftasync %0)
|
||||
|
||||
// CHECK: value: 42
|
||||
|
||||
130
test/embedded/linkage/diamond.swift
Normal file
130
test/embedded/linkage/diamond.swift
Normal file
@@ -0,0 +1,130 @@
|
||||
// This test makes sure that we can build, link, and execute an Embedded Swift
|
||||
// application that's composed of multiple libraries. It tests various
|
||||
// combinations of "leaf" and "non-leaf" modules along the way to ensure that
|
||||
// every combination produces a working binary that is free of either missing or
|
||||
// (incorrectly) duplicated symbols. All of the modules implicitly depend on the
|
||||
// Swift standard library.
|
||||
//
|
||||
// The overall shape of the module dependencies looks like this:
|
||||
//
|
||||
//
|
||||
// Swift
|
||||
// |
|
||||
// |
|
||||
// Root
|
||||
// / \
|
||||
// / \
|
||||
// ClientA ClientB
|
||||
// \ /
|
||||
// \ /
|
||||
// Application
|
||||
//
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// Test #1: Defaults for everything
|
||||
// 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 -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-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
|
||||
|
||||
// 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 -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/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-run %t/Application | %FileCheck %s
|
||||
|
||||
// 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 -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/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-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
|
||||
|
||||
// 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 -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/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-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
|
||||
|
||||
// Test #%: All "intermediate", all the time. Main drives code generation
|
||||
// TODO: This requires -emit-empty-object-file to still emit the main symbol.
|
||||
// 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 -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/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/Application.o %t/Application.swift -enable-experimental-feature Embedded -emit-empty-object-file -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-run %t/Application | %FileCheck %s
|
||||
|
||||
|
||||
// REQUIRES: swift_in_compiler
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: swift_feature_Embedded
|
||||
|
||||
//--- Root.swift
|
||||
struct Point {
|
||||
var x, y: Int
|
||||
}
|
||||
|
||||
public func enumerateByteOffsets<T>(_: T.Type) -> [Int] {
|
||||
var array: [Int] = []
|
||||
for i in 0..<MemoryLayout<T>.size {
|
||||
array.append(i)
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
public func getPointOffsets() -> [Int] {
|
||||
enumerateByteOffsets(Point.self)
|
||||
}
|
||||
|
||||
//--- ClientA.swift
|
||||
import Root
|
||||
|
||||
public struct Color {
|
||||
var red: UInt8
|
||||
var green: UInt8
|
||||
var blue: UInt8
|
||||
}
|
||||
|
||||
public func getPointAndColorOffsets() -> [Int] {
|
||||
getPointOffsets() + enumerateByteOffsets(Color.self)
|
||||
}
|
||||
|
||||
//--- ClientB.swift
|
||||
import Root
|
||||
|
||||
struct Point3D {
|
||||
var x, y, z: Double
|
||||
}
|
||||
|
||||
public func getExtraPoint3DOffsets() -> [Int] {
|
||||
let pointOffsets = getPointOffsets()
|
||||
let point3DOffsets = enumerateByteOffsets(Point3D.self)
|
||||
return Array(point3DOffsets[pointOffsets.count...])
|
||||
}
|
||||
|
||||
//--- Application.swift
|
||||
import ClientA
|
||||
import ClientB
|
||||
|
||||
@main
|
||||
struct Main {
|
||||
static func main() {
|
||||
let pointAndColorOffsets = getPointAndColorOffsets()
|
||||
let extraColor3DOffsets = getExtraPoint3DOffsets()
|
||||
print(pointAndColorOffsets.count)
|
||||
print(extraColor3DOffsets.count)
|
||||
|
||||
// CHECK: DONE
|
||||
print("DONE")
|
||||
}
|
||||
}
|
||||
82
test/embedded/linkage/leaf_application.swift
Normal file
82
test/embedded/linkage/leaf_application.swift
Normal file
@@ -0,0 +1,82 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// Library module
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// Application module
|
||||
|
||||
// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-sil -o - | %FileCheck -check-prefix APPLICATION-SIL %s
|
||||
|
||||
// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-ir -o - | %FileCheck -check-prefix APPLICATION-IR --dump-input-filter all %s
|
||||
|
||||
// REQUIRES: swift_in_compiler
|
||||
// REQUIRES: swift_feature_Embedded
|
||||
|
||||
//--- Library.swift
|
||||
|
||||
// TODO: These are expected once "emit empty object file" becomes "be lazy".
|
||||
// LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = linkonce_odr {{(protected |dllexport )?}}global
|
||||
// LIBRARY-IR-NOT: @"$es16_emptyBoxStorageSi_Sitvp" = linkonce_odr {{(protected |dllexport )?}}global
|
||||
|
||||
// LIBRARY-IR-NOT: define {{.*}}@"$e7Library5helloSaySiGyF"()
|
||||
public func hello() -> [Int] {
|
||||
getArray()
|
||||
}
|
||||
|
||||
// LIBRARY-IR-NOT: define {{.*}} @"$e7Library8getArraySaySiGyF"()
|
||||
public func getArray() -> [Int] {
|
||||
throughInternal()
|
||||
}
|
||||
|
||||
// LIBRARY-IR-NOT: define {{.*}} @"$e7Library15throughInternalSaySiGyF"()
|
||||
func throughInternal() -> [Int] {
|
||||
throughPrivate()
|
||||
}
|
||||
|
||||
// LIBRARY-IR-NOT: define {{.*}} @"$e7Library14throughPrivate
|
||||
private func throughPrivate() -> [Int] {
|
||||
[5, 6, 7]
|
||||
}
|
||||
|
||||
// LIBRARY-IR-NOT: unnecessary
|
||||
public func unnecessary() -> Int64 { 5 }
|
||||
|
||||
// LIBRARY-IR-NOT: define swiftcc
|
||||
// LIBRARY-IR-NOT: define hidden swiftcc
|
||||
|
||||
// LIBRARY-IR-NOT: define {{.*}} @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5"
|
||||
|
||||
// LIBRARY-SIL: sil [ossa] @$e7Library5helloSaySiGyF
|
||||
// LIBRARY-SIL: sil [ossa] @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array<Int> {
|
||||
|
||||
//--- Application.swift
|
||||
import Library
|
||||
|
||||
public func testMe() {
|
||||
_ = hello()
|
||||
_ = getArray()
|
||||
}
|
||||
|
||||
// APPLICATION-IR: define {{(protected |dllexport )?}}swiftcc void @"$e11Application6testMeyyF"()
|
||||
|
||||
// APPLICATION-SIL: sil public_external @$e7Library5helloSaySiGyF : $@convention(thin) () -> @owned Array<Int> {
|
||||
// APPLICATION-IR: define linkonce_odr hidden swiftcc ptr @"$e7Library5helloSaySiGyF"()
|
||||
|
||||
// APPLICATION-SIL: sil public_external @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array<Int> {
|
||||
// APPLICATION-IR: define linkonce_odr hidden swiftcc ptr @"$e7Library8getArraySaySiGyF"()
|
||||
|
||||
// APPLICATION-IR: define {{(protected |dllexport )?}}i32 @Application_main
|
||||
|
||||
// APPLICATION-IR: define linkonce_odr hidden swiftcc { ptr, ptr } @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5"
|
||||
|
||||
@main
|
||||
struct Main {
|
||||
static func main() {
|
||||
}
|
||||
}
|
||||
73
test/embedded/linkage/leaf_library.swift
Normal file
73
test/embedded/linkage/leaf_library.swift
Normal file
@@ -0,0 +1,73 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// Library module
|
||||
|
||||
// SIL checking
|
||||
// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -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.
|
||||
// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -emit-ir -o - | %FileCheck -check-prefix LIBRARY-IR --dump-input-filter all %s
|
||||
|
||||
// Application module
|
||||
|
||||
// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-sil -o - | %FileCheck -check-prefix APPLICATION-SIL %s
|
||||
|
||||
// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-ir -o - | %FileCheck -check-prefix APPLICATION-IR --dump-input-filter all %s
|
||||
|
||||
// REQUIRES: swift_in_compiler
|
||||
// REQUIRES: swift_feature_Embedded
|
||||
|
||||
//--- Library.swift
|
||||
|
||||
// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library5helloSaySiGyF"()
|
||||
public func hello() -> [Int] {
|
||||
getArray()
|
||||
}
|
||||
|
||||
// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library8getArraySaySiGyF"()
|
||||
public func getArray() -> [Int] {
|
||||
throughInternal()
|
||||
}
|
||||
|
||||
// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library15throughInternalSaySiGyF"()
|
||||
func throughInternal() -> [Int] {
|
||||
throughPrivate()
|
||||
}
|
||||
|
||||
// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library14throughPrivate33_
|
||||
private func throughPrivate() -> [Int] {
|
||||
[5, 6, 7]
|
||||
}
|
||||
|
||||
// LIBRARY-IR: define linkonce_odr hidden swiftcc { ptr, ptr } @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5"
|
||||
|
||||
// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc i64 @"$e7Library11unnecessarys5Int64VyF"()
|
||||
public func unnecessary() -> Int64 { 5 }
|
||||
|
||||
// LIBRARY-SIL: sil @$e7Library5helloSaySiGyF
|
||||
// LIBRARY-SIL: sil @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array<Int> {
|
||||
|
||||
//--- Application.swift
|
||||
import Library
|
||||
|
||||
public func testMe() {
|
||||
_ = hello()
|
||||
_ = getArray()
|
||||
}
|
||||
|
||||
// APPLICATION-IR: define {{(protected |dllexport )?}}swiftcc void @"$e11Application6testMeyyF"()
|
||||
|
||||
// APPLICATION-SIL: sil public_external @$e7Library5helloSaySiGyF : $@convention(thin) () -> @owned Array<Int> {
|
||||
// APPLICATION-IR: define linkonce_odr hidden swiftcc ptr @"$e7Library5helloSaySiGyF"()
|
||||
|
||||
// APPLICATION-SIL: sil public_external @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array<Int> {
|
||||
// APPLICATION-IR: define linkonce_odr hidden swiftcc ptr @"$e7Library8getArraySaySiGyF"()
|
||||
|
||||
// APPLICATION-IR: define {{(protected |dllexport )?}}i32 @Application_main
|
||||
@main
|
||||
struct Main {
|
||||
static func main() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ public func test() {
|
||||
// CHECK: sil hidden [Onone] @$s4main8MyStructV3fooyyF : $@convention(method) <T> (MyStruct<T>) -> () {
|
||||
|
||||
// EMBEDDED: // specialized MyStruct.foo()
|
||||
// EMBEDDED: sil [Onone] @$e4main8MyStructV3fooyyFAA1XV_Tg5 : $@convention(method) (MyStruct<X>) -> () {
|
||||
// EMBEDDED: sil shared [Onone] @$e4main8MyStructV3fooyyFAA1XV_Tg5 : $@convention(method) (MyStruct<X>) -> () {
|
||||
|
||||
@@ -31,6 +31,6 @@ public func test() {
|
||||
createFoo(x: 1)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @$e8MyModule9createFoo1xyx_ts17FixedWidthIntegerRzlFSi_Ttg5 :
|
||||
// CHECK-LABEL: sil shared @$e8MyModule9createFoo1xyx_ts17FixedWidthIntegerRzlFSi_Ttg5 :
|
||||
// CHECK-NOT: release
|
||||
// CHECK: } // end sil function '$e8MyModule9createFoo1xyx_ts17FixedWidthIntegerRzlFSi_Ttg5'
|
||||
|
||||
Reference in New Issue
Block a user