Seperate asmstring parsing from emission. This allows the code to be simpler
authorChris Lattner <sabre@nondot.org>
Sat, 22 Jan 2005 17:32:42 +0000 (17:32 +0000)
committerChris Lattner <sabre@nondot.org>
Sat, 22 Jan 2005 17:32:42 +0000 (17:32 +0000)
and more understandable.  It also allows us to do simple things like fold
consequtive literal strings together.  For example, instead of emitting this
for the X86 backend:

  O  << "adc" << "l" << " ";

we now generate this:

  O << "adcl ";

*whoa* :)

This shrinks the X86 asmwriters from 62729->58267 and 65176->58644 bytes
for the intel/att asm writers respectively.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19749 91177308-0d34-0410-b5e6-96231b3b80d8

utils/TableGen/AsmWriterEmitter.cpp

index 711a20ba0c8f88ebce6f7b3790ce8f045e70f92c..d44515fe2e1e03a77e9b7bec8e7790d5c614b085 100644 (file)
@@ -25,6 +25,154 @@ static bool isIdentChar(char C) {
          C == '_';
 }
 
+namespace {
+  struct AsmWriterOperand {
+    enum { isLiteralTextOperand, isMachineInstrOperand } OperandType;
+
+    /// Str - For isLiteralTextOperand, this IS the literal text.  For
+    /// isMachineInstrOperand, this is the PrinterMethodName for the operand.
+    std::string Str;
+
+    /// MiOpNo - For isMachineInstrOperand, this is the operand number of the
+    /// machine instruction.
+    unsigned MIOpNo;
+
+    /// OpVT - For isMachineInstrOperand, this is the value type for the
+    /// operand.
+    MVT::ValueType OpVT;
+
+    AsmWriterOperand(const std::string &LitStr)
+      : OperandType(isLiteralTextOperand),  Str(LitStr) {}
+
+    AsmWriterOperand(const std::string &Printer, unsigned OpNo,
+                     MVT::ValueType VT) : OperandType(isMachineInstrOperand),
+                                          Str(Printer), MIOpNo(OpNo), OpVT(VT){}
+
+    void EmitCode(std::ostream &OS) const;
+  };
+
+  struct AsmWriterInst {
+    std::vector<AsmWriterOperand> Operands;
+    
+    void ParseAsmString(const CodeGenInstruction &CGI, unsigned Variant);
+    void EmitCode(std::ostream &OS) const {
+      for (unsigned i = 0, e = Operands.size(); i != e; ++i)
+        Operands[i].EmitCode(OS);
+    }
+  private:
+    void AddLiteralString(const std::string &Str) {
+      // If the last operand was already a literal text string, append this to
+      // it, otherwise add a new operand.
+      if (!Operands.empty() &&
+          Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand)
+        Operands.back().Str.append(Str);
+      else
+        Operands.push_back(AsmWriterOperand(Str));
+    }
+  };
+}
+
+
+void AsmWriterOperand::EmitCode(std::ostream &OS) const {
+  if (OperandType == isLiteralTextOperand)
+    OS << "O << \"" << Str << "\"; ";
+  else
+    OS << Str << "(MI, " << MIOpNo << ", MVT::" << getName(OpVT) << "); ";
+}
+
+
+/// ParseAsmString - Parse the specified Instruction's AsmString into this
+/// AsmWriterInst.
+///
+void AsmWriterInst::ParseAsmString(const CodeGenInstruction &CGI,
+                                   unsigned Variant) {
+  bool inVariant = false;  // True if we are inside a {.|.|.} region.
+
+  const std::string &AsmString = CGI.AsmString;
+  std::string::size_type LastEmitted = 0;
+  while (LastEmitted != AsmString.size()) {
+    std::string::size_type DollarPos =
+      AsmString.find_first_of("${|}", LastEmitted);
+    if (DollarPos == std::string::npos) DollarPos = AsmString.size();
+
+    // Emit a constant string fragment.
+    if (DollarPos != LastEmitted) {
+      // TODO: this should eventually handle escaping.
+      AddLiteralString(std::string(AsmString.begin()+LastEmitted,
+                                   AsmString.begin()+DollarPos));
+      LastEmitted = DollarPos;
+    } else if (AsmString[DollarPos] == '{') {
+      if (inVariant)
+        throw "Nested variants found for instruction '" + CGI.Name + "'!";
+      LastEmitted = DollarPos+1;
+      inVariant = true;   // We are now inside of the variant!
+      for (unsigned i = 0; i != Variant; ++i) {
+        // Skip over all of the text for an irrelevant variant here.  The
+        // next variant starts at |, or there may not be text for this
+        // variant if we see a }.
+        std::string::size_type NP =
+          AsmString.find_first_of("|}", LastEmitted);
+        if (NP == std::string::npos)
+          throw "Incomplete variant for instruction '" + CGI.Name + "'!";
+        LastEmitted = NP+1;
+        if (AsmString[NP] == '}') {
+          inVariant = false;        // No text for this variant.
+          break;
+        }
+      }
+    } else if (AsmString[DollarPos] == '|') {
+      if (!inVariant)
+        throw "'|' character found outside of a variant in instruction '"
+          + CGI.Name + "'!";
+      // Move to the end of variant list.
+      std::string::size_type NP = AsmString.find('}', LastEmitted);
+      if (NP == std::string::npos)
+        throw "Incomplete variant for instruction '" + CGI.Name + "'!";
+      LastEmitted = NP+1;
+      inVariant = false;
+    } else if (AsmString[DollarPos] == '}') {
+      if (!inVariant)
+        throw "'}' character found outside of a variant in instruction '"
+          + CGI.Name + "'!";
+      LastEmitted = DollarPos+1;
+      inVariant = false;
+    } else if (DollarPos+1 != AsmString.size() &&
+               AsmString[DollarPos+1] == '$') {
+      AddLiteralString("$");  // "$$" -> $
+      LastEmitted = DollarPos+2;
+    } else {
+      // Get the name of the variable.
+      // TODO: should eventually handle ${foo}bar as $foo
+      std::string::size_type VarEnd = DollarPos+1;
+      while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
+        ++VarEnd;
+      std::string VarName(AsmString.begin()+DollarPos+1,
+                          AsmString.begin()+VarEnd);
+      if (VarName.empty())
+        throw "Stray '$' in '" + CGI.Name + "' asm string, maybe you want $$?";
+
+      unsigned OpNo = CGI.getOperandNamed(VarName);
+
+      // If this is a two-address instruction and we are not accessing the
+      // 0th operand, remove an operand.
+      unsigned MIOp = CGI.OperandList[OpNo].MIOperandNo;
+      if (CGI.isTwoAddress && MIOp != 0) {
+        if (MIOp == 1)
+          throw "Should refer to operand #0 instead of #1 for two-address"
+            " instruction '" + CGI.Name + "'!";
+        --MIOp;
+      }
+
+      Operands.push_back(AsmWriterOperand(CGI.OperandList[OpNo].PrinterMethodName,
+                                          MIOp, CGI.OperandList[OpNo].Ty));
+      LastEmitted = VarEnd;
+    }
+  }
+
+  AddLiteralString("\\n");
+}
+
+
 void AsmWriterEmitter::run(std::ostream &O) {
   EmitSourceFileHeader("Assembly Writer Source Fragment", O);
 
@@ -45,96 +193,15 @@ void AsmWriterEmitter::run(std::ostream &O) {
 
   std::string Namespace = Target.inst_begin()->second.Namespace;
 
-  bool inVariant = false;  // True if we are inside a {.|.|.} region.
-
   for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
          E = Target.inst_end(); I != E; ++I)
     if (!I->second.AsmString.empty()) {
-      const std::string &AsmString = I->second.AsmString;
-      O << "  case " << Namespace << "::" << I->first << ": O ";
-
-      std::string::size_type LastEmitted = 0;
-      while (LastEmitted != AsmString.size()) {
-        std::string::size_type DollarPos =
-          AsmString.find_first_of("${|}", LastEmitted);
-        if (DollarPos == std::string::npos) DollarPos = AsmString.size();
-
-        // Emit a constant string fragment.
-        if (DollarPos != LastEmitted) {
-          // TODO: this should eventually handle escaping.
-          O << " << \"" << std::string(AsmString.begin()+LastEmitted,
-                                       AsmString.begin()+DollarPos) << "\"";
-          LastEmitted = DollarPos;
-        } else if (AsmString[DollarPos] == '{') {
-          if (inVariant)
-            throw "Nested variants found for instruction '" + I->first + "'!";
-          LastEmitted = DollarPos+1;
-          inVariant = true;   // We are now inside of the variant!
-          for (unsigned i = 0; i != Variant; ++i) {
-            // Skip over all of the text for an irrelevant variant here.  The
-            // next variant starts at |, or there may not be text for this
-            // variant if we see a }.
-            std::string::size_type NP =
-              AsmString.find_first_of("|}", LastEmitted);
-            if (NP == std::string::npos)
-              throw "Incomplete variant for instruction '" + I->first + "'!";
-            LastEmitted = NP+1;
-            if (AsmString[NP] == '}') {
-              inVariant = false;        // No text for this variant.
-              break;
-            }
-          }
-        } else if (AsmString[DollarPos] == '|') {
-          if (!inVariant)
-            throw "'|' character found outside of a variant in instruction '"
-                  + I->first + "'!";
-          // Move to the end of variant list.
-          std::string::size_type NP = AsmString.find('}', LastEmitted);
-          if (NP == std::string::npos)
-            throw "Incomplete variant for instruction '" + I->first + "'!";
-          LastEmitted = NP+1;
-          inVariant = false;
-        } else if (AsmString[DollarPos] == '}') {
-          if (!inVariant)
-            throw "'}' character found outside of a variant in instruction '"
-                  + I->first + "'!";
-          LastEmitted = DollarPos+1;
-          inVariant = false;
-        } else if (DollarPos+1 != AsmString.size() &&
-                   AsmString[DollarPos+1] == '$') {
-          O << " << '$'";         // "$$" -> $
-         LastEmitted = DollarPos+2;
-        } else {
-          // Get the name of the variable.
-          // TODO: should eventually handle ${foo}bar as $foo
-          std::string::size_type VarEnd = DollarPos+1;
-          while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
-            ++VarEnd;
-          std::string VarName(AsmString.begin()+DollarPos+1,
-                              AsmString.begin()+VarEnd);
-          if (VarName.empty())
-            throw "Stray '$' in '" + I->first +
-                  "' asm string, maybe you want $$?";
-          unsigned OpNo = I->second.getOperandNamed(VarName);
-
-          // If this is a two-address instruction and we are not accessing the
-          // 0th operand, remove an operand.
-          unsigned MIOp = I->second.OperandList[OpNo].MIOperandNo;
-          if (I->second.isTwoAddress && MIOp != 0) {
-            if (MIOp == 1)
-              throw "Should refer to operand #0 instead of #1 for two-address"
-                    " instruction '" + I->first + "'!";
-            --MIOp;
-          }
-
-          O << ";  " << I->second.OperandList[OpNo].PrinterMethodName 
-            << "(MI, " << MIOp << ", MVT::"
-            << getName(I->second.OperandList[OpNo].Ty) << "); O ";
-          LastEmitted = VarEnd;
-        }
-      }
+      O << "  case " << Namespace << "::" << I->first << ": ";
 
-      O << " << '\\n'; break;\n";
+      AsmWriterInst AWI;
+      AWI.ParseAsmString(I->second, Variant);
+      AWI.EmitCode(O);
+      O << " break;\n";
     }
 
   O << "  }\n"