summaryrefslogtreecommitdiff
path: root/utils/TableGen
diff options
context:
space:
mode:
authorJohnny Chen <johnny.chen@apple.com>2009-10-29 01:45:07 +0000
committerJohnny Chen <johnny.chen@apple.com>2009-10-29 01:45:07 +0000
commit1846dfa45079376f170fa50153344f48ff2bd257 (patch)
tree7b44e59adec7741701bcaf20224cd15340cadff4 /utils/TableGen
parent4c0236fd8b94f9721bac8a66c3220e797310c593 (diff)
downloadllvm-1846dfa45079376f170fa50153344f48ff2bd257.tar.gz
llvm-1846dfa45079376f170fa50153344f48ff2bd257.tar.bz2
llvm-1846dfa45079376f170fa50153344f48ff2bd257.tar.xz
Minor tweak to forgo the the curly braces for most case blocks, except when
declaring local variables. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85467 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/TableGen')
-rw-r--r--utils/TableGen/RISCDisassemblerEmitter.cpp1158
1 files changed, 1158 insertions, 0 deletions
diff --git a/utils/TableGen/RISCDisassemblerEmitter.cpp b/utils/TableGen/RISCDisassemblerEmitter.cpp
new file mode 100644
index 0000000000..3ef697ccb8
--- /dev/null
+++ b/utils/TableGen/RISCDisassemblerEmitter.cpp
@@ -0,0 +1,1158 @@
+//===- RISCDisassemblerEmitter.cpp - Disassembler Generator ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// FIXME: document
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCDisassemblerEmitter.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <cstdio>
+#include <map>
+#include <string>
+#include <sstream>
+
+#include <asl.h>
+
+using namespace llvm;
+
+#pragma mark Utility classes / structures
+
+// LLVM coding style
+#define INDENT_LEVEL 2
+
+class Indenter {
+public:
+ Indenter() : fDepth(0) {
+ memset(fString, ' ', sizeof(fString));
+ fString[fDepth] = '\0';
+ }
+
+ void push() {
+ if (fDepth < sizeof(fString) - INDENT_LEVEL) {
+ fString[fDepth] = ' ';
+ fDepth += INDENT_LEVEL;
+ fString[fDepth] = '\0';
+ }
+ }
+
+ void pop() {
+ if(fDepth >= INDENT_LEVEL) {
+ fString[fDepth] = ' ';
+ fDepth -= INDENT_LEVEL;
+ fString[fDepth] = '\0';
+ }
+ }
+
+ const char* indent() const {
+ return &fString[0];
+ }
+private:
+ char fString[256];
+ uint8_t fDepth;
+};
+
+#pragma mark Utility functions
+
+#if 0
+static int dprintf(int level, const char* format, ...) throw() {
+ static aslmsg* fMessage = NULL;
+
+ if (!fMessage) {
+ fMessage = new aslmsg;
+ *fMessage = asl_new(ASL_TYPE_MSG);
+ asl_set(*fMessage, ASL_KEY_FACILITY, "com.apple.llvm.disassembler.emitter.risc");
+ }
+
+ va_list ap;
+
+ va_start(ap, format);
+ int ret = asl_vlog(NULL, *fMessage, level, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
+
+static uint8_t byteFromBitsInit(BitsInit& init) {
+ int width = init.getNumBits();
+
+ assert(width <= 8 && "Field is too large for uint8_t!");
+
+ int index;
+ uint8_t mask = 0x01;
+
+ uint8_t ret = 0;
+
+ for (index = 0; index < width; index++) {
+ if (static_cast<BitInit*>(init.getBit(index))->getValue())
+ ret |= mask;
+
+ mask <<= 1;
+ }
+
+ return ret;
+}
+
+static uint8_t getByteField(const Record& def, const char* str) {
+ BitsInit* bits = def.getValueAsBitsInit(str);
+ return byteFromBitsInit(*bits);
+}
+
+static BitsInit& getBitsField(const Record& def, const char* str) {
+ BitsInit* bits = def.getValueAsBitsInit(str);
+ return *bits;
+}
+
+#if 0
+static void binaryFromNumber(std::string& binary,
+ uint64_t number,
+ unsigned minimumWidth = 1) {
+ unsigned bitIndex;
+ bool emitting = false;
+
+ binary = "0b";
+
+ for (bitIndex = (sizeof(number) * 8); bitIndex > 0; bitIndex--) {
+ uint64_t bit = (number & (1 << (bitIndex - 1))) >> (bitIndex - 1);
+
+ if (bitIndex == minimumWidth)
+ emitting = true;
+
+ if (bit) {
+ emitting = true;
+ binary.append("1");
+ } else if(emitting) {
+ binary.append("0");
+ }
+ }
+}
+#endif
+
+// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system
+// for a bit value.
+//
+// BIT_UNFILTERED is used as the init value for a filter position. It is used
+// only for filter processings.
+typedef enum {
+ BIT_TRUE, // '1'
+ BIT_FALSE, // '0'
+ BIT_UNSET, // '?'
+ BIT_UNFILTERED // unfiltered
+} bitValue_t;
+
+static bitValue_t bitFromBits(BitsInit& bits, unsigned index) {
+ if (BitInit* bit = dynamic_cast<BitInit*>(bits.getBit(index)))
+ return bit->getValue() ? BIT_TRUE : BIT_FALSE;
+
+ // The bit is uninitialized.
+ return BIT_UNSET;
+}
+
+static void dumpBits(std::ostream& o, BitsInit& bits) {
+ unsigned index;
+
+ for (index = bits.getNumBits(); index > 0; index--) {
+ switch (bitFromBits(bits, index - 1)) {
+ case BIT_TRUE:
+ o << "1";
+ break;
+ case BIT_FALSE:
+ o << "0";
+ break;
+ case BIT_UNSET:
+ o << "_";
+ break;
+ default:
+ assert(0 && "unexpected return value from bitFromBits");
+ }
+ }
+}
+
+#pragma mark Enums
+
+#define ARM_FORMS \
+ ENTRY(ARM_FORM_PSEUDO, 0) \
+ ENTRY(ARM_FORM_MULFRM, 1) \
+ ENTRY(ARM_FORM_BRFRM, 2) \
+ ENTRY(ARM_FORM_BRMISCFRM, 3) \
+ ENTRY(ARM_FORM_DPFRM, 4) \
+ ENTRY(ARM_FORM_DPSOREGFRM, 5) \
+ ENTRY(ARM_FORM_LDFRM, 6) \
+ ENTRY(ARM_FORM_STFRM, 7) \
+ ENTRY(ARM_FORM_LDMISCFRM, 8) \
+ ENTRY(ARM_FORM_STMISCFRM, 9) \
+ ENTRY(ARM_FORM_LDSTMULFRM, 10) \
+ ENTRY(ARM_FORM_ARITHMISCFRM, 11) \
+ ENTRY(ARM_FORM_EXTFRM, 12) \
+ ENTRY(ARM_FORM_VFPUNARYFRM, 13) \
+ ENTRY(ARM_FORM_VFPBINARYFRM, 14) \
+ ENTRY(ARM_FORM_VFPCONV1FRM, 15) \
+ ENTRY(ARM_FORM_VFPCONV2FRM, 16) \
+ ENTRY(ARM_FORM_VFPCONV3FRM, 17) \
+ ENTRY(ARM_FORM_VFPCONV4FRM, 18) \
+ ENTRY(ARM_FORM_VFPCONV5FRM, 19) \
+ ENTRY(ARM_FORM_VFPLDSTFRM, 20) \
+ ENTRY(ARM_FORM_VFPLDSTMULFRM, 21) \
+ ENTRY(ARM_FORM_VFPMISCFRM, 22) \
+ ENTRY(ARM_FORM_THUMBFRM, 23) \
+ ENTRY(ARM_FORM_NEONFRM, 24) \
+ ENTRY(ARM_FORM_NEONGETLNFRM, 25) \
+ ENTRY(ARM_FORM_NEONSETLNFRM, 26) \
+ ENTRY(ARM_FORM_NEONDUPFRM, 27)
+
+// ARM instruction format specifies the encoding used by the instruction.
+#define ENTRY(n, v) n = v,
+enum ARMForm {
+ ARM_FORMS
+ ARM_FORM_max
+};
+#undef ENTRY
+
+// Converts enum to const char*.
+static const char* stringWithARMForm(enum ARMForm form) {
+#define ENTRY(n, v) case n: return #n;
+ switch(form) {
+ ARM_FORMS
+ case ARM_FORM_max:
+ default:
+ return "";
+ }
+#undef ENTRY
+}
+
+static std::vector< std::vector<unsigned> > sConflicts;
+
+class AbstractFilterChooser {
+public:
+ virtual void emitTop(std::ostream& o, Indenter& i) = 0;
+};
+
+template <unsigned tBitWidth>
+class FilterChooser : public AbstractFilterChooser {
+protected:
+ // Representation of the instruction to work on.
+ typedef uint8_t insn_t[tBitWidth];
+
+ class Filter {
+ protected:
+ FilterChooser* fParent; // pointer without ownership
+ unsigned fStartBit; // the starting bit position
+ unsigned fNumBits; // number of bits to filter
+ bool fMixed; // a mixed region contains set and unset bits
+
+ // Map of well-known segment value to the set of uid's with that value.
+ std::map<uint64_t, std::vector<unsigned> > fFilteredInstructions;
+
+ // Set of uid's with non-constant segment values.
+ std::vector<unsigned> fVariableInstructions;
+
+ // Map of well-known segment value to its delegate.
+ std::map<unsigned, FilterChooser> fSubChoosers;
+ public:
+ Filter(const Filter& f) :
+ fParent(f.fParent),
+ fStartBit(f.fStartBit),
+ fNumBits(f.fNumBits),
+ fMixed(f.fMixed),
+ fFilteredInstructions(f.fFilteredInstructions),
+ fVariableInstructions(f.fVariableInstructions),
+ fSubChoosers(f.fSubChoosers) { }
+
+ Filter(FilterChooser& parent, unsigned startBit, unsigned numBits, bool mixed) :
+ fParent(&parent),
+ fStartBit(startBit),
+ fNumBits(numBits),
+ fMixed(mixed)
+ {
+ unsigned insnIndex;
+ unsigned numInsns = fParent->fInstructionsToFilter.size();
+
+ for (insnIndex = 0; insnIndex < numInsns; insnIndex++) {
+ insn_t insn;
+
+ // Populates the insn given the uid.
+ fParent->insnWithID(insn, fParent->fInstructionsToFilter[insnIndex]);
+
+ uint64_t field;
+ // Scans the segment for possibly well-specified encoding bits.
+ bool ok = fParent->fieldFromInsn(field, insn, fStartBit, fNumBits);
+
+ if (ok) {
+ // The encoding bits are well-known. Lets add the uid of the
+ // instruction into the bucket keyed off the constant field value.
+ fFilteredInstructions[field].push_back(fParent->fInstructionsToFilter[insnIndex]);
+ } else {
+ // Some of the encoding bit(s) are unspecfied. This contributes to
+ // one additional member of "Variable" instructions.
+ fVariableInstructions.push_back(fParent->fInstructionsToFilter[insnIndex]);
+ }
+ }
+
+ assert((fFilteredInstructions.size() + fVariableInstructions.size() > 0)
+ && "Filter returns no instruction categories");
+ }
+
+ // Divides the decoding task into sub tasks and delegates them to the
+ // inferior FilterChooser's.
+ void recurse() {
+ std::map<uint64_t, std::vector<unsigned> >::const_iterator mapIterator;
+
+ bitValue_t filtered[tBitWidth];
+ // Starts by inheriting our parent filter chooser's bit values.
+ memcpy(filtered, fParent->fFiltered, sizeof(filtered));
+
+ unsigned bitIndex;
+
+ for (mapIterator = fFilteredInstructions.begin();
+ mapIterator != fFilteredInstructions.end();
+ mapIterator++) {
+
+ // Marks all the segment positions with either BIT_TRUE or BIT_FALSE.
+ for (bitIndex = 0; bitIndex < fNumBits; bitIndex++) {
+ if (mapIterator->first & (1 << bitIndex))
+ filtered[fStartBit + bitIndex] = BIT_TRUE;
+ else
+ filtered[fStartBit + bitIndex] = BIT_FALSE;
+ }
+
+ // Delegates to an inferior filter chooser for futher processing on this
+ // category of instructions.
+ fSubChoosers.insert(std::pair<unsigned, FilterChooser>(
+ mapIterator->first,
+ FilterChooser(fParent->fAllInstructions,
+ mapIterator->second,
+ filtered,
+ *fParent)
+ ));
+ }
+
+ if (fVariableInstructions.size()) {
+ // Conservatively marks each segment position as BIT_UNSET.
+ for (bitIndex = 0; bitIndex < fNumBits; bitIndex++)
+ filtered[fStartBit + bitIndex] = BIT_UNSET;
+
+ // Delegates to an inferior filter chooser for futher processing on this
+ // group of instructions whose segment values are variable.
+ fSubChoosers.insert(std::pair<unsigned, FilterChooser>(
+ (unsigned)-1,
+ FilterChooser(fParent->fAllInstructions,
+ fVariableInstructions,
+ filtered,
+ *fParent)
+ ));
+ }
+ }
+
+ // Emits code to decode instructions given a segment of bits.
+ void emit(std::ostream& o, Indenter& i) {
+ o << i.indent() << "// Check Inst{";
+
+ if (fNumBits > 1)
+ o << (fStartBit + fNumBits - 1) << '-';
+
+ o << fStartBit << "} ...\n";
+
+ o << i.indent() << "switch (fieldFromInstruction(insn, " << fStartBit << ", " << fNumBits << ")) {\n";
+ i.push();
+
+ typename std::map<unsigned, FilterChooser>::iterator filterIterator;
+
+ for (filterIterator = fSubChoosers.begin();
+ filterIterator != fSubChoosers.end();
+ filterIterator++) {
+
+ // Field value -1 implies a non-empty set of variable instructions.
+ // See also recurse().
+ if (filterIterator->first == (unsigned)-1)
+ o << i.indent() << "default:\n";
+ else
+ o << i.indent() << "case " << filterIterator->first << ":\n";
+
+ // We arrive at a category of instructions with the same segment value.
+ // Now delegate to the sub filter chooser for further decodings.
+ i.push();
+ {
+ bool finished = filterIterator->second.emit(o, i);
+ if (!finished) o << i.indent() << "break;\n";
+ }
+ i.pop();
+ }
+
+ i.pop();
+ o << i.indent() << "}\n";
+ }
+
+ // Returns the number of fanout produced by the filter. More fanout implies
+ // the filter distinguishes more categories of instructions.
+ unsigned usefulness() const {
+ if (fVariableInstructions.size())
+ return fFilteredInstructions.size();
+ else
+ return fFilteredInstructions.size() - 1;
+ }
+ };
+
+ friend class Filter;
+
+ // Vector of codegen instructions to choose our filter.
+ const std::vector<const CodeGenInstruction*>& fAllInstructions;
+
+ // Vector of uid's for this filter chooser to work on.
+ const std::vector<unsigned> fInstructionsToFilter;
+
+ // Vector of candidate filters.
+ std::vector<Filter> fFilters;
+
+ // Array of bit values passed down from our parent.
+ // Set to all BIT_UNFILTERED's for fRarent == NULL.
+ bitValue_t fFiltered[tBitWidth];
+
+ // Link to the FilterChooser in our parent chain.
+ FilterChooser* fParent;
+
+ // Index of the best filter from fFilters.
+ int fBestIndex;
+
+public:
+ FilterChooser(const FilterChooser& fc) :
+ AbstractFilterChooser(),
+ fAllInstructions(fc.fAllInstructions),
+ fInstructionsToFilter(fc.fInstructionsToFilter),
+ fFilters(fc.fFilters),
+ fParent(fc.fParent),
+ fBestIndex(fc.fBestIndex)
+ {
+ memcpy(fFiltered, fc.fFiltered, sizeof(fFiltered));
+ }
+
+ FilterChooser(const std::vector<const CodeGenInstruction*>& allInstructions,
+ const std::vector<unsigned>& instructionsToFilter) :
+ fAllInstructions(allInstructions),
+ fInstructionsToFilter(instructionsToFilter),
+ fFilters(),
+ fParent(NULL),
+ fBestIndex(-1)
+ {
+ unsigned bitIndex;
+
+ for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++)
+ fFiltered[bitIndex] = BIT_UNFILTERED;
+
+ doFilter();
+ }
+
+ FilterChooser(const std::vector<const CodeGenInstruction*>& allInstructions,
+ const std::vector<unsigned>& instructionsToFilter,
+ bitValue_t (&lastFiltered)[tBitWidth],
+ FilterChooser& parent) :
+ fAllInstructions(allInstructions),
+ fInstructionsToFilter(instructionsToFilter),
+ fFilters(),
+ fParent(&parent),
+ fBestIndex(-1)
+ {
+ unsigned bitIndex;
+
+ for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++)
+ fFiltered[bitIndex] = lastFiltered[bitIndex];
+
+ doFilter();
+ }
+
+ void emitTop(std::ostream& o, Indenter& i) {
+ switch(tBitWidth) {
+ case 8:
+ o << i.indent() << "typedef uint8_t field_t;\n";
+ break;
+ case 16:
+ o << i.indent() << "typedef uint16_t field_t;\n";
+ break;
+ case 32:
+ o << i.indent() << "typedef uint32_t field_t;\n";
+ break;
+ case 64:
+ o << i.indent() << "typedef uint64_t field_t;\n";
+ break;
+ default:
+ assert(0 && "Unexpected instruction size!");
+ }
+
+ o << '\n';
+
+ o << i.indent() << "field_t fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n";
+
+ o << i.indent() << "{\n";
+ i.push();
+ {
+ o << i.indent() << "assert(startBit + numBits <= " << tBitWidth << " && \"Instruction field out of bounds!\");\n";
+ o << '\n';
+ o << i.indent() << "field_t fieldMask;\n";
+ o << '\n';
+ o << i.indent() << "if (numBits == " << tBitWidth << ")\n";
+
+ i.push();
+ {
+ o << i.indent() << "fieldMask = (field_t)-1;\n";
+ }
+ i.pop();
+
+ o << i.indent() << "else\n";
+
+ i.push();
+ {
+ o << i.indent() << "fieldMask = ((1 << numBits) - 1) << startBit;\n";
+ }
+ i.pop();
+
+ o << '\n';
+ o << i.indent() << "return (insn & fieldMask) >> numBits;\n";
+ }
+ i.pop();
+ o << i.indent() << "}\n";
+
+ o << '\n';
+
+ o << i.indent() << "uint16_t decodeInstruction(field_t insn) {\n";
+
+ i.push();
+ {
+ // Emits code to decode the instructions.
+ emit(o, i);
+
+ o << '\n';
+ o << i.indent() << "return 0;\n";
+ }
+ i.pop();
+
+ o << i.indent() << "}" << std::endl;
+ }
+
+protected:
+ // Populates the insn given the uid.
+ void insnWithID(insn_t& insn, unsigned insnID) const {
+ BitsInit& bits = getBitsField(*fAllInstructions[insnID]->TheDef, "Inst");
+
+ unsigned index;
+
+ for (index = 0; index < tBitWidth; index++)
+ insn[index] = bitFromBits(bits, index);
+ }
+
+ // Returns the record name.
+ const std::string& nameWithID(unsigned insnID) const {
+ return fAllInstructions[insnID]->TheDef->getName();
+ }
+
+ // Populates the field of the insn given the start position and the number of
+ // consecutive bits to scan for.
+ //
+ // Returns false if and on the first uninitialized bit value encountered.
+ // Returns true, otherwise.
+ const bool fieldFromInsn(uint64_t& field, insn_t& insn, unsigned startBit,
+ unsigned numBits) const {
+ unsigned bitIndex;
+
+ field = 0;
+
+ for (bitIndex = 0; bitIndex < numBits; bitIndex++) {
+ if (insn[startBit + bitIndex] == BIT_UNSET)
+ return false;
+
+ if (insn[startBit + bitIndex] == BIT_TRUE)
+ field = field | (1 << bitIndex);
+ }
+
+ return true;
+ }
+
+ void dumpFilterArray(std::ostream& o, bitValue_t (&filter)[tBitWidth]) {
+ unsigned bitIndex;
+
+ for (bitIndex = tBitWidth; bitIndex > 0; bitIndex--) {
+ switch (filter[bitIndex - 1]) {
+ case BIT_UNFILTERED:
+ o << ".";
+ break;
+ case BIT_UNSET:
+ o << "_";
+ break;
+ case BIT_TRUE:
+ o << "1";
+ break;
+ case BIT_FALSE:
+ o << "0";
+ break;
+ }
+ }
+ }
+
+ void dumpStack(std::ostream& o, const char* prefix) {
+ FilterChooser* current = this;
+
+ while (current) {
+ o << prefix;
+
+ dumpFilterArray(o, current->fFiltered);
+
+ o << std::endl;
+
+ current = current->fParent;
+ }
+ }
+
+ Filter& bestFilter() {
+ assert(fBestIndex != -1 && "fBestIndex not set");
+ return fFilters[fBestIndex];
+ }
+
+ // States of our finite state machines.
+ typedef enum {
+ ATTR_NONE,
+ ATTR_FILTERED,
+ ATTR_ALL_SET,
+ ATTR_ALL_UNSET,
+ ATTR_MIXED
+ } bitAttr_t;
+
+ bool filterProcessor(bool allowMixed = true) {
+ fFilters.clear();
+ unsigned numInstructions = fInstructionsToFilter.size();
+
+ assert(numInstructions && "Filter created with no instructions");
+
+ // No further filtering is necessary.
+ if (numInstructions == 1)
+ return true;
+
+ unsigned bitIndex, insnIndex;
+
+ // We maintain tBitWidth copies of the bitAttrs automaton.
+ // The automaton consumes the corresponding bit from each
+ // instruction.
+ //
+ // Input symbols: 0, 1, and _ (unset).
+ // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED.
+ // Initial state: NONE.
+ //
+ // (NONE) ------- [01] -> (ALL_SET)
+ // (NONE) ------- _ ----> (ALL_UNSET)
+ // (ALL_SET) ---- [01] -> (ALL_SET)
+ // (ALL_SET) ---- _ ----> (MIXED)
+ // (ALL_UNSET) -- [01] -> (MIXED)
+ // (ALL_UNSET) -- _ ----> (ALL_UNSET)
+ // (MIXED) ------ . ----> (MIXED)
+ // (FILTERED)---- . ----> (FILTERED)
+
+ bitAttr_t bitAttrs[tBitWidth];
+
+ // FILTERED bit positions provide no entropy and are not worthy of pursuing.
+ // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position.
+ for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex)
+ if (fFiltered[bitIndex] == BIT_TRUE || fFiltered[bitIndex] == BIT_FALSE)
+ bitAttrs[bitIndex] = ATTR_FILTERED;
+ else
+ bitAttrs[bitIndex] = ATTR_NONE;
+
+ for (insnIndex = 0; insnIndex < numInstructions; ++insnIndex) {
+ insn_t insn;
+
+ insnWithID(insn, fInstructionsToFilter[insnIndex]);
+
+ for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) {
+ switch (bitAttrs[bitIndex]) {
+ case ATTR_NONE:
+ if (insn[bitIndex] == BIT_UNSET)
+ bitAttrs[bitIndex] = ATTR_ALL_UNSET;
+ else
+ bitAttrs[bitIndex] = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_SET:
+ if (insn[bitIndex] == BIT_UNSET)
+ bitAttrs[bitIndex] = ATTR_MIXED;
+ break;
+ case ATTR_ALL_UNSET:
+ if (insn[bitIndex] != BIT_UNSET)
+ bitAttrs[bitIndex] = ATTR_MIXED;
+ break;
+ case ATTR_MIXED:
+ case ATTR_FILTERED:
+ break;
+ }
+ }
+ }
+
+ // The regionAttr automaton consumes the bitAttrs automatons' state,
+ // lowest-to-highest.
+ //
+ // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed)
+ // States: NONE, ALL_SET, MIXED
+ // Initial state: NONE
+ //
+ // (NONE) ----- F --> (NONE)
+ // (NONE) ----- S --> (ALL_SET) ; and set region start
+ // (NONE) ----- U --> (NONE)
+ // (NONE) ----- M --> (MIXED) ; and set region start
+ // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region
+ // (ALL_SET) -- S --> (ALL_SET)
+ // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region
+ // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region
+ // (MIXED) ---- F --> (NONE) ; and report a MIXED region
+ // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region
+ // (MIXED) ---- U --> (NONE) ; and report a MIXED region
+ // (MIXED) ---- M --> (MIXED)
+
+ bitAttr_t regionAttr = ATTR_NONE;
+
+ unsigned startBit = 0;
+
+ for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++) {
+ bitAttr_t bitAttr = bitAttrs[bitIndex];
+
+ assert(bitAttr != ATTR_NONE && "Bit without attributes");
+
+#define SET_START \
+ startBit = bitIndex;
+
+#define REPORT_REGION \
+ if (regionAttr == ATTR_MIXED && allowMixed) \
+ fFilters.push_back(Filter(*this, startBit, bitIndex - startBit, true));\
+ else if (regionAttr == ATTR_ALL_SET && !allowMixed) \
+ fFilters.push_back(Filter(*this, startBit, bitIndex - startBit, false));
+
+ switch (regionAttr) {
+ case ATTR_NONE:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ break;
+ case ATTR_ALL_SET:
+ SET_START
+ regionAttr = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_UNSET:
+ break;
+ case ATTR_MIXED:
+ SET_START
+ regionAttr = ATTR_MIXED;
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_ALL_SET:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ REPORT_REGION
+ regionAttr = ATTR_NONE;
+ break;
+ case ATTR_ALL_SET:
+ break;
+ case ATTR_ALL_UNSET:
+ REPORT_REGION
+ regionAttr = ATTR_NONE;
+ break;
+ case ATTR_MIXED:
+ REPORT_REGION
+ SET_START
+ regionAttr = ATTR_MIXED;
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_MIXED:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ REPORT_REGION
+ SET_START
+ regionAttr = ATTR_NONE;
+ break;
+ case ATTR_ALL_SET:
+ REPORT_REGION
+ SET_START
+ regionAttr = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_UNSET:
+ REPORT_REGION
+ regionAttr = ATTR_NONE;
+ break;
+ case ATTR_MIXED:
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_ALL_UNSET:
+ assert(0 && "regionAttr state machine has no ATTR_UNSET state");
+ case ATTR_FILTERED:
+ assert(0 && "regionAttr state machine has no ATTR_FILTERED state");
+ }
+ }
+
+ // At the end, if we're still in ALL_SET or MIXED states, report a region
+
+ switch (regionAttr) {
+ case ATTR_NONE:
+ break;
+ case ATTR_FILTERED:
+ break;
+ case ATTR_ALL_SET:
+ REPORT_REGION
+ break;
+ case ATTR_ALL_UNSET:
+ break;
+ case ATTR_MIXED:
+ REPORT_REGION
+ break;
+ }
+
+#undef SET_START
+#undef REPORT_REGION
+
+ bool allAreUseless = true;
+ fBestIndex = 0;
+ unsigned bestUsefulness = 0;
+ unsigned filterIndex;
+ unsigned numFilters = fFilters.size();
+
+ for (filterIndex = 0; filterIndex < numFilters; ++filterIndex) {
+ unsigned usefulness = fFilters[filterIndex].usefulness();
+
+ if (usefulness)
+ allAreUseless = false;
+
+ if (usefulness > bestUsefulness) {
+ fBestIndex = filterIndex;
+ bestUsefulness = usefulness;
+ }
+ }
+
+ if (!allAreUseless) {
+ bestFilter().recurse();
+ }
+
+ return !allAreUseless;
+ } // end of filterProcessor(bool)
+
+ // Decides on the best configuration of filter(s) to use in order to decode
+ // the instructions. A conflict of instructions may occur, in which case we
+ // dump the conflict set to the standard error.
+ void doFilter() {
+ unsigned numInstructions = fInstructionsToFilter.size();
+ assert(numInstructions && "FilterChooser created with no instructions");
+
+ if (filterProcessor(false))
+ return;
+
+ if (filterProcessor(true))
+ return;
+
+ // If we come to here, the instruction decoding has failed.
+ // Print out the instructions in the conflict set...
+
+ fBestIndex = -1;
+
+ std::cerr << "Conflict:" << std::endl;
+
+ unsigned insnIndex;
+
+ dumpStack(std::cerr, " ");
+
+ for (insnIndex = 0; insnIndex < numInstructions; insnIndex++) {
+ const std::string& name = nameWithID(fInstructionsToFilter[insnIndex]);
+
+ std::cerr << " " << std::setw(15) << std::left << name << " ";
+ dumpBits(std::cerr,
+ getBitsField(*fAllInstructions[
+ fInstructionsToFilter[insnIndex]]->TheDef,
+ "Inst"));
+ std::cerr << std::endl;
+ }
+ }
+
+ // Emits code to decode our share of instructions. Returns true if the
+ // emitted code causes a return, which occurs if we known how to decode
+ // the instruction at this level or the instruction is not decodeable.
+ bool emit(std::ostream& o, Indenter& i) {
+ if (fInstructionsToFilter.size() == 1) {
+ // There is only one instruction in the set, which is great!
+ // Lets return the decoded instruction.
+ o << i.indent() << "return " << fInstructionsToFilter[0] << "; // "
+ << nameWithID(fInstructionsToFilter[0]) << '\n';
+ return true;
+ } else if (fBestIndex == -1) {
+ if (fInstructionsToFilter.size() == 2) {
+ // Resolve the known conflicts sets:
+ //
+ // 1. source registers are identical => VMOVD; otherwise => VORRd
+ // 2. source registers are identical => VMOVQ; otherwise => VORRq
+ const std::string& name1 = nameWithID(fInstructionsToFilter[0]);
+ const std::string& name2 = nameWithID(fInstructionsToFilter[1]);
+ if ((name1 == "VMOVD" && name2 == "VORRd") ||
+ (name1 == "VMOVQ" && name2 == "VORRq")) {
+ // Inserting the opening curly brace for this case block.
+ i.pop();
+ o << i.indent() << "{\n";
+ i.push();
+
+ o << i.indent() <<
+ "field_t N = fieldFromInstruction(insn, 7, 1), M = fieldFromInstruction(insn, 5, 1);\n";
+ o << i.indent() <<
+ "field_t Vn = fieldFromInstruction(insn, 16, 4), Vm = fieldFromInstruction(insn, 0, 4);\n";
+ o << i.indent() << "return (N == M && Vn == Vm) ? "
+ << fInstructionsToFilter[0] << " /* " << name1 << " */ : "
+ << fInstructionsToFilter[1] << " /* " << name2 << " */ ;\n";
+
+ // Inserting the closing curly brace for this case block.
+ i.pop();
+ o << i.indent() << "}\n";
+ i.push();
+
+ return true;
+ }
+ // Otherwise, it does not belong to the known conflict sets.
+ }
+ // We don't know how to decode this instruction! Dump the conflict set!
+ o << i.indent() << "return 0;" << " // Conflict set: ";
+ for (int i = 0, N = fInstructionsToFilter.size(); i < N; ++i) {
+ o << nameWithID(fInstructionsToFilter[i]);
+ if (i < (N - 1))
+ o << ", ";
+ else
+ o << '\n';
+ }
+ return true;
+ } else {
+ // Choose the best filter to do the decodings!
+ bestFilter().emit(o, i);
+ return false;
+ }
+ }
+};
+
+#pragma mark Backend
+
+class RISCDisassemblerEmitter::RISCDEBackend {
+public:
+ RISCDEBackend(RISCDisassemblerEmitter& frontend) :
+ fNumberedInstructions(),
+ fTopLevelInstructions(),
+ fFrontend(frontend),
+ fTarget(),
+ fFilterChooser(NULL)
+ {
+ populateInstructions();
+
+ if (fTarget.getName() == "ARM") {
+ fTargetName = TARGET_ARM;
+ } else {
+ std::cerr << "Target name " << fTarget.getName() << " not recognized" << std::endl;
+ assert(0 && "Unknown target");
+ }
+ }
+
+ ~RISCDEBackend() {
+ if (fFilterChooser) {
+ delete fFilterChooser;
+ fFilterChooser = NULL;
+ }
+ }
+
+ void getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>&
+ numberedInstructions) {
+ // Dig down to the proper namespace. Code shamelessly stolen from
+ // InstrEnumEmitter.cpp
+ std::string Namespace;
+ CodeGenTarget::inst_iterator II, E;
+
+ for (II = fTarget.inst_begin(), E = fTarget.inst_end(); II != E; ++II)
+ if (II->second.Namespace != "TargetInstrInfo") {
+ Namespace = II->second.Namespace;
+ break;
+ }
+
+ assert(!Namespace.empty() && "No instructions defined.");
+
+ fTarget.getInstructionsByEnumValue(numberedInstructions);
+ }
+
+ bool populateInstruction(const CodeGenInstruction& insn) {
+ const Record& def = *insn.TheDef;
+ const std::string& name = def.getName();
+ uint8_t form = getByteField(def, "Form");
+ BitsInit& bits = getBitsField(def, "Inst");
+
+ if (fTargetName == TARGET_ARM) {
+ if (form == ARM_FORM_PSEUDO)
+ return false;
+ if (fTargetName == TARGET_ARM && name[0] == 't')
+ return false;
+ if (name.find("CMPz") != std::string::npos ||
+ name.find("CMNz") != std::string::npos)
+ return false;
+ if (name.find("BX_RET") != std::string::npos ||
+ name.find("BXr9") != std::string::npos ||
+ name.find("BLXr9") != std::string::npos)
+ return false;
+
+ //
+ // The following special cases are for conflict resolutions.
+ //
+
+ // RSCSri and RSCSrs set the 's' bit, but are not predicated. We are
+ // better off using the generic RSCri and RSCrs instructions.
+ if (name == "RSCSri" || name == "RSCSrs") return false;
+
+ // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used
+ // in the compiler to implement conditional moves. We can ignore them in
+ // favor of their more generic versions of instructions.
+ // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op).
+ if (name == "MOVCCr" || name == "MOVCCs" || name == "MOVCCi" ||
+ name == "FCPYScc" || name == "FCPYDcc" ||
+ name == "FNEGScc" || name == "FNEGDcc")
+ return false;
+
+ // Ignore the *_sfp instructions when decoding. They are used by the
+ // compiler to implement scalar floating point operations using vector
+ // operations in order to work around some performance issues.
+ if (name.find("_sfp") != std::string::npos) return false;
+
+ // LDM_RET is a special case of LDM (Load Multiple) where the registers
+ // loaded include the PC, causing a branch to a loaded address. Ignore
+ // the LDM_RET instruction when decoding.
+ if (name == "LDM_RET") return false;
+
+ // Bcc is in a more generic form than B. Ignore B when decoding.
+ if (name == "B") return false;
+
+ // Ignore the non-Darwin BL instructions and the TPsoft (TLS) instruction.
+ if (name == "BL" || name == "BL_pred" || name == "TPsoft") return false;
+
+ // Ignore VDUPf[d|q] instructions known to conflict with VDUP32[d-q] for
+ // decoding. The instruction duplicates an element from an ARM core
+ // register into every element of the destination vector. There is no
+ // distinction between data types.
+ if (name == "VDUPfd" || name == "VDUPfq") return false;
+ }
+
+ // Dumps the instruction encoding format.
+ switch (fTargetName) {
+ case TARGET_ARM:
+ std::cerr << name << " " << stringWithARMForm((ARMForm)form);
+ break;
+ }
+
+ std::cerr << " ";
+
+ // Dumps the instruction encoding bits.
+ dumpBits(std::cerr, bits);
+
+ std::cerr << std::endl;
+
+ // Dumps the list of operand info.
+ for (unsigned i = 0, e = insn.OperandList.size(); i != e; ++i) {
+ CodeGenInstruction::OperandInfo info = insn.OperandList[i];
+ const std::string& operandName = info.Name;
+ const Record& operandDef = *info.Rec;
+
+ std::cerr << "\t" << operandName << " (" << operandDef.getName() << ") "
+ << std::endl;
+ }
+
+ return true;
+ }
+
+ void populateInstructions() {
+ getInstructionsByEnumValue(fNumberedInstructions);
+
+ uint16_t numUIDs = fNumberedInstructions.size();
+ uint16_t uid;
+
+ const char* instClass;
+
+ switch (fTargetName) {
+ case TARGET_ARM:
+ instClass = "InstARM";
+ }
+
+ for (uid = 0; uid < numUIDs; uid++) {
+ // filter out intrinsics
+ if (!fNumberedInstructions[uid]->TheDef->isSubClassOf(instClass))
+ continue;
+
+ if (populateInstruction(*fNumberedInstructions[uid]))
+ fTopLevelInstructions.push_back(uid);
+ }
+
+ switch (fTargetName) {
+ case TARGET_ARM:
+ fFilterChooser = new FilterChooser<32>(fNumberedInstructions,
+ fTopLevelInstructions);
+ }
+ }
+
+ // Emits disassembler code for instruction decoding. This delegates to the
+ // FilterChooser instance to do the heavy lifting.
+ void emit(std::ostream& o) {
+ Indenter i;
+ std::string s;
+ raw_string_ostream ro(s);
+
+ switch (fTargetName) {
+ case TARGET_ARM:
+ fFrontend.EmitSourceFileHeader("ARM Disassembler", ro);
+ }
+
+ ro.flush();
+ o << s;
+
+ o << i.indent() << "#include <inttypes.h>\n";
+ o << i.indent() << "#include <assert.h>\n";
+ o << '\n';
+
+ fFilterChooser->emitTop(o, i);
+ }
+
+protected:
+ std::vector<const CodeGenInstruction*> fNumberedInstructions;
+ std::vector<unsigned> fTopLevelInstructions;
+ RISCDisassemblerEmitter& fFrontend;
+ CodeGenTarget fTarget;
+ AbstractFilterChooser* fFilterChooser;
+
+ enum {
+ TARGET_ARM = 0
+ } fTargetName;
+};
+
+#pragma mark Backend interface
+
+void RISCDisassemblerEmitter::initBackend()
+{
+ fBackend = new RISCDEBackend(*this);
+}
+
+void RISCDisassemblerEmitter::run(raw_ostream& o)
+{
+ std::ostringstream so;
+ fBackend->emit(so);
+ o << so.str();
+}
+
+void RISCDisassemblerEmitter::shutdownBackend()
+{
+ delete fBackend;
+}