Sketch out parser/IR support for OperationInst, and a new Instruction base
class.

Introduce an Identifier class to MLIRContext to represent uniqued identifiers,
introduce string literal support to the lexer, introducing parser and printer
support etc.

PiperOrigin-RevId: 202592007
diff --git a/lib/IR/AsmPrinter.cpp b/lib/IR/AsmPrinter.cpp
index 03871fc..639000b 100644
--- a/lib/IR/AsmPrinter.cpp
+++ b/lib/IR/AsmPrinter.cpp
@@ -77,7 +77,11 @@
 
   void print();
   void print(const BasicBlock *block);
-  void print(const TerminatorInst *inst);
+
+  void print(const Instruction *inst);
+  void print(const OperationInst *inst);
+  void print(const ReturnInst *inst);
+  void print(const BranchInst *inst);
 
   unsigned getBBID(const BasicBlock *block) {
     auto it = basicBlockIDs.find(block);
@@ -114,32 +118,47 @@
 void CFGFunctionState::print(const BasicBlock *block) {
   os << "bb" << getBBID(block) << ":\n";
 
-  // TODO Print arguments and instructions.
+  // TODO Print arguments.
+  for (auto inst : block->instList)
+    print(inst);
 
   print(block->getTerminator());
 }
 
-void CFGFunctionState::print(const TerminatorInst *inst) {
+void CFGFunctionState::print(const Instruction *inst) {
   switch (inst->getKind()) {
+  case Instruction::Kind::Operation:
+    return print(cast<OperationInst>(inst));
   case TerminatorInst::Kind::Branch:
-    os << "  br bb" << getBBID(cast<BranchInst>(inst)->getDest()) << "\n";
-    break;
+    return print(cast<BranchInst>(inst));
   case TerminatorInst::Kind::Return:
-    os << "  return\n";
-    break;
+    return print(cast<ReturnInst>(inst));
   }
 }
 
+void CFGFunctionState::print(const OperationInst *inst) {
+  // TODO: escape name if necessary.
+  os << "  \"" << inst->getName().str() << "\"()\n";
+}
+
+void CFGFunctionState::print(const BranchInst *inst) {
+  os << "  br bb" << getBBID(inst->getDest()) << "\n";
+}
+void CFGFunctionState::print(const ReturnInst *inst) {
+  os << "  return\n";
+}
+
 //===----------------------------------------------------------------------===//
 // print and dump methods
 //===----------------------------------------------------------------------===//
 
-void TerminatorInst::print(raw_ostream &os) const {
+
+void Instruction::print(raw_ostream &os) const {
   CFGFunctionState state(getFunction(), os);
   state.print(this);
 }
 
-void TerminatorInst::dump() const {
+void Instruction::dump() const {
   print(llvm::errs());
 }
 
diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp
index c32e878..2222a12 100644
--- a/lib/IR/Instructions.cpp
+++ b/lib/IR/Instructions.cpp
@@ -19,14 +19,33 @@
 #include "mlir/IR/BasicBlock.h"
 using namespace mlir;
 
-CFGFunction *TerminatorInst::getFunction() const {
+//===----------------------------------------------------------------------===//
+// Instruction
+//===----------------------------------------------------------------------===//
+
+CFGFunction *Instruction::getFunction() const {
   return getBlock()->getFunction();
 }
 
+//===----------------------------------------------------------------------===//
+// OperationInst
+//===----------------------------------------------------------------------===//
+
+OperationInst::OperationInst(Identifier name, BasicBlock *block) :
+  Instruction(Kind::Operation, block), name(name) {
+  getBlock()->instList.push_back(this);
+}
+
+//===----------------------------------------------------------------------===//
+// Terminators
+//===----------------------------------------------------------------------===//
+
 ReturnInst::ReturnInst(BasicBlock *parent)
   : TerminatorInst(Kind::Return, parent) {
+  getBlock()->setTerminator(this);
 }
 
 BranchInst::BranchInst(BasicBlock *dest, BasicBlock *parent)
   : TerminatorInst(Kind::Branch, parent), dest(dest) {
+  getBlock()->setTerminator(this);
 }
diff --git a/lib/IR/MLIRContext.cpp b/lib/IR/MLIRContext.cpp
index 8a035b6..5f2bd8e 100644
--- a/lib/IR/MLIRContext.cpp
+++ b/lib/IR/MLIRContext.cpp
@@ -16,9 +16,11 @@
 // =============================================================================
 
 #include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/Identifier.h"
 #include "mlir/IR/Types.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Allocator.h"
 using namespace mlir;
 using namespace llvm;
@@ -89,6 +91,9 @@
   /// We put immortal objects into this allocator.
   llvm::BumpPtrAllocator allocator;
 
+  /// These are identifiers uniqued into this MLIRContext.
+  llvm::StringMap<char, llvm::BumpPtrAllocator&> identifiers;
+
   // Primitive type uniquing.
   PrimitiveType *primitives[int(TypeKind::LAST_PRIMITIVE_TYPE)+1] = { nullptr };
 
@@ -110,6 +115,8 @@
 
 
 public:
+  MLIRContextImpl() : identifiers(allocator) {}
+
   /// Copy the specified array of elements into memory managed by our bump
   /// pointer allocator.  This assumes the elements are all PODs.
   template<typename T>
@@ -128,9 +135,28 @@
 }
 
 
+//===----------------------------------------------------------------------===//
+// Identifier
+//===----------------------------------------------------------------------===//
+
+/// Return an identifier for the specified string.
+Identifier Identifier::get(StringRef str, const MLIRContext *context) {
+  assert(!str.empty() && "Cannot create an empty identifier");
+  assert(str.find('\0') == StringRef::npos &&
+         "Cannot create an identifier with a nul character");
+
+  auto &impl = context->getImpl();
+  auto it = impl.identifiers.insert({str, char()}).first;
+  return Identifier(it->getKeyData());
+}
+
+
+//===----------------------------------------------------------------------===//
+// Types
+//===----------------------------------------------------------------------===//
+
 PrimitiveType::PrimitiveType(TypeKind kind, MLIRContext *context)
   : Type(kind, context) {
-
 }
 
 PrimitiveType *PrimitiveType::get(TypeKind kind, MLIRContext *context) {