diff options
Diffstat (limited to 'llvm/lib/TableGen')
| -rw-r--r-- | llvm/lib/TableGen/Error.cpp | 82 | ||||
| -rw-r--r-- | llvm/lib/TableGen/JSONBackend.cpp | 188 | ||||
| -rw-r--r-- | llvm/lib/TableGen/Main.cpp | 142 | ||||
| -rw-r--r-- | llvm/lib/TableGen/Record.cpp | 2422 | ||||
| -rw-r--r-- | llvm/lib/TableGen/SetTheory.cpp | 333 | ||||
| -rw-r--r-- | llvm/lib/TableGen/StringMatcher.cpp | 156 | ||||
| -rw-r--r-- | llvm/lib/TableGen/TGLexer.cpp | 1021 | ||||
| -rw-r--r-- | llvm/lib/TableGen/TGLexer.h | 373 | ||||
| -rw-r--r-- | llvm/lib/TableGen/TGParser.cpp | 3243 | ||||
| -rw-r--r-- | llvm/lib/TableGen/TGParser.h | 208 | ||||
| -rw-r--r-- | llvm/lib/TableGen/TableGenBackend.cpp | 52 | 
11 files changed, 8220 insertions, 0 deletions
| diff --git a/llvm/lib/TableGen/Error.cpp b/llvm/lib/TableGen/Error.cpp new file mode 100644 index 000000000000..54b063cb4f8d --- /dev/null +++ b/llvm/lib/TableGen/Error.cpp @@ -0,0 +1,82 @@ +//===- Error.cpp - tblgen error handling helper routines --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains error handling helper routines to pretty-print diagnostic +// messages from tblgen. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/Error.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdlib> + +namespace llvm { + +SourceMgr SrcMgr; +unsigned ErrorsPrinted = 0; + +static void PrintMessage(ArrayRef<SMLoc> Loc, SourceMgr::DiagKind Kind, +                         const Twine &Msg) { +  // Count the total number of errors printed. +  // This is used to exit with an error code if there were any errors. +  if (Kind == SourceMgr::DK_Error) +    ++ErrorsPrinted; + +  SMLoc NullLoc; +  if (Loc.empty()) +    Loc = NullLoc; +  SrcMgr.PrintMessage(Loc.front(), Kind, Msg); +  for (unsigned i = 1; i < Loc.size(); ++i) +    SrcMgr.PrintMessage(Loc[i], SourceMgr::DK_Note, +                        "instantiated from multiclass"); +} + +void PrintNote(const Twine &Msg) { WithColor::note() << Msg << "\n"; } + +void PrintNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) { +  PrintMessage(NoteLoc, SourceMgr::DK_Note, Msg); +} + +void PrintWarning(ArrayRef<SMLoc> WarningLoc, const Twine &Msg) { +  PrintMessage(WarningLoc, SourceMgr::DK_Warning, Msg); +} + +void PrintWarning(const char *Loc, const Twine &Msg) { +  SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), SourceMgr::DK_Warning, Msg); +} + +void PrintWarning(const Twine &Msg) { WithColor::warning() << Msg << "\n"; } + +void PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg) { +  PrintMessage(ErrorLoc, SourceMgr::DK_Error, Msg); +} + +void PrintError(const char *Loc, const Twine &Msg) { +  SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), SourceMgr::DK_Error, Msg); +} + +void PrintError(const Twine &Msg) { WithColor::error() << Msg << "\n"; } + +void PrintFatalError(const Twine &Msg) { +  PrintError(Msg); +  // The following call runs the file cleanup handlers. +  sys::RunInterruptHandlers(); +  std::exit(1); +} + +void PrintFatalError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg) { +  PrintError(ErrorLoc, Msg); +  // The following call runs the file cleanup handlers. +  sys::RunInterruptHandlers(); +  std::exit(1); +} + +} // end namespace llvm diff --git a/llvm/lib/TableGen/JSONBackend.cpp b/llvm/lib/TableGen/JSONBackend.cpp new file mode 100644 index 000000000000..196644cda667 --- /dev/null +++ b/llvm/lib/TableGen/JSONBackend.cpp @@ -0,0 +1,188 @@ +//===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This TableGen back end generates a machine-readable representation +// of all the classes and records defined by the input, in JSON format. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/Support/JSON.h" + +#define DEBUG_TYPE "json-emitter" + +using namespace llvm; + +namespace { + +class JSONEmitter { +private: +  RecordKeeper &Records; + +  json::Value translateInit(const Init &I); +  json::Array listSuperclasses(const Record &R); + +public: +  JSONEmitter(RecordKeeper &R); + +  void run(raw_ostream &OS); +}; + +} // end anonymous namespace + +JSONEmitter::JSONEmitter(RecordKeeper &R) : Records(R) {} + +json::Value JSONEmitter::translateInit(const Init &I) { + +  // Init subclasses that we return as JSON primitive values of one +  // kind or another. + +  if (isa<UnsetInit>(&I)) { +    return nullptr; +  } else if (auto *Bit = dyn_cast<BitInit>(&I)) { +    return Bit->getValue() ? 1 : 0; +  } else if (auto *Bits = dyn_cast<BitsInit>(&I)) { +    json::Array array; +    for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++) +      array.push_back(translateInit(*Bits->getBit(i))); +    return std::move(array); +  } else if (auto *Int = dyn_cast<IntInit>(&I)) { +    return Int->getValue(); +  } else if (auto *Str = dyn_cast<StringInit>(&I)) { +    return Str->getValue(); +  } else if (auto *Code = dyn_cast<CodeInit>(&I)) { +    return Code->getValue(); +  } else if (auto *List = dyn_cast<ListInit>(&I)) { +    json::Array array; +    for (auto val : *List) +      array.push_back(translateInit(*val)); +    return std::move(array); +  } + +  // Init subclasses that we return as JSON objects containing a +  // 'kind' discriminator. For these, we also provide the same +  // translation back into TableGen input syntax that -print-records +  // would give. + +  json::Object obj; +  obj["printable"] = I.getAsString(); + +  if (auto *Def = dyn_cast<DefInit>(&I)) { +    obj["kind"] = "def"; +    obj["def"] = Def->getDef()->getName(); +    return std::move(obj); +  } else if (auto *Var = dyn_cast<VarInit>(&I)) { +    obj["kind"] = "var"; +    obj["var"] = Var->getName(); +    return std::move(obj); +  } else if (auto *VarBit = dyn_cast<VarBitInit>(&I)) { +    if (auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) { +      obj["kind"] = "varbit"; +      obj["var"] = Var->getName(); +      obj["index"] = VarBit->getBitNum(); +      return std::move(obj); +    } +  } else if (auto *Dag = dyn_cast<DagInit>(&I)) { +    obj["kind"] = "dag"; +    obj["operator"] = translateInit(*Dag->getOperator()); +    if (auto name = Dag->getName()) +      obj["name"] = name->getAsUnquotedString(); +    json::Array args; +    for (unsigned i = 0, limit = Dag->getNumArgs(); i < limit; ++i) { +      json::Array arg; +      arg.push_back(translateInit(*Dag->getArg(i))); +      if (auto argname = Dag->getArgName(i)) +        arg.push_back(argname->getAsUnquotedString()); +      else +        arg.push_back(nullptr); +      args.push_back(std::move(arg)); +    } +    obj["args"] = std::move(args); +    return std::move(obj); +  } + +  // Final fallback: anything that gets past here is simply given a +  // kind field of 'complex', and the only other field is the standard +  // 'printable' representation. + +  assert(!I.isConcrete()); +  obj["kind"] = "complex"; +  return std::move(obj); +} + +void JSONEmitter::run(raw_ostream &OS) { +  json::Object root; + +  root["!tablegen_json_version"] = 1; + +  // Prepare the arrays that will list the instances of every class. +  // We mostly fill those in by iterating over the superclasses of +  // each def, but we also want to ensure we store an empty list for a +  // class with no instances at all, so we do a preliminary iteration +  // over the classes, invoking std::map::operator[] to default- +  // construct the array for each one. +  std::map<std::string, json::Array> instance_lists; +  for (const auto &C : Records.getClasses()) { +    auto &Name = C.second->getNameInitAsString(); +    (void)instance_lists[Name]; +  } + +  // Main iteration over the defs. +  for (const auto &D : Records.getDefs()) { +    auto &Name = D.second->getNameInitAsString(); +    auto &Def = *D.second; + +    json::Object obj; +    json::Array fields; + +    for (const RecordVal &RV : Def.getValues()) { +      if (!Def.isTemplateArg(RV.getNameInit())) { +        auto Name = RV.getNameInitAsString(); +        if (RV.getPrefix()) +          fields.push_back(Name); +        obj[Name] = translateInit(*RV.getValue()); +      } +    } + +    obj["!fields"] = std::move(fields); + +    json::Array superclasses; +    for (const auto &SuperPair : Def.getSuperClasses()) +      superclasses.push_back(SuperPair.first->getNameInitAsString()); +    obj["!superclasses"] = std::move(superclasses); + +    obj["!name"] = Name; +    obj["!anonymous"] = Def.isAnonymous(); + +    root[Name] = std::move(obj); + +    // Add this def to the instance list for each of its superclasses. +    for (const auto &SuperPair : Def.getSuperClasses()) { +      auto SuperName = SuperPair.first->getNameInitAsString(); +      instance_lists[SuperName].push_back(Name); +    } +  } + +  // Make a JSON object from the std::map of instance lists. +  json::Object instanceof; +  for (auto kv: instance_lists) +    instanceof[kv.first] = std::move(kv.second); +  root["!instanceof"] = std::move(instanceof); + +  // Done. Write the output. +  OS << json::Value(std::move(root)) << "\n"; +} + +namespace llvm { + +void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); } +} // end namespace llvm diff --git a/llvm/lib/TableGen/Main.cpp b/llvm/lib/TableGen/Main.cpp new file mode 100644 index 000000000000..48ded6c45a46 --- /dev/null +++ b/llvm/lib/TableGen/Main.cpp @@ -0,0 +1,142 @@ +//===- Main.cpp - Top-Level TableGen implementation -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// TableGen is a tool which can be used to build up a description of something, +// then invoke one or more "tablegen backends" to emit information about the +// description in some predefined format.  In practice, this is used by the LLVM +// code generators to automate generation of a code generator through a +// high-level description of the target. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/Main.h" +#include "TGParser.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include <algorithm> +#include <cstdio> +#include <system_error> +using namespace llvm; + +static cl::opt<std::string> +OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), +               cl::init("-")); + +static cl::opt<std::string> +DependFilename("d", +               cl::desc("Dependency filename"), +               cl::value_desc("filename"), +               cl::init("")); + +static cl::opt<std::string> +InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-")); + +static cl::list<std::string> +IncludeDirs("I", cl::desc("Directory of include files"), +            cl::value_desc("directory"), cl::Prefix); + +static cl::list<std::string> +MacroNames("D", cl::desc("Name of the macro to be defined"), +            cl::value_desc("macro name"), cl::Prefix); + +static cl::opt<bool> +WriteIfChanged("write-if-changed", cl::desc("Only write output if it changed")); + +static int reportError(const char *ProgName, Twine Msg) { +  errs() << ProgName << ": " << Msg; +  errs().flush(); +  return 1; +} + +/// Create a dependency file for `-d` option. +/// +/// This functionality is really only for the benefit of the build system. +/// It is similar to GCC's `-M*` family of options. +static int createDependencyFile(const TGParser &Parser, const char *argv0) { +  if (OutputFilename == "-") +    return reportError(argv0, "the option -d must be used together with -o\n"); + +  std::error_code EC; +  ToolOutputFile DepOut(DependFilename, EC, sys::fs::OF_None); +  if (EC) +    return reportError(argv0, "error opening " + DependFilename + ":" + +                                  EC.message() + "\n"); +  DepOut.os() << OutputFilename << ":"; +  for (const auto &Dep : Parser.getDependencies()) { +    DepOut.os() << ' ' << Dep.first; +  } +  DepOut.os() << "\n"; +  DepOut.keep(); +  return 0; +} + +int llvm::TableGenMain(char *argv0, TableGenMainFn *MainFn) { +  RecordKeeper Records; + +  // Parse the input file. +  ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = +      MemoryBuffer::getFileOrSTDIN(InputFilename); +  if (std::error_code EC = FileOrErr.getError()) +    return reportError(argv0, "Could not open input file '" + InputFilename + +                                  "': " + EC.message() + "\n"); + +  // Tell SrcMgr about this buffer, which is what TGParser will pick up. +  SrcMgr.AddNewSourceBuffer(std::move(*FileOrErr), SMLoc()); + +  // Record the location of the include directory so that the lexer can find +  // it later. +  SrcMgr.setIncludeDirs(IncludeDirs); + +  TGParser Parser(SrcMgr, MacroNames, Records); + +  if (Parser.ParseFile()) +    return 1; + +  // Write output to memory. +  std::string OutString; +  raw_string_ostream Out(OutString); +  if (MainFn(Out, Records)) +    return 1; + +  // Always write the depfile, even if the main output hasn't changed. +  // If it's missing, Ninja considers the output dirty.  If this was below +  // the early exit below and someone deleted the .inc.d file but not the .inc +  // file, tablegen would never write the depfile. +  if (!DependFilename.empty()) { +    if (int Ret = createDependencyFile(Parser, argv0)) +      return Ret; +  } + +  if (WriteIfChanged) { +    // Only updates the real output file if there are any differences. +    // This prevents recompilation of all the files depending on it if there +    // aren't any. +    if (auto ExistingOrErr = MemoryBuffer::getFile(OutputFilename)) +      if (std::move(ExistingOrErr.get())->getBuffer() == Out.str()) +        return 0; +  } + +  std::error_code EC; +  ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_None); +  if (EC) +    return reportError(argv0, "error opening " + OutputFilename + ":" + +                                  EC.message() + "\n"); +  OutFile.os() << Out.str(); + +  if (ErrorsPrinted > 0) +    return reportError(argv0, Twine(ErrorsPrinted) + " errors.\n"); + +  // Declare success. +  OutFile.keep(); +  return 0; +} diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp new file mode 100644 index 000000000000..835ef8c7141b --- /dev/null +++ b/llvm/lib/TableGen/Record.cpp @@ -0,0 +1,2422 @@ +//===- Record.cpp - Record implementation ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implement the tablegen record classes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <map> +#include <string> +#include <utility> +#include <vector> + +using namespace llvm; + +#define DEBUG_TYPE "tblgen-records" + +static BumpPtrAllocator Allocator; + +STATISTIC(CodeInitsConstructed, +          "The total number of unique CodeInits constructed"); + +//===----------------------------------------------------------------------===// +//    Type implementations +//===----------------------------------------------------------------------===// + +BitRecTy BitRecTy::Shared; +CodeRecTy CodeRecTy::Shared; +IntRecTy IntRecTy::Shared; +StringRecTy StringRecTy::Shared; +DagRecTy DagRecTy::Shared; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void RecTy::dump() const { print(errs()); } +#endif + +ListRecTy *RecTy::getListTy() { +  if (!ListTy) +    ListTy = new(Allocator) ListRecTy(this); +  return ListTy; +} + +bool RecTy::typeIsConvertibleTo(const RecTy *RHS) const { +  assert(RHS && "NULL pointer"); +  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; +  if (const BitsRecTy *BitsTy = dyn_cast<BitsRecTy>(RHS)) +    return BitsTy->getNumBits() == 1; +  return false; +} + +BitsRecTy *BitsRecTy::get(unsigned Sz) { +  static std::vector<BitsRecTy*> Shared; +  if (Sz >= Shared.size()) +    Shared.resize(Sz + 1); +  BitsRecTy *&Ty = Shared[Sz]; +  if (!Ty) +    Ty = new(Allocator) BitsRecTy(Sz); +  return Ty; +} + +std::string BitsRecTy::getAsString() const { +  return "bits<" + utostr(Size) + ">"; +} + +bool BitsRecTy::typeIsConvertibleTo(const RecTy *RHS) const { +  if (RecTy::typeIsConvertibleTo(RHS)) //argument and the sender are same type +    return cast<BitsRecTy>(RHS)->Size == Size; +  RecTyKind kind = RHS->getRecTyKind(); +  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; +} + +bool CodeRecTy::typeIsConvertibleTo(const RecTy *RHS) const { +  RecTyKind Kind = RHS->getRecTyKind(); +  return Kind == CodeRecTyKind || Kind == StringRecTyKind; +} + +std::string StringRecTy::getAsString() const { +  return "string"; +} + +bool StringRecTy::typeIsConvertibleTo(const RecTy *RHS) const { +  RecTyKind Kind = RHS->getRecTyKind(); +  return Kind == StringRecTyKind || Kind == CodeRecTyKind; +} + +std::string ListRecTy::getAsString() const { +  return "list<" + Ty->getAsString() + ">"; +} + +bool ListRecTy::typeIsConvertibleTo(const RecTy *RHS) const { +  if (const auto *ListTy = dyn_cast<ListRecTy>(RHS)) +    return Ty->typeIsConvertibleTo(ListTy->getElementType()); +  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"; +} + +static void ProfileRecordRecTy(FoldingSetNodeID &ID, +                               ArrayRef<Record *> Classes) { +  ID.AddInteger(Classes.size()); +  for (Record *R : Classes) +    ID.AddPointer(R); +} + +RecordRecTy *RecordRecTy::get(ArrayRef<Record *> UnsortedClasses) { +  if (UnsortedClasses.empty()) { +    static RecordRecTy AnyRecord(0); +    return &AnyRecord; +  } + +  FoldingSet<RecordRecTy> &ThePool = +      UnsortedClasses[0]->getRecords().RecordTypePool; + +  SmallVector<Record *, 4> Classes(UnsortedClasses.begin(), +                                   UnsortedClasses.end()); +  llvm::sort(Classes, [](Record *LHS, Record *RHS) { +    return LHS->getNameInitAsString() < RHS->getNameInitAsString(); +  }); + +  FoldingSetNodeID ID; +  ProfileRecordRecTy(ID, Classes); + +  void *IP = nullptr; +  if (RecordRecTy *Ty = ThePool.FindNodeOrInsertPos(ID, IP)) +    return Ty; + +#ifndef NDEBUG +  // Check for redundancy. +  for (unsigned i = 0; i < Classes.size(); ++i) { +    for (unsigned j = 0; j < Classes.size(); ++j) { +      assert(i == j || !Classes[i]->isSubClassOf(Classes[j])); +    } +    assert(&Classes[0]->getRecords() == &Classes[i]->getRecords()); +  } +#endif + +  void *Mem = Allocator.Allocate(totalSizeToAlloc<Record *>(Classes.size()), +                                 alignof(RecordRecTy)); +  RecordRecTy *Ty = new(Mem) RecordRecTy(Classes.size()); +  std::uninitialized_copy(Classes.begin(), Classes.end(), +                          Ty->getTrailingObjects<Record *>()); +  ThePool.InsertNode(Ty, IP); +  return Ty; +} + +void RecordRecTy::Profile(FoldingSetNodeID &ID) const { +  ProfileRecordRecTy(ID, getClasses()); +} + +std::string RecordRecTy::getAsString() const { +  if (NumClasses == 1) +    return getClasses()[0]->getNameInitAsString(); + +  std::string Str = "{"; +  bool First = true; +  for (Record *R : getClasses()) { +    if (!First) +      Str += ", "; +    First = false; +    Str += R->getNameInitAsString(); +  } +  Str += "}"; +  return Str; +} + +bool RecordRecTy::isSubClassOf(Record *Class) const { +  return llvm::any_of(getClasses(), [Class](Record *MySuperClass) { +                                      return MySuperClass == Class || +                                             MySuperClass->isSubClassOf(Class); +                                    }); +} + +bool RecordRecTy::typeIsConvertibleTo(const RecTy *RHS) const { +  if (this == RHS) +    return true; + +  const RecordRecTy *RTy = dyn_cast<RecordRecTy>(RHS); +  if (!RTy) +    return false; + +  return llvm::all_of(RTy->getClasses(), [this](Record *TargetClass) { +                                           return isSubClassOf(TargetClass); +                                         }); +} + +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; + +  Stack.insert(Stack.end(), T1->classes_begin(), T1->classes_end()); + +  while (!Stack.empty()) { +    Record *R = Stack.back(); +    Stack.pop_back(); + +    if (T2->isSubClassOf(R)) { +      CommonSuperClasses.push_back(R); +    } else { +      R->getDirectSuperClasses(Stack); +    } +  } + +  return RecordRecTy::get(CommonSuperClasses); +} + +RecTy *llvm::resolveTypes(RecTy *T1, RecTy *T2) { +  if (T1 == T2) +    return T1; + +  if (RecordRecTy *RecTy1 = dyn_cast<RecordRecTy>(T1)) { +    if (RecordRecTy *RecTy2 = dyn_cast<RecordRecTy>(T2)) +      return resolveRecordTypes(RecTy1, RecTy2); +  } + +  if (T1->typeIsConvertibleTo(T2)) +    return T2; +  if (T2->typeIsConvertibleTo(T1)) +    return T1; + +  if (ListRecTy *ListTy1 = dyn_cast<ListRecTy>(T1)) { +    if (ListRecTy *ListTy2 = dyn_cast<ListRecTy>(T2)) { +      RecTy* NewType = resolveTypes(ListTy1->getElementType(), +                                    ListTy2->getElementType()); +      if (NewType) +        return NewType->getListTy(); +    } +  } + +  return nullptr; +} + +//===----------------------------------------------------------------------===// +//    Initializer implementations +//===----------------------------------------------------------------------===// + +void Init::anchor() {} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void Init::dump() const { return print(errs()); } +#endif + +UnsetInit *UnsetInit::get() { +  static UnsetInit TheInit; +  return &TheInit; +} + +Init *UnsetInit::getCastTo(RecTy *Ty) const { +  return const_cast<UnsetInit *>(this); +} + +Init *UnsetInit::convertInitializerTo(RecTy *Ty) const { +  return const_cast<UnsetInit *>(this); +} + +BitInit *BitInit::get(bool V) { +  static BitInit True(true); +  static BitInit False(false); + +  return V ? &True : &False; +} + +Init *BitInit::convertInitializerTo(RecTy *Ty) const { +  if (isa<BitRecTy>(Ty)) +    return const_cast<BitInit *>(this); + +  if (isa<IntRecTy>(Ty)) +    return IntInit::get(getValue()); + +  if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) { +    // Can only convert single bit. +    if (BRT->getNumBits() == 1) +      return BitsInit::get(const_cast<BitInit *>(this)); +  } + +  return nullptr; +} + +static void +ProfileBitsInit(FoldingSetNodeID &ID, ArrayRef<Init *> Range) { +  ID.AddInteger(Range.size()); + +  for (Init *I : Range) +    ID.AddPointer(I); +} + +BitsInit *BitsInit::get(ArrayRef<Init *> Range) { +  static FoldingSet<BitsInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileBitsInit(ID, Range); + +  void *IP = nullptr; +  if (BitsInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Range.size()), +                                 alignof(BitsInit)); +  BitsInit *I = new(Mem) BitsInit(Range.size()); +  std::uninitialized_copy(Range.begin(), Range.end(), +                          I->getTrailingObjects<Init *>()); +  ThePool.InsertNode(I, IP); +  return I; +} + +void BitsInit::Profile(FoldingSetNodeID &ID) const { +  ProfileBitsInit(ID, makeArrayRef(getTrailingObjects<Init *>(), NumBits)); +} + +Init *BitsInit::convertInitializerTo(RecTy *Ty) const { +  if (isa<BitRecTy>(Ty)) { +    if (getNumBits() != 1) return nullptr; // Only accept if just one bit! +    return getBit(0); +  } + +  if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) { +    // If the number of bits is right, return it.  Otherwise we need to expand +    // or truncate. +    if (getNumBits() != BRT->getNumBits()) return nullptr; +    return const_cast<BitsInit *>(this); +  } + +  if (isa<IntRecTy>(Ty)) { +    int64_t Result = 0; +    for (unsigned i = 0, e = getNumBits(); i != e; ++i) +      if (auto *Bit = dyn_cast<BitInit>(getBit(i))) +        Result |= static_cast<int64_t>(Bit->getValue()) << i; +      else +        return nullptr; +    return IntInit::get(Result); +  } + +  return nullptr; +} + +Init * +BitsInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const { +  SmallVector<Init *, 16> NewBits(Bits.size()); + +  for (unsigned i = 0, e = Bits.size(); i != e; ++i) { +    if (Bits[i] >= getNumBits()) +      return nullptr; +    NewBits[i] = getBit(Bits[i]); +  } +  return BitsInit::get(NewBits); +} + +bool BitsInit::isConcrete() const { +  for (unsigned i = 0, e = getNumBits(); i != e; ++i) { +    if (!getBit(i)->isConcrete()) +      return false; +  } +  return true; +} + +std::string BitsInit::getAsString() const { +  std::string Result = "{ "; +  for (unsigned i = 0, e = getNumBits(); i != e; ++i) { +    if (i) Result += ", "; +    if (Init *Bit = getBit(e-i-1)) +      Result += Bit->getAsString(); +    else +      Result += "*"; +  } +  return Result + " }"; +} + +// resolveReferences - If there are any field references that refer to fields +// that have been filled in, we can propagate the values now. +Init *BitsInit::resolveReferences(Resolver &R) const { +  bool Changed = false; +  SmallVector<Init *, 16> NewBits(getNumBits()); + +  Init *CachedBitVarRef = nullptr; +  Init *CachedBitVarResolved = nullptr; + +  for (unsigned i = 0, e = getNumBits(); i != e; ++i) { +    Init *CurBit = getBit(i); +    Init *NewBit = CurBit; + +    if (VarBitInit *CurBitVar = dyn_cast<VarBitInit>(CurBit)) { +      if (CurBitVar->getBitVar() != CachedBitVarRef) { +        CachedBitVarRef = CurBitVar->getBitVar(); +        CachedBitVarResolved = CachedBitVarRef->resolveReferences(R); +      } +      assert(CachedBitVarResolved && "Unresolved bitvar reference"); +      NewBit = CachedBitVarResolved->getBit(CurBitVar->getBitNum()); +    } else { +      // getBit(0) implicitly converts int and bits<1> values to bit. +      NewBit = CurBit->resolveReferences(R)->getBit(0); +    } + +    if (isa<UnsetInit>(NewBit) && R.keepUnsetBits()) +      NewBit = CurBit; +    NewBits[i] = NewBit; +    Changed |= CurBit != NewBit; +  } + +  if (Changed) +    return BitsInit::get(NewBits); + +  return const_cast<BitsInit *>(this); +} + +IntInit *IntInit::get(int64_t V) { +  static std::map<int64_t, IntInit*> ThePool; + +  IntInit *&I = ThePool[V]; +  if (!I) I = new(Allocator) IntInit(V); +  return I; +} + +std::string IntInit::getAsString() const { +  return itostr(Value); +} + +static bool canFitInBitfield(int64_t Value, unsigned NumBits) { +  // For example, with NumBits == 4, we permit Values from [-7 .. 15]. +  return (NumBits >= sizeof(Value) * 8) || +         (Value >> NumBits == 0) || (Value >> (NumBits-1) == -1); +} + +Init *IntInit::convertInitializerTo(RecTy *Ty) const { +  if (isa<IntRecTy>(Ty)) +    return const_cast<IntInit *>(this); + +  if (isa<BitRecTy>(Ty)) { +    int64_t Val = getValue(); +    if (Val != 0 && Val != 1) return nullptr;  // Only accept 0 or 1 for a bit! +    return BitInit::get(Val != 0); +  } + +  if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) { +    int64_t Value = getValue(); +    // Make sure this bitfield is large enough to hold the integer value. +    if (!canFitInBitfield(Value, BRT->getNumBits())) +      return nullptr; + +    SmallVector<Init *, 16> NewBits(BRT->getNumBits()); +    for (unsigned i = 0; i != BRT->getNumBits(); ++i) +      NewBits[i] = BitInit::get(Value & ((i < 64) ? (1LL << i) : 0)); + +    return BitsInit::get(NewBits); +  } + +  return nullptr; +} + +Init * +IntInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const { +  SmallVector<Init *, 16> NewBits(Bits.size()); + +  for (unsigned i = 0, e = Bits.size(); i != e; ++i) { +    if (Bits[i] >= 64) +      return nullptr; + +    NewBits[i] = BitInit::get(Value & (INT64_C(1) << Bits[i])); +  } +  return BitsInit::get(NewBits); +} + +CodeInit *CodeInit::get(StringRef V, const SMLoc &Loc) { +  static StringSet<BumpPtrAllocator &> ThePool(Allocator); + +  CodeInitsConstructed++; + +  // Unlike StringMap, StringSet doesn't accept empty keys. +  if (V.empty()) +    return new (Allocator) CodeInit("", Loc); + +  // Location tracking prevents us from de-duping CodeInits as we're never +  // called with the same string and same location twice. However, we can at +  // least de-dupe the strings for a modest saving. +  auto &Entry = *ThePool.insert(V).first; +  return new(Allocator) CodeInit(Entry.getKey(), Loc); +} + +StringInit *StringInit::get(StringRef V) { +  static StringMap<StringInit*, BumpPtrAllocator &> ThePool(Allocator); + +  auto &Entry = *ThePool.insert(std::make_pair(V, nullptr)).first; +  if (!Entry.second) +    Entry.second = new(Allocator) StringInit(Entry.getKey()); +  return Entry.second; +} + +Init *StringInit::convertInitializerTo(RecTy *Ty) const { +  if (isa<StringRecTy>(Ty)) +    return const_cast<StringInit *>(this); +  if (isa<CodeRecTy>(Ty)) +    return CodeInit::get(getValue(), SMLoc()); + +  return nullptr; +} + +Init *CodeInit::convertInitializerTo(RecTy *Ty) const { +  if (isa<CodeRecTy>(Ty)) +    return const_cast<CodeInit *>(this); +  if (isa<StringRecTy>(Ty)) +    return StringInit::get(getValue()); + +  return nullptr; +} + +static void ProfileListInit(FoldingSetNodeID &ID, +                            ArrayRef<Init *> Range, +                            RecTy *EltTy) { +  ID.AddInteger(Range.size()); +  ID.AddPointer(EltTy); + +  for (Init *I : Range) +    ID.AddPointer(I); +} + +ListInit *ListInit::get(ArrayRef<Init *> Range, RecTy *EltTy) { +  static FoldingSet<ListInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileListInit(ID, Range, EltTy); + +  void *IP = nullptr; +  if (ListInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  assert(Range.empty() || !isa<TypedInit>(Range[0]) || +         cast<TypedInit>(Range[0])->getType()->typeIsConvertibleTo(EltTy)); + +  void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Range.size()), +                                 alignof(ListInit)); +  ListInit *I = new(Mem) ListInit(Range.size(), EltTy); +  std::uninitialized_copy(Range.begin(), Range.end(), +                          I->getTrailingObjects<Init *>()); +  ThePool.InsertNode(I, IP); +  return I; +} + +void ListInit::Profile(FoldingSetNodeID &ID) const { +  RecTy *EltTy = cast<ListRecTy>(getType())->getElementType(); + +  ProfileListInit(ID, getValues(), EltTy); +} + +Init *ListInit::convertInitializerTo(RecTy *Ty) const { +  if (getType() == Ty) +    return const_cast<ListInit*>(this); + +  if (auto *LRT = dyn_cast<ListRecTy>(Ty)) { +    SmallVector<Init*, 8> Elements; +    Elements.reserve(getValues().size()); + +    // Verify that all of the elements of the list are subclasses of the +    // appropriate class! +    bool Changed = false; +    RecTy *ElementType = LRT->getElementType(); +    for (Init *I : getValues()) +      if (Init *CI = I->convertInitializerTo(ElementType)) { +        Elements.push_back(CI); +        if (CI != I) +          Changed = true; +      } else +        return nullptr; + +    if (!Changed) +      return const_cast<ListInit*>(this); +    return ListInit::get(Elements, ElementType); +  } + +  return nullptr; +} + +Init *ListInit::convertInitListSlice(ArrayRef<unsigned> Elements) const { +  SmallVector<Init*, 8> Vals; +  Vals.reserve(Elements.size()); +  for (unsigned Element : Elements) { +    if (Element >= size()) +      return nullptr; +    Vals.push_back(getElement(Element)); +  } +  return ListInit::get(Vals, getElementType()); +} + +Record *ListInit::getElementAsRecord(unsigned i) const { +  assert(i < NumValues && "List element index out of range!"); +  DefInit *DI = dyn_cast<DefInit>(getElement(i)); +  if (!DI) +    PrintFatalError("Expected record in list!"); +  return DI->getDef(); +} + +Init *ListInit::resolveReferences(Resolver &R) const { +  SmallVector<Init*, 8> Resolved; +  Resolved.reserve(size()); +  bool Changed = false; + +  for (Init *CurElt : getValues()) { +    Init *E = CurElt->resolveReferences(R); +    Changed |= E != CurElt; +    Resolved.push_back(E); +  } + +  if (Changed) +    return ListInit::get(Resolved, getElementType()); +  return const_cast<ListInit *>(this); +} + +bool ListInit::isConcrete() const { +  for (Init *Element : *this) { +    if (!Element->isConcrete()) +      return false; +  } +  return true; +} + +std::string ListInit::getAsString() const { +  std::string Result = "["; +  const char *sep = ""; +  for (Init *Element : *this) { +    Result += sep; +    sep = ", "; +    Result += Element->getAsString(); +  } +  return Result + "]"; +} + +Init *OpInit::getBit(unsigned Bit) const { +  if (getType() == BitRecTy::get()) +    return const_cast<OpInit*>(this); +  return VarBitInit::get(const_cast<OpInit*>(this), Bit); +} + +static void +ProfileUnOpInit(FoldingSetNodeID &ID, unsigned Opcode, Init *Op, RecTy *Type) { +  ID.AddInteger(Opcode); +  ID.AddPointer(Op); +  ID.AddPointer(Type); +} + +UnOpInit *UnOpInit::get(UnaryOp Opc, Init *LHS, RecTy *Type) { +  static FoldingSet<UnOpInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileUnOpInit(ID, Opc, LHS, Type); + +  void *IP = nullptr; +  if (UnOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  UnOpInit *I = new(Allocator) UnOpInit(Opc, LHS, Type); +  ThePool.InsertNode(I, IP); +  return I; +} + +void UnOpInit::Profile(FoldingSetNodeID &ID) const { +  ProfileUnOpInit(ID, getOpcode(), getOperand(), getType()); +} + +Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const { +  switch (getOpcode()) { +  case CAST: +    if (isa<StringRecTy>(getType())) { +      if (StringInit *LHSs = dyn_cast<StringInit>(LHS)) +        return LHSs; + +      if (DefInit *LHSd = dyn_cast<DefInit>(LHS)) +        return StringInit::get(LHSd->getAsString()); + +      if (IntInit *LHSi = dyn_cast<IntInit>(LHS)) +        return StringInit::get(LHSi->getAsString()); +    } else if (isa<RecordRecTy>(getType())) { +      if (StringInit *Name = dyn_cast<StringInit>(LHS)) { +        if (!CurRec && !IsFinal) +          break; +        assert(CurRec && "NULL pointer"); +        Record *D; + +        // Self-references are allowed, but their resolution is delayed until +        // the final resolve to ensure that we get the correct type for them. +        if (Name == CurRec->getNameInit()) { +          if (!IsFinal) +            break; +          D = CurRec; +        } else { +          D = CurRec->getRecords().getDef(Name->getValue()); +          if (!D) { +            if (IsFinal) +              PrintFatalError(CurRec->getLoc(), +                              Twine("Undefined reference to record: '") + +                              Name->getValue() + "'\n"); +            break; +          } +        } + +        DefInit *DI = DefInit::get(D); +        if (!DI->getType()->typeIsA(getType())) { +          PrintFatalError(CurRec->getLoc(), +                          Twine("Expected type '") + +                          getType()->getAsString() + "', got '" + +                          DI->getType()->getAsString() + "' in: " + +                          getAsString() + "\n"); +        } +        return DI; +      } +    } + +    if (Init *NewInit = LHS->convertInitializerTo(getType())) +      return NewInit; +    break; + +  case HEAD: +    if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) { +      assert(!LHSl->empty() && "Empty list in head"); +      return LHSl->getElement(0); +    } +    break; + +  case TAIL: +    if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) { +      assert(!LHSl->empty() && "Empty list in tail"); +      // Note the +1.  We can't just pass the result of getValues() +      // directly. +      return ListInit::get(LHSl->getValues().slice(1), LHSl->getElementType()); +    } +    break; + +  case SIZE: +    if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) +      return IntInit::get(LHSl->size()); +    break; + +  case EMPTY: +    if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) +      return IntInit::get(LHSl->empty()); +    if (StringInit *LHSs = dyn_cast<StringInit>(LHS)) +      return IntInit::get(LHSs->getValue().empty()); +    break; +  } +  return const_cast<UnOpInit *>(this); +} + +Init *UnOpInit::resolveReferences(Resolver &R) const { +  Init *lhs = LHS->resolveReferences(R); + +  if (LHS != lhs || (R.isFinal() && getOpcode() == CAST)) +    return (UnOpInit::get(getOpcode(), lhs, getType())) +        ->Fold(R.getCurrentRecord(), R.isFinal()); +  return const_cast<UnOpInit *>(this); +} + +std::string UnOpInit::getAsString() const { +  std::string Result; +  switch (getOpcode()) { +  case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break; +  case HEAD: Result = "!head"; break; +  case TAIL: Result = "!tail"; break; +  case SIZE: Result = "!size"; break; +  case EMPTY: Result = "!empty"; break; +  } +  return Result + "(" + LHS->getAsString() + ")"; +} + +static void +ProfileBinOpInit(FoldingSetNodeID &ID, unsigned Opcode, Init *LHS, Init *RHS, +                 RecTy *Type) { +  ID.AddInteger(Opcode); +  ID.AddPointer(LHS); +  ID.AddPointer(RHS); +  ID.AddPointer(Type); +} + +BinOpInit *BinOpInit::get(BinaryOp Opc, Init *LHS, +                          Init *RHS, RecTy *Type) { +  static FoldingSet<BinOpInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileBinOpInit(ID, Opc, LHS, RHS, Type); + +  void *IP = nullptr; +  if (BinOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  BinOpInit *I = new(Allocator) BinOpInit(Opc, LHS, RHS, Type); +  ThePool.InsertNode(I, IP); +  return I; +} + +void BinOpInit::Profile(FoldingSetNodeID &ID) const { +  ProfileBinOpInit(ID, getOpcode(), getLHS(), getRHS(), getType()); +} + +static StringInit *ConcatStringInits(const StringInit *I0, +                                     const StringInit *I1) { +  SmallString<80> Concat(I0->getValue()); +  Concat.append(I1->getValue()); +  return StringInit::get(Concat); +} + +Init *BinOpInit::getStrConcat(Init *I0, Init *I1) { +  // Shortcut for the common case of concatenating two strings. +  if (const StringInit *I0s = dyn_cast<StringInit>(I0)) +    if (const StringInit *I1s = dyn_cast<StringInit>(I1)) +      return ConcatStringInits(I0s, I1s); +  return BinOpInit::get(BinOpInit::STRCONCAT, I0, I1, StringRecTy::get()); +} + +static ListInit *ConcatListInits(const ListInit *LHS, +                                 const ListInit *RHS) { +  SmallVector<Init *, 8> Args; +  Args.insert(Args.end(), LHS->begin(), LHS->end()); +  Args.insert(Args.end(), RHS->begin(), RHS->end()); +  return ListInit::get(Args, LHS->getElementType()); +} + +Init *BinOpInit::getListConcat(TypedInit *LHS, Init *RHS) { +  assert(isa<ListRecTy>(LHS->getType()) && "First arg must be a list"); + +  // Shortcut for the common case of concatenating two lists. +   if (const ListInit *LHSList = dyn_cast<ListInit>(LHS)) +     if (const ListInit *RHSList = dyn_cast<ListInit>(RHS)) +       return ConcatListInits(LHSList, RHSList); +   return BinOpInit::get(BinOpInit::LISTCONCAT, LHS, RHS, LHS->getType()); +} + +Init *BinOpInit::getListSplat(TypedInit *LHS, Init *RHS) { +  return BinOpInit::get(BinOpInit::LISTSPLAT, LHS, RHS, LHS->getType()); +} + +Init *BinOpInit::Fold(Record *CurRec) const { +  switch (getOpcode()) { +  case CONCAT: { +    DagInit *LHSs = dyn_cast<DagInit>(LHS); +    DagInit *RHSs = dyn_cast<DagInit>(RHS); +    if (LHSs && RHSs) { +      DefInit *LOp = dyn_cast<DefInit>(LHSs->getOperator()); +      DefInit *ROp = dyn_cast<DefInit>(RHSs->getOperator()); +      if (!LOp || !ROp) +        break; +      if (LOp->getDef() != ROp->getDef()) { +        PrintFatalError(Twine("Concatenated Dag operators do not match: '") + +                        LHSs->getAsString() + "' vs. '" + RHSs->getAsString() + +                        "'"); +      } +      SmallVector<Init*, 8> Args; +      SmallVector<StringInit*, 8> ArgNames; +      for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { +        Args.push_back(LHSs->getArg(i)); +        ArgNames.push_back(LHSs->getArgName(i)); +      } +      for (unsigned i = 0, e = RHSs->getNumArgs(); i != e; ++i) { +        Args.push_back(RHSs->getArg(i)); +        ArgNames.push_back(RHSs->getArgName(i)); +      } +      return DagInit::get(LHSs->getOperator(), nullptr, Args, ArgNames); +    } +    break; +  } +  case LISTCONCAT: { +    ListInit *LHSs = dyn_cast<ListInit>(LHS); +    ListInit *RHSs = dyn_cast<ListInit>(RHS); +    if (LHSs && RHSs) { +      SmallVector<Init *, 8> Args; +      Args.insert(Args.end(), LHSs->begin(), LHSs->end()); +      Args.insert(Args.end(), RHSs->begin(), RHSs->end()); +      return ListInit::get(Args, LHSs->getElementType()); +    } +    break; +  } +  case LISTSPLAT: { +    TypedInit *Value = dyn_cast<TypedInit>(LHS); +    IntInit *Size = dyn_cast<IntInit>(RHS); +    if (Value && Size) { +      SmallVector<Init *, 8> Args(Size->getValue(), Value); +      return ListInit::get(Args, Value->getType()); +    } +    break; +  } +  case STRCONCAT: { +    StringInit *LHSs = dyn_cast<StringInit>(LHS); +    StringInit *RHSs = dyn_cast<StringInit>(RHS); +    if (LHSs && RHSs) +      return ConcatStringInits(LHSs, RHSs); +    break; +  } +  case EQ: +  case NE: +  case LE: +  case LT: +  case GE: +  case GT: { +    // try to fold eq comparison for 'bit' and 'int', otherwise fallback +    // to string objects. +    IntInit *L = +        dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get())); +    IntInit *R = +        dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get())); + +    if (L && R) { +      bool Result; +      switch (getOpcode()) { +      case EQ: Result = L->getValue() == R->getValue(); break; +      case NE: Result = L->getValue() != R->getValue(); break; +      case LE: Result = L->getValue() <= R->getValue(); break; +      case LT: Result = L->getValue() < R->getValue(); break; +      case GE: Result = L->getValue() >= R->getValue(); break; +      case GT: Result = L->getValue() > R->getValue(); break; +      default: llvm_unreachable("unhandled comparison"); +      } +      return BitInit::get(Result); +    } + +    if (getOpcode() == EQ || getOpcode() == NE) { +      StringInit *LHSs = dyn_cast<StringInit>(LHS); +      StringInit *RHSs = dyn_cast<StringInit>(RHS); + +      // Make sure we've resolved +      if (LHSs && RHSs) { +        bool Equal = LHSs->getValue() == RHSs->getValue(); +        return BitInit::get(getOpcode() == EQ ? Equal : !Equal); +      } +    } + +    break; +  } +  case ADD: +  case MUL: +  case AND: +  case OR: +  case SHL: +  case SRA: +  case SRL: { +    IntInit *LHSi = +      dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get())); +    IntInit *RHSi = +      dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get())); +    if (LHSi && RHSi) { +      int64_t LHSv = LHSi->getValue(), RHSv = RHSi->getValue(); +      int64_t Result; +      switch (getOpcode()) { +      default: llvm_unreachable("Bad opcode!"); +      case ADD: Result = LHSv +  RHSv; break; +      case MUL: Result = LHSv *  RHSv; break; +      case AND: Result = LHSv &  RHSv; break; +      case OR: Result = LHSv | RHSv; break; +      case SHL: Result = LHSv << RHSv; break; +      case SRA: Result = LHSv >> RHSv; break; +      case SRL: Result = (uint64_t)LHSv >> (uint64_t)RHSv; break; +      } +      return IntInit::get(Result); +    } +    break; +  } +  } +  return const_cast<BinOpInit *>(this); +} + +Init *BinOpInit::resolveReferences(Resolver &R) const { +  Init *lhs = LHS->resolveReferences(R); +  Init *rhs = RHS->resolveReferences(R); + +  if (LHS != lhs || RHS != rhs) +    return (BinOpInit::get(getOpcode(), lhs, rhs, getType())) +        ->Fold(R.getCurrentRecord()); +  return const_cast<BinOpInit *>(this); +} + +std::string BinOpInit::getAsString() const { +  std::string Result; +  switch (getOpcode()) { +  case CONCAT: Result = "!con"; break; +  case ADD: Result = "!add"; break; +  case MUL: Result = "!mul"; break; +  case AND: Result = "!and"; break; +  case OR: Result = "!or"; break; +  case SHL: Result = "!shl"; break; +  case SRA: Result = "!sra"; break; +  case SRL: Result = "!srl"; break; +  case EQ: Result = "!eq"; break; +  case NE: Result = "!ne"; break; +  case LE: Result = "!le"; break; +  case LT: Result = "!lt"; break; +  case GE: Result = "!ge"; break; +  case GT: Result = "!gt"; break; +  case LISTCONCAT: Result = "!listconcat"; break; +  case LISTSPLAT: Result = "!listsplat"; break; +  case STRCONCAT: Result = "!strconcat"; break; +  } +  return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; +} + +static void +ProfileTernOpInit(FoldingSetNodeID &ID, unsigned Opcode, Init *LHS, Init *MHS, +                  Init *RHS, RecTy *Type) { +  ID.AddInteger(Opcode); +  ID.AddPointer(LHS); +  ID.AddPointer(MHS); +  ID.AddPointer(RHS); +  ID.AddPointer(Type); +} + +TernOpInit *TernOpInit::get(TernaryOp Opc, Init *LHS, Init *MHS, Init *RHS, +                            RecTy *Type) { +  static FoldingSet<TernOpInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileTernOpInit(ID, Opc, LHS, MHS, RHS, Type); + +  void *IP = nullptr; +  if (TernOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  TernOpInit *I = new(Allocator) TernOpInit(Opc, LHS, MHS, RHS, Type); +  ThePool.InsertNode(I, IP); +  return I; +} + +void TernOpInit::Profile(FoldingSetNodeID &ID) const { +  ProfileTernOpInit(ID, getOpcode(), getLHS(), getMHS(), getRHS(), getType()); +} + +static Init *ForeachApply(Init *LHS, Init *MHSe, Init *RHS, Record *CurRec) { +  MapResolver R(CurRec); +  R.set(LHS, MHSe); +  return RHS->resolveReferences(R); +} + +static Init *ForeachDagApply(Init *LHS, DagInit *MHSd, Init *RHS, +                             Record *CurRec) { +  bool Change = false; +  Init *Val = ForeachApply(LHS, MHSd->getOperator(), RHS, CurRec); +  if (Val != MHSd->getOperator()) +    Change = true; + +  SmallVector<std::pair<Init *, StringInit *>, 8> NewArgs; +  for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) { +    Init *Arg = MHSd->getArg(i); +    Init *NewArg; +    StringInit *ArgName = MHSd->getArgName(i); + +    if (DagInit *Argd = dyn_cast<DagInit>(Arg)) +      NewArg = ForeachDagApply(LHS, Argd, RHS, CurRec); +    else +      NewArg = ForeachApply(LHS, Arg, RHS, CurRec); + +    NewArgs.push_back(std::make_pair(NewArg, ArgName)); +    if (Arg != NewArg) +      Change = true; +  } + +  if (Change) +    return DagInit::get(Val, nullptr, NewArgs); +  return MHSd; +} + +// Applies RHS to all elements of MHS, using LHS as a temp variable. +static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, +                           Record *CurRec) { +  if (DagInit *MHSd = dyn_cast<DagInit>(MHS)) +    return ForeachDagApply(LHS, MHSd, RHS, CurRec); + +  if (ListInit *MHSl = dyn_cast<ListInit>(MHS)) { +    SmallVector<Init *, 8> NewList(MHSl->begin(), MHSl->end()); + +    for (Init *&Item : NewList) { +      Init *NewItem = ForeachApply(LHS, Item, RHS, CurRec); +      if (NewItem != Item) +        Item = NewItem; +    } +    return ListInit::get(NewList, cast<ListRecTy>(Type)->getElementType()); +  } + +  return nullptr; +} + +Init *TernOpInit::Fold(Record *CurRec) const { +  switch (getOpcode()) { +  case SUBST: { +    DefInit *LHSd = dyn_cast<DefInit>(LHS); +    VarInit *LHSv = dyn_cast<VarInit>(LHS); +    StringInit *LHSs = dyn_cast<StringInit>(LHS); + +    DefInit *MHSd = dyn_cast<DefInit>(MHS); +    VarInit *MHSv = dyn_cast<VarInit>(MHS); +    StringInit *MHSs = dyn_cast<StringInit>(MHS); + +    DefInit *RHSd = dyn_cast<DefInit>(RHS); +    VarInit *RHSv = dyn_cast<VarInit>(RHS); +    StringInit *RHSs = dyn_cast<StringInit>(RHS); + +    if (LHSd && MHSd && RHSd) { +      Record *Val = RHSd->getDef(); +      if (LHSd->getAsString() == RHSd->getAsString()) +        Val = MHSd->getDef(); +      return DefInit::get(Val); +    } +    if (LHSv && MHSv && RHSv) { +      std::string Val = RHSv->getName(); +      if (LHSv->getAsString() == RHSv->getAsString()) +        Val = MHSv->getName(); +      return VarInit::get(Val, getType()); +    } +    if (LHSs && MHSs && RHSs) { +      std::string Val = RHSs->getValue(); + +      std::string::size_type found; +      std::string::size_type idx = 0; +      while (true) { +        found = Val.find(LHSs->getValue(), idx); +        if (found == std::string::npos) +          break; +        Val.replace(found, LHSs->getValue().size(), MHSs->getValue()); +        idx = found + MHSs->getValue().size(); +      } + +      return StringInit::get(Val); +    } +    break; +  } + +  case FOREACH: { +    if (Init *Result = ForeachHelper(LHS, MHS, RHS, getType(), CurRec)) +      return Result; +    break; +  } + +  case IF: { +    if (IntInit *LHSi = dyn_cast_or_null<IntInit>( +                            LHS->convertInitializerTo(IntRecTy::get()))) { +      if (LHSi->getValue()) +        return MHS; +      return RHS; +    } +    break; +  } + +  case DAG: { +    ListInit *MHSl = dyn_cast<ListInit>(MHS); +    ListInit *RHSl = dyn_cast<ListInit>(RHS); +    bool MHSok = MHSl || isa<UnsetInit>(MHS); +    bool RHSok = RHSl || isa<UnsetInit>(RHS); + +    if (isa<UnsetInit>(MHS) && isa<UnsetInit>(RHS)) +      break; // Typically prevented by the parser, but might happen with template args + +    if (MHSok && RHSok && (!MHSl || !RHSl || MHSl->size() == RHSl->size())) { +      SmallVector<std::pair<Init *, StringInit *>, 8> Children; +      unsigned Size = MHSl ? MHSl->size() : RHSl->size(); +      for (unsigned i = 0; i != Size; ++i) { +        Init *Node = MHSl ? MHSl->getElement(i) : UnsetInit::get(); +        Init *Name = RHSl ? RHSl->getElement(i) : UnsetInit::get(); +        if (!isa<StringInit>(Name) && !isa<UnsetInit>(Name)) +          return const_cast<TernOpInit *>(this); +        Children.emplace_back(Node, dyn_cast<StringInit>(Name)); +      } +      return DagInit::get(LHS, nullptr, Children); +    } +    break; +  } +  } + +  return const_cast<TernOpInit *>(this); +} + +Init *TernOpInit::resolveReferences(Resolver &R) const { +  Init *lhs = LHS->resolveReferences(R); + +  if (getOpcode() == IF && lhs != LHS) { +    if (IntInit *Value = dyn_cast_or_null<IntInit>( +                             lhs->convertInitializerTo(IntRecTy::get()))) { +      // Short-circuit +      if (Value->getValue()) +        return MHS->resolveReferences(R); +      return RHS->resolveReferences(R); +    } +  } + +  Init *mhs = MHS->resolveReferences(R); +  Init *rhs; + +  if (getOpcode() == FOREACH) { +    ShadowResolver SR(R); +    SR.addShadow(lhs); +    rhs = RHS->resolveReferences(SR); +  } else { +    rhs = RHS->resolveReferences(R); +  } + +  if (LHS != lhs || MHS != mhs || RHS != rhs) +    return (TernOpInit::get(getOpcode(), lhs, mhs, rhs, getType())) +        ->Fold(R.getCurrentRecord()); +  return const_cast<TernOpInit *>(this); +} + +std::string TernOpInit::getAsString() const { +  std::string Result; +  bool UnquotedLHS = false; +  switch (getOpcode()) { +  case SUBST: Result = "!subst"; break; +  case FOREACH: Result = "!foreach"; UnquotedLHS = true; break; +  case IF: Result = "!if"; break; +  case DAG: Result = "!dag"; break; +  } +  return (Result + "(" + +          (UnquotedLHS ? LHS->getAsUnquotedString() : LHS->getAsString()) + +          ", " + MHS->getAsString() + ", " + RHS->getAsString() + ")"); +} + +static void ProfileFoldOpInit(FoldingSetNodeID &ID, Init *A, Init *B, +                              Init *Start, Init *List, Init *Expr, +                              RecTy *Type) { +  ID.AddPointer(Start); +  ID.AddPointer(List); +  ID.AddPointer(A); +  ID.AddPointer(B); +  ID.AddPointer(Expr); +  ID.AddPointer(Type); +} + +FoldOpInit *FoldOpInit::get(Init *Start, Init *List, Init *A, Init *B, +                            Init *Expr, RecTy *Type) { +  static FoldingSet<FoldOpInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileFoldOpInit(ID, Start, List, A, B, Expr, Type); + +  void *IP = nullptr; +  if (FoldOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  FoldOpInit *I = new (Allocator) FoldOpInit(Start, List, A, B, Expr, Type); +  ThePool.InsertNode(I, IP); +  return I; +} + +void FoldOpInit::Profile(FoldingSetNodeID &ID) const { +  ProfileFoldOpInit(ID, Start, List, A, B, Expr, getType()); +} + +Init *FoldOpInit::Fold(Record *CurRec) const { +  if (ListInit *LI = dyn_cast<ListInit>(List)) { +    Init *Accum = Start; +    for (Init *Elt : *LI) { +      MapResolver R(CurRec); +      R.set(A, Accum); +      R.set(B, Elt); +      Accum = Expr->resolveReferences(R); +    } +    return Accum; +  } +  return const_cast<FoldOpInit *>(this); +} + +Init *FoldOpInit::resolveReferences(Resolver &R) const { +  Init *NewStart = Start->resolveReferences(R); +  Init *NewList = List->resolveReferences(R); +  ShadowResolver SR(R); +  SR.addShadow(A); +  SR.addShadow(B); +  Init *NewExpr = Expr->resolveReferences(SR); + +  if (Start == NewStart && List == NewList && Expr == NewExpr) +    return const_cast<FoldOpInit *>(this); + +  return get(NewStart, NewList, A, B, NewExpr, getType()) +      ->Fold(R.getCurrentRecord()); +} + +Init *FoldOpInit::getBit(unsigned Bit) const { +  return VarBitInit::get(const_cast<FoldOpInit *>(this), Bit); +} + +std::string FoldOpInit::getAsString() const { +  return (Twine("!foldl(") + Start->getAsString() + ", " + List->getAsString() + +          ", " + A->getAsUnquotedString() + ", " + B->getAsUnquotedString() + +          ", " + Expr->getAsString() + ")") +      .str(); +} + +static void ProfileIsAOpInit(FoldingSetNodeID &ID, RecTy *CheckType, +                             Init *Expr) { +  ID.AddPointer(CheckType); +  ID.AddPointer(Expr); +} + +IsAOpInit *IsAOpInit::get(RecTy *CheckType, Init *Expr) { +  static FoldingSet<IsAOpInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileIsAOpInit(ID, CheckType, Expr); + +  void *IP = nullptr; +  if (IsAOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  IsAOpInit *I = new (Allocator) IsAOpInit(CheckType, Expr); +  ThePool.InsertNode(I, IP); +  return I; +} + +void IsAOpInit::Profile(FoldingSetNodeID &ID) const { +  ProfileIsAOpInit(ID, CheckType, Expr); +} + +Init *IsAOpInit::Fold() const { +  if (TypedInit *TI = dyn_cast<TypedInit>(Expr)) { +    // Is the expression type known to be (a subclass of) the desired type? +    if (TI->getType()->typeIsConvertibleTo(CheckType)) +      return IntInit::get(1); + +    if (isa<RecordRecTy>(CheckType)) { +      // If the target type is not a subclass of the expression type, or if +      // the expression has fully resolved to a record, we know that it can't +      // be of the required type. +      if (!CheckType->typeIsConvertibleTo(TI->getType()) || isa<DefInit>(Expr)) +        return IntInit::get(0); +    } else { +      // We treat non-record types as not castable. +      return IntInit::get(0); +    } +  } +  return const_cast<IsAOpInit *>(this); +} + +Init *IsAOpInit::resolveReferences(Resolver &R) const { +  Init *NewExpr = Expr->resolveReferences(R); +  if (Expr != NewExpr) +    return get(CheckType, NewExpr)->Fold(); +  return const_cast<IsAOpInit *>(this); +} + +Init *IsAOpInit::getBit(unsigned Bit) const { +  return VarBitInit::get(const_cast<IsAOpInit *>(this), Bit); +} + +std::string IsAOpInit::getAsString() const { +  return (Twine("!isa<") + CheckType->getAsString() + ">(" + +          Expr->getAsString() + ")") +      .str(); +} + +RecTy *TypedInit::getFieldType(StringInit *FieldName) const { +  if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType())) { +    for (Record *Rec : RecordType->getClasses()) { +      if (RecordVal *Field = Rec->getValue(FieldName)) +        return Field->getType(); +    } +  } +  return nullptr; +} + +Init * +TypedInit::convertInitializerTo(RecTy *Ty) const { +  if (getType() == Ty || getType()->typeIsA(Ty)) +    return const_cast<TypedInit *>(this); + +  if (isa<BitRecTy>(getType()) && isa<BitsRecTy>(Ty) && +      cast<BitsRecTy>(Ty)->getNumBits() == 1) +    return BitsInit::get({const_cast<TypedInit *>(this)}); + +  return nullptr; +} + +Init *TypedInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const { +  BitsRecTy *T = dyn_cast<BitsRecTy>(getType()); +  if (!T) return nullptr;  // Cannot subscript a non-bits variable. +  unsigned NumBits = T->getNumBits(); + +  SmallVector<Init *, 16> NewBits; +  NewBits.reserve(Bits.size()); +  for (unsigned Bit : Bits) { +    if (Bit >= NumBits) +      return nullptr; + +    NewBits.push_back(VarBitInit::get(const_cast<TypedInit *>(this), Bit)); +  } +  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); +} + +Init *TypedInit::convertInitListSlice(ArrayRef<unsigned> Elements) const { +  ListRecTy *T = dyn_cast<ListRecTy>(getType()); +  if (!T) return nullptr;  // Cannot subscript a non-list variable. + +  if (Elements.size() == 1) +    return VarListElementInit::get(const_cast<TypedInit *>(this), Elements[0]); + +  SmallVector<Init*, 8> ListInits; +  ListInits.reserve(Elements.size()); +  for (unsigned Element : Elements) +    ListInits.push_back(VarListElementInit::get(const_cast<TypedInit *>(this), +                                                Element)); +  return ListInit::get(ListInits, T->getElementType()); +} + + +VarInit *VarInit::get(StringRef VN, RecTy *T) { +  Init *Value = StringInit::get(VN); +  return VarInit::get(Value, T); +} + +VarInit *VarInit::get(Init *VN, RecTy *T) { +  using Key = std::pair<RecTy *, Init *>; +  static DenseMap<Key, VarInit*> ThePool; + +  Key TheKey(std::make_pair(T, VN)); + +  VarInit *&I = ThePool[TheKey]; +  if (!I) +    I = new(Allocator) VarInit(VN, T); +  return I; +} + +StringRef VarInit::getName() const { +  StringInit *NameString = cast<StringInit>(getNameInit()); +  return NameString->getValue(); +} + +Init *VarInit::getBit(unsigned Bit) const { +  if (getType() == BitRecTy::get()) +    return const_cast<VarInit*>(this); +  return VarBitInit::get(const_cast<VarInit*>(this), Bit); +} + +Init *VarInit::resolveReferences(Resolver &R) const { +  if (Init *Val = R.resolve(VarName)) +    return Val; +  return const_cast<VarInit *>(this); +} + +VarBitInit *VarBitInit::get(TypedInit *T, unsigned B) { +  using Key = std::pair<TypedInit *, unsigned>; +  static DenseMap<Key, VarBitInit*> ThePool; + +  Key TheKey(std::make_pair(T, B)); + +  VarBitInit *&I = ThePool[TheKey]; +  if (!I) +    I = new(Allocator) VarBitInit(T, B); +  return I; +} + +std::string VarBitInit::getAsString() const { +  return TI->getAsString() + "{" + utostr(Bit) + "}"; +} + +Init *VarBitInit::resolveReferences(Resolver &R) const { +  Init *I = TI->resolveReferences(R); +  if (TI != I) +    return I->getBit(getBitNum()); + +  return const_cast<VarBitInit*>(this); +} + +VarListElementInit *VarListElementInit::get(TypedInit *T, +                                            unsigned E) { +  using Key = std::pair<TypedInit *, unsigned>; +  static DenseMap<Key, VarListElementInit*> ThePool; + +  Key TheKey(std::make_pair(T, E)); + +  VarListElementInit *&I = ThePool[TheKey]; +  if (!I) I = new(Allocator) VarListElementInit(T, E); +  return I; +} + +std::string VarListElementInit::getAsString() const { +  return TI->getAsString() + "[" + utostr(Element) + "]"; +} + +Init *VarListElementInit::resolveReferences(Resolver &R) const { +  Init *NewTI = TI->resolveReferences(R); +  if (ListInit *List = dyn_cast<ListInit>(NewTI)) { +    // Leave out-of-bounds array references as-is. This can happen without +    // being an error, e.g. in the untaken "branch" of an !if expression. +    if (getElementNum() < List->size()) +      return List->getElement(getElementNum()); +  } +  if (NewTI != TI && isa<TypedInit>(NewTI)) +    return VarListElementInit::get(cast<TypedInit>(NewTI), getElementNum()); +  return const_cast<VarListElementInit *>(this); +} + +Init *VarListElementInit::getBit(unsigned Bit) const { +  if (getType() == BitRecTy::get()) +    return const_cast<VarListElementInit*>(this); +  return VarBitInit::get(const_cast<VarListElementInit*>(this), Bit); +} + +DefInit::DefInit(Record *D) +    : TypedInit(IK_DefInit, D->getType()), Def(D) {} + +DefInit *DefInit::get(Record *R) { +  return R->getDefInit(); +} + +Init *DefInit::convertInitializerTo(RecTy *Ty) const { +  if (auto *RRT = dyn_cast<RecordRecTy>(Ty)) +    if (getType()->typeIsConvertibleTo(RRT)) +      return const_cast<DefInit *>(this); +  return nullptr; +} + +RecTy *DefInit::getFieldType(StringInit *FieldName) const { +  if (const RecordVal *RV = Def->getValue(FieldName)) +    return RV->getType(); +  return nullptr; +} + +std::string DefInit::getAsString() const { +  return Def->getName(); +} + +static void ProfileVarDefInit(FoldingSetNodeID &ID, +                              Record *Class, +                              ArrayRef<Init *> Args) { +  ID.AddInteger(Args.size()); +  ID.AddPointer(Class); + +  for (Init *I : Args) +    ID.AddPointer(I); +} + +VarDefInit *VarDefInit::get(Record *Class, ArrayRef<Init *> Args) { +  static FoldingSet<VarDefInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileVarDefInit(ID, Class, Args); + +  void *IP = nullptr; +  if (VarDefInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Args.size()), +                                 alignof(VarDefInit)); +  VarDefInit *I = new(Mem) VarDefInit(Class, Args.size()); +  std::uninitialized_copy(Args.begin(), Args.end(), +                          I->getTrailingObjects<Init *>()); +  ThePool.InsertNode(I, IP); +  return I; +} + +void VarDefInit::Profile(FoldingSetNodeID &ID) const { +  ProfileVarDefInit(ID, Class, args()); +} + +DefInit *VarDefInit::instantiate() { +  if (!Def) { +    RecordKeeper &Records = Class->getRecords(); +    auto NewRecOwner = std::make_unique<Record>(Records.getNewAnonymousName(), +                                           Class->getLoc(), Records, +                                           /*IsAnonymous=*/true); +    Record *NewRec = NewRecOwner.get(); + +    // Copy values from class to instance +    for (const RecordVal &Val : Class->getValues()) +      NewRec->addValue(Val); + +    // Substitute and resolve template arguments +    ArrayRef<Init *> TArgs = Class->getTemplateArgs(); +    MapResolver R(NewRec); + +    for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { +      if (i < args_size()) +        R.set(TArgs[i], getArg(i)); +      else +        R.set(TArgs[i], NewRec->getValue(TArgs[i])->getValue()); + +      NewRec->removeValue(TArgs[i]); +    } + +    NewRec->resolveReferences(R); + +    // Add superclasses. +    ArrayRef<std::pair<Record *, SMRange>> SCs = Class->getSuperClasses(); +    for (const auto &SCPair : SCs) +      NewRec->addSuperClass(SCPair.first, SCPair.second); + +    NewRec->addSuperClass(Class, +                          SMRange(Class->getLoc().back(), +                                  Class->getLoc().back())); + +    // Resolve internal references and store in record keeper +    NewRec->resolveReferences(); +    Records.addDef(std::move(NewRecOwner)); + +    Def = DefInit::get(NewRec); +  } + +  return Def; +} + +Init *VarDefInit::resolveReferences(Resolver &R) const { +  TrackUnresolvedResolver UR(&R); +  bool Changed = false; +  SmallVector<Init *, 8> NewArgs; +  NewArgs.reserve(args_size()); + +  for (Init *Arg : args()) { +    Init *NewArg = Arg->resolveReferences(UR); +    NewArgs.push_back(NewArg); +    Changed |= NewArg != Arg; +  } + +  if (Changed) { +    auto New = VarDefInit::get(Class, NewArgs); +    if (!UR.foundUnresolved()) +      return New->instantiate(); +    return New; +  } +  return const_cast<VarDefInit *>(this); +} + +Init *VarDefInit::Fold() const { +  if (Def) +    return Def; + +  TrackUnresolvedResolver R; +  for (Init *Arg : args()) +    Arg->resolveReferences(R); + +  if (!R.foundUnresolved()) +    return const_cast<VarDefInit *>(this)->instantiate(); +  return const_cast<VarDefInit *>(this); +} + +std::string VarDefInit::getAsString() const { +  std::string Result = Class->getNameInitAsString() + "<"; +  const char *sep = ""; +  for (Init *Arg : args()) { +    Result += sep; +    sep = ", "; +    Result += Arg->getAsString(); +  } +  return Result + ">"; +} + +FieldInit *FieldInit::get(Init *R, StringInit *FN) { +  using Key = std::pair<Init *, StringInit *>; +  static DenseMap<Key, FieldInit*> ThePool; + +  Key TheKey(std::make_pair(R, FN)); + +  FieldInit *&I = ThePool[TheKey]; +  if (!I) I = new(Allocator) FieldInit(R, FN); +  return I; +} + +Init *FieldInit::getBit(unsigned Bit) const { +  if (getType() == BitRecTy::get()) +    return const_cast<FieldInit*>(this); +  return VarBitInit::get(const_cast<FieldInit*>(this), Bit); +} + +Init *FieldInit::resolveReferences(Resolver &R) const { +  Init *NewRec = Rec->resolveReferences(R); +  if (NewRec != Rec) +    return FieldInit::get(NewRec, FieldName)->Fold(R.getCurrentRecord()); +  return const_cast<FieldInit *>(this); +} + +Init *FieldInit::Fold(Record *CurRec) const { +  if (DefInit *DI = dyn_cast<DefInit>(Rec)) { +    Record *Def = DI->getDef(); +    if (Def == CurRec) +      PrintFatalError(CurRec->getLoc(), +                      Twine("Attempting to access field '") + +                      FieldName->getAsUnquotedString() + "' of '" + +                      Rec->getAsString() + "' is a forbidden self-reference"); +    Init *FieldVal = Def->getValue(FieldName)->getValue(); +    if (FieldVal->isComplete()) +      return FieldVal; +  } +  return const_cast<FieldInit *>(this); +} + +static void ProfileCondOpInit(FoldingSetNodeID &ID, +                             ArrayRef<Init *> CondRange, +                             ArrayRef<Init *> ValRange, +                             const RecTy *ValType) { +  assert(CondRange.size() == ValRange.size() && +         "Number of conditions and values must match!"); +  ID.AddPointer(ValType); +  ArrayRef<Init *>::iterator Case = CondRange.begin(); +  ArrayRef<Init *>::iterator Val = ValRange.begin(); + +  while (Case != CondRange.end()) { +    ID.AddPointer(*Case++); +    ID.AddPointer(*Val++); +  } +} + +void CondOpInit::Profile(FoldingSetNodeID &ID) const { +  ProfileCondOpInit(ID, +      makeArrayRef(getTrailingObjects<Init *>(), NumConds), +      makeArrayRef(getTrailingObjects<Init *>() + NumConds, NumConds), +      ValType); +} + +CondOpInit * +CondOpInit::get(ArrayRef<Init *> CondRange, +                ArrayRef<Init *> ValRange, RecTy *Ty) { +  assert(CondRange.size() == ValRange.size() && +         "Number of conditions and values must match!"); + +  static FoldingSet<CondOpInit> ThePool; +  FoldingSetNodeID ID; +  ProfileCondOpInit(ID, CondRange, ValRange, Ty); + +  void *IP = nullptr; +  if (CondOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(2*CondRange.size()), +                                 alignof(BitsInit)); +  CondOpInit *I = new(Mem) CondOpInit(CondRange.size(), Ty); + +  std::uninitialized_copy(CondRange.begin(), CondRange.end(), +                          I->getTrailingObjects<Init *>()); +  std::uninitialized_copy(ValRange.begin(), ValRange.end(), +                          I->getTrailingObjects<Init *>()+CondRange.size()); +  ThePool.InsertNode(I, IP); +  return I; +} + +Init *CondOpInit::resolveReferences(Resolver &R) const { +  SmallVector<Init*, 4> NewConds; +  bool Changed = false; +  for (const Init *Case : getConds()) { +    Init *NewCase = Case->resolveReferences(R); +    NewConds.push_back(NewCase); +    Changed |= NewCase != Case; +  } + +  SmallVector<Init*, 4> NewVals; +  for (const Init *Val : getVals()) { +    Init *NewVal = Val->resolveReferences(R); +    NewVals.push_back(NewVal); +    Changed |= NewVal != Val; +  } + +  if (Changed) +    return (CondOpInit::get(NewConds, NewVals, +            getValType()))->Fold(R.getCurrentRecord()); + +  return const_cast<CondOpInit *>(this); +} + +Init *CondOpInit::Fold(Record *CurRec) const { +  for ( unsigned i = 0; i < NumConds; ++i) { +    Init *Cond = getCond(i); +    Init *Val = getVal(i); + +    if (IntInit *CondI = dyn_cast_or_null<IntInit>( +            Cond->convertInitializerTo(IntRecTy::get()))) { +      if (CondI->getValue()) +        return Val->convertInitializerTo(getValType()); +    } else +     return const_cast<CondOpInit *>(this); +  } + +  PrintFatalError(CurRec->getLoc(), +                  CurRec->getName() + +                  " does not have any true condition in:" + +                  this->getAsString()); +  return nullptr; +} + +bool CondOpInit::isConcrete() const { +  for (const Init *Case : getConds()) +    if (!Case->isConcrete()) +      return false; + +  for (const Init *Val : getVals()) +    if (!Val->isConcrete()) +      return false; + +  return true; +} + +bool CondOpInit::isComplete() const { +  for (const Init *Case : getConds()) +    if (!Case->isComplete()) +      return false; + +  for (const Init *Val : getVals()) +    if (!Val->isConcrete()) +      return false; + +  return true; +} + +std::string CondOpInit::getAsString() const { +  std::string Result = "!cond("; +  for (unsigned i = 0; i < getNumConds(); i++) { +    Result += getCond(i)->getAsString() + ": "; +    Result += getVal(i)->getAsString(); +    if (i != getNumConds()-1) +      Result += ", "; +  } +  return Result + ")"; +} + +Init *CondOpInit::getBit(unsigned Bit) const { +  return VarBitInit::get(const_cast<CondOpInit *>(this), Bit); +} + +static void ProfileDagInit(FoldingSetNodeID &ID, Init *V, StringInit *VN, +                           ArrayRef<Init *> ArgRange, +                           ArrayRef<StringInit *> NameRange) { +  ID.AddPointer(V); +  ID.AddPointer(VN); + +  ArrayRef<Init *>::iterator Arg = ArgRange.begin(); +  ArrayRef<StringInit *>::iterator Name = NameRange.begin(); +  while (Arg != ArgRange.end()) { +    assert(Name != NameRange.end() && "Arg name underflow!"); +    ID.AddPointer(*Arg++); +    ID.AddPointer(*Name++); +  } +  assert(Name == NameRange.end() && "Arg name overflow!"); +} + +DagInit * +DagInit::get(Init *V, StringInit *VN, ArrayRef<Init *> ArgRange, +             ArrayRef<StringInit *> NameRange) { +  static FoldingSet<DagInit> ThePool; + +  FoldingSetNodeID ID; +  ProfileDagInit(ID, V, VN, ArgRange, NameRange); + +  void *IP = nullptr; +  if (DagInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) +    return I; + +  void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *, StringInit *>(ArgRange.size(), NameRange.size()), alignof(BitsInit)); +  DagInit *I = new(Mem) DagInit(V, VN, ArgRange.size(), NameRange.size()); +  std::uninitialized_copy(ArgRange.begin(), ArgRange.end(), +                          I->getTrailingObjects<Init *>()); +  std::uninitialized_copy(NameRange.begin(), NameRange.end(), +                          I->getTrailingObjects<StringInit *>()); +  ThePool.InsertNode(I, IP); +  return I; +} + +DagInit * +DagInit::get(Init *V, StringInit *VN, +             ArrayRef<std::pair<Init*, StringInit*>> args) { +  SmallVector<Init *, 8> Args; +  SmallVector<StringInit *, 8> Names; + +  for (const auto &Arg : args) { +    Args.push_back(Arg.first); +    Names.push_back(Arg.second); +  } + +  return DagInit::get(V, VN, Args, Names); +} + +void DagInit::Profile(FoldingSetNodeID &ID) const { +  ProfileDagInit(ID, Val, ValName, makeArrayRef(getTrailingObjects<Init *>(), NumArgs), makeArrayRef(getTrailingObjects<StringInit *>(), NumArgNames)); +} + +Record *DagInit::getOperatorAsDef(ArrayRef<SMLoc> Loc) const { +  if (DefInit *DefI = dyn_cast<DefInit>(Val)) +    return DefI->getDef(); +  PrintFatalError(Loc, "Expected record as operator"); +  return nullptr; +} + +Init *DagInit::resolveReferences(Resolver &R) const { +  SmallVector<Init*, 8> NewArgs; +  NewArgs.reserve(arg_size()); +  bool ArgsChanged = false; +  for (const Init *Arg : getArgs()) { +    Init *NewArg = Arg->resolveReferences(R); +    NewArgs.push_back(NewArg); +    ArgsChanged |= NewArg != Arg; +  } + +  Init *Op = Val->resolveReferences(R); +  if (Op != Val || ArgsChanged) +    return DagInit::get(Op, ValName, NewArgs, getArgNames()); + +  return const_cast<DagInit *>(this); +} + +bool DagInit::isConcrete() const { +  if (!Val->isConcrete()) +    return false; +  for (const Init *Elt : getArgs()) { +    if (!Elt->isConcrete()) +      return false; +  } +  return true; +} + +std::string DagInit::getAsString() const { +  std::string Result = "(" + Val->getAsString(); +  if (ValName) +    Result += ":" + ValName->getAsUnquotedString(); +  if (!arg_empty()) { +    Result += " " + getArg(0)->getAsString(); +    if (getArgName(0)) Result += ":$" + getArgName(0)->getAsUnquotedString(); +    for (unsigned i = 1, e = getNumArgs(); i != e; ++i) { +      Result += ", " + getArg(i)->getAsString(); +      if (getArgName(i)) Result += ":$" + getArgName(i)->getAsUnquotedString(); +    } +  } +  return Result + ")"; +} + +//===----------------------------------------------------------------------===// +//    Other implementations +//===----------------------------------------------------------------------===// + +RecordVal::RecordVal(Init *N, RecTy *T, bool P) +  : Name(N), TyAndPrefix(T, P) { +  setValue(UnsetInit::get()); +  assert(Value && "Cannot create unset value for current type!"); +} + +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 + +void RecordVal::print(raw_ostream &OS, bool PrintSem) const { +  if (getPrefix()) OS << "field "; +  OS << *getType() << " " << getNameInitAsString(); + +  if (getValue()) +    OS << " = " << *getValue(); + +  if (PrintSem) OS << ";\n"; +} + +unsigned Record::LastID = 0; + +void Record::checkName() { +  // Ensure the record name has string type. +  const TypedInit *TypedName = cast<const TypedInit>(Name); +  if (!isa<StringRecTy>(TypedName->getType())) +    PrintFatalError(getLoc(), Twine("Record name '") + Name->getAsString() + +                                  "' is not a string!"); +} + +RecordRecTy *Record::getType() { +  SmallVector<Record *, 4> DirectSCs; +  getDirectSuperClasses(DirectSCs); +  return RecordRecTy::get(DirectSCs); +} + +DefInit *Record::getDefInit() { +  if (!TheInit) +    TheInit = new(Allocator) DefInit(this); +  return TheInit; +} + +void Record::setName(Init *NewName) { +  Name = NewName; +  checkName(); +  // DO NOT resolve record values to the name at this point because +  // there might be default values for arguments of this def.  Those +  // arguments might not have been resolved yet so we don't want to +  // prematurely assume values for those arguments were not passed to +  // this def. +  // +  // Nonetheless, it may be that some of this Record's values +  // reference the record name.  Indeed, the reason for having the +  // record name be an Init is to provide this flexibility.  The extra +  // resolve steps after completely instantiating defs takes care of +  // this.  See TGParser::ParseDef and TGParser::ParseDefm. +} + +void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const { +  ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses(); +  while (!SCs.empty()) { +    // Superclasses are in reverse preorder, so 'back' is a direct superclass, +    // and its transitive superclasses are directly preceding it. +    Record *SC = SCs.back().first; +    SCs = SCs.drop_back(1 + SC->getSuperClasses().size()); +    Classes.push_back(SC); +  } +} + +void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) { +  for (RecordVal &Value : Values) { +    if (SkipVal == &Value) // Skip resolve the same field as the given one +      continue; +    if (Init *V = Value.getValue()) { +      Init *VR = V->resolveReferences(R); +      if (Value.setValue(VR)) { +        std::string Type; +        if (TypedInit *VRT = dyn_cast<TypedInit>(VR)) +          Type = +              (Twine("of type '") + VRT->getType()->getAsString() + "' ").str(); +        PrintFatalError(getLoc(), Twine("Invalid value ") + Type + +                                      "is found when setting '" + +                                      Value.getNameInitAsString() + +                                      "' of type '" + +                                      Value.getType()->getAsString() + +                                      "' after resolving references: " + +                                      VR->getAsUnquotedString() + "\n"); +      } +    } +  } +  Init *OldName = getNameInit(); +  Init *NewName = Name->resolveReferences(R); +  if (NewName != OldName) { +    // Re-register with RecordKeeper. +    setName(NewName); +  } +} + +void Record::resolveReferences() { +  RecordResolver R(*this); +  R.setFinal(true); +  resolveReferences(R); +} + +void Record::resolveReferencesTo(const RecordVal *RV) { +  RecordValResolver R(*this, RV); +  resolveReferences(R, RV); +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void Record::dump() const { errs() << *this; } +#endif + +raw_ostream &llvm::operator<<(raw_ostream &OS, const Record &R) { +  OS << R.getNameInitAsString(); + +  ArrayRef<Init *> TArgs = R.getTemplateArgs(); +  if (!TArgs.empty()) { +    OS << "<"; +    bool NeedComma = false; +    for (const Init *TA : TArgs) { +      if (NeedComma) OS << ", "; +      NeedComma = true; +      const RecordVal *RV = R.getValue(TA); +      assert(RV && "Template argument record not found??"); +      RV->print(OS, false); +    } +    OS << ">"; +  } + +  OS << " {"; +  ArrayRef<std::pair<Record *, SMRange>> SC = R.getSuperClasses(); +  if (!SC.empty()) { +    OS << "\t//"; +    for (const auto &SuperPair : SC) +      OS << " " << SuperPair.first->getNameInitAsString(); +  } +  OS << "\n"; + +  for (const RecordVal &Val : R.getValues()) +    if (Val.getPrefix() && !R.isTemplateArg(Val.getNameInit())) +      OS << Val; +  for (const RecordVal &Val : R.getValues()) +    if (!Val.getPrefix() && !R.isTemplateArg(Val.getNameInit())) +      OS << Val; + +  return OS << "}\n"; +} + +Init *Record::getValueInit(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); +  return R->getValue(); +} + +StringRef Record::getValueAsString(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (StringInit *SI = dyn_cast<StringInit>(R->getValue())) +    return SI->getValue(); +  if (CodeInit *CI = dyn_cast<CodeInit>(R->getValue())) +    return CI->getValue(); + +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a string initializer!"); +} + +BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (BitsInit *BI = dyn_cast<BitsInit>(R->getValue())) +    return BI; +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a BitsInit initializer!"); +} + +ListInit *Record::getValueAsListInit(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (ListInit *LI = dyn_cast<ListInit>(R->getValue())) +    return LI; +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a list initializer!"); +} + +std::vector<Record*> +Record::getValueAsListOfDefs(StringRef FieldName) const { +  ListInit *List = getValueAsListInit(FieldName); +  std::vector<Record*> Defs; +  for (Init *I : List->getValues()) { +    if (DefInit *DI = dyn_cast<DefInit>(I)) +      Defs.push_back(DI->getDef()); +    else +      PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +        FieldName + "' list is not entirely DefInit!"); +  } +  return Defs; +} + +int64_t Record::getValueAsInt(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (IntInit *II = dyn_cast<IntInit>(R->getValue())) +    return II->getValue(); +  PrintFatalError(getLoc(), Twine("Record `") + getName() + "', field `" + +                                FieldName + +                                "' does not have an int initializer: " + +                                R->getValue()->getAsString()); +} + +std::vector<int64_t> +Record::getValueAsListOfInts(StringRef FieldName) const { +  ListInit *List = getValueAsListInit(FieldName); +  std::vector<int64_t> Ints; +  for (Init *I : List->getValues()) { +    if (IntInit *II = dyn_cast<IntInit>(I)) +      Ints.push_back(II->getValue()); +    else +      PrintFatalError(getLoc(), +                      Twine("Record `") + getName() + "', field `" + FieldName + +                          "' does not have a list of ints initializer: " + +                          I->getAsString()); +  } +  return Ints; +} + +std::vector<StringRef> +Record::getValueAsListOfStrings(StringRef FieldName) const { +  ListInit *List = getValueAsListInit(FieldName); +  std::vector<StringRef> Strings; +  for (Init *I : List->getValues()) { +    if (StringInit *SI = dyn_cast<StringInit>(I)) +      Strings.push_back(SI->getValue()); +    else +      PrintFatalError(getLoc(), +                      Twine("Record `") + getName() + "', field `" + FieldName + +                          "' does not have a list of strings initializer: " + +                          I->getAsString()); +  } +  return Strings; +} + +Record *Record::getValueAsDef(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (DefInit *DI = dyn_cast<DefInit>(R->getValue())) +    return DI->getDef(); +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a def initializer!"); +} + +bool Record::getValueAsBit(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (BitInit *BI = dyn_cast<BitInit>(R->getValue())) +    return BI->getValue(); +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a bit initializer!"); +} + +bool Record::getValueAsBitOrUnset(StringRef FieldName, bool &Unset) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName.str() + "'!\n"); + +  if (isa<UnsetInit>(R->getValue())) { +    Unset = true; +    return false; +  } +  Unset = false; +  if (BitInit *BI = dyn_cast<BitInit>(R->getValue())) +    return BI->getValue(); +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a bit initializer!"); +} + +DagInit *Record::getValueAsDag(StringRef FieldName) const { +  const RecordVal *R = getValue(FieldName); +  if (!R || !R->getValue()) +    PrintFatalError(getLoc(), "Record `" + getName() + +      "' does not have a field named `" + FieldName + "'!\n"); + +  if (DagInit *DI = dyn_cast<DagInit>(R->getValue())) +    return DI; +  PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + +    FieldName + "' does not have a dag initializer!"); +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void RecordKeeper::dump() const { errs() << *this; } +#endif + +raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) { +  OS << "------------- Classes -----------------\n"; +  for (const auto &C : RK.getClasses()) +    OS << "class " << *C.second; + +  OS << "------------- Defs -----------------\n"; +  for (const auto &D : RK.getDefs()) +    OS << "def " << *D.second; +  return OS; +} + +/// GetNewAnonymousName - Generate a unique anonymous name that can be used as +/// an identifier. +Init *RecordKeeper::getNewAnonymousName() { +  return StringInit::get("anonymous_" + utostr(AnonCounter++)); +} + +std::vector<Record *> +RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const { +  Record *Class = getClass(ClassName); +  if (!Class) +    PrintFatalError("ERROR: Couldn't find the `" + ClassName + "' class!\n"); + +  std::vector<Record*> Defs; +  for (const auto &D : getDefs()) +    if (D.second->isSubClassOf(Class)) +      Defs.push_back(D.second.get()); + +  return Defs; +} + +Init *MapResolver::resolve(Init *VarName) { +  auto It = Map.find(VarName); +  if (It == Map.end()) +    return nullptr; + +  Init *I = It->second.V; + +  if (!It->second.Resolved && Map.size() > 1) { +    // Resolve mutual references among the mapped variables, but prevent +    // infinite recursion. +    Map.erase(It); +    I = I->resolveReferences(*this); +    Map[VarName] = {I, true}; +  } + +  return I; +} + +Init *RecordResolver::resolve(Init *VarName) { +  Init *Val = Cache.lookup(VarName); +  if (Val) +    return Val; + +  for (Init *S : Stack) { +    if (S == VarName) +      return nullptr; // prevent infinite recursion +  } + +  if (RecordVal *RV = getCurrentRecord()->getValue(VarName)) { +    if (!isa<UnsetInit>(RV->getValue())) { +      Val = RV->getValue(); +      Stack.push_back(VarName); +      Val = Val->resolveReferences(*this); +      Stack.pop_back(); +    } +  } + +  Cache[VarName] = Val; +  return Val; +} + +Init *TrackUnresolvedResolver::resolve(Init *VarName) { +  Init *I = nullptr; + +  if (R) { +    I = R->resolve(VarName); +    if (I && !FoundUnresolved) { +      // Do not recurse into the resolved initializer, as that would change +      // the behavior of the resolver we're delegating, but do check to see +      // if there are unresolved variables remaining. +      TrackUnresolvedResolver Sub; +      I->resolveReferences(Sub); +      FoundUnresolved |= Sub.FoundUnresolved; +    } +  } + +  if (!I) +    FoundUnresolved = true; +  return I; +} + +Init *HasReferenceResolver::resolve(Init *VarName) +{ +  if (VarName == VarNameToTrack) +    Found = true; +  return nullptr; +} diff --git a/llvm/lib/TableGen/SetTheory.cpp b/llvm/lib/TableGen/SetTheory.cpp new file mode 100644 index 000000000000..5a30ee98cce9 --- /dev/null +++ b/llvm/lib/TableGen/SetTheory.cpp @@ -0,0 +1,333 @@ +//===- SetTheory.cpp - Generate ordered sets from DAG expressions ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the SetTheory class that computes ordered sets of +// Records from DAG expressions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" +#include <algorithm> +#include <cstdint> +#include <string> +#include <utility> + +using namespace llvm; + +// Define the standard operators. +namespace { + +using RecSet = SetTheory::RecSet; +using RecVec = SetTheory::RecVec; + +// (add a, b, ...) Evaluate and union all arguments. +struct AddOp : public SetTheory::Operator { +  void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, +             ArrayRef<SMLoc> Loc) override { +    ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); +  } +}; + +// (sub Add, Sub, ...) Set difference. +struct SubOp : public SetTheory::Operator { +  void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, +             ArrayRef<SMLoc> Loc) override { +    if (Expr->arg_size() < 2) +      PrintFatalError(Loc, "Set difference needs at least two arguments: " + +        Expr->getAsString()); +    RecSet Add, Sub; +    ST.evaluate(*Expr->arg_begin(), Add, Loc); +    ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Sub, Loc); +    for (RecSet::iterator I = Add.begin(), E = Add.end(); I != E; ++I) +      if (!Sub.count(*I)) +        Elts.insert(*I); +  } +}; + +// (and S1, S2) Set intersection. +struct AndOp : public SetTheory::Operator { +  void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, +             ArrayRef<SMLoc> Loc) override { +    if (Expr->arg_size() != 2) +      PrintFatalError(Loc, "Set intersection requires two arguments: " + +        Expr->getAsString()); +    RecSet S1, S2; +    ST.evaluate(Expr->arg_begin()[0], S1, Loc); +    ST.evaluate(Expr->arg_begin()[1], S2, Loc); +    for (RecSet::iterator I = S1.begin(), E = S1.end(); I != E; ++I) +      if (S2.count(*I)) +        Elts.insert(*I); +  } +}; + +// SetIntBinOp - Abstract base class for (Op S, N) operators. +struct SetIntBinOp : public SetTheory::Operator { +  virtual void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, +                      RecSet &Elts, ArrayRef<SMLoc> Loc) = 0; + +  void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, +             ArrayRef<SMLoc> Loc) override { +    if (Expr->arg_size() != 2) +      PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " + +        Expr->getAsString()); +    RecSet Set; +    ST.evaluate(Expr->arg_begin()[0], Set, Loc); +    IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[1]); +    if (!II) +      PrintFatalError(Loc, "Second argument must be an integer: " + +        Expr->getAsString()); +    apply2(ST, Expr, Set, II->getValue(), Elts, Loc); +  } +}; + +// (shl S, N) Shift left, remove the first N elements. +struct ShlOp : public SetIntBinOp { +  void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, +              RecSet &Elts, ArrayRef<SMLoc> Loc) override { +    if (N < 0) +      PrintFatalError(Loc, "Positive shift required: " + +        Expr->getAsString()); +    if (unsigned(N) < Set.size()) +      Elts.insert(Set.begin() + N, Set.end()); +  } +}; + +// (trunc S, N) Truncate after the first N elements. +struct TruncOp : public SetIntBinOp { +  void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, +              RecSet &Elts, ArrayRef<SMLoc> Loc) override { +    if (N < 0) +      PrintFatalError(Loc, "Positive length required: " + +        Expr->getAsString()); +    if (unsigned(N) > Set.size()) +      N = Set.size(); +    Elts.insert(Set.begin(), Set.begin() + N); +  } +}; + +// Left/right rotation. +struct RotOp : public SetIntBinOp { +  const bool Reverse; + +  RotOp(bool Rev) : Reverse(Rev) {} + +  void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, +              RecSet &Elts, ArrayRef<SMLoc> Loc) override { +    if (Reverse) +      N = -N; +    // N > 0 -> rotate left, N < 0 -> rotate right. +    if (Set.empty()) +      return; +    if (N < 0) +      N = Set.size() - (-N % Set.size()); +    else +      N %= Set.size(); +    Elts.insert(Set.begin() + N, Set.end()); +    Elts.insert(Set.begin(), Set.begin() + N); +  } +}; + +// (decimate S, N) Pick every N'th element of S. +struct DecimateOp : public SetIntBinOp { +  void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N, +              RecSet &Elts, ArrayRef<SMLoc> Loc) override { +    if (N <= 0) +      PrintFatalError(Loc, "Positive stride required: " + +        Expr->getAsString()); +    for (unsigned I = 0; I < Set.size(); I += N) +      Elts.insert(Set[I]); +  } +}; + +// (interleave S1, S2, ...) Interleave elements of the arguments. +struct InterleaveOp : public SetTheory::Operator { +  void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, +             ArrayRef<SMLoc> Loc) override { +    // Evaluate the arguments individually. +    SmallVector<RecSet, 4> Args(Expr->getNumArgs()); +    unsigned MaxSize = 0; +    for (unsigned i = 0, e = Expr->getNumArgs(); i != e; ++i) { +      ST.evaluate(Expr->getArg(i), Args[i], Loc); +      MaxSize = std::max(MaxSize, unsigned(Args[i].size())); +    } +    // Interleave arguments into Elts. +    for (unsigned n = 0; n != MaxSize; ++n) +      for (unsigned i = 0, e = Expr->getNumArgs(); i != e; ++i) +        if (n < Args[i].size()) +          Elts.insert(Args[i][n]); +  } +}; + +// (sequence "Format", From, To) Generate a sequence of records by name. +struct SequenceOp : public SetTheory::Operator { +  void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, +             ArrayRef<SMLoc> Loc) override { +    int Step = 1; +    if (Expr->arg_size() > 4) +      PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " + +        Expr->getAsString()); +    else if (Expr->arg_size() == 4) { +      if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[3])) { +        Step = II->getValue(); +      } else +        PrintFatalError(Loc, "Stride must be an integer: " + +          Expr->getAsString()); +    } + +    std::string Format; +    if (StringInit *SI = dyn_cast<StringInit>(Expr->arg_begin()[0])) +      Format = SI->getValue(); +    else +      PrintFatalError(Loc,  "Format must be a string: " + Expr->getAsString()); + +    int64_t From, To; +    if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[1])) +      From = II->getValue(); +    else +      PrintFatalError(Loc, "From must be an integer: " + Expr->getAsString()); +    if (From < 0 || From >= (1 << 30)) +      PrintFatalError(Loc, "From out of range"); + +    if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[2])) +      To = II->getValue(); +    else +      PrintFatalError(Loc, "To must be an integer: " + Expr->getAsString()); +    if (To < 0 || To >= (1 << 30)) +      PrintFatalError(Loc, "To out of range"); + +    RecordKeeper &Records = +      cast<DefInit>(Expr->getOperator())->getDef()->getRecords(); + +    Step *= From <= To ? 1 : -1; +    while (true) { +      if (Step > 0 && From > To) +        break; +      else if (Step < 0 && From < To) +        break; +      std::string Name; +      raw_string_ostream OS(Name); +      OS << format(Format.c_str(), unsigned(From)); +      Record *Rec = Records.getDef(OS.str()); +      if (!Rec) +        PrintFatalError(Loc, "No def named '" + Name + "': " + +          Expr->getAsString()); +      // Try to reevaluate Rec in case it is a set. +      if (const RecVec *Result = ST.expand(Rec)) +        Elts.insert(Result->begin(), Result->end()); +      else +        Elts.insert(Rec); + +      From += Step; +    } +  } +}; + +// Expand a Def into a set by evaluating one of its fields. +struct FieldExpander : public SetTheory::Expander { +  StringRef FieldName; + +  FieldExpander(StringRef fn) : FieldName(fn) {} + +  void expand(SetTheory &ST, Record *Def, RecSet &Elts) override { +    ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc()); +  } +}; + +} // end anonymous namespace + +// Pin the vtables to this file. +void SetTheory::Operator::anchor() {} +void SetTheory::Expander::anchor() {} + +SetTheory::SetTheory() { +  addOperator("add", std::make_unique<AddOp>()); +  addOperator("sub", std::make_unique<SubOp>()); +  addOperator("and", std::make_unique<AndOp>()); +  addOperator("shl", std::make_unique<ShlOp>()); +  addOperator("trunc", std::make_unique<TruncOp>()); +  addOperator("rotl", std::make_unique<RotOp>(false)); +  addOperator("rotr", std::make_unique<RotOp>(true)); +  addOperator("decimate", std::make_unique<DecimateOp>()); +  addOperator("interleave", std::make_unique<InterleaveOp>()); +  addOperator("sequence", std::make_unique<SequenceOp>()); +} + +void SetTheory::addOperator(StringRef Name, std::unique_ptr<Operator> Op) { +  Operators[Name] = std::move(Op); +} + +void SetTheory::addExpander(StringRef ClassName, std::unique_ptr<Expander> E) { +  Expanders[ClassName] = std::move(E); +} + +void SetTheory::addFieldExpander(StringRef ClassName, StringRef FieldName) { +  addExpander(ClassName, std::make_unique<FieldExpander>(FieldName)); +} + +void SetTheory::evaluate(Init *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) { +  // A def in a list can be a just an element, or it may expand. +  if (DefInit *Def = dyn_cast<DefInit>(Expr)) { +    if (const RecVec *Result = expand(Def->getDef())) +      return Elts.insert(Result->begin(), Result->end()); +    Elts.insert(Def->getDef()); +    return; +  } + +  // Lists simply expand. +  if (ListInit *LI = dyn_cast<ListInit>(Expr)) +    return evaluate(LI->begin(), LI->end(), Elts, Loc); + +  // Anything else must be a DAG. +  DagInit *DagExpr = dyn_cast<DagInit>(Expr); +  if (!DagExpr) +    PrintFatalError(Loc, "Invalid set element: " + Expr->getAsString()); +  DefInit *OpInit = dyn_cast<DefInit>(DagExpr->getOperator()); +  if (!OpInit) +    PrintFatalError(Loc, "Bad set expression: " + Expr->getAsString()); +  auto I = Operators.find(OpInit->getDef()->getName()); +  if (I == Operators.end()) +    PrintFatalError(Loc, "Unknown set operator: " + Expr->getAsString()); +  I->second->apply(*this, DagExpr, Elts, Loc); +} + +const RecVec *SetTheory::expand(Record *Set) { +  // Check existing entries for Set and return early. +  ExpandMap::iterator I = Expansions.find(Set); +  if (I != Expansions.end()) +    return &I->second; + +  // This is the first time we see Set. Find a suitable expander. +  ArrayRef<std::pair<Record *, SMRange>> SC = Set->getSuperClasses(); +  for (const auto &SCPair : SC) { +    // Skip unnamed superclasses. +    if (!isa<StringInit>(SCPair.first->getNameInit())) +      continue; +    auto I = Expanders.find(SCPair.first->getName()); +    if (I != Expanders.end()) { +      // This breaks recursive definitions. +      RecVec &EltVec = Expansions[Set]; +      RecSet Elts; +      I->second->expand(*this, Set, Elts); +      EltVec.assign(Elts.begin(), Elts.end()); +      return &EltVec; +    } +  } + +  // Set is not expandable. +  return nullptr; +} diff --git a/llvm/lib/TableGen/StringMatcher.cpp b/llvm/lib/TableGen/StringMatcher.cpp new file mode 100644 index 000000000000..2fca068893f3 --- /dev/null +++ b/llvm/lib/TableGen/StringMatcher.cpp @@ -0,0 +1,156 @@ +//===- StringMatcher.cpp - Generate a matcher for input strings -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringMatcher class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <map> +#include <string> +#include <utility> +#include <vector> + +using namespace llvm; + +/// FindFirstNonCommonLetter - Find the first character in the keys of the +/// string pairs that is not shared across the whole set of strings.  All +/// strings are assumed to have the same length. +static unsigned +FindFirstNonCommonLetter(const std::vector<const +                              StringMatcher::StringPair*> &Matches) { +  assert(!Matches.empty()); +  for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) { +    // Check to see if letter i is the same across the set. +    char Letter = Matches[0]->first[i]; + +    for (unsigned str = 0, e = Matches.size(); str != e; ++str) +      if (Matches[str]->first[i] != Letter) +        return i; +  } + +  return Matches[0]->first.size(); +} + +/// EmitStringMatcherForChar - Given a set of strings that are known to be the +/// same length and whose characters leading up to CharNo are the same, emit +/// code to verify that CharNo and later are the same. +/// +/// \return - True if control can leave the emitted code fragment. +bool StringMatcher::EmitStringMatcherForChar( +    const std::vector<const StringPair *> &Matches, unsigned CharNo, +    unsigned IndentCount, bool IgnoreDuplicates) const { +  assert(!Matches.empty() && "Must have at least one string to match!"); +  std::string Indent(IndentCount * 2 + 4, ' '); + +  // If we have verified that the entire string matches, we're done: output the +  // matching code. +  if (CharNo == Matches[0]->first.size()) { +    if (Matches.size() > 1 && !IgnoreDuplicates) +      report_fatal_error("Had duplicate keys to match on"); + +    // If the to-execute code has \n's in it, indent each subsequent line. +    StringRef Code = Matches[0]->second; + +    std::pair<StringRef, StringRef> Split = Code.split('\n'); +    OS << Indent << Split.first << "\t // \"" << Matches[0]->first << "\"\n"; + +    Code = Split.second; +    while (!Code.empty()) { +      Split = Code.split('\n'); +      OS << Indent << Split.first << "\n"; +      Code = Split.second; +    } +    return false; +  } + +  // Bucket the matches by the character we are comparing. +  std::map<char, std::vector<const StringPair*>> MatchesByLetter; + +  for (unsigned i = 0, e = Matches.size(); i != e; ++i) +    MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]); + + +  // If we have exactly one bucket to match, see how many characters are common +  // across the whole set and match all of them at once. +  if (MatchesByLetter.size() == 1) { +    unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches); +    unsigned NumChars = FirstNonCommonLetter-CharNo; + +    // Emit code to break out if the prefix doesn't match. +    if (NumChars == 1) { +      // Do the comparison with if (Str[1] != 'f') +      // FIXME: Need to escape general characters. +      OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '" +      << Matches[0]->first[CharNo] << "')\n"; +      OS << Indent << "  break;\n"; +    } else { +      // Do the comparison with if memcmp(Str.data()+1, "foo", 3). +      // FIXME: Need to escape general strings. +      OS << Indent << "if (memcmp(" << StrVariableName << ".data()+" << CharNo +         << ", \"" << Matches[0]->first.substr(CharNo, NumChars) << "\", " +         << NumChars << ") != 0)\n"; +      OS << Indent << "  break;\n"; +    } + +    return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount, +                                    IgnoreDuplicates); +  } + +  // Otherwise, we have multiple possible things, emit a switch on the +  // character. +  OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n"; +  OS << Indent << "default: break;\n"; + +  for (std::map<char, std::vector<const StringPair*>>::iterator LI = +       MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) { +    // TODO: escape hard stuff (like \n) if we ever care about it. +    OS << Indent << "case '" << LI->first << "':\t // " +       << LI->second.size() << " string"; +    if (LI->second.size() != 1) OS << 's'; +    OS << " to match.\n"; +    if (EmitStringMatcherForChar(LI->second, CharNo + 1, IndentCount + 1, +                                 IgnoreDuplicates)) +      OS << Indent << "  break;\n"; +  } + +  OS << Indent << "}\n"; +  return true; +} + +/// Emit - Top level entry point. +/// +void StringMatcher::Emit(unsigned Indent, bool IgnoreDuplicates) const { +  // If nothing to match, just fall through. +  if (Matches.empty()) return; + +  // First level categorization: group strings by length. +  std::map<unsigned, std::vector<const StringPair*>> MatchesByLength; + +  for (unsigned i = 0, e = Matches.size(); i != e; ++i) +    MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]); + +  // Output a switch statement on length and categorize the elements within each +  // bin. +  OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n"; +  OS.indent(Indent*2+2) << "default: break;\n"; + +  for (std::map<unsigned, std::vector<const StringPair*>>::iterator LI = +       MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) { +    OS.indent(Indent*2+2) << "case " << LI->first << ":\t // " +       << LI->second.size() +       << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n"; +    if (EmitStringMatcherForChar(LI->second, 0, Indent, IgnoreDuplicates)) +      OS.indent(Indent*2+4) << "break;\n"; +  } + +  OS.indent(Indent*2+2) << "}\n"; +} diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp new file mode 100644 index 000000000000..da2286e41fe5 --- /dev/null +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -0,0 +1,1021 @@ +//===- TGLexer.cpp - Lexer for TableGen -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implement the Lexer for TableGen. +// +//===----------------------------------------------------------------------===// + +#include "TGLexer.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" // for strtoull()/strtoll() define +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/TableGen/Error.h" +#include <algorithm> +#include <cctype> +#include <cerrno> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> + +using namespace llvm; + +namespace { +// A list of supported preprocessing directives with their +// internal token kinds and names. +struct { +  tgtok::TokKind Kind; +  const char *Word; +} PreprocessorDirs[] = { +  { tgtok::Ifdef, "ifdef" }, +  { tgtok::Ifndef, "ifndef" }, +  { tgtok::Else, "else" }, +  { tgtok::Endif, "endif" }, +  { tgtok::Define, "define" } +}; +} // end anonymous namespace + +TGLexer::TGLexer(SourceMgr &SM, ArrayRef<std::string> Macros) : SrcMgr(SM) { +  CurBuffer = SrcMgr.getMainFileID(); +  CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(); +  CurPtr = CurBuf.begin(); +  TokStart = nullptr; + +  // Pretend that we enter the "top-level" include file. +  PrepIncludeStack.push_back( +      std::make_unique<std::vector<PreprocessorControlDesc>>()); + +  // Put all macros defined in the command line into the DefinedMacros set. +  std::for_each(Macros.begin(), Macros.end(), +                [this](const std::string &MacroName) { +                  DefinedMacros.insert(MacroName); +                }); +} + +SMLoc TGLexer::getLoc() const { +  return SMLoc::getFromPointer(TokStart); +} + +/// ReturnError - Set the error to the specified string at the specified +/// location.  This is defined to always return tgtok::Error. +tgtok::TokKind TGLexer::ReturnError(SMLoc Loc, const Twine &Msg) { +  PrintError(Loc, Msg); +  return tgtok::Error; +} + +tgtok::TokKind TGLexer::ReturnError(const char *Loc, const Twine &Msg) { +  return ReturnError(SMLoc::getFromPointer(Loc), Msg); +} + +bool TGLexer::processEOF() { +  SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); +  if (ParentIncludeLoc != SMLoc()) { +    // If prepExitInclude() detects a problem with the preprocessing +    // control stack, it will return false.  Pretend that we reached +    // the final EOF and stop lexing more tokens by returning false +    // to LexToken(). +    if (!prepExitInclude(false)) +      return false; + +    CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); +    CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(); +    CurPtr = ParentIncludeLoc.getPointer(); +    // Make sure TokStart points into the parent file's buffer. +    // LexToken() assigns to it before calling getNextChar(), +    // so it is pointing into the included file now. +    TokStart = CurPtr; +    return true; +  } + +  // Pretend that we exit the "top-level" include file. +  // Note that in case of an error (e.g. control stack imbalance) +  // the routine will issue a fatal error. +  prepExitInclude(true); +  return false; +} + +int TGLexer::getNextChar() { +  char CurChar = *CurPtr++; +  switch (CurChar) { +  default: +    return (unsigned char)CurChar; +  case 0: { +    // A nul character in the stream is either the end of the current buffer or +    // a random nul in the file.  Disambiguate that here. +    if (CurPtr-1 != CurBuf.end()) +      return 0;  // Just whitespace. + +    // Otherwise, return end of file. +    --CurPtr;  // Another call to lex will return EOF again. +    return EOF; +  } +  case '\n': +  case '\r': +    // Handle the newline character by ignoring it and incrementing the line +    // count.  However, be careful about 'dos style' files with \n\r in them. +    // Only treat a \n\r or \r\n as a single line. +    if ((*CurPtr == '\n' || (*CurPtr == '\r')) && +        *CurPtr != CurChar) +      ++CurPtr;  // Eat the two char newline sequence. +    return '\n'; +  } +} + +int TGLexer::peekNextChar(int Index) const { +  return *(CurPtr + Index); +} + +tgtok::TokKind TGLexer::LexToken(bool FileOrLineStart) { +  TokStart = CurPtr; +  // This always consumes at least one character. +  int CurChar = getNextChar(); + +  switch (CurChar) { +  default: +    // Handle letters: [a-zA-Z_] +    if (isalpha(CurChar) || CurChar == '_') +      return LexIdentifier(); + +    // Unknown character, emit an error. +    return ReturnError(TokStart, "Unexpected character"); +  case EOF: +    // Lex next token, if we just left an include file. +    // Note that leaving an include file means that the next +    // symbol is located at the end of 'include "..."' +    // construct, so LexToken() is called with default +    // false parameter. +    if (processEOF()) +      return LexToken(); + +    // Return EOF denoting the end of lexing. +    return tgtok::Eof; + +  case ':': return tgtok::colon; +  case ';': return tgtok::semi; +  case '.': return tgtok::period; +  case ',': return tgtok::comma; +  case '<': return tgtok::less; +  case '>': return tgtok::greater; +  case ']': return tgtok::r_square; +  case '{': return tgtok::l_brace; +  case '}': return tgtok::r_brace; +  case '(': return tgtok::l_paren; +  case ')': return tgtok::r_paren; +  case '=': return tgtok::equal; +  case '?': return tgtok::question; +  case '#': +    if (FileOrLineStart) { +      tgtok::TokKind Kind = prepIsDirective(); +      if (Kind != tgtok::Error) +        return lexPreprocessor(Kind); +    } + +    return tgtok::paste; + +  case '\r': +    PrintFatalError("getNextChar() must never return '\r'"); +    return tgtok::Error; + +  case 0: +  case ' ': +  case '\t': +    // Ignore whitespace. +    return LexToken(FileOrLineStart); +  case '\n': +    // Ignore whitespace, and identify the new line. +    return LexToken(true); +  case '/': +    // If this is the start of a // comment, skip until the end of the line or +    // the end of the buffer. +    if (*CurPtr == '/') +      SkipBCPLComment(); +    else if (*CurPtr == '*') { +      if (SkipCComment()) +        return tgtok::Error; +    } else // Otherwise, this is an error. +      return ReturnError(TokStart, "Unexpected character"); +    return LexToken(FileOrLineStart); +  case '-': case '+': +  case '0': case '1': case '2': case '3': case '4': case '5': case '6': +  case '7': case '8': case '9': { +    int NextChar = 0; +    if (isdigit(CurChar)) { +      // Allow identifiers to start with a number if it is followed by +      // an identifier.  This can happen with paste operations like +      // foo#8i. +      int i = 0; +      do { +        NextChar = peekNextChar(i++); +      } while (isdigit(NextChar)); + +      if (NextChar == 'x' || NextChar == 'b') { +        // If this is [0-9]b[01] or [0-9]x[0-9A-fa-f] this is most +        // likely a number. +        int NextNextChar = peekNextChar(i); +        switch (NextNextChar) { +        default: +          break; +        case '0': case '1': +          if (NextChar == 'b') +            return LexNumber(); +          LLVM_FALLTHROUGH; +        case '2': case '3': case '4': case '5': +        case '6': case '7': case '8': case '9': +        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': +        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': +          if (NextChar == 'x') +            return LexNumber(); +          break; +        } +      } +    } + +    if (isalpha(NextChar) || NextChar == '_') +      return LexIdentifier(); + +    return LexNumber(); +  } +  case '"': return LexString(); +  case '$': return LexVarName(); +  case '[': return LexBracket(); +  case '!': return LexExclaim(); +  } +} + +/// LexString - Lex "[^"]*" +tgtok::TokKind TGLexer::LexString() { +  const char *StrStart = CurPtr; + +  CurStrVal = ""; + +  while (*CurPtr != '"') { +    // If we hit the end of the buffer, report an error. +    if (*CurPtr == 0 && CurPtr == CurBuf.end()) +      return ReturnError(StrStart, "End of file in string literal"); + +    if (*CurPtr == '\n' || *CurPtr == '\r') +      return ReturnError(StrStart, "End of line in string literal"); + +    if (*CurPtr != '\\') { +      CurStrVal += *CurPtr++; +      continue; +    } + +    ++CurPtr; + +    switch (*CurPtr) { +    case '\\': case '\'': case '"': +      // These turn into their literal character. +      CurStrVal += *CurPtr++; +      break; +    case 't': +      CurStrVal += '\t'; +      ++CurPtr; +      break; +    case 'n': +      CurStrVal += '\n'; +      ++CurPtr; +      break; + +    case '\n': +    case '\r': +      return ReturnError(CurPtr, "escaped newlines not supported in tblgen"); + +    // If we hit the end of the buffer, report an error. +    case '\0': +      if (CurPtr == CurBuf.end()) +        return ReturnError(StrStart, "End of file in string literal"); +      LLVM_FALLTHROUGH; +    default: +      return ReturnError(CurPtr, "invalid escape in string literal"); +    } +  } + +  ++CurPtr; +  return tgtok::StrVal; +} + +tgtok::TokKind TGLexer::LexVarName() { +  if (!isalpha(CurPtr[0]) && CurPtr[0] != '_') +    return ReturnError(TokStart, "Invalid variable name"); + +  // Otherwise, we're ok, consume the rest of the characters. +  const char *VarNameStart = CurPtr++; + +  while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_') +    ++CurPtr; + +  CurStrVal.assign(VarNameStart, CurPtr); +  return tgtok::VarName; +} + +tgtok::TokKind TGLexer::LexIdentifier() { +  // The first letter is [a-zA-Z_]. +  const char *IdentStart = TokStart; + +  // Match the rest of the identifier regex: [0-9a-zA-Z_]* +  while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_') +    ++CurPtr; + +  // Check to see if this identifier is a keyword. +  StringRef Str(IdentStart, CurPtr-IdentStart); + +  if (Str == "include") { +    if (LexInclude()) return tgtok::Error; +    return Lex(); +  } + +  tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(Str) +    .Case("int", tgtok::Int) +    .Case("bit", tgtok::Bit) +    .Case("bits", tgtok::Bits) +    .Case("string", tgtok::String) +    .Case("list", tgtok::List) +    .Case("code", tgtok::Code) +    .Case("dag", tgtok::Dag) +    .Case("class", tgtok::Class) +    .Case("def", tgtok::Def) +    .Case("foreach", tgtok::Foreach) +    .Case("defm", tgtok::Defm) +    .Case("defset", tgtok::Defset) +    .Case("multiclass", tgtok::MultiClass) +    .Case("field", tgtok::Field) +    .Case("let", tgtok::Let) +    .Case("in", tgtok::In) +    .Default(tgtok::Id); + +  if (Kind == tgtok::Id) +    CurStrVal.assign(Str.begin(), Str.end()); +  return Kind; +} + +/// LexInclude - We just read the "include" token.  Get the string token that +/// comes next and enter the include. +bool TGLexer::LexInclude() { +  // The token after the include must be a string. +  tgtok::TokKind Tok = LexToken(); +  if (Tok == tgtok::Error) return true; +  if (Tok != tgtok::StrVal) { +    PrintError(getLoc(), "Expected filename after include"); +    return true; +  } + +  // Get the string. +  std::string Filename = CurStrVal; +  std::string IncludedFile; + +  CurBuffer = SrcMgr.AddIncludeFile(Filename, SMLoc::getFromPointer(CurPtr), +                                    IncludedFile); +  if (!CurBuffer) { +    PrintError(getLoc(), "Could not find include file '" + Filename + "'"); +    return true; +  } + +  DependenciesMapTy::const_iterator Found = Dependencies.find(IncludedFile); +  if (Found != Dependencies.end()) { +    PrintError(getLoc(), +               "File '" + IncludedFile + "' has already been included."); +    SrcMgr.PrintMessage(Found->second, SourceMgr::DK_Note, +                        "previously included here"); +    return true; +  } +  Dependencies.insert(std::make_pair(IncludedFile, getLoc())); +  // Save the line number and lex buffer of the includer. +  CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(); +  CurPtr = CurBuf.begin(); + +  PrepIncludeStack.push_back( +      std::make_unique<std::vector<PreprocessorControlDesc>>()); +  return false; +} + +void TGLexer::SkipBCPLComment() { +  ++CurPtr;  // skip the second slash. +  while (true) { +    switch (*CurPtr) { +    case '\n': +    case '\r': +      return;  // Newline is end of comment. +    case 0: +      // If this is the end of the buffer, end the comment. +      if (CurPtr == CurBuf.end()) +        return; +      break; +    } +    // Otherwise, skip the character. +    ++CurPtr; +  } +} + +/// SkipCComment - This skips C-style /**/ comments.  The only difference from C +/// is that we allow nesting. +bool TGLexer::SkipCComment() { +  ++CurPtr;  // skip the star. +  unsigned CommentDepth = 1; + +  while (true) { +    int CurChar = getNextChar(); +    switch (CurChar) { +    case EOF: +      PrintError(TokStart, "Unterminated comment!"); +      return true; +    case '*': +      // End of the comment? +      if (CurPtr[0] != '/') break; + +      ++CurPtr;   // End the */. +      if (--CommentDepth == 0) +        return false; +      break; +    case '/': +      // Start of a nested comment? +      if (CurPtr[0] != '*') break; +      ++CurPtr; +      ++CommentDepth; +      break; +    } +  } +} + +/// LexNumber - Lex: +///    [-+]?[0-9]+ +///    0x[0-9a-fA-F]+ +///    0b[01]+ +tgtok::TokKind TGLexer::LexNumber() { +  if (CurPtr[-1] == '0') { +    if (CurPtr[0] == 'x') { +      ++CurPtr; +      const char *NumStart = CurPtr; +      while (isxdigit(CurPtr[0])) +        ++CurPtr; + +      // Requires at least one hex digit. +      if (CurPtr == NumStart) +        return ReturnError(TokStart, "Invalid hexadecimal number"); + +      errno = 0; +      CurIntVal = strtoll(NumStart, nullptr, 16); +      if (errno == EINVAL) +        return ReturnError(TokStart, "Invalid hexadecimal number"); +      if (errno == ERANGE) { +        errno = 0; +        CurIntVal = (int64_t)strtoull(NumStart, nullptr, 16); +        if (errno == EINVAL) +          return ReturnError(TokStart, "Invalid hexadecimal number"); +        if (errno == ERANGE) +          return ReturnError(TokStart, "Hexadecimal number out of range"); +      } +      return tgtok::IntVal; +    } else if (CurPtr[0] == 'b') { +      ++CurPtr; +      const char *NumStart = CurPtr; +      while (CurPtr[0] == '0' || CurPtr[0] == '1') +        ++CurPtr; + +      // Requires at least one binary digit. +      if (CurPtr == NumStart) +        return ReturnError(CurPtr-2, "Invalid binary number"); +      CurIntVal = strtoll(NumStart, nullptr, 2); +      return tgtok::BinaryIntVal; +    } +  } + +  // Check for a sign without a digit. +  if (!isdigit(CurPtr[0])) { +    if (CurPtr[-1] == '-') +      return tgtok::minus; +    else if (CurPtr[-1] == '+') +      return tgtok::plus; +  } + +  while (isdigit(CurPtr[0])) +    ++CurPtr; +  CurIntVal = strtoll(TokStart, nullptr, 10); +  return tgtok::IntVal; +} + +/// LexBracket - We just read '['.  If this is a code block, return it, +/// otherwise return the bracket.  Match: '[' and '[{ ( [^}]+ | }[^]] )* }]' +tgtok::TokKind TGLexer::LexBracket() { +  if (CurPtr[0] != '{') +    return tgtok::l_square; +  ++CurPtr; +  const char *CodeStart = CurPtr; +  while (true) { +    int Char = getNextChar(); +    if (Char == EOF) break; + +    if (Char != '}') continue; + +    Char = getNextChar(); +    if (Char == EOF) break; +    if (Char == ']') { +      CurStrVal.assign(CodeStart, CurPtr-2); +      return tgtok::CodeFragment; +    } +  } + +  return ReturnError(CodeStart-2, "Unterminated Code Block"); +} + +/// LexExclaim - Lex '!' and '![a-zA-Z]+'. +tgtok::TokKind TGLexer::LexExclaim() { +  if (!isalpha(*CurPtr)) +    return ReturnError(CurPtr - 1, "Invalid \"!operator\""); + +  const char *Start = CurPtr++; +  while (isalpha(*CurPtr)) +    ++CurPtr; + +  // Check to see which operator this is. +  tgtok::TokKind Kind = +    StringSwitch<tgtok::TokKind>(StringRef(Start, CurPtr - Start)) +    .Case("eq", tgtok::XEq) +    .Case("ne", tgtok::XNe) +    .Case("le", tgtok::XLe) +    .Case("lt", tgtok::XLt) +    .Case("ge", tgtok::XGe) +    .Case("gt", tgtok::XGt) +    .Case("if", tgtok::XIf) +    .Case("cond", tgtok::XCond) +    .Case("isa", tgtok::XIsA) +    .Case("head", tgtok::XHead) +    .Case("tail", tgtok::XTail) +    .Case("size", tgtok::XSize) +    .Case("con", tgtok::XConcat) +    .Case("dag", tgtok::XDag) +    .Case("add", tgtok::XADD) +    .Case("mul", tgtok::XMUL) +    .Case("and", tgtok::XAND) +    .Case("or", tgtok::XOR) +    .Case("shl", tgtok::XSHL) +    .Case("sra", tgtok::XSRA) +    .Case("srl", tgtok::XSRL) +    .Case("cast", tgtok::XCast) +    .Case("empty", tgtok::XEmpty) +    .Case("subst", tgtok::XSubst) +    .Case("foldl", tgtok::XFoldl) +    .Case("foreach", tgtok::XForEach) +    .Case("listconcat", tgtok::XListConcat) +    .Case("listsplat", tgtok::XListSplat) +    .Case("strconcat", tgtok::XStrConcat) +    .Default(tgtok::Error); + +  return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator"); +} + +bool TGLexer::prepExitInclude(bool IncludeStackMustBeEmpty) { +  // Report an error, if preprocessor control stack for the current +  // file is not empty. +  if (!PrepIncludeStack.back()->empty()) { +    prepReportPreprocessorStackError(); + +    return false; +  } + +  // Pop the preprocessing controls from the include stack. +  if (PrepIncludeStack.empty()) { +    PrintFatalError("Preprocessor include stack is empty"); +  } + +  PrepIncludeStack.pop_back(); + +  if (IncludeStackMustBeEmpty) { +    if (!PrepIncludeStack.empty()) +      PrintFatalError("Preprocessor include stack is not empty"); +  } else { +    if (PrepIncludeStack.empty()) +      PrintFatalError("Preprocessor include stack is empty"); +  } + +  return true; +} + +tgtok::TokKind TGLexer::prepIsDirective() const { +  for (unsigned ID = 0; ID < llvm::array_lengthof(PreprocessorDirs); ++ID) { +    int NextChar = *CurPtr; +    bool Match = true; +    unsigned I = 0; +    for (; I < strlen(PreprocessorDirs[ID].Word); ++I) { +      if (NextChar != PreprocessorDirs[ID].Word[I]) { +        Match = false; +        break; +      } + +      NextChar = peekNextChar(I + 1); +    } + +    // Check for whitespace after the directive.  If there is no whitespace, +    // then we do not recognize it as a preprocessing directive. +    if (Match) { +      tgtok::TokKind Kind = PreprocessorDirs[ID].Kind; + +      // New line and EOF may follow only #else/#endif.  It will be reported +      // as an error for #ifdef/#define after the call to prepLexMacroName(). +      if (NextChar == ' ' || NextChar == '\t' || NextChar == EOF || +          NextChar == '\n' || +          // It looks like TableGen does not support '\r' as the actual +          // carriage return, e.g. getNextChar() treats a single '\r' +          // as '\n'.  So we do the same here. +          NextChar == '\r') +        return Kind; + +      // Allow comments after some directives, e.g.: +      //     #else// OR #else/**/ +      //     #endif// OR #endif/**/ +      // +      // Note that we do allow comments after #ifdef/#define here, e.g. +      //     #ifdef/**/ AND #ifdef// +      //     #define/**/ AND #define// +      // +      // These cases will be reported as incorrect after calling +      // prepLexMacroName().  We could have supported C-style comments +      // after #ifdef/#define, but this would complicate the code +      // for little benefit. +      if (NextChar == '/') { +        NextChar = peekNextChar(I + 1); + +        if (NextChar == '*' || NextChar == '/') +          return Kind; + +        // Pretend that we do not recognize the directive. +      } +    } +  } + +  return tgtok::Error; +} + +bool TGLexer::prepEatPreprocessorDirective(tgtok::TokKind Kind) { +  TokStart = CurPtr; + +  for (unsigned ID = 0; ID < llvm::array_lengthof(PreprocessorDirs); ++ID) +    if (PreprocessorDirs[ID].Kind == Kind) { +      // Advance CurPtr to the end of the preprocessing word. +      CurPtr += strlen(PreprocessorDirs[ID].Word); +      return true; +    } + +  PrintFatalError("Unsupported preprocessing token in " +                  "prepEatPreprocessorDirective()"); +  return false; +} + +tgtok::TokKind TGLexer::lexPreprocessor( +    tgtok::TokKind Kind, bool ReturnNextLiveToken) { + +  // We must be looking at a preprocessing directive.  Eat it! +  if (!prepEatPreprocessorDirective(Kind)) +    PrintFatalError("lexPreprocessor() called for unknown " +                    "preprocessor directive"); + +  if (Kind == tgtok::Ifdef || Kind == tgtok::Ifndef) { +    StringRef MacroName = prepLexMacroName(); +    StringRef IfTokName = Kind == tgtok::Ifdef ? "#ifdef" : "#ifndef"; +    if (MacroName.empty()) +      return ReturnError(TokStart, "Expected macro name after " + IfTokName); + +    bool MacroIsDefined = DefinedMacros.count(MacroName) != 0; + +    // Canonicalize ifndef to ifdef equivalent +    if (Kind == tgtok::Ifndef) { +      MacroIsDefined = !MacroIsDefined; +      Kind = tgtok::Ifdef; +    } + +    // Regardless of whether we are processing tokens or not, +    // we put the #ifdef control on stack. +    PrepIncludeStack.back()->push_back( +        {Kind, MacroIsDefined, SMLoc::getFromPointer(TokStart)}); + +    if (!prepSkipDirectiveEnd()) +      return ReturnError(CurPtr, "Only comments are supported after " + +                                     IfTokName + " NAME"); + +    // If we were not processing tokens before this #ifdef, +    // then just return back to the lines skipping code. +    if (!ReturnNextLiveToken) +      return Kind; + +    // If we were processing tokens before this #ifdef, +    // and the macro is defined, then just return the next token. +    if (MacroIsDefined) +      return LexToken(); + +    // We were processing tokens before this #ifdef, and the macro +    // is not defined, so we have to start skipping the lines. +    // If the skipping is successful, it will return the token following +    // either #else or #endif corresponding to this #ifdef. +    if (prepSkipRegion(ReturnNextLiveToken)) +      return LexToken(); + +    return tgtok::Error; +  } else if (Kind == tgtok::Else) { +    // Check if this #else is correct before calling prepSkipDirectiveEnd(), +    // which will move CurPtr away from the beginning of #else. +    if (PrepIncludeStack.back()->empty()) +      return ReturnError(TokStart, "#else without #ifdef or #ifndef"); + +    PreprocessorControlDesc IfdefEntry = PrepIncludeStack.back()->back(); + +    if (IfdefEntry.Kind != tgtok::Ifdef) { +      PrintError(TokStart, "double #else"); +      return ReturnError(IfdefEntry.SrcPos, "Previous #else is here"); +    } + +    // Replace the corresponding #ifdef's control with its negation +    // on the control stack. +    PrepIncludeStack.back()->pop_back(); +    PrepIncludeStack.back()->push_back( +        {Kind, !IfdefEntry.IsDefined, SMLoc::getFromPointer(TokStart)}); + +    if (!prepSkipDirectiveEnd()) +      return ReturnError(CurPtr, "Only comments are supported after #else"); + +    // If we were processing tokens before this #else, +    // we have to start skipping lines until the matching #endif. +    if (ReturnNextLiveToken) { +      if (prepSkipRegion(ReturnNextLiveToken)) +        return LexToken(); + +      return tgtok::Error; +    } + +    // Return to the lines skipping code. +    return Kind; +  } else if (Kind == tgtok::Endif) { +    // Check if this #endif is correct before calling prepSkipDirectiveEnd(), +    // which will move CurPtr away from the beginning of #endif. +    if (PrepIncludeStack.back()->empty()) +      return ReturnError(TokStart, "#endif without #ifdef"); + +    auto &IfdefOrElseEntry = PrepIncludeStack.back()->back(); + +    if (IfdefOrElseEntry.Kind != tgtok::Ifdef && +        IfdefOrElseEntry.Kind != tgtok::Else) { +      PrintFatalError("Invalid preprocessor control on the stack"); +      return tgtok::Error; +    } + +    if (!prepSkipDirectiveEnd()) +      return ReturnError(CurPtr, "Only comments are supported after #endif"); + +    PrepIncludeStack.back()->pop_back(); + +    // If we were processing tokens before this #endif, then +    // we should continue it. +    if (ReturnNextLiveToken) { +      return LexToken(); +    } + +    // Return to the lines skipping code. +    return Kind; +  } else if (Kind == tgtok::Define) { +    StringRef MacroName = prepLexMacroName(); +    if (MacroName.empty()) +      return ReturnError(TokStart, "Expected macro name after #define"); + +    if (!DefinedMacros.insert(MacroName).second) +      PrintWarning(getLoc(), +                   "Duplicate definition of macro: " + Twine(MacroName)); + +    if (!prepSkipDirectiveEnd()) +      return ReturnError(CurPtr, +                         "Only comments are supported after #define NAME"); + +    if (!ReturnNextLiveToken) { +      PrintFatalError("#define must be ignored during the lines skipping"); +      return tgtok::Error; +    } + +    return LexToken(); +  } + +  PrintFatalError("Preprocessing directive is not supported"); +  return tgtok::Error; +} + +bool TGLexer::prepSkipRegion(bool MustNeverBeFalse) { +  if (!MustNeverBeFalse) +    PrintFatalError("Invalid recursion."); + +  do { +    // Skip all symbols to the line end. +    prepSkipToLineEnd(); + +    // Find the first non-whitespace symbol in the next line(s). +    if (!prepSkipLineBegin()) +      return false; + +    // If the first non-blank/comment symbol on the line is '#', +    // it may be a start of preprocessing directive. +    // +    // If it is not '#' just go to the next line. +    if (*CurPtr == '#') +      ++CurPtr; +    else +      continue; + +    tgtok::TokKind Kind = prepIsDirective(); + +    // If we did not find a preprocessing directive or it is #define, +    // then just skip to the next line.  We do not have to do anything +    // for #define in the line-skipping mode. +    if (Kind == tgtok::Error || Kind == tgtok::Define) +      continue; + +    tgtok::TokKind ProcessedKind = lexPreprocessor(Kind, false); + +    // If lexPreprocessor() encountered an error during lexing this +    // preprocessor idiom, then return false to the calling lexPreprocessor(). +    // This will force tgtok::Error to be returned to the tokens processing. +    if (ProcessedKind == tgtok::Error) +      return false; + +    if (Kind != ProcessedKind) +      PrintFatalError("prepIsDirective() and lexPreprocessor() " +                      "returned different token kinds"); + +    // If this preprocessing directive enables tokens processing, +    // then return to the lexPreprocessor() and get to the next token. +    // We can move from line-skipping mode to processing tokens only +    // due to #else or #endif. +    if (prepIsProcessingEnabled()) { +      if (Kind != tgtok::Else && Kind != tgtok::Endif) { +        PrintFatalError("Tokens processing was enabled by an unexpected " +                        "preprocessing directive"); +        return false; +      } + +      return true; +    } +  } while (CurPtr != CurBuf.end()); + +  // We have reached the end of the file, but never left the lines-skipping +  // mode.  This means there is no matching #endif. +  prepReportPreprocessorStackError(); +  return false; +} + +StringRef TGLexer::prepLexMacroName() { +  // Skip whitespaces between the preprocessing directive and the macro name. +  while (*CurPtr == ' ' || *CurPtr == '\t') +    ++CurPtr; + +  TokStart = CurPtr; +  // Macro names start with [a-zA-Z_]. +  if (*CurPtr != '_' && !isalpha(*CurPtr)) +    return ""; + +  // Match the rest of the identifier regex: [0-9a-zA-Z_]* +  while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_') +    ++CurPtr; + +  return StringRef(TokStart, CurPtr - TokStart); +} + +bool TGLexer::prepSkipLineBegin() { +  while (CurPtr != CurBuf.end()) { +    switch (*CurPtr) { +    case ' ': +    case '\t': +    case '\n': +    case '\r': +      break; + +    case '/': { +      int NextChar = peekNextChar(1); +      if (NextChar == '*') { +        // Skip C-style comment. +        // Note that we do not care about skipping the C++-style comments. +        // If the line contains "//", it may not contain any processable +        // preprocessing directive.  Just return CurPtr pointing to +        // the first '/' in this case.  We also do not care about +        // incorrect symbols after the first '/' - we are in lines-skipping +        // mode, so incorrect code is allowed to some extent. + +        // Set TokStart to the beginning of the comment to enable proper +        // diagnostic printing in case of error in SkipCComment(). +        TokStart = CurPtr; + +        // CurPtr must point to '*' before call to SkipCComment(). +        ++CurPtr; +        if (SkipCComment()) +          return false; +      } else { +        // CurPtr points to the non-whitespace '/'. +        return true; +      } + +      // We must not increment CurPtr after the comment was lexed. +      continue; +    } + +    default: +      return true; +    } + +    ++CurPtr; +  } + +  // We have reached the end of the file.  Return to the lines skipping +  // code, and allow it to handle the EOF as needed. +  return true; +} + +bool TGLexer::prepSkipDirectiveEnd() { +  while (CurPtr != CurBuf.end()) { +    switch (*CurPtr) { +    case ' ': +    case '\t': +      break; + +    case '\n': +    case '\r': +      return true; + +    case '/': { +      int NextChar = peekNextChar(1); +      if (NextChar == '/') { +        // Skip C++-style comment. +        // We may just return true now, but let's skip to the line/buffer end +        // to simplify the method specification. +        ++CurPtr; +        SkipBCPLComment(); +      } else if (NextChar == '*') { +        // When we are skipping C-style comment at the end of a preprocessing +        // directive, we can skip several lines.  If any meaningful TD token +        // follows the end of the C-style comment on the same line, it will +        // be considered as an invalid usage of TD token. +        // For example, we want to forbid usages like this one: +        //     #define MACRO class Class {} +        // But with C-style comments we also disallow the following: +        //     #define MACRO /* This macro is used +        //                      to ... */ class Class {} +        // One can argue that this should be allowed, but it does not seem +        // to be worth of the complication.  Moreover, this matches +        // the C preprocessor behavior. + +        // Set TokStart to the beginning of the comment to enable proper +        // diagnostic printer in case of error in SkipCComment(). +        TokStart = CurPtr; +        ++CurPtr; +        if (SkipCComment()) +          return false; +      } else { +        TokStart = CurPtr; +        PrintError(CurPtr, "Unexpected character"); +        return false; +      } + +      // We must not increment CurPtr after the comment was lexed. +      continue; +    } + +    default: +      // Do not allow any non-whitespaces after the directive. +      TokStart = CurPtr; +      return false; +    } + +    ++CurPtr; +  } + +  return true; +} + +void TGLexer::prepSkipToLineEnd() { +  while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) +    ++CurPtr; +} + +bool TGLexer::prepIsProcessingEnabled() { +  for (auto I = PrepIncludeStack.back()->rbegin(), +            E = PrepIncludeStack.back()->rend(); +       I != E; ++I) { +    if (!I->IsDefined) +      return false; +  } + +  return true; +} + +void TGLexer::prepReportPreprocessorStackError() { +  if (PrepIncludeStack.back()->empty()) +    PrintFatalError("prepReportPreprocessorStackError() called with " +                    "empty control stack"); + +  auto &PrepControl = PrepIncludeStack.back()->back(); +  PrintError(CurBuf.end(), "Reached EOF without matching #endif"); +  PrintError(PrepControl.SrcPos, "The latest preprocessor control is here"); + +  TokStart = CurPtr; +} diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h new file mode 100644 index 000000000000..3085ab2c0478 --- /dev/null +++ b/llvm/lib/TableGen/TGLexer.h @@ -0,0 +1,373 @@ +//===- TGLexer.h - Lexer for TableGen Files ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This class represents the Lexer for tablegen files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TABLEGEN_TGLEXER_H +#define LLVM_LIB_TABLEGEN_TGLEXER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/SMLoc.h" +#include <cassert> +#include <map> +#include <memory> +#include <string> + +namespace llvm { +class SourceMgr; +class SMLoc; +class Twine; + +namespace tgtok { +  enum TokKind { +    // Markers +    Eof, Error, + +    // Tokens with no info. +    minus, plus,        // - + +    l_square, r_square, // [ ] +    l_brace, r_brace,   // { } +    l_paren, r_paren,   // ( ) +    less, greater,      // < > +    colon, semi,        // : ; +    comma, period,      // , . +    equal, question,    // = ? +    paste,              // # + +    // Keywords. +    Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List, +    MultiClass, String, Defset, + +    // !keywords. +    XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XListSplat, +    XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, +    XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, + +    // Integer value. +    IntVal, + +    // Binary constant.  Note that these are sized according to the number of +    // bits given. +    BinaryIntVal, + +    // String valued tokens. +    Id, StrVal, VarName, CodeFragment, + +    // Preprocessing tokens for internal usage by the lexer. +    // They are never returned as a result of Lex(). +    Ifdef, Ifndef, Else, Endif, Define +  }; +} + +/// TGLexer - TableGen Lexer class. +class TGLexer { +  SourceMgr &SrcMgr; + +  const char *CurPtr; +  StringRef CurBuf; + +  // Information about the current token. +  const char *TokStart; +  tgtok::TokKind CurCode; +  std::string CurStrVal;  // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT +  int64_t CurIntVal;      // This is valid for INTVAL. + +  /// CurBuffer - This is the current buffer index we're lexing from as managed +  /// by the SourceMgr object. +  unsigned CurBuffer; + +public: +  typedef std::map<std::string, SMLoc> DependenciesMapTy; +private: +  /// Dependencies - This is the list of all included files. +  DependenciesMapTy Dependencies; + +public: +  TGLexer(SourceMgr &SrcMgr, ArrayRef<std::string> Macros); + +  tgtok::TokKind Lex() { +    return CurCode = LexToken(CurPtr == CurBuf.begin()); +  } + +  const DependenciesMapTy &getDependencies() const { +    return Dependencies; +  } + +  tgtok::TokKind getCode() const { return CurCode; } + +  const std::string &getCurStrVal() const { +    assert((CurCode == tgtok::Id || CurCode == tgtok::StrVal || +            CurCode == tgtok::VarName || CurCode == tgtok::CodeFragment) && +           "This token doesn't have a string value"); +    return CurStrVal; +  } +  int64_t getCurIntVal() const { +    assert(CurCode == tgtok::IntVal && "This token isn't an integer"); +    return CurIntVal; +  } +  std::pair<int64_t, unsigned> getCurBinaryIntVal() const { +    assert(CurCode == tgtok::BinaryIntVal && +           "This token isn't a binary integer"); +    return std::make_pair(CurIntVal, (CurPtr - TokStart)-2); +  } + +  SMLoc getLoc() const; + +private: +  /// LexToken - Read the next token and return its code. +  tgtok::TokKind LexToken(bool FileOrLineStart = false); + +  tgtok::TokKind ReturnError(SMLoc Loc, const Twine &Msg); +  tgtok::TokKind ReturnError(const char *Loc, const Twine &Msg); + +  int getNextChar(); +  int peekNextChar(int Index) const; +  void SkipBCPLComment(); +  bool SkipCComment(); +  tgtok::TokKind LexIdentifier(); +  bool LexInclude(); +  tgtok::TokKind LexString(); +  tgtok::TokKind LexVarName(); +  tgtok::TokKind LexNumber(); +  tgtok::TokKind LexBracket(); +  tgtok::TokKind LexExclaim(); + +  // Process EOF encountered in LexToken(). +  // If EOF is met in an include file, then the method will update +  // CurPtr, CurBuf and preprocessing include stack, and return true. +  // If EOF is met in the top-level file, then the method will +  // update and check the preprocessing include stack, and return false. +  bool processEOF(); + +  // *** Structures and methods for preprocessing support *** + +  // A set of macro names that are defined either via command line or +  // by using: +  //     #define NAME +  StringSet<> DefinedMacros; + +  // Each of #ifdef and #else directives has a descriptor associated +  // with it. +  // +  // An ordered list of preprocessing controls defined by #ifdef/#else +  // directives that are in effect currently is called preprocessing +  // control stack.  It is represented as a vector of PreprocessorControlDesc's. +  // +  // The control stack is updated according to the following rules: +  // +  // For each #ifdef we add an element to the control stack. +  // For each #else we replace the top element with a descriptor +  // with an inverted IsDefined value. +  // For each #endif we pop the top element from the control stack. +  // +  // When CurPtr reaches the current buffer's end, the control stack +  // must be empty, i.e. #ifdef and the corresponding #endif +  // must be located in the same file. +  struct PreprocessorControlDesc { +    // Either tgtok::Ifdef or tgtok::Else. +    tgtok::TokKind Kind; + +    // True, if the condition for this directive is true, false - otherwise. +    // Examples: +    //     #ifdef NAME       : true, if NAME is defined, false - otherwise. +    //     ... +    //     #else             : false, if NAME is defined, true - otherwise. +    bool IsDefined; + +    // Pointer into CurBuf to the beginning of the preprocessing directive +    // word, e.g.: +    //     #ifdef NAME +    //      ^ - SrcPos +    SMLoc SrcPos; +  }; + +  // We want to disallow code like this: +  //     file1.td: +  //         #define NAME +  //         #ifdef NAME +  //         include "file2.td" +  //     EOF +  //     file2.td: +  //         #endif +  //     EOF +  // +  // To do this, we clear the preprocessing control stack on entry +  // to each of the included file.  PrepIncludeStack is used to store +  // preprocessing control stacks for the current file and all its +  // parent files.  The back() element is the preprocessing control +  // stack for the current file. +  std::vector<std::unique_ptr<std::vector<PreprocessorControlDesc>>> +      PrepIncludeStack; + +  // Validate that the current preprocessing control stack is empty, +  // since we are about to exit a file, and pop the include stack. +  // +  // If IncludeStackMustBeEmpty is true, the include stack must be empty +  // after the popping, otherwise, the include stack must not be empty +  // after the popping.  Basically, the include stack must be empty +  // only if we exit the "top-level" file (i.e. finish lexing). +  // +  // The method returns false, if the current preprocessing control stack +  // is not empty (e.g. there is an unterminated #ifdef/#else), +  // true - otherwise. +  bool prepExitInclude(bool IncludeStackMustBeEmpty); + +  // Look ahead for a preprocessing directive starting from CurPtr.  The caller +  // must only call this method, if *(CurPtr - 1) is '#'.  If the method matches +  // a preprocessing directive word followed by a whitespace, then it returns +  // one of the internal token kinds, i.e. Ifdef, Else, Endif, Define. +  // +  // CurPtr is not adjusted by this method. +  tgtok::TokKind prepIsDirective() const; + +  // Given a preprocessing token kind, adjusts CurPtr to the end +  // of the preprocessing directive word.  Returns true, unless +  // an unsupported token kind is passed in. +  // +  // We use look-ahead prepIsDirective() and prepEatPreprocessorDirective() +  // to avoid adjusting CurPtr before we are sure that '#' is followed +  // by a preprocessing directive.  If it is not, then we fall back to +  // tgtok::paste interpretation of '#'. +  bool prepEatPreprocessorDirective(tgtok::TokKind Kind); + +  // The main "exit" point from the token parsing to preprocessor. +  // +  // The method is called for CurPtr, when prepIsDirective() returns +  // true.  The first parameter matches the result of prepIsDirective(), +  // denoting the actual preprocessor directive to be processed. +  // +  // If the preprocessing directive disables the tokens processing, e.g.: +  //     #ifdef NAME // NAME is undefined +  // then lexPreprocessor() enters the lines-skipping mode. +  // In this mode, it does not parse any tokens, because the code under +  // the #ifdef may not even be a correct tablegen code.  The preprocessor +  // looks for lines containing other preprocessing directives, which +  // may be prepended with whitespaces and C-style comments.  If the line +  // does not contain a preprocessing directive, it is skipped completely. +  // Otherwise, the preprocessing directive is processed by recursively +  // calling lexPreprocessor().  The processing of the encountered +  // preprocessing directives includes updating preprocessing control stack +  // and adding new macros into DefinedMacros set. +  // +  // The second parameter controls whether lexPreprocessor() is called from +  // LexToken() (true) or recursively from lexPreprocessor() (false). +  // +  // If ReturnNextLiveToken is true, the method returns the next +  // LEX token following the current directive or following the end +  // of the disabled preprocessing region corresponding to this directive. +  // If ReturnNextLiveToken is false, the method returns the first parameter, +  // unless there were errors encountered in the disabled preprocessing +  // region - in this case, it returns tgtok::Error. +  tgtok::TokKind lexPreprocessor(tgtok::TokKind Kind, +                                 bool ReturnNextLiveToken = true); + +  // Worker method for lexPreprocessor() to skip lines after some +  // preprocessing directive up to the buffer end or to the directive +  // that re-enables token processing.  The method returns true +  // upon processing the next directive that re-enables tokens +  // processing.  False is returned if an error was encountered. +  // +  // Note that prepSkipRegion() calls lexPreprocessor() to process +  // encountered preprocessing directives.  In this case, the second +  // parameter to lexPreprocessor() is set to false.  Being passed +  // false ReturnNextLiveToken, lexPreprocessor() must never call +  // prepSkipRegion().  We assert this by passing ReturnNextLiveToken +  // to prepSkipRegion() and checking that it is never set to false. +  bool prepSkipRegion(bool MustNeverBeFalse); + +  // Lex name of the macro after either #ifdef or #define.  We could have used +  // LexIdentifier(), but it has special handling of "include" word, which +  // could result in awkward diagnostic errors.  Consider: +  // ---- +  // #ifdef include +  // class ... +  // ---- +  // LexIdentifier() will engage LexInclude(), which will complain about +  // missing file with name "class".  Instead, prepLexMacroName() will treat +  // "include" as a normal macro name. +  // +  // On entry, CurPtr points to the end of a preprocessing directive word. +  // The method allows for whitespaces between the preprocessing directive +  // and the macro name.  The allowed whitespaces are ' ' and '\t'. +  // +  // If the first non-whitespace symbol after the preprocessing directive +  // is a valid start symbol for an identifier (i.e. [a-zA-Z_]), then +  // the method updates TokStart to the position of the first non-whitespace +  // symbol, sets CurPtr to the position of the macro name's last symbol, +  // and returns a string reference to the macro name.  Otherwise, +  // TokStart is set to the first non-whitespace symbol after the preprocessing +  // directive, and the method returns an empty string reference. +  // +  // In all cases, TokStart may be used to point to the word following +  // the preprocessing directive. +  StringRef prepLexMacroName(); + +  // Skip any whitespaces starting from CurPtr.  The method is used +  // only in the lines-skipping mode to find the first non-whitespace +  // symbol after or at CurPtr.  Allowed whitespaces are ' ', '\t', '\n' +  // and '\r'.  The method skips C-style comments as well, because +  // it is used to find the beginning of the preprocessing directive. +  // If we do not handle C-style comments the following code would +  // result in incorrect detection of a preprocessing directive: +  //     /* +  //     #ifdef NAME +  //     */ +  // As long as we skip C-style comments, the following code is correctly +  // recognized as a preprocessing directive: +  //     /* first line comment +  //        second line comment */ #ifdef NAME +  // +  // The method returns true upon reaching the first non-whitespace symbol +  // or EOF, CurPtr is set to point to this symbol.  The method returns false, +  // if an error occured during skipping of a C-style comment. +  bool prepSkipLineBegin(); + +  // Skip any whitespaces or comments after a preprocessing directive. +  // The method returns true upon reaching either end of the line +  // or end of the file.  If there is a multiline C-style comment +  // after the preprocessing directive, the method skips +  // the comment, so the final CurPtr may point to one of the next lines. +  // The method returns false, if an error occured during skipping +  // C- or C++-style comment, or a non-whitespace symbol appears +  // after the preprocessing directive. +  // +  // The method maybe called both during lines-skipping and tokens +  // processing.  It actually verifies that only whitespaces or/and +  // comments follow a preprocessing directive. +  // +  // After the execution of this mehod, CurPtr points either to new line +  // symbol, buffer end or non-whitespace symbol following the preprocesing +  // directive. +  bool prepSkipDirectiveEnd(); + +  // Skip all symbols to the end of the line/file. +  // The method adjusts CurPtr, so that it points to either new line +  // symbol in the current line or the buffer end. +  void prepSkipToLineEnd(); + +  // Return true, if the current preprocessor control stack is such that +  // we should allow lexer to process the next token, false - otherwise. +  // +  // In particular, the method returns true, if all the #ifdef/#else +  // controls on the stack have their IsDefined member set to true. +  bool prepIsProcessingEnabled(); + +  // Report an error, if we reach EOF with non-empty preprocessing control +  // stack.  This means there is no matching #endif for the previous +  // #ifdef/#else. +  void prepReportPreprocessorStackError(); +}; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp new file mode 100644 index 000000000000..c373e2899a5d --- /dev/null +++ b/llvm/lib/TableGen/TGParser.cpp @@ -0,0 +1,3243 @@ +//===- TGParser.cpp - Parser for TableGen Files ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implement the Parser for TableGen. +// +//===----------------------------------------------------------------------===// + +#include "TGParser.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Record.h" +#include <algorithm> +#include <cassert> +#include <cstdint> + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Support Code for the Semantic Actions. +//===----------------------------------------------------------------------===// + +namespace llvm { + +struct SubClassReference { +  SMRange RefRange; +  Record *Rec; +  SmallVector<Init*, 4> TemplateArgs; + +  SubClassReference() : Rec(nullptr) {} + +  bool isInvalid() const { return Rec == nullptr; } +}; + +struct SubMultiClassReference { +  SMRange RefRange; +  MultiClass *MC; +  SmallVector<Init*, 4> TemplateArgs; + +  SubMultiClassReference() : MC(nullptr) {} + +  bool isInvalid() const { return MC == nullptr; } +  void dump() const; +}; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void SubMultiClassReference::dump() const { +  errs() << "Multiclass:\n"; + +  MC->dump(); + +  errs() << "Template args:\n"; +  for (Init *TA : TemplateArgs) +    TA->dump(); +} +#endif + +} // end namespace llvm + +static bool checkBitsConcrete(Record &R, const RecordVal &RV) { +  BitsInit *BV = cast<BitsInit>(RV.getValue()); +  for (unsigned i = 0, e = BV->getNumBits(); i != e; ++i) { +    Init *Bit = BV->getBit(i); +    bool IsReference = false; +    if (auto VBI = dyn_cast<VarBitInit>(Bit)) { +      if (auto VI = dyn_cast<VarInit>(VBI->getBitVar())) { +        if (R.getValue(VI->getName())) +          IsReference = true; +      } +    } else if (isa<VarInit>(Bit)) { +      IsReference = true; +    } +    if (!(IsReference || Bit->isConcrete())) +      return false; +  } +  return true; +} + +static void checkConcrete(Record &R) { +  for (const RecordVal &RV : R.getValues()) { +    // HACK: Disable this check for variables declared with 'field'. This is +    // done merely because existing targets have legitimate cases of +    // non-concrete variables in helper defs. Ideally, we'd introduce a +    // 'maybe' or 'optional' modifier instead of this. +    if (RV.getPrefix()) +      continue; + +    if (Init *V = RV.getValue()) { +      bool Ok = isa<BitsInit>(V) ? checkBitsConcrete(R, RV) : V->isConcrete(); +      if (!Ok) { +        PrintError(R.getLoc(), +                   Twine("Initializer of '") + RV.getNameInitAsString() + +                   "' in '" + R.getNameInitAsString() + +                   "' could not be fully resolved: " + +                   RV.getValue()->getAsString()); +      } +    } +  } +} + +/// Return an Init with a qualifier prefix referring +/// to CurRec's name. +static Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass, +                        Init *Name, StringRef Scoper) { +  Init *NewName = +      BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(Scoper)); +  NewName = BinOpInit::getStrConcat(NewName, Name); +  if (CurMultiClass && Scoper != "::") { +    Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(), +                                           StringInit::get("::")); +    NewName = BinOpInit::getStrConcat(Prefix, NewName); +  } + +  if (BinOpInit *BinOp = dyn_cast<BinOpInit>(NewName)) +    NewName = BinOp->Fold(&CurRec); +  return NewName; +} + +/// Return the qualified version of the implicit 'NAME' template argument. +static Init *QualifiedNameOfImplicitName(Record &Rec, +                                         MultiClass *MC = nullptr) { +  return QualifyName(Rec, MC, StringInit::get("NAME"), MC ? "::" : ":"); +} + +static Init *QualifiedNameOfImplicitName(MultiClass *MC) { +  return QualifiedNameOfImplicitName(MC->Rec, MC); +} + +bool TGParser::AddValue(Record *CurRec, SMLoc Loc, const RecordVal &RV) { +  if (!CurRec) +    CurRec = &CurMultiClass->Rec; + +  if (RecordVal *ERV = CurRec->getValue(RV.getNameInit())) { +    // The value already exists in the class, treat this as a set. +    if (ERV->setValue(RV.getValue())) +      return Error(Loc, "New definition of '" + RV.getName() + "' of type '" + +                   RV.getType()->getAsString() + "' is incompatible with " + +                   "previous definition of type '" + +                   ERV->getType()->getAsString() + "'"); +  } else { +    CurRec->addValue(RV); +  } +  return false; +} + +/// SetValue - +/// Return true on error, false on success. +bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName, +                        ArrayRef<unsigned> BitList, Init *V, +                        bool AllowSelfAssignment) { +  if (!V) return false; + +  if (!CurRec) CurRec = &CurMultiClass->Rec; + +  RecordVal *RV = CurRec->getValue(ValName); +  if (!RV) +    return Error(Loc, "Value '" + ValName->getAsUnquotedString() + +                 "' unknown!"); + +  // Do not allow assignments like 'X = X'.  This will just cause infinite loops +  // in the resolution machinery. +  if (BitList.empty()) +    if (VarInit *VI = dyn_cast<VarInit>(V)) +      if (VI->getNameInit() == ValName && !AllowSelfAssignment) +        return Error(Loc, "Recursion / self-assignment forbidden"); + +  // If we are assigning to a subset of the bits in the value... then we must be +  // assigning to a field of BitsRecTy, which must have a BitsInit +  // initializer. +  // +  if (!BitList.empty()) { +    BitsInit *CurVal = dyn_cast<BitsInit>(RV->getValue()); +    if (!CurVal) +      return Error(Loc, "Value '" + ValName->getAsUnquotedString() + +                   "' is not a bits type"); + +    // Convert the incoming value to a bits type of the appropriate size... +    Init *BI = V->getCastTo(BitsRecTy::get(BitList.size())); +    if (!BI) +      return Error(Loc, "Initializer is not compatible with bit range"); + +    SmallVector<Init *, 16> NewBits(CurVal->getNumBits()); + +    // Loop over bits, assigning values as appropriate. +    for (unsigned i = 0, e = BitList.size(); i != e; ++i) { +      unsigned Bit = BitList[i]; +      if (NewBits[Bit]) +        return Error(Loc, "Cannot set bit #" + Twine(Bit) + " of value '" + +                     ValName->getAsUnquotedString() + "' more than once"); +      NewBits[Bit] = BI->getBit(i); +    } + +    for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i) +      if (!NewBits[i]) +        NewBits[i] = CurVal->getBit(i); + +    V = BitsInit::get(NewBits); +  } + +  if (RV->setValue(V)) { +    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() + +                          "' of type '" + RV->getType()->getAsString() + +                          "' is incompatible with initializer '" + +                          V->getAsString() + InitType + "'"); +  } +  return false; +} + +/// AddSubClass - Add SubClass as a subclass to CurRec, resolving its template +/// args as SubClass's template arguments. +bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { +  Record *SC = SubClass.Rec; +  // Add all of the values in the subclass into the current class. +  for (const RecordVal &Val : SC->getValues()) +    if (AddValue(CurRec, SubClass.RefRange.Start, Val)) +      return true; + +  ArrayRef<Init *> TArgs = SC->getTemplateArgs(); + +  // Ensure that an appropriate number of template arguments are specified. +  if (TArgs.size() < SubClass.TemplateArgs.size()) +    return Error(SubClass.RefRange.Start, +                 "More template args specified than expected"); + +  // Loop over all of the template arguments, setting them to the specified +  // value or leaving them as the default if necessary. +  MapResolver R(CurRec); + +  for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { +    if (i < SubClass.TemplateArgs.size()) { +      // If a value is specified for this template arg, set it now. +      if (SetValue(CurRec, SubClass.RefRange.Start, TArgs[i], +                   None, SubClass.TemplateArgs[i])) +        return true; +    } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { +      return Error(SubClass.RefRange.Start, +                   "Value not specified for template argument #" + +                   Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + +                   ") of subclass '" + SC->getNameInitAsString() + "'!"); +    } + +    R.set(TArgs[i], CurRec->getValue(TArgs[i])->getValue()); + +    CurRec->removeValue(TArgs[i]); +  } + +  Init *Name; +  if (CurRec->isClass()) +    Name = +        VarInit::get(QualifiedNameOfImplicitName(*CurRec), StringRecTy::get()); +  else +    Name = CurRec->getNameInit(); +  R.set(QualifiedNameOfImplicitName(*SC), Name); + +  CurRec->resolveReferences(R); + +  // Since everything went well, we can now set the "superclass" list for the +  // current record. +  ArrayRef<std::pair<Record *, SMRange>> SCs = SC->getSuperClasses(); +  for (const auto &SCPair : SCs) { +    if (CurRec->isSubClassOf(SCPair.first)) +      return Error(SubClass.RefRange.Start, +                   "Already subclass of '" + SCPair.first->getName() + "'!\n"); +    CurRec->addSuperClass(SCPair.first, SCPair.second); +  } + +  if (CurRec->isSubClassOf(SC)) +    return Error(SubClass.RefRange.Start, +                 "Already subclass of '" + SC->getName() + "'!\n"); +  CurRec->addSuperClass(SC, SubClass.RefRange); +  return false; +} + +bool TGParser::AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass) { +  if (Entry.Rec) +    return AddSubClass(Entry.Rec.get(), SubClass); + +  for (auto &E : Entry.Loop->Entries) { +    if (AddSubClass(E, SubClass)) +      return true; +  } + +  return false; +} + +/// AddSubMultiClass - Add SubMultiClass as a subclass to +/// CurMC, resolving its template args as SubMultiClass's +/// template arguments. +bool TGParser::AddSubMultiClass(MultiClass *CurMC, +                                SubMultiClassReference &SubMultiClass) { +  MultiClass *SMC = SubMultiClass.MC; + +  ArrayRef<Init *> SMCTArgs = SMC->Rec.getTemplateArgs(); +  if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size()) +    return Error(SubMultiClass.RefRange.Start, +                 "More template args specified than expected"); + +  // Prepare the mapping of template argument name to value, filling in default +  // values if necessary. +  SubstStack TemplateArgs; +  for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) { +    if (i < SubMultiClass.TemplateArgs.size()) { +      TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]); +    } else { +      Init *Default = SMC->Rec.getValue(SMCTArgs[i])->getValue(); +      if (!Default->isComplete()) { +        return Error(SubMultiClass.RefRange.Start, +                     "value not specified for template argument #" + Twine(i) + +                         " (" + SMCTArgs[i]->getAsUnquotedString() + +                         ") of multiclass '" + SMC->Rec.getNameInitAsString() + +                         "'"); +      } +      TemplateArgs.emplace_back(SMCTArgs[i], Default); +    } +  } + +  TemplateArgs.emplace_back( +      QualifiedNameOfImplicitName(SMC), +      VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get())); + +  // Add all of the defs in the subclass into the current multiclass. +  return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries); +} + +/// Add a record or foreach loop to the current context (global record keeper, +/// current inner-most foreach loop, or multiclass). +bool TGParser::addEntry(RecordsEntry E) { +  assert(!E.Rec || !E.Loop); + +  if (!Loops.empty()) { +    Loops.back()->Entries.push_back(std::move(E)); +    return false; +  } + +  if (E.Loop) { +    SubstStack Stack; +    return resolve(*E.Loop, Stack, CurMultiClass == nullptr, +                   CurMultiClass ? &CurMultiClass->Entries : nullptr); +  } + +  if (CurMultiClass) { +    CurMultiClass->Entries.push_back(std::move(E)); +    return false; +  } + +  return addDefOne(std::move(E.Rec)); +} + +/// Resolve the entries in \p Loop, going over inner loops recursively +/// and making the given subsitutions of (name, value) pairs. +/// +/// The resulting records are stored in \p Dest if non-null. Otherwise, they +/// are added to the global record keeper. +bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs, +                       bool Final, std::vector<RecordsEntry> *Dest, +                       SMLoc *Loc) { +  MapResolver R; +  for (const auto &S : Substs) +    R.set(S.first, S.second); +  Init *List = Loop.ListValue->resolveReferences(R); +  auto LI = dyn_cast<ListInit>(List); +  if (!LI) { +    if (!Final) { +      Dest->emplace_back(std::make_unique<ForeachLoop>(Loop.Loc, Loop.IterVar, +                                                  List)); +      return resolve(Loop.Entries, Substs, Final, &Dest->back().Loop->Entries, +                     Loc); +    } + +    PrintError(Loop.Loc, Twine("attempting to loop over '") + +                              List->getAsString() + "', expected a list"); +    return true; +  } + +  bool Error = false; +  for (auto Elt : *LI) { +    Substs.emplace_back(Loop.IterVar->getNameInit(), Elt); +    Error = resolve(Loop.Entries, Substs, Final, Dest); +    Substs.pop_back(); +    if (Error) +      break; +  } +  return Error; +} + +/// Resolve the entries in \p Source, going over loops recursively and +/// making the given substitutions of (name, value) pairs. +/// +/// The resulting records are stored in \p Dest if non-null. Otherwise, they +/// are added to the global record keeper. +bool TGParser::resolve(const std::vector<RecordsEntry> &Source, +                       SubstStack &Substs, bool Final, +                       std::vector<RecordsEntry> *Dest, SMLoc *Loc) { +  bool Error = false; +  for (auto &E : Source) { +    if (E.Loop) { +      Error = resolve(*E.Loop, Substs, Final, Dest); +    } else { +      auto Rec = std::make_unique<Record>(*E.Rec); +      if (Loc) +        Rec->appendLoc(*Loc); + +      MapResolver R(Rec.get()); +      for (const auto &S : Substs) +        R.set(S.first, S.second); +      Rec->resolveReferences(R); + +      if (Dest) +        Dest->push_back(std::move(Rec)); +      else +        Error = addDefOne(std::move(Rec)); +    } +    if (Error) +      break; +  } +  return Error; +} + +/// Resolve the record fully and add it to the record keeper. +bool TGParser::addDefOne(std::unique_ptr<Record> Rec) { +  if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) { +    if (!Rec->isAnonymous()) { +      PrintError(Rec->getLoc(), +                 "def already exists: " + Rec->getNameInitAsString()); +      PrintNote(Prev->getLoc(), "location of previous definition"); +      return true; +    } +    Rec->setName(Records.getNewAnonymousName()); +  } + +  Rec->resolveReferences(); +  checkConcrete(*Rec); + +  if (!isa<StringInit>(Rec->getNameInit())) { +    PrintError(Rec->getLoc(), Twine("record name '") + +                                  Rec->getNameInit()->getAsString() + +                                  "' could not be fully resolved"); +    return true; +  } + +  // If ObjectBody has template arguments, it's an error. +  assert(Rec->getTemplateArgs().empty() && "How'd this get template args?"); + +  for (DefsetRecord *Defset : Defsets) { +    DefInit *I = Rec->getDefInit(); +    if (!I->getType()->typeIsA(Defset->EltTy)) { +      PrintError(Rec->getLoc(), Twine("adding record of incompatible type '") + +                                    I->getType()->getAsString() + +                                     "' to defset"); +      PrintNote(Defset->Loc, "location of defset declaration"); +      return true; +    } +    Defset->Elements.push_back(I); +  } + +  Records.addDef(std::move(Rec)); +  return false; +} + +//===----------------------------------------------------------------------===// +// Parser Code +//===----------------------------------------------------------------------===// + +/// isObjectStart - Return true if this is a valid first token for an Object. +static bool isObjectStart(tgtok::TokKind K) { +  return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm || +         K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach || +         K == tgtok::Defset; +} + +/// ParseObjectName - If a valid object name is specified, return it. If no +/// name is specified, return the unset initializer. Return nullptr on parse +/// error. +///   ObjectName ::= Value [ '#' Value ]* +///   ObjectName ::= /*empty*/ +/// +Init *TGParser::ParseObjectName(MultiClass *CurMultiClass) { +  switch (Lex.getCode()) { +  case tgtok::colon: +  case tgtok::semi: +  case tgtok::l_brace: +    // These are all of the tokens that can begin an object body. +    // Some of these can also begin values but we disallow those cases +    // because they are unlikely to be useful. +    return UnsetInit::get(); +  default: +    break; +  } + +  Record *CurRec = nullptr; +  if (CurMultiClass) +    CurRec = &CurMultiClass->Rec; + +  Init *Name = ParseValue(CurRec, StringRecTy::get(), ParseNameMode); +  if (!Name) +    return nullptr; + +  if (CurMultiClass) { +    Init *NameStr = QualifiedNameOfImplicitName(CurMultiClass); +    HasReferenceResolver R(NameStr); +    Name->resolveReferences(R); +    if (!R.found()) +      Name = BinOpInit::getStrConcat(VarInit::get(NameStr, StringRecTy::get()), +                                     Name); +  } + +  return Name; +} + +/// ParseClassID - Parse and resolve a reference to a class name.  This returns +/// null on error. +/// +///    ClassID ::= ID +/// +Record *TGParser::ParseClassID() { +  if (Lex.getCode() != tgtok::Id) { +    TokError("expected name for ClassID"); +    return nullptr; +  } + +  Record *Result = Records.getClass(Lex.getCurStrVal()); +  if (!Result) { +    std::string Msg("Couldn't find class '" + Lex.getCurStrVal() + "'"); +    if (MultiClasses[Lex.getCurStrVal()].get()) +      TokError(Msg + ". Use 'defm' if you meant to use multiclass '" + +               Lex.getCurStrVal() + "'"); +    else +      TokError(Msg); +  } + +  Lex.Lex(); +  return Result; +} + +/// ParseMultiClassID - Parse and resolve a reference to a multiclass name. +/// This returns null on error. +/// +///    MultiClassID ::= ID +/// +MultiClass *TGParser::ParseMultiClassID() { +  if (Lex.getCode() != tgtok::Id) { +    TokError("expected name for MultiClassID"); +    return nullptr; +  } + +  MultiClass *Result = MultiClasses[Lex.getCurStrVal()].get(); +  if (!Result) +    TokError("Couldn't find multiclass '" + Lex.getCurStrVal() + "'"); + +  Lex.Lex(); +  return Result; +} + +/// ParseSubClassReference - Parse a reference to a subclass or to a templated +/// subclass.  This returns a SubClassRefTy with a null Record* on error. +/// +///  SubClassRef ::= ClassID +///  SubClassRef ::= ClassID '<' ValueList '>' +/// +SubClassReference TGParser:: +ParseSubClassReference(Record *CurRec, bool isDefm) { +  SubClassReference Result; +  Result.RefRange.Start = Lex.getLoc(); + +  if (isDefm) { +    if (MultiClass *MC = ParseMultiClassID()) +      Result.Rec = &MC->Rec; +  } else { +    Result.Rec = ParseClassID(); +  } +  if (!Result.Rec) return Result; + +  // If there is no template arg list, we're done. +  if (Lex.getCode() != tgtok::less) { +    Result.RefRange.End = Lex.getLoc(); +    return Result; +  } +  Lex.Lex();  // Eat the '<' + +  if (Lex.getCode() == tgtok::greater) { +    TokError("subclass reference requires a non-empty list of template values"); +    Result.Rec = nullptr; +    return Result; +  } + +  ParseValueList(Result.TemplateArgs, CurRec, Result.Rec); +  if (Result.TemplateArgs.empty()) { +    Result.Rec = nullptr;   // Error parsing value list. +    return Result; +  } + +  if (Lex.getCode() != tgtok::greater) { +    TokError("expected '>' in template value list"); +    Result.Rec = nullptr; +    return Result; +  } +  Lex.Lex(); +  Result.RefRange.End = Lex.getLoc(); + +  return Result; +} + +/// ParseSubMultiClassReference - Parse a reference to a subclass or to a +/// templated submulticlass.  This returns a SubMultiClassRefTy with a null +/// Record* on error. +/// +///  SubMultiClassRef ::= MultiClassID +///  SubMultiClassRef ::= MultiClassID '<' ValueList '>' +/// +SubMultiClassReference TGParser:: +ParseSubMultiClassReference(MultiClass *CurMC) { +  SubMultiClassReference Result; +  Result.RefRange.Start = Lex.getLoc(); + +  Result.MC = ParseMultiClassID(); +  if (!Result.MC) return Result; + +  // If there is no template arg list, we're done. +  if (Lex.getCode() != tgtok::less) { +    Result.RefRange.End = Lex.getLoc(); +    return Result; +  } +  Lex.Lex();  // Eat the '<' + +  if (Lex.getCode() == tgtok::greater) { +    TokError("subclass reference requires a non-empty list of template values"); +    Result.MC = nullptr; +    return Result; +  } + +  ParseValueList(Result.TemplateArgs, &CurMC->Rec, &Result.MC->Rec); +  if (Result.TemplateArgs.empty()) { +    Result.MC = nullptr;   // Error parsing value list. +    return Result; +  } + +  if (Lex.getCode() != tgtok::greater) { +    TokError("expected '>' in template value list"); +    Result.MC = nullptr; +    return Result; +  } +  Lex.Lex(); +  Result.RefRange.End = Lex.getLoc(); + +  return Result; +} + +/// ParseRangePiece - Parse a bit/value range. +///   RangePiece ::= INTVAL +///   RangePiece ::= INTVAL '-' INTVAL +///   RangePiece ::= INTVAL INTVAL +bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges, +                               TypedInit *FirstItem) { +  Init *CurVal = FirstItem; +  if (!CurVal) +    CurVal = ParseValue(nullptr); + +  IntInit *II = dyn_cast_or_null<IntInit>(CurVal); +  if (!II) +    return TokError("expected integer or bitrange"); + +  int64_t Start = II->getValue(); +  int64_t End; + +  if (Start < 0) +    return TokError("invalid range, cannot be negative"); + +  switch (Lex.getCode()) { +  default: +    Ranges.push_back(Start); +    return false; +  case tgtok::minus: { +    Lex.Lex(); // eat + +    Init *I_End = ParseValue(nullptr); +    IntInit *II_End = dyn_cast_or_null<IntInit>(I_End); +    if (!II_End) { +      TokError("expected integer value as end of range"); +      return true; +    } + +    End = II_End->getValue(); +    break; +  } +  case tgtok::IntVal: { +    End = -Lex.getCurIntVal(); +    Lex.Lex(); +    break; +  } +  } +  if (End < 0) +    return TokError("invalid range, cannot be negative"); + +  // Add to the range. +  if (Start < End) +    for (; Start <= End; ++Start) +      Ranges.push_back(Start); +  else +    for (; Start >= End; --Start) +      Ranges.push_back(Start); +  return false; +} + +/// ParseRangeList - Parse a list of scalars and ranges into scalar values. +/// +///   RangeList ::= RangePiece (',' RangePiece)* +/// +void TGParser::ParseRangeList(SmallVectorImpl<unsigned> &Result) { +  // Parse the first piece. +  if (ParseRangePiece(Result)) { +    Result.clear(); +    return; +  } +  while (Lex.getCode() == tgtok::comma) { +    Lex.Lex();  // Eat the comma. + +    // Parse the next range piece. +    if (ParseRangePiece(Result)) { +      Result.clear(); +      return; +    } +  } +} + +/// ParseOptionalRangeList - Parse either a range list in <>'s or nothing. +///   OptionalRangeList ::= '<' RangeList '>' +///   OptionalRangeList ::= /*empty*/ +bool TGParser::ParseOptionalRangeList(SmallVectorImpl<unsigned> &Ranges) { +  if (Lex.getCode() != tgtok::less) +    return false; + +  SMLoc StartLoc = Lex.getLoc(); +  Lex.Lex(); // eat the '<' + +  // Parse the range list. +  ParseRangeList(Ranges); +  if (Ranges.empty()) return true; + +  if (Lex.getCode() != tgtok::greater) { +    TokError("expected '>' at end of range list"); +    return Error(StartLoc, "to match this '<'"); +  } +  Lex.Lex();   // eat the '>'. +  return false; +} + +/// ParseOptionalBitList - Parse either a bit list in {}'s or nothing. +///   OptionalBitList ::= '{' RangeList '}' +///   OptionalBitList ::= /*empty*/ +bool TGParser::ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges) { +  if (Lex.getCode() != tgtok::l_brace) +    return false; + +  SMLoc StartLoc = Lex.getLoc(); +  Lex.Lex(); // eat the '{' + +  // Parse the range list. +  ParseRangeList(Ranges); +  if (Ranges.empty()) return true; + +  if (Lex.getCode() != tgtok::r_brace) { +    TokError("expected '}' at end of bit list"); +    return Error(StartLoc, "to match this '{'"); +  } +  Lex.Lex();   // eat the '}'. +  return false; +} + +/// ParseType - Parse and return a tblgen type.  This returns null on error. +/// +///   Type ::= STRING                       // string type +///   Type ::= CODE                         // code type +///   Type ::= BIT                          // bit type +///   Type ::= BITS '<' INTVAL '>'          // bits<x> type +///   Type ::= INT                          // int type +///   Type ::= LIST '<' Type '>'            // list<x> type +///   Type ::= DAG                          // dag type +///   Type ::= ClassID                      // Record Type +/// +RecTy *TGParser::ParseType() { +  switch (Lex.getCode()) { +  default: TokError("Unknown token when expecting a type"); return nullptr; +  case tgtok::String: Lex.Lex(); return StringRecTy::get(); +  case tgtok::Code:   Lex.Lex(); return CodeRecTy::get(); +  case tgtok::Bit:    Lex.Lex(); return BitRecTy::get(); +  case tgtok::Int:    Lex.Lex(); return IntRecTy::get(); +  case tgtok::Dag:    Lex.Lex(); return DagRecTy::get(); +  case tgtok::Id: +    if (Record *R = ParseClassID()) return RecordRecTy::get(R); +    TokError("unknown class name"); +    return nullptr; +  case tgtok::Bits: { +    if (Lex.Lex() != tgtok::less) { // Eat 'bits' +      TokError("expected '<' after bits type"); +      return nullptr; +    } +    if (Lex.Lex() != tgtok::IntVal) {  // Eat '<' +      TokError("expected integer in bits<n> type"); +      return nullptr; +    } +    uint64_t Val = Lex.getCurIntVal(); +    if (Lex.Lex() != tgtok::greater) {  // Eat count. +      TokError("expected '>' at end of bits<n> type"); +      return nullptr; +    } +    Lex.Lex();  // Eat '>' +    return BitsRecTy::get(Val); +  } +  case tgtok::List: { +    if (Lex.Lex() != tgtok::less) { // Eat 'bits' +      TokError("expected '<' after list type"); +      return nullptr; +    } +    Lex.Lex();  // Eat '<' +    RecTy *SubType = ParseType(); +    if (!SubType) return nullptr; + +    if (Lex.getCode() != tgtok::greater) { +      TokError("expected '>' at end of list<ty> type"); +      return nullptr; +    } +    Lex.Lex();  // Eat '>' +    return ListRecTy::get(SubType); +  } +  } +} + +/// ParseIDValue - This is just like ParseIDValue above, but it assumes the ID +/// has already been read. +Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc, +                             IDParseMode Mode) { +  if (CurRec) { +    if (const RecordVal *RV = CurRec->getValue(Name)) +      return VarInit::get(Name, RV->getType()); +  } + +  if ((CurRec && CurRec->isClass()) || CurMultiClass) { +    Init *TemplateArgName; +    if (CurMultiClass) { +      TemplateArgName = +          QualifyName(CurMultiClass->Rec, CurMultiClass, Name, "::"); +    } else +      TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, ":"); + +    Record *TemplateRec = CurMultiClass ? &CurMultiClass->Rec : CurRec; +    if (TemplateRec->isTemplateArg(TemplateArgName)) { +      const RecordVal *RV = TemplateRec->getValue(TemplateArgName); +      assert(RV && "Template arg doesn't exist??"); +      return VarInit::get(TemplateArgName, RV->getType()); +    } else if (Name->getValue() == "NAME") { +      return VarInit::get(TemplateArgName, StringRecTy::get()); +    } +  } + +  // If this is in a foreach loop, make sure it's not a loop iterator +  for (const auto &L : Loops) { +    VarInit *IterVar = dyn_cast<VarInit>(L->IterVar); +    if (IterVar && IterVar->getNameInit() == Name) +      return IterVar; +  } + +  if (Mode == ParseNameMode) +    return Name; + +  if (Init *I = Records.getGlobal(Name->getValue())) +    return I; + +  // Allow self-references of concrete defs, but delay the lookup so that we +  // get the correct type. +  if (CurRec && !CurRec->isClass() && !CurMultiClass && +      CurRec->getNameInit() == Name) +    return UnOpInit::get(UnOpInit::CAST, Name, CurRec->getType()); + +  Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'"); +  return nullptr; +} + +/// ParseOperation - Parse an operator.  This returns null on error. +/// +/// Operation ::= XOperator ['<' Type '>'] '(' Args ')' +/// +Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { +  switch (Lex.getCode()) { +  default: +    TokError("unknown operation"); +    return nullptr; +  case tgtok::XHead: +  case tgtok::XTail: +  case tgtok::XSize: +  case tgtok::XEmpty: +  case tgtok::XCast: {  // Value ::= !unop '(' Value ')' +    UnOpInit::UnaryOp Code; +    RecTy *Type = nullptr; + +    switch (Lex.getCode()) { +    default: llvm_unreachable("Unhandled code!"); +    case tgtok::XCast: +      Lex.Lex();  // eat the operation +      Code = UnOpInit::CAST; + +      Type = ParseOperatorType(); + +      if (!Type) { +        TokError("did not get type for unary operator"); +        return nullptr; +      } + +      break; +    case tgtok::XHead: +      Lex.Lex();  // eat the operation +      Code = UnOpInit::HEAD; +      break; +    case tgtok::XTail: +      Lex.Lex();  // eat the operation +      Code = UnOpInit::TAIL; +      break; +    case tgtok::XSize: +      Lex.Lex(); +      Code = UnOpInit::SIZE; +      Type = IntRecTy::get(); +      break; +    case tgtok::XEmpty: +      Lex.Lex();  // eat the operation +      Code = UnOpInit::EMPTY; +      Type = IntRecTy::get(); +      break; +    } +    if (Lex.getCode() != tgtok::l_paren) { +      TokError("expected '(' after unary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the '(' + +    Init *LHS = ParseValue(CurRec); +    if (!LHS) return nullptr; + +    if (Code == UnOpInit::HEAD || +        Code == UnOpInit::TAIL || +        Code == UnOpInit::EMPTY) { +      ListInit *LHSl = dyn_cast<ListInit>(LHS); +      StringInit *LHSs = dyn_cast<StringInit>(LHS); +      TypedInit *LHSt = dyn_cast<TypedInit>(LHS); +      if (!LHSl && !LHSs && !LHSt) { +        TokError("expected list or string type argument in unary operator"); +        return nullptr; +      } +      if (LHSt) { +        ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType()); +        StringRecTy *SType = dyn_cast<StringRecTy>(LHSt->getType()); +        if (!LType && !SType) { +          TokError("expected list or string type argument in unary operator"); +          return nullptr; +        } +      } + +      if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL || +          Code == UnOpInit::SIZE) { +        if (!LHSl && !LHSt) { +          TokError("expected list type argument in unary operator"); +          return nullptr; +        } +      } + +      if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) { +        if (LHSl && LHSl->empty()) { +          TokError("empty list argument in unary operator"); +          return nullptr; +        } +        if (LHSl) { +          Init *Item = LHSl->getElement(0); +          TypedInit *Itemt = dyn_cast<TypedInit>(Item); +          if (!Itemt) { +            TokError("untyped list element in unary operator"); +            return nullptr; +          } +          Type = (Code == UnOpInit::HEAD) ? Itemt->getType() +                                          : ListRecTy::get(Itemt->getType()); +        } else { +          assert(LHSt && "expected list type argument in unary operator"); +          ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType()); +          if (!LType) { +            TokError("expected list type argument in unary operator"); +            return nullptr; +          } +          Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType; +        } +      } +    } + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in unary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ')' +    return (UnOpInit::get(Code, LHS, Type))->Fold(CurRec); +  } + +  case tgtok::XIsA: { +    // Value ::= !isa '<' Type '>' '(' Value ')' +    Lex.Lex(); // eat the operation + +    RecTy *Type = ParseOperatorType(); +    if (!Type) +      return nullptr; + +    if (Lex.getCode() != tgtok::l_paren) { +      TokError("expected '(' after type of !isa"); +      return nullptr; +    } +    Lex.Lex(); // eat the '(' + +    Init *LHS = ParseValue(CurRec); +    if (!LHS) +      return nullptr; + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in !isa"); +      return nullptr; +    } +    Lex.Lex(); // eat the ')' + +    return (IsAOpInit::get(Type, LHS))->Fold(); +  } + +  case tgtok::XConcat: +  case tgtok::XADD: +  case tgtok::XMUL: +  case tgtok::XAND: +  case tgtok::XOR: +  case tgtok::XSRA: +  case tgtok::XSRL: +  case tgtok::XSHL: +  case tgtok::XEq: +  case tgtok::XNe: +  case tgtok::XLe: +  case tgtok::XLt: +  case tgtok::XGe: +  case tgtok::XGt: +  case tgtok::XListConcat: +  case tgtok::XListSplat: +  case tgtok::XStrConcat: {  // Value ::= !binop '(' Value ',' Value ')' +    tgtok::TokKind OpTok = Lex.getCode(); +    SMLoc OpLoc = Lex.getLoc(); +    Lex.Lex();  // eat the operation + +    BinOpInit::BinaryOp Code; +    switch (OpTok) { +    default: llvm_unreachable("Unhandled code!"); +    case tgtok::XConcat: Code = BinOpInit::CONCAT; break; +    case tgtok::XADD:    Code = BinOpInit::ADD; break; +    case tgtok::XMUL:    Code = BinOpInit::MUL; break; +    case tgtok::XAND:    Code = BinOpInit::AND; break; +    case tgtok::XOR:     Code = BinOpInit::OR; break; +    case tgtok::XSRA:    Code = BinOpInit::SRA; break; +    case tgtok::XSRL:    Code = BinOpInit::SRL; break; +    case tgtok::XSHL:    Code = BinOpInit::SHL; break; +    case tgtok::XEq:     Code = BinOpInit::EQ; break; +    case tgtok::XNe:     Code = BinOpInit::NE; break; +    case tgtok::XLe:     Code = BinOpInit::LE; break; +    case tgtok::XLt:     Code = BinOpInit::LT; break; +    case tgtok::XGe:     Code = BinOpInit::GE; break; +    case tgtok::XGt:     Code = BinOpInit::GT; break; +    case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; +    case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break; +    case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; +    } + +    RecTy *Type = nullptr; +    RecTy *ArgType = nullptr; +    switch (OpTok) { +    default: +      llvm_unreachable("Unhandled code!"); +    case tgtok::XConcat: +      Type = DagRecTy::get(); +      ArgType = DagRecTy::get(); +      break; +    case tgtok::XAND: +    case tgtok::XOR: +    case tgtok::XSRA: +    case tgtok::XSRL: +    case tgtok::XSHL: +    case tgtok::XADD: +    case tgtok::XMUL: +      Type = IntRecTy::get(); +      ArgType = IntRecTy::get(); +      break; +    case tgtok::XEq: +    case tgtok::XNe: +      Type = BitRecTy::get(); +      // ArgType for Eq / Ne is not known at this point +      break; +    case tgtok::XLe: +    case tgtok::XLt: +    case tgtok::XGe: +    case tgtok::XGt: +      Type = BitRecTy::get(); +      ArgType = IntRecTy::get(); +      break; +    case tgtok::XListConcat: +      // We don't know the list type until we parse the first argument +      ArgType = ItemType; +      break; +    case tgtok::XListSplat: +      // Can't do any typechecking until we parse the first argument. +      break; +    case tgtok::XStrConcat: +      Type = StringRecTy::get(); +      ArgType = StringRecTy::get(); +      break; +    } + +    if (Type && ItemType && !Type->typeIsConvertibleTo(ItemType)) { +      Error(OpLoc, Twine("expected value of type '") + +                   ItemType->getAsString() + "', got '" + +                   Type->getAsString() + "'"); +      return nullptr; +    } + +    if (Lex.getCode() != tgtok::l_paren) { +      TokError("expected '(' after binary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the '(' + +    SmallVector<Init*, 2> InitList; + +    for (;;) { +      SMLoc InitLoc = Lex.getLoc(); +      InitList.push_back(ParseValue(CurRec, ArgType)); +      if (!InitList.back()) return nullptr; + +      // All BinOps require their arguments to be of compatible types. +      RecTy *ListType = cast<TypedInit>(InitList.back())->getType(); +      if (!ArgType) { +        ArgType = ListType; + +        switch (Code) { +        case BinOpInit::LISTCONCAT: +          if (!isa<ListRecTy>(ArgType)) { +            Error(InitLoc, Twine("expected a list, got value of type '") + +                           ArgType->getAsString() + "'"); +            return nullptr; +          } +          break; +        case BinOpInit::LISTSPLAT: +          if (ItemType && InitList.size() == 1) { +            if (!isa<ListRecTy>(ItemType)) { +              Error(OpLoc, +                    Twine("expected output type to be a list, got type '") + +                        ItemType->getAsString() + "'"); +              return nullptr; +            } +            if (!ArgType->getListTy()->typeIsConvertibleTo(ItemType)) { +              Error(OpLoc, Twine("expected first arg type to be '") + +                               ArgType->getAsString() + +                               "', got value of type '" + +                               cast<ListRecTy>(ItemType) +                                   ->getElementType() +                                   ->getAsString() + +                               "'"); +              return nullptr; +            } +          } +          if (InitList.size() == 2 && !isa<IntRecTy>(ArgType)) { +            Error(InitLoc, Twine("expected second parameter to be an int, got " +                                 "value of type '") + +                               ArgType->getAsString() + "'"); +            return nullptr; +          } +          ArgType = nullptr; // Broken invariant: types not identical. +          break; +        case BinOpInit::EQ: +        case BinOpInit::NE: +          if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) && +              !ArgType->typeIsConvertibleTo(StringRecTy::get())) { +            Error(InitLoc, Twine("expected int, bits, or string; got value of " +                                 "type '") + ArgType->getAsString() + "'"); +            return nullptr; +          } +          break; +        default: llvm_unreachable("other ops have fixed argument types"); +        } +      } else { +        RecTy *Resolved = resolveTypes(ArgType, ListType); +        if (!Resolved) { +          Error(InitLoc, Twine("expected value of type '") + +                             ArgType->getAsString() + "', got '" + +                             ListType->getAsString() + "'"); +          return nullptr; +        } +        if (Code != BinOpInit::ADD && Code != BinOpInit::AND && +            Code != BinOpInit::OR && Code != BinOpInit::SRA && +            Code != BinOpInit::SRL && Code != BinOpInit::SHL && +            Code != BinOpInit::MUL) +          ArgType = Resolved; +      } + +      if (Lex.getCode() != tgtok::comma) +        break; +      Lex.Lex();  // eat the ',' +    } + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ')' + +    // listconcat returns a list with type of the argument. +    if (Code == BinOpInit::LISTCONCAT) +      Type = ArgType; +    // listsplat returns a list of type of the *first* argument. +    if (Code == BinOpInit::LISTSPLAT) +      Type = cast<TypedInit>(InitList.front())->getType()->getListTy(); + +    // We allow multiple operands to associative operators like !strconcat as +    // shorthand for nesting them. +    if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT || +        Code == BinOpInit::CONCAT || Code == BinOpInit::ADD || +        Code == BinOpInit::AND || Code == BinOpInit::OR || +        Code == BinOpInit::MUL) { +      while (InitList.size() > 2) { +        Init *RHS = InitList.pop_back_val(); +        RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))->Fold(CurRec); +        InitList.back() = RHS; +      } +    } + +    if (InitList.size() == 2) +      return (BinOpInit::get(Code, InitList[0], InitList[1], Type)) +          ->Fold(CurRec); + +    Error(OpLoc, "expected two operands to operator"); +    return nullptr; +  } + +  case tgtok::XForEach: { // Value ::= !foreach '(' Id ',' Value ',' Value ')' +    SMLoc OpLoc = Lex.getLoc(); +    Lex.Lex(); // eat the operation +    if (Lex.getCode() != tgtok::l_paren) { +      TokError("expected '(' after !foreach"); +      return nullptr; +    } + +    if (Lex.Lex() != tgtok::Id) { // eat the '(' +      TokError("first argument of !foreach must be an identifier"); +      return nullptr; +    } + +    Init *LHS = StringInit::get(Lex.getCurStrVal()); + +    if (CurRec && CurRec->getValue(LHS)) { +      TokError((Twine("iteration variable '") + LHS->getAsString() + +                "' already defined") +                   .str()); +      return nullptr; +    } + +    if (Lex.Lex() != tgtok::comma) { // eat the id +      TokError("expected ',' in ternary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ',' + +    Init *MHS = ParseValue(CurRec); +    if (!MHS) +      return nullptr; + +    if (Lex.getCode() != tgtok::comma) { +      TokError("expected ',' in ternary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ',' + +    TypedInit *MHSt = dyn_cast<TypedInit>(MHS); +    if (!MHSt) { +      TokError("could not get type of !foreach input"); +      return nullptr; +    } + +    RecTy *InEltType = nullptr; +    RecTy *OutEltType = nullptr; +    bool IsDAG = false; + +    if (ListRecTy *InListTy = dyn_cast<ListRecTy>(MHSt->getType())) { +      InEltType = InListTy->getElementType(); +      if (ItemType) { +        if (ListRecTy *OutListTy = dyn_cast<ListRecTy>(ItemType)) { +          OutEltType = OutListTy->getElementType(); +        } else { +          Error(OpLoc, +                "expected value of type '" + Twine(ItemType->getAsString()) + +                "', but got !foreach of list type"); +          return nullptr; +        } +      } +    } else if (DagRecTy *InDagTy = dyn_cast<DagRecTy>(MHSt->getType())) { +      InEltType = InDagTy; +      if (ItemType && !isa<DagRecTy>(ItemType)) { +        Error(OpLoc, +              "expected value of type '" + Twine(ItemType->getAsString()) + +              "', but got !foreach of dag type"); +        return nullptr; +      } +      IsDAG = true; +    } else { +      TokError("!foreach must have list or dag input"); +      return nullptr; +    } + +    // We need to create a temporary record to provide a scope for the iteration +    // variable while parsing top-level foreach's. +    std::unique_ptr<Record> ParseRecTmp; +    Record *ParseRec = CurRec; +    if (!ParseRec) { +      ParseRecTmp = std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records); +      ParseRec = ParseRecTmp.get(); +    } + +    ParseRec->addValue(RecordVal(LHS, InEltType, false)); +    Init *RHS = ParseValue(ParseRec, OutEltType); +    ParseRec->removeValue(LHS); +    if (!RHS) +      return nullptr; + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in binary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ')' + +    RecTy *OutType; +    if (IsDAG) { +      OutType = InEltType; +    } else { +      TypedInit *RHSt = dyn_cast<TypedInit>(RHS); +      if (!RHSt) { +        TokError("could not get type of !foreach result"); +        return nullptr; +      } +      OutType = RHSt->getType()->getListTy(); +    } + +    return (TernOpInit::get(TernOpInit::FOREACH, LHS, MHS, RHS, OutType)) +        ->Fold(CurRec); +  } + +  case tgtok::XDag: +  case tgtok::XIf: +  case tgtok::XSubst: {  // Value ::= !ternop '(' Value ',' Value ',' Value ')' +    TernOpInit::TernaryOp Code; +    RecTy *Type = nullptr; + +    tgtok::TokKind LexCode = Lex.getCode(); +    Lex.Lex();  // eat the operation +    switch (LexCode) { +    default: llvm_unreachable("Unhandled code!"); +    case tgtok::XDag: +      Code = TernOpInit::DAG; +      Type = DagRecTy::get(); +      ItemType = nullptr; +      break; +    case tgtok::XIf: +      Code = TernOpInit::IF; +      break; +    case tgtok::XSubst: +      Code = TernOpInit::SUBST; +      break; +    } +    if (Lex.getCode() != tgtok::l_paren) { +      TokError("expected '(' after ternary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the '(' + +    Init *LHS = ParseValue(CurRec); +    if (!LHS) return nullptr; + +    if (Lex.getCode() != tgtok::comma) { +      TokError("expected ',' in ternary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ',' + +    SMLoc MHSLoc = Lex.getLoc(); +    Init *MHS = ParseValue(CurRec, ItemType); +    if (!MHS) +      return nullptr; + +    if (Lex.getCode() != tgtok::comma) { +      TokError("expected ',' in ternary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ',' + +    SMLoc RHSLoc = Lex.getLoc(); +    Init *RHS = ParseValue(CurRec, ItemType); +    if (!RHS) +      return nullptr; + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in binary operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ')' + +    switch (LexCode) { +    default: llvm_unreachable("Unhandled code!"); +    case tgtok::XDag: { +      TypedInit *MHSt = dyn_cast<TypedInit>(MHS); +      if (!MHSt && !isa<UnsetInit>(MHS)) { +        Error(MHSLoc, "could not determine type of the child list in !dag"); +        return nullptr; +      } +      if (MHSt && !isa<ListRecTy>(MHSt->getType())) { +        Error(MHSLoc, Twine("expected list of children, got type '") + +                          MHSt->getType()->getAsString() + "'"); +        return nullptr; +      } + +      TypedInit *RHSt = dyn_cast<TypedInit>(RHS); +      if (!RHSt && !isa<UnsetInit>(RHS)) { +        Error(RHSLoc, "could not determine type of the name list in !dag"); +        return nullptr; +      } +      if (RHSt && StringRecTy::get()->getListTy() != RHSt->getType()) { +        Error(RHSLoc, Twine("expected list<string>, got type '") + +                          RHSt->getType()->getAsString() + "'"); +        return nullptr; +      } + +      if (!MHSt && !RHSt) { +        Error(MHSLoc, +              "cannot have both unset children and unset names in !dag"); +        return nullptr; +      } +      break; +    } +    case tgtok::XIf: { +      RecTy *MHSTy = nullptr; +      RecTy *RHSTy = nullptr; + +      if (TypedInit *MHSt = dyn_cast<TypedInit>(MHS)) +        MHSTy = MHSt->getType(); +      if (BitsInit *MHSbits = dyn_cast<BitsInit>(MHS)) +        MHSTy = BitsRecTy::get(MHSbits->getNumBits()); +      if (isa<BitInit>(MHS)) +        MHSTy = BitRecTy::get(); + +      if (TypedInit *RHSt = dyn_cast<TypedInit>(RHS)) +        RHSTy = RHSt->getType(); +      if (BitsInit *RHSbits = dyn_cast<BitsInit>(RHS)) +        RHSTy = BitsRecTy::get(RHSbits->getNumBits()); +      if (isa<BitInit>(RHS)) +        RHSTy = BitRecTy::get(); + +      // For UnsetInit, it's typed from the other hand. +      if (isa<UnsetInit>(MHS)) +        MHSTy = RHSTy; +      if (isa<UnsetInit>(RHS)) +        RHSTy = MHSTy; + +      if (!MHSTy || !RHSTy) { +        TokError("could not get type for !if"); +        return nullptr; +      } + +      Type = resolveTypes(MHSTy, RHSTy); +      if (!Type) { +        TokError(Twine("inconsistent types '") + MHSTy->getAsString() + +                 "' and '" + RHSTy->getAsString() + "' for !if"); +        return nullptr; +      } +      break; +    } +    case tgtok::XSubst: { +      TypedInit *RHSt = dyn_cast<TypedInit>(RHS); +      if (!RHSt) { +        TokError("could not get type for !subst"); +        return nullptr; +      } +      Type = RHSt->getType(); +      break; +    } +    } +    return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec); +  } + +  case tgtok::XCond: +    return ParseOperationCond(CurRec, ItemType); + +  case tgtok::XFoldl: { +    // Value ::= !foldl '(' Id ',' Id ',' Value ',' Value ',' Value ')' +    Lex.Lex(); // eat the operation +    if (Lex.getCode() != tgtok::l_paren) { +      TokError("expected '(' after !foldl"); +      return nullptr; +    } +    Lex.Lex(); // eat the '(' + +    Init *StartUntyped = ParseValue(CurRec); +    if (!StartUntyped) +      return nullptr; + +    TypedInit *Start = dyn_cast<TypedInit>(StartUntyped); +    if (!Start) { +      TokError(Twine("could not get type of !foldl start: '") + +               StartUntyped->getAsString() + "'"); +      return nullptr; +    } + +    if (Lex.getCode() != tgtok::comma) { +      TokError("expected ',' in !foldl"); +      return nullptr; +    } +    Lex.Lex(); // eat the ',' + +    Init *ListUntyped = ParseValue(CurRec); +    if (!ListUntyped) +      return nullptr; + +    TypedInit *List = dyn_cast<TypedInit>(ListUntyped); +    if (!List) { +      TokError(Twine("could not get type of !foldl list: '") + +               ListUntyped->getAsString() + "'"); +      return nullptr; +    } + +    ListRecTy *ListType = dyn_cast<ListRecTy>(List->getType()); +    if (!ListType) { +      TokError(Twine("!foldl list must be a list, but is of type '") + +               List->getType()->getAsString()); +      return nullptr; +    } + +    if (Lex.getCode() != tgtok::comma) { +      TokError("expected ',' in !foldl"); +      return nullptr; +    } + +    if (Lex.Lex() != tgtok::Id) { // eat the ',' +      TokError("third argument of !foldl must be an identifier"); +      return nullptr; +    } + +    Init *A = StringInit::get(Lex.getCurStrVal()); +    if (CurRec && CurRec->getValue(A)) { +      TokError((Twine("left !foldl variable '") + A->getAsString() + +                "' already defined") +                   .str()); +      return nullptr; +    } + +    if (Lex.Lex() != tgtok::comma) { // eat the id +      TokError("expected ',' in !foldl"); +      return nullptr; +    } + +    if (Lex.Lex() != tgtok::Id) { // eat the ',' +      TokError("fourth argument of !foldl must be an identifier"); +      return nullptr; +    } + +    Init *B = StringInit::get(Lex.getCurStrVal()); +    if (CurRec && CurRec->getValue(B)) { +      TokError((Twine("right !foldl variable '") + B->getAsString() + +                "' already defined") +                   .str()); +      return nullptr; +    } + +    if (Lex.Lex() != tgtok::comma) { // eat the id +      TokError("expected ',' in !foldl"); +      return nullptr; +    } +    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. +    std::unique_ptr<Record> ParseRecTmp; +    Record *ParseRec = CurRec; +    if (!ParseRec) { +      ParseRecTmp = std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records); +      ParseRec = ParseRecTmp.get(); +    } + +    ParseRec->addValue(RecordVal(A, Start->getType(), false)); +    ParseRec->addValue(RecordVal(B, ListType->getElementType(), false)); +    Init *ExprUntyped = ParseValue(ParseRec); +    ParseRec->removeValue(A); +    ParseRec->removeValue(B); +    if (!ExprUntyped) +      return nullptr; + +    TypedInit *Expr = dyn_cast<TypedInit>(ExprUntyped); +    if (!Expr) { +      TokError("could not get type of !foldl expression"); +      return nullptr; +    } + +    if (Expr->getType() != Start->getType()) { +      TokError(Twine("!foldl expression must be of same type as start (") + +               Start->getType()->getAsString() + "), but is of type " + +               Expr->getType()->getAsString()); +      return nullptr; +    } + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in fold operator"); +      return nullptr; +    } +    Lex.Lex(); // eat the ')' + +    return FoldOpInit::get(Start, List, A, B, Expr, Start->getType()) +        ->Fold(CurRec); +  } +  } +} + +/// ParseOperatorType - Parse a type for an operator.  This returns +/// null on error. +/// +/// OperatorType ::= '<' Type '>' +/// +RecTy *TGParser::ParseOperatorType() { +  RecTy *Type = nullptr; + +  if (Lex.getCode() != tgtok::less) { +    TokError("expected type name for operator"); +    return nullptr; +  } +  Lex.Lex();  // eat the < + +  Type = ParseType(); + +  if (!Type) { +    TokError("expected type name for operator"); +    return nullptr; +  } + +  if (Lex.getCode() != tgtok::greater) { +    TokError("expected type name for operator"); +    return nullptr; +  } +  Lex.Lex();  // eat the > + +  return Type; +} + +Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) { +  Lex.Lex();  // eat the operation 'cond' + +  if (Lex.getCode() != tgtok::l_paren) { +     TokError("expected '(' after !cond operator"); +     return nullptr; +  } +  Lex.Lex();  // eat the '(' + +  // Parse through '[Case: Val,]+' +  SmallVector<Init *, 4> Case; +  SmallVector<Init *, 4> Val; +  while (true) { +    if (Lex.getCode() == tgtok::r_paren) { +      Lex.Lex(); // eat the ')' +      break; +    } + +    Init *V = ParseValue(CurRec); +    if (!V) +      return nullptr; +    Case.push_back(V); + +    if (Lex.getCode() != tgtok::colon) { +      TokError("expected ':'  following a condition in !cond operator"); +      return nullptr; +    } +    Lex.Lex(); // eat the ':' + +    V = ParseValue(CurRec, ItemType); +    if (!V) +      return nullptr; +    Val.push_back(V); + +    if (Lex.getCode() == tgtok::r_paren) { +      Lex.Lex(); // eat the ')' +      break; +    } + +    if (Lex.getCode() != tgtok::comma) { +      TokError("expected ',' or ')' following a value in !cond operator"); +      return nullptr; +    } +    Lex.Lex();  // eat the ',' +  } + +  if (Case.size() < 1) { +    TokError("there should be at least 1 'condition : value' in the !cond operator"); +    return nullptr; +  } + +  // resolve type +  RecTy *Type = nullptr; +  for (Init *V : Val) { +    RecTy *VTy = nullptr; +    if (TypedInit *Vt = dyn_cast<TypedInit>(V)) +      VTy = Vt->getType(); +    if (BitsInit *Vbits = dyn_cast<BitsInit>(V)) +      VTy = BitsRecTy::get(Vbits->getNumBits()); +    if (isa<BitInit>(V)) +      VTy = BitRecTy::get(); + +    if (Type == nullptr) { +      if (!isa<UnsetInit>(V)) +        Type = VTy; +    } else { +      if (!isa<UnsetInit>(V)) { +        RecTy *RType = resolveTypes(Type, VTy); +        if (!RType) { +          TokError(Twine("inconsistent types '") + Type->getAsString() + +                         "' and '" + VTy->getAsString() + "' for !cond"); +          return nullptr; +        } +        Type = RType; +      } +    } +  } + +  if (!Type) { +    TokError("could not determine type for !cond from its arguments"); +    return nullptr; +  } +  return CondOpInit::get(Case, Val, Type)->Fold(CurRec); +} + +/// ParseSimpleValue - Parse a tblgen value.  This returns null on error. +/// +///   SimpleValue ::= IDValue +///   SimpleValue ::= INTVAL +///   SimpleValue ::= STRVAL+ +///   SimpleValue ::= CODEFRAGMENT +///   SimpleValue ::= '?' +///   SimpleValue ::= '{' ValueList '}' +///   SimpleValue ::= ID '<' ValueListNE '>' +///   SimpleValue ::= '[' ValueList ']' +///   SimpleValue ::= '(' IDValue DagArgList ')' +///   SimpleValue ::= CONCATTOK '(' Value ',' Value ')' +///   SimpleValue ::= ADDTOK '(' Value ',' Value ')' +///   SimpleValue ::= SHLTOK '(' Value ',' Value ')' +///   SimpleValue ::= SRATOK '(' Value ',' Value ')' +///   SimpleValue ::= SRLTOK '(' Value ',' Value ')' +///   SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')' +///   SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')' +///   SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' +///   SimpleValue ::= COND '(' [Value ':' Value,]+ ')' +/// +Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, +                                 IDParseMode Mode) { +  Init *R = nullptr; +  switch (Lex.getCode()) { +  default: TokError("Unknown token when parsing a value"); break; +  case tgtok::paste: +    // This is a leading paste operation.  This is deprecated but +    // still exists in some .td files.  Ignore it. +    Lex.Lex();  // Skip '#'. +    return ParseSimpleValue(CurRec, ItemType, Mode); +  case tgtok::IntVal: R = IntInit::get(Lex.getCurIntVal()); Lex.Lex(); break; +  case tgtok::BinaryIntVal: { +    auto BinaryVal = Lex.getCurBinaryIntVal(); +    SmallVector<Init*, 16> Bits(BinaryVal.second); +    for (unsigned i = 0, e = BinaryVal.second; i != e; ++i) +      Bits[i] = BitInit::get(BinaryVal.first & (1LL << i)); +    R = BitsInit::get(Bits); +    Lex.Lex(); +    break; +  } +  case tgtok::StrVal: { +    std::string Val = Lex.getCurStrVal(); +    Lex.Lex(); + +    // Handle multiple consecutive concatenated strings. +    while (Lex.getCode() == tgtok::StrVal) { +      Val += Lex.getCurStrVal(); +      Lex.Lex(); +    } + +    R = StringInit::get(Val); +    break; +  } +  case tgtok::CodeFragment: +    R = CodeInit::get(Lex.getCurStrVal(), Lex.getLoc()); +    Lex.Lex(); +    break; +  case tgtok::question: +    R = UnsetInit::get(); +    Lex.Lex(); +    break; +  case tgtok::Id: { +    SMLoc NameLoc = Lex.getLoc(); +    StringInit *Name = StringInit::get(Lex.getCurStrVal()); +    if (Lex.Lex() != tgtok::less)  // consume the Id. +      return ParseIDValue(CurRec, Name, NameLoc, Mode);    // Value ::= IDValue + +    // Value ::= ID '<' ValueListNE '>' +    if (Lex.Lex() == tgtok::greater) { +      TokError("expected non-empty value list"); +      return nullptr; +    } + +    // This is a CLASS<initvalslist> expression.  This is supposed to synthesize +    // a new anonymous definition, deriving from CLASS<initvalslist> with no +    // body. +    Record *Class = Records.getClass(Name->getValue()); +    if (!Class) { +      Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'"); +      return nullptr; +    } + +    SmallVector<Init *, 8> Args; +    ParseValueList(Args, CurRec, Class); +    if (Args.empty()) return nullptr; + +    if (Lex.getCode() != tgtok::greater) { +      TokError("expected '>' at end of value list"); +      return nullptr; +    } +    Lex.Lex();  // eat the '>' + +    // Typecheck the template arguments list +    ArrayRef<Init *> ExpectedArgs = Class->getTemplateArgs(); +    if (ExpectedArgs.size() < Args.size()) { +      Error(NameLoc, +            "More template args specified than expected"); +      return nullptr; +    } + +    for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) { +      RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]); +      if (i < Args.size()) { +        if (TypedInit *TI = dyn_cast<TypedInit>(Args[i])) { +          RecTy *ExpectedType = ExpectedArg->getType(); +          if (!TI->getType()->typeIsConvertibleTo(ExpectedType)) { +            Error(NameLoc, +                  "Value specified for template argument #" + Twine(i) + " (" + +                  ExpectedArg->getNameInitAsString() + ") is of type '" + +                  TI->getType()->getAsString() + "', expected '" + +                  ExpectedType->getAsString() + "': " + TI->getAsString()); +            return nullptr; +          } +          continue; +        } +      } else if (ExpectedArg->getValue()->isComplete()) +        continue; + +      Error(NameLoc, +            "Value not specified for template argument #" + Twine(i) + " (" + +            ExpectedArgs[i]->getAsUnquotedString() + ")"); +      return nullptr; +    } + +    return VarDefInit::get(Class, Args)->Fold(); +  } +  case tgtok::l_brace: {           // Value ::= '{' ValueList '}' +    SMLoc BraceLoc = Lex.getLoc(); +    Lex.Lex(); // eat the '{' +    SmallVector<Init*, 16> Vals; + +    if (Lex.getCode() != tgtok::r_brace) { +      ParseValueList(Vals, CurRec); +      if (Vals.empty()) return nullptr; +    } +    if (Lex.getCode() != tgtok::r_brace) { +      TokError("expected '}' at end of bit list value"); +      return nullptr; +    } +    Lex.Lex();  // eat the '}' + +    SmallVector<Init *, 16> NewBits; + +    // As we parse { a, b, ... }, 'a' is the highest bit, but we parse it +    // first.  We'll first read everything in to a vector, then we can reverse +    // it to get the bits in the correct order for the BitsInit value. +    for (unsigned i = 0, e = Vals.size(); i != e; ++i) { +      // FIXME: The following two loops would not be duplicated +      //        if the API was a little more orthogonal. + +      // bits<n> values are allowed to initialize n bits. +      if (BitsInit *BI = dyn_cast<BitsInit>(Vals[i])) { +        for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) +          NewBits.push_back(BI->getBit((e - i) - 1)); +        continue; +      } +      // bits<n> can also come from variable initializers. +      if (VarInit *VI = dyn_cast<VarInit>(Vals[i])) { +        if (BitsRecTy *BitsRec = dyn_cast<BitsRecTy>(VI->getType())) { +          for (unsigned i = 0, e = BitsRec->getNumBits(); i != e; ++i) +            NewBits.push_back(VI->getBit((e - i) - 1)); +          continue; +        } +        // Fallthrough to try convert this to a bit. +      } +      // All other values must be convertible to just a single bit. +      Init *Bit = Vals[i]->getCastTo(BitRecTy::get()); +      if (!Bit) { +        Error(BraceLoc, "Element #" + Twine(i) + " (" + Vals[i]->getAsString() + +              ") is not convertable to a bit"); +        return nullptr; +      } +      NewBits.push_back(Bit); +    } +    std::reverse(NewBits.begin(), NewBits.end()); +    return BitsInit::get(NewBits); +  } +  case tgtok::l_square: {          // Value ::= '[' ValueList ']' +    Lex.Lex(); // eat the '[' +    SmallVector<Init*, 16> Vals; + +    RecTy *DeducedEltTy = nullptr; +    ListRecTy *GivenListTy = nullptr; + +    if (ItemType) { +      ListRecTy *ListType = dyn_cast<ListRecTy>(ItemType); +      if (!ListType) { +        TokError(Twine("Type mismatch for list, expected list type, got ") + +                 ItemType->getAsString()); +        return nullptr; +      } +      GivenListTy = ListType; +    } + +    if (Lex.getCode() != tgtok::r_square) { +      ParseValueList(Vals, CurRec, nullptr, +                     GivenListTy ? GivenListTy->getElementType() : nullptr); +      if (Vals.empty()) return nullptr; +    } +    if (Lex.getCode() != tgtok::r_square) { +      TokError("expected ']' at end of list value"); +      return nullptr; +    } +    Lex.Lex();  // eat the ']' + +    RecTy *GivenEltTy = nullptr; +    if (Lex.getCode() == tgtok::less) { +      // Optional list element type +      Lex.Lex();  // eat the '<' + +      GivenEltTy = ParseType(); +      if (!GivenEltTy) { +        // Couldn't parse element type +        return nullptr; +      } + +      if (Lex.getCode() != tgtok::greater) { +        TokError("expected '>' at end of list element type"); +        return nullptr; +      } +      Lex.Lex();  // eat the '>' +    } + +    // Check elements +    RecTy *EltTy = nullptr; +    for (Init *V : Vals) { +      TypedInit *TArg = dyn_cast<TypedInit>(V); +      if (TArg) { +        if (EltTy) { +          EltTy = resolveTypes(EltTy, TArg->getType()); +          if (!EltTy) { +            TokError("Incompatible types in list elements"); +            return nullptr; +          } +        } else { +          EltTy = TArg->getType(); +        } +      } +    } + +    if (GivenEltTy) { +      if (EltTy) { +        // Verify consistency +        if (!EltTy->typeIsConvertibleTo(GivenEltTy)) { +          TokError("Incompatible types in list elements"); +          return nullptr; +        } +      } +      EltTy = GivenEltTy; +    } + +    if (!EltTy) { +      if (!ItemType) { +        TokError("No type for list"); +        return nullptr; +      } +      DeducedEltTy = GivenListTy->getElementType(); +    } else { +      // Make sure the deduced type is compatible with the given type +      if (GivenListTy) { +        if (!EltTy->typeIsConvertibleTo(GivenListTy->getElementType())) { +          TokError(Twine("Element type mismatch for list: element type '") + +                   EltTy->getAsString() + "' not convertible to '" + +                   GivenListTy->getElementType()->getAsString()); +          return nullptr; +        } +      } +      DeducedEltTy = EltTy; +    } + +    return ListInit::get(Vals, DeducedEltTy); +  } +  case tgtok::l_paren: {         // Value ::= '(' IDValue DagArgList ')' +    Lex.Lex();   // eat the '(' +    if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast) { +      TokError("expected identifier in dag init"); +      return nullptr; +    } + +    Init *Operator = ParseValue(CurRec); +    if (!Operator) return nullptr; + +    // If the operator name is present, parse it. +    StringInit *OperatorName = nullptr; +    if (Lex.getCode() == tgtok::colon) { +      if (Lex.Lex() != tgtok::VarName) { // eat the ':' +        TokError("expected variable name in dag operator"); +        return nullptr; +      } +      OperatorName = StringInit::get(Lex.getCurStrVal()); +      Lex.Lex();  // eat the VarName. +    } + +    SmallVector<std::pair<llvm::Init*, StringInit*>, 8> DagArgs; +    if (Lex.getCode() != tgtok::r_paren) { +      ParseDagArgList(DagArgs, CurRec); +      if (DagArgs.empty()) return nullptr; +    } + +    if (Lex.getCode() != tgtok::r_paren) { +      TokError("expected ')' in dag init"); +      return nullptr; +    } +    Lex.Lex();  // eat the ')' + +    return DagInit::get(Operator, OperatorName, DagArgs); +  } + +  case tgtok::XHead: +  case tgtok::XTail: +  case tgtok::XSize: +  case tgtok::XEmpty: +  case tgtok::XCast:  // Value ::= !unop '(' Value ')' +  case tgtok::XIsA: +  case tgtok::XConcat: +  case tgtok::XDag: +  case tgtok::XADD: +  case tgtok::XMUL: +  case tgtok::XAND: +  case tgtok::XOR: +  case tgtok::XSRA: +  case tgtok::XSRL: +  case tgtok::XSHL: +  case tgtok::XEq: +  case tgtok::XNe: +  case tgtok::XLe: +  case tgtok::XLt: +  case tgtok::XGe: +  case tgtok::XGt: +  case tgtok::XListConcat: +  case tgtok::XListSplat: +  case tgtok::XStrConcat:   // Value ::= !binop '(' Value ',' Value ')' +  case tgtok::XIf: +  case tgtok::XCond: +  case tgtok::XFoldl: +  case tgtok::XForEach: +  case tgtok::XSubst: {  // Value ::= !ternop '(' Value ',' Value ',' Value ')' +    return ParseOperation(CurRec, ItemType); +  } +  } + +  return R; +} + +/// ParseValue - Parse a tblgen value.  This returns null on error. +/// +///   Value       ::= SimpleValue ValueSuffix* +///   ValueSuffix ::= '{' BitList '}' +///   ValueSuffix ::= '[' BitList ']' +///   ValueSuffix ::= '.' ID +/// +Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { +  Init *Result = ParseSimpleValue(CurRec, ItemType, Mode); +  if (!Result) return nullptr; + +  // Parse the suffixes now if present. +  while (true) { +    switch (Lex.getCode()) { +    default: return Result; +    case tgtok::l_brace: { +      if (Mode == ParseNameMode) +        // This is the beginning of the object body. +        return Result; + +      SMLoc CurlyLoc = Lex.getLoc(); +      Lex.Lex(); // eat the '{' +      SmallVector<unsigned, 16> Ranges; +      ParseRangeList(Ranges); +      if (Ranges.empty()) return nullptr; + +      // Reverse the bitlist. +      std::reverse(Ranges.begin(), Ranges.end()); +      Result = Result->convertInitializerBitRange(Ranges); +      if (!Result) { +        Error(CurlyLoc, "Invalid bit range for value"); +        return nullptr; +      } + +      // Eat the '}'. +      if (Lex.getCode() != tgtok::r_brace) { +        TokError("expected '}' at end of bit range list"); +        return nullptr; +      } +      Lex.Lex(); +      break; +    } +    case tgtok::l_square: { +      SMLoc SquareLoc = Lex.getLoc(); +      Lex.Lex(); // eat the '[' +      SmallVector<unsigned, 16> Ranges; +      ParseRangeList(Ranges); +      if (Ranges.empty()) return nullptr; + +      Result = Result->convertInitListSlice(Ranges); +      if (!Result) { +        Error(SquareLoc, "Invalid range for list slice"); +        return nullptr; +      } + +      // Eat the ']'. +      if (Lex.getCode() != tgtok::r_square) { +        TokError("expected ']' at end of list slice"); +        return nullptr; +      } +      Lex.Lex(); +      break; +    } +    case tgtok::period: { +      if (Lex.Lex() != tgtok::Id) {  // eat the . +        TokError("expected field identifier after '.'"); +        return nullptr; +      } +      StringInit *FieldName = StringInit::get(Lex.getCurStrVal()); +      if (!Result->getFieldType(FieldName)) { +        TokError("Cannot access field '" + Lex.getCurStrVal() + "' of value '" + +                 Result->getAsString() + "'"); +        return nullptr; +      } +      Result = FieldInit::get(Result, FieldName)->Fold(CurRec); +      Lex.Lex();  // eat field name +      break; +    } + +    case tgtok::paste: +      SMLoc PasteLoc = Lex.getLoc(); +      TypedInit *LHS = dyn_cast<TypedInit>(Result); +      if (!LHS) { +        Error(PasteLoc, "LHS of paste is not typed!"); +        return nullptr; +      } + +      // Check if it's a 'listA # listB' +      if (isa<ListRecTy>(LHS->getType())) { +        Lex.Lex();  // Eat the '#'. + +        switch (Lex.getCode()) { +        case tgtok::colon: +        case tgtok::semi: +        case tgtok::l_brace: +          Result = LHS; // trailing paste, ignore. +          break; +        default: +          Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode); +          Result = BinOpInit::getListConcat(LHS, RHSResult); +        } +        break; +      } + +      // Create a !strconcat() operation, first casting each operand to +      // a string if necessary. +      if (LHS->getType() != StringRecTy::get()) { +        auto CastLHS = dyn_cast<TypedInit>( +            UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get()) +                ->Fold(CurRec)); +        if (!CastLHS) { +          Error(PasteLoc, +                Twine("can't cast '") + LHS->getAsString() + "' to string"); +          return nullptr; +        } +        LHS = CastLHS; +      } + +      TypedInit *RHS = nullptr; + +      Lex.Lex();  // Eat the '#'. +      switch (Lex.getCode()) { +      case tgtok::colon: +      case tgtok::semi: +      case tgtok::l_brace: +        // These are all of the tokens that can begin an object body. +        // Some of these can also begin values but we disallow those cases +        // because they are unlikely to be useful. + +        // Trailing paste, concat with an empty string. +        RHS = StringInit::get(""); +        break; + +      default: +        Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode); +        RHS = dyn_cast<TypedInit>(RHSResult); +        if (!RHS) { +          Error(PasteLoc, "RHS of paste is not typed!"); +          return nullptr; +        } + +        if (RHS->getType() != StringRecTy::get()) { +          auto CastRHS = dyn_cast<TypedInit>( +              UnOpInit::get(UnOpInit::CAST, RHS, StringRecTy::get()) +                  ->Fold(CurRec)); +          if (!CastRHS) { +            Error(PasteLoc, +                  Twine("can't cast '") + RHS->getAsString() + "' to string"); +            return nullptr; +          } +          RHS = CastRHS; +        } + +        break; +      } + +      Result = BinOpInit::getStrConcat(LHS, RHS); +      break; +    } +  } +} + +/// ParseDagArgList - Parse the argument list for a dag literal expression. +/// +///    DagArg     ::= Value (':' VARNAME)? +///    DagArg     ::= VARNAME +///    DagArgList ::= DagArg +///    DagArgList ::= DagArgList ',' DagArg +void TGParser::ParseDagArgList( +    SmallVectorImpl<std::pair<llvm::Init*, StringInit*>> &Result, +    Record *CurRec) { + +  while (true) { +    // DagArg ::= VARNAME +    if (Lex.getCode() == tgtok::VarName) { +      // A missing value is treated like '?'. +      StringInit *VarName = StringInit::get(Lex.getCurStrVal()); +      Result.emplace_back(UnsetInit::get(), VarName); +      Lex.Lex(); +    } else { +      // DagArg ::= Value (':' VARNAME)? +      Init *Val = ParseValue(CurRec); +      if (!Val) { +        Result.clear(); +        return; +      } + +      // If the variable name is present, add it. +      StringInit *VarName = nullptr; +      if (Lex.getCode() == tgtok::colon) { +        if (Lex.Lex() != tgtok::VarName) { // eat the ':' +          TokError("expected variable name in dag literal"); +          Result.clear(); +          return; +        } +        VarName = StringInit::get(Lex.getCurStrVal()); +        Lex.Lex();  // eat the VarName. +      } + +      Result.push_back(std::make_pair(Val, VarName)); +    } +    if (Lex.getCode() != tgtok::comma) break; +    Lex.Lex(); // eat the ',' +  } +} + +/// ParseValueList - Parse a comma separated list of values, returning them as a +/// vector.  Note that this always expects to be able to parse at least one +/// value.  It returns an empty list if this is not possible. +/// +///   ValueList ::= Value (',' Value) +/// +void TGParser::ParseValueList(SmallVectorImpl<Init*> &Result, Record *CurRec, +                              Record *ArgsRec, RecTy *EltTy) { +  RecTy *ItemType = EltTy; +  unsigned int ArgN = 0; +  if (ArgsRec && !EltTy) { +    ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs(); +    if (TArgs.empty()) { +      TokError("template argument provided to non-template class"); +      Result.clear(); +      return; +    } +    const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]); +    if (!RV) { +      errs() << "Cannot find template arg " << ArgN << " (" << TArgs[ArgN] +        << ")\n"; +    } +    assert(RV && "Template argument record not found??"); +    ItemType = RV->getType(); +    ++ArgN; +  } +  Result.push_back(ParseValue(CurRec, ItemType)); +  if (!Result.back()) { +    Result.clear(); +    return; +  } + +  while (Lex.getCode() == tgtok::comma) { +    Lex.Lex();  // Eat the comma + +    // ignore trailing comma for lists +    if (Lex.getCode() == tgtok::r_square) +      return; + +    if (ArgsRec && !EltTy) { +      ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs(); +      if (ArgN >= TArgs.size()) { +        TokError("too many template arguments"); +        Result.clear(); +        return; +      } +      const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]); +      assert(RV && "Template argument record not found??"); +      ItemType = RV->getType(); +      ++ArgN; +    } +    Result.push_back(ParseValue(CurRec, ItemType)); +    if (!Result.back()) { +      Result.clear(); +      return; +    } +  } +} + +/// ParseDeclaration - Read a declaration, returning the name of field ID, or an +/// empty string on error.  This can happen in a number of different context's, +/// including within a def or in the template args for a def (which which case +/// CurRec will be non-null) and within the template args for a multiclass (in +/// which case CurRec will be null, but CurMultiClass will be set).  This can +/// also happen within a def that is within a multiclass, which will set both +/// CurRec and CurMultiClass. +/// +///  Declaration ::= FIELD? Type ID ('=' Value)? +/// +Init *TGParser::ParseDeclaration(Record *CurRec, +                                       bool ParsingTemplateArgs) { +  // Read the field prefix if present. +  bool HasField = Lex.getCode() == tgtok::Field; +  if (HasField) Lex.Lex(); + +  RecTy *Type = ParseType(); +  if (!Type) return nullptr; + +  if (Lex.getCode() != tgtok::Id) { +    TokError("Expected identifier in declaration"); +    return nullptr; +  } + +  std::string Str = Lex.getCurStrVal(); +  if (Str == "NAME") { +    TokError("'" + Str + "' is a reserved variable name"); +    return nullptr; +  } + +  SMLoc IdLoc = Lex.getLoc(); +  Init *DeclName = StringInit::get(Str); +  Lex.Lex(); + +  if (ParsingTemplateArgs) { +    if (CurRec) +      DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":"); +    else +      assert(CurMultiClass); +    if (CurMultiClass) +      DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName, +                             "::"); +  } + +  // Add the value. +  if (AddValue(CurRec, IdLoc, RecordVal(DeclName, Type, HasField))) +    return nullptr; + +  // If a value is present, parse it. +  if (Lex.getCode() == tgtok::equal) { +    Lex.Lex(); +    SMLoc ValLoc = Lex.getLoc(); +    Init *Val = ParseValue(CurRec, Type); +    if (!Val || +        SetValue(CurRec, ValLoc, DeclName, None, Val)) +      // Return the name, even if an error is thrown.  This is so that we can +      // continue to make some progress, even without the value having been +      // initialized. +      return DeclName; +  } + +  return DeclName; +} + +/// ParseForeachDeclaration - Read a foreach declaration, returning +/// the name of the declared object or a NULL Init on error.  Return +/// the name of the parsed initializer list through ForeachListName. +/// +///  ForeachDeclaration ::= ID '=' '{' RangeList '}' +///  ForeachDeclaration ::= ID '=' RangePiece +///  ForeachDeclaration ::= ID '=' Value +/// +VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) { +  if (Lex.getCode() != tgtok::Id) { +    TokError("Expected identifier in foreach declaration"); +    return nullptr; +  } + +  Init *DeclName = StringInit::get(Lex.getCurStrVal()); +  Lex.Lex(); + +  // If a value is present, parse it. +  if (Lex.getCode() != tgtok::equal) { +    TokError("Expected '=' in foreach declaration"); +    return nullptr; +  } +  Lex.Lex();  // Eat the '=' + +  RecTy *IterType = nullptr; +  SmallVector<unsigned, 16> Ranges; + +  switch (Lex.getCode()) { +  case tgtok::l_brace: { // '{' RangeList '}' +    Lex.Lex(); // eat the '{' +    ParseRangeList(Ranges); +    if (Lex.getCode() != tgtok::r_brace) { +      TokError("expected '}' at end of bit range list"); +      return nullptr; +    } +    Lex.Lex(); +    break; +  } + +  default: { +    SMLoc ValueLoc = Lex.getLoc(); +    Init *I = ParseValue(nullptr); +    if (!I) +      return nullptr; + +    TypedInit *TI = dyn_cast<TypedInit>(I); +    if (TI && isa<ListRecTy>(TI->getType())) { +      ForeachListValue = I; +      IterType = cast<ListRecTy>(TI->getType())->getElementType(); +      break; +    } + +    if (TI) { +      if (ParseRangePiece(Ranges, TI)) +        return nullptr; +      break; +    } + +    std::string Type; +    if (TI) +      Type = (Twine("' of type '") + TI->getType()->getAsString()).str(); +    Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'"); +    if (CurMultiClass) { +      PrintNote({}, "references to multiclass template arguments cannot be " +                "resolved at this time"); +    } +    return nullptr; +  } +  } + + +  if (!Ranges.empty()) { +    assert(!IterType && "Type already initialized?"); +    IterType = IntRecTy::get(); +    std::vector<Init*> Values; +    for (unsigned R : Ranges) +      Values.push_back(IntInit::get(R)); +    ForeachListValue = ListInit::get(Values, IterType); +  } + +  if (!IterType) +    return nullptr; + +  return VarInit::get(DeclName, IterType); +} + +/// ParseTemplateArgList - Read a template argument list, which is a non-empty +/// sequence of template-declarations in <>'s.  If CurRec is non-null, these are +/// template args for a def, which may or may not be in a multiclass.  If null, +/// these are the template args for a multiclass. +/// +///    TemplateArgList ::= '<' Declaration (',' Declaration)* '>' +/// +bool TGParser::ParseTemplateArgList(Record *CurRec) { +  assert(Lex.getCode() == tgtok::less && "Not a template arg list!"); +  Lex.Lex(); // eat the '<' + +  Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec; + +  // Read the first declaration. +  Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/); +  if (!TemplArg) +    return true; + +  TheRecToAddTo->addTemplateArg(TemplArg); + +  while (Lex.getCode() == tgtok::comma) { +    Lex.Lex(); // eat the ',' + +    // Read the following declarations. +    SMLoc Loc = Lex.getLoc(); +    TemplArg = ParseDeclaration(CurRec, true/*templateargs*/); +    if (!TemplArg) +      return true; + +    if (TheRecToAddTo->isTemplateArg(TemplArg)) +      return Error(Loc, "template argument with the same name has already been " +                        "defined"); + +    TheRecToAddTo->addTemplateArg(TemplArg); +  } + +  if (Lex.getCode() != tgtok::greater) +    return TokError("expected '>' at end of template argument list"); +  Lex.Lex(); // eat the '>'. +  return false; +} + +/// ParseBodyItem - Parse a single item at within the body of a def or class. +/// +///   BodyItem ::= Declaration ';' +///   BodyItem ::= LET ID OptionalBitList '=' Value ';' +bool TGParser::ParseBodyItem(Record *CurRec) { +  if (Lex.getCode() != tgtok::Let) { +    if (!ParseDeclaration(CurRec, false)) +      return true; + +    if (Lex.getCode() != tgtok::semi) +      return TokError("expected ';' after declaration"); +    Lex.Lex(); +    return false; +  } + +  // LET ID OptionalRangeList '=' Value ';' +  if (Lex.Lex() != tgtok::Id) +    return TokError("expected field identifier after let"); + +  SMLoc IdLoc = Lex.getLoc(); +  StringInit *FieldName = StringInit::get(Lex.getCurStrVal()); +  Lex.Lex();  // eat the field name. + +  SmallVector<unsigned, 16> BitList; +  if (ParseOptionalBitList(BitList)) +    return true; +  std::reverse(BitList.begin(), BitList.end()); + +  if (Lex.getCode() != tgtok::equal) +    return TokError("expected '=' in let expression"); +  Lex.Lex();  // eat the '='. + +  RecordVal *Field = CurRec->getValue(FieldName); +  if (!Field) +    return TokError("Value '" + FieldName->getValue() + "' unknown!"); + +  RecTy *Type = Field->getType(); + +  Init *Val = ParseValue(CurRec, Type); +  if (!Val) return true; + +  if (Lex.getCode() != tgtok::semi) +    return TokError("expected ';' after let expression"); +  Lex.Lex(); + +  return SetValue(CurRec, IdLoc, FieldName, BitList, Val); +} + +/// ParseBody - Read the body of a class or def.  Return true on error, false on +/// success. +/// +///   Body     ::= ';' +///   Body     ::= '{' BodyList '}' +///   BodyList BodyItem* +/// +bool TGParser::ParseBody(Record *CurRec) { +  // If this is a null definition, just eat the semi and return. +  if (Lex.getCode() == tgtok::semi) { +    Lex.Lex(); +    return false; +  } + +  if (Lex.getCode() != tgtok::l_brace) +    return TokError("Expected ';' or '{' to start body"); +  // Eat the '{'. +  Lex.Lex(); + +  while (Lex.getCode() != tgtok::r_brace) +    if (ParseBodyItem(CurRec)) +      return true; + +  // Eat the '}'. +  Lex.Lex(); +  return false; +} + +/// Apply the current let bindings to \a CurRec. +/// \returns true on error, false otherwise. +bool TGParser::ApplyLetStack(Record *CurRec) { +  for (SmallVectorImpl<LetRecord> &LetInfo : LetStack) +    for (LetRecord &LR : LetInfo) +      if (SetValue(CurRec, LR.Loc, LR.Name, LR.Bits, LR.Value)) +        return true; +  return false; +} + +bool TGParser::ApplyLetStack(RecordsEntry &Entry) { +  if (Entry.Rec) +    return ApplyLetStack(Entry.Rec.get()); + +  for (auto &E : Entry.Loop->Entries) { +    if (ApplyLetStack(E)) +      return true; +  } + +  return false; +} + +/// ParseObjectBody - Parse the body of a def or class.  This consists of an +/// optional ClassList followed by a Body.  CurRec is the current def or class +/// that is being parsed. +/// +///   ObjectBody      ::= BaseClassList Body +///   BaseClassList   ::= /*empty*/ +///   BaseClassList   ::= ':' BaseClassListNE +///   BaseClassListNE ::= SubClassRef (',' SubClassRef)* +/// +bool TGParser::ParseObjectBody(Record *CurRec) { +  // If there is a baseclass list, read it. +  if (Lex.getCode() == tgtok::colon) { +    Lex.Lex(); + +    // Read all of the subclasses. +    SubClassReference SubClass = ParseSubClassReference(CurRec, false); +    while (true) { +      // Check for error. +      if (!SubClass.Rec) return true; + +      // Add it. +      if (AddSubClass(CurRec, SubClass)) +        return true; + +      if (Lex.getCode() != tgtok::comma) break; +      Lex.Lex(); // eat ','. +      SubClass = ParseSubClassReference(CurRec, false); +    } +  } + +  if (ApplyLetStack(CurRec)) +    return true; + +  return ParseBody(CurRec); +} + +/// ParseDef - Parse and return a top level or multiclass def, return the record +/// corresponding to it.  This returns null on error. +/// +///   DefInst ::= DEF ObjectName ObjectBody +/// +bool TGParser::ParseDef(MultiClass *CurMultiClass) { +  SMLoc DefLoc = Lex.getLoc(); +  assert(Lex.getCode() == tgtok::Def && "Unknown tok"); +  Lex.Lex();  // Eat the 'def' token. + +  // Parse ObjectName and make a record for it. +  std::unique_ptr<Record> CurRec; +  Init *Name = ParseObjectName(CurMultiClass); +  if (!Name) +    return true; + +  if (isa<UnsetInit>(Name)) +    CurRec = std::make_unique<Record>(Records.getNewAnonymousName(), DefLoc, Records, +                                 /*Anonymous=*/true); +  else +    CurRec = std::make_unique<Record>(Name, DefLoc, Records); + +  if (ParseObjectBody(CurRec.get())) +    return true; + +  return addEntry(std::move(CurRec)); +} + +/// ParseDefset - Parse a defset statement. +/// +///   Defset ::= DEFSET Type Id '=' '{' ObjectList '}' +/// +bool TGParser::ParseDefset() { +  assert(Lex.getCode() == tgtok::Defset); +  Lex.Lex(); // Eat the 'defset' token + +  DefsetRecord Defset; +  Defset.Loc = Lex.getLoc(); +  RecTy *Type = ParseType(); +  if (!Type) +    return true; +  if (!isa<ListRecTy>(Type)) +    return Error(Defset.Loc, "expected list type"); +  Defset.EltTy = cast<ListRecTy>(Type)->getElementType(); + +  if (Lex.getCode() != tgtok::Id) +    return TokError("expected identifier"); +  StringInit *DeclName = StringInit::get(Lex.getCurStrVal()); +  if (Records.getGlobal(DeclName->getValue())) +    return TokError("def or global variable of this name already exists"); + +  if (Lex.Lex() != tgtok::equal) // Eat the identifier +    return TokError("expected '='"); +  if (Lex.Lex() != tgtok::l_brace) // Eat the '=' +    return TokError("expected '{'"); +  SMLoc BraceLoc = Lex.getLoc(); +  Lex.Lex(); // Eat the '{' + +  Defsets.push_back(&Defset); +  bool Err = ParseObjectList(nullptr); +  Defsets.pop_back(); +  if (Err) +    return true; + +  if (Lex.getCode() != tgtok::r_brace) { +    TokError("expected '}' at end of defset"); +    return Error(BraceLoc, "to match this '{'"); +  } +  Lex.Lex();  // Eat the '}' + +  Records.addExtraGlobal(DeclName->getValue(), +                         ListInit::get(Defset.Elements, Defset.EltTy)); +  return false; +} + +/// ParseForeach - Parse a for statement.  Return the record corresponding +/// to it.  This returns true on error. +/// +///   Foreach ::= FOREACH Declaration IN '{ ObjectList '}' +///   Foreach ::= FOREACH Declaration IN Object +/// +bool TGParser::ParseForeach(MultiClass *CurMultiClass) { +  SMLoc Loc = Lex.getLoc(); +  assert(Lex.getCode() == tgtok::Foreach && "Unknown tok"); +  Lex.Lex();  // Eat the 'for' token. + +  // Make a temporary object to record items associated with the for +  // loop. +  Init *ListValue = nullptr; +  VarInit *IterName = ParseForeachDeclaration(ListValue); +  if (!IterName) +    return TokError("expected declaration in for"); + +  if (Lex.getCode() != tgtok::In) +    return TokError("Unknown tok"); +  Lex.Lex();  // Eat the in + +  // Create a loop object and remember it. +  Loops.push_back(std::make_unique<ForeachLoop>(Loc, IterName, ListValue)); + +  if (Lex.getCode() != tgtok::l_brace) { +    // FOREACH Declaration IN Object +    if (ParseObject(CurMultiClass)) +      return true; +  } else { +    SMLoc BraceLoc = Lex.getLoc(); +    // Otherwise, this is a group foreach. +    Lex.Lex();  // eat the '{'. + +    // Parse the object list. +    if (ParseObjectList(CurMultiClass)) +      return true; + +    if (Lex.getCode() != tgtok::r_brace) { +      TokError("expected '}' at end of foreach command"); +      return Error(BraceLoc, "to match this '{'"); +    } +    Lex.Lex();  // Eat the } +  } + +  // Resolve the loop or store it for later resolution. +  std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back()); +  Loops.pop_back(); + +  return addEntry(std::move(Loop)); +} + +/// ParseClass - Parse a tblgen class definition. +/// +///   ClassInst ::= CLASS ID TemplateArgList? ObjectBody +/// +bool TGParser::ParseClass() { +  assert(Lex.getCode() == tgtok::Class && "Unexpected token!"); +  Lex.Lex(); + +  if (Lex.getCode() != tgtok::Id) +    return TokError("expected class name after 'class' keyword"); + +  Record *CurRec = Records.getClass(Lex.getCurStrVal()); +  if (CurRec) { +    // If the body was previously defined, this is an error. +    if (!CurRec->getValues().empty() || +        !CurRec->getSuperClasses().empty() || +        !CurRec->getTemplateArgs().empty()) +      return TokError("Class '" + CurRec->getNameInitAsString() + +                      "' already defined"); +  } else { +    // If this is the first reference to this class, create and add it. +    auto NewRec = +        std::make_unique<Record>(Lex.getCurStrVal(), Lex.getLoc(), Records, +                                  /*Class=*/true); +    CurRec = NewRec.get(); +    Records.addClass(std::move(NewRec)); +  } +  Lex.Lex(); // eat the name. + +  // If there are template args, parse them. +  if (Lex.getCode() == tgtok::less) +    if (ParseTemplateArgList(CurRec)) +      return true; + +  return ParseObjectBody(CurRec); +} + +/// ParseLetList - Parse a non-empty list of assignment expressions into a list +/// of LetRecords. +/// +///   LetList ::= LetItem (',' LetItem)* +///   LetItem ::= ID OptionalRangeList '=' Value +/// +void TGParser::ParseLetList(SmallVectorImpl<LetRecord> &Result) { +  while (true) { +    if (Lex.getCode() != tgtok::Id) { +      TokError("expected identifier in let definition"); +      Result.clear(); +      return; +    } + +    StringInit *Name = StringInit::get(Lex.getCurStrVal()); +    SMLoc NameLoc = Lex.getLoc(); +    Lex.Lex();  // Eat the identifier. + +    // Check for an optional RangeList. +    SmallVector<unsigned, 16> Bits; +    if (ParseOptionalRangeList(Bits)) { +      Result.clear(); +      return; +    } +    std::reverse(Bits.begin(), Bits.end()); + +    if (Lex.getCode() != tgtok::equal) { +      TokError("expected '=' in let expression"); +      Result.clear(); +      return; +    } +    Lex.Lex();  // eat the '='. + +    Init *Val = ParseValue(nullptr); +    if (!Val) { +      Result.clear(); +      return; +    } + +    // Now that we have everything, add the record. +    Result.emplace_back(Name, Bits, Val, NameLoc); + +    if (Lex.getCode() != tgtok::comma) +      return; +    Lex.Lex();  // eat the comma. +  } +} + +/// ParseTopLevelLet - Parse a 'let' at top level.  This can be a couple of +/// different related productions. This works inside multiclasses too. +/// +///   Object ::= LET LetList IN '{' ObjectList '}' +///   Object ::= LET LetList IN Object +/// +bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) { +  assert(Lex.getCode() == tgtok::Let && "Unexpected token"); +  Lex.Lex(); + +  // Add this entry to the let stack. +  SmallVector<LetRecord, 8> LetInfo; +  ParseLetList(LetInfo); +  if (LetInfo.empty()) return true; +  LetStack.push_back(std::move(LetInfo)); + +  if (Lex.getCode() != tgtok::In) +    return TokError("expected 'in' at end of top-level 'let'"); +  Lex.Lex(); + +  // If this is a scalar let, just handle it now +  if (Lex.getCode() != tgtok::l_brace) { +    // LET LetList IN Object +    if (ParseObject(CurMultiClass)) +      return true; +  } else {   // Object ::= LETCommand '{' ObjectList '}' +    SMLoc BraceLoc = Lex.getLoc(); +    // Otherwise, this is a group let. +    Lex.Lex();  // eat the '{'. + +    // Parse the object list. +    if (ParseObjectList(CurMultiClass)) +      return true; + +    if (Lex.getCode() != tgtok::r_brace) { +      TokError("expected '}' at end of top level let command"); +      return Error(BraceLoc, "to match this '{'"); +    } +    Lex.Lex(); +  } + +  // Outside this let scope, this let block is not active. +  LetStack.pop_back(); +  return false; +} + +/// ParseMultiClass - Parse a multiclass definition. +/// +///  MultiClassInst ::= MULTICLASS ID TemplateArgList? +///                     ':' BaseMultiClassList '{' MultiClassObject+ '}' +///  MultiClassObject ::= DefInst +///  MultiClassObject ::= MultiClassInst +///  MultiClassObject ::= DefMInst +///  MultiClassObject ::= LETCommand '{' ObjectList '}' +///  MultiClassObject ::= LETCommand Object +/// +bool TGParser::ParseMultiClass() { +  assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token"); +  Lex.Lex();  // Eat the multiclass token. + +  if (Lex.getCode() != tgtok::Id) +    return TokError("expected identifier after multiclass for name"); +  std::string Name = Lex.getCurStrVal(); + +  auto Result = +    MultiClasses.insert(std::make_pair(Name, +                    std::make_unique<MultiClass>(Name, Lex.getLoc(),Records))); + +  if (!Result.second) +    return TokError("multiclass '" + Name + "' already defined"); + +  CurMultiClass = Result.first->second.get(); +  Lex.Lex();  // Eat the identifier. + +  // If there are template args, parse them. +  if (Lex.getCode() == tgtok::less) +    if (ParseTemplateArgList(nullptr)) +      return true; + +  bool inherits = false; + +  // If there are submulticlasses, parse them. +  if (Lex.getCode() == tgtok::colon) { +    inherits = true; + +    Lex.Lex(); + +    // Read all of the submulticlasses. +    SubMultiClassReference SubMultiClass = +      ParseSubMultiClassReference(CurMultiClass); +    while (true) { +      // Check for error. +      if (!SubMultiClass.MC) return true; + +      // Add it. +      if (AddSubMultiClass(CurMultiClass, SubMultiClass)) +        return true; + +      if (Lex.getCode() != tgtok::comma) break; +      Lex.Lex(); // eat ','. +      SubMultiClass = ParseSubMultiClassReference(CurMultiClass); +    } +  } + +  if (Lex.getCode() != tgtok::l_brace) { +    if (!inherits) +      return TokError("expected '{' in multiclass definition"); +    if (Lex.getCode() != tgtok::semi) +      return TokError("expected ';' in multiclass definition"); +    Lex.Lex();  // eat the ';'. +  } else { +    if (Lex.Lex() == tgtok::r_brace)  // eat the '{'. +      return TokError("multiclass must contain at least one def"); + +    while (Lex.getCode() != tgtok::r_brace) { +      switch (Lex.getCode()) { +      default: +        return TokError("expected 'let', 'def', 'defm' or 'foreach' in " +                        "multiclass body"); +      case tgtok::Let: +      case tgtok::Def: +      case tgtok::Defm: +      case tgtok::Foreach: +        if (ParseObject(CurMultiClass)) +          return true; +        break; +      } +    } +    Lex.Lex();  // eat the '}'. +  } + +  CurMultiClass = nullptr; +  return false; +} + +/// ParseDefm - Parse the instantiation of a multiclass. +/// +///   DefMInst ::= DEFM ID ':' DefmSubClassRef ';' +/// +bool TGParser::ParseDefm(MultiClass *CurMultiClass) { +  assert(Lex.getCode() == tgtok::Defm && "Unexpected token!"); +  Lex.Lex(); // eat the defm + +  Init *DefmName = ParseObjectName(CurMultiClass); +  if (!DefmName) +    return true; +  if (isa<UnsetInit>(DefmName)) { +    DefmName = Records.getNewAnonymousName(); +    if (CurMultiClass) +      DefmName = BinOpInit::getStrConcat( +          VarInit::get(QualifiedNameOfImplicitName(CurMultiClass), +                       StringRecTy::get()), +          DefmName); +  } + +  if (Lex.getCode() != tgtok::colon) +    return TokError("expected ':' after defm identifier"); + +  // Keep track of the new generated record definitions. +  std::vector<RecordsEntry> NewEntries; + +  // This record also inherits from a regular class (non-multiclass)? +  bool InheritFromClass = false; + +  // eat the colon. +  Lex.Lex(); + +  SMLoc SubClassLoc = Lex.getLoc(); +  SubClassReference Ref = ParseSubClassReference(nullptr, true); + +  while (true) { +    if (!Ref.Rec) return true; + +    // To instantiate a multiclass, we need to first get the multiclass, then +    // instantiate each def contained in the multiclass with the SubClassRef +    // template parameters. +    MultiClass *MC = MultiClasses[Ref.Rec->getName()].get(); +    assert(MC && "Didn't lookup multiclass correctly?"); +    ArrayRef<Init*> TemplateVals = Ref.TemplateArgs; + +    // Verify that the correct number of template arguments were specified. +    ArrayRef<Init *> TArgs = MC->Rec.getTemplateArgs(); +    if (TArgs.size() < TemplateVals.size()) +      return Error(SubClassLoc, +                   "more template args specified than multiclass expects"); + +    SubstStack Substs; +    for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { +      if (i < TemplateVals.size()) { +        Substs.emplace_back(TArgs[i], TemplateVals[i]); +      } else { +        Init *Default = MC->Rec.getValue(TArgs[i])->getValue(); +        if (!Default->isComplete()) { +          return Error(SubClassLoc, +                       "value not specified for template argument #" + +                           Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + +                           ") of multiclass '" + MC->Rec.getNameInitAsString() + +                           "'"); +        } +        Substs.emplace_back(TArgs[i], Default); +      } +    } + +    Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); + +    if (resolve(MC->Entries, Substs, CurMultiClass == nullptr, &NewEntries, +                &SubClassLoc)) +      return true; + +    if (Lex.getCode() != tgtok::comma) break; +    Lex.Lex(); // eat ','. + +    if (Lex.getCode() != tgtok::Id) +      return TokError("expected identifier"); + +    SubClassLoc = Lex.getLoc(); + +    // A defm can inherit from regular classes (non-multiclass) as +    // long as they come in the end of the inheritance list. +    InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != nullptr); + +    if (InheritFromClass) +      break; + +    Ref = ParseSubClassReference(nullptr, true); +  } + +  if (InheritFromClass) { +    // Process all the classes to inherit as if they were part of a +    // regular 'def' and inherit all record values. +    SubClassReference SubClass = ParseSubClassReference(nullptr, false); +    while (true) { +      // Check for error. +      if (!SubClass.Rec) return true; + +      // Get the expanded definition prototypes and teach them about +      // the record values the current class to inherit has +      for (auto &E : NewEntries) { +        // Add it. +        if (AddSubClass(E, SubClass)) +          return true; +      } + +      if (Lex.getCode() != tgtok::comma) break; +      Lex.Lex(); // eat ','. +      SubClass = ParseSubClassReference(nullptr, false); +    } +  } + +  for (auto &E : NewEntries) { +    if (ApplyLetStack(E)) +      return true; + +    addEntry(std::move(E)); +  } + +  if (Lex.getCode() != tgtok::semi) +    return TokError("expected ';' at end of defm"); +  Lex.Lex(); + +  return false; +} + +/// ParseObject +///   Object ::= ClassInst +///   Object ::= DefInst +///   Object ::= MultiClassInst +///   Object ::= DefMInst +///   Object ::= LETCommand '{' ObjectList '}' +///   Object ::= LETCommand Object +bool TGParser::ParseObject(MultiClass *MC) { +  switch (Lex.getCode()) { +  default: +    return TokError("Expected class, def, defm, defset, multiclass, let or " +                    "foreach"); +  case tgtok::Let:   return ParseTopLevelLet(MC); +  case tgtok::Def:   return ParseDef(MC); +  case tgtok::Foreach:   return ParseForeach(MC); +  case tgtok::Defm:  return ParseDefm(MC); +  case tgtok::Defset: +    if (MC) +      return TokError("defset is not allowed inside multiclass"); +    return ParseDefset(); +  case tgtok::Class: +    if (MC) +      return TokError("class is not allowed inside multiclass"); +    if (!Loops.empty()) +      return TokError("class is not allowed inside foreach loop"); +    return ParseClass(); +  case tgtok::MultiClass: +    if (!Loops.empty()) +      return TokError("multiclass is not allowed inside foreach loop"); +    return ParseMultiClass(); +  } +} + +/// ParseObjectList +///   ObjectList :== Object* +bool TGParser::ParseObjectList(MultiClass *MC) { +  while (isObjectStart(Lex.getCode())) { +    if (ParseObject(MC)) +      return true; +  } +  return false; +} + +bool TGParser::ParseFile() { +  Lex.Lex(); // Prime the lexer. +  if (ParseObjectList()) return true; + +  // If we have unread input at the end of the file, report it. +  if (Lex.getCode() == tgtok::Eof) +    return false; + +  return TokError("Unexpected input at top level"); +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void RecordsEntry::dump() const { +  if (Loop) +    Loop->dump(); +  if (Rec) +    Rec->dump(); +} + +LLVM_DUMP_METHOD void ForeachLoop::dump() const { +  errs() << "foreach " << IterVar->getAsString() << " = " +         << ListValue->getAsString() << " in {\n"; + +  for (const auto &E : Entries) +    E.dump(); + +  errs() << "}\n"; +} + +LLVM_DUMP_METHOD void MultiClass::dump() const { +  errs() << "Record:\n"; +  Rec.dump(); + +  errs() << "Defs:\n"; +  for (const auto &E : Entries) +    E.dump(); +} +#endif diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h new file mode 100644 index 000000000000..af2b639f8d59 --- /dev/null +++ b/llvm/lib/TableGen/TGParser.h @@ -0,0 +1,208 @@ +//===- TGParser.h - Parser for TableGen Files -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This class represents the Parser for tablegen files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TABLEGEN_TGPARSER_H +#define LLVM_LIB_TABLEGEN_TGPARSER_H + +#include "TGLexer.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include <map> + +namespace llvm { +  class Record; +  class RecordVal; +  class RecordKeeper; +  class RecTy; +  class Init; +  struct ForeachLoop; +  struct MultiClass; +  struct SubClassReference; +  struct SubMultiClassReference; + +  struct LetRecord { +    StringInit *Name; +    std::vector<unsigned> Bits; +    Init *Value; +    SMLoc Loc; +    LetRecord(StringInit *N, ArrayRef<unsigned> B, Init *V, SMLoc L) +      : Name(N), Bits(B), Value(V), Loc(L) { +    } +  }; + +  /// RecordsEntry - Can be either a record or a foreach loop. +  struct RecordsEntry { +    std::unique_ptr<Record> Rec; +    std::unique_ptr<ForeachLoop> Loop; + +    void dump() const; + +    RecordsEntry() {} +    RecordsEntry(std::unique_ptr<Record> Rec) : Rec(std::move(Rec)) {} +    RecordsEntry(std::unique_ptr<ForeachLoop> Loop) +      : Loop(std::move(Loop)) {} +  }; + +  /// ForeachLoop - Record the iteration state associated with a for loop. +  /// This is used to instantiate items in the loop body. +  struct ForeachLoop { +    SMLoc Loc; +    VarInit *IterVar; +    Init *ListValue; +    std::vector<RecordsEntry> Entries; + +    void dump() const; + +    ForeachLoop(SMLoc Loc, VarInit *IVar, Init *LValue) +      : Loc(Loc), IterVar(IVar), ListValue(LValue) {} +  }; + +  struct DefsetRecord { +    SMLoc Loc; +    RecTy *EltTy; +    SmallVector<Init *, 16> Elements; +  }; + +struct MultiClass { +  Record Rec;  // Placeholder for template args and Name. +  std::vector<RecordsEntry> Entries; + +  void dump() const; + +  MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records) : +    Rec(Name, Loc, Records) {} +}; + +class TGParser { +  TGLexer Lex; +  std::vector<SmallVector<LetRecord, 4>> LetStack; +  std::map<std::string, std::unique_ptr<MultiClass>> MultiClasses; + +  /// Loops - Keep track of any foreach loops we are within. +  /// +  std::vector<std::unique_ptr<ForeachLoop>> Loops; + +  SmallVector<DefsetRecord *, 2> Defsets; + +  /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the +  /// current value. +  MultiClass *CurMultiClass; + +  // Record tracker +  RecordKeeper &Records; + +  // A "named boolean" indicating how to parse identifiers.  Usually +  // identifiers map to some existing object but in special cases +  // (e.g. parsing def names) no such object exists yet because we are +  // in the middle of creating in.  For those situations, allow the +  // parser to ignore missing object errors. +  enum IDParseMode { +    ParseValueMode,   // We are parsing a value we expect to look up. +    ParseNameMode,    // We are parsing a name of an object that does not yet +                      // exist. +  }; + +public: +  TGParser(SourceMgr &SrcMgr, ArrayRef<std::string> Macros, +           RecordKeeper &records) +    : Lex(SrcMgr, Macros), CurMultiClass(nullptr), Records(records) {} + +  /// ParseFile - Main entrypoint for parsing a tblgen file.  These parser +  /// routines return true on error, or false on success. +  bool ParseFile(); + +  bool Error(SMLoc L, const Twine &Msg) const { +    PrintError(L, Msg); +    return true; +  } +  bool TokError(const Twine &Msg) const { +    return Error(Lex.getLoc(), Msg); +  } +  const TGLexer::DependenciesMapTy &getDependencies() const { +    return Lex.getDependencies(); +  } + +private:  // Semantic analysis methods. +  bool AddValue(Record *TheRec, SMLoc Loc, const RecordVal &RV); +  bool SetValue(Record *TheRec, SMLoc Loc, Init *ValName, +                ArrayRef<unsigned> BitList, Init *V, +                bool AllowSelfAssignment = false); +  bool AddSubClass(Record *Rec, SubClassReference &SubClass); +  bool AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass); +  bool AddSubMultiClass(MultiClass *CurMC, +                        SubMultiClassReference &SubMultiClass); + +  using SubstStack = SmallVector<std::pair<Init *, Init *>, 8>; + +  bool addEntry(RecordsEntry E); +  bool resolve(const ForeachLoop &Loop, SubstStack &Stack, bool Final, +               std::vector<RecordsEntry> *Dest, SMLoc *Loc = nullptr); +  bool resolve(const std::vector<RecordsEntry> &Source, SubstStack &Substs, +               bool Final, std::vector<RecordsEntry> *Dest, +               SMLoc *Loc = nullptr); +  bool addDefOne(std::unique_ptr<Record> Rec); + +private:  // Parser methods. +  bool ParseObjectList(MultiClass *MC = nullptr); +  bool ParseObject(MultiClass *MC); +  bool ParseClass(); +  bool ParseMultiClass(); +  bool ParseDefm(MultiClass *CurMultiClass); +  bool ParseDef(MultiClass *CurMultiClass); +  bool ParseDefset(); +  bool ParseForeach(MultiClass *CurMultiClass); +  bool ParseTopLevelLet(MultiClass *CurMultiClass); +  void ParseLetList(SmallVectorImpl<LetRecord> &Result); + +  bool ParseObjectBody(Record *CurRec); +  bool ParseBody(Record *CurRec); +  bool ParseBodyItem(Record *CurRec); + +  bool ParseTemplateArgList(Record *CurRec); +  Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); +  VarInit *ParseForeachDeclaration(Init *&ForeachListValue); + +  SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); +  SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC); + +  Init *ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc, +                     IDParseMode Mode = ParseValueMode); +  Init *ParseSimpleValue(Record *CurRec, RecTy *ItemType = nullptr, +                         IDParseMode Mode = ParseValueMode); +  Init *ParseValue(Record *CurRec, RecTy *ItemType = nullptr, +                   IDParseMode Mode = ParseValueMode); +  void ParseValueList(SmallVectorImpl<llvm::Init*> &Result, Record *CurRec, +                      Record *ArgsRec = nullptr, RecTy *EltTy = nullptr); +  void ParseDagArgList( +      SmallVectorImpl<std::pair<llvm::Init*, StringInit*>> &Result, +      Record *CurRec); +  bool ParseOptionalRangeList(SmallVectorImpl<unsigned> &Ranges); +  bool ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges); +  void ParseRangeList(SmallVectorImpl<unsigned> &Result); +  bool ParseRangePiece(SmallVectorImpl<unsigned> &Ranges, +                       TypedInit *FirstItem = nullptr); +  RecTy *ParseType(); +  Init *ParseOperation(Record *CurRec, RecTy *ItemType); +  Init *ParseOperationCond(Record *CurRec, RecTy *ItemType); +  RecTy *ParseOperatorType(); +  Init *ParseObjectName(MultiClass *CurMultiClass); +  Record *ParseClassID(); +  MultiClass *ParseMultiClassID(); +  bool ApplyLetStack(Record *CurRec); +  bool ApplyLetStack(RecordsEntry &Entry); +}; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/TableGen/TableGenBackend.cpp b/llvm/lib/TableGen/TableGenBackend.cpp new file mode 100644 index 000000000000..e11b28e8cff9 --- /dev/null +++ b/llvm/lib/TableGen/TableGenBackend.cpp @@ -0,0 +1,52 @@ +//===- TableGenBackend.cpp - Utilities for TableGen Backends ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides useful services for TableGen backends... +// +//===----------------------------------------------------------------------===// + +#include "llvm/TableGen/TableGenBackend.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +const size_t MAX_LINE_LEN = 80U; + +static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill, +                      StringRef Suffix) { +  size_t Pos = (size_t)OS.tell(); +  assert((Prefix.str().size() + Suffix.size() <= MAX_LINE_LEN) && +         "header line exceeds max limit"); +  OS << Prefix; +  for (size_t i = (size_t)OS.tell() - Pos, e = MAX_LINE_LEN - Suffix.size(); +         i < e; ++i) +    OS << Fill; +  OS << Suffix << '\n'; +} + +void llvm::emitSourceFileHeader(StringRef Desc, raw_ostream &OS) { +  printLine(OS, "/*===- TableGen'erated file ", '-', "*- C++ -*-===*\\"); +  StringRef Prefix("|* "); +  StringRef Suffix(" *|"); +  printLine(OS, Prefix, ' ', Suffix); +  size_t PSLen = Prefix.size() + Suffix.size(); +  assert(PSLen < MAX_LINE_LEN); +  size_t Pos = 0U; +  do { +    size_t Length = std::min(Desc.size() - Pos, MAX_LINE_LEN - PSLen); +    printLine(OS, Prefix + Desc.substr(Pos, Length), ' ', Suffix); +    Pos += Length; +  } while (Pos < Desc.size()); +  printLine(OS, Prefix, ' ', Suffix); +  printLine(OS, Prefix + "Automatically generated file, do not edit!", ' ', +    Suffix); +  printLine(OS, Prefix, ' ', Suffix); +  printLine(OS, "\\*===", '-', "===*/"); +  OS << '\n'; +} | 
