[llvm] r326785 - TableGen: Allow !cast of records, cleanup conversion machinery

Nicolai Haehnle via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 6 05:48:40 PST 2018


Author: nha
Date: Tue Mar  6 05:48:39 2018
New Revision: 326785

URL: http://llvm.org/viewvc/llvm-project?rev=326785&view=rev
Log:
TableGen: Allow !cast of records, cleanup conversion machinery

Summary:
Distinguish two relationships between types: is-a and convertible-to.
For example, a bit is not an int or vice versa, but they can be
converted into each other (with range checks that you can think of
as "dynamic": unlike other type checks, those range checks do not
happen during parsing, but only once the final values have been
established).

Actually converting initializers between types is subtle: even
when values of type A can be converted to type B (e.g. int into
string), it may not be possible to do so with a concrete initializer
(e.g., a VarInit that refers to a variable of type int cannot
be immediately converted to a string).

For this reason, distinguish between getCastTo and convertInitializerTo:
the latter implements the actual conversion when appropriate, while
the former will first try to do the actual conversion and fall back
to introducing a !cast operation so that the conversion will be
delayed until variable references have been resolved.

To make the approach of adding !cast operations to work, !cast needs
to fallback to convertInitializerTo when the special string <-> record
logic does not apply.

This enables casting records to a subclass, although that new
functionality is only truly useful together with !isa, which will be
added in a later change.

The test is removed because it uses !srl on a bit sequence,
which cannot really be supported consistently, but luckily
isn't used anywhere either.

Change-Id: I98168bf52649176654ed2ec61a29bdb29970cfe7

Reviewers: arsenm, craig.topper, tra, MartinO

Subscribers: wdng, llvm-commits

Differential Revision: https://reviews.llvm.org/D43753

Modified:
    llvm/trunk/docs/TableGen/LangIntro.rst
    llvm/trunk/include/llvm/TableGen/Record.h
    llvm/trunk/lib/TableGen/Record.cpp
    llvm/trunk/lib/TableGen/TGParser.cpp
    llvm/trunk/test/TableGen/BitsInit.td
    llvm/trunk/test/TableGen/BitsInitOverflow.td
    llvm/trunk/test/TableGen/FieldAccess.td
    llvm/trunk/test/TableGen/code.td

Modified: llvm/trunk/docs/TableGen/LangIntro.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/TableGen/LangIntro.rst?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/docs/TableGen/LangIntro.rst (original)
+++ llvm/trunk/docs/TableGen/LangIntro.rst Tue Mar  6 05:48:39 2018
@@ -182,10 +182,31 @@ supported include:
     the operand of the paste.
 
 ``!cast<type>(a)``
-    A symbol of type *type* obtained by looking up the string 'a' in the symbol
-    table.  If the type of 'a' does not match *type*, TableGen aborts with an
-    error. !cast<string> is a special case in that the argument must be an
-    object defined by a 'def' construct.
+    If 'a' is a string, a record of type *type* obtained by looking up the
+    string 'a' in the list of all records defined by the time that all template
+    arguments in 'a' are fully resolved.
+
+    For example, if !cast<type>(a) appears in a multiclass definition, or in a
+    class instantiated inside of a multiclass definition, and 'a' does not
+    reference any template arguments of the multiclass, then a record of name
+    'a' must be instantiated earlier in the source file. If 'a' does reference
+    a template argument, then the lookup is delayed until defm statements
+    instantiating the multiclass (or later, if the defm occurs in another
+    multiclass and template arguments of the inner multiclass that are
+    referenced by 'a' are substituted by values that themselves contain
+    references to template arguments of the outer multiclass).
+
+    If the type of 'a' does not match *type*, TableGen aborts with an error.
+
+    For historical reasons, 'a' can also be the name of a variable or a
+    template argument in some cases, but this use is unreliable and is
+    discouraged.
+
+    Otherwise, perform a normal type cast e.g. between an int and a bit, or
+    between record types. This allows casting a record to a subclass, though if
+    the types do not match, constant folding will be inhibited. !cast<string>
+    is a special case in that the argument can be an int or a record. In the
+    latter case, the record's name is returned.
 
 ``!subst(a, b, c)``
     If 'a' and 'b' are of string type or are symbol references, substitute 'b'

