68 changes: 50 additions & 18 deletions llvm/lib/IR/LLVMContextImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "LLVMContextImpl.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Regex.h"
Expand Down Expand Up @@ -48,20 +49,20 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)

namespace {

/// \brief Regular expression corresponding to the value given in the
/// command line flag -pass-remarks. Passes whose name matches this
/// regexp will emit a diagnostic when calling
/// LLVMContext::emitOptimizationRemark.
static Regex *OptimizationRemarkPattern = nullptr;

/// \brief Regular expression corresponding to the value given in one of the
/// -pass-remarks* command line flags. Passes whose name matches this regexp
/// will emit a diagnostic when calling the associated diagnostic function
/// (emitOptimizationRemark, emitOptimizationRemarkMissed or
/// emitOptimizationRemarkAnalysis).
struct PassRemarksOpt {
void operator=(const std::string &Val) const {
std::shared_ptr<Regex> Pattern;

void operator=(const std::string &Val) {
// Create a regexp object to match pass names for emitOptimizationRemark.
if (!Val.empty()) {
delete OptimizationRemarkPattern;
OptimizationRemarkPattern = new Regex(Val);
Pattern = std::make_shared<Regex>(Val);
std::string RegexError;
if (!OptimizationRemarkPattern->isValid(RegexError))
if (!Pattern->isValid(RegexError))
report_fatal_error("Invalid regular expression '" + Val +
"' in -pass-remarks: " + RegexError,
false);
Expand All @@ -70,31 +71,62 @@ struct PassRemarksOpt {
};

static PassRemarksOpt PassRemarksOptLoc;
static PassRemarksOpt PassRemarksMissedOptLoc;
static PassRemarksOpt PassRemarksAnalysisOptLoc;

// -pass-remarks
// Command line flag to enable LLVMContext::emitOptimizationRemark()
// and LLVMContext::emitOptimizationNote() calls.
// Command line flag to enable emitOptimizationRemark()
static cl::opt<PassRemarksOpt, true, cl::parser<std::string>>
PassRemarks("pass-remarks", cl::value_desc("pattern"),
cl::desc("Enable optimization remarks from passes whose name match "
"the given regular expression"),
cl::Hidden, cl::location(PassRemarksOptLoc), cl::ValueRequired,
cl::ZeroOrMore);

// -pass-remarks-missed
// Command line flag to enable emitOptimizationRemarkMissed()
static cl::opt<PassRemarksOpt, true, cl::parser<std::string>> PassRemarksMissed(
"pass-remarks-missed", cl::value_desc("pattern"),
cl::desc("Enable missed optimization remarks from passes whose name match "
"the given regular expression"),
cl::Hidden, cl::location(PassRemarksMissedOptLoc), cl::ValueRequired,
cl::ZeroOrMore);

// -pass-remarks-analysis
// Command line flag to enable emitOptimizationRemarkAnalysis()
static cl::opt<PassRemarksOpt, true, cl::parser<std::string>>
PassRemarksAnalysis(
"pass-remarks-analysis", cl::value_desc("pattern"),
cl::desc(
"Enable optimization analysis remarks from passes whose name match "
"the given regular expression"),
cl::Hidden, cl::location(PassRemarksAnalysisOptLoc), cl::ValueRequired,
cl::ZeroOrMore);
}

bool
LLVMContextImpl::optimizationRemarksEnabledFor(const char *PassName) const {
return OptimizationRemarkPattern &&
OptimizationRemarkPattern->match(PassName);
bool LLVMContextImpl::optimizationRemarkEnabledFor(
const DiagnosticInfoOptimizationRemark *DI) const {
return PassRemarksOptLoc.Pattern &&
PassRemarksOptLoc.Pattern->match(DI->getPassName());
}

bool LLVMContextImpl::optimizationRemarkEnabledFor(
const DiagnosticInfoOptimizationRemarkMissed *DI) const {
return PassRemarksMissedOptLoc.Pattern &&
PassRemarksMissedOptLoc.Pattern->match(DI->getPassName());
}

bool LLVMContextImpl::optimizationRemarkEnabledFor(
const DiagnosticInfoOptimizationRemarkAnalysis *DI) const {
return PassRemarksAnalysisOptLoc.Pattern &&
PassRemarksAnalysisOptLoc.Pattern->match(DI->getPassName());
}

namespace {
struct DropReferences {
// Takes the value_type of a ConstantUniqueMap's internal map, whose 'second'
// is a Constant*.
template<typename PairT>
void operator()(const PairT &P) {
template <typename PairT> void operator()(const PairT &P) {
P.second->dropAllReferences();
}
};
Expand Down
10 changes: 9 additions & 1 deletion llvm/lib/IR/LLVMContextImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ namespace llvm {

class ConstantInt;
class ConstantFP;
class DiagnosticInfoOptimizationRemark;
class DiagnosticInfoOptimizationRemarkMissed;
class DiagnosticInfoOptimizationRemarkAnalysis;
class LLVMContext;
class Type;
class Value;
Expand Down Expand Up @@ -373,7 +376,12 @@ class LLVMContextImpl {

/// \brief Return true if the given pass name should emit optimization
/// remarks.
bool optimizationRemarksEnabledFor(const char *PassName) const;
bool optimizationRemarkEnabledFor(
const DiagnosticInfoOptimizationRemark *DI) const;
bool optimizationRemarkEnabledFor(
const DiagnosticInfoOptimizationRemarkMissed *DI) const;
bool optimizationRemarkEnabledFor(
const DiagnosticInfoOptimizationRemarkAnalysis *DI) const;

int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx);
int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx);
Expand Down
51 changes: 43 additions & 8 deletions llvm/lib/Transforms/IPO/Inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ unsigned Inliner::getInlineThreshold(CallSite CS) const {
return thres;
}

static void emitAnalysis(CallSite CS, const Twine &Msg) {
Function *Caller = CS.getCaller();
LLVMContext &Ctx = Caller->getContext();
DebugLoc DLoc = CS.getInstruction()->getDebugLoc();
emitOptimizationRemarkAnalysis(Ctx, DEBUG_TYPE, *Caller, DLoc, Msg);
}

/// shouldInline - Return true if the inliner should attempt to inline
/// at the given CallSite.
bool Inliner::shouldInline(CallSite CS) {
Expand All @@ -309,12 +316,16 @@ bool Inliner::shouldInline(CallSite CS) {
if (IC.isAlways()) {
DEBUG(dbgs() << " Inlining: cost=always"
<< ", Call: " << *CS.getInstruction() << "\n");
emitAnalysis(CS, Twine(CS.getCalledFunction()->getName()) +
" should always be inlined (cost=always)");
return true;
}

if (IC.isNever()) {
DEBUG(dbgs() << " NOT Inlining: cost=never"
<< ", Call: " << *CS.getInstruction() << "\n");
emitAnalysis(CS, Twine(CS.getCalledFunction()->getName() +
" should never be inlined (cost=never)"));
return false;
}

Expand All @@ -323,6 +334,10 @@ bool Inliner::shouldInline(CallSite CS) {
DEBUG(dbgs() << " NOT Inlining: cost=" << IC.getCost()
<< ", thres=" << (IC.getCostDelta() + IC.getCost())
<< ", Call: " << *CS.getInstruction() << "\n");
emitAnalysis(CS, Twine(CS.getCalledFunction()->getName() +
" too costly to inline (cost=") +
Twine(IC.getCost()) + ", threshold=" +
Twine(IC.getCostDelta() + IC.getCost()) + ")");
return false;
}

Expand Down Expand Up @@ -390,13 +405,22 @@ bool Inliner::shouldInline(CallSite CS) {
DEBUG(dbgs() << " NOT Inlining: " << *CS.getInstruction() <<
" Cost = " << IC.getCost() <<
", outer Cost = " << TotalSecondaryCost << '\n');
emitAnalysis(
CS, Twine("Not inlining. Cost of inlining " +
CS.getCalledFunction()->getName() +
" increases the cost of inlining " +
CS.getCaller()->getName() + " in other contexts"));
return false;
}
}

DEBUG(dbgs() << " Inlining: cost=" << IC.getCost()
<< ", thres=" << (IC.getCostDelta() + IC.getCost())
<< ", Call: " << *CS.getInstruction() << '\n');
emitAnalysis(
CS, CS.getCalledFunction()->getName() + Twine(" can be inlined into ") +
CS.getCaller()->getName() + " with cost=" + Twine(IC.getCost()) +
" (threshold=" + Twine(IC.getCostDelta() + IC.getCost()) + ")");
return true;
}

Expand Down Expand Up @@ -518,24 +542,35 @@ bool Inliner::runOnSCC(CallGraphSCC &SCC) {
InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory))
continue;


// If the policy determines that we should inline this function,
// try to do so.
if (!shouldInline(CS))
continue;
LLVMContext &CallerCtx = Caller->getContext();

// Get DebugLoc to report. CS will be invalid after Inliner.
DebugLoc DLoc = CS.getInstruction()->getDebugLoc();

// If the policy determines that we should inline this function,
// try to do so.
if (!shouldInline(CS)) {
emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,
Twine(Callee->getName() +
" will not be inlined into " +
Caller->getName()));
continue;
}

// Attempt to inline the function.
if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas,
InlineHistoryID, InsertLifetime, DL))
InlineHistoryID, InsertLifetime, DL)) {
emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,
Twine(Callee->getName() +
" will not be inlined into " +
Caller->getName()));
continue;
}
++NumInlined;

