Skip to content

Commit

Permalink
New OptimizationRemarkEmitter pass for MIR
Browse files Browse the repository at this point in the history
This allows MIR passes to emit optimization remarks with the same level
of functionality that is available to IR passes.

It also hooks up the greedy register allocator to report spills.  This
allows for interesting use cases like increasing interleaving on a loop
until spilling of registers is observed.

I still need to experiment whether reporting every spill scales but this
demonstrates for now that the functionality works from llc
using -pass-remarks*=<pass>.

Differential Revision: https://reviews.llvm.org/D29004

llvm-svn: 293110
  • Loading branch information
anemet committed Jan 25, 2017
1 parent 484f93d commit a964066
Show file tree
Hide file tree
Showing 13 changed files with 530 additions and 51 deletions.
6 changes: 6 additions & 0 deletions llvm/include/llvm/Analysis/OptimizationDiagnosticInfo.h
Expand Up @@ -282,5 +282,11 @@ class OptimizationRemarkEmitterAnalysis
/// \brief Run the analysis pass over a function and produce BFI.
Result run(Function &F, FunctionAnalysisManager &AM);
};

namespace yaml {
template <> struct MappingTraits<DiagnosticInfoOptimizationBase *> {
static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag);
};
}
}
#endif // LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H
7 changes: 7 additions & 0 deletions llvm/include/llvm/CodeGen/MachineLoopInfo.h
Expand Up @@ -60,6 +60,13 @@ class MachineLoop : public LoopBase<MachineBasicBlock, MachineLoop> {
/// multiple exiting blocks are present.
MachineBasicBlock *findLoopControlBlock();

/// Return the debug location of the start of this loop.
/// This looks for a BB terminating instruction with a known debug
/// location by looking at the preheader and header blocks. If it
/// cannot find a terminating instruction with location information,
/// it returns an unknown location.
DebugLoc getStartLoc() const;

void dump() const;

private:
Expand Down
188 changes: 188 additions & 0 deletions llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h
@@ -0,0 +1,188 @@
///===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*----===//
///
/// The LLVM Compiler Infrastructure
///
/// This file is distributed under the University of Illinois Open Source
/// License. See LICENSE.TXT for details.
///
///===---------------------------------------------------------------------===//
/// \file
/// Optimization diagnostic interfaces for machine passes. It's packaged as an
/// analysis pass so that by using this service passes become dependent on MBFI
/// as well. MBFI is used to compute the "hotness" of the diagnostic message.
///
///===---------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H
#define LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H

#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"

namespace llvm {
class MachineBasicBlock;
class MachineBlockFrequencyInfo;

/// \brief Common features for diagnostics dealing with optimization remarks
/// that are used by machine passes.
class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase {
public:
DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName,
StringRef RemarkName, const DebugLoc &DLoc,
MachineBasicBlock *MBB)
: DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, RemarkName,
*MBB->getParent()->getFunction(), DLoc),
MBB(MBB) {}

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() >= DK_FirstMachineRemark &&
DI->getKind() <= DK_LastMachineRemark;
}

const MachineBasicBlock *getBlock() const { return MBB; }

private:
MachineBasicBlock *MBB;
};

/// Diagnostic information for applied optimization remarks.
class MachineOptimizationRemark : public DiagnosticInfoMIROptimization {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass=, then the diagnostic will
/// be emitted. \p RemarkName is a textual identifier for the remark. \p
/// DLoc is the debug location and \p MBB is the block that the optimization
/// operates in.
MachineOptimizationRemark(const char *PassName, StringRef RemarkName,
const DebugLoc &DLoc, MachineBasicBlock *MBB)
: DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName,
RemarkName, DLoc, MBB) {}

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_MachineOptimizationRemark;
}

/// \see DiagnosticInfoOptimizationBase::isEnabled.
bool isEnabled() const override {
return OptimizationRemark::isEnabled(getPassName());
}
};

/// Diagnostic information for missed-optimization remarks.
class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-missed=, then the
/// diagnostic will be emitted. \p RemarkName is a textual identifier for the
/// remark. \p DLoc is the debug location and \p MBB is the block that the
/// optimization operates in.
MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
const DebugLoc &DLoc, MachineBasicBlock *MBB)
: DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed,
PassName, RemarkName, DLoc, MBB) {}

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_MachineOptimizationRemarkMissed;
}

/// \see DiagnosticInfoOptimizationBase::isEnabled.
bool isEnabled() const override {
return OptimizationRemarkMissed::isEnabled(getPassName());
}
};

/// Diagnostic information for optimization analysis remarks.
class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization {
public:
/// \p PassName is the name of the pass emitting this diagnostic. If this name
/// matches the regular expression given in -Rpass-analysis=, then the
/// diagnostic will be emitted. \p RemarkName is a textual identifier for the
/// remark. \p DLoc is the debug location and \p MBB is the block that the
/// optimization operates in.
MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
const DebugLoc &DLoc,
MachineBasicBlock *MBB)
: DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
PassName, RemarkName, DLoc, MBB) {}

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_MachineOptimizationRemarkAnalysis;
}

