Skip to content

Commit 0ac0007

Browse files
committed
Merge branch 'clang-pgo-flag-support' into 'main'
Add support for Clang's -fprofile-use and -fprofile-generate profile-guided optimization flags See merge request Sharpmake/sharpmake!630
2 parents a4a176a + 3537425 commit 0ac0007

File tree

5 files changed

+128
-3
lines changed

5 files changed

+128
-3
lines changed

Sharpmake.Generators/FastBuild/Bff.Template.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,8 @@ public static class ConfigurationFile
443443
+ ' [cmdLineOptions.OmitFramePointers]'
444444
+ ' [cmdLineOptions.EnableFiberSafeOptimizations]'
445445
+ ' [cmdLineOptions.CompilerWholeProgramOptimization]'
446+
+ ' [cmdLineOptions.GenerateProfileGuidedOptimizationData]'
447+
+ ' [cmdLineOptions.UseProfileGuidedOptimizationData]'
446448
+ ' [options.AdditionalCompilerOptimizeOptions]'
447449
";
448450

Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,50 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
408408
Options.Option(Options.Vc.General.WholeProgramOptimization.Update, () => { context.Options["WholeProgramOptimization"] = "PGUpdate"; context.Options["CompilerWholeProgramOptimization"] = "true"; context.CommandLineOptions["CompilerWholeProgramOptimization"] = "/GL"; })
409409
);
410410

411+
// Options.Clang.Compiler.ProfileGuidedOptimization.Use
412+
string usePGODataCompilerOption = FileGeneratorUtilities.RemoveLineTag;
413+
string usePGODataPath = Options.PathOption.Get<Options.Clang.Compiler.ProfileGuidedOptimization.Use>(context.Configuration, FileGeneratorUtilities.RemoveLineTag, context.ProjectDirectoryCapitalized);
414+
if (usePGODataPath != FileGeneratorUtilities.RemoveLineTag)
415+
{
416+
string formattedPath = FormatCommandLineOptionPath(context, usePGODataPath);
417+
usePGODataCompilerOption = $"-fprofile-use={formattedPath}";
418+
context.Configuration.AdditionalCompilerOptions.Add("-Wno-backend-plugin");
419+
}
420+
context.CommandLineOptions["UseProfileGuidedOptimizationData"] = usePGODataCompilerOption;
421+
422+
// Options.Clang.Compiler.ProfileGuidedOptimization.Generate
423+
// Options.Clang.Compiler.ProfileGuidedOptimization.GenerateCS
424+
string generatePGODataCompilerOption = FileGeneratorUtilities.RemoveLineTag;
425+
string generatePGODataPath = Options.PathOption.Get<Options.Clang.Compiler.ProfileGuidedOptimization.Generate>(context.Configuration, FileGeneratorUtilities.RemoveLineTag, context.ProjectDirectoryCapitalized);
426+
string generateCSPGODataPath = Options.PathOption.Get<Options.Clang.Compiler.ProfileGuidedOptimization.GenerateCS>(context.Configuration, FileGeneratorUtilities.RemoveLineTag, context.ProjectDirectoryCapitalized);
427+
if (generatePGODataPath != FileGeneratorUtilities.RemoveLineTag && generateCSPGODataPath != FileGeneratorUtilities.RemoveLineTag)
428+
{
429+
string generatePGODataOptionName = typeof(Options.Clang.Compiler.ProfileGuidedOptimization.Generate).FullName.Replace("+", ".");
430+
string generateCSPGODataOptionName = typeof(Options.Clang.Compiler.ProfileGuidedOptimization.GenerateCS).FullName.Replace("+", ".");
431+
throw new Error($"Error in the configuration of {context.Configuration.ProjectName}: {generatePGODataOptionName} and {generateCSPGODataOptionName} cannot be used together.");
432+
}
433+
else if (generatePGODataPath != FileGeneratorUtilities.RemoveLineTag)
434+
{
435+
string generatePGODataCompilerOptionPrefix = "-fprofile-generate";
436+
generatePGODataCompilerOption = generatePGODataCompilerOptionPrefix;
437+
if (generatePGODataPath != null)
438+
{
439+
string formattedPath = FormatCommandLineOptionPath(context, generatePGODataPath);
440+
generatePGODataCompilerOption = $"{generatePGODataCompilerOptionPrefix}={formattedPath}";
441+
}
442+
}
443+
else if (generateCSPGODataPath != FileGeneratorUtilities.RemoveLineTag)
444+
{
445+
string generateCSPGODataCompilerOptionPrefix = "-fcs-profile-generate";
446+
generatePGODataCompilerOption = generateCSPGODataCompilerOptionPrefix;
447+
if (generateCSPGODataPath != null)
448+
{
449+
string formattedPath = FormatCommandLineOptionPath(context, generateCSPGODataPath);
450+
generatePGODataCompilerOption = $"{generateCSPGODataCompilerOptionPrefix}={formattedPath}";
451+
}
452+
}
453+
context.CommandLineOptions["GenerateProfileGuidedOptimizationData"] = generatePGODataCompilerOption;
454+
411455
optionsContext.PlatformVcxproj.SelectApplicationFormatOptions(context);
412456
optionsContext.PlatformVcxproj.SelectBuildType(context);
413457