// Report the inline decision.
Caller->getContext().emitOptimizationRemark(
DEBUG_TYPE, *Caller, DLoc,
emitOptimizationRemark(
CallerCtx, DEBUG_TYPE, *Caller, DLoc,
Twine(Callee->getName() + " inlined into " + Caller->getName()));

// If inlining this function gave us any new call sites, throw them
Expand Down
16 changes: 8 additions & 8 deletions llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
Expand Down Expand Up @@ -318,8 +319,8 @@ bool TailCallElim::markTails(Function &F, bool &AllCallsAreTailCalls) {
break;
}
if (SafeToTail) {
F.getContext().emitOptimizationRemark(
"tailcallelim", F, CI->getDebugLoc(),
emitOptimizationRemark(
F.getContext(), "tailcallelim", F, CI->getDebugLoc(),
"marked this readnone call a tail call candidate");
CI->setTailCall();
Modified = true;
Expand Down Expand Up @@ -365,9 +366,9 @@ bool TailCallElim::markTails(Function &F, bool &AllCallsAreTailCalls) {
if (Visited[CI->getParent()] != ESCAPED) {
// If the escape point was part way through the block, calls after the
// escape point wouldn't have been put into DeferredTails.
F.getContext().emitOptimizationRemark(
"tailcallelim", F, CI->getDebugLoc(),
"marked this call a tail call candidate");
emitOptimizationRemark(F.getContext(), "tailcallelim", F,
CI->getDebugLoc(),
"marked this call a tail call candidate");
CI->setTailCall();
Modified = true;
} else {
Expand Down Expand Up @@ -678,9 +679,8 @@ bool TailCallElim::EliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret,
BasicBlock *BB = Ret->getParent();
Function *F = BB->getParent();

F->getContext().emitOptimizationRemark(
"tailcallelim", *F, CI->getDebugLoc(),
"transforming tail recursion to loop");
emitOptimizationRemark(F->getContext(), "tailcallelim", *F, CI->getDebugLoc(),
"transforming tail recursion to loop");

// OK! We can transform this tail call. If this is the first one found,
// create the new entry block, allowing us to branch back to the old entry.
Expand Down
9 changes: 5 additions & 4 deletions llvm/lib/Transforms/Utils/LoopUnroll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -237,9 +238,9 @@ bool llvm::UnrollLoop(Loop *L, unsigned Count, unsigned TripCount,
if (CompletelyUnroll) {
DEBUG(dbgs() << "COMPLETELY UNROLLING loop %" << Header->getName()
<< " with trip count " << TripCount << "!\n");
Ctx.emitOptimizationRemark(DEBUG_TYPE, *F, LoopLoc,
Twine("completely unrolled loop with ") +
Twine(TripCount) + " iterations");
emitOptimizationRemark(Ctx, DEBUG_TYPE, *F, LoopLoc,
Twine("completely unrolled loop with ") +
Twine(TripCount) + " iterations");
} else {
DEBUG(dbgs() << "UNROLLING loop %" << Header->getName()
<< " by " << Count);
Expand All @@ -255,7 +256,7 @@ bool llvm::UnrollLoop(Loop *L, unsigned Count, unsigned TripCount,
DiagMsg.concat(" with run-time trip count");
}
DEBUG(dbgs() << "!\n");
Ctx.emitOptimizationRemark(DEBUG_TYPE, *F, LoopLoc, DiagMsg);
emitOptimizationRemark(Ctx, DEBUG_TYPE, *F, LoopLoc, DiagMsg);
}

bool ContinueOnTrue = L->contains(BI->getSuccessor(0));
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
Expand Down Expand Up @@ -789,9 +790,9 @@ struct StrLenOpt : public LibCallOptimization {
uint64_t LenTrue = GetStringLength(SI->getTrueValue());
uint64_t LenFalse = GetStringLength(SI->getFalseValue());
if (LenTrue && LenFalse) {
Context->emitOptimizationRemark(
"simplify-libcalls", *Caller, SI->getDebugLoc(),
"folded strlen(select) to select of constants");
emitOptimizationRemark(*Context, "simplify-libcalls", *Caller,
SI->getDebugLoc(),
"folded strlen(select) to select of constants");
return B.CreateSelect(SI->getCondition(),
ConstantInt::get(CI->getType(), LenTrue-1),
ConstantInt::get(CI->getType(), LenFalse-1));
Expand Down
13 changes: 7 additions & 6 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
Expand Down Expand Up @@ -1213,10 +1214,10 @@ struct LoopVectorize : public FunctionPass {
DEBUG(dbgs() << "LV: Trying to at least unroll the loops.\n");

// Report the unrolling decision.
F->getContext().emitOptimizationRemark(
DEBUG_TYPE, *F, L->getStartLoc(),
Twine("unrolled with interleaving factor " + Twine(UF) +
" (vectorization not beneficial)"));
emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, L->getStartLoc(),
Twine("unrolled with interleaving factor " +
Twine(UF) +
" (vectorization not beneficial)"));

// We decided not to vectorize, but we may want to unroll.
InnerLoopUnroller Unroller(L, SE, LI, DT, DL, TLI, UF);
Expand All @@ -1228,8 +1229,8 @@ struct LoopVectorize : public FunctionPass {
++LoopsVectorized;

// Report the vectorization decision.
F->getContext().emitOptimizationRemark(
DEBUG_TYPE, *F, L->getStartLoc(),
emitOptimizationRemark(
F->getContext(), DEBUG_TYPE, *F, L->getStartLoc(),
Twine("vectorized loop (vectorization factor: ") + Twine(VF.Width) +
", unrolling interleave factor: " + Twine(UF) + ")");
}
Expand Down
60 changes: 60 additions & 0 deletions llvm/test/Transforms/Inline/optimization-remarks.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline -pass-remarks-analysis=inline -S 2>&1 | FileCheck %s

; CHECK: foo should always be inlined (cost=always)
; CHECK: foo inlined into bar
; CHECK: foz should never be inlined (cost=never)
; CHECK: foz will not be inlined into bar

; Function Attrs: alwaysinline nounwind uwtable
define i32 @foo(i32 %x, i32 %y) #0 {
entry:
%x.addr = alloca i32, align 4
%y.addr = alloca i32, align 4
store i32 %x, i32* %x.addr, align 4
store i32 %y, i32* %y.addr, align 4
%0 = load i32* %x.addr, align 4
%1 = load i32* %y.addr, align 4
%add = add nsw i32 %0, %1
ret i32 %add
}

; Function Attrs: noinline nounwind uwtable
define float @foz(i32 %x, i32 %y) #1 {
entry:
%x.addr = alloca i32, align 4
%y.addr = alloca i32, align 4
store i32 %x, i32* %x.addr, align 4
store i32 %y, i32* %y.addr, align 4
%0 = load i32* %x.addr, align 4
%1 = load i32* %y.addr, align 4
%mul = mul nsw i32 %0, %1
%conv = sitofp i32 %mul to float
ret float %conv
}

; Function Attrs: nounwind uwtable
define i32 @bar(i32 %j) #2 {
entry:
%j.addr = alloca i32, align 4
store i32 %j, i32* %j.addr, align 4
%0 = load i32* %j.addr, align 4
%1 = load i32* %j.addr, align 4
%sub = sub nsw i32 %1, 2
%call = call i32 @foo(i32 %0, i32 %sub)
%conv = sitofp i32 %call to float
%2 = load i32* %j.addr, align 4
%sub1 = sub nsw i32 %2, 2
%3 = load i32* %j.addr, align 4
%call2 = call float @foz(i32 %sub1, i32 %3)
%mul = fmul float %conv, %call2
%conv3 = fptosi float %mul to i32
ret i32 %conv3
}

attributes #0 = { alwaysinline nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { noinline nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = metadata !{metadata !"clang version 3.5.0 "}