summaryrefslogtreecommitdiff
path: root/utils/TableGen/AsmWriterEmitter.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2005-01-22 17:32:42 +0000
committerChris Lattner <sabre@nondot.org>2005-01-22 17:32:42 +0000
commitb0b55e74a090454711b1bb17e4f872d62d6e6b65 (patch)
tree5fdcd16881d47e17995132a355ee733ccdfc7c13 /utils/TableGen/AsmWriterEmitter.cpp
parent2fce6d1a6972cbf533615be92fa3f59064b56baf (diff)
downloadllvm-b0b55e74a090454711b1bb17e4f872d62d6e6b65.tar.gz
llvm-b0b55e74a090454711b1bb17e4f872d62d6e6b65.tar.bz2
llvm-b0b55e74a090454711b1bb17e4f872d62d6e6b65.tar.xz
Seperate asmstring parsing from emission. This allows the code to be simpler
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
Diffstat (limited to 'utils/TableGen/AsmWriterEmitter.cpp')
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp239
1 files changed, 153 insertions, 86 deletions
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index 711a20ba0c..d44515fe2e 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -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"