[llvm] b393118 - Enhance TableGen so that backends can produce better error messages.

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 10:36:22 PDT 2020


Author: Paul C. Anagnostopoulos
Date: 2020-09-23T13:35:32-04:00
New Revision: b3931188fdc84ce2bd93a0770ddc8182d18c5010

URL: https://github.com/llvm/llvm-project/commit/b3931188fdc84ce2bd93a0770ddc8182d18c5010
DIFF: https://github.com/llvm/llvm-project/commit/b3931188fdc84ce2bd93a0770ddc8182d18c5010.diff

LOG: Enhance TableGen so that backends can produce better error messages.

Modify SearchableTableEmitter.cpp to take advantage.
Clean up formatting and capitalization issues.

Added: 
    

Modified: 
    llvm/include/llvm/TableGen/Error.h
    llvm/include/llvm/TableGen/Record.h
    llvm/lib/TableGen/Error.cpp
    llvm/lib/TableGen/Record.cpp
    llvm/lib/TableGen/TGParser.cpp
    llvm/test/TableGen/cond-type.td
    llvm/test/TableGen/generic-tables.td
    llvm/test/TableGen/getsetop.td
    llvm/test/TableGen/if-type.td
    llvm/test/TableGen/self-reference-typeerror.td
    llvm/utils/TableGen/SearchableTableEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/TableGen/Error.h b/llvm/include/llvm/TableGen/Error.h
index 1eed622ab393..ad2c1dd3ef36 100644
--- a/llvm/include/llvm/TableGen/Error.h
+++ b/llvm/include/llvm/TableGen/Error.h
@@ -15,6 +15,7 @@
 #define LLVM_TABLEGEN_ERROR_H
 
 #include "llvm/Support/SourceMgr.h"
+#include "llvm/TableGen/Record.h"
 
 namespace llvm {
 
@@ -34,6 +35,10 @@ void PrintError(const Twine &Msg);
 LLVM_ATTRIBUTE_NORETURN void PrintFatalError(const Twine &Msg);
 LLVM_ATTRIBUTE_NORETURN void PrintFatalError(ArrayRef<SMLoc> ErrorLoc,
                                              const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void PrintFatalError(const Record *Rec,
+                                             const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void PrintFatalError(const RecordVal *RecVal,
+                                             const Twine &Msg);
 
 extern SourceMgr SrcMgr;
 extern unsigned ErrorsPrinted;

diff  --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index 5e1a04d541ac..cbd31037260e 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -1402,11 +1402,13 @@ class RecordVal {
   friend class Record;
 
   Init *Name;
+  SMLoc Loc; // Source location of definition of name.
   PointerIntPair<RecTy *, 1, bool> TyAndPrefix;
   Init *Value;
 
 public:
   RecordVal(Init *N, RecTy *T, bool P);
+  RecordVal(Init *N, SMLoc Loc, RecTy *T, bool P);
 
   StringRef getName() const;
   Init *getNameInit() const { return Name; }
@@ -1415,11 +1417,13 @@ class RecordVal {
     return getNameInit()->getAsUnquotedString();
   }
 
+  const SMLoc &getLoc() const { return Loc; }
   bool getPrefix() const { return TyAndPrefix.getInt(); }
   RecTy *getType() const { return TyAndPrefix.getPointer(); }
   Init *getValue() const { return Value; }
 
   bool setValue(Init *V);
+  bool setValue(Init *V, SMLoc NewLoc);
 
   void dump() const;
   void print(raw_ostream &OS, bool PrintSem = true) const;

diff  --git a/llvm/lib/TableGen/Error.cpp b/llvm/lib/TableGen/Error.cpp
index 1dfba9fb6b5d..d13d725ea6ed 100644
--- a/llvm/lib/TableGen/Error.cpp
+++ b/llvm/lib/TableGen/Error.cpp
@@ -11,11 +11,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/TableGen/Error.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
 #include <cstdlib>
 
 namespace llvm {
@@ -86,4 +87,22 @@ void PrintFatalError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg) {
   std::exit(1);
 }
 
+// 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);
+}
+
+// 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);
+}
+
 } // end namespace llvm

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 49e95e22c0a0..29c10fa52bcb 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -2032,6 +2032,14 @@ RecordVal::RecordVal(Init *N, RecTy *T, bool P)
   assert(Value && "Cannot create unset value for current type!");
 }
 
