diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index de2a9d8b1a0..49eb1b0c144 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -43,6 +43,7 @@ enum DiagnosticKind { DK_InlineAsm, DK_StackSize, DK_DebugMetadataVersion, + DK_SampleProfile, DK_FirstPluginKind }; @@ -193,6 +194,47 @@ public: } }; +/// Diagnostic information for the sample profiler. +class DiagnosticInfoSampleProfile : public DiagnosticInfo { +public: + DiagnosticInfoSampleProfile(const char *FileName, unsigned LineNum, + const Twine &Msg, + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfo(DK_SampleProfile, Severity), FileName(FileName), + LineNum(LineNum), Msg(Msg) {} + DiagnosticInfoSampleProfile(const char *FileName, const Twine &Msg, + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfo(DK_SampleProfile, Severity), FileName(FileName), + LineNum(0), Msg(Msg) {} + DiagnosticInfoSampleProfile(const Twine &Msg, + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfo(DK_SampleProfile, Severity), FileName(NULL), + LineNum(0), Msg(Msg) {} + + /// \see DiagnosticInfo::print. + void print(DiagnosticPrinter &DP) const override; + + /// Hand rolled RTTI. + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_SampleProfile; + } + + const char *getFileName() const { return FileName; } + unsigned getLineNum() const { return LineNum; } + const Twine &getMsg() const { return Msg; } + +private: + /// Name of the input file associated with this diagnostic. + const char *FileName; + + /// Line number where the diagnostic occured. If 0, no line number will + /// be emitted in the message. + unsigned LineNum; + + /// Message to report. + const Twine &Msg; +}; + } // End namespace llvm #endif diff --git a/lib/IR/DiagnosticInfo.cpp b/lib/IR/DiagnosticInfo.cpp index 86e8788eb09..d59d4cf0b50 100644 --- a/lib/IR/DiagnosticInfo.cpp +++ b/lib/IR/DiagnosticInfo.cpp @@ -56,3 +56,11 @@ void DiagnosticInfoDebugMetadataVersion::print(DiagnosticPrinter &DP) const { DP << "ignoring debug info with an invalid version (" << getMetadataVersion() << ") in " << getModule(); } + +void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const { + if (getFileName() && getLineNum() > 0) + DP << getFileName() << ":" << getLineNum() << ": "; + else if (getFileName()) + DP << getFileName() << ": "; + DP << getMsg(); +} diff --git a/lib/Transforms/Scalar/SampleProfile.cpp b/lib/Transforms/Scalar/SampleProfile.cpp index ab26fa5b23e..e8adc64eeee 100644 --- a/lib/Transforms/Scalar/SampleProfile.cpp +++ b/lib/Transforms/Scalar/SampleProfile.cpp @@ -34,6 +34,7 @@ #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" @@ -238,10 +239,11 @@ protected: /// be relative to the start of the function. class SampleModuleProfile { public: - SampleModuleProfile(StringRef F) : Profiles(0), Filename(F) {} + SampleModuleProfile(const Module &M, StringRef F) + : Profiles(0), Filename(F), M(M) {} void dump(); - void loadText(); + bool loadText(); void loadNative() { llvm_unreachable("not implemented"); } void printFunctionProfile(raw_ostream &OS, StringRef FName); void dumpFunctionProfile(StringRef FName); @@ -251,7 +253,8 @@ public: /// \brief Report a parse error message and stop compilation. void reportParseError(int64_t LineNumber, Twine Msg) const { - report_fatal_error(Filename + ":" + Twine(LineNumber) + ": " + Msg + "\n"); + DiagnosticInfoSampleProfile Diag(Filename.data(), LineNumber, Msg); + M.getContext().diagnose(Diag); } protected: @@ -269,6 +272,10 @@ protected: /// version of the profile format to be used in constructing test /// cases and debugging. StringRef Filename; + + /// \brief Module being compiled. Used mainly to access the current + /// LLVM context for diagnostics. + const Module &M; }; /// \brief Sample profile pass. @@ -282,7 +289,7 @@ public: static char ID; SampleProfileLoader(StringRef Name = SampleProfileFile) - : FunctionPass(ID), Profiler(), Filename(Name) { + : FunctionPass(ID), Profiler(), Filename(Name), ProfileIsValid(false) { initializeSampleProfileLoaderPass(*PassRegistry::getPassRegistry()); } @@ -307,6 +314,9 @@ protected: /// \brief Name of the profile file to load. StringRef Filename; + + /// \brief Flag indicating whether the profile input loaded succesfully. + bool ProfileIsValid; }; } @@ -437,11 +447,17 @@ void SampleModuleProfile::dump() { /// for debugging purposes, but it should not be used to generate /// profiles for large programs, as the representation is extremely /// inefficient. -void SampleModuleProfile::loadText() { +/// +/// \returns true if the file was loaded successfully, false otherwise. +bool SampleModuleProfile::loadText() { std::unique_ptr Buffer; error_code EC = MemoryBuffer::getFile(Filename, Buffer); - if (EC) - report_fatal_error("Could not open file " + Filename + ": " + EC.message()); + if (EC) { + std::string Msg(EC.message()); + DiagnosticInfoSampleProfile Diag(Filename.data(), Msg); + M.getContext().diagnose(Diag); + return false; + } line_iterator LineIt(*Buffer, '#'); // Read the profile of each function. Since each function may be @@ -457,9 +473,11 @@ void SampleModuleProfile::loadText() { // // See above for an explanation of each field. SmallVector Matches; - if (!HeadRE.match(*LineIt, &Matches)) + if (!HeadRE.match(*LineIt, &Matches)) { reportParseError(LineIt.line_number(), "Expected 'mangled_name:NUM:NUM', found " + *LineIt); + return false; + } assert(Matches.size() == 4); StringRef FName = Matches[1]; unsigned NumSamples, NumHeadSamples; @@ -474,10 +492,12 @@ void SampleModuleProfile::loadText() { // Now read the body. The body of the function ends when we reach // EOF or when we see the start of the next function. while (!LineIt.is_at_eof() && isdigit((*LineIt)[0])) { - if (!LineSample.match(*LineIt, &Matches)) + if (!LineSample.match(*LineIt, &Matches)) { reportParseError( LineIt.line_number(), "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + *LineIt); + return false; + } assert(Matches.size() == 5); unsigned LineOffset, NumSamples, Discriminator = 0; Matches[1].getAsInteger(10, LineOffset); @@ -497,6 +517,8 @@ void SampleModuleProfile::loadText() { ++LineIt; } } + + return true; } /// \brief Get the weight for an instruction. @@ -935,7 +957,8 @@ void SampleFunctionProfile::propagateWeights(Function &F) { /// /// \param F Function object to query. /// -/// \returns the line number where \p F is defined. +/// \returns the line number where \p F is defined. If it returns 0, +/// it means that there is no debug information available for \p F. unsigned SampleFunctionProfile::getFunctionLoc(Function &F) { NamedMDNode *CUNodes = F.getParent()->getNamedMetadata("llvm.dbg.cu"); if (CUNodes) { @@ -950,8 +973,10 @@ unsigned SampleFunctionProfile::getFunctionLoc(Function &F) { } } - report_fatal_error("No debug information found in function " + F.getName() + - "\n"); + DiagnosticInfoSampleProfile Diag("No debug information found in function " + + F.getName()); + F.getContext().diagnose(Diag); + return 0; } /// \brief Generate branch weight metadata for all branches in \p F. @@ -1001,6 +1026,8 @@ unsigned SampleFunctionProfile::getFunctionLoc(Function &F) { /// metadata on B using the computed values for each of its branches. /// /// \param F The function to query. +/// +/// \returns true if \p F was modified. Returns false, otherwise. bool SampleFunctionProfile::emitAnnotations(Function &F, DominatorTree *DomTree, PostDominatorTree *PostDomTree, LoopInfo *Loops) { @@ -1008,6 +1035,9 @@ bool SampleFunctionProfile::emitAnnotations(Function &F, DominatorTree *DomTree, // Initialize invariants used during computation and propagation. HeaderLineno = getFunctionLoc(F); + if (HeaderLineno == 0) + return false; + DEBUG(dbgs() << "Line number for the first instruction in " << F.getName() << ": " << HeaderLineno << "\n"); DT = DomTree; @@ -1040,8 +1070,8 @@ INITIALIZE_PASS_END(SampleProfileLoader, "sample-profile", "Sample Profile loader", false, false) bool SampleProfileLoader::doInitialization(Module &M) { - Profiler.reset(new SampleModuleProfile(Filename)); - Profiler->loadText(); + Profiler.reset(new SampleModuleProfile(M, Filename)); + ProfileIsValid = Profiler->loadText(); return true; } @@ -1054,6 +1084,8 @@ FunctionPass *llvm::createSampleProfileLoaderPass(StringRef Name) { } bool SampleProfileLoader::runOnFunction(Function &F) { + if (!ProfileIsValid) + return false; DominatorTree *DT = &getAnalysis().getDomTree(); PostDominatorTree *PDT = &getAnalysis(); LoopInfo *LI = &getAnalysis(); diff --git a/test/Transforms/SampleProfile/syntax.ll b/test/Transforms/SampleProfile/syntax.ll index 60b9dac88cd..3aee6b219a8 100644 --- a/test/Transforms/SampleProfile/syntax.ll +++ b/test/Transforms/SampleProfile/syntax.ll @@ -10,10 +10,10 @@ define void @empty() { entry: ret void } -; NO-DEBUG: LLVM ERROR: No debug information found in function empty -; MISSING-FILE: LLVM ERROR: Could not open file missing.prof: -; BAD-FN-HEADER: LLVM ERROR: {{.*}}bad_fn_header.prof:1: Expected 'mangled_name:NUM:NUM', found empty:100:BAD -; BAD-SAMPLE-LINE: LLVM ERROR: {{.*}}bad_sample_line.prof:3: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1: BAD -; BAD-LINE-VALUES: LLVM ERROR: {{.*}}bad_line_values.prof:2: Expected 'mangled_name:NUM:NUM', found -1: 10 -; BAD-DISCRIMINATOR-VALUE: LLVM ERROR: {{.*}}bad_discriminator_value.prof:2: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1.-3: 10 -; BAD-SAMPLES: LLVM ERROR: {{.*}}bad_samples.prof:2: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1.3: -10 +; NO-DEBUG: error: No debug information found in function empty +; MISSING-FILE: error: missing.prof: No such file or directory +; BAD-FN-HEADER: error: {{.*}}bad_fn_header.prof:1: Expected 'mangled_name:NUM:NUM', found empty:100:BAD +; BAD-SAMPLE-LINE: error: {{.*}}bad_sample_line.prof:3: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1: BAD +; BAD-LINE-VALUES: error: {{.*}}bad_line_values.prof:2: Expected 'mangled_name:NUM:NUM', found -1: 10 +; BAD-DISCRIMINATOR-VALUE: error: {{.*}}bad_discriminator_value.prof:2: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1.-3: 10 +; BAD-SAMPLES: error: {{.*}}bad_samples.prof:2: Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found 1.3: -10