@@ -1118,6 +1162,13 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
11181162
// UndefineAllPreprocessorDefinitions
11191163
context.CommandLineOptions["UndefineAllPreprocessorDefinitions"] = FileGeneratorUtilities.RemoveLineTag;
11201164

1165+
// Options.Clang.Compiler.ValueProfileCountersPerSite
1166+
string valueProfileCountersPerSite = Options.IntOption.Get<Options.Clang.Compiler.ValueProfileCountersPerSite>(context.Configuration);
1167+
if (valueProfileCountersPerSite != FileGeneratorUtilities.RemoveLineTag)
1168+
{
1169+
context.Configuration.AdditionalCompilerOptions.Add($"-Xclang -mllvm -Xclang -vp-counters-per-site={valueProfileCountersPerSite}");
1170+
}
1171+
11211172
optionsContext.PlatformVcxproj.SelectPrecompiledHeaderOptions(context);
11221173

11231174
// Default defines...
@@ -1157,7 +1208,9 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
11571208
}
11581209

11591210
// We need to merge together AdditionalCompilerOptions and AdditionalCompilerOptimizeOptions for writing them on a single line in vcxproj files.
1160-
string[] allAdditionalOptions = new string[] { optionResults[0], optionResults[1] };
1211+
// WORKAROUND: we also add the Clang profile-guided-optimization options if they have been provided.
1212+
// This is needed because vcxproj does not directly support those options and adding the options in Project.Configuration.AdditionalCompilerOptions ends up duplicating them in the BFF.
1213+
string[] allAdditionalOptions = new string[] { optionResults[0], optionResults[1], context.CommandLineOptions["UseProfileGuidedOptimizationData"], context.CommandLineOptions["GenerateProfileGuidedOptimizationData"] };
11611214
var nonEmptyOptions = allAdditionalOptions.Where(a => a != FileGeneratorUtilities.RemoveLineTag);
11621215
if (nonEmptyOptions.Any())
11631216
{
@@ -1873,6 +1926,17 @@ private void GenerateLinkerOptions(IGenerationContext context, ProjectOptionsGen
18731926
linkerAdditionalOptions += ignoredLinkerWarnings;
18741927
}
18751928

1929+
// Treat Options.Clang.Linker.ExtTspBlockPlacement here because
1930+
// it does not have a specific line in the vcxproj
1931+
Options.Clang.Linker.ExtTspBlockPlacement extTSPBlockPlacement = Options.GetObject<Options.Clang.Linker.ExtTspBlockPlacement>(context.Configuration);
1932+
if (extTSPBlockPlacement == Options.Clang.Linker.ExtTspBlockPlacement.Enable)
1933+
{
1934+
if (linkerAdditionalOptions.Length > 0)
1935+
linkerAdditionalOptions += " ";
1936+
string mllvmLinkerPrefix = context.Configuration.Platform.IsMicrosoft() ? "-mllvm:" : "-Wl,-mllvm,";
1937+
linkerAdditionalOptions += $"{mllvmLinkerPrefix}-enable-ext-tsp-block-placement=1";
1938+
}
1939+
18761940
context.Options["AdditionalLibrarianOptions"] = additionalLibrarianOptions.Length > 0 ? additionalLibrarianOptions : FileGeneratorUtilities.RemoveLineTag;
18771941
context.Options["AdditionalLinkerOptions"] = linkerAdditionalOptions.Length > 0 ? linkerAdditionalOptions : FileGeneratorUtilities.RemoveLineTag;
18781942
}

