ldc/gen/irstate.h
Johan Engelen e0d9c58443 [PGO] Add PGO to LDC. Supported for LLVM >= 3.7
Add the commandline options -fprofile-instr-generate[=filename] and -profile-instr-use=filename
-fprofile-instr-generate
-- Add instrumentation on branches, switches, and function entry; uses LLVM's InstrProf pass.
-- Link to profile runtime that writes instrumentation counters to a file.
-fprofile-instr-use
-- Read profile data from a file and apply branch weights to branches and switches, and annotate functions with entrycount in LLVM IR.
-- Functions with low or high entrycount are marked with 'cold' or 'inlinehint'.

The only statement type without PGO yet is "try-finally".

A new pragma, `pragma(LDC_profile_instr, [ true | false ])`, is added to selectively disable/enable instrumentation of functions (granularity = whole functions).

The runtime library ldc-profile-rt is a copy of LLVM compiler-rt lib/profile. It has to be exactly in-sync with the LLVM version, and thus we need a copy for each PGO-supported LLVM (>=3.7).
import ldc.profile for a D interface to ldc-profile-rt (for example to reset execution counts after a program startup phase).

The instrumentation data is mainly passed on to LLVM: function-entry counts and branch counts/probabilities. LDC marks functions as hot when "execution count is 30% of the maximum function execution count", and marks functions as cold if their count is 1% of maximum function execution count.

The source of LLVM's llvm-profdata tool is hereby included in LDCs repository (different source for each LLVM version), and the binary is included in the install bin folder.
The executable is named "ldc-profdata" to avoid clashing with llvm-profdata on the same machine. This is needed because profdata executable has to be in-sync with the LLVM version used to build LDC.

Maintenance burden: for trunk LLVM, we have to keep ldc-profile-rt and llvm-profdata in sync. There is no diff with upstream; but because of active development there are the occasional API changes.
2016-06-20 17:28:22 +02:00

201 lines
5.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- gen/irstate.h - Global codegen state --------------------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the global state used and modified when generating the
// code (i.e. LLVM IR) for a given D module.
//
//===----------------------------------------------------------------------===//
#ifndef LDC_GEN_IRSTATE_H
#define LDC_GEN_IRSTATE_H
#include "aggregate.h"
#include "root.h"
#include "ir/iraggr.h"
#include "ir/irvar.h"
#include "gen/dibuilder.h"
#include <deque>
#include <list>
#include <set>
#include <sstream>
#include <vector>
#include "llvm/ADT/StringMap.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/IR/CallSite.h"
namespace llvm {
class LLVMContext;
class TargetMachine;
class IndexedInstrProfReader;
}
// global ir state for current module
struct IRState;
struct TargetABI;
extern IRState *gIR;
extern llvm::TargetMachine *gTargetMachine;
extern const llvm::DataLayout *gDataLayout;
extern TargetABI *gABI;
class TypeFunction;
class TypeStruct;
class ClassDeclaration;
class FuncDeclaration;
class Module;
class TypeStruct;
struct BaseClass;
class AnonDeclaration;
struct IrFunction;
struct IrModule;
// represents a scope
struct IRScope {
llvm::BasicBlock *begin;
IRBuilder<> builder;
IRScope();
explicit IRScope(llvm::BasicBlock *b);
IRScope &operator=(const IRScope &rhs);
};
struct IRBuilderHelper {
IRState *state;
IRBuilder<> *operator->();
};
struct IRAsmStmt {
IRAsmStmt() : isBranchToLabel(nullptr) {}
std::string code;
std::string out_c;
std::string in_c;
std::vector<LLValue *> out;
std::vector<LLValue *> in;
// if this is nonzero, it contains the target label
LabelDsymbol *isBranchToLabel;
};
struct IRAsmBlock {
std::deque<IRAsmStmt *> s;
std::set<std::string> clobs;
size_t outputcount;
// stores the labels within the asm block
std::vector<Identifier *> internalLabels;
CompoundAsmStatement *asmBlock;
LLType *retty;
unsigned retn;
bool retemu; // emulate abi ret with a temporary
LLValue *(*retfixup)(IRBuilderHelper b, LLValue *orig); // Modifies retval
explicit IRAsmBlock(CompoundAsmStatement *b)
: outputcount(0), asmBlock(b), retty(nullptr), retn(0), retemu(false),
retfixup(nullptr) {}
};
// represents the module
struct IRState {
IRState(const char *name, llvm::LLVMContext &context);
llvm::Module module;
llvm::LLVMContext &context() const { return module.getContext(); }
Module *dmodule;
LLStructType *mutexType;
LLStructType *moduleRefType;
// functions
typedef std::vector<IrFunction *> FunctionVector;
FunctionVector functions;
IrFunction *func();
llvm::Function *topfunc();
llvm::Instruction *topallocapoint();
// The function containing the D main() body, if any (not the actual main()
// implicitly emitted).
llvm::Function *mainFunc;
// basic block scopes
std::vector<IRScope> scopes;
IRScope &scope();
llvm::BasicBlock *scopebb();
bool scopereturned();
// create a call or invoke, depending on the landing pad info
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, const char *Name = "");
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
const char *Name = "");
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
LLValue *Arg2, const char *Name = "");
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
LLValue *Arg2, LLValue *Arg3,
const char *Name = "");
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
LLValue *Arg2, LLValue *Arg3, LLValue *Arg4,
const char *Name = "");
// this holds the array being indexed or sliced so $ will work
// might be a better way but it works. problem is I only get a
// VarDeclaration for __dollar, but I can't see how to get the
// array pointer from this :(
std::vector<DValue *> arrays;
// builder helper
IRBuilderHelper ir;
// debug info helper
ldc::DIBuilder DBuilder;
// PGO data file reader
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
// for inline asm
IRAsmBlock *asmBlock;
std::ostringstream nakedAsm;
// Globals to pin in the llvm.used array to make sure they are not
// eliminated.
std::vector<LLConstant *> usedArray;
/// Whether to emit array bounds checking in the current function.
bool emitArrayBoundsChecks();
// Global variables bound to string literals. Once created such a
// variable is reused whenever the same string literal is
// referenced in the module. Caching them per module prevents the
// duplication of identical literals.
llvm::StringMap<llvm::GlobalVariable *> stringLiteral1ByteCache;
llvm::StringMap<llvm::GlobalVariable *> stringLiteral2ByteCache;
llvm::StringMap<llvm::GlobalVariable *> stringLiteral4ByteCache;
/// Vector of options passed to the linker as metadata in object file.
#if LDC_LLVM_VER >= 306
llvm::SmallVector<llvm::Metadata *, 5> LinkerMetadataArgs;
#else
llvm::SmallVector<llvm::Value *, 5> LinkerMetadataArgs;
#endif
#if LDC_LLVM_VER >= 308
// MS C++ compatible type descriptors
llvm::DenseMap<size_t, llvm::StructType *> TypeDescriptorTypeMap;
llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> TypeDescriptorMap;
#endif
};
void Statement_toIR(Statement *s, IRState *irs);
#endif // LDC_GEN_IRSTATE_H