/// \see DiagnosticInfoOptimizationBase::isEnabled.
bool isEnabled() const override {
return OptimizationRemarkAnalysis::isEnabled(getPassName());
}
};

/// The optimization diagnostic interface.
///
/// It allows reporting when optimizations are performed and when they are not
/// along with the reasons for it. Hotness information of the corresponding
/// code region can be included in the remark if DiagnosticHotnessRequested is
/// enabled in the LLVM context.
class MachineOptimizationRemarkEmitter {
public:
MachineOptimizationRemarkEmitter(MachineFunction &MF,
MachineBlockFrequencyInfo *MBFI)
: MF(MF), MBFI(MBFI) {}

/// Emit an optimization remark.
void emit(DiagnosticInfoOptimizationBase &OptDiag);

/// \brief Whether we allow for extra compile-time budget to perform more
/// analysis to be more informative.
///
/// This is useful to enable additional missed optimizations to be reported
/// that are normally too noisy. In this mode, we can use the extra analysis
/// (1) to filter trivial false positives or (2) to provide more context so
/// that non-trivial false positives can be quickly detected by the user.
bool allowExtraAnalysis() const {
// For now, only allow this with -fsave-optimization-record since the -Rpass
// options are handled in the front-end.
return MF.getFunction()->getContext().getDiagnosticsOutputFile();
}

private:
MachineFunction &MF;

/// MBFI is only set if hotness is requested.
MachineBlockFrequencyInfo *MBFI;

/// Compute hotness from IR value (currently assumed to be a block) if PGO is
/// available.
Optional<uint64_t> computeHotness(const MachineBasicBlock &MBB);

/// Similar but use value from \p OptDiag and update hotness there.
void computeHotness(DiagnosticInfoMIROptimization &Remark);

/// \brief Only allow verbose messages if we know we're filtering by hotness
/// (BFI is only set in this case).
bool shouldEmitVerbose() { return MBFI != nullptr; }
};

/// The analysis pass
///
/// Note that this pass shouldn't generally be marked as preserved by other
/// passes. It's holding onto BFI, so if the pass does not preserve BFI, BFI
/// could be freed.
class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass {
std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;

public:
MachineOptimizationRemarkEmitterPass();

bool runOnMachineFunction(MachineFunction &MF) override;

void getAnalysisUsage(AnalysisUsage &AU) const override;

MachineOptimizationRemarkEmitter &getORE() {
assert(ORE && "pass not run yet");
return *ORE;
}

static char ID;
};
}

#endif
29 changes: 24 additions & 5 deletions llvm/include/llvm/IR/DiagnosticInfo.h
Expand Up @@ -69,6 +69,11 @@ enum DiagnosticKind {
DK_OptimizationFailure,
DK_FirstRemark = DK_OptimizationRemark,
DK_LastRemark = DK_OptimizationFailure,
DK_MachineOptimizationRemark,
DK_MachineOptimizationRemarkMissed,
DK_MachineOptimizationRemarkAnalysis,
DK_FirstMachineRemark = DK_MachineOptimizationRemark,
DK_LastMachineRemark = DK_MachineOptimizationRemarkAnalysis,
DK_MIRParser,
DK_PGOProfile,
DK_Unsupported,
Expand Down Expand Up @@ -440,8 +445,10 @@ class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithDebugLocBase {
bool isVerbose() const { return IsVerbose; }

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() >= DK_FirstRemark &&
DI->getKind() <= DK_LastRemark;
return (DI->getKind() >= DK_FirstRemark &&
DI->getKind() <= DK_LastRemark) ||
(DI->getKind() >= DK_FirstMachineRemark &&
DI->getKind() <= DK_LastMachineRemark);
}

protected:
Expand Down Expand Up @@ -529,6 +536,10 @@ class DiagnosticInfoIROptimization : public DiagnosticInfoOptimizationBase {

Value *getCodeRegion() const { return CodeRegion; }

static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() >= DK_FirstRemark && DI->getKind() <= DK_LastRemark;
}

private:
/// The IR value (currently basic block) that the optimization operates on.
/// This is currently used to provide run-time hotness information with PGO.
Expand Down Expand Up @@ -569,8 +580,10 @@ class OptimizationRemark : public DiagnosticInfoIROptimization {
return DI->getKind() == DK_OptimizationRemark;
}

static bool isEnabled(StringRef PassName);

/// \see DiagnosticInfoOptimizationBase::isEnabled.
bool isEnabled() const override;
bool isEnabled() const override { return isEnabled(getPassName()); }
};

/// Diagnostic information for missed-optimization remarks.
Expand Down Expand Up @@ -607,8 +620,10 @@ class OptimizationRemarkMissed : public DiagnosticInfoIROptimization {
return DI->getKind() == DK_OptimizationRemarkMissed;
}

static bool isEnabled(StringRef PassName);

