#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/DiagnosticInfo.h"
namespace llvm {
class Value;
class OptimizationRemarkEmitter;
class OptimizationRemarkMissed;
+class OptimizationRemarkAnalysis;
class StoreInst;
// FIXME: Once we get to more remarks like this one, we need to re-evaluate how
void visit(const Instruction *I);
protected:
- virtual std::string explainSource(StringRef Type);
+ virtual std::string explainSource(StringRef Type) const;
enum RemarkKind { RK_Store, RK_Unknown, RK_IntrinsicCall, RK_Call };
- virtual StringRef remarkName(RemarkKind RK);
+ virtual StringRef remarkName(RemarkKind RK) const;
+
+ virtual DiagnosticKind diagnosticKind() const { return DK_OptimizationRemarkAnalysis; }
private:
+ template<typename ...Ts>
+ std::unique_ptr<DiagnosticInfoIROptimization> makeRemark(Ts... Args);
+
/// Emit a remark using information from the store's destination, size, etc.
void visitStore(const StoreInst &SI);
/// Emit a generic auto-init remark.
/// Add callee information to a remark: whether it's known, the function name,
/// etc.
template <typename FTy>
- void visitCallee(FTy F, bool KnownLibCall, OptimizationRemarkMissed &R);
+ void visitCallee(FTy F, bool KnownLibCall, DiagnosticInfoIROptimization &R);
/// Add operand information to a remark based on knowledge we have for known
/// libcalls.
void visitKnownLibCall(const CallInst &CI, LibFunc LF,
- OptimizationRemarkMissed &R);
+ DiagnosticInfoIROptimization &R);
/// Add the memory operation size to a remark.
- void visitSizeOperand(Value *V, OptimizationRemarkMissed &R);
+ void visitSizeOperand(Value *V, DiagnosticInfoIROptimization &R);
struct VariableInfo {
Optional<StringRef> Name;
/// Gather more information about \p V as a variable. This can be debug info,
/// information from the alloca, etc. Since \p V can represent more than a
/// single variable, they will all be added to the remark.
- void visitPtr(Value *V, bool IsSrc, OptimizationRemarkMissed &R);
+ void visitPtr(Value *V, bool IsSrc, DiagnosticInfoIROptimization &R);
void visitVariable(const Value *V, SmallVectorImpl<VariableInfo> &Result);
};
static bool canHandle(const Instruction *I);
protected:
- virtual std::string explainSource(StringRef Type) override;
- virtual StringRef remarkName(RemarkKind RK) override;
+ virtual std::string explainSource(StringRef Type) const override;
+ virtual StringRef remarkName(RemarkKind RK) const override;
+ virtual DiagnosticKind diagnosticKind() const override {
+ return DK_OptimizationRemarkMissed;
+ }
};
} // namespace llvm
visitUnknown(*I);
}
-std::string MemoryOpRemark::explainSource(StringRef Type) {
+std::string MemoryOpRemark::explainSource(StringRef Type) const {
return (Type + ".").str();
}
-StringRef MemoryOpRemark::remarkName(RemarkKind RK) {
+StringRef MemoryOpRemark::remarkName(RemarkKind RK) const {
switch (RK) {
case RK_Store:
return "MemoryOpStore";
static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile,
bool Atomic,
- OptimizationRemarkMissed &R) {
+ DiagnosticInfoIROptimization &R) {
if (Inline && *Inline)
R << " Inlined: " << NV("StoreInlined", true) << ".";
if (Volatile)
return *SizeInBits / 8;
}
+template<typename ...Ts>
+std::unique_ptr<DiagnosticInfoIROptimization>
+MemoryOpRemark::makeRemark(Ts... Args) {
+ switch (diagnosticKind()) {
+ case DK_OptimizationRemarkAnalysis:
+ return std::make_unique<OptimizationRemarkAnalysis>(Args...);
+ case DK_OptimizationRemarkMissed:
+ return std::make_unique<OptimizationRemarkMissed>(Args...);
+ default:
+ llvm_unreachable("unexpected DiagnosticKind");
+ }
+}
+
void MemoryOpRemark::visitStore(const StoreInst &SI) {
bool Volatile = SI.isVolatile();
bool Atomic = SI.isAtomic();
int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
- OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Store), &SI);
- R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
- << " bytes.";
- visitPtr(SI.getOperand(1), /*IsRead=*/false, R);
- inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, R);
- ORE.emit(R);
+ auto R = makeRemark(RemarkPass.data(), remarkName(RK_Store), &SI);
+ *R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
+ << " bytes.";
+ visitPtr(SI.getOperand(1), /*IsRead=*/false, *R);
+ inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, *R);
+ ORE.emit(*R);
}
void MemoryOpRemark::visitUnknown(const Instruction &I) {
- OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Unknown), &I);
- R << explainSource("Initialization");
- ORE.emit(R);
+ auto R = makeRemark(RemarkPass.data(), remarkName(RK_Unknown), &I);
+ *R << explainSource("Initialization");
+ ORE.emit(*R);
}
void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {
return visitUnknown(II);
}
- OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_IntrinsicCall),
- &II);
- visitCallee(StringRef(CallTo), /*KnownLibCall=*/true, R);
- visitSizeOperand(II.getOperand(2), R);
+ auto R = makeRemark(RemarkPass.data(), remarkName(RK_IntrinsicCall), &II);
+ visitCallee(StringRef(CallTo), /*KnownLibCall=*/true, *R);
+ visitSizeOperand(II.getOperand(2), *R);
auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
// No such thing as a memory intrinsic that is both atomic and volatile.
case Intrinsic::memcpy:
case Intrinsic::memmove:
case Intrinsic::memcpy_element_unordered_atomic:
- visitPtr(II.getOperand(1), /*IsRead=*/true, R);
- visitPtr(II.getOperand(0), /*IsRead=*/false, R);
+ visitPtr(II.getOperand(1), /*IsRead=*/true, *R);
+ visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
break;
case Intrinsic::memset:
case Intrinsic::memset_element_unordered_atomic:
- visitPtr(II.getOperand(0), /*IsRead=*/false, R);
+ visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
break;
}
- inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, R);
- ORE.emit(R);
+ inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, *R);
+ ORE.emit(*R);
}
void MemoryOpRemark::visitCall(const CallInst &CI) {
LibFunc LF;
bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
- OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Call), &CI);
- visitCallee(F, KnownLibCall, R);
- visitKnownLibCall(CI, LF, R);
- ORE.emit(R);
+ auto R = makeRemark(RemarkPass.data(), remarkName(RK_Call), &CI);
+ visitCallee(F, KnownLibCall, *R);
+ visitKnownLibCall(CI, LF, *R);
+ ORE.emit(*R);
}
template <typename FTy>
void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,
- OptimizationRemarkMissed &R) {
+ DiagnosticInfoIROptimization &R) {
R << "Call to ";
if (!KnownLibCall)
R << NV("UnknownLibCall", "unknown") << " function ";
}
void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,
- OptimizationRemarkMissed &R) {
+ DiagnosticInfoIROptimization &R) {
switch (LF) {
default:
return;
}
}
-void MemoryOpRemark::visitSizeOperand(Value *V, OptimizationRemarkMissed &R) {
+void MemoryOpRemark::visitSizeOperand(Value *V, DiagnosticInfoIROptimization &R) {
if (auto *Len = dyn_cast<ConstantInt>(V)) {
uint64_t Size = Len->getZExtValue();
R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
Result.push_back(std::move(Var));
}
-void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, OptimizationRemarkMissed &R) {
+void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, DiagnosticInfoIROptimization &R) {
// Find if Ptr is a known variable we can give more information on.
SmallVector<Value *, 2> Objects;
getUnderlyingObjectsForCodeGen(Ptr, Objects);
});
}
-std::string AutoInitRemark::explainSource(StringRef Type) {
+std::string AutoInitRemark::explainSource(StringRef Type) const {
return (Type + " inserted by -ftrivial-auto-var-init.").str();
}
-StringRef AutoInitRemark::remarkName(RemarkKind RK) {
+StringRef AutoInitRemark::remarkName(RemarkKind RK) const {
switch (RK) {
case RK_Store:
return "AutoInitStore";
-; RUN: llc %s -pass-remarks-missed=memsize -pass-remarks-output=%t.opt.yaml -pass-remarks-filter=memsize -global-isel -o /dev/null 2>&1 | FileCheck %s --check-prefix=GISEL --implicit-check-not=GISEL
+; RUN: llc %s -pass-remarks-analysis=gisel-irtranslator-memsize -pass-remarks-output=%t.opt.yaml -pass-remarks-filter=gisel-irtranslator-memsize -global-isel -o /dev/null 2>&1 | FileCheck %s --check-prefix=GISEL --implicit-check-not=GISEL
; RUN: cat %t.opt.yaml | FileCheck -check-prefix=YAML %s
source_filename = "memsize.c"
; GISEL: Call to memset. Memory operation size: 1 bytes.
; GISEL-NOT: Read Variables:
; GISEL-NEXT: Written Variables: <unknown> (42 bytes).
-; YAML: --- !Missed
-; YAML: Pass: memsize
+; YAML: --- !Analysis
+; YAML: gisel-irtranslator-memsize
; YAML: Name: MemoryOpIntrinsicCall
; YAML-LABEL: Function: known_call_with_dereferenceable_bytes
; YAML-NEXT: Args:
; GISEL: Call to memcpy. Memory operation size: 1 bytes.
; GISEL-NEXT: Read Variables: <unknown> (314 bytes).
; GISEL-NEXT: Written Variables: <unknown> (42 bytes).
-; YAML: --- !Missed
-; YAML: Pass: memsize
+; YAML: --- !Analysis
+; YAML: gisel-irtranslator-memsize
; YAML: Name: MemoryOpIntrinsicCall
; YAML-LABEL: Function: known_call_with_dereferenceable_bytes
; YAML-NEXT: Args:
; GISEL: Call to memmove. Memory operation size: 1 bytes.
; GISEL-NEXT: Read Variables: <unknown> (314 bytes).
; GISEL-NEXT: Written Variables: <unknown> (42 bytes).
-; YAML: --- !Missed
-; YAML: Pass: memsize
+; YAML: --- !Analysis
+; YAML: gisel-irtranslator-memsize
; YAML: Name: MemoryOpIntrinsicCall
; YAML-LABEL: Function: known_call_with_dereferenceable_bytes
; YAML-NEXT: Args:
; GISEL: Call to bzero. Memory operation size: 1 bytes.
; GISEL-NOT: Read Variables:
; GISEL-NEXT: Written Variables: <unknown> (42 bytes).
-; YAML: --- !Missed
-; YAML: Pass: memsize
+; YAML: --- !Analysis
+; YAML: gisel-irtranslator-memsize
; YAML: Name: MemoryOpCall
; YAML-LABEL: Function: known_call_with_dereferenceable_bytes
; YAML-NEXT: Args:
; GISEL: Call to bcopy. Memory operation size: 1 bytes.
; GISEL-NEXT: Read Variables: <unknown> (314 bytes).
; GISEL-NEXT: Written Variables: <unknown> (42 bytes).
-; YAML: --- !Missed
-; YAML: Pass: memsize
+; YAML: --- !Analysis
+; YAML: gisel-irtranslator-memsize
; YAML: Name: MemoryOpCall
; YAML-LABEL: Function: known_call_with_dereferenceable_bytes
; YAML-NEXT: Args: