2004-08-01 05:59:33 +00:00
|
|
|
//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
|
2005-04-22 00:00:37 +00:00
|
|
|
//
|
2004-08-01 05:59:33 +00:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:37:13 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-04-22 00:00:37 +00:00
|
|
|
//
|
2004-08-01 05:59:33 +00: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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-02-09 21:50:41 +00:00
|
|
|
#include "AsmWriterInst.h"
|
2004-08-01 05:59:33 +00:00
|
|
|
#include "CodeGenTarget.h"
|
2012-03-30 21:12:52 +00:00
|
|
|
#include "SequenceToOffsetTable.h"
|
2014-04-29 23:26:49 +00:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2012-07-27 06:44:02 +00:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2011-06-27 21:06:21 +00:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2006-07-18 17:18:03 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
2013-09-11 15:42:16 +00:00
|
|
|
#include "llvm/Support/Format.h"
|
2006-07-18 17:18:03 +00:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2011-10-01 16:41:13 +00:00
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
2012-06-11 15:37:55 +00:00
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
2005-01-22 18:50:10 +00:00
|
|
|
#include <algorithm>
|
2012-06-11 15:37:55 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
2004-08-01 05:59:33 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-21 22:55:11 +00:00
|
|
|
#define DEBUG_TYPE "asm-writer-emitter"
|
|
|
|
|
2012-06-11 15:37:55 +00:00
|
|
|
namespace {
|
|
|
|
class AsmWriterEmitter {
|
|
|
|
RecordKeeper &Records;
|
2013-10-28 18:07:17 +00:00
|
|
|
CodeGenTarget Target;
|
2012-06-11 15:37:55 +00:00
|
|
|
std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
|
2014-02-05 07:56:49 +00:00
|
|
|
const std::vector<const CodeGenInstruction*> *NumberedInstructions;
|
2013-10-28 18:07:17 +00:00
|
|
|
std::vector<AsmWriterInst> Instructions;
|
2014-05-12 18:04:06 +00:00
|
|
|
std::vector<std::string> PrintMethods;
|
2012-06-11 15:37:55 +00:00
|
|
|
public:
|
2013-10-28 18:07:17 +00:00
|
|
|
AsmWriterEmitter(RecordKeeper &R);
|
2012-06-11 15:37:55 +00:00
|
|
|
|
|
|
|
void run(raw_ostream &o);
|
|
|
|
|
|
|
|
private:
|
|
|
|
void EmitPrintInstruction(raw_ostream &o);
|
|
|
|
void EmitGetRegisterName(raw_ostream &o);
|
|
|
|
void EmitPrintAliasInstruction(raw_ostream &O);
|
|
|
|
|
|
|
|
AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
|
2014-02-05 07:56:49 +00:00
|
|
|
assert(ID < NumberedInstructions->size());
|
2012-06-11 15:37:55 +00:00
|
|
|
std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I =
|
2014-02-05 07:56:49 +00:00
|
|
|
CGIAWIMap.find(NumberedInstructions->at(ID));
|
2012-06-11 15:37:55 +00:00
|
|
|
assert(I != CGIAWIMap.end() && "Didn't find inst!");
|
|
|
|
return I->second;
|
|
|
|
}
|
|
|
|
void FindUniqueOperandCommands(std::vector<std::string> &UOC,
|
|
|
|
std::vector<unsigned> &InstIdxs,
|
|
|
|
std::vector<unsigned> &InstOpsUsed) const;
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00:00
|
|
|
static void PrintCases(std::vector<std::pair<std::string,
|
2009-07-03 00:10:29 +00:00
|
|
|
AsmWriterOperand> > &OpsToPrint, raw_ostream &O) {
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00:00
|
|
|
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.
|
2006-07-18 17:18:03 +00:00
|
|
|
O << TheOp.getCode();
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00:00
|
|
|
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00: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,
|
2009-07-03 00:10:29 +00:00
|
|
|
raw_ostream &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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
AsmWriterInst FirstInst = Insts.back();
|
|
|
|
Insts.pop_back();
|
|
|
|
|
|
|
|
std::vector<AsmWriterInst> SimilarInsts;
|
|
|
|
unsigned DifferingOperand = ~0;
|
|
|
|
for (unsigned i = Insts.size(); i != 0; --i) {
|
2005-01-22 19:22:23 +00: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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00: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-22 19:22:23 +00: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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
SimilarInsts.push_back(Insts[i-1]);
|
|
|
|
Insts.erase(Insts.begin()+i-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-01 17:01:17 +00:00
|
|
|
O << " case " << FirstInst.CGI->Namespace << "::"
|
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
<< FirstInst.CGI->TheDef->getName() << ":\n";
|
2016-01-08 07:06:32 +00:00
|
|
|
for (const AsmWriterInst &AWI : SimilarInsts)
|
|
|
|
O << " case " << AWI.CGI->Namespace << "::"
|
|
|
|
<< AWI.CGI->TheDef->getName() << ":\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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
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.
|
2006-07-18 17:18:03 +00:00
|
|
|
O << " " << FirstInst.Operands[i].getCode();
|
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
} 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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00:00
|
|
|
std::vector<std::pair<std::string, AsmWriterOperand> > OpsToPrint;
|
2006-05-01 17:01:17 +00:00
|
|
|
OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace + "::" +
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00:00
|
|
|
FirstInst.CGI->TheDef->getName(),
|
|
|
|
FirstInst.Operands[i]));
|
2005-04-22 00:00:37 +00:00
|
|
|
|
2016-01-08 07:06:32 +00:00
|
|
|
for (const AsmWriterInst &AWI : SimilarInsts) {
|
2006-05-01 17:01:17 +00:00
|
|
|
OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace+"::"+
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00:00
|
|
|
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19760 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 20:31:17 +00: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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
O << " }";
|
|
|
|
}
|
|
|
|
O << "\n";
|
|
|
|
}
|
|
|
|
O << " break;\n";
|
|
|
|
}
|
2005-01-22 17:32:42 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
void AsmWriterEmitter::
|
2010-09-29 22:32:50 +00:00
|
|
|
FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
|
2006-07-18 18:28:27 +00:00
|
|
|
std::vector<unsigned> &InstIdxs,
|
|
|
|
std::vector<unsigned> &InstOpsUsed) const {
|
2014-02-05 07:56:49 +00:00
|
|
|
InstIdxs.assign(NumberedInstructions->size(), ~0U);
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// This vector parallels UniqueOperandCommands, keeping track of which
|
|
|
|
// instructions each case are used for. It is a comma separated string of
|
|
|
|
// enums.
|
|
|
|
std::vector<std::string> InstrsForCase;
|
|
|
|
InstrsForCase.resize(UniqueOperandCommands.size());
|
2006-07-18 18:28:27 +00:00
|
|
|
InstOpsUsed.assign(UniqueOperandCommands.size(), 0);
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2014-02-05 07:56:49 +00:00
|
|
|
for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) {
|
2006-07-18 17:18:03 +00:00
|
|
|
const AsmWriterInst *Inst = getAsmWriterInstByID(i);
|
2014-04-15 07:20:03 +00:00
|
|
|
if (!Inst)
|
2014-03-07 06:08:31 +00:00
|
|
|
continue; // PHI, INLINEASM, CFI_INSTRUCTION, etc.
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:56:07 +00:00
|
|
|
if (Inst->Operands.empty())
|
2006-07-18 17:18:03 +00:00
|
|
|
continue; // Instruction already done.
|
2006-07-18 17:50:22 +00:00
|
|
|
|
2016-01-08 07:06:29 +00:00
|
|
|
std::string Command = " " + Inst->Operands[0].getCode() + "\n";
|
2006-07-18 17:50:22 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Check to see if we already have 'Command' in UniqueOperandCommands.
|
|
|
|
// If not, add it.
|
|
|
|
bool FoundIt = false;
|
|
|
|
for (unsigned idx = 0, e = UniqueOperandCommands.size(); idx != e; ++idx)
|
|
|
|
if (UniqueOperandCommands[idx] == Command) {
|
|
|
|
InstIdxs[i] = idx;
|
|
|
|
InstrsForCase[idx] += ", ";
|
|
|
|
InstrsForCase[idx] += Inst->CGI->TheDef->getName();
|
|
|
|
FoundIt = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!FoundIt) {
|
|
|
|
InstIdxs[i] = UniqueOperandCommands.size();
|
2016-01-08 07:06:29 +00:00
|
|
|
UniqueOperandCommands.push_back(std::move(Command));
|
2006-07-18 17:18:03 +00:00
|
|
|
InstrsForCase.push_back(Inst->CGI->TheDef->getName());
|
2006-07-18 18:28:27 +00:00
|
|
|
|
|
|
|
// This command matches one operand so far.
|
|
|
|
InstOpsUsed.push_back(1);
|
|
|
|
}
|
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
// For each entry of UniqueOperandCommands, there is a set of instructions
|
|
|
|
// that uses it. If the next command of all instructions in the set are
|
|
|
|
// identical, fold it into the command.
|
|
|
|
for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size();
|
|
|
|
CommandIdx != e; ++CommandIdx) {
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
for (unsigned Op = 1; ; ++Op) {
|
|
|
|
// Scan for the first instruction in the set.
|
|
|
|
std::vector<unsigned>::iterator NIT =
|
|
|
|
std::find(InstIdxs.begin(), InstIdxs.end(), CommandIdx);
|
|
|
|
if (NIT == InstIdxs.end()) break; // No commonality.
|
|
|
|
|
|
|
|
// If this instruction has no more operands, we isn't anything to merge
|
|
|
|
// into this command.
|
2010-09-29 22:32:50 +00:00
|
|
|
const AsmWriterInst *FirstInst =
|
2006-07-18 18:28:27 +00:00
|
|
|
getAsmWriterInstByID(NIT-InstIdxs.begin());
|
|
|
|
if (!FirstInst || FirstInst->Operands.size() == Op)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Otherwise, scan to see if all of the other instructions in this command
|
|
|
|
// set share the operand.
|
|
|
|
bool AllSame = true;
|
2009-07-29 20:10:24 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx);
|
|
|
|
NIT != InstIdxs.end();
|
|
|
|
NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) {
|
|
|
|
// Okay, found another instruction in this command set. If the operand
|
|
|
|
// matches, we're ok, otherwise bail out.
|
2010-09-29 22:32:50 +00:00
|
|
|
const AsmWriterInst *OtherInst =
|
2006-07-18 18:28:27 +00:00
|
|
|
getAsmWriterInstByID(NIT-InstIdxs.begin());
|
2009-07-29 20:10:24 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
if (!OtherInst || OtherInst->Operands.size() == Op ||
|
|
|
|
OtherInst->Operands[Op] != FirstInst->Operands[Op]) {
|
|
|
|
AllSame = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!AllSame) break;
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
// Okay, everything in this command set has the same next operand. Add it
|
|
|
|
// to UniqueOperandCommands and remember that it was consumed.
|
|
|
|
std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n";
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
UniqueOperandCommands[CommandIdx] += Command;
|
|
|
|
InstOpsUsed[CommandIdx]++;
|
2006-07-18 17:18:03 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Prepend some of the instructions each case is used for onto the case val.
|
|
|
|
for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {
|
|
|
|
std::string Instrs = InstrsForCase[i];
|
|
|
|
if (Instrs.size() > 70) {
|
|
|
|
Instrs.erase(Instrs.begin()+70, Instrs.end());
|
|
|
|
Instrs += "...";
|
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
if (!Instrs.empty())
|
2010-09-29 22:32:50 +00:00
|
|
|
UniqueOperandCommands[i] = " // " + Instrs + "\n" +
|
2006-07-18 17:18:03 +00:00
|
|
|
UniqueOperandCommands[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-17 20:43:42 +00:00
|
|
|
static void UnescapeString(std::string &Str) {
|
|
|
|
for (unsigned i = 0; i != Str.size(); ++i) {
|
|
|
|
if (Str[i] == '\\' && i != Str.size()-1) {
|
|
|
|
switch (Str[i+1]) {
|
|
|
|
default: continue; // Don't execute the code after the switch.
|
|
|
|
case 'a': Str[i] = '\a'; break;
|
|
|
|
case 'b': Str[i] = '\b'; break;
|
|
|
|
case 'e': Str[i] = 27; break;
|
|
|
|
case 'f': Str[i] = '\f'; break;
|
|
|
|
case 'n': Str[i] = '\n'; break;
|
|
|
|
case 'r': Str[i] = '\r'; break;
|
|
|
|
case 't': Str[i] = '\t'; break;
|
|
|
|
case 'v': Str[i] = '\v'; break;
|
|
|
|
case '"': Str[i] = '\"'; break;
|
|
|
|
case '\'': Str[i] = '\''; break;
|
|
|
|
case '\\': Str[i] = '\\'; break;
|
|
|
|
}
|
|
|
|
// Nuke the second character.
|
|
|
|
Str.erase(Str.begin()+i+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-13 20:08:00 +00:00
|
|
|
/// EmitPrintInstruction - Generate the code for the "printInstruction" method
|
2013-10-28 18:07:17 +00:00
|
|
|
/// implementation. Destroys all instances of AsmWriterInst information, by
|
|
|
|
/// clearing the Instructions vector.
|
2009-09-13 20:08:00 +00:00
|
|
|
void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
|
2004-08-14 22:50:53 +00:00
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
2004-10-03 20:19:02 +00:00
|
|
|
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
2015-03-27 20:36:02 +00:00
|
|
|
unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2004-08-01 05:59:33 +00:00
|
|
|
O <<
|
|
|
|
"/// printInstruction - This method is automatically generated by tablegen\n"
|
2009-09-13 20:08:00 +00:00
|
|
|
"/// from the instruction set description.\n"
|
2009-08-08 01:32:19 +00:00
|
|
|
"void " << Target.getName() << ClassName
|
2015-03-27 20:36:02 +00:00
|
|
|
<< "::printInstruction(const MCInst *MI, "
|
|
|
|
<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
|
|
|
|
<< "raw_ostream &O) {\n";
|
2004-08-01 05:59:33 +00:00
|
|
|
|
2006-07-14 22:59:11 +00:00
|
|
|
// Build an aggregate string, and build a table of offsets into it.
|
2012-04-02 09:13:46 +00:00
|
|
|
SequenceToOffsetTable<std::string> StringTable;
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-09-27 16:44:09 +00:00
|
|
|
/// OpcodeInfo - This encodes the index of the string to use for the first
|
2006-07-18 17:32:27 +00:00
|
|
|
/// chunk of the output as well as indices used for operand printing.
|
2012-09-14 08:33:11 +00:00
|
|
|
std::vector<uint64_t> OpcodeInfo;
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2012-04-02 09:13:46 +00:00
|
|
|
// Add all strings to the string table upfront so it can generate an optimized
|
|
|
|
// representation.
|
2016-01-08 07:06:32 +00:00
|
|
|
for (const CodeGenInstruction *Inst : *NumberedInstructions) {
|
|
|
|
AsmWriterInst *AWI = CGIAWIMap[Inst];
|
2014-04-15 07:20:03 +00:00
|
|
|
if (AWI &&
|
2012-04-18 18:56:33 +00:00
|
|
|
AWI->Operands[0].OperandType ==
|
|
|
|
AsmWriterOperand::isLiteralTextOperand &&
|
2012-04-02 09:13:46 +00:00
|
|
|
!AWI->Operands[0].Str.empty()) {
|
|
|
|
std::string Str = AWI->Operands[0].Str;
|
|
|
|
UnescapeString(Str);
|
|
|
|
StringTable.add(Str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StringTable.layout();
|
|
|
|
|
2006-07-18 17:32:27 +00:00
|
|
|
unsigned MaxStringIdx = 0;
|
2016-01-08 07:06:32 +00:00
|
|
|
for (const CodeGenInstruction *Inst : *NumberedInstructions) {
|
|
|
|
AsmWriterInst *AWI = CGIAWIMap[Inst];
|
2006-07-14 22:59:11 +00:00
|
|
|
unsigned Idx;
|
2014-04-15 07:20:03 +00:00
|
|
|
if (!AWI) {
|
2006-07-14 22:59:11 +00:00
|
|
|
// Something not handled by the asmwriter printer.
|
2009-09-14 01:16:36 +00:00
|
|
|
Idx = ~0U;
|
2010-09-29 22:32:50 +00:00
|
|
|
} else if (AWI->Operands[0].OperandType !=
|
2006-07-19 01:39:06 +00:00
|
|
|
AsmWriterOperand::isLiteralTextOperand ||
|
|
|
|
AWI->Operands[0].Str.empty()) {
|
|
|
|
// Something handled by the asmwriter printer, but with no leading string.
|
2012-04-02 09:13:46 +00:00
|
|
|
Idx = StringTable.get("");
|
2006-07-14 22:59:11 +00:00
|
|
|
} else {
|
2009-09-14 01:16:36 +00:00
|
|
|
std::string Str = AWI->Operands[0].Str;
|
|
|
|
UnescapeString(Str);
|
2012-04-02 09:13:46 +00:00
|
|
|
Idx = StringTable.get(Str);
|
2009-09-14 01:16:36 +00:00
|
|
|
MaxStringIdx = std::max(MaxStringIdx, Idx);
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-14 22:59:11 +00:00
|
|
|
// Nuke the string from the operand list. It is now handled!
|
|
|
|
AWI->Operands.erase(AWI->Operands.begin());
|
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2009-09-14 01:16:36 +00:00
|
|
|
// Bias offset by one since we want 0 as a sentinel.
|
2012-09-14 08:33:11 +00:00
|
|
|
OpcodeInfo.push_back(Idx+1);
|
2006-07-18 17:18:03 +00:00
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:32:27 +00:00
|
|
|
// Figure out how many bits we used for the string index.
|
2009-09-14 01:16:36 +00:00
|
|
|
unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2);
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// To reduce code size, we compactify common instructions into a few bits
|
|
|
|
// in the opcode-indexed table.
|
2012-09-14 08:33:11 +00:00
|
|
|
unsigned BitsLeft = 64-AsmStrBits;
|
2006-07-18 17:18:03 +00:00
|
|
|
|
2014-11-25 20:11:25 +00:00
|
|
|
std::vector<std::vector<std::string>> TableDrivenOperandPrinters;
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:56:07 +00:00
|
|
|
while (1) {
|
2006-07-18 17:18:03 +00:00
|
|
|
std::vector<std::string> UniqueOperandCommands;
|
|
|
|
std::vector<unsigned> InstIdxs;
|
2006-07-18 18:28:27 +00:00
|
|
|
std::vector<unsigned> NumInstOpsHandled;
|
|
|
|
FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,
|
|
|
|
NumInstOpsHandled);
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// If we ran out of operands to print, we're done.
|
|
|
|
if (UniqueOperandCommands.empty()) break;
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Compute the number of bits we need to represent these cases, this is
|
|
|
|
// ceil(log2(numentries)).
|
|
|
|
unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size());
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// If we don't have enough bits for this operand, don't include it.
|
|
|
|
if (NumBits > BitsLeft) {
|
2009-08-23 04:44:11 +00:00
|
|
|
DEBUG(errs() << "Not enough bits to densely encode " << NumBits
|
|
|
|
<< " more bits\n");
|
2006-07-18 17:18:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Otherwise, we can include this in the initial lookup table. Add it in.
|
|
|
|
for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i)
|
2012-09-13 17:43:46 +00:00
|
|
|
if (InstIdxs[i] != ~0U) {
|
2012-09-14 08:33:11 +00:00
|
|
|
OpcodeInfo[i] |= (uint64_t)InstIdxs[i] << (64-BitsLeft);
|
2012-09-13 17:43:46 +00:00
|
|
|
}
|
2012-09-14 08:33:11 +00:00
|
|
|
BitsLeft -= NumBits;
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:56:07 +00:00
|
|
|
// Remove the info about this operand.
|
2014-02-05 07:56:49 +00:00
|
|
|
for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) {
|
2006-07-18 17:56:07 +00:00
|
|
|
if (AsmWriterInst *Inst = getAsmWriterInstByID(i))
|
2006-07-18 18:28:27 +00:00
|
|
|
if (!Inst->Operands.empty()) {
|
|
|
|
unsigned NumOps = NumInstOpsHandled[InstIdxs[i]];
|
2006-07-18 19:06:01 +00:00
|
|
|
assert(NumOps <= Inst->Operands.size() &&
|
|
|
|
"Can't remove this many ops!");
|
2006-07-18 18:28:27 +00:00
|
|
|
Inst->Operands.erase(Inst->Operands.begin(),
|
|
|
|
Inst->Operands.begin()+NumOps);
|
|
|
|
}
|
2006-07-18 17:56:07 +00:00
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:56:07 +00:00
|
|
|
// Remember the handlers for this set of operands.
|
2014-11-25 20:11:25 +00:00
|
|
|
TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands));
|
2006-07-18 17:18:03 +00:00
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2016-01-11 05:13:41 +00:00
|
|
|
// Emit the string table itself.
|
|
|
|
O << " static const char AsmStrs[] = {\n";
|
|
|
|
StringTable.emit(O, printChar);
|
2006-07-14 22:59:11 +00:00
|
|
|
O << " };\n\n";
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2016-01-11 05:13:41 +00:00
|
|
|
// Emit the lookup tables in pieces to minimize wasted bytes.
|
|
|
|
unsigned BytesNeeded = ((64 - BitsLeft) + 7) / 8;
|
|
|
|
unsigned Table = 0, Shift = 0;
|
|
|
|
SmallString<128> BitsString;
|
|
|
|
raw_svector_ostream BitsOS(BitsString);
|
|
|
|
// If the total bits is more than 32-bits we need to use a 64-bit type.
|
|
|
|
BitsOS << " uint" << ((BitsLeft < 32) ? 64 : 32) << "_t Bits = 0;\n";
|
|
|
|
while (BytesNeeded != 0) {
|
|
|
|
// Figure out how big this table section needs to be, but no bigger than 4.
|
|
|
|
unsigned TableSize = std::min(1 << Log2_32(BytesNeeded), 4);
|
|
|
|
BytesNeeded -= TableSize;
|
|
|
|
TableSize *= 8; // Convert to bits;
|
|
|
|
uint64_t Mask = (1ULL << TableSize) - 1;
|
|
|
|
O << " static const uint" << TableSize << "_t OpInfo" << Table
|
|
|
|
<< "[] = {\n";
|
2014-02-05 07:56:49 +00:00
|
|
|
for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) {
|
2016-01-11 05:13:41 +00:00
|
|
|
O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// "
|
2014-02-05 07:56:49 +00:00
|
|
|
<< NumberedInstructions->at(i)->TheDef->getName() << "\n";
|
2012-09-13 17:43:46 +00:00
|
|
|
}
|
|
|
|
O << " };\n\n";
|
2016-01-11 05:13:41 +00:00
|
|
|
// Emit string to combine the individual table lookups.
|
|
|
|
BitsOS << " Bits |= ";
|
|
|
|
// If the total bits is more than 32-bits we need to use a 64-bit type.
|
|
|
|
if (BitsLeft < 32)
|
|
|
|
BitsOS << "(uint64_t)";
|
|
|
|
BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n";
|
|
|
|
// Prepare the shift for the next iteration and increment the table count.
|
|
|
|
Shift += TableSize;
|
|
|
|
++Table;
|
2012-09-13 17:43:46 +00:00
|
|
|
}
|
|
|
|
|
2016-01-11 05:13:41 +00:00
|
|
|
// Emit the initial tab character.
|
2008-02-02 08:39:46 +00:00
|
|
|
O << " O << \"\\t\";\n\n";
|
|
|
|
|
2012-09-14 08:33:11 +00:00
|
|
|
O << " // Emit the opcode for the instruction.\n";
|
2016-01-11 05:13:41 +00:00
|
|
|
O << BitsString;
|
|
|
|
|
|
|
|
// Emit the starting string.
|
2012-09-13 17:43:46 +00:00
|
|
|
O << " assert(Bits != 0 && \"Cannot print this instruction.\");\n"
|
2009-09-14 01:16:36 +00:00
|
|
|
<< " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n";
|
2009-08-05 21:00:52 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Output the table driven operand information.
|
2012-09-14 08:33:11 +00:00
|
|
|
BitsLeft = 64-AsmStrBits;
|
2006-07-18 17:18:03 +00:00
|
|
|
for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {
|
|
|
|
std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];
|
2005-01-22 19:22:23 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Compute the number of bits we need to represent these cases, this is
|
|
|
|
// ceil(log2(numentries)).
|
|
|
|
unsigned NumBits = Log2_32_Ceil(Commands.size());
|
|
|
|
assert(NumBits <= BitsLeft && "consistency error");
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Emit code to extract this field from Bits.
|
|
|
|
O << "\n // Fragment " << i << " encoded into " << NumBits
|
2006-07-18 17:43:54 +00:00
|
|
|
<< " bits for " << Commands.size() << " unique commands.\n";
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 18:28:27 +00:00
|
|
|
if (Commands.size() == 2) {
|
2006-07-18 17:43:54 +00:00
|
|
|
// Emit two possibilitys with if/else.
|
2012-09-14 08:33:11 +00:00
|
|
|
O << " if ((Bits >> "
|
|
|
|
<< (64-BitsLeft) << ") & "
|
2006-07-18 17:43:54 +00:00
|
|
|
<< ((1 << NumBits)-1) << ") {\n"
|
|
|
|
<< Commands[1]
|
|
|
|
<< " } else {\n"
|
|
|
|
<< Commands[0]
|
|
|
|
<< " }\n\n";
|
2010-09-18 18:50:27 +00:00
|
|
|
} else if (Commands.size() == 1) {
|
|
|
|
// Emit a single possibility.
|
|
|
|
O << Commands[0] << "\n\n";
|
2006-07-18 17:43:54 +00:00
|
|
|
} else {
|
2012-09-14 08:33:11 +00:00
|
|
|
O << " switch ((Bits >> "
|
|
|
|
<< (64-BitsLeft) << ") & "
|
2006-07-18 17:43:54 +00:00
|
|
|
<< ((1 << NumBits)-1) << ") {\n"
|
2014-11-24 14:09:52 +00:00
|
|
|
<< " default: llvm_unreachable(\"Invalid command number.\");\n";
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:43:54 +00:00
|
|
|
// Print out all the cases.
|
2016-01-08 07:06:32 +00:00
|
|
|
for (unsigned j = 0, e = Commands.size(); j != e; ++j) {
|
|
|
|
O << " case " << j << ":\n";
|
|
|
|
O << Commands[j];
|
2006-07-18 17:43:54 +00:00
|
|
|
O << " break;\n";
|
|
|
|
}
|
|
|
|
O << " }\n\n";
|
2006-07-18 17:18:03 +00:00
|
|
|
}
|
2012-09-14 08:33:11 +00:00
|
|
|
BitsLeft -= NumBits;
|
2006-07-18 17:18:03 +00:00
|
|
|
}
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:56:07 +00:00
|
|
|
// Okay, delete instructions with no operand info left.
|
2016-01-13 07:20:10 +00:00
|
|
|
auto I = std::remove_if(Instructions.begin(), Instructions.end(),
|
|
|
|
[](AsmWriterInst &Inst) {
|
|
|
|
return Inst.Operands.empty();
|
|
|
|
});
|
|
|
|
Instructions.erase(I, Instructions.end());
|
2006-07-18 17:18:03 +00:00
|
|
|
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2006-07-18 17:18:03 +00:00
|
|
|
// Because this is a vector, we want to emit from the end. Reverse all of the
|
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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
// elements in the vector.
|
|
|
|
std::reverse(Instructions.begin(), Instructions.end());
|
2010-09-29 22:32:50 +00:00
|
|
|
|
|
|
|
|
2016-01-13 07:20:07 +00:00
|
|
|
// Now that we've emitted all of the operand info that fit into 64 bits, emit
|
2009-09-18 18:10:19 +00:00
|
|
|
// information for those instructions that are left. This is a less dense
|
2016-01-13 07:20:07 +00:00
|
|
|
// encoding, but we expect the main 64-bit table to handle the majority of
|
2009-09-18 18:10:19 +00:00
|
|
|
// instructions.
|
2006-07-18 17:38:46 +00:00
|
|
|
if (!Instructions.empty()) {
|
|
|
|
// Find the opcode # of inline asm.
|
|
|
|
O << " switch (MI->getOpcode()) {\n";
|
|
|
|
while (!Instructions.empty())
|
|
|
|
EmitInstructions(Instructions, 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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19755 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-22 18:38:13 +00:00
|
|
|
|
2006-07-18 17:38:46 +00:00
|
|
|
O << " }\n";
|
2009-08-08 01:32:19 +00:00
|
|
|
O << " return;\n";
|
2006-07-18 17:38:46 +00:00
|
|
|
}
|
2009-07-29 20:10:24 +00:00
|
|
|
|
2006-07-18 19:06:01 +00:00
|
|
|
O << "}\n";
|
2004-08-01 05:59:33 +00:00
|
|
|
}
|
2009-09-13 20:08:00 +00:00
|
|
|
|
2014-11-24 02:08:35 +00:00
|
|
|
static const char *getMinimalTypeForRange(uint64_t Range) {
|
|
|
|
assert(Range < 0xFFFFFFFFULL && "Enum too large");
|
|
|
|
if (Range > 0xFFFF)
|
|
|
|
return "uint32_t";
|
|
|
|
if (Range > 0xFF)
|
|
|
|
return "uint16_t";
|
|
|
|
return "uint8_t";
|
|
|
|
}
|
|
|
|
|
2011-06-27 21:06:21 +00:00
|
|
|
static void
|
|
|
|
emitRegisterNameString(raw_ostream &O, StringRef AltName,
|
2014-11-29 18:13:39 +00:00
|
|
|
const std::deque<CodeGenRegister> &Registers) {
|
2012-03-30 21:12:52 +00:00
|
|
|
SequenceToOffsetTable<std::string> StringTable;
|
|
|
|
SmallVector<std::string, 4> AsmNames(Registers.size());
|
2014-11-29 18:13:39 +00:00
|
|
|
unsigned i = 0;
|
|
|
|
for (const auto &Reg : Registers) {
|
|
|
|
std::string &AsmName = AsmNames[i++];
|
2011-06-27 21:06:21 +00:00
|
|
|
|
|
|
|
// "NoRegAltName" is special. We don't need to do a lookup for that,
|
|
|
|
// as it's just a reference to the default register name.
|
|
|
|
if (AltName == "" || AltName == "NoRegAltName") {
|
|
|
|
AsmName = Reg.TheDef->getValueAsString("AsmName");
|
|
|
|
if (AsmName.empty())
|
|
|
|
AsmName = Reg.getName();
|
|
|
|
} else {
|
|
|
|
// Make sure the register has an alternate name for this index.
|
|
|
|
std::vector<Record*> AltNameList =
|
|
|
|
Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");
|
|
|
|
unsigned Idx = 0, e;
|
|
|
|
for (e = AltNameList.size();
|
|
|
|
Idx < e && (AltNameList[Idx]->getName() != AltName);
|
|
|
|
++Idx)
|
|
|
|
;
|
|
|
|
// If the register has an alternate name for this index, use it.
|
|
|
|
// Otherwise, leave it empty as an error flag.
|
|
|
|
if (Idx < e) {
|
|
|
|
std::vector<std::string> AltNames =
|
|
|
|
Reg.TheDef->getValueAsListOfStrings("AltNames");
|
|
|
|
if (AltNames.size() <= Idx)
|
2012-10-25 20:33:17 +00:00
|
|
|
PrintFatalError(Reg.TheDef->getLoc(),
|
2014-03-29 17:17:15 +00:00
|
|
|
"Register definition missing alt name for '" +
|
|
|
|
AltName + "'.");
|
2011-06-27 21:06:21 +00:00
|
|
|
AsmName = AltNames[Idx];
|
|
|
|
}
|
|
|
|
}
|
2012-03-30 21:12:52 +00:00
|
|
|
StringTable.add(AsmName);
|
|
|
|
}
|
|
|
|
|
2012-09-15 01:22:42 +00:00
|
|
|
StringTable.layout();
|
2012-03-30 21:12:52 +00:00
|
|
|
O << " static const char AsmStrs" << AltName << "[] = {\n";
|
|
|
|
StringTable.emit(O, printChar);
|
|
|
|
O << " };\n\n";
|
2011-06-27 21:06:21 +00:00
|
|
|
|
2014-11-24 02:08:35 +00:00
|
|
|
O << " static const " << getMinimalTypeForRange(StringTable.size()-1)
|
|
|
|
<< " RegAsmOffset" << AltName << "[] = {";
|
2012-03-30 21:12:52 +00:00
|
|
|
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
|
2012-04-02 00:47:39 +00:00
|
|
|
if ((i % 14) == 0)
|
|
|
|
O << "\n ";
|
|
|
|
O << StringTable.get(AsmNames[i]) << ", ";
|
2011-06-27 21:06:21 +00:00
|
|
|
}
|
2012-04-03 06:52:47 +00:00
|
|
|
O << "\n };\n"
|
2011-06-27 21:06:21 +00:00
|
|
|
<< "\n";
|
|
|
|
}
|
2009-09-13 20:08:00 +00:00
|
|
|
|
|
|
|
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
|
|
|
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
2014-11-29 18:13:39 +00:00
|
|
|
const auto &Registers = Target.getRegBank().getRegisters();
|
2011-06-27 21:06:21 +00:00
|
|
|
std::vector<Record*> AltNameIndices = Target.getRegAltNameIndices();
|
|
|
|
bool hasAltNames = AltNameIndices.size() > 1;
|
2015-12-11 17:31:27 +00:00
|
|
|
std::string Namespace =
|
|
|
|
Registers.front().TheDef->getValueAsString("Namespace");
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2009-09-13 20:08:00 +00:00
|
|
|
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"
|
2011-06-27 21:06:21 +00:00
|
|
|
"const char *" << Target.getName() << ClassName << "::";
|
|
|
|
if (hasAltNames)
|
|
|
|
O << "\ngetRegisterName(unsigned RegNo, unsigned AltIdx) {\n";
|
|
|
|
else
|
|
|
|
O << "getRegisterName(unsigned RegNo) {\n";
|
|
|
|
O << " assert(RegNo && RegNo < " << (Registers.size()+1)
|
|
|
|
<< " && \"Invalid register number!\");\n"
|
2009-09-14 01:26:18 +00:00
|
|
|
<< "\n";
|
2010-09-29 22:32:50 +00:00
|
|
|
|
2011-06-27 21:06:21 +00:00
|
|
|
if (hasAltNames) {
|
2016-01-08 07:06:32 +00:00
|
|
|
for (const Record *R : AltNameIndices)
|
|
|
|
emitRegisterNameString(O, R->getName(), Registers);
|
2011-06-27 21:06:21 +00:00
|
|
|
} else
|
|
|
|
emitRegisterNameString(O, "", Registers);
|
|
|
|
|
|
|
|
if (hasAltNames) {
|
2014-11-24 02:08:35 +00:00
|
|
|
O << " switch(AltIdx) {\n"
|
2012-02-05 07:21:30 +00:00
|
|
|
<< " default: llvm_unreachable(\"Invalid register alt name index!\");\n";
|
2016-01-08 07:06:32 +00:00
|
|
|
for (const Record *R : AltNameIndices) {
|
|
|
|
std::string AltName(R->getName());
|
2015-12-11 17:31:27 +00:00
|
|
|
std::string Prefix = !Namespace.empty() ? Namespace + "::" : "";
|
|
|
|
O << " case " << Prefix << AltName << ":\n"
|
2014-11-24 02:08:35 +00:00
|
|
|
<< " assert(*(AsmStrs" << AltName << "+RegAsmOffset"
|
|
|
|
<< AltName << "[RegNo-1]) &&\n"
|
|
|
|
<< " \"Invalid alt name index for register!\");\n"
|
|
|
|
<< " return AsmStrs" << AltName << "+RegAsmOffset"
|
|
|
|
<< AltName << "[RegNo-1];\n";
|
2011-06-27 21:06:21 +00:00
|
|
|
}
|
2014-11-24 02:08:35 +00:00
|
|
|
O << " }\n";
|
|
|
|
} else {
|
|
|
|
O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n"
|
|
|
|
<< " \"Invalid alt name index for register!\");\n"
|
|
|
|
<< " return AsmStrs+RegAsmOffset[RegNo-1];\n";
|
2011-06-27 21:06:21 +00:00
|
|
|
}
|
2014-11-24 02:08:35 +00:00
|
|
|
O << "}\n";
|
2009-09-13 20:08:00 +00:00
|
|
|
}
|
|
|
|
|
2011-03-21 08:31:53 +00:00
|
|
|
namespace {
|
2011-03-21 08:40:31 +00:00
|
|
|
// IAPrinter - Holds information about an InstAlias. Two InstAliases match if
|
|
|
|
// they both have the same conditionals. In which case, we cannot print out the
|
|
|
|
// alias for that pattern.
|
|
|
|
class IAPrinter {
|
|
|
|
std::vector<std::string> Conds;
|
2014-05-12 18:04:06 +00:00
|
|
|
std::map<StringRef, std::pair<int, int>> OpMap;
|
|
|
|
SmallVector<Record*, 4> ReqFeatures;
|
|
|
|
|
2011-03-21 08:40:31 +00:00
|
|
|
std::string Result;
|
|
|
|
std::string AsmString;
|
|
|
|
public:
|
2014-05-12 18:04:06 +00:00
|
|
|
IAPrinter(std::string R, std::string AS) : Result(R), AsmString(AS) {}
|
2011-03-21 08:40:31 +00:00
|
|
|
|
|
|
|
void addCond(const std::string &C) { Conds.push_back(C); }
|
|
|
|
|
2014-05-12 18:04:06 +00:00
|
|
|
void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) {
|
|
|
|
assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range");
|
2014-05-13 09:37:41 +00:00
|
|
|
assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF &&
|
2014-05-13 08:26:53 +00:00
|
|
|
"Idx out of range");
|
2014-05-12 18:04:06 +00:00
|
|
|
OpMap[Op] = std::make_pair(OpIdx, PrintMethodIdx);
|
2013-09-11 15:42:16 +00:00
|
|
|
}
|
2014-05-12 18:04:06 +00:00
|
|
|
|
2011-03-21 08:40:31 +00:00
|
|
|
bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); }
|
2014-05-12 18:04:06 +00:00
|
|
|
int getOpIndex(StringRef Op) { return OpMap[Op].first; }
|
|
|
|
std::pair<int, int> &getOpData(StringRef Op) { return OpMap[Op]; }
|
2011-03-21 08:40:31 +00:00
|
|
|
|
2014-05-15 11:16:32 +00:00
|
|
|
std::pair<StringRef, StringRef::iterator> parseName(StringRef::iterator Start,
|
|
|
|
StringRef::iterator End) {
|
|
|
|
StringRef::iterator I = Start;
|
2014-12-16 18:16:17 +00:00
|
|
|
StringRef::iterator Next;
|
2014-05-15 11:16:32 +00:00
|
|
|
if (*I == '{') {
|
|
|
|
// ${some_name}
|
|
|
|
Start = ++I;
|
|
|
|
while (I != End && *I != '}')
|
|
|
|
++I;
|
2014-12-16 18:16:17 +00:00
|
|
|
Next = I;
|
|
|
|
// eat the final '}'
|
|
|
|
if (Next != End)
|
|
|
|
++Next;
|
2014-05-15 11:16:32 +00:00
|
|
|
} else {
|
|
|
|
// $name, just eat the usual suspects.
|
|
|
|
while (I != End &&
|
|
|
|
((*I >= 'a' && *I <= 'z') || (*I >= 'A' && *I <= 'Z') ||
|
|
|
|
(*I >= '0' && *I <= '9') || *I == '_'))
|
|
|
|
++I;
|
2014-12-16 18:16:17 +00:00
|
|
|
Next = I;
|
2014-05-15 11:16:32 +00:00
|
|
|
}
|
|
|
|
|
2014-12-16 18:16:17 +00:00
|
|
|
return std::make_pair(StringRef(Start, I - Start), Next);
|
2014-05-15 11:16:32 +00:00
|
|
|
}
|
|
|
|
|
2011-07-06 02:02:33 +00:00
|
|
|
void print(raw_ostream &O) {
|
2011-04-07 21:20:06 +00:00
|
|
|
if (Conds.empty() && ReqFeatures.empty()) {
|
|
|
|
O.indent(6) << "return true;\n";
|
2011-07-06 02:02:33 +00:00
|
|
|
return;
|
2011-04-07 21:20:06 +00:00
|
|
|
}
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2011-04-07 21:20:06 +00:00
|
|
|
O << "if (";
|
2011-03-21 08:40:31 +00:00
|
|
|
|
|
|
|
for (std::vector<std::string>::iterator
|
|
|
|
I = Conds.begin(), E = Conds.end(); I != E; ++I) {
|
|
|
|
if (I != Conds.begin()) {
|
|
|
|
O << " &&\n";
|
2011-04-07 21:20:06 +00:00
|
|
|
O.indent(8);
|
2011-03-21 08:40:31 +00:00
|
|
|
}
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2011-03-21 08:40:31 +00:00
|
|
|
O << *I;
|
|
|
|
}
|
|
|
|
|
2011-04-07 21:20:06 +00:00
|
|
|
O << ") {\n";
|
|
|
|
O.indent(6) << "// " << Result << "\n";
|
2011-03-21 08:40:31 +00:00
|
|
|
|
2013-09-11 15:42:16 +00:00
|
|
|
// Directly mangle mapped operands into the string. Each operand is
|
|
|
|
// identified by a '$' sign followed by a byte identifying the number of the
|
|
|
|
// operand. We add one to the index to avoid zero bytes.
|
2014-05-15 11:16:32 +00:00
|
|
|
StringRef ASM(AsmString);
|
|
|
|
SmallString<128> OutString;
|
|
|
|
raw_svector_ostream OS(OutString);
|
|
|
|
for (StringRef::iterator I = ASM.begin(), E = ASM.end(); I != E;) {
|
|
|
|
OS << *I;
|
|
|
|
if (*I == '$') {
|
|
|
|
StringRef Name;
|
|
|
|
std::tie(Name, I) = parseName(++I, E);
|
|
|
|
assert(isOpMapped(Name) && "Unmapped operand!");
|
|
|
|
|
|
|
|
int OpIndex, PrintIndex;
|
|
|
|
std::tie(OpIndex, PrintIndex) = getOpData(Name);
|
|
|
|
if (PrintIndex == -1) {
|
|
|
|
// Can use the default printOperand route.
|
|
|
|
OS << format("\\x%02X", (unsigned char)OpIndex + 1);
|
|
|
|
} else
|
|
|
|
// 3 bytes if a PrintMethod is needed: 0xFF, the MCInst operand
|
|
|
|
// number, and which of our pre-detected Methods to call.
|
|
|
|
OS << format("\\xFF\\x%02X\\x%02X", OpIndex + 1, PrintIndex + 1);
|
|
|
|
} else {
|
|
|
|
++I;
|
2013-09-11 15:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the string.
|
2015-03-10 07:33:23 +00:00
|
|
|
O.indent(6) << "AsmString = \"" << OutString << "\";\n";
|
2011-03-21 08:40:31 +00:00
|
|
|
|
2011-04-07 21:20:06 +00:00
|
|
|
O.indent(6) << "break;\n";
|
|
|
|
O.indent(4) << '}';
|
2011-03-21 08:40:31 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
bool operator==(const IAPrinter &RHS) const {
|
2011-03-21 08:40:31 +00:00
|
|
|
if (Conds.size() != RHS.Conds.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned Idx = 0;
|
2015-08-06 19:23:33 +00:00
|
|
|
for (const auto &str : Conds)
|
|
|
|
if (str != RHS.Conds[Idx++])
|
2011-03-21 08:40:31 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-03-21 08:31:53 +00:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
TableGen: fix operand counting for aliases
TableGen has a fairly dubious heuristic to decide whether an alias should be
printed: does the alias have lest operands than the real instruction. This is
bad enough (particularly with no way to override it), but it should at least be
calculated consistently for both strings.
This patch implements that logic: first get the *correct* string for the
variant, in the same way as the Matcher, without guessing; then count the
number of whitespace chars.
There are basically 4 changes this brings about after the previous
commits; all of these appear to be good, so I have changed the tests:
+ ARM64: we print "neg X, Y" instead of "sub X, xzr, Y".
+ ARM64: we skip implicit "uxtx" and "uxtw" modifiers.
+ Sparc: we print "mov A, B" instead of "or %g0, A, B".
+ Sparc: we print "fcmpX A, B" instead of "fcmpX %fcc0, A, B"
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208969 91177308-0d34-0410-b5e6-96231b3b80d8
2014-05-16 09:42:04 +00:00
|
|
|
static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) {
|
|
|
|
std::string FlatAsmString =
|
|
|
|
CodeGenInstruction::FlattenAsmStringVariants(AsmString, Variant);
|
|
|
|
AsmString = FlatAsmString;
|
2011-06-14 03:17:20 +00:00
|
|
|
|
TableGen: fix operand counting for aliases
TableGen has a fairly dubious heuristic to decide whether an alias should be
printed: does the alias have lest operands than the real instruction. This is
bad enough (particularly with no way to override it), but it should at least be
calculated consistently for both strings.
This patch implements that logic: first get the *correct* string for the
variant, in the same way as the Matcher, without guessing; then count the
number of whitespace chars.
There are basically 4 changes this brings about after the previous
commits; all of these appear to be good, so I have changed the tests:
+ ARM64: we print "neg X, Y" instead of "sub X, xzr, Y".
+ ARM64: we skip implicit "uxtx" and "uxtw" modifiers.
+ Sparc: we print "mov A, B" instead of "or %g0, A, B".
+ Sparc: we print "fcmpX A, B" instead of "fcmpX %fcc0, A, B"
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208969 91177308-0d34-0410-b5e6-96231b3b80d8
2014-05-16 09:42:04 +00:00
|
|
|
return AsmString.count(' ') + AsmString.count('\t');
|
2011-06-15 04:31:19 +00:00
|
|
|
}
|
2011-06-14 03:17:20 +00:00
|
|
|
|
2014-05-20 09:17:16 +00:00
|
|
|
namespace {
|
|
|
|
struct AliasPriorityComparator {
|
2015-08-06 19:23:33 +00:00
|
|
|
typedef std::pair<CodeGenInstAlias, int> ValueType;
|
2014-05-20 09:17:16 +00:00
|
|
|
bool operator()(const ValueType &LHS, const ValueType &RHS) {
|
|
|
|
if (LHS.second == RHS.second) {
|
|
|
|
// We don't actually care about the order, but for consistency it
|
|
|
|
// shouldn't depend on pointer comparisons.
|
2015-08-06 19:23:33 +00:00
|
|
|
return LHS.first.TheDef->getName() < RHS.first.TheDef->getName();
|
2014-05-20 09:17:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Aliases with larger priorities should be considered first.
|
|
|
|
return LHS.second > RHS.second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-21 08:31:53 +00:00
|
|
|
void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
|
|
|
|
|
|
|
O << "\n#ifdef PRINT_ALIAS_INSTR\n";
|
|
|
|
O << "#undef PRINT_ALIAS_INSTR\n\n";
|
|
|
|
|
2014-05-12 18:04:06 +00:00
|
|
|
//////////////////////////////
|
|
|
|
// Gather information about aliases we need to print
|
|
|
|
//////////////////////////////
|
|
|
|
|
2011-02-26 03:09:12 +00:00
|
|
|
// Emit the method that prints the alias instruction.
|
|
|
|
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
|
2014-05-20 09:17:16 +00:00
|
|
|
unsigned Variant = AsmWriter->getValueAsInt("Variant");
|
2015-03-27 20:36:02 +00:00
|
|
|
unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
2010-02-11 22:57:32 +00:00
|
|
|
|
2011-02-26 03:09:12 +00:00
|
|
|
std::vector<Record*> AllInstAliases =
|
|
|
|
Records.getAllDerivedDefinitions("InstAlias");
|
|
|
|
|
|
|
|
// Create a map from the qualified name to a list of potential matches.
|
2015-08-06 19:23:33 +00:00
|
|
|
typedef std::set<std::pair<CodeGenInstAlias, int>, AliasPriorityComparator>
|
2014-05-20 09:17:16 +00:00
|
|
|
AliasWithPriority;
|
|
|
|
std::map<std::string, AliasWithPriority> AliasMap;
|
2016-01-08 07:06:32 +00:00
|
|
|
for (Record *R : AllInstAliases) {
|
2014-05-20 09:17:16 +00:00
|
|
|
int Priority = R->getValueAsInt("EmitPriority");
|
|
|
|
if (Priority < 1)
|
|
|
|
continue; // Aliases with priority 0 are never emitted.
|
|
|
|
|
2011-02-26 03:09:12 +00:00
|
|
|
const DagInit *DI = R->getValueAsDag("ResultInst");
|
2012-10-10 20:24:47 +00:00
|
|
|
const DefInit *Op = cast<DefInit>(DI->getOperator());
|
2015-08-06 19:23:33 +00:00
|
|
|
AliasMap[getQualifiedName(Op->getDef())].insert(
|
2016-01-08 07:06:32 +00:00
|
|
|
std::make_pair(CodeGenInstAlias(R, Variant, Target), Priority));
|
2011-02-26 03:09:12 +00:00
|
|
|
}
|
|
|
|
|
2011-03-21 08:59:17 +00:00
|
|
|
// A map of which conditions need to be met for each instruction operand
|
|
|
|
// before it can be matched to the mnemonic.
|
2015-08-06 19:23:33 +00:00
|
|
|
std::map<std::string, std::vector<IAPrinter>> IAPrinterMap;
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2014-06-10 13:11:35 +00:00
|
|
|
// A list of MCOperandPredicates for all operands in use, and the reverse map
|
|
|
|
std::vector<const Record*> MCOpPredicates;
|
|
|
|
DenseMap<const Record*, unsigned> MCOpPredicateMap;
|
|
|
|
|
2014-05-20 09:17:16 +00:00
|
|
|
for (auto &Aliases : AliasMap) {
|
|
|
|
for (auto &Alias : Aliases.second) {
|
2015-08-06 19:23:33 +00:00
|
|
|
const CodeGenInstAlias &CGA = Alias.first;
|
|
|
|
unsigned LastOpNo = CGA.ResultInstOperandIndex.size();
|
2011-06-15 04:31:19 +00:00
|
|
|
unsigned NumResultOps =
|
2015-08-06 19:23:33 +00:00
|
|
|
CountNumOperands(CGA.ResultInst->AsmString, Variant);
|
2011-06-14 03:17:20 +00:00
|
|
|
|
|
|
|
// Don't emit the alias if it has more operands than what it's aliasing.
|
2015-08-06 19:23:33 +00:00
|
|
|
if (NumResultOps < CountNumOperands(CGA.AsmString, Variant))
|
2011-06-14 03:17:20 +00:00
|
|
|
continue;
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
IAPrinter IAP(CGA.Result->getAsString(), CGA.AsmString);
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2014-05-15 13:36:01 +00:00
|
|
|
unsigned NumMIOps = 0;
|
2015-08-06 19:23:33 +00:00
|
|
|
for (auto &Operand : CGA.ResultOperands)
|
2014-05-15 13:36:01 +00:00
|
|
|
NumMIOps += Operand.getMINumOperands();
|
|
|
|
|
2011-03-21 08:59:17 +00:00
|
|
|
std::string Cond;
|
2014-05-15 13:36:01 +00:00
|
|
|
Cond = std::string("MI->getNumOperands() == ") + llvm::utostr(NumMIOps);
|
2015-08-06 19:23:33 +00:00
|
|
|
IAP.addCond(Cond);
|
2011-03-21 08:59:17 +00:00
|
|
|
|
|
|
|
bool CantHandle = false;
|
|
|
|
|
2014-05-15 13:36:01 +00:00
|
|
|
unsigned MIOpNum = 0;
|
2011-03-21 08:59:17 +00:00
|
|
|
for (unsigned i = 0, e = LastOpNo; i != e; ++i) {
|
2014-06-10 12:47:23 +00:00
|
|
|
std::string Op = "MI->getOperand(" + llvm::utostr(MIOpNum) + ")";
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
const CodeGenInstAlias::ResultOperand &RO = CGA.ResultOperands[i];
|
2011-03-21 08:59:17 +00:00
|
|
|
|
|
|
|
switch (RO.Kind) {
|
|
|
|
case CodeGenInstAlias::ResultOperand::K_Record: {
|
|
|
|
const Record *Rec = RO.getRecord();
|
|
|
|
StringRef ROName = RO.getName();
|
2014-05-12 18:04:06 +00:00
|
|
|
int PrintMethodIdx = -1;
|
|
|
|
|
|
|
|
// These two may have a PrintMethod, which we want to record (if it's
|
|
|
|
// the first time we've seen it) and provide an index for the aliasing
|
|
|
|
// code to use.
|
|
|
|
if (Rec->isSubClassOf("RegisterOperand") ||
|
|
|
|
Rec->isSubClassOf("Operand")) {
|
|
|
|
std::string PrintMethod = Rec->getValueAsString("PrintMethod");
|
|
|
|
if (PrintMethod != "" && PrintMethod != "printOperand") {
|
|
|
|
PrintMethodIdx = std::find(PrintMethods.begin(),
|
|
|
|
PrintMethods.end(), PrintMethod) -
|
|
|
|
PrintMethods.begin();
|
|
|
|
if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size())
|
|
|
|
PrintMethods.push_back(PrintMethod);
|
|
|
|
}
|
|
|
|
}
|
2011-06-27 21:06:21 +00:00
|
|
|
|
|
|
|
if (Rec->isSubClassOf("RegisterOperand"))
|
|
|
|
Rec = Rec->getValueAsDef("RegClass");
|
2011-03-21 08:59:17 +00:00
|
|
|
if (Rec->isSubClassOf("RegisterClass")) {
|
2015-08-06 19:23:33 +00:00
|
|
|
IAP.addCond(Op + ".isReg()");
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
if (!IAP.isOpMapped(ROName)) {
|
|
|
|
IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);
|
|
|
|
Record *R = CGA.ResultOperands[i].getRecord();
|
2013-02-05 08:32:10 +00:00
|
|
|
if (R->isSubClassOf("RegisterOperand"))
|
|
|
|
R = R->getValueAsDef("RegClass");
|
2012-03-30 23:13:40 +00:00
|
|
|
Cond = std::string("MRI.getRegClass(") + Target.getName() + "::" +
|
2014-05-15 13:36:01 +00:00
|
|
|
R->getName() + "RegClassID)"
|
2014-06-10 12:47:23 +00:00
|
|
|
".contains(" + Op + ".getReg())";
|
2011-03-21 08:59:17 +00:00
|
|
|
} else {
|
2014-06-10 12:47:23 +00:00
|
|
|
Cond = Op + ".getReg() == MI->getOperand(" +
|
2015-08-06 19:23:33 +00:00
|
|
|
llvm::utostr(IAP.getOpIndex(ROName)) + ").getReg()";
|
2011-03-21 08:59:17 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-05-12 18:04:06 +00:00
|
|
|
// Assume all printable operands are desired for now. This can be
|
2014-05-15 01:52:21 +00:00
|
|
|
// overridden in the InstAlias instantiation if necessary.
|
2015-08-06 19:23:33 +00:00
|
|
|
IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2014-06-10 13:11:35 +00:00
|
|
|
// There might be an additional predicate on the MCOperand
|
|
|
|
unsigned Entry = MCOpPredicateMap[Rec];
|
|
|
|
if (!Entry) {
|
|
|
|
if (!Rec->isValueUnset("MCOperandPredicate")) {
|
|
|
|
MCOpPredicates.push_back(Rec);
|
|
|
|
Entry = MCOpPredicates.size();
|
|
|
|
MCOpPredicateMap[Rec] = Entry;
|
|
|
|
} else
|
|
|
|
break; // No conditions on this operand at all
|
|
|
|
}
|
|
|
|
Cond = Target.getName() + ClassName + "ValidateMCOperand(" +
|
2015-12-01 10:48:51 +00:00
|
|
|
Op + ", STI, " + llvm::utostr(Entry) + ")";
|
2014-06-10 13:11:35 +00:00
|
|
|
}
|
|
|
|
// for all subcases of ResultOperand::K_Record:
|
2015-08-06 19:23:33 +00:00
|
|
|
IAP.addCond(Cond);
|
2011-03-21 08:59:17 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-01-09 13:32:04 +00:00
|
|
|
case CodeGenInstAlias::ResultOperand::K_Imm: {
|
|
|
|
// Just because the alias has an immediate result, doesn't mean the
|
|
|
|
// MCInst will. An MCExpr could be present, for example.
|
2015-08-06 19:23:33 +00:00
|
|
|
IAP.addCond(Op + ".isImm()");
|
2013-01-09 13:32:04 +00:00
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
Cond = Op + ".getImm() == " +
|
|
|
|
llvm::utostr(CGA.ResultOperands[i].getImm());
|
|
|
|
IAP.addCond(Cond);
|
2011-03-21 08:59:17 +00:00
|
|
|
break;
|
2013-01-09 13:32:04 +00:00
|
|
|
}
|
2011-03-21 08:59:17 +00:00
|
|
|
case CodeGenInstAlias::ResultOperand::K_Reg:
|
2011-11-15 01:46:57 +00:00
|
|
|
// If this is zero_reg, something's playing tricks we're not
|
|
|
|
// equipped to handle.
|
2015-08-06 19:23:33 +00:00
|
|
|
if (!CGA.ResultOperands[i].getRegister()) {
|
2011-11-15 01:46:57 +00:00
|
|
|
CantHandle = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
Cond = Op + ".getReg() == " + Target.getName() + "::" +
|
|
|
|
CGA.ResultOperands[i].getRegister()->getName();
|
|
|
|
IAP.addCond(Cond);
|
2011-03-21 08:59:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-05-15 13:36:01 +00:00
|
|
|
MIOpNum += RO.getMINumOperands();
|
2011-03-21 08:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CantHandle) continue;
|
2015-08-06 19:23:33 +00:00
|
|
|
IAPrinterMap[Aliases.first].push_back(std::move(IAP));
|
2011-03-21 08:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-12 18:04:06 +00:00
|
|
|
//////////////////////////////
|
|
|
|
// Write out the printAliasInstr function
|
|
|
|
//////////////////////////////
|
|
|
|
|
2011-05-23 00:18:33 +00:00
|
|
|
std::string Header;
|
|
|
|
raw_string_ostream HeaderO(Header);
|
|
|
|
|
|
|
|
HeaderO << "bool " << Target.getName() << ClassName
|
2011-06-14 03:17:20 +00:00
|
|
|
<< "::printAliasInstr(const MCInst"
|
2015-03-27 20:36:02 +00:00
|
|
|
<< " *MI, " << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
|
|
|
|
<< "raw_ostream &OS) {\n";
|
2011-03-21 08:59:17 +00:00
|
|
|
|
2011-04-07 21:20:06 +00:00
|
|
|
std::string Cases;
|
|
|
|
raw_string_ostream CasesO(Cases);
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
for (auto &Entry : IAPrinterMap) {
|
|
|
|
std::vector<IAPrinter> &IAPs = Entry.second;
|
2011-04-07 21:20:06 +00:00
|
|
|
std::vector<IAPrinter*> UniqueIAPs;
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
for (auto &LHS : IAPs) {
|
2011-04-07 21:20:06 +00:00
|
|
|
bool IsDup = false;
|
2015-08-06 19:23:33 +00:00
|
|
|
for (const auto &RHS : IAPs) {
|
|
|
|
if (&LHS != &RHS && LHS == RHS) {
|
2011-04-07 21:20:06 +00:00
|
|
|
IsDup = true;
|
2011-02-26 03:09:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
if (!IsDup)
|
|
|
|
UniqueIAPs.push_back(&LHS);
|
2011-04-07 21:20:06 +00:00
|
|
|
}
|
2011-02-26 03:09:12 +00:00
|
|
|
|
2011-04-07 21:20:06 +00:00
|
|
|
if (UniqueIAPs.empty()) continue;
|
2011-02-26 03:09:12 +00:00
|
|
|
|
2015-08-06 19:23:33 +00:00
|
|
|
CasesO.indent(2) << "case " << Entry.first << ":\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
|
2016-01-08 07:06:32 +00:00
|
|
|
for (IAPrinter *IAP : UniqueIAPs) {
|
2011-04-07 21:20:06 +00:00
|
|
|
CasesO.indent(4);
|
2011-07-06 02:02:33 +00:00
|
|
|
IAP->print(CasesO);
|
2011-04-07 21:20:06 +00:00
|
|
|
CasesO << '\n';
|
2011-02-26 03:09:12 +00:00
|
|
|
}
|
|
|
|
|
2011-04-18 21:28:11 +00:00
|
|
|
CasesO.indent(4) << "return false;\n";
|
2011-04-07 21:20:06 +00:00
|
|
|
}
|
2011-02-26 03:09:12 +00:00
|
|
|
|
2011-06-14 03:17:20 +00:00
|
|
|
if (CasesO.str().empty()) {
|
2011-05-23 00:18:33 +00:00
|
|
|
O << HeaderO.str();
|
2011-04-18 21:28:11 +00:00
|
|
|
O << " return false;\n";
|
2011-04-07 21:20:06 +00:00
|
|
|
O << "}\n\n";
|
|
|
|
O << "#endif // PRINT_ALIAS_INSTR\n";
|
|
|
|
return;
|
2011-02-26 03:09:12 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 11:41:30 +00:00
|
|
|
if (!MCOpPredicates.empty())
|
2014-06-10 13:11:35 +00:00
|
|
|
O << "static bool " << Target.getName() << ClassName
|
2015-12-01 10:48:51 +00:00
|
|
|
<< "ValidateMCOperand(const MCOperand &MCOp,\n"
|
|
|
|
<< " const MCSubtargetInfo &STI,\n"
|
|
|
|
<< " unsigned PredicateIndex);\n";
|
2014-06-10 13:11:35 +00:00
|
|
|
|
2011-05-23 00:18:33 +00:00
|
|
|
O << HeaderO.str();
|
2013-09-11 15:42:16 +00:00
|
|
|
O.indent(2) << "const char *AsmString;\n";
|
2011-04-07 21:20:06 +00:00
|
|
|
O.indent(2) << "switch (MI->getOpcode()) {\n";
|
2011-04-18 21:28:11 +00:00
|
|
|
O.indent(2) << "default: return false;\n";
|
2011-04-07 21:20:06 +00:00
|
|
|
O << CasesO.str();
|
|
|
|
O.indent(2) << "}\n\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
|
|
|
|
// Code that prints the alias, replacing the operands with the ones from the
|
|
|
|
// MCInst.
|
2013-09-11 15:42:16 +00:00
|
|
|
O << " unsigned I = 0;\n";
|
2014-05-15 11:16:32 +00:00
|
|
|
O << " while (AsmString[I] != ' ' && AsmString[I] != '\t' &&\n";
|
|
|
|
O << " AsmString[I] != '\\0')\n";
|
2013-09-11 15:42:16 +00:00
|
|
|
O << " ++I;\n";
|
|
|
|
O << " OS << '\\t' << StringRef(AsmString, I);\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
|
2013-09-11 15:42:16 +00:00
|
|
|
O << " if (AsmString[I] != '\\0') {\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
O << " OS << '\\t';\n";
|
2013-09-11 15:42:16 +00:00
|
|
|
O << " do {\n";
|
|
|
|
O << " if (AsmString[I] == '$') {\n";
|
|
|
|
O << " ++I;\n";
|
2014-05-12 18:04:06 +00:00
|
|
|
O << " if (AsmString[I] == (char)0xff) {\n";
|
|
|
|
O << " ++I;\n";
|
|
|
|
O << " int OpIdx = AsmString[I++] - 1;\n";
|
|
|
|
O << " int PrintMethodIdx = AsmString[I++] - 1;\n";
|
2015-03-27 20:36:02 +00:00
|
|
|
O << " printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, ";
|
|
|
|
O << (PassSubtarget ? "STI, " : "");
|
|
|
|
O << "OS);\n";
|
2014-05-12 18:04:06 +00:00
|
|
|
O << " } else\n";
|
2015-03-27 20:36:02 +00:00
|
|
|
O << " printOperand(MI, unsigned(AsmString[I++]) - 1, ";
|
|
|
|
O << (PassSubtarget ? "STI, " : "");
|
|
|
|
O << "OS);\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
O << " } else {\n";
|
2013-09-11 15:42:16 +00:00
|
|
|
O << " OS << AsmString[I++];\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
O << " }\n";
|
2013-09-11 15:42:16 +00:00
|
|
|
O << " } while (AsmString[I] != '\\0');\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
O << " }\n\n";
|
2012-04-18 18:56:33 +00:00
|
|
|
|
2011-04-18 21:28:11 +00:00
|
|
|
O << " return true;\n";
|
2011-02-26 03:09:12 +00:00
|
|
|
O << "}\n\n";
|
|
|
|
|
2014-05-12 18:04:06 +00:00
|
|
|
//////////////////////////////
|
|
|
|
// Write out the printCustomAliasOperand function
|
|
|
|
//////////////////////////////
|
|
|
|
|
|
|
|
O << "void " << Target.getName() << ClassName << "::"
|
|
|
|
<< "printCustomAliasOperand(\n"
|
|
|
|
<< " const MCInst *MI, unsigned OpIdx,\n"
|
2015-03-27 20:36:02 +00:00
|
|
|
<< " unsigned PrintMethodIdx,\n"
|
|
|
|
<< (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "")
|
|
|
|
<< " raw_ostream &OS) {\n";
|
2014-05-13 12:52:35 +00:00
|
|
|
if (PrintMethods.empty())
|
|
|
|
O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n";
|
|
|
|
else {
|
|
|
|
O << " switch (PrintMethodIdx) {\n"
|
|
|
|
<< " default:\n"
|
|
|
|
<< " llvm_unreachable(\"Unknown PrintMethod kind\");\n"
|
2014-05-12 18:04:06 +00:00
|
|
|
<< " break;\n";
|
|
|
|
|
2014-05-13 12:52:35 +00:00
|
|
|
for (unsigned i = 0; i < PrintMethods.size(); ++i) {
|
|
|
|
O << " case " << i << ":\n"
|
2015-03-27 20:36:02 +00:00
|
|
|
<< " " << PrintMethods[i] << "(MI, OpIdx, "
|
|
|
|
<< (PassSubtarget ? "STI, " : "") << "OS);\n"
|
2014-05-13 12:52:35 +00:00
|
|
|
<< " break;\n";
|
|
|
|
}
|
|
|
|
O << " }\n";
|
|
|
|
}
|
|
|
|
O << "}\n\n";
|
2014-05-12 18:04:06 +00:00
|
|
|
|
2015-01-15 11:41:30 +00:00
|
|
|
if (!MCOpPredicates.empty()) {
|
2014-06-10 13:11:35 +00:00
|
|
|
O << "static bool " << Target.getName() << ClassName
|
2015-12-01 10:48:51 +00:00
|
|
|
<< "ValidateMCOperand(const MCOperand &MCOp,\n"
|
|
|
|
<< " const MCSubtargetInfo &STI,\n"
|
|
|
|
<< " unsigned PredicateIndex) {\n"
|
2014-06-10 13:11:35 +00:00
|
|
|
<< " switch (PredicateIndex) {\n"
|
|
|
|
<< " default:\n"
|
|
|
|
<< " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"
|
|
|
|
<< " break;\n";
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
|
|
|
|
Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate");
|
|
|
|
if (StringInit *SI = dyn_cast<StringInit>(MCOpPred)) {
|
|
|
|
O << " case " << i + 1 << ": {\n"
|
|
|
|
<< SI->getValue() << "\n"
|
|
|
|
<< " }\n";
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unexpected MCOperandPredicate field!");
|
|
|
|
}
|
|
|
|
O << " }\n"
|
|
|
|
<< "}\n\n";
|
|
|
|
}
|
|
|
|
|
2011-02-26 03:09:12 +00:00
|
|
|
O << "#endif // PRINT_ALIAS_INSTR\n";
|
|
|
|
}
|
2009-09-13 20:08:00 +00:00
|
|
|
|
2013-10-28 18:07:17 +00:00
|
|
|
AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {
|
|
|
|
Record *AsmWriter = Target.getAsmWriter();
|
2016-01-13 07:20:05 +00:00
|
|
|
unsigned Variant = AsmWriter->getValueAsInt("Variant");
|
|
|
|
unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
|
2014-11-25 20:11:31 +00:00
|
|
|
for (const CodeGenInstruction *I : Target.instructions())
|
|
|
|
if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")
|
2016-01-13 07:20:05 +00:00
|
|
|
Instructions.emplace_back(*I, Variant, PassSubtarget);
|
2013-10-28 18:07:17 +00:00
|
|
|
|
|
|
|
// Get the instruction numbering.
|
2014-02-05 07:56:49 +00:00
|
|
|
NumberedInstructions = &Target.getInstructionsByEnumValue();
|
2013-10-28 18:07:17 +00:00
|
|
|
|
|
|
|
// 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.
|
2016-01-08 07:06:32 +00:00
|
|
|
for (AsmWriterInst &AWI : Instructions)
|
|
|
|
CGIAWIMap.insert(std::make_pair(AWI.CGI, &AWI));
|
2013-10-28 18:07:17 +00:00
|
|
|
}
|
|
|
|
|
2009-09-13 20:08:00 +00:00
|
|
|
void AsmWriterEmitter::run(raw_ostream &O) {
|
|
|
|
EmitPrintInstruction(O);
|
|
|
|
EmitGetRegisterName(O);
|
2011-02-26 03:09:12 +00:00
|
|
|
EmitPrintAliasInstruction(O);
|
2009-09-13 20:08:00 +00:00
|
|
|
}
|
|
|
|
|
2012-06-11 15:37:55 +00:00
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS) {
|
|
|
|
emitSourceFileHeader("Assembly Writer Source Fragment", OS);
|
|
|
|
AsmWriterEmitter(RK).run(OS);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End llvm namespace
|