[llvm-mca] Propagate fatal llvm-mca errors from library classes to driver.

Summary:
This patch introduces error handling to propagate the errors from llvm-mca library classes (or what will become library classes) up to the driver.  This patch also introduces an enum to make clearer the intention of the return value for Stage::execute.

This supports PR38101.

Reviewers: andreadb, courbet, RKSimon

Reviewed By: andreadb

Subscribers: llvm-commits, tschuett, gbedwell

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

llvm-svn: 339594
diff --git a/llvm/tools/llvm-mca/InstrBuilder.cpp b/llvm/tools/llvm-mca/InstrBuilder.cpp
index 053b7b4..1688a56 100644
--- a/llvm/tools/llvm-mca/InstrBuilder.cpp
+++ b/llvm/tools/llvm-mca/InstrBuilder.cpp
@@ -155,8 +155,8 @@
   ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
 }
 
-void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
-                                  unsigned SchedClassID) {
+Error InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
+                                   unsigned SchedClassID) {
   const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
   const MCSchedModel &SM = STI.getSchedModel();
   const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
@@ -215,9 +215,11 @@
     CurrentDef++;
   }
 
-  if (CurrentDef != NumExplicitDefs)
-    llvm::report_fatal_error(
-        "error: Expected more register operand definitions. ");
+  if (CurrentDef != NumExplicitDefs) {
+    return make_error<StringError>(
+        "error: Expected more register operand definitions.",
+        inconvertibleErrorCode());
+  }
 
   CurrentDef = 0;
   for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
@@ -253,10 +255,10 @@
     // MCInst sequence.
     const MCOperand &Op = MCI.getOperand(MCI.getNumOperands() - 1);
     if (i == MCI.getNumOperands() || !Op.isReg())
-      llvm::report_fatal_error(
+      return make_error<StringError>(
           "error: expected a register operand for an optional "
-          "definition. Instruction has not be correctly analyzed.\n",
-          false);
+          "definition. Instruction has not be correctly analyzed.",
+          inconvertibleErrorCode());
 
     WriteDescriptor &Write = ID.Writes[TotalDefs - 1];
     Write.OpIndex = MCI.getNumOperands() - 1;
@@ -265,10 +267,12 @@
     Write.SClassOrWriteResourceID = 0;
     Write.IsOptionalDef = true;
   }
+
+  return ErrorSuccess();
 }
 
-void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
-                                 unsigned SchedClassID) {
+Error InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
+                                  unsigned SchedClassID) {
   const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
   unsigned NumExplicitDefs = MCDesc.getNumDefs();
 
@@ -280,9 +284,11 @@
       NumExplicitDefs--;
   }
 
-  if (NumExplicitDefs)
-    llvm::report_fatal_error(
-        "error: Expected more register operand definitions. ", false);
+  if (NumExplicitDefs) {
+    return make_error<StringError>(
+        "error: Expected more register operand definitions. ",
+        inconvertibleErrorCode());
+  }
 
   unsigned NumExplicitUses = MCI.getNumOperands() - i;
   unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
@@ -292,7 +298,7 @@
   }
   unsigned TotalUses = NumExplicitUses + NumImplicitUses;
   if (!TotalUses)
-    return;
+    return ErrorSuccess();
 
   ID.Reads.resize(TotalUses);
   for (unsigned CurrentUse = 0; CurrentUse < NumExplicitUses; ++CurrentUse) {
@@ -313,9 +319,11 @@
     LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex << ", RegisterID="
                       << MRI.getName(Read.RegisterID) << '\n');
   }
+  return ErrorSuccess();
 }
 
-const InstrDesc &InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
+Expected<const InstrDesc &>
+InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
   assert(STI.getSchedModel().hasInstrSchedModel() &&
          "Itineraries are not yet supported!");
 
@@ -333,11 +341,13 @@
     while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
       SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID);
 
-    if (!SchedClassID)
-      llvm::report_fatal_error("unable to resolve this variant class.");
+    if (!SchedClassID) {
+      return make_error<StringError>("unable to resolve this variant class.",
+                                     inconvertibleErrorCode());
+    }
   }
 
-  // Check if this instruction is supported. Otherwise, report a fatal error.
+  // Check if this instruction is supported. Otherwise, report an error.
   const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
   if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
     std::string ToString;
@@ -346,10 +356,10 @@
                        << " assembly sequence.\n";
     MCIP.printInst(&MCI, OS, "", STI);
     OS.flush();
-
     WithColor::note() << "instruction: " << ToString << '\n';
-    llvm::report_fatal_error(
-        "Don't know how to analyze unsupported instructions.");
+    return make_error<StringError>(
+        "Don't know how to analyze unsupported instructions",
+        inconvertibleErrorCode());
   }
 
   // Create a new empty descriptor.
@@ -375,8 +385,10 @@
 
   initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
   computeMaxLatency(*ID, MCDesc, SCDesc, STI);
-  populateWrites(*ID, MCI, SchedClassID);
-  populateReads(*ID, MCI, SchedClassID);
+  if (auto Err = populateWrites(*ID, MCI, SchedClassID))
+    return std::move(Err);
+  if (auto Err = populateReads(*ID, MCI, SchedClassID))
+    return std::move(Err);
 
   LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
   LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
@@ -392,7 +404,8 @@
   return *VariantDescriptors[&MCI];
 }
 
-const InstrDesc &InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
+Expected<const InstrDesc &>
+InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
   if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end())
     return *Descriptors[MCI.getOpcode()];
 
@@ -402,9 +415,12 @@
   return createInstrDescImpl(MCI);
 }
 
-std::unique_ptr<Instruction>
+Expected<std::unique_ptr<Instruction>>
 InstrBuilder::createInstruction(const MCInst &MCI) {
-  const InstrDesc &D = getOrCreateInstrDesc(MCI);
+  Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI);
+  if (!DescOrErr)
+    return DescOrErr.takeError();
+  const InstrDesc &D = *DescOrErr;
   std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
 
   // Initialize Reads first.
@@ -433,7 +449,7 @@
 
   // Early exit if there are no writes.
   if (D.Writes.empty())
-    return NewIS;
+    return std::move(NewIS);
 
   // Track register writes that implicitly clear the upper portion of the
   // underlying super-registers using an APInt.
@@ -464,6 +480,6 @@
     ++WriteIndex;
   }
 
-  return NewIS;
+  return std::move(NewIS);
 }
 } // namespace mca