llvm/lib/IR/DiagnosticInfo.cpp

265 lines
9.6 KiB
C++
Raw Normal View History

//===- llvm/Support/DiagnosticInfo.cpp - Diagnostic Definitions -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the different classes involved in low level diagnostics.
//
// Diagnostics reporting is still done as part of the LLVMContext.
//===----------------------------------------------------------------------===//
#include "LLVMContextImpl.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Regex.h"
#include <atomic>
#include <string>
using namespace llvm;
namespace {
/// \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 {
std::shared_ptr<Regex> Pattern;
void operator=(const std::string &Val) {
// Create a regexp object to match pass names for emitOptimizationRemark.
if (!Val.empty()) {
Pattern = std::make_shared<Regex>(Val);
std::string RegexError;
if (!Pattern->isValid(RegexError))
report_fatal_error("Invalid regular expression '" + Val +
"' in -pass-remarks: " + RegexError,
false);
}
}
};
static PassRemarksOpt PassRemarksOptLoc;
static PassRemarksOpt PassRemarksMissedOptLoc;
static PassRemarksOpt PassRemarksAnalysisOptLoc;
// -pass-remarks
// 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);
}
int llvm::getNextAvailablePluginDiagnosticKind() {
static std::atomic<int> PluginKindID(DK_FirstPluginKind);
return ++PluginKindID;
}
const char *DiagnosticInfoOptimizationRemarkAnalysis::AlwaysPrint = "";
DiagnosticInfoInlineAsm::DiagnosticInfoInlineAsm(const Instruction &I,
const Twine &MsgStr,
DiagnosticSeverity Severity)
: DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(0), MsgStr(MsgStr),
Instr(&I) {
if (const MDNode *SrcLoc = I.getMetadata("srcloc")) {
if (SrcLoc->getNumOperands() != 0)
IR: Split Metadata from Value Split `Metadata` away from the `Value` class hierarchy, as part of PR21532. Assembly and bitcode changes are in the wings, but this is the bulk of the change for the IR C++ API. I have a follow-up patch prepared for `clang`. If this breaks other sub-projects, I apologize in advance :(. Help me compile it on Darwin I'll try to fix it. FWIW, the errors should be easy to fix, so it may be simpler to just fix it yourself. This breaks the build for all metadata-related code that's out-of-tree. Rest assured the transition is mechanical and the compiler should catch almost all of the problems. Here's a quick guide for updating your code: - `Metadata` is the root of a class hierarchy with three main classes: `MDNode`, `MDString`, and `ValueAsMetadata`. It is distinct from the `Value` class hierarchy. It is typeless -- i.e., instances do *not* have a `Type`. - `MDNode`'s operands are all `Metadata *` (instead of `Value *`). - `TrackingVH<MDNode>` and `WeakVH` referring to metadata can be replaced with `TrackingMDNodeRef` and `TrackingMDRef`, respectively. If you're referring solely to resolved `MDNode`s -- post graph construction -- just use `MDNode*`. - `MDNode` (and the rest of `Metadata`) have only limited support for `replaceAllUsesWith()`. As long as an `MDNode` is pointing at a forward declaration -- the result of `MDNode::getTemporary()` -- it maintains a side map of its uses and can RAUW itself. Once the forward declarations are fully resolved RAUW support is dropped on the ground. This means that uniquing collisions on changing operands cause nodes to become "distinct". (This already happened fairly commonly, whenever an operand went to null.) If you're constructing complex (non self-reference) `MDNode` cycles, you need to call `MDNode::resolveCycles()` on each node (or on a top-level node that somehow references all of the nodes). Also, don't do that. Metadata cycles (and the RAUW machinery needed to construct them) are expensive. - An `MDNode` can only refer to a `Constant` through a bridge called `ConstantAsMetadata` (one of the subclasses of `ValueAsMetadata`). As a side effect, accessing an operand of an `MDNode` that is known to be, e.g., `ConstantInt`, takes three steps: first, cast from `Metadata` to `ConstantAsMetadata`; second, extract the `Constant`; third, cast down to `ConstantInt`. The eventual goal is to introduce `MDInt`/`MDFloat`/etc. and have metadata schema owners transition away from using `Constant`s when the type isn't important (and they don't care about referring to `GlobalValue`s). In the meantime, I've added transitional API to the `mdconst` namespace that matches semantics with the old code, in order to avoid adding the error-prone three-step equivalent to every call site. If your old code was: MDNode *N = foo(); bar(isa <ConstantInt>(N->getOperand(0))); baz(cast <ConstantInt>(N->getOperand(1))); bak(cast_or_null <ConstantInt>(N->getOperand(2))); bat(dyn_cast <ConstantInt>(N->getOperand(3))); bay(dyn_cast_or_null<ConstantInt>(N->getOperand(4))); you can trivially match its semantics with: MDNode *N = foo(); bar(mdconst::hasa <ConstantInt>(N->getOperand(0))); baz(mdconst::extract <ConstantInt>(N->getOperand(1))); bak(mdconst::extract_or_null <ConstantInt>(N->getOperand(2))); bat(mdconst::dyn_extract <ConstantInt>(N->getOperand(3))); bay(mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(4))); and when you transition your metadata schema to `MDInt`: MDNode *N = foo(); bar(isa <MDInt>(N->getOperand(0))); baz(cast <MDInt>(N->getOperand(1))); bak(cast_or_null <MDInt>(N->getOperand(2))); bat(dyn_cast <MDInt>(N->getOperand(3))); bay(dyn_cast_or_null<MDInt>(N->getOperand(4))); - A `CallInst` -- specifically, intrinsic instructions -- can refer to metadata through a bridge called `MetadataAsValue`. This is a subclass of `Value` where `getType()->isMetadataTy()`. `MetadataAsValue` is the *only* class that can legally refer to a `LocalAsMetadata`, which is a bridged form of non-`Constant` values like `Argument` and `Instruction`. It can also refer to any other `Metadata` subclass. (I'll break all your testcases in a follow-up commit, when I propagate this change to assembly.) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223802 91177308-0d34-0410-b5e6-96231b3b80d8
2014-12-09 18:38:53 +00:00
if (const auto *CI =
mdconst::dyn_extract<ConstantInt>(SrcLoc->getOperand(0)))
LocCookie = CI->getZExtValue();
}
}
void DiagnosticInfoInlineAsm::print(DiagnosticPrinter &DP) const {
DP << getMsgStr();
if (getLocCookie())
DP << " at line " << getLocCookie();
}
void DiagnosticInfoResourceLimit::print(DiagnosticPrinter &DP) const {
DP << getResourceName() << " limit";
if (getResourceLimit() != 0)
DP << " of " << getResourceLimit();
DP << " exceeded (" << getResourceSize() << ") in " << getFunction();
}
void DiagnosticInfoDebugMetadataVersion::print(DiagnosticPrinter &DP) const {
DP << "ignoring debug info with an invalid version (" << getMetadataVersion()
<< ") in " << getModule();
}
void DiagnosticInfoIgnoringInvalidDebugMetadata::print(
DiagnosticPrinter &DP) const {
DP << "ignoring invalid debug info in " << getModule().getModuleIdentifier();
}
void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const {
if (!FileName.empty()) {
DP << getFileName();
if (LineNum > 0)
DP << ":" << getLineNum();
DP << ": ";
}
DP << getMsg();
}
void DiagnosticInfoPGOProfile::print(DiagnosticPrinter &DP) const {
if (getFileName())
DP << getFileName() << ": ";
DP << getMsg();
}
bool DiagnosticInfoWithDebugLocBase::isLocationAvailable() const {
return getDebugLoc();
}
void DiagnosticInfoWithDebugLocBase::getLocation(StringRef *Filename,
unsigned *Line,
unsigned *Column) const {
DILocation *L = getDebugLoc();
assert(L != nullptr && "debug location is invalid");
*Filename = L->getFilename();
*Line = L->getLine();
*Column = L->getColumn();
}
const std::string DiagnosticInfoWithDebugLocBase::getLocationStr() const {
StringRef Filename("<unknown>");
unsigned Line = 0;
unsigned Column = 0;
if (isLocationAvailable())
getLocation(&Filename, &Line, &Column);
return (Filename + ":" + Twine(Line) + ":" + Twine(Column)).str();
}
void DiagnosticInfoOptimizationBase::print(DiagnosticPrinter &DP) const {
DP << getLocationStr() << ": " << getMsg();
[OptRemark,LDist] RFC: Add hotness attribute Summary: This is the first set of changes implementing the RFC from http://thread.gmane.org/gmane.comp.compilers.llvm.devel/98334 This is a cross-sectional patch; rather than implementing the hotness attribute for all optimization remarks and all passes in a patch set, it implements it for the 'missed-optimization' remark for Loop Distribution. My goal is to shake out the design issues before scaling it up to other types and passes. Hotness is computed as an integer as the multiplication of the block frequency with the function entry count. It's only printed in opt currently since clang prints the diagnostic fields directly. E.g.: remark: /tmp/t.c:3:3: loop not distributed: use -Rpass-analysis=loop-distribute for more info (hotness: 300) A new API added is similar to emitOptimizationRemarkMissed. The difference is that it additionally takes a code region that the diagnostic corresponds to. From this, hotness is computed using BFI. The new API is exposed via an analysis pass so that it can be made dependent on LazyBFI. (Thanks to Hal for the analysis pass idea.) This feature can all be enabled by setDiagnosticHotnessRequested in the LLVM context. If this is off, LazyBFI is not calculated (D22141) so there should be no overhead. A new command-line option is added to turn this on in opt. My plan is to switch all user of emitOptimizationRemark* to use this module instead. Reviewers: hfinkel Subscribers: rcox2, mzolotukhin, llvm-commits Differential Revision: http://reviews.llvm.org/D21771 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275583 91177308-0d34-0410-b5e6-96231b3b80d8
2016-07-15 17:23:20 +00:00
if (Hotness)
DP << " (hotness: " << *Hotness << ")";
}
bool DiagnosticInfoOptimizationRemark::isEnabled() const {
return PassRemarksOptLoc.Pattern &&
PassRemarksOptLoc.Pattern->match(getPassName());
}
bool DiagnosticInfoOptimizationRemarkMissed::isEnabled() const {
return PassRemarksMissedOptLoc.Pattern &&
PassRemarksMissedOptLoc.Pattern->match(getPassName());
}
bool DiagnosticInfoOptimizationRemarkAnalysis::isEnabled() const {
return shouldAlwaysPrint() ||
(PassRemarksAnalysisOptLoc.Pattern &&
PassRemarksAnalysisOptLoc.Pattern->match(getPassName()));
}
void DiagnosticInfoMIRParser::print(DiagnosticPrinter &DP) const {
DP << Diagnostic;
}
void llvm::emitOptimizationRemark(LLVMContext &Ctx, const char *PassName,
const Function &Fn, const DebugLoc &DLoc,
const Twine &Msg) {
Ctx.diagnose(DiagnosticInfoOptimizationRemark(PassName, Fn, DLoc, Msg));
}
void llvm::emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName,
const Function &Fn,
const DebugLoc &DLoc,
const Twine &Msg) {
Ctx.diagnose(DiagnosticInfoOptimizationRemarkMissed(PassName, Fn, DLoc, Msg));
}
void llvm::emitOptimizationRemarkAnalysis(LLVMContext &Ctx,
const char *PassName,
const Function &Fn,
const DebugLoc &DLoc,
const Twine &Msg) {
Ctx.diagnose(
DiagnosticInfoOptimizationRemarkAnalysis(PassName, Fn, DLoc, Msg));
}
void llvm::emitOptimizationRemarkAnalysisFPCommute(LLVMContext &Ctx,
const char *PassName,
const Function &Fn,
const DebugLoc &DLoc,
const Twine &Msg) {
Ctx.diagnose(DiagnosticInfoOptimizationRemarkAnalysisFPCommute(PassName, Fn,
DLoc, Msg));
}
void llvm::emitOptimizationRemarkAnalysisAliasing(LLVMContext &Ctx,
const char *PassName,
const Function &Fn,
const DebugLoc &DLoc,
const Twine &Msg) {
Ctx.diagnose(DiagnosticInfoOptimizationRemarkAnalysisAliasing(PassName, Fn,
DLoc, Msg));
}
bool DiagnosticInfoOptimizationFailure::isEnabled() const {
// Only print warnings.
return getSeverity() == DS_Warning;
}
void DiagnosticInfoUnsupported::print(DiagnosticPrinter &DP) const {
std::string Str;
raw_string_ostream OS(Str);
OS << getLocationStr() << ": in function " << getFunction().getName() << ' '
<< *getFunction().getFunctionType() << ": " << Msg << '\n';
OS.flush();
DP << Str;
}
void llvm::emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn,
const DebugLoc &DLoc, const Twine &Msg) {
Ctx.diagnose(DiagnosticInfoOptimizationFailure(
Fn, DLoc, Twine("loop not vectorized: " + Msg)));
}
void llvm::emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn,
const DebugLoc &DLoc, const Twine &Msg) {
Ctx.diagnose(DiagnosticInfoOptimizationFailure(
Fn, DLoc, Twine("loop not interleaved: " + Msg)));
}