/// \see DiagnosticInfoOptimizationBase::isEnabled.
bool isEnabled() const override;
bool isEnabled() const override { return isEnabled(getPassName()); }
};

/// Diagnostic information for optimization analysis remarks.
Expand Down Expand Up @@ -656,8 +671,12 @@ class OptimizationRemarkAnalysis : public DiagnosticInfoIROptimization {
return DI->getKind() == DK_OptimizationRemarkAnalysis;
}

static bool isEnabled(StringRef PassName);

/// \see DiagnosticInfoOptimizationBase::isEnabled.
bool isEnabled() const override;
bool isEnabled() const override {
return shouldAlwaysPrint() || isEnabled(getPassName());
}

static const char *AlwaysPrint;

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Expand Up @@ -232,6 +232,7 @@ void initializeMachineFunctionPrinterPassPass(PassRegistry&);
void initializeMachineLICMPass(PassRegistry&);
void initializeMachineLoopInfoPass(PassRegistry&);
void initializeMachineModuleInfoPass(PassRegistry&);
void initializeMachineOptimizationRemarkEmitterPassPass(PassRegistry&);
void initializeMachinePipelinerPass(PassRegistry&);
void initializeMachinePostDominatorTreePass(PassRegistry&);
void initializeMachineRegionInfoPassPass(PassRegistry&);
Expand Down
75 changes: 37 additions & 38 deletions llvm/lib/Analysis/OptimizationDiagnosticInfo.cpp
Expand Up @@ -67,44 +67,43 @@ Optional<uint64_t> OptimizationRemarkEmitter::computeHotness(const Value *V) {
namespace llvm {
namespace yaml {

template <> struct MappingTraits<DiagnosticInfoOptimizationBase *> {
static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag) {
assert(io.outputting() && "input not yet implemented");

if (io.mapTag("!Passed", OptDiag->getKind() == DK_OptimizationRemark))
;
else if (io.mapTag("!Missed",
OptDiag->getKind() == DK_OptimizationRemarkMissed))
;
else if (io.mapTag("!Analysis",
OptDiag->getKind() == DK_OptimizationRemarkAnalysis))
;
else if (io.mapTag("!AnalysisFPCommute",
OptDiag->getKind() ==
DK_OptimizationRemarkAnalysisFPCommute))
;
else if (io.mapTag("!AnalysisAliasing",
OptDiag->getKind() ==
DK_OptimizationRemarkAnalysisAliasing))
;
else
llvm_unreachable("todo");

// These are read-only for now.
DebugLoc DL = OptDiag->getDebugLoc();
StringRef FN = GlobalValue::getRealLinkageName(
OptDiag->getFunction().getName());

StringRef PassName(OptDiag->PassName);
io.mapRequired("Pass", PassName);
io.mapRequired("Name", OptDiag->RemarkName);
if (!io.outputting() || DL)
io.mapOptional("DebugLoc", DL);
io.mapRequired("Function", FN);
io.mapOptional("Hotness", OptDiag->Hotness);
io.mapOptional("Args", OptDiag->Args);
}
};
void MappingTraits<DiagnosticInfoOptimizationBase *>::mapping(
IO &io, DiagnosticInfoOptimizationBase *&OptDiag) {
assert(io.outputting() && "input not yet implemented");

if (io.mapTag("!Passed", OptDiag->getKind() == DK_OptimizationRemark))
;
else if (io.mapTag("!Missed",
OptDiag->getKind() == DK_OptimizationRemarkMissed))
;
else if (io.mapTag("!Analysis",
OptDiag->getKind() == DK_OptimizationRemarkAnalysis))
;
else if (io.mapTag("!AnalysisFPCommute",
OptDiag->getKind() ==
DK_OptimizationRemarkAnalysisFPCommute))
;
else if (io.mapTag("!AnalysisAliasing",
OptDiag->getKind() ==
DK_OptimizationRemarkAnalysisAliasing))
;
else
llvm_unreachable("todo");

// These are read-only for now.
DebugLoc DL = OptDiag->getDebugLoc();
StringRef FN =
GlobalValue::getRealLinkageName(OptDiag->getFunction().getName());

StringRef PassName(OptDiag->PassName);
io.mapRequired("Pass", PassName);
io.mapRequired("Name", OptDiag->RemarkName);
if (!io.outputting() || DL)
io.mapOptional("DebugLoc", DL);
io.mapRequired("Function", FN);
io.mapOptional("Hotness", OptDiag->Hotness);
io.mapOptional("Args", OptDiag->Args);
}

template <> struct MappingTraits<DebugLoc> {
static void mapping(IO &io, DebugLoc &DL) {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CMakeLists.txt
Expand Up @@ -71,6 +71,7 @@ add_llvm_library(LLVMCodeGen
MachineLoopInfo.cpp
MachineModuleInfo.cpp
MachineModuleInfoImpls.cpp
MachineOptimizationRemarkEmitter.cpp
MachinePassRegistry.cpp
MachinePipeliner.cpp
MachinePostDominators.cpp
Expand Down

0 comments on commit a964066

Please sign in to comment.