+// This constructor accepts the same arguments as the above, but also
+// a source location.
+RecordVal::RecordVal(Init *N, SMLoc Loc, RecTy *T, bool P)
+    : Name(N), Loc(Loc), TyAndPrefix(T, P) {
+  setValue(UnsetInit::get());
+  assert(Value && "Cannot create unset value for current type!");
+}
+
 StringRef RecordVal::getName() const {
   return cast<StringInit>(getNameInit())->getValue();
 }
@@ -2046,8 +2054,8 @@ bool RecordVal::setValue(Init *V) {
         if (!isa<BitsInit>(Value)) {
           SmallVector<Init *, 64> Bits;
           Bits.reserve(BTy->getNumBits());
-          for (unsigned i = 0, e = BTy->getNumBits(); i < e; ++i)
-            Bits.push_back(Value->getBit(i));
+          for (unsigned I = 0, E = BTy->getNumBits(); I < E; ++I)
+            Bits.push_back(Value->getBit(I));
           Value = BitsInit::get(Bits);
         }
       }
@@ -2058,6 +2066,32 @@ bool RecordVal::setValue(Init *V) {
   return false;
 }
 
+// This version of setValue takes an source location and resets the
+// location in the RecordVal.
+bool RecordVal::setValue(Init *V, SMLoc NewLoc) {
+  Loc = NewLoc;
+  if (V) {
+    Value = V->getCastTo(getType());
+    if (Value) {
+      assert(!isa<TypedInit>(Value) ||
+             cast<TypedInit>(Value)->getType()->typeIsA(getType()));
+      if (BitsRecTy *BTy = dyn_cast<BitsRecTy>(getType())) {
+        if (!isa<BitsInit>(Value)) {
+          SmallVector<Init *, 64> Bits;
+          Bits.reserve(BTy->getNumBits());
+          for (unsigned I = 0, E = BTy->getNumBits(); I < E; ++I)
+            Bits.push_back(Value->getBit(I));
+          Value = BitsInit::get(Bits);
+        }
+      }
+    }
+    return Value == nullptr;
+  }
+  Value = nullptr;
+  return false;
+}
+
+#include "llvm/TableGen/Record.h"
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void RecordVal::dump() const { errs() << *this; }
 #endif
@@ -2217,8 +2251,8 @@ StringRef Record::getValueAsString(StringRef FieldName) const {
   if (CodeInit *CI = dyn_cast<CodeInit>(R->getValue()))
     return CI->getValue();
 
-  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
-    FieldName + "' does not have a string initializer!");
+  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + FieldName + 
+                                "' exists but does not have a string value");
 }
 
 BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const {
@@ -2229,8 +2263,8 @@ BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const {
 
   if (BitsInit *BI = dyn_cast<BitsInit>(R->getValue()))
     return BI;
-  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
-    FieldName + "' does not have a BitsInit initializer!");
+  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + FieldName + 
+                                "' exists but does not have a bits value");
 }
 
 ListInit *Record::getValueAsListInit(StringRef FieldName) const {
@@ -2241,8 +2275,8 @@ ListInit *Record::getValueAsListInit(StringRef FieldName) const {
 
   if (ListInit *LI = dyn_cast<ListInit>(R->getValue()))
     return LI;
-  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
-    FieldName + "' does not have a list initializer!");
+  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + FieldName + 
+                                "' exists but does not have a list value");
 }
 
 std::vector<Record*>
@@ -2269,7 +2303,7 @@ int64_t Record::getValueAsInt(StringRef FieldName) const {
     return II->getValue();
   PrintFatalError(getLoc(), Twine("Record `") + getName() + "', field `" +
                                 FieldName +
-                                "' does not have an int initializer: " +
+                                "' exists but does not have an int value: " +
                                 R->getValue()->getAsString());
 }
 
