Skip to content

Commit 8da2c37

Browse files
committed
IRGen: add support for static linking on Windows
This adjusts the IRGen layer to accommodate the Windows linking model. We assume dynamic linking by default. The static linking is enabled by passing `-static` to the driver, which forwards it to the frontend when building the module statically. This has already been required when generating libraries, however, the non-Windows targets are more forgiving and let it work. On those platforms, using this hint would allow for more efficient code generation, reducing load times and some runtime penalties from the PLT and GOT references formed to symbols which are module local. This corrects static linking on Windows, which is one of the last few items that are missing on Windows. It also takes advantage of the hint for the one peculiar difference between Windows and non-Windows: protocol conformances that span module boundaries are not available as a constant. However, when statically linking, we can enable those conformances to be statically resolved. This should enable the last known pattern to work when using static linking. This support requires further work in the Swift Package Manager to actually enable building libraries properly. However, when building with CMake, this should be sufficient to enable static linking.
1 parent 762e9c7 commit 8da2c37

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,7 +2030,7 @@ void irgen::updateLinkageForDefinition(IRGenModule &IGM,
20302030
bool isKnownLocal = entity.isAlwaysSharedLinkage();
20312031
if (const auto *DC = entity.getDeclContextForEmission())
20322032
if (const auto *MD = DC->getParentModule())
2033-
isKnownLocal = IGM.getSwiftModule() == MD;
2033+
isKnownLocal = IGM.getSwiftModule() == MD || MD->isStaticLibrary();
20342034

20352035
auto IRL =
20362036
getIRLinkage(linkInfo, entity.getLinkage(ForDefinition),
@@ -2059,7 +2059,7 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo,
20592059
bool isKnownLocal = entity.isAlwaysSharedLinkage();
20602060
if (const auto *DC = entity.getDeclContextForEmission())
20612061
if (const auto *MD = DC->getParentModule())
2062-
isKnownLocal = MD == swiftModule;
2062+
isKnownLocal = MD == swiftModule || MD->isStaticLibrary();
20632063

20642064
entity.mangle(result.Name);
20652065
bool weakImported = entity.isWeakImported(swiftModule);
@@ -2074,6 +2074,8 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, StringRef name,
20742074
bool isWeakImported) {
20752075
LinkInfo result;
20762076

2077+
// TODO(compnerd) handle this properly
2078+
20772079
result.Name += name;
20782080
result.IRL = getIRLinkage(linkInfo, linkage, isDefinition, isWeakImported);
20792081
result.ForDefinition = isDefinition;

lib/IRGen/GenProto.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,9 +1117,15 @@ class DirectConformanceInfo : public ConformanceInfo {
11171117

11181118
llvm::Constant *tryGetConstantTable(IRGenModule &IGM,
11191119
CanType conformingType) const override {
1120-
if (IGM.getOptions().LazyInitializeProtocolConformances &&
1121-
RootConformance->getDeclContext()->getParentModule() != IGM.getSwiftModule())
1122-
return nullptr;
1120+
if (IGM.getOptions().LazyInitializeProtocolConformances) {
1121+
const auto *MD = RootConformance->getDeclContext()->getParentModule();
1122+
// If the protocol conformance is defined in the current module or the
1123+
// module will be statically linked, then we can statically initialize the
1124+
// conformance as we know that the protocol conformance is guaranteed to
1125+
// be present.
1126+
if (!(MD == IGM.getSwiftModule() || MD->isStaticLibrary()))
1127+
return nullptr;
1128+
}
11231129
return IGM.getAddrOfWitnessTable(RootConformance);
11241130
}
11251131
};

test/IRGen/windows-linking.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -static -emit-module -emit-module-path %t/module.swiftmodule -module-name module -DMODULE %s
3+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -S -emit-ir %s -module-name main -o - -I%t | %FileCheck %s -check-prefix CHECK-STATIC
4+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -emit-module -emit-module-path %t/module.swiftmodule -module-name module -DMODULE %s
5+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -S -emit-ir %s -module-name main -o - -I%t | %FileCheck %s -check-prefix CHECK-SHARED
6+
7+
#if MODULE
8+
9+
public struct S {}
10+
public var value: S {
11+
S()
12+
}
13+
14+
public func f(_ s: S) {}
15+
16+
public protocol P {
17+
}
18+
19+
public enum E: P {
20+
}
21+
22+
#else
23+
24+
import module
25+
26+
protocol Q: P {
27+
}
28+
29+
extension E: Q {
30+
}
31+
32+
@main
33+
struct Entry {
34+
public static func main() {
35+
f(value)
36+
}
37+
}
38+
39+
#endif
40+
41+
42+
// Ensure that static linking does not mark the entries as being indirected
43+
// through the IAT.
44+
45+
// CHECK-STATIC: @"$s6module1EO4main1QADWP" = hidden constant [2 x i8*] [
46+
// CHECK-STATIC-SAME: i8* bitcast (%swift.protocol_conformance_descriptor* @"$s6module1EO4main1QADMc" to i8*),
47+
// CHECK-STATIC-SAME: i8* bitcast (i8** @"$s6module1EOAA1PAAWP" to i8*)
48+
// CHECK-STATIC-SAME: ]
49+
50+
// CHECK-STATIC: declare swiftcc void @"$s6module5valueAA1SVvg"()
51+
52+
// CHECK-STATIC: declare swiftcc void @"$s6module1fyyAA1SVF"()
53+
54+
55+
// Ensure that shared linking does mark the functions as being indirected
56+
// through the IAT.
57+
58+
// CHECK-SHARED: @"$s6module1EO4main1QADWP" = hidden constant [2 x i8*] [
59+
// CHECK-SHARED-SAME: i8* bitcast (%swift.protocol_conformance_descriptor* @"$s6module1EO4main1QADMc" to i8*),
60+
// CHECK-SHARED-SAME: i8* null
61+
// CHECK-SHARED-SAME: ]
62+
63+
// CHECK-SHARED: declare dllimport swiftcc void @"$s6module5valueAA1SVvg"()
64+
65+
// CHECK-SHARED: declare dllimport swiftcc void @"$s6module1fyyAA1SVF"()

0 commit comments

Comments
 (0)