Skip to content

Commit

Permalink
Merge pull request #2474 from JohanEngelen/irpgo
Browse files Browse the repository at this point in the history
Add IR-based PGO
  • Loading branch information
JohanEngelen authored Jan 18, 2018
2 parents 3f7bebf + e8e28b3 commit 7f087f4
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 53 deletions.
1 change: 0 additions & 1 deletion ddmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ struct Param
bool cleanupObjectFiles;

// Profile-guided optimization:
bool genInstrProf; // Whether to generate PGO instrumented code
const(char)* datafileInstrProf; // Either the input or output file for PGO data

// target stuff
Expand Down
1 change: 0 additions & 1 deletion ddmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ struct Param
bool cleanupObjectFiles;

// Profile-guided optimization:
bool genInstrProf; // Whether to generate PGO instrumented code
const char *datafileInstrProf; // Either the input or output file for PGO data

const llvm::Triple *targetTriple;
Expand Down
81 changes: 64 additions & 17 deletions driver/cl_options_instrumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,48 @@

#include "driver/cl_options_instrumentation.h"

#include "errors.h"
#include "globals.h"

namespace opts {
namespace {
namespace cl = llvm::cl;

cl::opt<std::string>
genfileInstrProf("fprofile-instr-generate", cl::value_desc("filename"),
cl::desc("Generate instrumented code to collect a runtime "
"profile into default.profraw (overriden by "
"'=<filename>' or LLVM_PROFILE_FILE env var)"),
cl::ZeroOrMore, cl::ValueOptional);
#if LDC_LLVM_VER >= 309
/// Option for generating IR-based PGO instrumentation (LLVM pass)
cl::opt<std::string> IRPGOInstrGenFile(
"fprofile-generate", cl::value_desc("filename"),
cl::desc("Generate instrumented code to collect a runtime "
"profile into default.profraw (overriden by "
"'=<filename>' or LLVM_PROFILE_FILE env var)"),
cl::ZeroOrMore, cl::ValueOptional);

cl::opt<std::string> usefileInstrProf(
/// Option for generating IR-based PGO instrumentation (LLVM pass)
cl::opt<std::string> IRPGOInstrUseFile(
"fprofile-use", cl::ZeroOrMore, cl::value_desc("filename"),
cl::desc("Use instrumentation data for profile-guided optimization"),
cl::ValueRequired);
#endif

/// Option for generating frontend-based PGO instrumentation
cl::opt<std::string> ASTPGOInstrGenFile(
"fprofile-instr-generate", cl::value_desc("filename"),
cl::desc("Generate instrumented code to collect a runtime "
"profile into default.profraw (overriden by "
"'=<filename>' or LLVM_PROFILE_FILE env var)"),
cl::ZeroOrMore, cl::ValueOptional);

/// Option for generating frontend-based PGO instrumentation
cl::opt<std::string> ASTPGOInstrUseFile(
"fprofile-instr-use", cl::ZeroOrMore, cl::value_desc("filename"),
cl::desc("Use instrumentation data for profile-guided optimization"),
cl::ValueRequired);

} // anonymous namespace

namespace opts {

PGOKind pgoMode = PGO_None;

cl::opt<bool>
instrumentFunctions("finstrument-functions", cl::ZeroOrMore,
cl::desc("Instrument function entry and exit with "
Expand All @@ -42,23 +68,44 @@ static cl::opt<bool> dmdFunctionTrace(
cl::desc("DMD-style runtime performance profiling of generated code"));

void initializeInstrumentationOptionsFromCmdline() {
if (genfileInstrProf.getNumOccurrences() > 0) {
global.params.genInstrProf = true;
if (genfileInstrProf.empty()) {
if (ASTPGOInstrGenFile.getNumOccurrences() > 0) {
pgoMode = PGO_ASTBasedInstr;
if (ASTPGOInstrGenFile.empty()) {
#if LDC_LLVM_VER >= 309
// profile-rt provides a default filename by itself
global.params.datafileInstrProf = nullptr;
#else
global.params.datafileInstrProf = "default.profraw";
#endif
} else {
initFromPathString(global.params.datafileInstrProf, genfileInstrProf);
initFromPathString(global.params.datafileInstrProf, ASTPGOInstrGenFile);
}
} else {
global.params.genInstrProf = false;
// If we don't have to generate instrumentation, we could be given a
// profdata file:
initFromPathString(global.params.datafileInstrProf, usefileInstrProf);
} else if (!ASTPGOInstrUseFile.empty()) {
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)
Expand Down
30 changes: 25 additions & 5 deletions driver/cl_options_instrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,35 @@
namespace opts {
namespace cl = llvm::cl;

// PGO options
extern cl::opt<std::string> genfileInstrProf;
extern cl::opt<std::string> usefileInstrProf;

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 {
PGO_None,
PGO_ASTBasedInstr,
PGO_ASTBasedUse,
PGO_IRBasedInstr,
PGO_IRBasedUse,
};
extern PGOKind pgoMode;
inline bool isInstrumentingForPGO() {
return pgoMode == PGO_ASTBasedInstr || pgoMode == PGO_IRBasedInstr;
}
inline bool isUsingPGOProfile() {
return pgoMode == PGO_ASTBasedUse || pgoMode == PGO_IRBasedUse;
}
inline bool isInstrumentingForASTBasedPGO() {
return pgoMode == PGO_ASTBasedInstr;
}
inline bool isUsingASTBasedPGOProfile() { return pgoMode == PGO_ASTBasedUse; }
inline bool isInstrumentingForIRBasedPGO() {
return pgoMode == PGO_IRBasedInstr;
}
inline bool isUsingIRBasedPGOProfile() { return pgoMode == PGO_IRBasedUse; }

} // namespace opts
#endif // LDC_DRIVER_CL_OPTIONS_INSTRUMENTATION_H
3 changes: 2 additions & 1 deletion driver/codegenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "module.h"
#include "scope.h"
#include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/linker.h"
#include "driver/toobj.h"
#include "gen/logger.h"
Expand Down Expand Up @@ -68,7 +69,7 @@ createAndSetDiagnosticsOutputFile(IRState &irs, llvm::LLVMContext &ctx,
llvm::make_unique<llvm::yaml::Output>(diagnosticsOutputFile->os()));

// If there is instrumentation data available, also output function hotness
if (!global.params.genInstrProf && global.params.datafileInstrProf) {
if (opts::isUsingPGOProfile()) {
#if LDC_LLVM_VER >= 500
ctx.setDiagnosticsHotnessRequested(true);
#else
Expand Down
5 changes: 3 additions & 2 deletions driver/linker-gcc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "errors.h"
#include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/cl_options_sanitizers.h"
#include "driver/exe_path.h"
#include "driver/tool.h"
Expand Down Expand Up @@ -337,7 +338,7 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
}

// Link with profile-rt library when generating an instrumented binary.
if (global.params.genInstrProf) {
if (opts::isInstrumentingForPGO()) {
#if LDC_LLVM_VER >= 308
if (global.params.targetTriple->isOSLinux()) {
// For Linux, explicitly define __llvm_profile_runtime as undefined
Expand Down Expand Up @@ -394,7 +395,7 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
// instrumented binary. The runtime relies on magic sections, which
// would be stripped by gc-section on older version of ld, see bug:
// https://sourceware.org/bugzilla/show_bug.cgi?id=19161
if (!opts::disableLinkerStripDead && !global.params.genInstrProf) {
if (!opts::disableLinkerStripDead && !opts::isInstrumentingForPGO()) {
addLdFlag("--gc-sections");
}
}
Expand Down
4 changes: 2 additions & 2 deletions driver/linker-msvc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "errors.h"
#include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/tool.h"
#include "gen/logger.h"

Expand Down Expand Up @@ -110,8 +111,7 @@ int linkObjToBinaryMSVC(llvm::StringRef outputPath, bool useInternalLinker,
args.push_back(std::string("/DEF:") + global.params.deffile);

// Link with profile-rt library when generating an instrumented binary
// profile-rt depends on Phobos (MD5 hashing).
if (global.params.genInstrProf) {
if (opts::isInstrumentingForPGO()) {
args.push_back("ldc-profile-rt.lib");
// profile-rt depends on ws2_32 for symbol `gethostname`
args.push_back("ws2_32.lib");
Expand Down
3 changes: 2 additions & 1 deletion driver/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,6 @@ void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
}
#endif

opts::initializeInstrumentationOptionsFromCmdline();
opts::initializeSanitizerOptionsFromCmdline();

processVersions(debugArgs, "debug", DebugCondition::setGlobalLevel,
Expand Down Expand Up @@ -1067,6 +1066,8 @@ int cppmain(int argc, char **argv) {
global.lib_ext = "a";
}

opts::initializeInstrumentationOptionsFromCmdline();

Strings libmodules;
return mars_mainBody(files, libmodules);
}
Expand Down
2 changes: 1 addition & 1 deletion gen/funcgenstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#define LDC_GEN_FUNCGENSTATE_H

#include "gen/irstate.h"
#include "gen/pgo.h"
#include "gen/pgo_ASTbased.h"
#include "gen/trycatchfinally.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/CallSite.h"
Expand Down
2 changes: 1 addition & 1 deletion gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include "gen/mangling.h"
#include "gen/nested.h"
#include "gen/optimizer.h"
#include "gen/pgo.h"
#include "gen/pgo_ASTbased.h"
#include "gen/pragma.h"
#include "gen/runtime.h"
#include "gen/dynamiccompile.h"
Expand Down
6 changes: 3 additions & 3 deletions gen/modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "statement.h"
#include "target.h"
#include "template.h"
#include "driver/cl_options_instrumentation.h"
#include "gen/abi.h"
#include "gen/arrays.h"
#include "gen/functions.h"
Expand Down Expand Up @@ -611,9 +612,8 @@ void addCoverageAnalysisInitializer(Module *m) {
// TODO: This is probably not the right place, we should load it once for all
// modules?
void loadInstrProfileData(IRState *irs) {
// Only load from datafileInstrProf if we are not generating instrumented
// code.
if (!global.params.genInstrProf && global.params.datafileInstrProf) {
// Only load from datafileInstrProf if we are doing frontend-based PGO.
if (opts::isUsingASTBasedPGOProfile() && global.params.datafileInstrProf) {
IF_LOG Logger::println("Read profile data from %s",
global.params.datafileInstrProf);

Expand Down
21 changes: 16 additions & 5 deletions gen/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "gen/logger.h"
#include "gen/passes/Passes.h"
#include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/cl_options_sanitizers.h"
#include "driver/targetmachine.h"
#include "llvm/LinkAllPasses.h"
Expand Down Expand Up @@ -206,9 +207,9 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
}

// Adds PGO instrumentation generation and use passes.
static void addPGOPasses(legacy::PassManagerBase &mpm, unsigned optLevel) {
if (global.params.genInstrProf) {
// We are generating PGO instrumented code.
static void addPGOPasses(PassManagerBuilder &builder,
legacy::PassManagerBase &mpm, unsigned optLevel) {
if (opts::isInstrumentingForASTBasedPGO()) {
InstrProfOptions options;
options.NoRedZone = global.params.disableRedZone;
if (global.params.datafileInstrProf)
Expand All @@ -218,7 +219,7 @@ static void addPGOPasses(legacy::PassManagerBase &mpm, unsigned optLevel) {
#else
mpm.add(createInstrProfilingPass(options));
#endif
} else if (global.params.datafileInstrProf) {
} else if (opts::isUsingASTBasedPGOProfile()) {
// We are generating code with PGO profile information available.
#if LDC_LLVM_VER >= 500
// Do indirect call promotion from -O1
Expand All @@ -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
}

/**
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 7f087f4

Please sign in to comment.