From b0b55e74a090454711b1bb17e4f872d62d6e6b65 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 22 Jan 2005 17:32:42 +0000 Subject: 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 --- utils/TableGen/AsmWriterEmitter.cpp | 239 +++++++++++++++++++++++------------- 1 file changed, 153 insertions(+), 86 deletions(-) (limited to 'utils/TableGen/AsmWriterEmitter.cpp') 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 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" -- cgit v1.2.3