Implement *even more* factoring. In particular, if all of the instruction

strings starts out with a constant string, we emit the string first, using
a table lookup (instead of a switch statement).

Because this is usually the opcode portion of the asm string, the differences
between the instructions have now been greatly reduced.  This allows many
more case statements to be grouped together.

This patch also allows instruction cases to be grouped together when the
instruction patterns are exactly identical (common after the opcode string
has been ripped off), and when the differing operand is a MachineInstr
operand that needs to be formatted.

The end result of this is a mean and lean generated AsmPrinter!


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19759 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2005-01-22 19:22:23 +00:00
parent d648867173
commit f876668518

View File

@ -64,10 +64,10 @@ namespace {
AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant);
/// MatchesAllButOneString - If this instruction is exactly identical to the
/// specified instruction except for one differing literal string, return
/// the operand number of the literal string. Otherwise return ~0.
unsigned MatchesAllButOneString(const AsmWriterInst &Other) const;
/// MatchesAllButOneOp - If this instruction is exactly identical to the
/// specified instruction except for one differing operand, return the
/// differing operand number. Otherwise return ~0.
unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const;
private:
void AddLiteralString(const std::string &Str) {
@ -183,21 +183,18 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) {
AddLiteralString("\\n");
}
/// MatchesAllButOneString - If this instruction is exactly identical to the
/// specified instruction except for one differing literal string, return
/// the operand number of the literal string. Otherwise return ~0.
unsigned AsmWriterInst::MatchesAllButOneString(const AsmWriterInst &Other)const{
if (Operands.size() != Other.Operands.size()) return ~0;
/// MatchesAllButOneOp - If this instruction is exactly identical to the
/// specified instruction except for one differing operand, return the differing
/// operand number. If more than one operand mismatches, return ~1, otherwise
/// if the instructions are identical return ~0.
unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{
if (Operands.size() != Other.Operands.size()) return ~1;
unsigned MismatchOperand = ~0U;
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
if (Operands[i].OperandType != Other.Operands[i].OperandType)
return ~0U;
if (Operands[i] != Other.Operands[i])
if (Operands[i].OperandType == AsmWriterOperand::isMachineInstrOperand ||
MismatchOperand != ~0U)
return ~0U;
if (MismatchOperand != ~0U) // Already have one mismatch?
return ~1U;
else
MismatchOperand = i;
}
@ -215,14 +212,14 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
std::vector<AsmWriterInst> SimilarInsts;
unsigned DifferingOperand = ~0;
for (unsigned i = Insts.size(); i != 0; --i) {
unsigned DiffOp = Insts[i-1].MatchesAllButOneString(FirstInst);
if (DiffOp != ~0U) {
unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst);
if (DiffOp != ~1U) {
if (DifferingOperand == ~0U) // First match!
DifferingOperand = DiffOp;
// If this differs in the same operand as the rest of the instructions in
// this class, move it to the SimilarInsts list.
if (DifferingOperand == DiffOp) {
if (DifferingOperand == DiffOp || DiffOp == ~0U) {
SimilarInsts.push_back(Insts[i-1]);
Insts.erase(Insts.begin()+i-1);
}
@ -278,8 +275,6 @@ void AsmWriterEmitter::run(std::ostream &O) {
"/// it returns false.\n"
"bool " << Target.getName() << ClassName
<< "::printInstruction(const MachineInstr *MI) {\n";
O << " switch (MI->getOpcode()) {\n"
" default: return false;\n";
std::string Namespace = Target.inst_begin()->second.Namespace;
@ -290,9 +285,56 @@ void AsmWriterEmitter::run(std::ostream &O) {
if (!I->second.AsmString.empty())
Instructions.push_back(AsmWriterInst(I->second, Variant));
// If all of the instructions start with a constant string (a very very common
// occurance), emit all of the constant strings as a big table lookup instead
// of requiring a switch for them.
bool AllStartWithString = true;
for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
if (Instructions[i].Operands.empty() ||
Instructions[i].Operands[0].OperandType !=
AsmWriterOperand::isLiteralTextOperand) {
AllStartWithString = false;
break;
}
if (AllStartWithString) {
// Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not
// all machine instructions are necessarily being printed, so there may be
// target instructions not in this map.
std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i]));
// Emit a table of constant strings.
std::vector<const CodeGenInstruction*> NumberedInstructions;
Target.getInstructionsByEnumValue(NumberedInstructions);
O << " static const char * const OpStrs[] = {\n";
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]];
if (AWI == 0) {
// Something not handled by the asmwriter printer.
O << " 0,\t// ";
} else {
O << " \"" << AWI->Operands[0].Str << "\",\t// ";
// Nuke the string from the operand list. It is now handled!
AWI->Operands.erase(AWI->Operands.begin());
}
O << NumberedInstructions[i]->TheDef->getName() << "\n";
}
O << " };\n\n"
<< " // Emit the opcode for the instruction.\n"
<< " if (const char *AsmStr = OpStrs[MI->getOpcode()])\n"
<< " O << AsmStr;\n\n";
}
// Because this is a vector we want to emit from the end. Reverse all of the
// elements in the vector.
std::reverse(Instructions.begin(), Instructions.end());
O << " switch (MI->getOpcode()) {\n"
" default: return false;\n";
while (!Instructions.empty())
EmitInstructions(Instructions, O);