diff --git a/clang/include/clang/Basic/DiagnosticCategories.td b/clang/include/clang/Basic/DiagnosticCategories.td --- a/clang/include/clang/Basic/DiagnosticCategories.td +++ b/clang/include/clang/Basic/DiagnosticCategories.td @@ -7,4 +7,5 @@ //===----------------------------------------------------------------------===// class CatInlineAsm : DiagCategory<"Inline Assembly Issue">; +class CatSourceMgr : DiagCategory<"SourceMgr Reported Issue">; class CatBackend : DiagCategory<"Backend Issue">; diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -19,6 +19,10 @@ def warn_fe_inline_asm : Warning<"%0">, CatInlineAsm, InGroup; def note_fe_inline_asm : Note<"%0">, CatInlineAsm; def note_fe_inline_asm_here : Note<"instantiated into assembly here">; +def err_fe_source_mgr : Error<"%0">, CatSourceMgr; +def warn_fe_source_mgr : Warning<"%0">, CatSourceMgr, InGroup; +def note_fe_source_mgr : Note<"%0">, CatSourceMgr; +def remark_fe_source_mgr: Remark<"%0">, CatSourceMgr, InGroup; def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">, DefaultFatal; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1145,6 +1145,7 @@ // Backend warnings. def BackendInlineAsm : DiagGroup<"inline-asm">; +def BackendSourceMgr : DiagGroup<"source-mgr">; def BackendFrameLargerThanEQ : DiagGroup<"frame-larger-than=">; def BackendPlugin : DiagGroup<"backend-plugin">; def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">; diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -301,14 +301,7 @@ if (!getModule()) return; - // Install an inline asm handler so that diagnostics get printed through - // our diagnostics hooks. LLVMContext &Ctx = getModule()->getContext(); - LLVMContext::InlineAsmDiagHandlerTy OldHandler = - Ctx.getInlineAsmDiagnosticHandler(); - void *OldContext = Ctx.getInlineAsmDiagnosticContext(); - Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this); - std::unique_ptr OldDiagnosticHandler = Ctx.getDiagnosticHandler(); Ctx.setDiagnosticHandler(std::make_unique( @@ -342,8 +335,6 @@ LangOpts, C.getTargetInfo().getDataLayout(), getModule(), Action, std::move(AsmOutStream)); - Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext); - Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); if (OptRecordFile) @@ -377,12 +368,6 @@ Gen->HandleVTable(RD); } - static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, - unsigned LocCookie) { - SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); - ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc); - } - /// Get the best possible source location to represent a diagnostic that /// may have associated debug info. const FullSourceLoc @@ -390,14 +375,13 @@ bool &BadDebugInfo, StringRef &Filename, unsigned &Line, unsigned &Column) const; - void InlineAsmDiagHandler2(const llvm::SMDiagnostic &, - SourceLocation LocCookie); - void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI); /// Specialized handler for InlineAsm diagnostic. /// \return True if the diagnostic has been successfully reported, false /// otherwise. bool InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D); + /// Specialized handler for diagnostics reported using SMDiagnostic. + void SrcMgrDiagHandler(const llvm::DiagnosticInfoSrcMgr &D); /// Specialized handler for StackSize diagnostic. /// \return True if the diagnostic has been successfully reported, false /// otherwise. @@ -456,64 +440,6 @@ return FullSourceLoc(NewLoc, CSM); } - -/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an -/// error parsing inline asm. The SMDiagnostic indicates the error relative to -/// the temporary memory buffer that the inline asm parser has set up. -void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, - SourceLocation LocCookie) { - // There are a couple of different kinds of errors we could get here. First, - // we re-format the SMDiagnostic in terms of a clang diagnostic. - - // Strip "error: " off the start of the message string. - StringRef Message = D.getMessage(); - if (Message.startswith("error: ")) - Message = Message.substr(7); - - // If the SMDiagnostic has an inline asm source location, translate it. - FullSourceLoc Loc; - if (D.getLoc() != SMLoc()) - Loc = ConvertBackendLocation(D, Context->getSourceManager()); - - unsigned DiagID; - switch (D.getKind()) { - case llvm::SourceMgr::DK_Error: - DiagID = diag::err_fe_inline_asm; - break; - case llvm::SourceMgr::DK_Warning: - DiagID = diag::warn_fe_inline_asm; - break; - case llvm::SourceMgr::DK_Note: - DiagID = diag::note_fe_inline_asm; - break; - case llvm::SourceMgr::DK_Remark: - llvm_unreachable("remarks unexpected"); - } - // If this problem has clang-level source location information, report the - // issue in the source with a note showing the instantiated - // code. - if (LocCookie.isValid()) { - Diags.Report(LocCookie, DiagID).AddString(Message); - - if (D.getLoc().isValid()) { - DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here); - // Convert the SMDiagnostic ranges into SourceRange and attach them - // to the diagnostic. - for (const std::pair &Range : D.getRanges()) { - unsigned Column = D.getColumnNo(); - B << SourceRange(Loc.getLocWithOffset(Range.first - Column), - Loc.getLocWithOffset(Range.second - Column)); - } - } - return; - } - - // Otherwise, report the backend issue as occurring in the generated .s file. - // If Loc is invalid, we still need to report the issue, it just gets no - // location info. - Diags.Report(Loc, DiagID).AddString(Message); -} - #define ComputeDiagID(Severity, GroupName, DiagID) \ do { \ switch (Severity) { \ @@ -550,6 +476,65 @@ } \ } while (false) +void BackendConsumer::SrcMgrDiagHandler(const llvm::DiagnosticInfoSrcMgr &DI) { + const llvm::SMDiagnostic &D = DI.getSMDiag(); + + unsigned DiagID; + if (DI.isInlineAsmDiag()) + ComputeDiagID(DI.getSeverity(), inline_asm, DiagID); + else + ComputeDiagID(DI.getSeverity(), source_mgr, DiagID); + + // This is for the empty BackendConsumer that uses the clang diagnostic + // handler for IR input files. + if (!Context) { + D.print(nullptr, llvm::errs()); + Diags.Report(DiagID).AddString("cannot compile inline asm"); + return; + } + + // There are a couple of different kinds of errors we could get here. + // First, we re-format the SMDiagnostic in terms of a clang diagnostic. + + // Strip "error: " off the start of the message string. + StringRef Message = D.getMessage(); + (void)Message.consume_front("error: "); + + // If the SMDiagnostic has an inline asm source location, translate it. + FullSourceLoc Loc; + if (D.getLoc() != SMLoc()) + Loc = ConvertBackendLocation(D, Context->getSourceManager()); + + // If this problem has clang-level source location information, report the + // issue in the source with a note showing the instantiated + // code. + if (DI.isInlineAsmDiag()) { + SourceLocation LocCookie = + SourceLocation::getFromRawEncoding(DI.getLocCookie()); + if (LocCookie.isValid()) { + Diags.Report(LocCookie, DiagID).AddString(Message); + + if (D.getLoc().isValid()) { + DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here); + // Convert the SMDiagnostic ranges into SourceRange and attach them + // to the diagnostic. + for (const std::pair &Range : D.getRanges()) { + unsigned Column = D.getColumnNo(); + B << SourceRange(Loc.getLocWithOffset(Range.first - Column), + Loc.getLocWithOffset(Range.second - Column)); + } + } + return; + } + } + + // Otherwise, report the backend issue as occurring in the generated .s file. + // If Loc is invalid, we still need to report the issue, it just gets no + // location info. + Diags.Report(Loc, DiagID).AddString(Message); + return; +} + bool BackendConsumer::InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D) { unsigned DiagID; @@ -783,6 +768,9 @@ return; ComputeDiagID(Severity, inline_asm, DiagID); break; + case llvm::DK_SrcMgr: + SrcMgrDiagHandler(cast(DI)); + return; case llvm::DK_StackSize: if (StackSizeDiagHandler(cast(DI))) return; @@ -979,30 +967,6 @@ return std::move(Result); } -static void BitcodeInlineAsmDiagHandler(const llvm::SMDiagnostic &SM, - void *Context, - unsigned LocCookie) { - SM.print(nullptr, llvm::errs()); - - auto Diags = static_cast(Context); - unsigned DiagID; - switch (SM.getKind()) { - case llvm::SourceMgr::DK_Error: - DiagID = diag::err_fe_inline_asm; - break; - case llvm::SourceMgr::DK_Warning: - DiagID = diag::warn_fe_inline_asm; - break; - case llvm::SourceMgr::DK_Note: - DiagID = diag::note_fe_inline_asm; - break; - case llvm::SourceMgr::DK_Remark: - llvm_unreachable("remarks unexpected"); - } - - Diags->Report(DiagID).AddString("cannot compile inline asm"); -} - std::unique_ptr CodeGenAction::loadModule(MemoryBufferRef MBRef) { CompilerInstance &CI = getCompilerInstance(); @@ -1105,7 +1069,6 @@ EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile); LLVMContext &Ctx = TheModule->getContext(); - Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler, &Diagnostics); // Restore any diagnostic handler previously set before returning from this // function. diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -9,6 +9,8 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticHandler.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/SourceMgr.h" @@ -200,16 +202,26 @@ return ret; } -static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic, - void *Context, unsigned LocCookie) { - Status *err = static_cast(Context); +namespace { +struct IRExecDiagnosticHandler : public llvm::DiagnosticHandler { + Status *err; + IRExecDiagnosticHandler(Status *err) : err(err) {} + bool handleDiagnostics(const llvm::DiagnosticInfo &DI) override { + if (DI.getKind() == llvm::DK_SrcMgr) { + const auto &DISM = llvm::cast(DI); + if (err && err->Success()) { + err->SetErrorToGenericError(); + err->SetErrorStringWithFormat( + "Inline assembly error: %s", + DISM.getSMDiag().getMessage().str().c_str()); + } + return true; + } - if (err && err->Success()) { - err->SetErrorToGenericError(); - err->SetErrorStringWithFormat("Inline assembly error: %s", - diagnostic.getMessage().str().c_str()); + return false; } -} +}; +} // namespace void IRExecutionUnit::ReportSymbolLookupError(ConstString name) { m_failed_lookups.push_back(name); @@ -257,8 +269,8 @@ LLDB_LOGF(log, "Module being sent to JIT: \n%s", s.c_str()); } - m_module_up->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, - &error); + m_module_up->getContext().setDiagnosticHandler( + std::make_unique(&error)); llvm::EngineBuilder builder(std::move(m_module_up)); llvm::Triple triple(m_module->getTargetTriple()); diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -185,14 +185,6 @@ std::vector Handlers; size_t NumUserHandlers = 0; -public: - struct SrcMgrDiagInfo { - SourceMgr SrcMgr; - std::vector LocInfos; - LLVMContext::InlineAsmDiagHandlerTy DiagHandler; - void *DiagContext; - }; - private: /// If generated on the fly this own the instance. std::unique_ptr OwnedMDT; @@ -200,10 +192,6 @@ /// If generated on the fly this own the instance. std::unique_ptr OwnedMLI; - /// Structure for generating diagnostics for inline assembly. Only initialised - /// when necessary. - mutable std::unique_ptr DiagInfo; - /// If the target supports dwarf debug info, this pointer is non-null. DwarfDebug *DD = nullptr; diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h --- a/llvm/include/llvm/IR/DiagnosticInfo.h +++ b/llvm/include/llvm/IR/DiagnosticInfo.h @@ -78,6 +78,7 @@ DK_MIRParser, DK_PGOProfile, DK_Unsupported, + DK_SrcMgr, DK_FirstPluginKind // Must be last value to work with // getNextAvailablePluginDiagnosticKind }; @@ -916,6 +917,7 @@ }; /// Diagnostic information for machine IR parser. +// FIXME: Remove this, use DiagnosticInfoSrcMgr instead. class DiagnosticInfoMIRParser : public DiagnosticInfo { const SMDiagnostic &Diagnostic; @@ -1015,6 +1017,49 @@ void print(DiagnosticPrinter &DP) const override; }; +static DiagnosticSeverity getDiagnosticSeverity(SourceMgr::DiagKind DK) { + switch (DK) { + case llvm::SourceMgr::DK_Error: + return DS_Error; + break; + case llvm::SourceMgr::DK_Warning: + return DS_Warning; + break; + case llvm::SourceMgr::DK_Note: + return DS_Note; + break; + case llvm::SourceMgr::DK_Remark: + return DS_Remark; + break; + } + llvm_unreachable("unknown SourceMgr::DiagKind"); +} + +/// Diagnostic information for SMDiagnostic reporting. +class DiagnosticInfoSrcMgr : public DiagnosticInfo { + const SMDiagnostic &Diagnostic; + + // For inlineasm !srcloc translation. + bool InlineAsmDiag; + unsigned LocCookie; + +public: + DiagnosticInfoSrcMgr(const SMDiagnostic &Diagnostic, + bool InlineAsmDiag = true, unsigned LocCookie = 0) + : DiagnosticInfo(DK_SrcMgr, getDiagnosticSeverity(Diagnostic.getKind())), + Diagnostic(Diagnostic), InlineAsmDiag(InlineAsmDiag), + LocCookie(LocCookie) {} + + bool isInlineAsmDiag() const { return InlineAsmDiag; } + const SMDiagnostic &getSMDiag() const { return Diagnostic; } + unsigned getLocCookie() const { return LocCookie; } + void print(DiagnosticPrinter &DP) const override; + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_SrcMgr; + } +}; + } // end namespace llvm #endif // LLVM_IR_DIAGNOSTICINFO_H diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -153,31 +153,10 @@ void enableDebugTypeODRUniquing(); void disableDebugTypeODRUniquing(); - using InlineAsmDiagHandlerTy = void (*)(const SMDiagnostic&, void *Context, - unsigned LocCookie); - /// Defines the type of a yield callback. /// \see LLVMContext::setYieldCallback. using YieldCallbackTy = void (*)(LLVMContext *Context, void *OpaqueHandle); - /// setInlineAsmDiagnosticHandler - This method sets a handler that is invoked - /// when problems with inline asm are detected by the backend. The first - /// argument is a function pointer and the second is a context pointer that - /// gets passed into the DiagHandler. - /// - /// LLVMContext doesn't take ownership or interpret either of these - /// pointers. - void setInlineAsmDiagnosticHandler(InlineAsmDiagHandlerTy DiagHandler, - void *DiagContext = nullptr); - - /// getInlineAsmDiagnosticHandler - Return the diagnostic handler set by - /// setInlineAsmDiagnosticHandler. - InlineAsmDiagHandlerTy getInlineAsmDiagnosticHandler() const; - - /// getInlineAsmDiagnosticContext - Return the diagnostic context set by - /// setInlineAsmDiagnosticHandler. - void *getInlineAsmDiagnosticContext() const; - /// setDiagnosticHandlerCallBack - This method sets a handler call back /// that is invoked when the backend needs to report anything to the user. /// The first argument is a function pointer and the second is a context pointer diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,8 @@ class MCSymbolELF; class MCSymbolWasm; class MCSymbolXCOFF; + class MDNode; + class SMDiagnostic; class SMLoc; class SourceMgr; @@ -68,13 +71,19 @@ class MCContext { public: using SymbolTable = StringMap; + using DiagHandlerTy = + std::function &)>; private: /// The SourceMgr for this object, if any. const SourceMgr *SrcMgr; /// The SourceMgr for inline assembly, if any. - SourceMgr *InlineSrcMgr; + std::unique_ptr InlineSrcMgr; + std::vector LocInfos; + + DiagHandlerTy DiagHandler; /// The MCAsmInfo for this target. const MCAsmInfo *MAI; @@ -299,6 +308,9 @@ bool HadError = false; + void reportCommon(SMLoc Loc, + std::function); + MCSymbol *createSymbolImpl(const StringMapEntry *Name, bool CanBeUnnamed); MCSymbol *createSymbol(StringRef Name, bool AlwaysAddSuffix, @@ -363,7 +375,15 @@ const SourceMgr *getSourceManager() const { return SrcMgr; } - void setInlineSourceManager(SourceMgr *SM) { InlineSrcMgr = SM; } + void initInlineSourceManager(); + SourceMgr *getInlineSourceManager() { + assert(InlineSrcMgr); + return InlineSrcMgr.get(); + } + std::vector &getLocInfos() { return LocInfos; } + void setDiagnosticHandler(DiagHandlerTy DiagHandler) { + this->DiagHandler = DiagHandler; + } const MCAsmInfo *getAsmInfo() const { return MAI; } @@ -748,13 +768,13 @@ void deallocate(void *Ptr) {} bool hadError() { return HadError; } + void diagnose(const SMDiagnostic &SMD); void reportError(SMLoc L, const Twine &Msg); void reportWarning(SMLoc L, const Twine &Msg); // Unrecoverable error has occurred. Display the best diagnostic we can // and bail via exit(1). For now, most MC backend errors are unrecoverable. // FIXME: We should really do something about that. - LLVM_ATTRIBUTE_NORETURN void reportFatalError(SMLoc L, - const Twine &Msg); + LLVM_ATTRIBUTE_NORETURN void reportFatalError(SMLoc L, const Twine &Msg); const MCAsmMacro *lookupMacro(StringRef Name) { StringMap::iterator I = MacroMap.find(Name); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -39,54 +39,12 @@ #define DEBUG_TYPE "asm-printer" -/// srcMgrDiagHandler - This callback is invoked when the SourceMgr for an -/// inline asm has an error in it. diagInfo is a pointer to the SrcMgrDiagInfo -/// struct above. -static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) { - AsmPrinter::SrcMgrDiagInfo *DiagInfo = - static_cast(diagInfo); - assert(DiagInfo && "Diagnostic context not passed down?"); - - // Look up a LocInfo for the buffer this diagnostic is coming from. - unsigned BufNum = DiagInfo->SrcMgr.FindBufferContainingLoc(Diag.getLoc()); - const MDNode *LocInfo = nullptr; - if (BufNum > 0 && BufNum <= DiagInfo->LocInfos.size()) - LocInfo = DiagInfo->LocInfos[BufNum-1]; - - // If the inline asm had metadata associated with it, pull out a location - // cookie corresponding to which line the error occurred on. - unsigned LocCookie = 0; - if (LocInfo) { - unsigned ErrorLine = Diag.getLineNo()-1; - if (ErrorLine >= LocInfo->getNumOperands()) - ErrorLine = 0; - - if (LocInfo->getNumOperands() != 0) - if (const ConstantInt *CI = - mdconst::dyn_extract(LocInfo->getOperand(ErrorLine))) - LocCookie = CI->getZExtValue(); - } - - DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie); -} - unsigned AsmPrinter::addInlineAsmDiagBuffer(StringRef AsmStr, const MDNode *LocMDNode) const { - if (!DiagInfo) { - DiagInfo = std::make_unique(); - - MCContext &Context = MMI->getContext(); - Context.setInlineSourceManager(&DiagInfo->SrcMgr); - - LLVMContext &LLVMCtx = MMI->getModule()->getContext(); - if (LLVMCtx.getInlineAsmDiagnosticHandler()) { - DiagInfo->DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler(); - DiagInfo->DiagContext = LLVMCtx.getInlineAsmDiagnosticContext(); - DiagInfo->SrcMgr.setDiagHandler(srcMgrDiagHandler, DiagInfo.get()); - } - } - - SourceMgr &SrcMgr = DiagInfo->SrcMgr; + MCContext &Context = MMI->getContext(); + Context.initInlineSourceManager(); + SourceMgr &SrcMgr = *Context.getInlineSourceManager(); + std::vector &LocInfos = Context.getLocInfos(); std::unique_ptr Buffer; // The inline asm source manager will outlive AsmStr, so make a copy of the @@ -98,8 +56,8 @@ // Store LocMDNode in DiagInfo, using BufNum as an identifier. if (LocMDNode) { - DiagInfo->LocInfos.resize(BufNum); - DiagInfo->LocInfos[BufNum - 1] = LocMDNode; + LocInfos.resize(BufNum); + LocInfos[BufNum - 1] = LocMDNode; } return BufNum; @@ -134,10 +92,11 @@ } unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode); - DiagInfo->SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths); + SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager(); + SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths); - std::unique_ptr Parser(createMCAsmParser( - DiagInfo->SrcMgr, OutContext, *OutStreamer, *MAI, BufNum)); + std::unique_ptr Parser( + createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum)); // Do not use assembler-level information for parsing inline assembly. OutStreamer->setUseAssemblerInfoForParsing(false); @@ -162,12 +121,9 @@ emitInlineAsmStart(); // Don't implicitly switch to the text section before the asm. - int Res = Parser->Run(/*NoInitialTextSection*/ true, - /*NoFinalize*/ true); + (void)Parser->Run(/*NoInitialTextSection*/ true, + /*NoFinalize*/ true); emitInlineAsmEnd(STI, &TAP->getSTI()); - - if (Res && !DiagInfo->DiagHandler) - report_fatal_error("Error parsing inline asm\n"); } static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, @@ -572,7 +528,7 @@ if (!RestrRegs.empty()) { unsigned BufNum = addInlineAsmDiagBuffer(OS.str(), LocMD); - auto &SrcMgr = DiagInfo->SrcMgr; + auto &SrcMgr = *MMI->getContext().getInlineSourceManager(); SMLoc Loc = SMLoc::getFromPointer( SrcMgr.getMemoryBuffer(BufNum)->getBuffer().begin()); diff --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp --- a/llvm/lib/CodeGen/MachineModuleInfo.cpp +++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp @@ -16,7 +16,9 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" @@ -315,9 +317,44 @@ "Machine Module Information", false, false) char MachineModuleInfoWrapperPass::ID = 0; +static unsigned getLocCookie(const SMDiagnostic &SMD, const SourceMgr &SrcMgr, + std::vector &LocInfos) { + // Look up a LocInfo for the buffer this diagnostic is coming from. + unsigned BufNum = SrcMgr.FindBufferContainingLoc(SMD.getLoc()); + const MDNode *LocInfo = nullptr; + if (BufNum > 0 && BufNum <= LocInfos.size()) + LocInfo = LocInfos[BufNum - 1]; + + // If the inline asm had metadata associated with it, pull out a location + // cookie corresponding to which line the error occurred on. + unsigned LocCookie = 0; + if (LocInfo) { + unsigned ErrorLine = SMD.getLineNo() - 1; + if (ErrorLine >= LocInfo->getNumOperands()) + ErrorLine = 0; + + if (LocInfo->getNumOperands() != 0) + if (const ConstantInt *CI = + mdconst::dyn_extract(LocInfo->getOperand(ErrorLine))) + LocCookie = CI->getZExtValue(); + } + + return LocCookie; +} + bool MachineModuleInfoWrapperPass::doInitialization(Module &M) { MMI.initialize(); MMI.TheModule = &M; + // FIXME: Do this for new pass manager. + LLVMContext &Ctx = M.getContext(); + MMI.getContext().setDiagnosticHandler( + [&Ctx](const SMDiagnostic &SMD, bool IsInlineAsm, const SourceMgr &SrcMgr, + std::vector &LocInfos) { + unsigned LocCookie = 0; + if (IsInlineAsm) + LocCookie = getLocCookie(SMD, SrcMgr, LocInfos); + Ctx.diagnose(DiagnosticInfoSrcMgr(SMD, IsInlineAsm, LocCookie)); + }); MMI.DbgInfoAvailable = !M.debug_compile_units().empty(); return false; } diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -330,6 +330,10 @@ DP << Diagnostic; } +void DiagnosticInfoSrcMgr::print(DiagnosticPrinter &DP) const { + DP << Diagnostic; +} + DiagnosticInfoOptimizationFailure::DiagnosticInfoOptimizationFailure( const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc, const Value *CodeRegion) diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -111,26 +111,6 @@ // Recoverable Backend Errors //===----------------------------------------------------------------------===// -void LLVMContext:: -setInlineAsmDiagnosticHandler(InlineAsmDiagHandlerTy DiagHandler, - void *DiagContext) { - pImpl->InlineAsmDiagHandler = DiagHandler; - pImpl->InlineAsmDiagContext = DiagContext; -} - -/// getInlineAsmDiagnosticHandler - Return the diagnostic handler set by -/// setInlineAsmDiagnosticHandler. -LLVMContext::InlineAsmDiagHandlerTy -LLVMContext::getInlineAsmDiagnosticHandler() const { - return pImpl->InlineAsmDiagHandler; -} - -/// getInlineAsmDiagnosticContext - Return the diagnostic context set by -/// setInlineAsmDiagnosticHandler. -void *LLVMContext::getInlineAsmDiagnosticContext() const { - return pImpl->InlineAsmDiagContext; -} - void LLVMContext::setDiagnosticHandlerCallBack( DiagnosticHandler::DiagnosticHandlerTy DiagnosticHandler, void *DiagnosticContext, bool RespectFilters) { diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1314,9 +1314,6 @@ /// will be automatically deleted if this context is deleted. SmallPtrSet OwnedModules; - LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler = nullptr; - void *InlineAsmDiagContext = nullptr; - /// The main remark streamer used by all the other streamers (e.g. IR, MIR, /// frontends, etc.). This should only be used by the specific streamers, and /// never directly. diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -57,11 +57,16 @@ "AS_SECURE_LOG_FILE env variable)"), cl::init(getenv("AS_SECURE_LOG_FILE")), cl::Hidden); +static void defaultDiagHandler(const SMDiagnostic &SMD, bool, const SourceMgr &, + std::vector &) { + SMD.print(nullptr, errs()); +} + MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, const MCObjectFileInfo *mofi, const SourceMgr *mgr, MCTargetOptions const *TargetOpts, bool DoAutoReset) - : SrcMgr(mgr), InlineSrcMgr(nullptr), MAI(mai), MRI(mri), MOFI(mofi), - Symbols(Allocator), UsedNames(Allocator), + : SrcMgr(mgr), InlineSrcMgr(nullptr), DiagHandler(defaultDiagHandler), + MAI(mai), MRI(mri), MOFI(mofi), Symbols(Allocator), UsedNames(Allocator), InlineAsmUsedLabelNames(Allocator), CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), AutoReset(DoAutoReset), TargetOptions(TargetOpts) { @@ -80,11 +85,21 @@ // we don't need to free them here. } +void MCContext::initInlineSourceManager() { + if (!InlineSrcMgr) + InlineSrcMgr.reset(new SourceMgr()); +} + //===----------------------------------------------------------------------===// // Module Lifetime Management //===----------------------------------------------------------------------===// void MCContext::reset() { + SrcMgr = nullptr; + InlineSrcMgr.release(); + LocInfos.clear(); + DiagHandler = defaultDiagHandler; + // Call the destructors so the fragments are freed COFFAllocator.DestroyAll(); ELFAllocator.DestroyAll(); @@ -835,32 +850,67 @@ // Error Reporting //===----------------------------------------------------------------------===// +void MCContext::diagnose(const SMDiagnostic &SMD) { + assert(DiagHandler && "MCContext::DiagHandler is not set"); + bool UseInlineSrcMgr = false; + const SourceMgr *SMP = nullptr; + if (SrcMgr) { + SMP = SrcMgr; + } else if (InlineSrcMgr) { + SMP = InlineSrcMgr.get(); + UseInlineSrcMgr = true; + } else + llvm_unreachable("Either SourceMgr should be available"); + DiagHandler(SMD, UseInlineSrcMgr, *SMP, LocInfos); +} + +void MCContext::reportCommon( + SMLoc Loc, + std::function GetMessage) { + // * MCContext::SrcMgr is null when the MC layer emits machine code for input + // other than assembly file, say, for .c/.cpp/.ll/.bc. + // * MCContext::InlineSrcMgr is null when the inline asm is not used. + // * A default SourceMgr is needed for diagnosing when both MCContext::SrcMgr + // and MCContext::InlineSrcMgr are null. + SourceMgr SM; + const SourceMgr *SMP = &SM; + bool UseInlineSrcMgr = false; + + // FIXME: Simplify these by combining InlineSrcMgr & SrcMgr. + // For MC-only execution, only SrcMgr is used; + // For non MC-only execution, InlineSrcMgr is only ctor'd if there is + // inline asm in the IR. + if (Loc.isValid()) { + if (SrcMgr) { + SMP = SrcMgr; + } else if (InlineSrcMgr) { + SMP = InlineSrcMgr.get(); + UseInlineSrcMgr = true; + } else + llvm_unreachable("Either SourceMgr should be available"); + } + + SMDiagnostic D; + GetMessage(D, SMP); + DiagHandler(D, UseInlineSrcMgr, *SMP, LocInfos); +} + void MCContext::reportError(SMLoc Loc, const Twine &Msg) { HadError = true; - - // If we have a source manager use it. Otherwise, try using the inline source - // manager. - // If that fails, construct a temporary SourceMgr. - if (SrcMgr) - SrcMgr->PrintMessage(Loc, SourceMgr::DK_Error, Msg); - else if (InlineSrcMgr) - InlineSrcMgr->PrintMessage(Loc, SourceMgr::DK_Error, Msg); - else - SourceMgr().PrintMessage(Loc, SourceMgr::DK_Error, Msg); + reportCommon(Loc, [&](SMDiagnostic &D, const SourceMgr *SMP) { + D = SMP->GetMessage(Loc, SourceMgr::DK_Error, Msg); + }); } void MCContext::reportWarning(SMLoc Loc, const Twine &Msg) { if (TargetOptions && TargetOptions->MCNoWarn) return; - if (TargetOptions && TargetOptions->MCFatalWarnings) + if (TargetOptions && TargetOptions->MCFatalWarnings) { reportError(Loc, Msg); - else { - // If we have a source manager use it. Otherwise, try using the inline - // source manager. - if (SrcMgr) - SrcMgr->PrintMessage(Loc, SourceMgr::DK_Warning, Msg); - else if (InlineSrcMgr) - InlineSrcMgr->PrintMessage(Loc, SourceMgr::DK_Warning, Msg); + } else { + reportCommon(Loc, [&](SMDiagnostic &D, const SourceMgr *SMP) { + D = SMP->GetMessage(Loc, SourceMgr::DK_Warning, Msg); + }); } } diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -2348,7 +2348,7 @@ /// will use the last parsed cpp hash line filename comment /// for the Filename and LineNo if any in the diagnostic. void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { - const AsmParser *Parser = static_cast(Context); + auto *Parser = static_cast(Context); raw_ostream &OS = errs(); const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr(); @@ -2369,12 +2369,8 @@ // If we have not parsed a cpp hash line filename comment or the source // manager changed or buffer changed (like in a nested include) then just // print the normal diagnostic using its Filename and LineNo. - if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr || - DiagBuf != CppHashBuf) { - if (Parser->SavedDiagHandler) - Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext); - else - Diag.print(nullptr, OS); + if (!Parser->CppHashInfo.LineNumber || DiagBuf != CppHashBuf) { + Parser->getContext().diagnose(Diag); return; } @@ -2393,10 +2389,7 @@ Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(), Diag.getLineContents(), Diag.getRanges()); - if (Parser->SavedDiagHandler) - Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext); - else - NewDiag.print(nullptr, OS); + Parser->getContext().diagnose(NewDiag); } // FIXME: This is mostly duplicated from the function in AsmLexer.cpp. The diff --git a/llvm/test/CodeGen/AMDGPU/lds-initializer.ll b/llvm/test/CodeGen/AMDGPU/lds-initializer.ll --- a/llvm/test/CodeGen/AMDGPU/lds-initializer.ll +++ b/llvm/test/CodeGen/AMDGPU/lds-initializer.ll @@ -1,5 +1,5 @@ -; RUN: llc -march=amdgcn -mcpu=tahiti < %s -o /dev/null 2>&1 | FileCheck %s -; RUN: llc -march=amdgcn -mcpu=tonga < %s -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc -march=amdgcn -mcpu=tahiti < %s -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc -march=amdgcn -mcpu=tonga < %s -o /dev/null 2>&1 | FileCheck %s ; CHECK: lds: unsupported initializer for address space diff --git a/llvm/test/CodeGen/AMDGPU/lds-zero-initializer.ll b/llvm/test/CodeGen/AMDGPU/lds-zero-initializer.ll --- a/llvm/test/CodeGen/AMDGPU/lds-zero-initializer.ll +++ b/llvm/test/CodeGen/AMDGPU/lds-zero-initializer.ll @@ -1,7 +1,7 @@ -; RUN: llc -march=amdgcn -mcpu=tahiti < %s -o /dev/null 2>&1 | FileCheck %s -; RUN: llc -march=amdgcn -mcpu=tonga < %s -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc -march=amdgcn -mcpu=tahiti -filetype=null < %s 2>&1 | FileCheck %s +; RUN: not llc -march=amdgcn -mcpu=tonga -filetype=null < %s 2>&1 | FileCheck %s -; CHECK: lds: unsupported initializer for address space +; CHECK: error: lds: unsupported initializer for address space @lds = addrspace(3) global [256 x i32] zeroinitializer diff --git a/llvm/test/CodeGen/XCore/section-name.ll b/llvm/test/CodeGen/XCore/section-name.ll --- a/llvm/test/CodeGen/XCore/section-name.ll +++ b/llvm/test/CodeGen/XCore/section-name.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=xcore -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc < %s -march=xcore -o /dev/null 2>&1 | FileCheck %s @bar = internal global i32 zeroinitializer diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -290,6 +290,22 @@ bool *HasError; LLCDiagnosticHandler(bool *HasErrorPtr) : HasError(HasErrorPtr) {} bool handleDiagnostics(const DiagnosticInfo &DI) override { + if (DI.getKind() == llvm::DK_SrcMgr) { + const auto &DISM = cast(DI); + const SMDiagnostic &SMD = DISM.getSMDiag(); + + if (SMD.getKind() == SourceMgr::DK_Error) + *HasError = true; + + SMD.print(nullptr, errs()); + + // For testing purposes, we print the LocCookie here. + if (DISM.isInlineAsmDiag() && DISM.getLocCookie()) + WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n"; + + return true; + } + if (DI.getSeverity() == DS_Error) *HasError = true; @@ -305,19 +321,6 @@ } }; -static void InlineAsmDiagHandler(const SMDiagnostic &SMD, void *Context, - unsigned LocCookie) { - bool *HasError = static_cast(Context); - if (SMD.getKind() == SourceMgr::DK_Error) - *HasError = true; - - SMD.print(nullptr, errs()); - - // For testing purposes, we print the LocCookie here. - if (LocCookie) - WithColor::note() << "!srcloc = " << LocCookie << "\n"; -} - // main - Entry point for the llc compiler. // int main(int argc, char **argv) { @@ -367,7 +370,6 @@ bool HasError = false; Context.setDiagnosticHandler( std::make_unique(&HasError)); - Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError); Expected> RemarksFileOrErr = setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,