Skip to content

Commit b45effc

Browse files
authored
Merge pull request #75097 from hamishknight/windows-coverage
[Driver] Pass `-lld-allow-duplicate-weak` for coverage on Windows
2 parents e08bd95 + df4d28f commit b45effc

File tree

4 files changed

+101
-6
lines changed

4 files changed

+101
-6
lines changed

lib/Driver/WindowsToolChains.cpp

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

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

80106
switch (context.OI.LTOVariant) {
@@ -88,12 +114,6 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
88114
break;
89115
}
90116

91-
if (Linker.empty() && context.OI.LTOVariant != OutputInfo::LTOKind::None) {
92-
// Force to use lld for LTO on Windows because we don't support link LTO or
93-
// something else except for lld LTO at this time.
94-
Linker = "lld";
95-
}
96-
97117
if (!Linker.empty())
98118
Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker));
99119

@@ -176,6 +196,14 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
176196
Arguments.push_back(context.Args.MakeArgString(
177197
Twine({"-include:", llvm::getInstrProfRuntimeHookVarName()})));
178198
Arguments.push_back(context.Args.MakeArgString("-lclang_rt.profile"));
199+
200+
// FIXME(rdar://131295678): Currently profiling requires the ability to
201+
// emit duplicate weak symbols. Assuming we're using lld, pass
202+
// -lld-allow-duplicate-weak to enable this behavior.
203+
if (requiresLLD) {
204+
Arguments.push_back("-Xlinker");
205+
Arguments.push_back("-lld-allow-duplicate-weak");
206+
}
179207
}
180208

181209
context.Args.AddAllArgs(Arguments, options::OPT_Xlinker);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
// REQUIRES: profile_runtime
20+
21+
//--- a.swift
22+
@_transparent
23+
public func foo() {}
24+
25+
//--- b.swift
26+
import A
27+
28+
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)