Sharpmake/Options.Clang.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,52 @@ public enum OptimizationLevel
9898
ForSize
9999
}
100100

101+
public static class ProfileGuidedOptimization
102+
{
103+
/// <summary>
104+
/// Use profile data for profile-guided optimization.
105+
/// </summary>
106+
/// <remarks>
107+
/// Note that Sharpmake's usual placeholder strings can be used in path.
108+
/// For more information, see https://clang.llvm.org/docs/UsersManual.html#cmdoption-fprofile-use
109+
/// </remarks>
110+
public class Use : PathOption
111+
{
112+
public Use(string path) : base(path) { }
113+
}
114+
115+
/// <summary>
116+
/// Generate instrumented code to collect raw profile data in the directory specified as directoryPath.
117+
/// </summary>
118+
/// <remarks>
119+
/// This option cannot be used at the same time as the GenerateCS option.
120+
/// Note that Sharpmake's usual placeholder strings can be used in directoryPath.
121+
/// For more information, see https://clang.llvm.org/docs/UsersManual.html#cmdoption-fprofile-generate
122+
/// </remarks>
123+
public class Generate : PathOption
124+
{
125+
public Generate(string directoryPath = null) : base(directoryPath) { }
126+
}
127+
128+
/// <summary>
129+
/// Generate context-sensitive (i.e. post-inlining) instrumented code to collect raw profile data in the directory specified as directoryPath.
130+
/// </summary>
131+
/// <remarks>
132+
/// This option cannot be used at the same time as the Generate option.
133+
/// Note that Sharpmake's usual placeholder strings can be used in directoryPath.
134+
/// For more information, see https://clang.llvm.org/docs/UsersManual.html#cmdoption-fcs-profile-generate
135+
/// </remarks>
136+
public class GenerateCS: PathOption
137+
{
138+
public GenerateCS(string directoryPath = null) : base(directoryPath) { }
139+
}
140+
}
141+
142+
public class ValueProfileCountersPerSite : IntOption
143+
{
144+
public ValueProfileCountersPerSite(int counter) : base(counter) { }
145+
}
146+
101147
public enum Rtti
102148
{
103149
[Default]
@@ -135,6 +181,16 @@ public class LLVMVcPlatformToolset : WithArgOption<Vc.General.PlatformToolset>
135181
public LLVMVcPlatformToolset(Vc.General.PlatformToolset vcPlatformToolset) : base(vcPlatformToolset) { }
136182
}
137183
}
184+
185+
public static class Linker
186+
{
187+
public enum ExtTspBlockPlacement
188+
{
189+
[Default]
190+
Disable,
191+
Enable
192+
}
193+
}
138194
}
139195
}
140196
}

Sharpmake/Options.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static string Get<T>(Project.Configuration conf, string fallback = Remove
6161
{
6262
return fallback;
6363
}
64-
if (!string.IsNullOrEmpty(rootpath))
64+
if (!string.IsNullOrEmpty(rootpath) && option.Path != null)
6565
{
6666
return Util.PathGetRelative(rootpath, option.Path, true);
6767
}

Sharpmake/Project.Configuration.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3018,7 +3018,10 @@ internal void Resolve(Resolver resolver)
30183018
if (pathOption != null)
30193019
{
30203020
pathOption.Path = resolver.Resolve(pathOption.Path);
3021-
Util.ResolvePath(Project.SourceRootPath, ref pathOption.Path);
3021+
if (pathOption.Path != null)
3022+
{
3023+
Util.ResolvePath(Project.SourceRootPath, ref pathOption.Path);
3024+
}
30223025
}
30233026
}
30243027

0 commit comments

Comments
 (0)