Skip to content

Commit d2da4ff

Browse files
committed
[Driver] Pass -lld-allow-duplicate-weak for coverage on Windows
And add an integration test for both the legacy and new driver. rdar://129337999
1 parent 83de87a commit d2da4ff

File tree

4 files changed

+99
-6
lines changed

4 files changed

+99
-6
lines changed

lib/Driver/WindowsToolChains.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,36 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
8181
llvm_unreachable("invalid link kind");
8282
}
8383

84+
// Check to see whether we need to use lld as the linker.
85+
auto requiresLLD = [&]{
86+
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
87+
return llvm::StringSwitch<bool>(A->getValue())
88+
.Cases("lld", "lld.exe", "lld-link", "lld-link.exe", true)
89+
.Default(false);
90+
}
91+
// Force to use lld for LTO on Windows because we don't support link LTO or
92+
// something else except for lld LTO at this time.
93+
if (context.OI.LTOVariant != OutputInfo::LTOKind::None) {
94+
return true;
95+
}
96+
// Profiling currently relies on the ability to emit duplicate weak
97+
// symbols across translation units and having the linker coalesce them.
98+
// Unfortunately link.exe does not support this, so require lld-link
99+
// for now, which supports the behavior via a flag.
100+
// TODO: Once we've changed coverage to no longer rely on emitting
101+
// duplicate weak symbols (rdar://131295678), we can remove this.
102+
if (context.Args.getLastArg(options::OPT_profile_generate)) {
103+
return true;
104+
}
105+
return false;
106+
}();
107+
84108
// Select the linker to use.
85109
std::string Linker;
86110
if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) {
87111
Linker = A->getValue();
112+
} else if (requiresLLD) {
113+
Linker = "lld";
88114
}
89115

90116
switch (context.OI.LTOVariant) {
@@ -98,12 +124,6 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
98124
break;
99125
}
100126

101-
if (Linker.empty() && context.OI.LTOVariant != OutputInfo::LTOKind::None) {
102-
// Force to use lld for LTO on Windows because we don't support link LTO or
103-
// something else except for lld LTO at this time.
104-
Linker = "lld";
105-
}
106-
107127
if (!Linker.empty())
108128
Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker));
109129

@@ -186,6 +206,14 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
186206
Arguments.push_back(context.Args.MakeArgString(
187207
Twine({"-include:", llvm::getInstrProfRuntimeHookVarName()})));
188208
Arguments.push_back(context.Args.MakeArgString("-lclang_rt.profile"));
209+
210+
// FIXME(rdar://131295678): Currently profiling requires the ability to
211+
// emit duplicate weak symbols. Assuming we're using lld, pass
212+
// -lld-allow-duplicate-weak to enable this behavior.
213+
if (requiresLLD) {
214+
Arguments.push_back("-Xlinker");
215+
Arguments.push_back("-lld-allow-duplicate-weak");
216+
}
189217
}
190218

191219
context.Args.AddAllArgs(Arguments, options::OPT_Xlinker);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t/out)
2+
// RUN: split-file %s %t
3+
4+
// rdar://129337999 - Make sure we can link without issues.
5+
6+
// The legacy driver does not support doing this in one invocation, so split it
7+
// up for compatibility with both the legacy and new driver.
8+
// RUN: %target-build-swift -c %t/a.swift -profile-generate -profile-coverage-mapping -parse-as-library -module-name A -o %t/out/a.swift.o
9+
// RUN: %target-build-swift -emit-module %t/a.swift -profile-generate -profile-coverage-mapping -parse-as-library -module-name A -emit-module-path %t/out/A.swiftmodule
10+
11+
// RUN: %target-build-swift %t/b.swift -profile-generate -profile-coverage-mapping -o %t/main -module-name B -I %t/out %t/out/a.swift.o
12+
13+
// Test again using only the old driver.
14+
// RUN: %empty-directory(%t/out)
15+
// RUN: env SWIFT_USE_OLD_DRIVER=1 %target-build-swift -c %t/a.swift -profile-generate -profile-coverage-mapping -parse-as-library -module-name A -o %t/out/a.swift.o
16+
// RUN: env SWIFT_USE_OLD_DRIVER=1 %target-build-swift -emit-module %t/a.swift -profile-generate -profile-coverage-mapping -parse-as-library -module-name A -emit-module-path %t/out/A.swiftmodule
17+
// RUN: env SWIFT_USE_OLD_DRIVER=1 %target-build-swift %t/b.swift -profile-generate -profile-coverage-mapping -o %t/main -module-name B -I %t/out %t/out/a.swift.o
18+
19+
//--- a.swift
20+
@_transparent
21+
public func foo() {}
22+
23+
//--- b.swift
24+
import A
25+
26+
foo()
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t/out)
2+
// RUN: split-file %s %t
3+
4+
// rdar://129337999 - Make sure we can link without issues.
5+
6+
// The legacy driver does not support doing this in one invocation, so split it
7+
// up for compatibility with both the legacy and new driver.
8+
// RUN: %target-build-swift -c %t/a.swift -profile-generate -profile-coverage-mapping -parse-as-library -module-name A -o %t/out/a.swift.o
9+
// RUN: %target-build-swift -emit-module %t/a.swift -profile-generate -profile-coverage-mapping -parse-as-library -module-name A -emit-module-path %t/out/A.swiftmodule
10+
11+
// RUN: %target-build-swift %t/b.swift -profile-generate -profile-coverage-mapping -o %t/main -module-name B -I %t/out %t/out/a.swift.o
12+
13+
// RUN: %target-codesign %t/main
14+
// RUN: env %env-LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
15+
16+
// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
17+
18+
// The implicit-check-not here ensures we match all recorded line counts.
19+
// RUN: %llvm-cov show %t/main -instr-profile=%t/default.profdata | %FileCheck --implicit-check-not "{{[ ]*\|[ ]*[0-9]+}}" %s
20+
21+
// REQUIRES: profile_runtime
22+
// REQUIRES: executable_test
23+
24+
//--- a.swift
25+
@_transparent
26+
public func foo() {}
27+
// CHECK: 1|public func foo() {}
28+
29+
//--- b.swift
30+
import A
31+
32+
foo()
33+
// CHECK: 1|foo()

test/Profiler/lit.local.cfg

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Make a local copy of the environment.
2+
config.environment = dict(config.environment)
3+
4+
# Prefer the new driver for profiling tests
5+
del config.environment['SWIFT_USE_OLD_DRIVER']
6+
del config.environment['SWIFT_AVOID_WARNING_USING_OLD_DRIVER']

0 commit comments

Comments
 (0)