Modified: llvm/trunk/include/llvm/TableGen/Record.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/TableGen/Record.h?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/include/llvm/TableGen/Record.h (original)
+++ llvm/trunk/include/llvm/TableGen/Record.h Tue Mar  6 05:48:39 2018
@@ -46,6 +46,7 @@ class RecordKeeper;
 class RecordVal;
 class Resolver;
 class StringInit;
+class TypedInit;
 
 //===----------------------------------------------------------------------===//
 //  Type Classes
@@ -83,6 +84,10 @@ public:
   /// type.
   virtual bool typeIsConvertibleTo(const RecTy *RHS) const;
 
+  /// Return true if 'this' type is equal to or a subtype of RHS. For example,
+  /// a bit set is not an int, but they are convertible.
+  virtual bool typeIsA(const RecTy *RHS) const;
+
   /// Returns the type representing list<this>.
   ListRecTy *getListTy();
 };
@@ -128,6 +133,8 @@ public:
   std::string getAsString() const override;
 
   bool typeIsConvertibleTo(const RecTy *RHS) const override;
+
+  bool typeIsA(const RecTy *RHS) const override;
 };
 
 /// 'code' - Represent a code fragment
@@ -174,8 +181,7 @@ class StringRecTy : public RecTy {
 
 public:
   static bool classof(const RecTy *RT) {
-    return RT->getRecTyKind() == StringRecTyKind ||
-           RT->getRecTyKind() == CodeRecTyKind;
+    return RT->getRecTyKind() == StringRecTyKind;
   }
 
   static StringRecTy *get() { return &Shared; }
@@ -205,6 +211,8 @@ public:
   std::string getAsString() const override;
 
   bool typeIsConvertibleTo(const RecTy *RHS) const override;
+
+  bool typeIsA(const RecTy *RHS) const override;
 };
 
 /// 'dag' - Represent a dag fragment
@@ -265,6 +273,8 @@ public:
 
   bool isSubClassOf(Record *Class) const;
   bool typeIsConvertibleTo(const RecTy *RHS) const override;
+
+  bool typeIsA(const RecTy *RHS) const override;
 };
 
 /// Find a common type that T1 and T2 convert to.
@@ -353,8 +363,14 @@ public:
   /// invokes print on stderr.
   void dump() const;
 
-  /// This virtual function converts to the appropriate
-  /// Init based on the passed in type.
+  /// If this initializer is convertible to Ty, return an initializer whose
+  /// type is-a Ty, generating a !cast operation if required. Otherwise, return
+  /// nullptr.
+  virtual Init *getCastTo(RecTy *Ty) const = 0;
+
+  /// Convert to an initializer whose type is-a Ty, or return nullptr if this
+  /// is not possible (this can happen if the initializer's type is convertible
+  /// to Ty, but there are unresolved references).
   virtual Init *convertInitializerTo(RecTy *Ty) const = 0;
 
   /// This method is used to implement the bitrange
@@ -417,6 +433,7 @@ public:
 
   RecTy *getType() const { return Ty; }
 
+  Init *getCastTo(RecTy *Ty) const override;
   Init *convertInitializerTo(RecTy *Ty) const override;
 
   Init *convertInitializerBitRange(ArrayRef<unsigned> Bits) const override;
@@ -443,6 +460,7 @@ public:
 
   static UnsetInit *get();
 
