diff options
Diffstat (limited to 'utils/TableGen/AsmWriterEmitter.cpp')
-rw-r--r-- | utils/TableGen/AsmWriterEmitter.cpp | 298 |
1 files changed, 186 insertions, 112 deletions
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index f34feef0c28d..84a647bea309 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -15,13 +15,14 @@ #include "AsmWriterEmitter.h" #include "CodeGenTarget.h" #include "Record.h" +#include "StringToOffsetTable.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include <algorithm> -#include <iostream> using namespace llvm; + static bool isIdentChar(char C) { return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || @@ -32,10 +33,20 @@ static bool isIdentChar(char C) { // This should be an anon namespace, this works around a GCC warning. namespace llvm { struct AsmWriterOperand { - enum { isLiteralTextOperand, isMachineInstrOperand } OperandType; + enum OpType { + // Output this text surrounded by quotes to the asm. + isLiteralTextOperand, + // This is the name of a routine to call to print the operand. + isMachineInstrOperand, + // Output this text verbatim to the asm writer. It is code that + // will output some text to the asm. + isLiteralStatementOperand + } OperandType; /// Str - For isLiteralTextOperand, this IS the literal text. For - /// isMachineInstrOperand, this is the PrinterMethodName for the operand. + /// isMachineInstrOperand, this is the PrinterMethodName for the operand.. + /// For isLiteralStatementOperand, this is the code to insert verbatim + /// into the asm writer. std::string Str; /// MiOpNo - For isMachineInstrOperand, this is the operand number of the @@ -47,14 +58,16 @@ namespace llvm { std::string MiModifier; // To make VS STL happy - AsmWriterOperand():OperandType(isLiteralTextOperand) {} + AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {} - explicit AsmWriterOperand(const std::string &LitStr) - : OperandType(isLiteralTextOperand), Str(LitStr) {} + AsmWriterOperand(const std::string &LitStr, + OpType op = isLiteralTextOperand) + : OperandType(op), Str(LitStr) {} AsmWriterOperand(const std::string &Printer, unsigned OpNo, - const std::string &Modifier) - : OperandType(isMachineInstrOperand), Str(Printer), MIOpNo(OpNo), + const std::string &Modifier, + OpType op = isMachineInstrOperand) + : OperandType(op), Str(Printer), MIOpNo(OpNo), MiModifier(Modifier) {} bool operator!=(const AsmWriterOperand &Other) const { @@ -78,7 +91,7 @@ namespace llvm { std::vector<AsmWriterOperand> Operands; const CodeGenInstruction *CGI; - AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant); + AsmWriterInst(const CodeGenInstruction &CGI, Record *AsmWriter); /// MatchesAllButOneOp - If this instruction is exactly identical to the /// specified instruction except for one differing operand, return the @@ -100,8 +113,14 @@ namespace llvm { std::string AsmWriterOperand::getCode() const { - if (OperandType == isLiteralTextOperand) + if (OperandType == isLiteralTextOperand) { + if (Str.size() == 1) + return "O << '" + Str + "'; "; return "O << \"" + Str + "\"; "; + } + + if (OperandType == isLiteralStatementOperand) + return Str; std::string Result = Str + "(MI"; if (MIOpNo != ~0U) @@ -115,10 +134,19 @@ std::string AsmWriterOperand::getCode() const { /// ParseAsmString - Parse the specified Instruction's AsmString into this /// AsmWriterInst. /// -AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { +AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, Record *AsmWriter) { this->CGI = &CGI; + + unsigned Variant = AsmWriter->getValueAsInt("Variant"); + int FirstOperandColumn = AsmWriter->getValueAsInt("FirstOperandColumn"); + int OperandSpacing = AsmWriter->getValueAsInt("OperandSpacing"); + unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #. + // This is the number of tabs we've seen if we're doing columnar layout. + unsigned CurColumn = 0; + + // NOTE: Any extensions to this code need to be mirrored in the // AsmPrinter::printInlineAsm code that executes as compile time (assuming // that inline asm strings should also get the new feature)! @@ -130,14 +158,35 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { if (DollarPos == std::string::npos) DollarPos = AsmString.size(); // Emit a constant string fragment. + if (DollarPos != LastEmitted) { if (CurVariant == Variant || CurVariant == ~0U) { for (; LastEmitted != DollarPos; ++LastEmitted) switch (AsmString[LastEmitted]) { - case '\n': AddLiteralString("\\n"); break; - case '\t': AddLiteralString("\\t"); break; - case '"': AddLiteralString("\\\""); break; - case '\\': AddLiteralString("\\\\"); break; + case '\n': + AddLiteralString("\\n"); + break; + case '\t': + // If the asm writer is not using a columnar layout, \t is not + // magic. + if (FirstOperandColumn == -1 || OperandSpacing == -1) { + AddLiteralString("\\t"); + } else { + // We recognize a tab as an operand delimeter. + unsigned DestColumn = FirstOperandColumn + + CurColumn++ * OperandSpacing; + Operands.push_back( + AsmWriterOperand("O.PadToColumn(" + + utostr(DestColumn) + ");\n", + AsmWriterOperand::isLiteralStatementOperand)); + } + break; + case '"': + AddLiteralString("\\\""); + break; + case '\\': + AddLiteralString("\\\\"); + break; default: AddLiteralString(std::string(1, AsmString[LastEmitted])); break; @@ -151,7 +200,20 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { if (AsmString[DollarPos+1] == 'n') { AddLiteralString("\\n"); } else if (AsmString[DollarPos+1] == 't') { - AddLiteralString("\\t"); + // If the asm writer is not using a columnar layout, \t is not + // magic. + if (FirstOperandColumn == -1 || OperandSpacing == -1) { + AddLiteralString("\\t"); + break; + } + + // We recognize a tab as an operand delimeter. + unsigned DestColumn = FirstOperandColumn + + CurColumn++ * OperandSpacing; + Operands.push_back( + AsmWriterOperand("O.PadToColumn(" + utostr(DestColumn) + ");\n", + AsmWriterOperand::isLiteralStatementOperand)); + break; } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) != std::string::npos) { AddLiteralString(std::string(1, AsmString[DollarPos+1])); @@ -182,13 +244,14 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { CurVariant = ~0U; } else if (DollarPos+1 != AsmString.size() && AsmString[DollarPos+1] == '$') { - if (CurVariant == Variant || CurVariant == ~0U) + if (CurVariant == Variant || CurVariant == ~0U) { AddLiteralString("$"); // "$$" -> $ + } LastEmitted = DollarPos+2; } else { // Get the name of the variable. std::string::size_type VarEnd = DollarPos+1; - + // handle ${foo}bar as $foo by detecting whether the character following // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos // so the variable name does not contain the leading curly brace. @@ -259,8 +322,9 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { LastEmitted = VarEnd; } } - - AddLiteralString("\\n"); + + Operands.push_back(AsmWriterOperand("return;", + AsmWriterOperand::isLiteralStatementOperand)); } /// MatchesAllButOneOp - If this instruction is exactly identical to the @@ -357,7 +421,6 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts, } O << "\n"; } - O << " break;\n"; } @@ -384,10 +447,6 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, Command = " " + Inst->Operands[0].getCode() + "\n"; - // If this is the last operand, emit a return. - if (Inst->Operands.size() == 1) - Command += " return true;\n"; - // Check to see if we already have 'Command' in UniqueOperandCommands. // If not, add it. bool FoundIt = false; @@ -431,7 +490,10 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // Otherwise, scan to see if all of the other instructions in this command // set share the operand. bool AllSame = true; - + // Keep track of the maximum, number of operands or any + // instruction we see in the group. + size_t MaxSize = FirstInst->Operands.size(); + for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx); NIT != InstIdxs.end(); NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) { @@ -439,6 +501,11 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // matches, we're ok, otherwise bail out. const AsmWriterInst *OtherInst = getAsmWriterInstByID(NIT-InstIdxs.begin()); + + if (OtherInst && + OtherInst->Operands.size() > FirstInst->Operands.size()) + MaxSize = std::max(MaxSize, OtherInst->Operands.size()); + if (!OtherInst || OtherInst->Operands.size() == Op || OtherInst->Operands[Op] != FirstInst->Operands[Op]) { AllSame = false; @@ -451,10 +518,6 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // to UniqueOperandCommands and remember that it was consumed. std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n"; - // If this is the last operand, emit a return after the code. - if (FirstInst->Operands.size() == Op+1) - Command += " return true;\n"; - UniqueOperandCommands[CommandIdx] += Command; InstOpsUsed[CommandIdx]++; } @@ -475,29 +538,26 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, } - -void AsmWriterEmitter::run(raw_ostream &O) { - EmitSourceFileHeader("Assembly Writer Source Fragment", O); - +/// EmitPrintInstruction - Generate the code for the "printInstruction" method +/// implementation. +void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { CodeGenTarget Target; Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); - unsigned Variant = AsmWriter->getValueAsInt("Variant"); - + O << "/// printInstruction - This method is automatically generated by tablegen\n" - "/// from the instruction set description. This method returns true if the\n" - "/// machine instruction was sufficiently described to print it, otherwise\n" - "/// it returns false.\n" - "bool " << Target.getName() << ClassName + "/// from the instruction set description.\n" + "void " << Target.getName() << ClassName << "::printInstruction(const MachineInstr *MI) {\n"; std::vector<AsmWriterInst> Instructions; for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) - if (!I->second.AsmString.empty()) - Instructions.push_back(AsmWriterInst(I->second, Variant)); + if (!I->second.AsmString.empty() && + I->second.TheDef->getName() != "PHI") + Instructions.push_back(AsmWriterInst(I->second, AsmWriter)); // Get the instruction numbering. Target.getInstructionsByEnumValue(NumberedInstructions); @@ -509,10 +569,7 @@ void AsmWriterEmitter::run(raw_ostream &O) { CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); // Build an aggregate string, and build a table of offsets into it. - std::map<std::string, unsigned> StringOffset; - std::string AggregateString; - AggregateString.push_back(0); // "\0" - AggregateString.push_back(0); // "\0" + StringToOffsetTable StringTable; /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. @@ -524,32 +581,28 @@ void AsmWriterEmitter::run(raw_ostream &O) { unsigned Idx; if (AWI == 0) { // Something not handled by the asmwriter printer. - Idx = 0; + Idx = ~0U; } else if (AWI->Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand || AWI->Operands[0].Str.empty()) { // Something handled by the asmwriter printer, but with no leading string. - Idx = 1; + Idx = StringTable.GetOrAddStringOffset(""); } else { - unsigned &Entry = StringOffset[AWI->Operands[0].Str]; - if (Entry == 0) { - // Add the string to the aggregate if this is the first time found. - MaxStringIdx = Entry = AggregateString.size(); - std::string Str = AWI->Operands[0].Str; - UnescapeString(Str); - AggregateString += Str; - AggregateString += '\0'; - } - Idx = Entry; - + std::string Str = AWI->Operands[0].Str; + UnescapeString(Str); + Idx = StringTable.GetOrAddStringOffset(Str); + MaxStringIdx = std::max(MaxStringIdx, Idx); + // Nuke the string from the operand list. It is now handled! AWI->Operands.erase(AWI->Operands.begin()); } - OpcodeInfo.push_back(Idx); + + // Bias offset by one since we want 0 as a sentinel. + OpcodeInfo.push_back(Idx+1); } // Figure out how many bits we used for the string index. - unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+1); + unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2); // To reduce code size, we compactify common instructions into a few bits // in the opcode-indexed table. @@ -557,17 +610,8 @@ void AsmWriterEmitter::run(raw_ostream &O) { std::vector<std::vector<std::string> > TableDrivenOperandPrinters; - bool isFirst = true; while (1) { std::vector<std::string> UniqueOperandCommands; - - // For the first operand check, add a default value for instructions with - // just opcode strings to use. - if (isFirst) { - UniqueOperandCommands.push_back(" return true;\n"); - isFirst = false; - } - std::vector<unsigned> InstIdxs; std::vector<unsigned> NumInstOpsHandled; FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, @@ -582,8 +626,8 @@ void AsmWriterEmitter::run(raw_ostream &O) { // If we don't have enough bits for this operand, don't include it. if (NumBits > BitsLeft) { - DOUT << "Not enough bits to densely encode " << NumBits - << " more bits\n"; + DEBUG(errs() << "Not enough bits to densely encode " << NumBits + << " more bits\n"); break; } @@ -621,52 +665,24 @@ void AsmWriterEmitter::run(raw_ostream &O) { O << " };\n\n"; // Emit the string itself. - O << " const char *AsmStrs = \n \""; - unsigned CharsPrinted = 0; - EscapeString(AggregateString); - for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) { - if (CharsPrinted > 70) { - O << "\"\n \""; - CharsPrinted = 0; - } - O << AggregateString[i]; - ++CharsPrinted; - - // Print escape sequences all together. - if (AggregateString[i] == '\\') { - assert(i+1 < AggregateString.size() && "Incomplete escape sequence!"); - if (isdigit(AggregateString[i+1])) { - assert(isdigit(AggregateString[i+2]) && isdigit(AggregateString[i+3]) && - "Expected 3 digit octal escape!"); - O << AggregateString[++i]; - O << AggregateString[++i]; - O << AggregateString[++i]; - CharsPrinted += 3; - } else { - O << AggregateString[++i]; - ++CharsPrinted; - } - } - } - O << "\";\n\n"; - - O << " processDebugLoc(MI->getDebugLoc());\n\n"; + O << " const char *AsmStrs = \n"; + StringTable.EmitString(O); + O << ";\n\n"; O << "\n#ifndef NO_ASM_WRITER_BOILERPLATE\n"; O << " if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {\n" << " O << \"\\t\";\n" << " printInlineAsm(MI);\n" - << " return true;\n" + << " return;\n" << " } else if (MI->isLabel()) {\n" << " printLabel(MI);\n" - << " return true;\n" - << " } else if (MI->getOpcode() == TargetInstrInfo::DECLARE) {\n" - << " printDeclare(MI);\n" - << " return true;\n" + << " return;\n" << " } else if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF) {\n" << " printImplicitDef(MI);\n" - << " return true;\n" + << " return;\n" + << " } else if (MI->getOpcode() == TargetInstrInfo::KILL) {\n" + << " return;\n" << " }\n\n"; O << "\n#endif\n"; @@ -675,8 +691,8 @@ void AsmWriterEmitter::run(raw_ostream &O) { O << " // Emit the opcode for the instruction.\n" << " unsigned Bits = OpInfo[MI->getOpcode()];\n" - << " if (Bits == 0) return false;\n" - << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ");\n\n"; + << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" + << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n"; // Output the table driven operand information. BitsLeft = 32-AsmStrBits; @@ -732,6 +748,11 @@ void AsmWriterEmitter::run(raw_ostream &O) { // elements in the vector. std::reverse(Instructions.begin(), Instructions.end()); + + // Now that we've emitted all of the operand info that fit into 32 bits, emit + // information for those instructions that are left. This is a less dense + // encoding, but we expect the main 32-bit table to handle the majority of + // instructions. if (!Instructions.empty()) { // Find the opcode # of inline asm. O << " switch (MI->getOpcode()) {\n"; @@ -739,8 +760,61 @@ void AsmWriterEmitter::run(raw_ostream &O) { EmitInstructions(Instructions, O); O << " }\n"; - O << " return true;\n"; + O << " return;\n"; } - + + O << " return;\n"; O << "}\n"; } + + +void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { + CodeGenTarget Target; + Record *AsmWriter = Target.getAsmWriter(); + std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); + const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); + + StringToOffsetTable StringTable; + O << + "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" + "/// from the register set description. This returns the assembler name\n" + "/// for the specified register.\n" + "const char *" << Target.getName() << ClassName + << "::getRegisterName(unsigned RegNo) {\n" + << " assert(RegNo && RegNo < " << (Registers.size()+1) + << " && \"Invalid register number!\");\n" + << "\n" + << " static const unsigned RegAsmOffset[] = {"; + for (unsigned i = 0, e = Registers.size(); i != e; ++i) { + const CodeGenRegister &Reg = Registers[i]; + + std::string AsmName = Reg.TheDef->getValueAsString("AsmName"); + if (AsmName.empty()) + AsmName = Reg.getName(); + + + if ((i % 14) == 0) + O << "\n "; + + O << StringTable.GetOrAddStringOffset(AsmName) << ", "; + } + O << "0\n" + << " };\n" + << "\n"; + + O << " const char *AsmStrs =\n"; + StringTable.EmitString(O); + O << ";\n"; + + O << " return AsmStrs+RegAsmOffset[RegNo-1];\n" + << "}\n"; +} + + +void AsmWriterEmitter::run(raw_ostream &O) { + EmitSourceFileHeader("Assembly Writer Source Fragment", O); + + EmitPrintInstruction(O); + EmitGetRegisterName(O); +} + |