Skip to content

Commit dc28e0e

Browse files
Support caching Clang invocations with -fprofile-use and -fprofile-instr-use.
1 parent 573c9ba commit dc28e0e

File tree

3 files changed

+154
-3
lines changed

3 files changed

+154
-3
lines changed

src/compiler/clang.rs

+127-2
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,14 @@ counted_array!(pub static ARGS: [ArgInfo<gcc::ArgData>; _] = [
118118
take_arg!("-fdebug-compilation-dir", OsString, Separated, PassThrough),
119119
flag!("-fmodules", TooHardFlag),
120120
flag!("-fno-color-diagnostics", NoDiagnosticsColorFlag),
121+
flag!("-fno-profile-instr-generate", TooHardFlag),
122+
flag!("-fno-profile-instr-use", TooHardFlag),
121123
take_arg!("-fplugin", PathBuf, CanBeConcatenated('='), ExtraHashFile),
122124
flag!("-fprofile-instr-generate", ProfileGenerate),
123-
// Can be either -fprofile-instr-use or -fprofile-instr-use=path
124-
take_arg!("-fprofile-instr-use", OsString, Concatenated, TooHard),
125+
// Note: the PathBuf argument is optional
126+
take_arg!("-fprofile-instr-use", PathBuf, Concatenated('='), ClangProfileUse),
127+
// Note: this overrides the -fprofile-use option in gcc.rs.
128+
take_arg!("-fprofile-use", PathBuf, Concatenated('='), ClangProfileUse),
125129
take_arg!("-fsanitize-blacklist", PathBuf, Concatenated('='), ExtraHashFile),
126130
take_arg!("-gcc-toolchain", OsString, Separated, PassThrough),
127131
take_arg!("-include-pch", PathBuf, CanBeSeparated, PreprocessorArgumentPath),
@@ -132,6 +136,27 @@ counted_array!(pub static ARGS: [ArgInfo<gcc::ArgData>; _] = [
132136
flag!("-verify", PreprocessorArgumentFlag),
133137
]);
134138

139+
// Maps the `-fprofile-use` argument to the actual path of the
140+
// .profdata file Clang will try to use.
141+
pub(crate) fn resolve_profile_use_path(arg: &Path, cwd: &Path) -> PathBuf {
142+
// Note that `arg` might be empty (if no argument was given to
143+
// -fprofile-use), in which case `path` will be `cwd` after
144+
// the next statement and "./default.profdata" at the end of the
145+
// block. This matches Clang's behavior for when no argument is
146+
// given.
147+
let mut path = cwd.join(arg);
148+
149+
assert!(!arg.as_os_str().is_empty() || path == cwd);
150+
151+
// Clang allows specifying a directory here, in which case it
152+
// will look for the file `default.profdata` in that directory.
153+
if path.is_dir() {
154+
path.push("default.profdata");
155+
}
156+
157+
path
158+
}
159+
135160
#[cfg(test)]
136161
mod test {
137162
use super::*;
@@ -406,4 +431,104 @@ mod test {
406431
let a = parses!("-c", "foo.c", "-o", "foo.o");
407432
assert_eq!(a.color_mode, ColorMode::Auto);
408433
}
434+
435+
#[test]
436+
fn test_parse_arguments_profile_instr_use() {
437+
let a = parses!(
438+
"-c",
439+
"foo.c",
440+
"-o",
441+
"foo.o",
442+
"-fprofile-instr-use=foo.profdata"
443+
);
444+
assert_eq!(ovec!["-fprofile-instr-use=foo.profdata"], a.common_args);
445+
assert_eq!(
446+
ovec![std::env::current_dir().unwrap().join("foo.profdata")],
447+
a.extra_hash_files
448+
);
449+
}
450+
451+
#[test]
452+
fn test_parse_arguments_profile_use() {
453+
let a = parses!("-c", "foo.c", "-o", "foo.o", "-fprofile-use=xyz.profdata");
454+
455+
assert_eq!(ovec!["-fprofile-use=xyz.profdata"], a.common_args);
456+
assert_eq!(
457+
ovec![std::env::current_dir().unwrap().join("xyz.profdata")],
458+
a.extra_hash_files
459+
);
460+
}
461+
462+
#[test]
463+
fn test_parse_arguments_profile_use_with_directory() {
464+
let a = parses!("-c", "foo.c", "-o", "foo.o", "-fprofile-use=.");
465+
466+
assert_eq!(ovec!["-fprofile-use=."], a.common_args);
467+
assert_eq!(
468+
ovec![std::env::current_dir().unwrap().join("default.profdata")],
469+
a.extra_hash_files
470+
);
471+
}
472+
473+
#[test]
474+
fn test_parse_arguments_profile_use_with_no_argument() {
475+
let a = parses!("-c", "foo.c", "-o", "foo.o", "-fprofile-use");
476+
477+
assert_eq!(ovec!["-fprofile-use"], a.common_args);
478+
assert_eq!(
479+
ovec![std::env::current_dir().unwrap().join("default.profdata")],
480+
a.extra_hash_files
481+
);
482+
}
483+
484+
#[test]
485+
fn test_parse_arguments_pgo_cancellation() {
486+
assert_eq!(
487+
CompilerArguments::CannotCache("-fno-profile-use", None),
488+
parse_arguments_(stringvec![
489+
"-c",
490+
"foo.c",
491+
"-o",
492+
"foo.o",
493+
"-fprofile-use",
494+
"-fno-profile-use"
495+
])
496+
);
497+
498+
assert_eq!(
499+
CompilerArguments::CannotCache("-fno-profile-instr-use", None),
500+
parse_arguments_(stringvec![
501+
"-c",
502+
"foo.c",
503+
"-o",
504+
"foo.o",
505+
"-fprofile-instr-use",
506+
"-fno-profile-instr-use"
507+
])
508+
);
509+
510+
assert_eq!(
511+
CompilerArguments::CannotCache("-fno-profile-generate", None),
512+
parse_arguments_(stringvec![
513+
"-c",
514+
"foo.c",
515+
"-o",
516+
"foo.o",
517+
"-fprofile-generate",
518+
"-fno-profile-generate"
519+
])
520+
);
521+
522+
assert_eq!(
523+
CompilerArguments::CannotCache("-fno-profile-instr-generate", None),
524+
parse_arguments_(stringvec![
525+
"-c",
526+
"foo.c",
527+
"-o",
528+
"foo.o",
529+
"-fprofile-instr-generate",
530+
"-fno-profile-instr-generate"
531+
])
532+
);
533+
}
409534
}

src/compiler/gcc.rs

+8
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ ArgData! { pub
122122
Language(OsString),
123123
SplitDwarf,
124124
ProfileGenerate,
125+
ClangProfileUse(PathBuf),
125126
TestCoverage,
126127
Coverage,
127128
ExtraHashFile(PathBuf),
@@ -168,6 +169,8 @@ counted_array!(pub static ARGS: [ArgInfo<ArgData>; _] = [
168169
flag!("-c", DoCompilation),
169170
take_arg!("-fdiagnostics-color", OsString, Concatenated('='), DiagnosticsColor),
170171
flag!("-fno-diagnostics-color", NoDiagnosticsColorFlag),
172+
flag!("-fno-profile-generate", TooHardFlag),
173+
flag!("-fno-profile-use", TooHardFlag),
171174
flag!("-fno-working-directory", PreprocessorArgumentFlag),
172175
flag!("-fplugin=libcc1plugin", TooHardFlag),
173176
flag!("-fprofile-arcs", ProfileGenerate),
@@ -278,6 +281,9 @@ where
278281
OsString::from(arg.flag_str().expect("Compilation flag expected"));
279282
}
280283
Some(ProfileGenerate) => profile_generate = true,
284+
Some(ClangProfileUse(path)) => {
285+
extra_hash_files.push(clang::resolve_profile_use_path(path, cwd));
286+
}
281287
Some(TestCoverage) => outputs_gcno = true,
282288
Some(Coverage) => {
283289
outputs_gcno = true;
@@ -337,6 +343,7 @@ where
337343
let args = match arg.get_data() {
338344
Some(SplitDwarf)
339345
| Some(ProfileGenerate)
346+
| Some(ClangProfileUse(_))
340347
| Some(TestCoverage)
341348
| Some(Coverage)
342349
| Some(DiagnosticsColor(_))
@@ -380,6 +387,7 @@ where
380387
let args = match arg.get_data() {
381388
Some(SplitDwarf)
382389
| Some(ProfileGenerate)
390+
| Some(ClangProfileUse(_))
383391
| Some(TestCoverage)
384392
| Some(Coverage)
385393
| Some(DoCompilation)

src/compiler/msvc.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,12 @@ pub fn parse_arguments(
603603
profile_generate = true;
604604
&mut common_args
605605
}
606+
607+
Some(ClangProfileUse(path)) => {
608+
extra_hash_files.push(clang::resolve_profile_use_path(path, cwd));
609+
&mut common_args
610+
}
611+
606612
Some(ExtraHashFile(path)) => {
607613
extra_hash_files.push(cwd.join(path));
608614
&mut common_args
@@ -1061,13 +1067,15 @@ mod test {
10611067
"-Xclang",
10621068
"host_dictionary.obj",
10631069
"-clang:-fprofile-generate",
1070+
"-clang:-fprofile-use=xyz.profdata",
10641071
"dictionary.c"
10651072
];
10661073
let ParsedArguments {
10671074
dependency_args,
10681075
preprocessor_args,
10691076
common_args,
10701077
profile_generate,
1078+
extra_hash_files,
10711079
..
10721080
} = match parse_arguments(args) {
10731081
CompilerArguments::Ok(args) => args,
@@ -1090,7 +1098,17 @@ mod test {
10901098
"host_dictionary.obj"
10911099
)
10921100
);
1093-
assert_eq!(common_args, ovec!("-clang:-fprofile-generate"));
1101+
assert_eq!(
1102+
common_args,
1103+
ovec!(
1104+
"-clang:-fprofile-generate",
1105+
"-clang:-fprofile-use=xyz.profdata"
1106+
)
1107+
);
1108+
assert_eq!(
1109+
extra_hash_files,
1110+
ovec!(std::env::current_dir().unwrap().join("xyz.profdata"))
1111+
);
10941112
}
10951113

10961114
#[test]

0 commit comments

Comments
 (0)