+  Init *getCastTo(RecTy *Ty) const override;
   Init *convertInitializerTo(RecTy *Ty) const override;
 
   Init *getBit(unsigned Bit) const override {
@@ -944,8 +962,6 @@ public:
 
   static VarBitInit *get(TypedInit *T, unsigned B);
 
-  Init *convertInitializerTo(RecTy *Ty) const override;
-
   Init *getBitVar() const { return TI; }
   unsigned getBitNum() const { return Bit; }
 
@@ -1089,8 +1105,6 @@ public:
 
   void Profile(FoldingSetNodeID &ID) const;
 
-  Init *convertInitializerTo(RecTy *Ty) const override;
-
   Init *getOperator() const { return Val; }
 
   StringInit *getName() const { return ValName; }
@@ -1173,16 +1187,7 @@ public:
   RecTy *getType() const { return TyAndPrefix.getPointer(); }
   Init *getValue() const { return Value; }
 
-  bool setValue(Init *V) {
-    if (V) {
-      Value = V->convertInitializerTo(getType());
-      assert(!Value || !isa<TypedInit>(Value) ||
-             cast<TypedInit>(Value)->getType()->typeIsConvertibleTo(getType()));
-      return Value == nullptr;
-    }
-    Value = nullptr;
-    return false;
-  }
+  bool setValue(Init *V);
 
   void dump() const;
   void print(raw_ostream &OS, bool PrintSem = true) const;

Modified: llvm/trunk/lib/TableGen/Record.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/Record.cpp?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/Record.cpp (original)
+++ llvm/trunk/lib/TableGen/Record.cpp Tue Mar  6 05:48:39 2018
@@ -63,6 +63,8 @@ bool RecTy::typeIsConvertibleTo(const Re
   return Kind == RHS->getRecTyKind();
 }
 
+bool RecTy::typeIsA(const RecTy *RHS) const { return this == RHS; }
+
 bool BitRecTy::typeIsConvertibleTo(const RecTy *RHS) const{
   if (RecTy::typeIsConvertibleTo(RHS) || RHS->getRecTyKind() == IntRecTyKind)
     return true;
@@ -92,6 +94,12 @@ bool BitsRecTy::typeIsConvertibleTo(cons
   return (kind == BitRecTyKind && Size == 1) || (kind == IntRecTyKind);
 }
 
+bool BitsRecTy::typeIsA(const RecTy *RHS) const {
+  if (const BitsRecTy *RHSb = dyn_cast<BitsRecTy>(RHS))
+    return RHSb->Size == Size;
+  return false;
+}
+
 bool IntRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
   RecTyKind kind = RHS->getRecTyKind();
   return kind==BitRecTyKind || kind==BitsRecTyKind || kind==IntRecTyKind;
@@ -121,6 +129,12 @@ bool ListRecTy::typeIsConvertibleTo(cons
   return false;
 }
 
+bool ListRecTy::typeIsA(const RecTy *RHS) const {
+  if (const ListRecTy *RHSl = dyn_cast<ListRecTy>(RHS))
+    return getElementType()->typeIsA(RHSl->getElementType());
+  return false;
+}
+
 std::string DagRecTy::getAsString() const {
   return "dag";
 }
@@ -214,6 +228,10 @@ bool RecordRecTy::typeIsConvertibleTo(co
                                          });
 }
 
