diff --git a/llvm/include/llvm/TableGen/Error.h b/llvm/include/llvm/TableGen/Error.h index 04618995e0fe..a51ed48dba0e 100644 --- a/llvm/include/llvm/TableGen/Error.h +++ b/llvm/include/llvm/TableGen/Error.h @@ -14,12 +14,16 @@ #ifndef LLVM_TABLEGEN_ERROR_H #define LLVM_TABLEGEN_ERROR_H +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/TableGen/Record.h" namespace llvm { +class Record; +class RecordVal; +class Init; void PrintNote(const Twine &Msg); +void PrintNote(function_ref PrintMsg); void PrintNote(ArrayRef NoteLoc, const Twine &Msg); [[noreturn]] void PrintFatalNote(const Twine &Msg); @@ -32,6 +36,7 @@ void PrintWarning(ArrayRef WarningLoc, const Twine &Msg); void PrintWarning(const char *Loc, const Twine &Msg); void PrintError(const Twine &Msg); +void PrintError(function_ref PrintMsg); void PrintError(ArrayRef ErrorLoc, const Twine &Msg); void PrintError(const char *Loc, const Twine &Msg); void PrintError(const Record *Rec, const Twine &Msg); @@ -41,6 +46,7 @@ void PrintError(const RecordVal *RecVal, const Twine &Msg); [[noreturn]] void PrintFatalError(ArrayRef ErrorLoc, const Twine &Msg); [[noreturn]] void PrintFatalError(const Record *Rec, const Twine &Msg); [[noreturn]] void PrintFatalError(const RecordVal *RecVal, const Twine &Msg); +[[noreturn]] void PrintFatalError(function_ref PrintMsg); void CheckAssert(SMLoc Loc, Init *Condition, Init *Message); void dumpMessage(SMLoc Loc, Init *Message); diff --git a/llvm/lib/TableGen/Error.cpp b/llvm/lib/TableGen/Error.cpp index 4b99ff89da3b..e21f369833be 100644 --- a/llvm/lib/TableGen/Error.cpp +++ b/llvm/lib/TableGen/Error.cpp @@ -40,12 +40,23 @@ static void PrintMessage(ArrayRef Loc, SourceMgr::DiagKind Kind, "instantiated from multiclass"); } +// Run file cleanup handlers and then exit fatally (with non-zero exit code). +[[noreturn]] inline static void fatal_exit() { + // The following call runs the file cleanup handlers. + sys::RunInterruptHandlers(); + std::exit(1); +} + // Functions to print notes. void PrintNote(const Twine &Msg) { WithColor::note() << Msg << "\n"; } +void PrintNote(function_ref PrintMsg) { + PrintMsg(WithColor::note()); +} + void PrintNote(ArrayRef NoteLoc, const Twine &Msg) { PrintMessage(NoteLoc, SourceMgr::DK_Note, Msg); } @@ -54,34 +65,26 @@ void PrintNote(ArrayRef NoteLoc, const Twine &Msg) { void PrintFatalNote(const Twine &Msg) { PrintNote(Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } void PrintFatalNote(ArrayRef NoteLoc, const Twine &Msg) { PrintNote(NoteLoc, Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } // This method takes a Record and uses the source location // stored in it. void PrintFatalNote(const Record *Rec, const Twine &Msg) { PrintNote(Rec->getLoc(), Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } // This method takes a RecordVal and uses the source location // stored in it. void PrintFatalNote(const RecordVal *RecVal, const Twine &Msg) { PrintNote(RecVal->getLoc(), Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } // Functions to print warnings. @@ -100,6 +103,10 @@ void PrintWarning(const char *Loc, const Twine &Msg) { void PrintError(const Twine &Msg) { WithColor::error() << Msg << "\n"; } +void PrintError(function_ref PrintMsg) { + PrintMsg(WithColor::error()); +} + void PrintError(ArrayRef ErrorLoc, const Twine &Msg) { PrintMessage(ErrorLoc, SourceMgr::DK_Error, Msg); } @@ -124,34 +131,31 @@ void PrintError(const RecordVal *RecVal, const Twine &Msg) { void PrintFatalError(const Twine &Msg) { PrintError(Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); +} + +void PrintFatalError(function_ref PrintMsg) { + PrintError(PrintMsg); + fatal_exit(); } void PrintFatalError(ArrayRef ErrorLoc, const Twine &Msg) { PrintError(ErrorLoc, Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } // This method takes a Record and uses the source location // stored in it. void PrintFatalError(const Record *Rec, const Twine &Msg) { PrintError(Rec->getLoc(), Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } // This method takes a RecordVal and uses the source location // stored in it. void PrintFatalError(const RecordVal *RecVal, const Twine &Msg) { PrintError(RecVal->getLoc(), Msg); - // The following call runs the file cleanup handlers. - sys::RunInterruptHandlers(); - std::exit(1); + fatal_exit(); } // Check an assertion: Obtain the condition value and be sure it is true. diff --git a/llvm/test/TableGen/intrinsic-prefix-error.td b/llvm/test/TableGen/intrinsic-prefix-error.td new file mode 100644 index 000000000000..3869bde3a4ba --- /dev/null +++ b/llvm/test/TableGen/intrinsic-prefix-error.td @@ -0,0 +1,14 @@ +// RUN: not llvm-tblgen -gen-intrinsic-enums --intrinsic-prefix=gen3 -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS 2>&1 | FileCheck %s + +include "llvm/IR/Intrinsics.td" + +// CHECK: error: tried to generate intrinsics for unknown target gen3 +// CHECK-NEXT: Known targets are: gen1, gen2 + +let TargetPrefix = "gen1" in { + def int_gen1_int0 : Intrinsic<[llvm_i32_ty]>; +} + +let TargetPrefix = "gen2" in { + def int_gen2_int0 : Intrinsic<[llvm_i32_ty]>; +} diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp index df3f72ff2ec7..9a31d4f6487c 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp @@ -1603,14 +1603,11 @@ static TreePatternNode &getOperandNum(unsigned OpNo, TreePatternNode &N, OpNo -= NumResults; if (OpNo >= N.getNumChildren()) { - std::string S; - raw_string_ostream OS(S); - OS << "Invalid operand number in type constraint " << (OpNo + NumResults) - << " "; - N.print(OS); - PrintFatalError(S); + PrintFatalError([&N, OpNo, NumResults](raw_ostream &OS) { + OS << "Invalid operand number in type constraint " << (OpNo + NumResults); + N.print(OS); + }); } - return N.getChild(OpNo); } diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index f46a8d1e9f08..e367fad5838a 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -1961,12 +1961,11 @@ void parseVarLenInstOperand(const Record &Def, } static void debugDumpRecord(const Record &Rec) { - // Dump the record, so we can see what's going on... - std::string E; - raw_string_ostream S(E); - S << "Dumping record for previous error:\n"; - S << Rec; - PrintNote(E); + // Dump the record, so we can see what's going on. + PrintNote([&Rec](raw_ostream &OS) { + OS << "Dumping record for previous error:\n"; + OS << Rec; + }); } /// For an operand field named OpName: populate OpInfo.InitValue with the diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp index bda97c61d3d5..71a6ecd0b488 100644 --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -14,7 +14,6 @@ #include "Basic/SequenceToOffsetTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" @@ -122,7 +121,8 @@ void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints, // Find the TargetSet for which to generate enums. There will be an initial // set with an empty target prefix which will include target independent // intrinsics like dbg.value. - const CodeGenIntrinsicTable::TargetSet *Set = nullptr; + using TargetSet = CodeGenIntrinsicTable::TargetSet; + const TargetSet *Set = nullptr; for (const auto &Target : Ints.Targets) { if (Target.Name == IntrinsicPrefix) { Set = &Target; @@ -130,13 +130,15 @@ void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints, } } if (!Set) { - std::vector KnownTargets; - for (const auto &Target : Ints.Targets) - if (!Target.Name.empty()) - KnownTargets.push_back(Target.Name.str()); - PrintFatalError("tried to generate intrinsics for unknown target " + - IntrinsicPrefix + - "\nKnown targets are: " + join(KnownTargets, ", ") + "\n"); + // The first entry is for target independent intrinsics, so drop it. + auto KnowTargets = ArrayRef(Ints.Targets).drop_front(); + PrintFatalError([KnowTargets](raw_ostream &OS) { + OS << "tried to generate intrinsics for unknown target " + << IntrinsicPrefix << "\nKnown targets are: "; + interleaveComma(KnowTargets, OS, + [&OS](const TargetSet &Target) { OS << Target.Name; }); + OS << '\n'; + }); } // Generate a complete header for target specific intrinsics.