2004-08-01 13:59:33 +08:00
|
|
|
//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
|
2005-04-22 08:00:37 +08:00
|
|
|
//
|
2004-08-01 13:59:33 +08:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by the LLVM research group and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
2005-04-22 08:00:37 +08:00
|
|
|
//
|
2004-08-01 13:59:33 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This tablegen backend is emits an assembly printer for the current target.
|
|
|
|
// Note that this is currently fairly skeletal, but will grow over time.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "AsmWriterEmitter.h"
|
|
|
|
#include "CodeGenTarget.h"
|
2004-08-15 06:50:53 +08:00
|
|
|
#include "Record.h"
|
2005-01-23 02:50:10 +08:00
|
|
|
#include <algorithm>
|
2004-08-01 13:59:33 +08:00
|
|
|
#include <ostream>
|
|
|
|
using namespace llvm;
|
|
|
|
|
2004-08-01 15:43:02 +08:00
|
|
|
static bool isIdentChar(char C) {
|
|
|
|
return (C >= 'a' && C <= 'z') ||
|
|
|
|
(C >= 'A' && C <= 'Z') ||
|
|
|
|
(C >= '0' && C <= '9') ||
|
|
|
|
C == '_';
|
|
|
|
}
|
|
|
|
|
2005-01-23 01:32:42 +08:00
|
|
|
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){}
|
|
|
|
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
bool operator!=(const AsmWriterOperand &Other) const {
|
|
|
|
if (OperandType != Other.OperandType || Str != Other.Str) return true;
|
|
|
|
if (OperandType == isMachineInstrOperand)
|
|
|
|
return MIOpNo != Other.MIOpNo || OpVT != Other.OpVT;
|
|
|
|
return false;
|
|
|
|
}
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
bool operator==(const AsmWriterOperand &Other) const {
|
|
|
|
return !operator!=(Other);
|
|
|
|
}
|
2005-01-23 01:32:42 +08:00
|
|
|
void EmitCode(std::ostream &OS) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct AsmWriterInst {
|
|
|
|
std::vector<AsmWriterOperand> Operands;
|
2005-01-23 01:40:38 +08:00
|
|
|
const CodeGenInstruction *CGI;
|
2005-04-22 08:00:37 +08:00
|
|
|
|
2005-01-23 01:40:38 +08:00
|
|
|
AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant);
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
|
2005-01-23 03:22:23 +08:00
|
|
|
/// 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;
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
|
2005-01-23 01:32:42 +08:00
|
|
|
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
|
2005-01-23 04:59:38 +08:00
|
|
|
OS << Str << "(MI, " << MIOpNo << ", MVT::" << getEnumName(OpVT) << "); ";
|
2005-01-23 01:32:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ParseAsmString - Parse the specified Instruction's AsmString into this
|
|
|
|
/// AsmWriterInst.
|
|
|
|
///
|
2005-01-23 01:40:38 +08:00
|
|
|
AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) {
|
|
|
|
this->CGI = &CGI;
|
2005-01-23 01:32:42 +08:00
|
|
|
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)
|
2005-07-27 14:12:32 +08:00
|
|
|
throw "Nested variants found for instruction '" +
|
2005-07-16 06:43:04 +08:00
|
|
|
CGI.TheDef->getName() + "'!";
|
2005-01-23 01:32:42 +08:00
|
|
|
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)
|
2005-07-27 14:12:32 +08:00
|
|
|
throw "Incomplete variant for instruction '" +
|
2005-07-16 06:43:04 +08:00
|
|
|
CGI.TheDef->getName() + "'!";
|
2005-01-23 01:32:42 +08:00
|
|
|
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 '"
|
2005-07-16 06:43:04 +08:00
|
|
|
+ CGI.TheDef->getName() + "'!";
|
2005-01-23 01:32:42 +08:00
|
|
|
// Move to the end of variant list.
|
|
|
|
std::string::size_type NP = AsmString.find('}', LastEmitted);
|
|
|
|
if (NP == std::string::npos)
|
2005-07-27 14:12:32 +08:00
|
|
|
throw "Incomplete variant for instruction '" +
|
2005-07-16 06:43:04 +08:00
|
|
|
CGI.TheDef->getName() + "'!";
|
2005-01-23 01:32:42 +08:00
|
|
|
LastEmitted = NP+1;
|
|
|
|
inVariant = false;
|
|
|
|
} else if (AsmString[DollarPos] == '}') {
|
|
|
|
if (!inVariant)
|
|
|
|
throw "'}' character found outside of a variant in instruction '"
|
2005-07-16 06:43:04 +08:00
|
|
|
+ CGI.TheDef->getName() + "'!";
|
2005-01-23 01:32:42 +08:00
|
|
|
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.
|
|
|
|
std::string::size_type VarEnd = DollarPos+1;
|
2005-07-15 06:50:30 +08:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
bool hasCurlyBraces = false;
|
|
|
|
if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) {
|
|
|
|
hasCurlyBraces = true;
|
|
|
|
++DollarPos;
|
|
|
|
++VarEnd;
|
|
|
|
}
|
|
|
|
|
2005-01-23 01:32:42 +08:00
|
|
|
while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
|
|
|
|
++VarEnd;
|
|
|
|
std::string VarName(AsmString.begin()+DollarPos+1,
|
|
|
|
AsmString.begin()+VarEnd);
|
2005-07-15 06:50:30 +08:00
|
|
|
|
|
|
|
// In order to avoid starting the next string at the terminating curly
|
|
|
|
// brace, advance the end position past it if we found an opening curly
|
|
|
|
// brace.
|
|
|
|
if (hasCurlyBraces) {
|
|
|
|
if (VarEnd >= AsmString.size())
|
|
|
|
throw "Reached end of string before terminating curly brace in '"
|
2005-07-16 06:43:04 +08:00
|
|
|
+ CGI.TheDef->getName() + "'";
|
2005-07-15 06:50:30 +08:00
|
|
|
if (AsmString[VarEnd] != '}')
|
|
|
|
throw "Variant name beginning with '{' did not end with '}' in '"
|
2005-07-16 06:43:04 +08:00
|
|
|
+ CGI.TheDef->getName() + "'";
|
2005-07-15 06:50:30 +08:00
|
|
|
++VarEnd;
|
|
|
|
}
|
2005-01-23 01:32:42 +08:00
|
|
|
if (VarName.empty())
|
2005-07-27 14:12:32 +08:00
|
|
|
throw "Stray '$' in '" + CGI.TheDef->getName() +
|
2005-07-16 06:43:04 +08:00
|
|
|
"' asm string, maybe you want $$?";
|
2005-01-23 01:32:42 +08:00
|
|
|
|
|
|
|
unsigned OpNo = CGI.getOperandNamed(VarName);
|
2005-01-23 01:40:38 +08:00
|
|
|
CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
|
2005-01-23 01:32:42 +08:00
|
|
|
|
|
|
|
// If this is a two-address instruction and we are not accessing the
|
|
|
|
// 0th operand, remove an operand.
|
2005-01-23 01:40:38 +08:00
|
|
|
unsigned MIOp = OpInfo.MIOperandNo;
|
2005-01-23 01:32:42 +08:00
|
|
|
if (CGI.isTwoAddress && MIOp != 0) {
|
|
|
|
if (MIOp == 1)
|
|
|
|
throw "Should refer to operand #0 instead of #1 for two-address"
|
2005-07-16 06:43:04 +08:00
|
|
|
" instruction '" + CGI.TheDef->getName() + "'!";
|
2005-01-23 01:32:42 +08:00
|
|
|
--MIOp;
|
|
|
|
}
|
|
|
|
|
2005-01-23 01:40:38 +08:00
|
|
|
Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName,
|
|
|
|
MIOp, OpInfo.Ty));
|
2005-01-23 01:32:42 +08:00
|
|
|
LastEmitted = VarEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AddLiteralString("\\n");
|
|
|
|
}
|
|
|
|
|
2005-01-23 03:22:23 +08:00
|
|
|
/// 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;
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
|
|
|
|
unsigned MismatchOperand = ~0U;
|
|
|
|
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
|
|
|
|
if (Operands[i] != Other.Operands[i])
|
2005-01-23 03:22:23 +08:00
|
|
|
if (MismatchOperand != ~0U) // Already have one mismatch?
|
|
|
|
return ~1U;
|
2005-04-22 08:00:37 +08:00
|
|
|
else
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
MismatchOperand = i;
|
|
|
|
}
|
|
|
|
return MismatchOperand;
|
|
|
|
}
|
|
|
|
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
static void PrintCases(std::vector<std::pair<std::string,
|
|
|
|
AsmWriterOperand> > &OpsToPrint, std::ostream &O) {
|
|
|
|
O << " case " << OpsToPrint.back().first << ": ";
|
|
|
|
AsmWriterOperand TheOp = OpsToPrint.back().second;
|
|
|
|
OpsToPrint.pop_back();
|
|
|
|
|
|
|
|
// Check to see if any other operands are identical in this list, and if so,
|
|
|
|
// emit a case label for them.
|
|
|
|
for (unsigned i = OpsToPrint.size(); i != 0; --i)
|
|
|
|
if (OpsToPrint[i-1].second == TheOp) {
|
|
|
|
O << "\n case " << OpsToPrint[i-1].first << ": ";
|
|
|
|
OpsToPrint.erase(OpsToPrint.begin()+i-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, emit the code.
|
|
|
|
TheOp.EmitCode(O);
|
|
|
|
O << "break;\n";
|
|
|
|
}
|
|
|
|
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
|
|
|
|
/// EmitInstructions - Emit the last instruction in the vector and any other
|
|
|
|
/// instructions that are suitably similar to it.
|
|
|
|
static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
|
|
|
|
std::ostream &O) {
|
|
|
|
AsmWriterInst FirstInst = Insts.back();
|
|
|
|
Insts.pop_back();
|
|
|
|
|
|
|
|
std::vector<AsmWriterInst> SimilarInsts;
|
|
|
|
unsigned DifferingOperand = ~0;
|
|
|
|
for (unsigned i = Insts.size(); i != 0; --i) {
|
2005-01-23 03:22:23 +08:00
|
|
|
unsigned DiffOp = Insts[i-1].MatchesAllButOneOp(FirstInst);
|
|
|
|
if (DiffOp != ~1U) {
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
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.
|
2005-01-23 03:22:23 +08:00
|
|
|
if (DifferingOperand == DiffOp || DiffOp == ~0U) {
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
SimilarInsts.push_back(Insts[i-1]);
|
|
|
|
Insts.erase(Insts.begin()+i-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Namespace = FirstInst.CGI->Namespace;
|
|
|
|
|
|
|
|
O << " case " << Namespace << "::"
|
|
|
|
<< FirstInst.CGI->TheDef->getName() << ":\n";
|
|
|
|
for (unsigned i = 0, e = SimilarInsts.size(); i != e; ++i)
|
|
|
|
O << " case " << Namespace << "::"
|
|
|
|
<< SimilarInsts[i].CGI->TheDef->getName() << ":\n";
|
|
|
|
for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
|
|
|
|
if (i != DifferingOperand) {
|
|
|
|
// If the operand is the same for all instructions, just print it.
|
|
|
|
O << " ";
|
|
|
|
FirstInst.Operands[i].EmitCode(O);
|
|
|
|
} else {
|
|
|
|
// If this is the operand that varies between all of the instructions,
|
|
|
|
// emit a switch for just this operand now.
|
|
|
|
O << " switch (MI->getOpcode()) {\n";
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint;
|
|
|
|
OpsToPrint.push_back(std::make_pair(Namespace+"::"+
|
|
|
|
FirstInst.CGI->TheDef->getName(),
|
|
|
|
FirstInst.Operands[i]));
|
2005-04-22 08:00:37 +08:00
|
|
|
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
for (unsigned si = 0, e = SimilarInsts.size(); si != e; ++si) {
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
AsmWriterInst &AWI = SimilarInsts[si];
|
|
|
|
OpsToPrint.push_back(std::make_pair(Namespace+"::"+
|
|
|
|
AWI.CGI->TheDef->getName(),
|
|
|
|
AWI.Operands[i]));
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
}
|
This is the final big of factoring. This shares cases in suboperand
differences, which means that identical instructions (after stripping off
the first literal string) do not run any different code at all. On the X86,
this turns this code:
switch (MI->getOpcode()) {
case X86::ADC32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADC32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi: printOperand(MI, 4, MVT::i32); break;
case X86::ADD32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::ADD32mr: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi: printOperand(MI, 4, MVT::i32); break;
case X86::AND32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::AND32mr: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mi: printOperand(MI, 4, MVT::i32); break;
case X86::CMP32mr: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mi: printOperand(MI, 4, MVT::i32); break;
case X86::MOV32mr: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::OR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::OR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ROL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::ROR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SAR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SBB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SBB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::SHL32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHLD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SHR32mi: printOperand(MI, 4, MVT::i8); break;
case X86::SHRD32mrCL: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi: printOperand(MI, 4, MVT::i32); break;
case X86::SUB32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::SUB32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mi: printOperand(MI, 4, MVT::i32); break;
case X86::TEST32mr: printOperand(MI, 4, MVT::i32); break;
case X86::TEST8mi: printOperand(MI, 4, MVT::i8); break;
case X86::XCHG32mr: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi: printOperand(MI, 4, MVT::i32); break;
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
}
into this:
switch (MI->getOpcode()) {
case X86::ADC32mi:
case X86::ADC32mr:
case X86::ADD32mi:
case X86::ADD32mr:
case X86::AND32mi:
case X86::AND32mr:
case X86::CMP32mi:
case X86::CMP32mr:
case X86::MOV32mi:
case X86::MOV32mr:
case X86::OR32mi:
case X86::OR32mr:
case X86::SBB32mi:
case X86::SBB32mr:
case X86::SHLD32mrCL:
case X86::SHRD32mrCL:
case X86::SUB32mi:
case X86::SUB32mr:
case X86::TEST32mi:
case X86::TEST32mr:
case X86::XCHG32mr:
case X86::XOR32mi:
case X86::XOR32mr: printOperand(MI, 4, MVT::i32); break;
case X86::ADC32mi8:
case X86::ADD32mi8:
case X86::AND32mi8:
case X86::OR32mi8:
case X86::ROL32mi:
case X86::ROR32mi:
case X86::SAR32mi:
case X86::SBB32mi8:
case X86::SHL32mi:
case X86::SHR32mi:
case X86::SUB32mi8:
case X86::TEST8mi:
case X86::XOR32mi8: printOperand(MI, 4, MVT::i8); break;
}
After this, the generated asmwriters look pretty much as though they were
generated by hand. This shrinks the X86 asmwriter.inc files from 55101->39669
and 55429->39551 bytes each, and PPC from 16766->12859 bytes.
llvm-svn: 19760
2005-01-23 04:31:17 +08:00
|
|
|
std::reverse(OpsToPrint.begin(), OpsToPrint.end());
|
|
|
|
while (!OpsToPrint.empty())
|
|
|
|
PrintCases(OpsToPrint, O);
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
O << " }";
|
|
|
|
}
|
|
|
|
O << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
O << " break;\n";
|
|
|
|
}
|
2005-01-23 01:32:42 +08:00
|
|
|
|
2004-08-01 13:59:33 +08:00
|
|
|
void AsmWriterEmitter::run(std::ostream &O) {
|
|
|
|
EmitSourceFileHeader("Assembly Writer Source Fragment", O);
|
|
|
|
|
|
|
|
CodeGenTarget Target;
|
2004-08-15 06:50:53 +08:00
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
2004-10-04 04:19:02 +08:00
|
|
|
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
|
|
|
unsigned Variant = AsmWriter->getValueAsInt("Variant");
|
2004-08-15 06:50:53 +08:00
|
|
|
|
2004-08-01 13:59:33 +08:00
|
|
|
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"
|
2004-10-04 04:19:02 +08:00
|
|
|
"bool " << Target.getName() << ClassName
|
2004-08-15 06:50:53 +08:00
|
|
|
<< "::printInstruction(const MachineInstr *MI) {\n";
|
2004-08-01 13:59:33 +08:00
|
|
|
|
|
|
|
std::string Namespace = Target.inst_begin()->second.Namespace;
|
|
|
|
|
2005-01-23 01:40:38 +08:00
|
|
|
std::vector<AsmWriterInst> Instructions;
|
|
|
|
|
2004-08-01 13:59:33 +08:00
|
|
|
for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
|
|
|
|
E = Target.inst_end(); I != E; ++I)
|
2005-01-23 01:40:38 +08:00
|
|
|
if (!I->second.AsmString.empty())
|
|
|
|
Instructions.push_back(AsmWriterInst(I->second, Variant));
|
|
|
|
|
2005-01-23 03:22:23 +08:00
|
|
|
// 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
|
2005-04-22 08:00:37 +08:00
|
|
|
// of requiring a switch for them.
|
2005-01-23 03:22:23 +08:00
|
|
|
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;
|
|
|
|
}
|
2005-04-22 08:00:37 +08:00
|
|
|
|
2005-01-23 03:22:23 +08:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
// 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());
|
2005-01-23 03:22:23 +08:00
|
|
|
|
|
|
|
O << " switch (MI->getOpcode()) {\n"
|
|
|
|
" default: return false;\n";
|
2005-04-22 08:00:37 +08:00
|
|
|
|
Implement factoring of instruction pattern strings. In particular, instead of
emitting code like this:
case PPC::ADD: O << "add "; printOperand(MI, 0, MVT::i64); O << ", "; prin
tOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '\n
'; break;
case PPC::ADDC: O << "addc "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
case PPC::ADDE: O << "adde "; printOperand(MI, 0, MVT::i64); O << ", "; pr
intOperand(MI, 1, MVT::i64); O << ", "; printOperand(MI, 2, MVT::i64); O << '
\n'; break;
...
Emit code like this:
case PPC::ADD:
case PPC::ADDC:
case PPC::ADDE:
...
switch (MI->getOpcode()) {
case PPC::ADD: O << "add "; break;
case PPC::ADDC: O << "addc "; break;
case PPC::ADDE: O << "adde "; break;
...
}
printOperand(MI, 0, MVT::i64);
O << ", ";
printOperand(MI, 1, MVT::i64);
O << ", ";
printOperand(MI, 2, MVT::i64);
O << "\n";
break;
This shrinks the PPC asm writer from 24785->15205 bytes (even though the new
asmwriter has much more whitespace than the old one), and the X86 printers shrink
quite a bit too. The important implication of this is that GCC no longer hits swap
when building the PPC backend in optimized mode. Thus this fixes PR448.
-Chris
llvm-svn: 19755
2005-01-23 02:38:13 +08:00
|
|
|
while (!Instructions.empty())
|
|
|
|
EmitInstructions(Instructions, O);
|
|
|
|
|
2004-08-01 13:59:33 +08:00
|
|
|
O << " }\n"
|
|
|
|
" return true;\n"
|
|
|
|
"}\n";
|
|
|
|
}
|