+bool RecordRecTy::typeIsA(const RecTy *RHS) const {
+  return typeIsConvertibleTo(RHS);
+}
+
 static RecordRecTy *resolveRecordTypes(RecordRecTy *T1, RecordRecTy *T2) {
   SmallVector<Record *, 4> CommonSuperClasses;
   SmallVector<Record *, 4> Stack;
@@ -275,17 +293,11 @@ UnsetInit *UnsetInit::get() {
   return &TheInit;
 }
 
-Init *UnsetInit::convertInitializerTo(RecTy *Ty) const {
-  if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
-    SmallVector<Init *, 16> NewBits(BRT->getNumBits());
-
-    for (unsigned i = 0; i != BRT->getNumBits(); ++i)
-      NewBits[i] = UnsetInit::get();
-
-    return BitsInit::get(NewBits);
-  }
+Init *UnsetInit::getCastTo(RecTy *Ty) const {
+  return const_cast<UnsetInit *>(this);
+}
 
-  // All other types can just be returned.
+Init *UnsetInit::convertInitializerTo(RecTy *Ty) const {
   return const_cast<UnsetInit *>(this);
 }
 
@@ -684,7 +696,7 @@ Init *UnOpInit::Fold(Record *CurRec, Mul
 
       if (IntInit *LHSi = dyn_cast<IntInit>(LHS))
         return StringInit::get(LHSi->getAsString());
-    } else {
+    } else if (isa<RecordRecTy>(getType())) {
       if (StringInit *Name = dyn_cast<StringInit>(LHS)) {
         // From TGParser::ParseIDValue
         if (CurRec) {
@@ -729,15 +741,10 @@ Init *UnOpInit::Fold(Record *CurRec, Mul
         PrintFatalError(CurRec->getLoc(),
                         "Undefined reference:'" + Name->getValue() + "'\n");
       }
-
-      if (isa<IntRecTy>(getType())) {
-        if (BitsInit *BI = dyn_cast<BitsInit>(LHS)) {
-          if (Init *NewInit = BI->convertInitializerTo(IntRecTy::get()))
-            return NewInit;
-          break;
-        }
-      }
     }
+
+    if (Init *NewInit = LHS->convertInitializerTo(getType()))
+      return NewInit;
     break;
 
   case HEAD:
@@ -1083,10 +1090,8 @@ Init *TernOpInit::Fold(Record *CurRec, M
   }
 
   case IF: {
-    IntInit *LHSi = dyn_cast<IntInit>(LHS);
-    if (Init *I = LHS->convertInitializerTo(IntRecTy::get()))
-      LHSi = dyn_cast<IntInit>(I);
-    if (LHSi) {
+    if (IntInit *LHSi = dyn_cast_or_null<IntInit>(
+                            LHS->convertInitializerTo(IntRecTy::get()))) {
       if (LHSi->getValue())
         return MHS;
       return RHS;
@@ -1102,19 +1107,12 @@ Init *TernOpInit::resolveReferences(Reso
   Init *lhs = LHS->resolveReferences(R);
 
   if (getOpcode() == IF && lhs != LHS) {
-    IntInit *Value = dyn_cast<IntInit>(lhs);
-    if (Init *I = lhs->convertInitializerTo(IntRecTy::get()))
-      Value = dyn_cast<IntInit>(I);
-    if (Value) {
+    if (IntInit *Value = dyn_cast_or_null<IntInit>(
+                             lhs->convertInitializerTo(IntRecTy::get()))) {
       // Short-circuit
-      if (Value->getValue()) {
-        Init *mhs = MHS->resolveReferences(R);
-        return (TernOpInit::get(getOpcode(), lhs, mhs, RHS, getType()))
-            ->Fold(R.getCurrentRecord(), nullptr);
-      }
-      Init *rhs = RHS->resolveReferences(R);
-      return (TernOpInit::get(getOpcode(), lhs, MHS, rhs, getType()))
-          ->Fold(R.getCurrentRecord(), nullptr);
+      if (Value->getValue())
+        return MHS->resolveReferences(R);
+      return RHS->resolveReferences(R);
     }
   }
 
@@ -1158,79 +1156,12 @@ RecTy *TypedInit::getFieldType(StringIni
 
 Init *
 TypedInit::convertInitializerTo(RecTy *Ty) const {
-  if (isa<IntRecTy>(Ty)) {
-    if (getType()->typeIsConvertibleTo(Ty))
-      return const_cast<TypedInit *>(this);
-    return nullptr;
-  }
-
-  if (isa<StringRecTy>(Ty)) {
-    if (isa<StringRecTy>(getType()))
-      return const_cast<TypedInit *>(this);
-    return nullptr;
-  }
-
-  if (isa<CodeRecTy>(Ty)) {
-    if (isa<CodeRecTy>(getType()))
-      return const_cast<TypedInit *>(this);
-    return nullptr;
-  }
-
-  if (isa<BitRecTy>(Ty)) {
-    // Accept variable if it is already of bit type!
-    if (isa<BitRecTy>(getType()))
-      return const_cast<TypedInit *>(this);
-    if (auto *BitsTy = dyn_cast<BitsRecTy>(getType())) {
-      // Accept only bits<1> expression.
-      if (BitsTy->getNumBits() == 1)
-        return const_cast<TypedInit *>(this);
-      return nullptr;
-    }
-    // Ternary !if can be converted to bit, but only if both sides are
-    // convertible to a bit.
-    if (const auto *TOI = dyn_cast<TernOpInit>(this)) {
-      if (TOI->getOpcode() == TernOpInit::TernaryOp::IF &&
-          TOI->getMHS()->convertInitializerTo(BitRecTy::get()) &&
-          TOI->getRHS()->convertInitializerTo(BitRecTy::get()))
-        return const_cast<TypedInit *>(this);
-      return nullptr;
-    }
-    return nullptr;
-  }
+  if (getType() == Ty || getType()->typeIsA(Ty))
+    return const_cast<TypedInit *>(this);
 
-  if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
-    if (BRT->getNumBits() == 1 && isa<BitRecTy>(getType()))
-      return BitsInit::get(const_cast<TypedInit *>(this));
-
-    if (getType()->typeIsConvertibleTo(BRT)) {
-      SmallVector<Init *, 16> NewBits(BRT->getNumBits());
-
-      for (unsigned i = 0; i != BRT->getNumBits(); ++i)
-        NewBits[i] = VarBitInit::get(const_cast<TypedInit *>(this), i);
-      return BitsInit::get(NewBits);
-    }
-
-    return nullptr;
-  }
-
-  if (auto *DLRT = dyn_cast<ListRecTy>(Ty)) {
-    if (auto *SLRT = dyn_cast<ListRecTy>(getType()))
-      if (SLRT->getElementType()->typeIsConvertibleTo(DLRT->getElementType()))
-        return const_cast<TypedInit *>(this);
-    return nullptr;
-  }
-
-  if (auto *DRT = dyn_cast<DagRecTy>(Ty)) {
-    if (getType()->typeIsConvertibleTo(DRT))
-      return const_cast<TypedInit *>(this);
-    return nullptr;
-  }
-
-  if (auto *SRRT = dyn_cast<RecordRecTy>(Ty)) {
-    if (getType()->typeIsConvertibleTo(SRRT))
-      return const_cast<TypedInit *>(this);
-    return nullptr;
-  }
+  if (isa<BitRecTy>(getType()) && isa<BitsRecTy>(Ty) &&
+      cast<BitsRecTy>(Ty)->getNumBits() == 1)
+    return BitsInit::get({const_cast<TypedInit *>(this)});
 
   return nullptr;
 }
@@ -1251,6 +1182,24 @@ Init *TypedInit::convertInitializerBitRa
   return BitsInit::get(NewBits);
 }
 
+Init *TypedInit::getCastTo(RecTy *Ty) const {
+  // Handle the common case quickly
+  if (getType() == Ty || getType()->typeIsA(Ty))
+    return const_cast<TypedInit *>(this);
+
+  if (Init *Converted = convertInitializerTo(Ty)) {
+    assert(!isa<TypedInit>(Converted) ||
+           cast<TypedInit>(Converted)->getType()->typeIsA(Ty));
+    return Converted;
+  }
+
+  if (!getType()->typeIsConvertibleTo(Ty))
+    return nullptr;
+
+  return UnOpInit::get(UnOpInit::CAST, const_cast<TypedInit *>(this), Ty)
+             ->Fold(nullptr, nullptr);
+}
+
 Init *TypedInit::convertInitListSlice(ArrayRef<unsigned> Elements) const {
   ListRecTy *T = dyn_cast<ListRecTy>(getType());
   if (!T) return nullptr;  // Cannot subscript a non-list variable.
@@ -1313,13 +1262,6 @@ VarBitInit *VarBitInit::get(TypedInit *T
   return I;
 }
 
-Init *VarBitInit::convertInitializerTo(RecTy *Ty) const {
-  if (isa<BitRecTy>(Ty))
-    return const_cast<VarBitInit *>(this);
-
-  return nullptr;
-}
-
 std::string VarBitInit::getAsString() const {
   return TI->getAsString() + "{" + utostr(Bit) + "}";
 }
@@ -1485,13 +1427,6 @@ void DagInit::Profile(FoldingSetNodeID &
   ProfileDagInit(ID, Val, ValName, makeArrayRef(getTrailingObjects<Init *>(), NumArgs), makeArrayRef(getTrailingObjects<StringInit *>(), NumArgNames));
 }
 
-Init *DagInit::convertInitializerTo(RecTy *Ty) const {
-  if (isa<DagRecTy>(Ty))
-    return const_cast<DagInit *>(this);
-
-  return nullptr;
-}
-
 Init *DagInit::resolveReferences(Resolver &R) const {
   SmallVector<Init*, 8> NewArgs;
   NewArgs.reserve(arg_size());
@@ -1530,7 +1465,7 @@ std::string DagInit::getAsString() const
 
 RecordVal::RecordVal(Init *N, RecTy *T, bool P)
   : Name(N), TyAndPrefix(T, P) {
-  Value = UnsetInit::get()->convertInitializerTo(T);
+  setValue(UnsetInit::get());
   assert(Value && "Cannot create unset value for current type!");
 }
 
@@ -1538,6 +1473,28 @@ StringRef RecordVal::getName() const {
   return cast<StringInit>(getNameInit())->getValue();
 }
 
+bool RecordVal::setValue(Init *V) {
+  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;
+}
+
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void RecordVal::dump() const { errs() << *this; }
 #endif

Modified: llvm/trunk/lib/TableGen/TGParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.cpp?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/TGParser.cpp (original)
+++ llvm/trunk/lib/TableGen/TGParser.cpp Tue Mar  6 05:48:39 2018
@@ -117,13 +117,10 @@ bool TGParser::SetValue(Record *CurRec,
                    "' is not a bits type");
 
     // Convert the incoming value to a bits type of the appropriate size...
-    Init *BI = V->convertInitializerTo(BitsRecTy::get(BitList.size()));
+    Init *BI = V->getCastTo(BitsRecTy::get(BitList.size()));
     if (!BI)
       return Error(Loc, "Initializer is not compatible with bit range");
 
-    // We should have a BitsInit type now.
-    BitsInit *BInit = cast<BitsInit>(BI);
-
     SmallVector<Init *, 16> NewBits(CurVal->getNumBits());
 
     // Loop over bits, assigning values as appropriate.
@@ -132,7 +129,7 @@ bool TGParser::SetValue(Record *CurRec,
       if (NewBits[Bit])
         return Error(Loc, "Cannot set bit #" + Twine(Bit) + " of value '" +
                      ValName->getAsUnquotedString() + "' more than once");
-      NewBits[Bit] = BInit->getBit(i);
+      NewBits[Bit] = BI->getBit(i);
     }
 
     for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i)
@@ -1408,7 +1405,7 @@ Init *TGParser::ParseSimpleValue(Record
         // Fallthrough to try convert this to a bit.
       }
       // All other values must be convertible to just a single bit.
-      Init *Bit = Vals[i]->convertInitializerTo(BitRecTy::get());
+      Init *Bit = Vals[i]->getCastTo(BitRecTy::get());
       if (!Bit) {
         Error(BraceLoc, "Element #" + Twine(i) + " (" + Vals[i]->getAsString() +
               ") is not convertable to a bit");
@@ -2528,11 +2525,11 @@ Record *TGParser::InstantiateMulticlassD
       DefName = CurRec->getNameInit();
       DefNameString = dyn_cast<StringInit>(DefName);
 
-      if (!DefNameString)
+      if (!DefNameString) {
         DefName = DefName->convertInitializerTo(StringRecTy::get());
+        DefNameString = dyn_cast<StringInit>(DefName);
+      }
 
-      // We ran out of options here...
-      DefNameString = dyn_cast<StringInit>(DefName);
       if (!DefNameString) {
         PrintFatalError(CurRec->getLoc()[CurRec->getLoc().size() - 1],
                         DefName->getAsUnquotedString() + " is not a string.");

Modified: llvm/trunk/test/TableGen/BitsInit.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/BitsInit.td?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/BitsInit.td (original)
+++ llvm/trunk/test/TableGen/BitsInit.td Tue Mar  6 05:48:39 2018
@@ -69,7 +69,7 @@ def {
 // CHECK: bits<3> D4;
 // CHECK: bits<1> D5 = { 0 };
 // CHECK: bits<1> D6 = { 1 };
-// CHECK: bits<1> D7 = { ? };
+// CHECK: bits<1> D7 = { !cast<bit>(3) };
 // CHECK: bits<2> D8;
 // CHECK: bits<8> E = { 0, 0, 1, ?, 0, 0, 1, 0 };
 // CHECK: bits<8> F1 = { 0, 1, 1, 0, 0, 1, 0, 0 };

Modified: llvm/trunk/test/TableGen/BitsInitOverflow.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/BitsInitOverflow.td?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/BitsInitOverflow.td (original)
+++ llvm/trunk/test/TableGen/BitsInitOverflow.td Tue Mar  6 05:48:39 2018
@@ -1,4 +1,8 @@
-// RUN: not llvm-tblgen %s 2> /dev/null
+// RUN: llvm-tblgen %s | FileCheck %s
+
+// Check that a large integer is not truncated to a small bit sequence.
+//
+// CHECK: bits<2> X = { !cast<bits<2>>(5){1}, !cast<bits<2>>(5){0} };
 
 def {
   bits<2> X = 5;  // bitfield is too small, reject

Modified: llvm/trunk/test/TableGen/FieldAccess.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/FieldAccess.td?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/FieldAccess.td (original)
+++ llvm/trunk/test/TableGen/FieldAccess.td Tue Mar  6 05:48:39 2018
@@ -1,6 +1,20 @@
-// RUN: llvm-tblgen %s
+// RUN: llvm-tblgen %s | FileCheck %s
 // XFAIL: vg_leak
 
+// CHECK: --- Defs ---
+
+// CHECK: def a {
+// CHECK:   string blu = "";
+// CHECK: }
+
+// CHECK: def b {
+// CHECK:   string blu = "";
+// CHECK: }
+
+// CHECK: def c {
+// CHECK:   string blu = "";
+// CHECK: }
+
 class Bla<string t>
 {
   string blu = t;
@@ -12,5 +26,5 @@ class Bli<Bla t>
 }
 
 def a : Bli<Bla<"">>;
-def b : Bla<!cast<Bla>(a.bla).blu>; // works
-def c : Bla<a.bla.blu>; // doesn't work: Cannot access field 'blu' of value 'a.bla'
+def b : Bla<!cast<Bla>(a.bla).blu>;
+def c : Bla<a.bla.blu>;

Modified: llvm/trunk/test/TableGen/code.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/code.td?rev=326785&r1=326784&r2=326785&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/code.td (original)
+++ llvm/trunk/test/TableGen/code.td Tue Mar  6 05:48:39 2018
@@ -3,13 +3,12 @@
 
 // CHECK: --- Defs ---
 
-// TODO: Both of these should result in CodeInits, i.e. print [{...}].
 // CHECK: def A0 {
-// CHECK:   code Code = "Simple";
+// CHECK:   code Code = [{Simple}];
 // CHECK: }
 
 // CHECK: def B0 {
-// CHECK:   code Code = "With paste 7";
+// CHECK:   code Code = [{With paste 7}];
 // CHECK: }
 
 class A<code c> {




More information about the llvm-commits mailing list