@@ -2283,7 +2317,7 @@ Record::getValueAsListOfInts(StringRef FieldName) const {
     else
       PrintFatalError(getLoc(),
                       Twine("Record `") + getName() + "', field `" + FieldName +
-                          "' does not have a list of ints initializer: " +
+                          "' exists but does not have a list of ints value: " +
                           I->getAsString());
   }
   return Ints;
@@ -2301,7 +2335,7 @@ Record::getValueAsListOfStrings(StringRef FieldName) const {
     else
       PrintFatalError(getLoc(),
                       Twine("Record `") + getName() + "', field `" + FieldName +
-                          "' does not have a list of strings initializer: " +
+                          "' exists but does not have a list of strings value: " +
                           I->getAsString());
   }
   return Strings;

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 7c6902a9b0fc..eb5053b9c480 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -209,16 +209,16 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
     V = BitsInit::get(NewBits);
   }
 
-  if (RV->setValue(V)) {
+  if (RV->setValue(V, Loc)) {
     std::string InitType;
     if (BitsInit *BI = dyn_cast<BitsInit>(V))
       InitType = (Twine("' of type bit initializer with length ") +
                   Twine(BI->getNumBits())).str();
     else if (TypedInit *TI = dyn_cast<TypedInit>(V))
       InitType = (Twine("' of type '") + TI->getType()->getAsString()).str();
-    return Error(Loc, "Value '" + ValName->getAsUnquotedString() +
+    return Error(Loc, "Field '" + ValName->getAsUnquotedString() +
                           "' of type '" + RV->getType()->getAsString() +
-                          "' is incompatible with initializer '" +
+                          "' is incompatible with value '" +
                           V->getAsString() + InitType + "'");
   }
   return false;
@@ -1294,7 +1294,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     return nullptr;
   }
 
-  case tgtok::XForEach: { // Value ::= !foreach '(' Id ',' Value ',' Value ')'
+  case tgtok::XForEach: {
+    // Value ::= !foreach '(' Id ',' Value ',' Value ')'
     SMLoc OpLoc = Lex.getLoc();
     Lex.Lex(); // eat the operation
     if (Lex.getCode() != tgtok::l_paren) {
@@ -1367,8 +1368,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
       return nullptr;
     }
 
-    // We need to create a temporary record to provide a scope for the iteration
-    // variable while parsing top-level foreach's.
+    // We need to create a temporary record to provide a scope for the
+    // iteration variable.
     std::unique_ptr<Record> ParseRecTmp;
     Record *ParseRec = CurRec;
     if (!ParseRec) {
@@ -1544,7 +1545,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     return ParseOperationCond(CurRec, ItemType);
 
   case tgtok::XFoldl: {
-    // Value ::= !foldl '(' Id ',' Id ',' Value ',' Value ',' Value ')'
+    // Value ::= !foldl '(' Value ',' Value ',' Id ',' Id ',' Expr ')'
     Lex.Lex(); // eat the operation
     if (!consume(tgtok::l_paren)) {
       TokError("expected '(' after !foldl");
@@ -1627,8 +1628,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     }
     Lex.Lex(); // eat the ','
 
-    // We need to create a temporary record to provide a scope for the iteration
-    // variable while parsing top-level foreach's.
+    // We need to create a temporary record to provide a scope for the
+    // two variables.
     std::unique_ptr<Record> ParseRecTmp;
     Record *ParseRec = CurRec;
     if (!ParseRec) {
@@ -2419,7 +2420,7 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
   }
 
   // Add the value.
-  if (AddValue(CurRec, IdLoc, RecordVal(DeclName, Type, HasField)))
+  if (AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, HasField)))
     return nullptr;
 
   // If a value is present, parse it.

diff  --git a/llvm/test/TableGen/cond-type.td b/llvm/test/TableGen/cond-type.td
index fd2a3cc52b78..7dc42f77cb1c 100644
--- a/llvm/test/TableGen/cond-type.td
+++ b/llvm/test/TableGen/cond-type.td
@@ -5,7 +5,7 @@ class A<int dummy> {}
 class B<int dummy> : A<dummy> {}
 class C<int dummy> : A<dummy> {}
 
-// CHECK: Value 'x' of type 'C' is incompatible with initializer '{{.*}}' of type 'A'
+// CHECK: Field 'x' of type 'C' is incompatible with value '{{.*}}' of type 'A'
 class X<int cc, B b, C c> {
   C x = !cond(cc: b, 1 : c);
 }

diff  --git a/llvm/test/TableGen/generic-tables.td b/llvm/test/TableGen/generic-tables.td
index b374a25c4eab..fefa82684294 100644
--- a/llvm/test/TableGen/generic-tables.td
+++ b/llvm/test/TableGen/generic-tables.td
@@ -146,7 +146,7 @@ class DEntry<string str, int val1> {
 }
 
 def DFoo : DEntry<"foo", 1>;
-// ERROR1: [[@LINE+1]]:1: error: Record 'DBar' in table 'DTable' is missing field 'Val1'
+// ERROR1: [[@LINE+1]]:1: error: Record 'DBar' for table 'DTable' is missing field 'Val1'
 def DBar : DEntry<"bar", ?>;
 
 def DTable : GenericTable {

diff  --git a/llvm/test/TableGen/getsetop.td b/llvm/test/TableGen/getsetop.td
index 81dc59d06226..5def8e50de75 100644
--- a/llvm/test/TableGen/getsetop.td
+++ b/llvm/test/TableGen/getsetop.td
@@ -38,7 +38,7 @@ def test {
   // assignment whose LHS demands an instance of Base, so we expect a
   // static (parse-time) type-checking error.
 
-  // ERROR1: error: Value 'noCast' of type 'Base' is incompatible with initializer '!getop(orig)' of type '{}'
+  // ERROR1: error: Field 'noCast' of type 'Base' is incompatible with value '!getop(orig)' of type '{}'
   Base noCast = !getop(orig);
 #endif
 

diff  --git a/llvm/test/TableGen/if-type.td b/llvm/test/TableGen/if-type.td
index 809195be007e..f4049e692e80 100644
--- a/llvm/test/TableGen/if-type.td
+++ b/llvm/test/TableGen/if-type.td
@@ -5,7 +5,7 @@ class A<int dummy> {}
 class B<int dummy> : A<dummy> {}
 class C<int dummy> : A<dummy> {}
 
-// CHECK: Value 'x' of type 'C' is incompatible with initializer '{{.*}}' of type 'A'
+// CHECK: Field 'x' of type 'C' is incompatible with value '{{.*}}' of type 'A'
 class X<int cc, B b, C c> {
   C x = !if(cc, b, c);
 }

diff  --git a/llvm/test/TableGen/self-reference-typeerror.td b/llvm/test/TableGen/self-reference-typeerror.td
index 43fb062cd50e..35c6131fa2c9 100644
--- a/llvm/test/TableGen/self-reference-typeerror.td
+++ b/llvm/test/TableGen/self-reference-typeerror.td
@@ -9,5 +9,5 @@ class A<A x> {
 // This kind of self-reference is discourage, but if you *really* want it, you
 // can force it with !cast.
 //
-// CHECK: Value 'A:x' of type 'A' is incompatible with initializer
+// CHECK: Field 'A:x' of type 'A' is incompatible with value
 def A0 : A<A0>;

diff  --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index d092daf0d1f5..910778158784 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -12,6 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "CodeGenIntrinsics.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Format.h"
@@ -19,7 +21,6 @@
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
-#include "CodeGenIntrinsics.h"
 #include <algorithm>
 #include <set>
 #include <string>
@@ -62,12 +63,14 @@ struct GenericField {
 
 struct SearchIndex {
   std::string Name;
+  SMLoc Loc; // Source location of PrimaryKey or Key field definition.
   SmallVector<GenericField, 1> Fields;
   bool EarlyOut = false;
 };
 
 struct GenericTable {
   std::string Name;
+  ArrayRef<SMLoc> Locs; // Source locations from the Record instance.
   std::string PreprocessorGuard;
   std::string CppTypeName;
   SmallVector<GenericField, 2> Fields;
@@ -106,7 +109,8 @@ class SearchableTableEmitter {
     TypeInArgument,
   };
 
-  std::string primaryRepresentation(const GenericField &Field, Init *I) {
+  std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
+                                    Init *I) {
     if (StringInit *SI = dyn_cast<StringInit>(I))
       return SI->getAsString();
     else if (BitsInit *BI = dyn_cast<BitsInit>(I))
@@ -122,11 +126,12 @@ class SearchableTableEmitter {
     else if (Field.Enum) {
       auto *Entry = Field.Enum->EntryMap[cast<DefInit>(I)->getDef()];
       if (!Entry)
-        PrintFatalError(Twine("Entry for field '") + Field.Name + "' is null");
+        PrintFatalError(Loc,
+                        Twine("Entry for field '") + Field.Name + "' is null");
       return std::string(Entry->first);
     }
-    PrintFatalError(Twine("invalid field type for field '") + Field.Name +
-                    "', expected: string, bits, bit or code");
+    PrintFatalError(Loc, Twine("invalid field type for field '") + Field.Name + 
+                             "'; expected: bit, bits, string, or code");
   }
 
   bool isIntrinsic(Init *I) {
@@ -149,7 +154,9 @@ class SearchableTableEmitter {
     return isa<BitsInit>(I) || isa<CodeInit>(I) || isIntrinsic(I);
   }
 
-  std::string searchableFieldType(const GenericField &Field, TypeContext Ctx) {
+  std::string searchableFieldType(const GenericTable &Table,
+                                  const SearchIndex &Index,
+                                  const GenericField &Field, TypeContext Ctx) {
     if (isa<StringRecTy>(Field.RecType)) {
       if (Ctx == TypeInStaticStruct)
         return "const char *";
@@ -166,12 +173,16 @@ class SearchableTableEmitter {
         return "uint32_t";
       if (NumBits <= 64)
         return "uint64_t";
-      PrintFatalError(Twine("bitfield '") + Field.Name +
-                      "' too large to search");
+      PrintFatalError(Index.Loc, Twine("In table '") + Table.Name + 
+                                     "' lookup method '" + Index.Name +
+                                     "', key field '" + Field.Name +
+                                     "' of type bits is too large");
     } else if (Field.Enum || Field.IsIntrinsic || Field.IsInstruction)
       return "unsigned";
-    PrintFatalError(Twine("Field '") + Field.Name + "' has unknown type '" +
-                    Field.RecType->getAsString() + "' to search by");
+    PrintFatalError(Index.Loc,
+                    Twine("In table '") + Table.Name + "' lookup method '" +
+                        Index.Name + "', key field '" + Field.Name +
+                        "' has invalid type: " + Field.RecType->getAsString());
   }
 
   void emitGenericTable(const GenericTable &Table, raw_ostream &OS);
@@ -184,7 +195,7 @@ class SearchableTableEmitter {
 
   bool parseFieldType(GenericField &Field, Init *II);
   std::unique_ptr<SearchIndex>
-  parseSearchIndex(GenericTable &Table, StringRef Name,
+  parseSearchIndex(GenericTable &Table, const RecordVal *RecVal, StringRef Name,
                    const std::vector<StringRef> &Key, bool EarlyOut);
   void collectEnumEntries(GenericEnum &Enum, StringRef NameField,
                           StringRef ValueField,
@@ -259,8 +270,8 @@ bool SearchableTableEmitter::compareBy(Record *LHS, Record *RHS,
       if (LHSv > RHSv)
         return false;
     } else {
-      std::string LHSs = primaryRepresentation(Field, LHSI);
-      std::string RHSs = primaryRepresentation(Field, RHSI);
+      std::string LHSs = primaryRepresentation(Index.Loc, Field, LHSI);
+      std::string RHSs = primaryRepresentation(Index.Loc, Field, RHSI);
 
       if (isa<StringRecTy>(Field.RecType)) {
         LHSs = StringRef(LHSs).upper();
@@ -315,7 +326,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
   } else {
     OS << "  struct IndexType {\n";
     for (const auto &Field : Index.Fields) {
-      OS << "    " << searchableFieldType(Field, TypeInStaticStruct) << " "
+      OS << "    "
+         << searchableFieldType(Table, Index, Field, TypeInStaticStruct) << " "
          << Field.Name << ";\n";
     }
     OS << "    unsigned _index;\n";
@@ -345,8 +357,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
           OS << ", ";
         NeedComma = true;
 
-        std::string Repr =
-            primaryRepresentation(Field, Entry.first->getValueInit(Field.Name));
+        std::string Repr = primaryRepresentation(
+            Index.Loc, Field, Entry.first->getValueInit(Field.Name));
         if (isa<StringRecTy>(Field.RecType))
           Repr = StringRef(Repr).upper();
         OS << Repr;
@@ -389,10 +401,10 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
 
   if (Index.EarlyOut) {
     const GenericField &Field = Index.Fields[0];
-    std::string FirstRepr =
-        primaryRepresentation(Field, IndexRows[0]->getValueInit(Field.Name));
+    std::string FirstRepr = primaryRepresentation(
+        Index.Loc, Field, IndexRows[0]->getValueInit(Field.Name));
     std::string LastRepr = primaryRepresentation(
-        Field, IndexRows.back()->getValueInit(Field.Name));
+        Index.Loc, Field, IndexRows.back()->getValueInit(Field.Name));
     OS << "  if ((" << Field.Name << " < " << FirstRepr << ") ||\n";
     OS << "      (" << Field.Name << " > " << LastRepr << "))\n";
     OS << "    return nullptr;\n\n";
@@ -400,8 +412,8 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
 
   OS << "  struct KeyType {\n";
   for (const auto &Field : Index.Fields) {
-    OS << "    " << searchableFieldType(Field, TypeInTempStruct) << " "
-       << Field.Name << ";\n";
+    OS << "    " << searchableFieldType(Table, Index, Field, TypeInTempStruct) 
+       << " " << Field.Name << ";\n";
   }
   OS << "  };\n";
   OS << "  KeyType Key = { ";
@@ -415,9 +427,11 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
     if (isa<StringRecTy>(Field.RecType)) {
       OS << ".upper()";
       if (IsPrimary)
-        PrintFatalError(Twine("Use a secondary index for case-insensitive "
-                              "comparison of field '") +
-                        Field.Name + "' in table '" + Table.Name + "'");
+        PrintFatalError(Index.Loc, 
+                        Twine("In table '") + Table.Name +
+                            "', use a secondary lookup method for "
+                            "case-insensitive comparison of field '" +
+                            Field.Name + "'");
     }
   }
   OS << " };\n";
@@ -477,7 +491,8 @@ void SearchableTableEmitter::emitLookupDeclaration(const GenericTable &Table,
       OS << ", ";
     NeedComma = true;
 
-    OS << searchableFieldType(Field, TypeInArgument) << " " << Field.Name;
+    OS << searchableFieldType(Table, Index, Field, TypeInArgument) << " "
+       << Field.Name;
   }
   OS << ")";
 }
@@ -512,7 +527,8 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
         OS << ", ";
       NeedComma = true;
 
-      OS << primaryRepresentation(Field, Entry->getValueInit(Field.Name));
+      OS << primaryRepresentation(Table.Locs[0], Field,
+                                  Entry->getValueInit(Field.Name));
     }
 
     OS << " }, // " << i << "\n";
@@ -542,27 +558,30 @@ bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) {
   return false;
 }
 
-std::unique_ptr<SearchIndex>
-SearchableTableEmitter::parseSearchIndex(GenericTable &Table, StringRef Name,
-                                         const std::vector<StringRef> &Key,
-                                         bool EarlyOut) {
+std::unique_ptr<SearchIndex> SearchableTableEmitter::parseSearchIndex(
+    GenericTable &Table, const RecordVal *KeyRecVal, StringRef Name,
+    const std::vector<StringRef> &Key, bool EarlyOut) {
   auto Index = std::make_unique<SearchIndex>();
   Index->Name = std::string(Name);
+  Index->Loc = KeyRecVal->getLoc();
   Index->EarlyOut = EarlyOut;
 
   for (const auto &FieldName : Key) {
     const GenericField *Field = Table.getFieldByName(FieldName);
     if (!Field)
-      PrintFatalError(Twine("Search index '") + Name +
-                      "' refers to non-existing field '" + FieldName +
-                      "' in table '" + Table.Name + "'");
+      PrintFatalError(
+          KeyRecVal,
+          Twine("In table '") + Table.Name +
+              "', 'PrimaryKey' or 'Key' refers to nonexistent field '" +
+              FieldName + "'");
+                      
     Index->Fields.push_back(*Field);
   }
 
   if (EarlyOut && isa<StringRecTy>(Index->Fields[0].RecType)) {
     PrintFatalError(
-        "Early-out is not supported for string types (in search index '" +
-        Twine(Name) + "'");
+        KeyRecVal, Twine("In lookup method '") + Name + "', early-out is not " +
+                       "supported for a first key field of type string");
   }
 
   return Index;
@@ -601,31 +620,33 @@ void SearchableTableEmitter::collectEnumEntries(
 void SearchableTableEmitter::collectTableEntries(
     GenericTable &Table, const std::vector<Record *> &Items) {
   if (Items.empty())
-    PrintWarning(Twine("Table '") + Table.Name + "' has no items");
+    PrintFatalError(Table.Locs,
+                    Twine("Table '") + Table.Name + "' has no entries");
 
   for (auto EntryRec : Items) {
     for (auto &Field : Table.Fields) {
       auto TI = dyn_cast<TypedInit>(EntryRec->getValueInit(Field.Name));
       if (!TI || !TI->isComplete()) {
-        PrintFatalError(EntryRec->getLoc(),
-                        Twine("Record '") + EntryRec->getName() +
-                            "' in table '" + Table.Name +
-                            "' is missing field '" + Field.Name + "'");
+        PrintFatalError(EntryRec, Twine("Record '") + EntryRec->getName() +
+                                      "' for table '" + Table.Name +
+                                      "' is missing field '" + Field.Name +
+                                      "'");
       }
       if (!Field.RecType) {
         Field.RecType = TI->getType();
       } else {
         RecTy *Ty = resolveTypes(Field.RecType, TI->getType());
         if (!Ty)
-          PrintFatalError(Twine("Field '") + Field.Name + "' of table '" +
-                          Table.Name + "' has incompatible type: " +
-                          Field.RecType->getAsString() + " vs. " +
-                          TI->getType()->getAsString());
+          PrintFatalError(EntryRec->getValue(Field.Name), 
+                          Twine("Field '") + Field.Name + "' of table '" +
+                          Table.Name + "' entry has incompatible type: " +
+                          TI->getType()->getAsString() + " vs. " +
+                          Field.RecType->getAsString());
         Field.RecType = Ty;
       }
     }
 
-    Table.Entries.push_back(EntryRec);
+    Table.Entries.push_back(EntryRec); // Add record to table's record list.
   }
 
   Record *IntrinsicClass = Records.getClass("Intrinsic");
@@ -666,8 +687,9 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
     StringRef FilterClass = EnumRec->getValueAsString("FilterClass");
     Enum->Class = Records.getClass(FilterClass);
     if (!Enum->Class)
-      PrintFatalError(EnumRec->getLoc(), Twine("Enum FilterClass '") +
-                                             FilterClass + "' does not exist");
+      PrintFatalError(EnumRec->getValue("FilterClass"), 
+                      Twine("Enum FilterClass '") + FilterClass +
+                          "' does not exist");
 
     collectEnumEntries(*Enum, NameField, ValueField,
                        Records.getAllDerivedDefinitions(FilterClass));
@@ -678,29 +700,36 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
   for (auto TableRec : Records.getAllDerivedDefinitions("GenericTable")) {
     auto Table = std::make_unique<GenericTable>();
     Table->Name = std::string(TableRec->getName());
+    Table->Locs = TableRec->getLoc();
     Table->PreprocessorGuard = std::string(TableRec->getName());
     Table->CppTypeName = std::string(TableRec->getValueAsString("CppTypeName"));
 
     std::vector<StringRef> Fields = TableRec->getValueAsListOfStrings("Fields");
     for (const auto &FieldName : Fields) {
-      Table->Fields.emplace_back(FieldName);
+      Table->Fields.emplace_back(FieldName); // Construct a GenericField.
 
       if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
         if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) {
-          PrintFatalError(TableRec->getLoc(),
+          PrintFatalError(TypeOfVal, 
                           Twine("Table '") + Table->Name +
-                              "' has bad 'TypeOf_" + FieldName +
+                              "' has invalid 'TypeOf_" + FieldName +
                               "': " + TypeOfVal->getValue()->getAsString());
         }
       }
     }
 
-    collectTableEntries(*Table, Records.getAllDerivedDefinitions(
-                                    TableRec->getValueAsString("FilterClass")));
+    StringRef FilterClass = TableRec->getValueAsString("FilterClass");
+    if (!Records.getClass(FilterClass))
+      PrintFatalError(TableRec->getValue("FilterClass"), 
+                      Twine("Table FilterClass '") +
+                          FilterClass + "' does not exist");
+
+    collectTableEntries(*Table, Records.getAllDerivedDefinitions(FilterClass));
 
     if (!TableRec->isValueUnset("PrimaryKey")) {
       Table->PrimaryKey =
-          parseSearchIndex(*Table, TableRec->getValueAsString("PrimaryKeyName"),
+          parseSearchIndex(*Table, TableRec->getValue("PrimaryKey"),
+                           TableRec->getValueAsString("PrimaryKeyName"),
                            TableRec->getValueAsListOfStrings("PrimaryKey"),
                            TableRec->getValueAsBit("PrimaryKeyEarlyOut"));
 
@@ -718,15 +747,16 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
     Record *TableRec = IndexRec->getValueAsDef("Table");
     auto It = TableMap.find(TableRec);
     if (It == TableMap.end())
-      PrintFatalError(IndexRec->getLoc(),
+      PrintFatalError(IndexRec->getValue("Table"), 
                       Twine("SearchIndex '") + IndexRec->getName() +
-                          "' refers to non-existing table '" +
+                          "' refers to nonexistent table '" +
                           TableRec->getName());
 
     GenericTable &Table = *It->second;
-    Table.Indices.push_back(parseSearchIndex(
-        Table, IndexRec->getName(), IndexRec->getValueAsListOfStrings("Key"),
-        IndexRec->getValueAsBit("EarlyOut")));
+    Table.Indices.push_back(
+        parseSearchIndex(Table, IndexRec->getValue("Key"), IndexRec->getName(), 
+                         IndexRec->getValueAsListOfStrings("Key"),
+                         IndexRec->getValueAsBit("EarlyOut")));
   }
 
   // Translate legacy tables.
@@ -757,6 +787,7 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
 
     auto Table = std::make_unique<GenericTable>();
     Table->Name = (Twine(Class->getName()) + "sList").str();
+    Table->Locs = Class->getLoc();
     Table->PreprocessorGuard = Class->getName().upper();
     Table->CppTypeName = std::string(Class->getName());
 
@@ -779,7 +810,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
          Class->getValueAsListOfStrings("SearchableFields")) {
       std::string Name =
           (Twine("lookup") + Table->CppTypeName + "By" + Field).str();
-      Table->Indices.push_back(parseSearchIndex(*Table, Name, {Field}, false));
+      Table->Indices.push_back(parseSearchIndex(*Table, Class->getValue(Field),
+                                                Name, {Field}, false));
     }
 
     Tables.emplace_back(std::move(Table));


        


More information about the llvm-commits mailing list