PGO: Add IR-based PGO.

This commit is contained in:
Johan Engelen 2017-12-28 16:01:47 +01:00
parent 3ec79179b4
commit e8e28b33b2
5 changed files with 104 additions and 4 deletions

View file

@ -15,9 +15,11 @@
#include "driver/cl_options_instrumentation.h"
#include "errors.h"
#include "globals.h"
namespace {
namespace cl = llvm::cl;
#if LDC_LLVM_VER >= 309
/// Option for generating IR-based PGO instrumentation (LLVM pass)
@ -82,6 +84,29 @@ void initializeInstrumentationOptionsFromCmdline() {
pgoMode = PGO_ASTBasedUse;
initFromPathString(global.params.datafileInstrProf, ASTPGOInstrUseFile);
}
#if LDC_LLVM_VER >= 309
else if (IRPGOInstrGenFile.getNumOccurrences() > 0) {
pgoMode = PGO_IRBasedInstr;
if (IRPGOInstrGenFile.empty()) {
global.params.datafileInstrProf = "default_%m.profraw";
} else {
initFromPathString(global.params.datafileInstrProf, IRPGOInstrGenFile);
}
} else if (!IRPGOInstrUseFile.empty()) {
pgoMode = PGO_IRBasedUse;
initFromPathString(global.params.datafileInstrProf, IRPGOInstrUseFile);
}
#endif
// There is a bug in (our use of?) LLVM where codegen errors with
// PGO_IRBasedInstr for Windows targets. So disable IRBased PGO on Windows for
// now.
assert(global.params.targetTriple);
if ((pgoMode == PGO_IRBasedInstr) &&
global.params.targetTriple->isOSWindows()) {
error(Loc(),
"'-fprofile-generate' is not yet supported for Windows targets.");
}
if (dmdFunctionTrace)
global.params.trace = true;

View file

@ -24,7 +24,8 @@ namespace cl = llvm::cl;
extern cl::opt<bool> instrumentFunctions;
/// This initializes the instrumentation options, and checks the validity of the
/// commandline flags. It should be called only once.
/// commandline flags. targetTriple should be initialized before calling this.
/// It should be called only once.
void initializeInstrumentationOptionsFromCmdline();
enum PGOKind {

View file

@ -431,7 +431,6 @@ void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
}
#endif
opts::initializeInstrumentationOptionsFromCmdline();
opts::initializeSanitizerOptionsFromCmdline();
processVersions(debugArgs, "debug", DebugCondition::setGlobalLevel,
@ -1067,6 +1066,8 @@ int cppmain(int argc, char **argv) {
global.lib_ext = "a";
}
opts::initializeInstrumentationOptionsFromCmdline();
Strings libmodules;
return mars_mainBody(files, libmodules);
}

View file

@ -207,7 +207,8 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
}
// Adds PGO instrumentation generation and use passes.
static void addPGOPasses(legacy::PassManagerBase &mpm, unsigned optLevel) {
static void addPGOPasses(PassManagerBuilder &builder,
legacy::PassManagerBase &mpm, unsigned optLevel) {
if (opts::isInstrumentingForASTBasedPGO()) {
InstrProfOptions options;
options.NoRedZone = global.params.disableRedZone;
@ -227,6 +228,16 @@ static void addPGOPasses(legacy::PassManagerBase &mpm, unsigned optLevel) {
}
#endif
}
#if LDC_LLVM_VER >= 309
else if (opts::isInstrumentingForIRBasedPGO()) {
#if LDC_LLVM_VER >= 400
builder.EnablePGOInstrGen = true;
#endif
builder.PGOInstrGen = global.params.datafileInstrProf;
} else if (opts::isUsingIRBasedPGOProfile()) {
builder.PGOInstrUse = global.params.datafileInstrProf;
}
#endif
}
/**
@ -328,7 +339,7 @@ static void addOptimizationPasses(legacy::PassManagerBase &mpm,
builder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addStripExternalsPass);
addPGOPasses(mpm, optLevel);
addPGOPasses(builder, mpm, optLevel);
builder.populateFunctionPassManager(fpm);
builder.populateModulePassManager(mpm);

View file

@ -0,0 +1,62 @@
// Test instrumentation of indirect calls
// REQUIRES: atleast_llvm309
// There is an LLVM bug, this test currently errors during LLVM codegen for Windows.
// XFAIL: Windows
// RUN: %ldc -O3 -fprofile-generate=%t.profraw -run %s \
// RUN: && %profdata merge %t.profraw -o %t.profdata \
// RUN: && %ldc -O3 -c -output-ll -of=%t.use.ll -fprofile-use=%t.profdata %s \
// RUN: && FileCheck %s -check-prefix=PROFUSE < %t.use.ll
import ldc.attributes : weak;
extern (C)
{ // simplify name mangling for simpler string matching
@weak // disable reasoning about this function
void hot()
{
}
void luke()
{
}
void cold()
{
}
void function() foo;
@weak // disable reasoning about this function
void select_func(int i)
{
if (i < 1700)
foo = &hot;
else if (i < 1990)
foo = &luke;
else
foo = &cold;
}
} // extern C
// PROFUSE-LABEL: @_Dmain(
int main()
{
for (int i; i < 2000; ++i)
{
select_func(i);
// PROFUSE: [[REG1:%[0-9]+]] = load void ()*, void ()** @foo
// PROFUSE: [[REG2:%[0-9]+]] = icmp eq void ()* [[REG1]], @hot
// PROFUSE: call void @hot()
// PROFUSE: call void [[REG1]]()
foo();
}
return 0;
}