aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorShih-wei Liao <sliao@google.com>2010-04-28 01:47:00 -0700
committerShih-wei Liao <sliao@google.com>2010-04-28 01:47:00 -0700
commit7abe37e4aee38cc79d91dd069a37d7e91d5bef53 (patch)
treec13b26fc3d8909240f981988535c0b82dd9bf37c /utils
parent6037a7c3c97b651dd70e48ebe5453134713971ed (diff)
downloadexternal_llvm-7abe37e4aee38cc79d91dd069a37d7e91d5bef53.zip
external_llvm-7abe37e4aee38cc79d91dd069a37d7e91d5bef53.tar.gz
external_llvm-7abe37e4aee38cc79d91dd069a37d7e91d5bef53.tar.bz2
Sync upstream to r102410.
Re-turn on sdk. Change-Id: I91a890863989a67243b4d2dfd1ae09b843ebaeaf
Diffstat (limited to 'utils')
-rw-r--r--utils/FileCheck/FileCheck.cpp17
-rwxr-xr-xutils/NewNightlyTest.pl23
-rw-r--r--utils/TableGen/ARMDecoderEmitter.cpp1870
-rw-r--r--utils/TableGen/ARMDecoderEmitter.h50
-rw-r--r--utils/TableGen/Android.mk1
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp37
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp14
-rw-r--r--utils/TableGen/AsmWriterInst.cpp1
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp2
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp10
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp1712
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h247
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp81
-rw-r--r--utils/TableGen/CodeGenInstruction.h14
-rw-r--r--utils/TableGen/CodeGenTarget.cpp210
-rw-r--r--utils/TableGen/CodeGenTarget.h54
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp82
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp19
-rw-r--r--utils/TableGen/DAGISelMatcher.h8
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp57
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp124
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp17
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp12
-rw-r--r--utils/TableGen/EDEmitter.cpp634
-rw-r--r--utils/TableGen/FastISelEmitter.cpp24
-rw-r--r--utils/TableGen/InstrEnumEmitter.cpp13
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp100
-rw-r--r--utils/TableGen/InstrInfoEmitter.h2
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp13
-rw-r--r--utils/TableGen/Record.cpp35
-rw-r--r--utils/TableGen/Record.h14
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp44
-rw-r--r--utils/TableGen/SubtargetEmitter.h3
-rw-r--r--utils/TableGen/TableGen.cpp8
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp4
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp3
-rwxr-xr-xutils/buildit/build_llvm9
-rw-r--r--utils/fpcmp/fpcmp.cpp4
-rw-r--r--utils/lit/lit/ExampleTests/Clang/lit.cfg33
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll2
-rw-r--r--utils/lit/lit/LitConfig.py21
-rw-r--r--utils/lit/lit/LitFormats.py1
-rw-r--r--utils/lit/lit/LitTestCase.py30
-rw-r--r--utils/lit/lit/TestFormats.py20
-rw-r--r--utils/lit/lit/TestRunner.py43
-rw-r--r--utils/lit/lit/TestingConfig.py8
-rwxr-xr-xutils/lit/lit/lit.py55
-rwxr-xr-xutils/mkpatch2
-rw-r--r--utils/unittest/UnitTestMain/Makefile6
-rw-r--r--utils/unittest/googletest/Makefile10
-rw-r--r--utils/unittest/googletest/gtest-filepath.cc4
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h1
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-port.h3
54 files changed, 4300 insertions, 1512 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index 3c4742c..e7cd713 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -401,11 +401,12 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
}
}
- if (Best != StringRef::npos && BestQuality < 50) {
- // Print the "possible intended match here" line if we found something
- // reasonable.
- SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Best),
- "possible intended match here", "note");
+ // Print the "possible intended match here" line if we found something
+ // reasonable and not equal to what we showed in the "scanning from here"
+ // line.
+ if (Best && Best != StringRef::npos && BestQuality < 50) {
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Best),
+ "possible intended match here", "note");
// FIXME: If we wanted to be really friendly we would show why the match
// failed, as it can be hard to spot simple one character differences.
@@ -440,7 +441,7 @@ struct CheckString {
/// CanonicalizeInputFile - Remove duplicate horizontal space from the specified
/// memory buffer, free it, and return a new one.
static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
- SmallVector<char, 16> NewFile;
+ SmallString<128> NewFile;
NewFile.reserve(MB->getBufferSize());
for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd();
@@ -460,9 +461,7 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
// Free the old buffer and return a new one.
MemoryBuffer *MB2 =
- MemoryBuffer::getMemBufferCopy(NewFile.data(),
- NewFile.data() + NewFile.size(),
- MB->getBufferIdentifier());
+ MemoryBuffer::getMemBufferCopy(NewFile.str(), MB->getBufferIdentifier());
delete MB;
return MB2;
diff --git a/utils/NewNightlyTest.pl b/utils/NewNightlyTest.pl
index a306382..4287cc1 100755
--- a/utils/NewNightlyTest.pl
+++ b/utils/NewNightlyTest.pl
@@ -24,6 +24,7 @@ use Socket;
# IMPLEMENTED.
# -nickname NAME The NAME argument specifieds the nickname this script
# will submit to the nightlytest results repository.
+# -nouname Don't include uname data (machine will be identified by nickname only).
# -submit-server Specifies a server to submit the test results too. If this
# option is not specified it defaults to
# llvm.org. This is basically just the address of the
@@ -220,6 +221,7 @@ while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) {
$LLVMGCCPATH = $ARGV[0] . '/bin';
shift; next;}
if (/^-noexternals$/) { $NOEXTERNALS = 1; next; }
+ if (/^-nouname$/) { $NOUNAME = 1; next; }
if (/^-use-gmake/) { $MAKECMD = "gmake"; shift; next; }
if (/^-extraflags/) { $CONFIGUREARGS .=
" --with-extra-options=\'$ARGV[0]\'"; shift; next;}
@@ -693,12 +695,21 @@ $endtime = `date "+20%y-%m-%d %H:%M:%S"`;
if ( $VERBOSE ) { print "PREPARING LOGS TO BE SENT TO SERVER\n"; }
-$machine_data = "uname: ".`uname -a`.
- "hardware: ".`uname -m`.
- "os: ".`uname -sr`.
- "name: ".`uname -n`.
- "date: ".`date \"+20%y-%m-%d\"`.
- "time: ".`date +\"%H:%M:%S\"`;
+if ( ! $NOUNAME ) {
+ $machine_data = "uname: ".`uname -a`.
+ "hardware: ".`uname -m`.
+ "os: ".`uname -sr`.
+ "name: ".`uname -n`.
+ "date: ".`date \"+20%y-%m-%d\"`.
+ "time: ".`date +\"%H:%M:%S\"`;
+} else {
+ $machine_data = "uname: (excluded)\n".
+ "hardware: ".`uname -m`.
+ "os: ".`uname -sr`.
+ "name: $nickname\n".
+ "date: ".`date \"+20%y-%m-%d\"`.
+ "time: ".`date +\"%H:%M:%S\"`;
+}
# Get gcc version.
my $gcc_version_long = "";
diff --git a/utils/TableGen/ARMDecoderEmitter.cpp b/utils/TableGen/ARMDecoderEmitter.cpp
new file mode 100644
index 0000000..c879a54
--- /dev/null
+++ b/utils/TableGen/ARMDecoderEmitter.cpp
@@ -0,0 +1,1870 @@
+//===------------ ARMDecoderEmitter.cpp - Decoder Generator ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the ARM Disassembler.
+// It contains the tablegen backend that emits the decoder functions for ARM and
+// Thumb. The disassembler core includes the auto-generated file, invokes the
+// decoder functions, and builds up the MCInst based on the decoded Opcode.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "arm-decoder-emitter"
+
+#include "ARMDecoderEmitter.h"
+#include "CodeGenTarget.h"
+#include "Record.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <vector>
+#include <map>
+#include <string>
+
+using namespace llvm;
+
+/////////////////////////////////////////////////////
+// //
+// Enums and Utilities for ARM Instruction Format //
+// //
+/////////////////////////////////////////////////////
+
+#define ARM_FORMATS \
+ ENTRY(ARM_FORMAT_PSEUDO, 0) \
+ ENTRY(ARM_FORMAT_MULFRM, 1) \
+ ENTRY(ARM_FORMAT_BRFRM, 2) \
+ ENTRY(ARM_FORMAT_BRMISCFRM, 3) \
+ ENTRY(ARM_FORMAT_DPFRM, 4) \
+ ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \
+ ENTRY(ARM_FORMAT_LDFRM, 6) \
+ ENTRY(ARM_FORMAT_STFRM, 7) \
+ ENTRY(ARM_FORMAT_LDMISCFRM, 8) \
+ ENTRY(ARM_FORMAT_STMISCFRM, 9) \
+ ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \
+ ENTRY(ARM_FORMAT_LDSTEXFRM, 11) \
+ ENTRY(ARM_FORMAT_ARITHMISCFRM, 12) \
+ ENTRY(ARM_FORMAT_EXTFRM, 13) \
+ ENTRY(ARM_FORMAT_VFPUNARYFRM, 14) \
+ ENTRY(ARM_FORMAT_VFPBINARYFRM, 15) \
+ ENTRY(ARM_FORMAT_VFPCONV1FRM, 16) \
+ ENTRY(ARM_FORMAT_VFPCONV2FRM, 17) \
+ ENTRY(ARM_FORMAT_VFPCONV3FRM, 18) \
+ ENTRY(ARM_FORMAT_VFPCONV4FRM, 19) \
+ ENTRY(ARM_FORMAT_VFPCONV5FRM, 20) \
+ ENTRY(ARM_FORMAT_VFPLDSTFRM, 21) \
+ ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 22) \
+ ENTRY(ARM_FORMAT_VFPMISCFRM, 23) \
+ ENTRY(ARM_FORMAT_THUMBFRM, 24) \
+ ENTRY(ARM_FORMAT_NEONFRM, 25) \
+ ENTRY(ARM_FORMAT_NEONGETLNFRM, 26) \
+ ENTRY(ARM_FORMAT_NEONSETLNFRM, 27) \
+ ENTRY(ARM_FORMAT_NEONDUPFRM, 28) \
+ ENTRY(ARM_FORMAT_MISCFRM, 29) \
+ ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) \
+ ENTRY(ARM_FORMAT_NLdSt, 31) \
+ ENTRY(ARM_FORMAT_N1RegModImm, 32) \
+ ENTRY(ARM_FORMAT_N2Reg, 33) \
+ ENTRY(ARM_FORMAT_NVCVT, 34) \
+ ENTRY(ARM_FORMAT_NVecDupLn, 35) \
+ ENTRY(ARM_FORMAT_N2RegVecShL, 36) \
+ ENTRY(ARM_FORMAT_N2RegVecShR, 37) \
+ ENTRY(ARM_FORMAT_N3Reg, 38) \
+ ENTRY(ARM_FORMAT_N3RegVecSh, 39) \
+ ENTRY(ARM_FORMAT_NVecExtract, 40) \
+ ENTRY(ARM_FORMAT_NVecMulScalar, 41) \
+ ENTRY(ARM_FORMAT_NVTBL, 42)
+
+// ARM instruction format specifies the encoding used by the instruction.
+#define ENTRY(n, v) n = v,
+typedef enum {
+ ARM_FORMATS
+ ARM_FORMAT_NA
+} ARMFormat;
+#undef ENTRY
+
+// Converts enum to const char*.
+static const char *stringForARMFormat(ARMFormat form) {
+#define ENTRY(n, v) case n: return #n;
+ switch(form) {
+ ARM_FORMATS
+ case ARM_FORMAT_NA:
+ default:
+ return "";
+ }
+#undef ENTRY
+}
+
+enum {
+ IndexModeNone = 0,
+ IndexModePre = 1,
+ IndexModePost = 2,
+ IndexModeUpd = 3
+};
+
+/////////////////////////
+// //
+// Utility functions //
+// //
+/////////////////////////
+
+/// byteFromBitsInit - Return the byte value from a BitsInit.
+/// Called from getByteField().
+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;
+}
+
+/// sameStringExceptSuffix - Return true if the two strings differ only in RHS's
+/// suffix. ("VST4d8", "VST4d8_UPD", "_UPD") as input returns true.
+static
+bool sameStringExceptSuffix(const StringRef LHS, const StringRef RHS,
+ const StringRef Suffix) {
+
+ if (RHS.startswith(LHS) && RHS.endswith(Suffix))
+ return RHS.size() == LHS.size() + Suffix.size();
+
+ return false;
+}
+
+/// thumbInstruction - Determine whether we have a Thumb instruction.
+/// See also ARMInstrFormats.td.
+static bool thumbInstruction(uint8_t Form) {
+ return Form == ARM_FORMAT_THUMBFRM;
+}
+
+// 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
+} bit_value_t;
+
+static bool ValueSet(bit_value_t V) {
+ return (V == BIT_TRUE || V == BIT_FALSE);
+}
+static bool ValueNotSet(bit_value_t V) {
+ return (V == BIT_UNSET);
+}
+static int Value(bit_value_t V) {
+ return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1);
+}
+static bit_value_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;
+}
+// Prints the bit value for each position.
+static void dumpBits(raw_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");
+ }
+ }
+}
+
+// Enums for the available target names.
+typedef enum {
+ TARGET_ARM = 0,
+ TARGET_THUMB
+} TARGET_NAME_t;
+
+// FIXME: Possibly auto-detected?
+#define BIT_WIDTH 32
+
+// Forward declaration.
+class FilterChooser;
+
+// Representation of the instruction to work on.
+typedef bit_value_t insn_t[BIT_WIDTH];
+
+/// Filter - Filter works with FilterChooser to produce the decoding tree for
+/// the ISA.
+///
+/// It is useful to think of a Filter as governing the switch stmts of the
+/// decoding tree in a certain level. Each case stmt delegates to an inferior
+/// FilterChooser to decide what further decoding logic to employ, or in another
+/// words, what other remaining bits to look at. The FilterChooser eventually
+/// chooses a best Filter to do its job.
+///
+/// This recursive scheme ends when the number of Opcodes assigned to the
+/// FilterChooser becomes 1 or if there is a conflict. A conflict happens when
+/// the Filter/FilterChooser combo does not know how to distinguish among the
+/// Opcodes assigned.
+///
+/// An example of a conflcit is
+///
+/// Conflict:
+/// 111101000.00........00010000....
+/// 111101000.00........0001........
+/// 1111010...00........0001........
+/// 1111010...00....................
+/// 1111010.........................
+/// 1111............................
+/// ................................
+/// VST4q8a 111101000_00________00010000____
+/// VST4q8b 111101000_00________00010000____
+///
+/// The Debug output shows the path that the decoding tree follows to reach the
+/// the conclusion that there is a conflict. VST4q8a is a vst4 to double-spaced
+/// even registers, while VST4q8b is a vst4 to double-spaced odd regsisters.
+///
+/// The encoding info in the .td files does not specify this meta information,
+/// which could have been used by the decoder to resolve the conflict. The
+/// decoder could try to decode the even/odd register numbering and assign to
+/// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a"
+/// version and return the Opcode since the two have the same Asm format string.
+class Filter {
+protected:
+ FilterChooser *Owner; // points to the FilterChooser who owns this filter
+ unsigned StartBit; // the starting bit position
+ unsigned NumBits; // number of bits to filter
+ bool Mixed; // a mixed region contains both 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> > FilteredInstructions;
+
+ // Set of uid's with non-constant segment values.
+ std::vector<unsigned> VariableInstructions;
+
+ // Map of well-known segment value to its delegate.
+ std::map<unsigned, FilterChooser*> FilterChooserMap;
+
+ // Number of instructions which fall under FilteredInstructions category.
+ unsigned NumFiltered;
+
+ // Keeps track of the last opcode in the filtered bucket.
+ unsigned LastOpcFiltered;
+
+ // Number of instructions which fall under VariableInstructions category.
+ unsigned NumVariable;
+
+public:
+ unsigned getNumFiltered() { return NumFiltered; }
+ unsigned getNumVariable() { return NumVariable; }
+ unsigned getSingletonOpc() {
+ assert(NumFiltered == 1);
+ return LastOpcFiltered;
+ }
+ // Return the filter chooser for the group of instructions without constant
+ // segment values.
+ FilterChooser &getVariableFC() {
+ assert(NumFiltered == 1);
+ assert(FilterChooserMap.size() == 1);
+ return *(FilterChooserMap.find((unsigned)-1)->second);
+ }
+
+ Filter(const Filter &f);
+ Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, bool mixed);
+
+ ~Filter();
+
+ // Divides the decoding task into sub tasks and delegates them to the
+ // inferior FilterChooser's.
+ //
+ // A special case arises when there's only one entry in the filtered
+ // instructions. In order to unambiguously decode the singleton, we need to
+ // match the remaining undecoded encoding bits against the singleton.
+ void recurse();
+
+ // Emit code to decode instructions given a segment or segments of bits.
+ void emit(raw_ostream &o, unsigned &Indentation);
+
+ // Returns the number of fanout produced by the filter. More fanout implies
+ // the filter distinguishes more categories of instructions.
+ unsigned usefulness() const;
+}; // End of class Filter
+
+// These are states of our finite state machines used in FilterChooser's
+// filterProcessor() which produces the filter candidates to use.
+typedef enum {
+ ATTR_NONE,
+ ATTR_FILTERED,
+ ATTR_ALL_SET,
+ ATTR_ALL_UNSET,
+ ATTR_MIXED
+} bitAttr_t;
+
+/// FilterChooser - FilterChooser chooses the best filter among a set of Filters
+/// in order to perform the decoding of instructions at the current level.
+///
+/// Decoding proceeds from the top down. Based on the well-known encoding bits
+/// of instructions available, FilterChooser builds up the possible Filters that
+/// can further the task of decoding by distinguishing among the remaining
+/// candidate instructions.
+///
+/// Once a filter has been chosen, it is called upon to divide the decoding task
+/// into sub-tasks and delegates them to its inferior FilterChoosers for further
+/// processings.
+///
+/// It is useful to think of a Filter as governing the switch stmts of the
+/// decoding tree. And each case is delegated to an inferior FilterChooser to
+/// decide what further remaining bits to look at.
+class FilterChooser {
+ static TARGET_NAME_t TargetName;
+
+protected:
+ friend class Filter;
+
+ // Vector of codegen instructions to choose our filter.
+ const std::vector<const CodeGenInstruction*> &AllInstructions;
+
+ // Vector of uid's for this filter chooser to work on.
+ const std::vector<unsigned> Opcodes;
+
+ // Vector of candidate filters.
+ std::vector<Filter> Filters;
+
+ // Array of bit values passed down from our parent.
+ // Set to all BIT_UNFILTERED's for Parent == NULL.
+ bit_value_t FilterBitValues[BIT_WIDTH];
+
+ // Links to the FilterChooser above us in the decoding tree.
+ FilterChooser *Parent;
+
+ // Index of the best filter from Filters.
+ int BestIndex;
+
+public:
+ static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; }
+
+ FilterChooser(const FilterChooser &FC) :
+ AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes),
+ Filters(FC.Filters), Parent(FC.Parent), BestIndex(FC.BestIndex) {
+ memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues));
+ }
+
+ FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ const std::vector<unsigned> &IDs) :
+ AllInstructions(Insts), Opcodes(IDs), Filters(), Parent(NULL),
+ BestIndex(-1) {
+ for (unsigned i = 0; i < BIT_WIDTH; ++i)
+ FilterBitValues[i] = BIT_UNFILTERED;
+
+ doFilter();
+ }
+
+ FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ const std::vector<unsigned> &IDs,
+ bit_value_t (&ParentFilterBitValues)[BIT_WIDTH],
+ FilterChooser &parent) :
+ AllInstructions(Insts), Opcodes(IDs), Filters(), Parent(&parent),
+ BestIndex(-1) {
+ for (unsigned i = 0; i < BIT_WIDTH; ++i)
+ FilterBitValues[i] = ParentFilterBitValues[i];
+
+ doFilter();
+ }
+
+ // The top level filter chooser has NULL as its parent.
+ bool isTopLevel() { return Parent == NULL; }
+
+ // This provides an opportunity for target specific code emission.
+ void emitTopHook(raw_ostream &o);
+
+ // Emit the top level typedef and decodeInstruction() function.
+ void emitTop(raw_ostream &o, unsigned &Indentation);
+
+ // This provides an opportunity for target specific code emission after
+ // emitTop().
+ void emitBot(raw_ostream &o, unsigned &Indentation);
+
+protected:
+ // Populates the insn given the uid.
+ void insnWithID(insn_t &Insn, unsigned Opcode) const {
+ BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst");
+
+ for (unsigned i = 0; i < BIT_WIDTH; ++i)
+ Insn[i] = bitFromBits(Bits, i);
+
+ // Set Inst{21} to 1 (wback) when IndexModeBits == IndexModeUpd.
+ if (getByteField(*AllInstructions[Opcode]->TheDef, "IndexModeBits")
+ == IndexModeUpd)
+ Insn[21] = BIT_TRUE;
+ }
+
+ // Returns the record name.
+ const std::string &nameWithID(unsigned Opcode) const {
+ return AllInstructions[Opcode]->TheDef->getName();
+ }
+
+ // Populates the field of the insn given the start position and the number of
+ // consecutive bits to scan for.
+ //
+ // Returns false if there exists any uninitialized bit value in the range.
+ // Returns true, otherwise.
+ bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit,
+ unsigned NumBits) const;
+
+ /// dumpFilterArray - dumpFilterArray prints out debugging info for the given
+ /// filter array as a series of chars.
+ void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[BIT_WIDTH]);
+
+ /// dumpStack - dumpStack traverses the filter chooser chain and calls
+ /// dumpFilterArray on each filter chooser up to the top level one.
+ void dumpStack(raw_ostream &o, const char *prefix);
+
+ Filter &bestFilter() {
+ assert(BestIndex != -1 && "BestIndex not set");
+ return Filters[BestIndex];
+ }
+
+ // Called from Filter::recurse() when singleton exists. For debug purpose.
+ void SingletonExists(unsigned Opc);
+
+ bool PositionFiltered(unsigned i) {
+ return ValueSet(FilterBitValues[i]);
+ }
+
+ // Calculates the island(s) needed to decode the instruction.
+ // This returns a lit of undecoded bits of an instructions, for example,
+ // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be
+ // decoded bits in order to verify that the instruction matches the Opcode.
+ unsigned getIslands(std::vector<unsigned> &StartBits,
+ std::vector<unsigned> &EndBits, std::vector<uint64_t> &FieldVals,
+ insn_t &Insn);
+
+ // The purpose of this function is for the API client to detect possible
+ // Load/Store Coprocessor instructions. If the coprocessor number is of
+ // the instruction is either 10 or 11, the decoder should not report the
+ // instruction as LDC/LDC2/STC/STC2, but should match against Advanced SIMD or
+ // VFP instructions.
+ bool LdStCopEncoding1(unsigned Opc) {
+ const std::string &Name = nameWithID(Opc);
+ if (Name == "LDC_OFFSET" || Name == "LDC_OPTION" ||
+ Name == "LDC_POST" || Name == "LDC_PRE" ||
+ Name == "LDCL_OFFSET" || Name == "LDCL_OPTION" ||
+ Name == "LDCL_POST" || Name == "LDCL_PRE" ||
+ Name == "STC_OFFSET" || Name == "STC_OPTION" ||
+ Name == "STC_POST" || Name == "STC_PRE" ||
+ Name == "STCL_OFFSET" || Name == "STCL_OPTION" ||
+ Name == "STCL_POST" || Name == "STCL_PRE")
+ return true;
+ else
+ return false;
+ }
+
+ // Emits code to decode the singleton. Return true if we have matched all the
+ // well-known bits.
+ bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,unsigned Opc);
+
+ // Emits code to decode the singleton, and then to decode the rest.
+ void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,Filter &Best);
+
+ // Assign a single filter and run with it.
+ void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit,
+ bool mixed);
+
+ // reportRegion is a helper function for filterProcessor to mark a region as
+ // eligible for use as a filter region.
+ void reportRegion(bitAttr_t RA, unsigned StartBit, unsigned BitIndex,
+ bool AllowMixed);
+
+ // FilterProcessor scans the well-known encoding bits of the instructions and
+ // builds up a list of candidate filters. It chooses the best filter and
+ // recursively descends down the decoding tree.
+ bool filterProcessor(bool AllowMixed, bool Greedy = true);
+
+ // 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();
+
+ // Emits code to decode our share of instructions. Returns true if the
+ // emitted code causes a return, which occurs if we know how to decode
+ // the instruction at this level or the instruction is not decodeable.
+ bool emit(raw_ostream &o, unsigned &Indentation);
+};
+
+///////////////////////////
+// //
+// Filter Implmenetation //
+// //
+///////////////////////////
+
+Filter::Filter(const Filter &f) :
+ Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed),
+ FilteredInstructions(f.FilteredInstructions),
+ VariableInstructions(f.VariableInstructions),
+ FilterChooserMap(f.FilterChooserMap), NumFiltered(f.NumFiltered),
+ LastOpcFiltered(f.LastOpcFiltered), NumVariable(f.NumVariable) {
+}
+
+Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
+ bool mixed) : Owner(&owner), StartBit(startBit), NumBits(numBits),
+ Mixed(mixed) {
+ assert(StartBit + NumBits - 1 < BIT_WIDTH);
+
+ NumFiltered = 0;
+ LastOpcFiltered = 0;
+ NumVariable = 0;
+
+ for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) {
+ insn_t Insn;
+
+ // Populates the insn given the uid.
+ Owner->insnWithID(Insn, Owner->Opcodes[i]);
+
+ uint64_t Field;
+ // Scans the segment for possibly well-specified encoding bits.
+ bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits);
+
+ if (ok) {
+ // The encoding bits are well-known. Lets add the uid of the
+ // instruction into the bucket keyed off the constant field value.
+ LastOpcFiltered = Owner->Opcodes[i];
+ FilteredInstructions[Field].push_back(LastOpcFiltered);
+ ++NumFiltered;
+ } else {
+ // Some of the encoding bit(s) are unspecfied. This contributes to
+ // one additional member of "Variable" instructions.
+ VariableInstructions.push_back(Owner->Opcodes[i]);
+ ++NumVariable;
+ }
+ }
+
+ assert((FilteredInstructions.size() + VariableInstructions.size() > 0)
+ && "Filter returns no instruction categories");
+}
+
+Filter::~Filter() {
+ std::map<unsigned, FilterChooser*>::iterator filterIterator;
+ for (filterIterator = FilterChooserMap.begin();
+ filterIterator != FilterChooserMap.end();
+ filterIterator++) {
+ delete filterIterator->second;
+ }
+}
+
+// Divides the decoding task into sub tasks and delegates them to the
+// inferior FilterChooser's.
+//
+// A special case arises when there's only one entry in the filtered
+// instructions. In order to unambiguously decode the singleton, we need to
+// match the remaining undecoded encoding bits against the singleton.
+void Filter::recurse() {
+ std::map<uint64_t, std::vector<unsigned> >::const_iterator mapIterator;
+
+ bit_value_t BitValueArray[BIT_WIDTH];
+ // Starts by inheriting our parent filter chooser's filter bit values.
+ memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray));
+
+ unsigned bitIndex;
+
+ if (VariableInstructions.size()) {
+ // Conservatively marks each segment position as BIT_UNSET.
+ for (bitIndex = 0; bitIndex < NumBits; bitIndex++)
+ BitValueArray[StartBit + bitIndex] = BIT_UNSET;
+
+ // Delegates to an inferior filter chooser for futher processing on this
+ // group of instructions whose segment values are variable.
+ FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ (unsigned)-1,
+ new FilterChooser(Owner->AllInstructions,
+ VariableInstructions,
+ BitValueArray,
+ *Owner)
+ ));
+ }
+
+ // No need to recurse for a singleton filtered instruction.
+ // See also Filter::emit().
+ if (getNumFiltered() == 1) {
+ //Owner->SingletonExists(LastOpcFiltered);
+ assert(FilterChooserMap.size() == 1);
+ return;
+ }
+
+ // Otherwise, create sub choosers.
+ for (mapIterator = FilteredInstructions.begin();
+ mapIterator != FilteredInstructions.end();
+ mapIterator++) {
+
+ // Marks all the segment positions with either BIT_TRUE or BIT_FALSE.
+ for (bitIndex = 0; bitIndex < NumBits; bitIndex++) {
+ if (mapIterator->first & (1ULL << bitIndex))
+ BitValueArray[StartBit + bitIndex] = BIT_TRUE;
+ else
+ BitValueArray[StartBit + bitIndex] = BIT_FALSE;
+ }
+
+ // Delegates to an inferior filter chooser for futher processing on this
+ // category of instructions.
+ FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ mapIterator->first,
+ new FilterChooser(Owner->AllInstructions,
+ mapIterator->second,
+ BitValueArray,
+ *Owner)
+ ));
+ }
+}
+
+// Emit code to decode instructions given a segment or segments of bits.
+void Filter::emit(raw_ostream &o, unsigned &Indentation) {
+ o.indent(Indentation) << "// Check Inst{";
+
+ if (NumBits > 1)
+ o << (StartBit + NumBits - 1) << '-';
+
+ o << StartBit << "} ...\n";
+
+ o.indent(Indentation) << "switch (fieldFromInstruction(insn, "
+ << StartBit << ", " << NumBits << ")) {\n";
+
+ std::map<unsigned, FilterChooser*>::iterator filterIterator;
+
+ bool DefaultCase = false;
+ for (filterIterator = FilterChooserMap.begin();
+ filterIterator != FilterChooserMap.end();
+ filterIterator++) {
+
+ // Field value -1 implies a non-empty set of variable instructions.
+ // See also recurse().
+ if (filterIterator->first == (unsigned)-1) {
+ DefaultCase = true;
+
+ o.indent(Indentation) << "default:\n";
+ o.indent(Indentation) << " break; // fallthrough\n";
+
+ // Closing curly brace for the switch statement.
+ // This is unconventional because we want the default processing to be
+ // performed for the fallthrough cases as well, i.e., when the "cases"
+ // did not prove a decoded instruction.
+ o.indent(Indentation) << "}\n";
+
+ } else
+ o.indent(Indentation) << "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.
+ // The case may fallthrough, which happens if the remaining well-known
+ // encoding bits do not match exactly.
+ if (!DefaultCase) { ++Indentation; ++Indentation; }
+
+ bool finished = filterIterator->second->emit(o, Indentation);
+ // For top level default case, there's no need for a break statement.
+ if (Owner->isTopLevel() && DefaultCase)
+ break;
+ if (!finished)
+ o.indent(Indentation) << "break;\n";
+
+ if (!DefaultCase) { --Indentation; --Indentation; }
+ }
+
+ // If there is no default case, we still need to supply a closing brace.
+ if (!DefaultCase) {
+ // Closing curly brace for the switch statement.
+ o.indent(Indentation) << "}\n";
+ }
+}
+
+// Returns the number of fanout produced by the filter. More fanout implies
+// the filter distinguishes more categories of instructions.
+unsigned Filter::usefulness() const {
+ if (VariableInstructions.size())
+ return FilteredInstructions.size();
+ else
+ return FilteredInstructions.size() + 1;
+}
+
+//////////////////////////////////
+// //
+// Filterchooser Implementation //
+// //
+//////////////////////////////////
+
+// Define the symbol here.
+TARGET_NAME_t FilterChooser::TargetName;
+
+// This provides an opportunity for target specific code emission.
+void FilterChooser::emitTopHook(raw_ostream &o) {
+ if (TargetName == TARGET_ARM) {
+ // Emit code that references the ARMFormat data type.
+ o << "static const ARMFormat ARMFormats[] = {\n";
+ for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) {
+ const Record &Def = *(AllInstructions[i]->TheDef);
+ const std::string &Name = Def.getName();
+ if (Def.isSubClassOf("InstARM") || Def.isSubClassOf("InstThumb"))
+ o.indent(2) <<
+ stringForARMFormat((ARMFormat)getByteField(Def, "Form"));
+ else
+ o << " ARM_FORMAT_NA";
+
+ o << ",\t// Inst #" << i << " = " << Name << '\n';
+ }
+ o << " ARM_FORMAT_NA\t// Unreachable.\n";
+ o << "};\n\n";
+ }
+}
+
+// Emit the top level typedef and decodeInstruction() function.
+void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) {
+ // Run the target specific emit hook.
+ emitTopHook(o);
+
+ switch (BIT_WIDTH) {
+ case 8:
+ o.indent(Indentation) << "typedef uint8_t field_t;\n";
+ break;
+ case 16:
+ o.indent(Indentation) << "typedef uint16_t field_t;\n";
+ break;
+ case 32:
+ o.indent(Indentation) << "typedef uint32_t field_t;\n";
+ break;
+ case 64:
+ o.indent(Indentation) << "typedef uint64_t field_t;\n";
+ break;
+ default:
+ assert(0 && "Unexpected instruction size!");
+ }
+
+ o << '\n';
+
+ o.indent(Indentation) << "static field_t " <<
+ "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n";
+
+ o.indent(Indentation) << "{\n";
+
+ ++Indentation; ++Indentation;
+ o.indent(Indentation) << "assert(startBit + numBits <= " << BIT_WIDTH
+ << " && \"Instruction field out of bounds!\");\n";
+ o << '\n';
+ o.indent(Indentation) << "field_t fieldMask;\n";
+ o << '\n';
+ o.indent(Indentation) << "if (numBits == " << BIT_WIDTH << ")\n";
+
+ ++Indentation; ++Indentation;
+ o.indent(Indentation) << "fieldMask = (field_t)-1;\n";
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "else\n";
+
+ ++Indentation; ++Indentation;
+ o.indent(Indentation) << "fieldMask = ((1 << numBits) - 1) << startBit;\n";
+ --Indentation; --Indentation;
+
+ o << '\n';
+ o.indent(Indentation) << "return (insn & fieldMask) >> startBit;\n";
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "}\n";
+
+ o << '\n';
+
+ o.indent(Indentation) << "static uint16_t decodeInstruction(field_t insn) {\n";
+
+ ++Indentation; ++Indentation;
+ // Emits code to decode the instructions.
+ emit(o, Indentation);
+
+ o << '\n';
+ o.indent(Indentation) << "return 0;\n";
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "}\n";
+
+ o << '\n';
+}
+
+// This provides an opportunity for target specific code emission after
+// emitTop().
+void FilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) {
+ if (TargetName != TARGET_THUMB) return;
+
+ // Emit code that decodes the Thumb ISA.
+ o.indent(Indentation)
+ << "static uint16_t decodeThumbInstruction(field_t insn) {\n";
+
+ ++Indentation; ++Indentation;
+
+ // Emits code to decode the instructions.
+ emit(o, Indentation);
+
+ o << '\n';
+ o.indent(Indentation) << "return 0;\n";
+
+ --Indentation; --Indentation;
+
+ o.indent(Indentation) << "}\n";
+}
+
+// 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.
+bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
+ unsigned StartBit, unsigned NumBits) const {
+ Field = 0;
+
+ for (unsigned i = 0; i < NumBits; ++i) {
+ if (Insn[StartBit + i] == BIT_UNSET)
+ return false;
+
+ if (Insn[StartBit + i] == BIT_TRUE)
+ Field = Field | (1ULL << i);
+ }
+
+ return true;
+}
+
+/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
+/// filter array as a series of chars.
+void FilterChooser::dumpFilterArray(raw_ostream &o,
+ bit_value_t (&filter)[BIT_WIDTH]) {
+ unsigned bitIndex;
+
+ for (bitIndex = BIT_WIDTH; 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;
+ }
+ }
+}
+
+/// dumpStack - dumpStack traverses the filter chooser chain and calls
+/// dumpFilterArray on each filter chooser up to the top level one.
+void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
+ FilterChooser *current = this;
+
+ while (current) {
+ o << prefix;
+ dumpFilterArray(o, current->FilterBitValues);
+ o << '\n';
+ current = current->Parent;
+ }
+}
+
+// Called from Filter::recurse() when singleton exists. For debug purpose.
+void FilterChooser::SingletonExists(unsigned Opc) {
+ insn_t Insn0;
+ insnWithID(Insn0, Opc);
+
+ errs() << "Singleton exists: " << nameWithID(Opc)
+ << " with its decoding dominating ";
+ for (unsigned i = 0; i < Opcodes.size(); ++i) {
+ if (Opcodes[i] == Opc) continue;
+ errs() << nameWithID(Opcodes[i]) << ' ';
+ }
+ errs() << '\n';
+
+ dumpStack(errs(), "\t\t");
+ for (unsigned i = 0; i < Opcodes.size(); i++) {
+ const std::string &Name = nameWithID(Opcodes[i]);
+
+ errs() << '\t' << Name << " ";
+ dumpBits(errs(),
+ getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
+ errs() << '\n';
+ }
+}
+
+// Calculates the island(s) needed to decode the instruction.
+// This returns a list of undecoded bits of an instructions, for example,
+// Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be
+// decoded bits in order to verify that the instruction matches the Opcode.
+unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
+ std::vector<unsigned> &EndBits, std::vector<uint64_t> &FieldVals,
+ insn_t &Insn) {
+ unsigned Num, BitNo;
+ Num = BitNo = 0;
+
+ uint64_t FieldVal = 0;
+
+ // 0: Init
+ // 1: Water (the bit value does not affect decoding)
+ // 2: Island (well-known bit value needed for decoding)
+ int State = 0;
+ int Val = -1;
+
+ for (unsigned i = 0; i < BIT_WIDTH; ++i) {
+ Val = Value(Insn[i]);
+ bool Filtered = PositionFiltered(i);
+ switch (State) {
+ default:
+ assert(0 && "Unreachable code!");
+ break;
+ case 0:
+ case 1:
+ if (Filtered || Val == -1)
+ State = 1; // Still in Water
+ else {
+ State = 2; // Into the Island
+ BitNo = 0;
+ StartBits.push_back(i);
+ FieldVal = Val;
+ }
+ break;
+ case 2:
+ if (Filtered || Val == -1) {
+ State = 1; // Into the Water
+ EndBits.push_back(i - 1);
+ FieldVals.push_back(FieldVal);
+ ++Num;
+ } else {
+ State = 2; // Still in Island
+ ++BitNo;
+ FieldVal = FieldVal | Val << BitNo;
+ }
+ break;
+ }
+ }
+ // If we are still in Island after the loop, do some housekeeping.
+ if (State == 2) {
+ EndBits.push_back(BIT_WIDTH - 1);
+ FieldVals.push_back(FieldVal);
+ ++Num;
+ }
+
+ assert(StartBits.size() == Num && EndBits.size() == Num &&
+ FieldVals.size() == Num);
+ return Num;
+}
+
+// Emits code to decode the singleton. Return true if we have matched all the
+// well-known bits.
+bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ unsigned Opc) {
+ std::vector<unsigned> StartBits;
+ std::vector<unsigned> EndBits;
+ std::vector<uint64_t> FieldVals;
+ insn_t Insn;
+ insnWithID(Insn, Opc);
+
+ // This provides a good opportunity to check for possible Ld/St Coprocessor
+ // Opcode and escapes if the coproc # is either 10 or 11. It is a NEON/VFP
+ // instruction is disguise.
+ if (TargetName == TARGET_ARM && LdStCopEncoding1(Opc)) {
+ o.indent(Indentation);
+ // A8.6.51 & A8.6.188
+ // If coproc = 0b101?, i.e, slice(insn, 11, 8) = 10 or 11, escape.
+ o << "if (fieldFromInstruction(insn, 9, 3) == 5) break; // fallthrough\n";
+ }
+
+ // Look for islands of undecoded bits of the singleton.
+ getIslands(StartBits, EndBits, FieldVals, Insn);
+
+ unsigned Size = StartBits.size();
+ unsigned I, NumBits;
+
+ // If we have matched all the well-known bits, just issue a return.
+ if (Size == 0) {
+ o.indent(Indentation) << "return " << Opc << "; // " << nameWithID(Opc)
+ << '\n';
+ return true;
+ }
+
+ // Otherwise, there are more decodings to be done!
+
+ // Emit code to match the island(s) for the singleton.
+ o.indent(Indentation) << "// Check ";
+
+ for (I = Size; I != 0; --I) {
+ o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} ";
+ if (I > 1)
+ o << "&& ";
+ else
+ o << "for singleton decoding...\n";
+ }
+
+ o.indent(Indentation) << "if (";
+
+ for (I = Size; I != 0; --I) {
+ NumBits = EndBits[I-1] - StartBits[I-1] + 1;
+ o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits
+ << ") == " << FieldVals[I-1];
+ if (I > 1)
+ o << " && ";
+ else
+ o << ")\n";
+ }
+
+ o.indent(Indentation) << " return " << Opc << "; // " << nameWithID(Opc)
+ << '\n';
+
+ return false;
+}
+
+// Emits code to decode the singleton, and then to decode the rest.
+void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ Filter &Best) {
+
+ unsigned Opc = Best.getSingletonOpc();
+
+ emitSingletonDecoder(o, Indentation, Opc);
+
+ // Emit code for the rest.
+ o.indent(Indentation) << "else\n";
+
+ Indentation += 2;
+ Best.getVariableFC().emit(o, Indentation);
+ Indentation -= 2;
+}
+
+// Assign a single filter and run with it. Top level API client can initialize
+// with a single filter to start the filtering process.
+void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit,
+ unsigned numBit, bool mixed) {
+ Filters.clear();
+ Filter F(*this, startBit, numBit, true);
+ Filters.push_back(F);
+ BestIndex = 0; // Sole Filter instance to choose from.
+ bestFilter().recurse();
+}
+
+// reportRegion is a helper function for filterProcessor to mark a region as
+// eligible for use as a filter region.
+void FilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit,
+ unsigned BitIndex, bool AllowMixed) {
+ if (RA == ATTR_MIXED && AllowMixed)
+ Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, true));
+ else if (RA == ATTR_ALL_SET && !AllowMixed)
+ Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, false));
+}
+
+// FilterProcessor scans the well-known encoding bits of the instructions and
+// builds up a list of candidate filters. It chooses the best filter and
+// recursively descends down the decoding tree.
+bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
+ Filters.clear();
+ BestIndex = -1;
+ unsigned numInstructions = Opcodes.size();
+
+ assert(numInstructions && "Filter created with no instructions");
+
+ // No further filtering is necessary.
+ if (numInstructions == 1)
+ return true;
+
+ // Heuristics. See also doFilter()'s "Heuristics" comment when num of
+ // instructions is 3.
+ if (AllowMixed && !Greedy) {
+ assert(numInstructions == 3);
+
+ for (unsigned i = 0; i < Opcodes.size(); ++i) {
+ std::vector<unsigned> StartBits;
+ std::vector<unsigned> EndBits;
+ std::vector<uint64_t> FieldVals;
+ insn_t Insn;
+
+ insnWithID(Insn, Opcodes[i]);
+
+ // Look for islands of undecoded bits of any instruction.
+ if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) {
+ // Found an instruction with island(s). Now just assign a filter.
+ runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1,
+ true);
+ return true;
+ }
+ }
+ }
+
+ unsigned BitIndex, InsnIndex;
+
+ // We maintain BIT_WIDTH 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[BIT_WIDTH];
+
+ // 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 < BIT_WIDTH; ++BitIndex)
+ if (FilterBitValues[BitIndex] == BIT_TRUE ||
+ FilterBitValues[BitIndex] == BIT_FALSE)
+ bitAttrs[BitIndex] = ATTR_FILTERED;
+ else
+ bitAttrs[BitIndex] = ATTR_NONE;
+
+ for (InsnIndex = 0; InsnIndex < numInstructions; ++InsnIndex) {
+ insn_t insn;
+
+ insnWithID(insn, Opcodes[InsnIndex]);
+
+ for (BitIndex = 0; BitIndex < BIT_WIDTH; ++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 RA = ATTR_NONE;
+ unsigned StartBit = 0;
+
+ for (BitIndex = 0; BitIndex < BIT_WIDTH; BitIndex++) {
+ bitAttr_t bitAttr = bitAttrs[BitIndex];
+
+ assert(bitAttr != ATTR_NONE && "Bit without attributes");
+
+ switch (RA) {
+ case ATTR_NONE:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ break;
+ case ATTR_ALL_SET:
+ StartBit = BitIndex;
+ RA = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_UNSET:
+ break;
+ case ATTR_MIXED:
+ StartBit = BitIndex;
+ RA = ATTR_MIXED;
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_ALL_SET:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ RA = ATTR_NONE;
+ break;
+ case ATTR_ALL_SET:
+ break;
+ case ATTR_ALL_UNSET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ RA = ATTR_NONE;
+ break;
+ case ATTR_MIXED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ StartBit = BitIndex;
+ RA = ATTR_MIXED;
+ break;
+ default:
+ assert(0 && "Unexpected bitAttr!");
+ }
+ break;
+ case ATTR_MIXED:
+ switch (bitAttr) {
+ case ATTR_FILTERED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ StartBit = BitIndex;
+ RA = ATTR_NONE;
+ break;
+ case ATTR_ALL_SET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ StartBit = BitIndex;
+ RA = ATTR_ALL_SET;
+ break;
+ case ATTR_ALL_UNSET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ RA = 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 (RA) {
+ case ATTR_NONE:
+ break;
+ case ATTR_FILTERED:
+ break;
+ case ATTR_ALL_SET:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ break;
+ case ATTR_ALL_UNSET:
+ break;
+ case ATTR_MIXED:
+ reportRegion(RA, StartBit, BitIndex, AllowMixed);
+ break;
+ }
+
+ // We have finished with the filter processings. Now it's time to choose
+ // the best performing filter.
+ BestIndex = 0;
+ bool AllUseless = true;
+ unsigned BestScore = 0;
+
+ for (unsigned i = 0, e = Filters.size(); i != e; ++i) {
+ unsigned Usefulness = Filters[i].usefulness();
+
+ if (Usefulness)
+ AllUseless = false;
+
+ if (Usefulness > BestScore) {
+ BestIndex = i;
+ BestScore = Usefulness;
+ }
+ }
+
+ if (!AllUseless)
+ bestFilter().recurse();
+
+ return !AllUseless;
+} // end of FilterChooser::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 FilterChooser::doFilter() {
+ unsigned Num = Opcodes.size();
+ assert(Num && "FilterChooser created with no instructions");
+
+ // Heuristics: Use Inst{31-28} as the top level filter for ARM ISA.
+ if (TargetName == TARGET_ARM && Parent == NULL) {
+ runSingleFilter(*this, 28, 4, false);
+ return;
+ }
+
+ // Try regions of consecutive known bit values first.
+ if (filterProcessor(false))
+ return;
+
+ // Then regions of mixed bits (both known and unitialized bit values allowed).
+ if (filterProcessor(true))
+ return;
+
+ // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where
+ // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a
+ // well-known encoding pattern. In such case, we backtrack and scan for the
+ // the very first consecutive ATTR_ALL_SET region and assign a filter to it.
+ if (Num == 3 && filterProcessor(true, false))
+ return;
+
+ // If we come to here, the instruction decoding has failed.
+ // Set the BestIndex to -1 to indicate so.
+ BestIndex = -1;
+}
+
+// Emits code to decode our share of instructions. Returns true if the
+// emitted code causes a return, which occurs if we know how to decode
+// the instruction at this level or the instruction is not decodeable.
+bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
+ if (Opcodes.size() == 1)
+ // There is only one instruction in the set, which is great!
+ // Call emitSingletonDecoder() to see whether there are any remaining
+ // encodings bits.
+ return emitSingletonDecoder(o, Indentation, Opcodes[0]);
+
+ // Choose the best filter to do the decodings!
+ if (BestIndex != -1) {
+ Filter &Best = bestFilter();
+ if (Best.getNumFiltered() == 1)
+ emitSingletonDecoder(o, Indentation, Best);
+ else
+ bestFilter().emit(o, Indentation);
+ return false;
+ }
+
+ // If we reach here, there is a conflict in decoding. Let's resolve the known
+ // conflicts!
+ if ((TargetName == TARGET_ARM || TargetName == TARGET_THUMB) &&
+ Opcodes.size() == 2) {
+ // Resolve the known conflict sets:
+ //
+ // 1. source registers are identical => VMOVDneon; otherwise => VORRd
+ // 2. source registers are identical => VMOVQ; otherwise => VORRq
+ // 3. LDR, LDRcp => return LDR for now.
+ // FIXME: How can we distinguish between LDR and LDRcp? Do we need to?
+ // 4. tLDM, tLDM_UPD => Rn = Inst{10-8}, reglist = Inst{7-0},
+ // wback = registers<Rn> = 0
+ // NOTE: (tLDM, tLDM_UPD) resolution must come before Advanced SIMD
+ // addressing mode resolution!!!
+ // 5. VLD[234]LN*/VST[234]LN* vs. VLD[234]LN*_UPD/VST[234]LN*_UPD conflicts
+ // are resolved returning the non-UPD versions of the instructions if the
+ // Rm field, i.e., Inst{3-0} is 0b1111. This is specified in A7.7.1
+ // Advanced SIMD addressing mode.
+ const std::string &name1 = nameWithID(Opcodes[0]);
+ const std::string &name2 = nameWithID(Opcodes[1]);
+ if ((name1 == "VMOVDneon" && name2 == "VORRd") ||
+ (name1 == "VMOVQ" && name2 == "VORRq")) {
+ // Inserting the opening curly brace for this case block.
+ --Indentation; --Indentation;
+ o.indent(Indentation) << "{\n";
+ ++Indentation; ++Indentation;
+
+ o.indent(Indentation)
+ << "field_t N = fieldFromInstruction(insn, 7, 1), "
+ << "M = fieldFromInstruction(insn, 5, 1);\n";
+ o.indent(Indentation)
+ << "field_t Vn = fieldFromInstruction(insn, 16, 4), "
+ << "Vm = fieldFromInstruction(insn, 0, 4);\n";
+ o.indent(Indentation)
+ << "return (N == M && Vn == Vm) ? "
+ << Opcodes[0] << " /* " << name1 << " */ : "
+ << Opcodes[1] << " /* " << name2 << " */ ;\n";
+
+ // Inserting the closing curly brace for this case block.
+ --Indentation; --Indentation;
+ o.indent(Indentation) << "}\n";
+ ++Indentation; ++Indentation;
+
+ return true;
+ }
+ if (name1 == "LDR" && name2 == "LDRcp") {
+ o.indent(Indentation)
+ << "return " << Opcodes[0]
+ << "; // Returning LDR for {LDR, LDRcp}\n";
+ return true;
+ }
+ if (name1 == "tLDM" && name2 == "tLDM_UPD") {
+ // Inserting the opening curly brace for this case block.
+ --Indentation; --Indentation;
+ o.indent(Indentation) << "{\n";
+ ++Indentation; ++Indentation;
+
+ o.indent(Indentation)
+ << "unsigned Rn = fieldFromInstruction(insn, 8, 3), "
+ << "list = fieldFromInstruction(insn, 0, 8);\n";
+ o.indent(Indentation)
+ << "return ((list >> Rn) & 1) == 0 ? "
+ << Opcodes[1] << " /* " << name2 << " */ : "
+ << Opcodes[0] << " /* " << name1 << " */ ;\n";
+
+ // Inserting the closing curly brace for this case block.
+ --Indentation; --Indentation;
+ o.indent(Indentation) << "}\n";
+ ++Indentation; ++Indentation;
+
+ return true;
+ }
+ if (sameStringExceptSuffix(name1, name2, "_UPD")) {
+ o.indent(Indentation)
+ << "return fieldFromInstruction(insn, 0, 4) == 15 ? " << Opcodes[0]
+ << " /* " << name1 << " */ : " << Opcodes[1] << "/* " << name2
+ << " */ ; // Advanced SIMD addressing mode\n";
+ return true;
+ }
+
+ // Otherwise, it does not belong to the known conflict sets.
+ }
+
+ // We don't know how to decode these instructions! Return 0 and dump the
+ // conflict set!
+ o.indent(Indentation) << "return 0;" << " // Conflict set: ";
+ for (int i = 0, N = Opcodes.size(); i < N; ++i) {
+ o << nameWithID(Opcodes[i]);
+ if (i < (N - 1))
+ o << ", ";
+ else
+ o << '\n';
+ }
+
+ // Print out useful conflict information for postmortem analysis.
+ errs() << "Decoding Conflict:\n";
+
+ dumpStack(errs(), "\t\t");
+
+ for (unsigned i = 0; i < Opcodes.size(); i++) {
+ const std::string &Name = nameWithID(Opcodes[i]);
+
+ errs() << '\t' << Name << " ";
+ dumpBits(errs(),
+ getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
+ errs() << '\n';
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////
+// //
+// ARMDEBackend //
+// (Helper class for ARMDecoderEmitter) //
+// //
+////////////////////////////////////////////
+
+class ARMDecoderEmitter::ARMDEBackend {
+public:
+ ARMDEBackend(ARMDecoderEmitter &frontend) :
+ NumberedInstructions(),
+ Opcodes(),
+ Frontend(frontend),
+ Target(),
+ FC(NULL)
+ {
+ if (Target.getName() == "ARM")
+ TargetName = TARGET_ARM;
+ else {
+ errs() << "Target name " << Target.getName() << " not recognized\n";
+ assert(0 && "Unknown target");
+ }
+
+ // Populate the instructions for our TargetName.
+ populateInstructions();
+ }
+
+ ~ARMDEBackend() {
+ if (FC) {
+ delete FC;
+ FC = NULL;
+ }
+ }
+
+ void getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
+ &NumberedInstructions) {
+ // We must emit the PHI opcode first...
+ std::string Namespace = Target.getInstNamespace();
+ assert(!Namespace.empty() && "No instructions defined.");
+
+ NumberedInstructions = Target.getInstructionsByEnumValue();
+ }
+
+ bool populateInstruction(const CodeGenInstruction &CGI, TARGET_NAME_t TN);
+
+ void populateInstructions();
+
+ // Emits disassembler code for instruction decoding. This delegates to the
+ // FilterChooser instance to do the heavy lifting.
+ void emit(raw_ostream &o);
+
+protected:
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+ std::vector<unsigned> Opcodes;
+ // Special case for the ARM chip, which supports ARM and Thumb ISAs.
+ // Opcodes2 will be populated with the Thumb opcodes.
+ std::vector<unsigned> Opcodes2;
+ ARMDecoderEmitter &Frontend;
+ CodeGenTarget Target;
+ FilterChooser *FC;
+
+ TARGET_NAME_t TargetName;
+};
+
+bool ARMDecoderEmitter::ARMDEBackend::populateInstruction(
+ const CodeGenInstruction &CGI, TARGET_NAME_t TN) {
+ const Record &Def = *CGI.TheDef;
+ const StringRef Name = Def.getName();
+ uint8_t Form = getByteField(Def, "Form");
+
+ BitsInit &Bits = getBitsField(Def, "Inst");
+
+ // If all the bit positions are not specified; do not decode this instruction.
+ // We are bound to fail! For proper disassembly, the well-known encoding bits
+ // of the instruction must be fully specified.
+ //
+ // This also removes pseudo instructions from considerations of disassembly,
+ // which is a better design and less fragile than the name matchings.
+ if (Bits.allInComplete()) return false;
+
+ if (TN == TARGET_ARM) {
+ // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6?
+ if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") &&
+ Form == ARM_FORMAT_PSEUDO)
+ return false;
+ if (thumbInstruction(Form))
+ return false;
+ if (Name.find("CMPz") != std::string::npos /* ||
+ Name.find("CMNz") != std::string::npos */)
+ return false;
+
+ // Ignore pseudo instructions.
+ if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9")
+ return false;
+
+ // VLDMQ/VSTMQ can be hanlded with the more generic VLDMD/VSTMD.
+ if (Name == "VLDMQ" || Name == "VLDMQ_UPD" ||
+ Name == "VSTMQ" || Name == "VSTMQ_UPD")
+ return false;
+
+ //
+ // The following special cases are for conflict resolutions.
+ //
+
+ // NEON NLdStFrm conflict resolutions:
+ //
+ // 1. Ignore suffix "odd" and "odd_UPD", prefer the "even" register-
+ // numbered ones which have the same Asm format string.
+ // 2. Ignore VST2d64_UPD, which conflicts with VST1q64_UPD.
+ // 3. Ignore VLD2d64_UPD, which conflicts with VLD1q64_UPD.
+ // 4. Ignore VLD1q[_UPD], which conflicts with VLD1q64[_UPD].
+ // 5. Ignore VST1q[_UPD], which conflicts with VST1q64[_UPD].
+ if (Name.endswith("odd") || Name.endswith("odd_UPD") ||
+ Name == "VST2d64_UPD" || Name == "VLD2d64_UPD" ||
+ Name == "VLD1q" || Name == "VLD1q_UPD" ||
+ Name == "VST1q" || Name == "VST1q_UPD")
+ return false;
+
+ // 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;
+
+ // Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc.
+ if (Name == "VMOVDcc" || Name == "VMOVScc" || Name == "VNEGDcc" ||
+ Name == "VNEGScc")
+ 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 == "BLX" || Name == "BX" ||
+ 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;
+
+ // A8-598: VEXT
+ // Vector Extract extracts elements from the bottom end of the second
+ // operand vector and the top end of the first, concatenates them and
+ // places the result in the destination vector. The elements of the
+ // vectors are treated as being 8-bit bitfields. There is no distinction
+ // between data types. The size of the operation can be specified in
+ // assembler as vext.size. If the value is 16, 32, or 64, the syntax is
+ // a pseudo-instruction for a VEXT instruction specifying the equivalent
+ // number of bytes.
+ //
+ // Variants VEXTd16, VEXTd32, VEXTd8, and VEXTdf are reduced to VEXTd8;
+ // variants VEXTq16, VEXTq32, VEXTq8, and VEXTqf are reduced to VEXTq8.
+ if (Name == "VEXTd16" || Name == "VEXTd32" || Name == "VEXTdf" ||
+ Name == "VEXTq16" || Name == "VEXTq32" || Name == "VEXTqf")
+ return false;
+
+ // Vector Reverse is similar to Vector Extract. There is no distinction
+ // between data types, other than size.
+ //
+ // VREV64df is equivalent to VREV64d32.
+ // VREV64qf is equivalent to VREV64q32.
+ if (Name == "VREV64df" || Name == "VREV64qf") return false;
+
+ // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d.
+ // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q.
+ // VLD1df is equivalent to VLD1d32.
+ // VLD1qf is equivalent to VLD1q32.
+ // VLD2d64 is equivalent to VLD1q64.
+ // VST1df is equivalent to VST1d32.
+ // VST1qf is equivalent to VST1q32.
+ // VST2d64 is equivalent to VST1q64.
+ if (Name == "VDUPLNfd" || Name == "VDUPfdf" ||
+ Name == "VDUPLNfq" || Name == "VDUPfqf" ||
+ Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" ||
+ Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64")
+ return false;
+ } else if (TN == TARGET_THUMB) {
+ if (!thumbInstruction(Form))
+ return false;
+
+ // On Darwin R9 is call-clobbered. Ignore the non-Darwin counterparts.
+ if (Name == "tBL" || Name == "tBLXi" || Name == "tBLXr")
+ return false;
+
+ // Ignore the TPsoft (TLS) instructions, which conflict with tBLr9.
+ if (Name == "tTPsoft" || Name == "t2TPsoft")
+ return false;
+
+ // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi.
+ if (Name == "tLEApcrel" || Name == "tLEApcrelJT")
+ return false;
+
+ // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing.
+ if (Name == "t2LEApcrel")
+ return false;
+
+ // Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr.
+ // Ignore t2SUBrSPs, prefer the t2SUB[S]r[r|s].
+ // Ignore t2ADDrSPs, prefer the t2ADD[S]r[r|s].
+ // Ignore t2ADDrSPi/t2SUBrSPi, which have more generic couterparts.
+ // Ignore t2ADDrSPi12/t2SUBrSPi12, which have more generic couterparts
+ if (Name == "tADDrSP" || Name == "tADDspr" || Name == "tPICADD" ||
+ Name == "t2SUBrSPs" || Name == "t2ADDrSPs" ||
+ Name == "t2ADDrSPi" || Name == "t2SUBrSPi" ||
+ Name == "t2ADDrSPi12" || Name == "t2SUBrSPi12")
+ return false;
+
+ // Ignore t2LDRDpci, prefer the generic t2LDRDi8, t2LDRD_PRE, t2LDRD_POST.
+ if (Name == "t2LDRDpci")
+ return false;
+
+ // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen.
+ if (Name == "t2TBB" || Name == "t2TBH")
+ return false;
+
+ // Resolve conflicts:
+ //
+ // tBfar conflicts with tBLr9
+ // tCMNz conflicts with tCMN (with assembly format strings being equal)
+ // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto)
+ // tMOVCCi conflicts with tMOVi8
+ // tMOVCCr conflicts with tMOVgpr2gpr
+ // tBR_JTr conflicts with tBRIND
+ // tSpill conflicts with tSTRspi
+ // tLDRcp conflicts with tLDRspi
+ // tRestore conflicts with tLDRspi
+ // t2LEApcrelJT conflicts with t2LEApcrel
+ if (Name == "tBfar" ||
+ /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" ||
+ Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" ||
+ Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" ||
+ Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" ||
+ Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" ||
+ Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" ||
+ Name == "t2LEApcrelJT")
+ return false;
+ }
+
+ // Dumps the instruction encoding format.
+ switch (TargetName) {
+ case TARGET_ARM:
+ case TARGET_THUMB:
+ DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form));
+ break;
+ }
+
+ DEBUG({
+ errs() << " ";
+
+ // Dumps the instruction encoding bits.
+ dumpBits(errs(), Bits);
+
+ errs() << '\n';
+
+ // Dumps the list of operand info.
+ for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
+ CodeGenInstruction::OperandInfo Info = CGI.OperandList[i];
+ const std::string &OperandName = Info.Name;
+ const Record &OperandDef = *Info.Rec;
+
+ errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n";
+ }
+ });
+
+ return true;
+}
+
+void ARMDecoderEmitter::ARMDEBackend::populateInstructions() {
+ getInstructionsByEnumValue(NumberedInstructions);
+
+ uint16_t numUIDs = NumberedInstructions.size();
+ uint16_t uid;
+
+ const char *instClass = NULL;
+
+ switch (TargetName) {
+ case TARGET_ARM:
+ instClass = "InstARM";
+ break;
+ default:
+ assert(0 && "Unreachable code!");
+ }
+
+ for (uid = 0; uid < numUIDs; uid++) {
+ // filter out intrinsics
+ if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass))
+ continue;
+
+ if (populateInstruction(*NumberedInstructions[uid], TargetName))
+ Opcodes.push_back(uid);
+ }
+
+ // Special handling for the ARM chip, which supports two modes of execution.
+ // This branch handles the Thumb opcodes.
+ if (TargetName == TARGET_ARM) {
+ for (uid = 0; uid < numUIDs; uid++) {
+ // filter out intrinsics
+ if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM")
+ && !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb"))
+ continue;
+
+ if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB))
+ Opcodes2.push_back(uid);
+ }
+ }
+}
+
+// Emits disassembler code for instruction decoding. This delegates to the
+// FilterChooser instance to do the heavy lifting.
+void ARMDecoderEmitter::ARMDEBackend::emit(raw_ostream &o) {
+ switch (TargetName) {
+ case TARGET_ARM:
+ Frontend.EmitSourceFileHeader("ARM/Thumb Decoders", o);
+ break;
+ default:
+ assert(0 && "Unreachable code!");
+ }
+
+ o << "#include \"llvm/System/DataTypes.h\"\n";
+ o << "#include <assert.h>\n";
+ o << '\n';
+ o << "namespace llvm {\n\n";
+
+ FilterChooser::setTargetName(TargetName);
+
+ switch (TargetName) {
+ case TARGET_ARM: {
+ // Emit common utility and ARM ISA decoder.
+ FC = new FilterChooser(NumberedInstructions, Opcodes);
+ // Reset indentation level.
+ unsigned Indentation = 0;
+ FC->emitTop(o, Indentation);
+ delete FC;
+
+ // Emit Thumb ISA decoder as well.
+ FilterChooser::setTargetName(TARGET_THUMB);
+ FC = new FilterChooser(NumberedInstructions, Opcodes2);
+ // Reset indentation level.
+ Indentation = 0;
+ FC->emitBot(o, Indentation);
+ break;
+ }
+ default:
+ assert(0 && "Unreachable code!");
+ }
+
+ o << "\n} // End llvm namespace \n";
+}
+
+/////////////////////////
+// Backend interface //
+/////////////////////////
+
+void ARMDecoderEmitter::initBackend()
+{
+ Backend = new ARMDEBackend(*this);
+}
+
+void ARMDecoderEmitter::run(raw_ostream &o)
+{
+ Backend->emit(o);
+}
+
+void ARMDecoderEmitter::shutdownBackend()
+{
+ delete Backend;
+ Backend = NULL;
+}
diff --git a/utils/TableGen/ARMDecoderEmitter.h b/utils/TableGen/ARMDecoderEmitter.h
new file mode 100644
index 0000000..107e085
--- /dev/null
+++ b/utils/TableGen/ARMDecoderEmitter.h
@@ -0,0 +1,50 @@
+//===------------ ARMDecoderEmitter.h - Decoder Generator -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the ARM Disassembler.
+// It contains the tablegen backend declaration ARMDecoderEmitter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ARMDECODEREMITTER_H
+#define ARMDECODEREMITTER_H
+
+#include "TableGenBackend.h"
+
+#include "llvm/System/DataTypes.h"
+
+namespace llvm {
+
+class ARMDecoderEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+public:
+ ARMDecoderEmitter(RecordKeeper &R) : Records(R) {
+ initBackend();
+ }
+
+ ~ARMDecoderEmitter() {
+ shutdownBackend();
+ }
+
+ // run - Output the code emitter
+ void run(raw_ostream &o);
+
+private:
+ // Helper class for ARMDecoderEmitter.
+ class ARMDEBackend;
+
+ ARMDEBackend *Backend;
+
+ void initBackend();
+ void shutdownBackend();
+};
+
+} // end llvm namespace
+
+#endif
diff --git a/utils/TableGen/Android.mk b/utils/TableGen/Android.mk
index e600305..8347d5e 100644
--- a/utils/TableGen/Android.mk
+++ b/utils/TableGen/Android.mk
@@ -5,6 +5,7 @@ LOCAL_SRC_FILES := \
AsmMatcherEmitter.cpp \
AsmWriterEmitter.cpp \
AsmWriterInst.cpp \
+ ARMDecoderEmitter.cpp \
CallingConvEmitter.cpp \
ClangDiagnosticsEmitter.cpp \
CodeEmitterGen.cpp \
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index b823e57..e5c068b 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -844,19 +844,20 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
// Parse the instructions; we need to do this first so that we can gather the
// singleton register classes.
std::set<std::string> SingletonRegisterNames;
- for (std::map<std::string, CodeGenInstruction>::const_iterator
- it = Target.getInstructions().begin(),
- ie = Target.getInstructions().end();
- it != ie; ++it) {
- const CodeGenInstruction &CGI = it->second;
+
+ const std::vector<const CodeGenInstruction*> &InstrList =
+ Target.getInstructionsByEnumValue();
+
+ for (unsigned i = 0, e = InstrList.size(); i != e; ++i) {
+ const CodeGenInstruction &CGI = *InstrList[i];
- if (!StringRef(it->first).startswith(MatchPrefix))
+ if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix))
continue;
- OwningPtr<InstructionInfo> II(new InstructionInfo);
+ OwningPtr<InstructionInfo> II(new InstructionInfo());
- II->InstrName = it->first;
- II->Instr = &it->second;
+ II->InstrName = CGI.TheDef->getName();
+ II->Instr = &CGI;
II->AsmString = FlattenVariants(CGI.AsmString, 0);
// Remove comments from the asm string.
@@ -869,7 +870,7 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) {
TokenizeAsmString(II->AsmString, II->Tokens);
// Ignore instructions which shouldn't be matched.
- if (!IsAssemblerInstruction(it->first, CGI, II->Tokens))
+ if (!IsAssemblerInstruction(CGI.TheDef->getName(), CGI, II->Tokens))
continue;
// Collect singleton registers, if used.
@@ -998,7 +999,7 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
// Start the unified conversion function.
- CvtOS << "static bool ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
+ CvtOS << "static void ConvertToMCInst(ConversionKind Kind, MCInst &Inst, "
<< "unsigned Opcode,\n"
<< " const SmallVectorImpl<MCParsedAsmOperand*"
<< "> &Operands) {\n";
@@ -1155,13 +1156,12 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
}
}
- CvtOS << " break;\n";
+ CvtOS << " return;\n";
}
// Finish the convert function.
CvtOS << " }\n";
- CvtOS << " return false;\n";
CvtOS << "}\n\n";
// Finish the enum, and drop the convert function after it.
@@ -1634,8 +1634,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " continue;\n";
}
OS << "\n";
- OS << " return ConvertToMCInst(it->ConvertFn, Inst, "
- << "it->Opcode, Operands);\n";
+ OS << " ConvertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
+
+ // Call the post-processing function, if used.
+ std::string InsnCleanupFn =
+ AsmParser->getValueAsString("AsmParserInstCleanup");
+ if (!InsnCleanupFn.empty())
+ OS << " " << InsnCleanupFn << "(Inst);\n";
+
+ OS << " return false;\n";
OS << " }\n\n";
OS << " return true;\n";
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index 3a38dd4..1e95467 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -248,22 +248,22 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
"/// printInstruction - This method is automatically generated by tablegen\n"
"/// from the instruction set description.\n"
"void " << Target.getName() << ClassName
- << "::printInstruction(const MachineInstr *MI) {\n";
+ << "::printInstruction(const MachineInstr *MI, raw_ostream &O) {\n";
std::vector<AsmWriterInst> Instructions;
for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
E = Target.inst_end(); I != E; ++I)
- if (!I->second.AsmString.empty() &&
- I->second.TheDef->getName() != "PHI")
+ if (!(*I)->AsmString.empty() &&
+ (*I)->TheDef->getName() != "PHI")
Instructions.push_back(
- AsmWriterInst(I->second,
+ AsmWriterInst(**I,
AsmWriter->getValueAsInt("Variant"),
AsmWriter->getValueAsInt("FirstOperandColumn"),
AsmWriter->getValueAsInt("OperandSpacing")));
// Get the instruction numbering.
- Target.getInstructionsByEnumValue(NumberedInstructions);
+ NumberedInstructions = Target.getInstructionsByEnumValue();
// Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not
// all machine instructions are necessarily being printed, so there may be
@@ -499,8 +499,8 @@ void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
- std::vector<const CodeGenInstruction*> NumberedInstructions;
- Target.getInstructionsByEnumValue(NumberedInstructions);
+ const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ Target.getInstructionsByEnumValue();
StringToOffsetTable StringTable;
O <<
diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp
index 508e453..b2228b0 100644
--- a/utils/TableGen/AsmWriterInst.cpp
+++ b/utils/TableGen/AsmWriterInst.cpp
@@ -38,6 +38,7 @@ std::string AsmWriterOperand::getCode() const {
std::string Result = Str + "(MI";
if (MIOpNo != ~0U)
Result += ", " + utostr(MIOpNo);
+ Result += ", O";
if (!MiModifier.empty())
Result += ", \"" + MiModifier + '"';
return Result + "); ";
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 881b50a..f68159a 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,4 +1,5 @@
add_executable(tblgen
+ ARMDecoderEmitter.cpp
AsmMatcherEmitter.cpp
AsmWriterEmitter.cpp
AsmWriterInst.cpp
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 6f1080e..27b1654 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -34,7 +34,7 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
<< ",\n";
OS << "#undef " << ComponentName << "START\n";
- OS << "#endif\n";
+ OS << "#endif\n\n";
}
const std::vector<Record*> &Diags =
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index f1857f5..1ede452 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -86,8 +86,8 @@ void CodeEmitterGen::run(raw_ostream &o) {
EmitSourceFileHeader("Machine Code Emitter", o);
std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::";
- std::vector<const CodeGenInstruction*> NumberedInstructions;
- Target.getInstructionsByEnumValue(NumberedInstructions);
+ const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ Target.getInstructionsByEnumValue();
// Emit function declaration
o << "unsigned " << Target.getName() << "CodeEmitter::"
@@ -95,7 +95,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
// Emit instruction base values
o << " static const unsigned InstBits[] = {\n";
- for (std::vector<const CodeGenInstruction*>::iterator
+ for (std::vector<const CodeGenInstruction*>::const_iterator
IN = NumberedInstructions.begin(),
EN = NumberedInstructions.end();
IN != EN; ++IN) {
@@ -156,7 +156,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
BitsInit *BI = R->getValueAsBitsInit("Inst");
const std::vector<RecordVal> &Vals = R->getValues();
- CodeGenInstruction &CGI = Target.getInstruction(InstName);
+ CodeGenInstruction &CGI = Target.getInstruction(R);
// Loop over all of the fields in the instruction, determining which are the
// operands to the instruction.
@@ -249,7 +249,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
<< " std::string msg;\n"
<< " raw_string_ostream Msg(msg);\n"
<< " Msg << \"Not supported instr: \" << MI;\n"
- << " llvm_report_error(Msg.str());\n"
+ << " report_fatal_error(Msg.str());\n"
<< " }\n"
<< " return Value;\n"
<< "}\n\n";
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index ce737bf..a0bccfc 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -15,90 +15,427 @@
#include "CodeGenDAGPatterns.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include <set>
#include <algorithm>
-#include <iostream>
using namespace llvm;
//===----------------------------------------------------------------------===//
-// Helpers for working with extended types.
+// EEVT::TypeSet Implementation
+//===----------------------------------------------------------------------===//
-/// FilterVTs - Filter a list of VT's according to a predicate.
-///
-template<typename T>
-static std::vector<MVT::SimpleValueType>
-FilterVTs(const std::vector<MVT::SimpleValueType> &InVTs, T Filter) {
- std::vector<MVT::SimpleValueType> Result;
- for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
- if (Filter(InVTs[i]))
- Result.push_back(InVTs[i]);
- return Result;
+static inline bool isInteger(MVT::SimpleValueType VT) {
+ return EVT(VT).isInteger();
+}
+static inline bool isFloatingPoint(MVT::SimpleValueType VT) {
+ return EVT(VT).isFloatingPoint();
+}
+static inline bool isVector(MVT::SimpleValueType VT) {
+ return EVT(VT).isVector();
+}
+static inline bool isScalar(MVT::SimpleValueType VT) {
+ return !EVT(VT).isVector();
}
-template<typename T>
-static std::vector<unsigned char>
-FilterEVTs(const std::vector<unsigned char> &InVTs, T Filter) {
- std::vector<unsigned char> Result;
- for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
- if (Filter((MVT::SimpleValueType)InVTs[i]))
- Result.push_back(InVTs[i]);
- return Result;
+EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) {
+ if (VT == MVT::iAny)
+ EnforceInteger(TP);
+ else if (VT == MVT::fAny)
+ EnforceFloatingPoint(TP);
+ else if (VT == MVT::vAny)
+ EnforceVector(TP);
+ else {
+ assert((VT < MVT::LAST_VALUETYPE || VT == MVT::iPTR ||
+ VT == MVT::iPTRAny) && "Not a concrete type!");
+ TypeVec.push_back(VT);
+ }
}
-static std::vector<unsigned char>
-ConvertVTs(const std::vector<MVT::SimpleValueType> &InVTs) {
- std::vector<unsigned char> Result;
- for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
- Result.push_back(InVTs[i]);
- return Result;
+
+EEVT::TypeSet::TypeSet(const std::vector<MVT::SimpleValueType> &VTList) {
+ assert(!VTList.empty() && "empty list?");
+ TypeVec.append(VTList.begin(), VTList.end());
+
+ if (!VTList.empty())
+ assert(VTList[0] != MVT::iAny && VTList[0] != MVT::vAny &&
+ VTList[0] != MVT::fAny);
+
+ // Verify no duplicates.
+ array_pod_sort(TypeVec.begin(), TypeVec.end());
+ assert(std::unique(TypeVec.begin(), TypeVec.end()) == TypeVec.end());
+}
+
+/// FillWithPossibleTypes - Set to all legal types and return true, only valid
+/// on completely unknown type sets.
+bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP,
+ bool (*Pred)(MVT::SimpleValueType),
+ const char *PredicateName) {
+ assert(isCompletelyUnknown());
+ const std::vector<MVT::SimpleValueType> &LegalTypes =
+ TP.getDAGPatterns().getTargetInfo().getLegalValueTypes();
+
+ for (unsigned i = 0, e = LegalTypes.size(); i != e; ++i)
+ if (Pred == 0 || Pred(LegalTypes[i]))
+ TypeVec.push_back(LegalTypes[i]);
+
+ // If we have nothing that matches the predicate, bail out.
+ if (TypeVec.empty())
+ TP.error("Type inference contradiction found, no " +
+ std::string(PredicateName) + " types found");
+ // No need to sort with one element.
+ if (TypeVec.size() == 1) return true;
+
+ // Remove duplicates.
+ array_pod_sort(TypeVec.begin(), TypeVec.end());
+ TypeVec.erase(std::unique(TypeVec.begin(), TypeVec.end()), TypeVec.end());
+
+ return true;
}
-static inline bool isInteger(MVT::SimpleValueType VT) {
- return EVT(VT).isInteger();
+/// hasIntegerTypes - Return true if this TypeSet contains iAny or an
+/// integer value type.
+bool EEVT::TypeSet::hasIntegerTypes() const {
+ for (unsigned i = 0, e = TypeVec.size(); i != e; ++i)
+ if (isInteger(TypeVec[i]))
+ return true;
+ return false;
+}
+
+/// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or
+/// a floating point value type.
+bool EEVT::TypeSet::hasFloatingPointTypes() const {
+ for (unsigned i = 0, e = TypeVec.size(); i != e; ++i)
+ if (isFloatingPoint(TypeVec[i]))
+ return true;
+ return false;
+}
+
+/// hasVectorTypes - Return true if this TypeSet contains a vAny or a vector
+/// value type.
+bool EEVT::TypeSet::hasVectorTypes() const {
+ for (unsigned i = 0, e = TypeVec.size(); i != e; ++i)
+ if (isVector(TypeVec[i]))
+ return true;
+ return false;
}
-static inline bool isFloatingPoint(MVT::SimpleValueType VT) {
- return EVT(VT).isFloatingPoint();
+
+std::string EEVT::TypeSet::getName() const {
+ if (TypeVec.empty()) return "<empty>";
+
+ std::string Result;
+
+ for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) {
+ std::string VTName = llvm::getEnumName(TypeVec[i]);
+ // Strip off MVT:: prefix if present.
+ if (VTName.substr(0,5) == "MVT::")
+ VTName = VTName.substr(5);
+ if (i) Result += ':';
+ Result += VTName;
+ }
+
+ if (TypeVec.size() == 1)
+ return Result;
+ return "{" + Result + "}";
}
-static inline bool isVector(MVT::SimpleValueType VT) {
- return EVT(VT).isVector();
+/// MergeInTypeInfo - This merges in type information from the specified
+/// argument. If 'this' changes, it returns true. If the two types are
+/// contradictory (e.g. merge f32 into i32) then this throws an exception.
+bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){
+ if (InVT.isCompletelyUnknown() || *this == InVT)
+ return false;
+
+ if (isCompletelyUnknown()) {
+ *this = InVT;
+ return true;
+ }
+
+ assert(TypeVec.size() >= 1 && InVT.TypeVec.size() >= 1 && "No unknowns");
+
+ // Handle the abstract cases, seeing if we can resolve them better.
+ switch (TypeVec[0]) {
+ default: break;
+ case MVT::iPTR:
+ case MVT::iPTRAny:
+ if (InVT.hasIntegerTypes()) {
+ EEVT::TypeSet InCopy(InVT);
+ InCopy.EnforceInteger(TP);
+ InCopy.EnforceScalar(TP);
+
+ if (InCopy.isConcrete()) {
+ // If the RHS has one integer type, upgrade iPTR to i32.
+ TypeVec[0] = InVT.TypeVec[0];
+ return true;
+ }
+
+ // If the input has multiple scalar integers, this doesn't add any info.
+ if (!InCopy.isCompletelyUnknown())
+ return false;
+ }
+ break;
+ }
+
+ // If the input constraint is iAny/iPTR and this is an integer type list,
+ // remove non-integer types from the list.
+ if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) &&
+ hasIntegerTypes()) {
+ bool MadeChange = EnforceInteger(TP);
+
+ // If we're merging in iPTR/iPTRAny and the node currently has a list of
+ // multiple different integer types, replace them with a single iPTR.
+ if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) &&
+ TypeVec.size() != 1) {
+ TypeVec.resize(1);
+ TypeVec[0] = InVT.TypeVec[0];
+ MadeChange = true;
+ }
+
+ return MadeChange;
+ }
+
+ // If this is a type list and the RHS is a typelist as well, eliminate entries
+ // from this list that aren't in the other one.
+ bool MadeChange = false;
+ TypeSet InputSet(*this);
+
+ for (unsigned i = 0; i != TypeVec.size(); ++i) {
+ bool InInVT = false;
+ for (unsigned j = 0, e = InVT.TypeVec.size(); j != e; ++j)
+ if (TypeVec[i] == InVT.TypeVec[j]) {
+ InInVT = true;
+ break;
+ }
+
+ if (InInVT) continue;
+ TypeVec.erase(TypeVec.begin()+i--);
+ MadeChange = true;
+ }
+
+ // If we removed all of our types, we have a type contradiction.
+ if (!TypeVec.empty())
+ return MadeChange;
+
+ // FIXME: Really want an SMLoc here!
+ TP.error("Type inference contradiction found, merging '" +
+ InVT.getName() + "' into '" + InputSet.getName() + "'");
+ return true; // unreachable
}
-static bool LHSIsSubsetOfRHS(const std::vector<unsigned char> &LHS,
- const std::vector<unsigned char> &RHS) {
- if (LHS.size() > RHS.size()) return false;
- for (unsigned i = 0, e = LHS.size(); i != e; ++i)
- if (std::find(RHS.begin(), RHS.end(), LHS[i]) == RHS.end())
- return false;
+/// EnforceInteger - Remove all non-integer types from this set.
+bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) {
+ // If we know nothing, then get the full set.
+ if (TypeVec.empty())
+ return FillWithPossibleTypes(TP, isInteger, "integer");
+ if (!hasFloatingPointTypes())
+ return false;
+
+ TypeSet InputSet(*this);
+
+ // Filter out all the fp types.
+ for (unsigned i = 0; i != TypeVec.size(); ++i)
+ if (!isInteger(TypeVec[i]))
+ TypeVec.erase(TypeVec.begin()+i--);
+
+ if (TypeVec.empty())
+ TP.error("Type inference contradiction found, '" +
+ InputSet.getName() + "' needs to be integer");
+ return true;
+}
+
+/// EnforceFloatingPoint - Remove all integer types from this set.
+bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) {
+ // If we know nothing, then get the full set.
+ if (TypeVec.empty())
+ return FillWithPossibleTypes(TP, isFloatingPoint, "floating point");
+
+ if (!hasIntegerTypes())
+ return false;
+
+ TypeSet InputSet(*this);
+
+ // Filter out all the fp types.
+ for (unsigned i = 0; i != TypeVec.size(); ++i)
+ if (!isFloatingPoint(TypeVec[i]))
+ TypeVec.erase(TypeVec.begin()+i--);
+
+ if (TypeVec.empty())
+ TP.error("Type inference contradiction found, '" +
+ InputSet.getName() + "' needs to be floating point");
+ return true;
+}
+
+/// EnforceScalar - Remove all vector types from this.
+bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) {
+ // If we know nothing, then get the full set.
+ if (TypeVec.empty())
+ return FillWithPossibleTypes(TP, isScalar, "scalar");
+
+ if (!hasVectorTypes())
+ return false;
+
+ TypeSet InputSet(*this);
+
+ // Filter out all the vector types.
+ for (unsigned i = 0; i != TypeVec.size(); ++i)
+ if (!isScalar(TypeVec[i]))
+ TypeVec.erase(TypeVec.begin()+i--);
+
+ if (TypeVec.empty())
+ TP.error("Type inference contradiction found, '" +
+ InputSet.getName() + "' needs to be scalar");
return true;
}
-namespace llvm {
-namespace EEVT {
-/// isExtIntegerInVTs - Return true if the specified extended value type vector
-/// contains iAny or an integer value type.
-bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs) {
- assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!");
- return EVTs[0] == MVT::iAny || !(FilterEVTs(EVTs, isInteger).empty());
+/// EnforceVector - Remove all vector types from this.
+bool EEVT::TypeSet::EnforceVector(TreePattern &TP) {
+ // If we know nothing, then get the full set.
+ if (TypeVec.empty())
+ return FillWithPossibleTypes(TP, isVector, "vector");
+
+ TypeSet InputSet(*this);
+ bool MadeChange = false;
+
+ // Filter out all the scalar types.
+ for (unsigned i = 0; i != TypeVec.size(); ++i)
+ if (!isVector(TypeVec[i])) {
+ TypeVec.erase(TypeVec.begin()+i--);
+ MadeChange = true;
+ }
+
+ if (TypeVec.empty())
+ TP.error("Type inference contradiction found, '" +
+ InputSet.getName() + "' needs to be a vector");
+ return MadeChange;
}
-/// isExtFloatingPointInVTs - Return true if the specified extended value type
-/// vector contains fAny or a FP value type.
-bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs) {
- assert(!EVTs.empty() && "Cannot check for FP in empty ExtVT list!");
- return EVTs[0] == MVT::fAny || !(FilterEVTs(EVTs, isFloatingPoint).empty());
+
+
+/// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update
+/// this an other based on this information.
+bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
+ // Both operands must be integer or FP, but we don't care which.
+ bool MadeChange = false;
+
+ if (isCompletelyUnknown())
+ MadeChange = FillWithPossibleTypes(TP);
+
+ if (Other.isCompletelyUnknown())
+ MadeChange = Other.FillWithPossibleTypes(TP);
+
+ // If one side is known to be integer or known to be FP but the other side has
+ // no information, get at least the type integrality info in there.
+ if (!hasFloatingPointTypes())
+ MadeChange |= Other.EnforceInteger(TP);
+ else if (!hasIntegerTypes())
+ MadeChange |= Other.EnforceFloatingPoint(TP);
+ if (!Other.hasFloatingPointTypes())
+ MadeChange |= EnforceInteger(TP);
+ else if (!Other.hasIntegerTypes())
+ MadeChange |= EnforceFloatingPoint(TP);
+
+ assert(!isCompletelyUnknown() && !Other.isCompletelyUnknown() &&
+ "Should have a type list now");
+
+ // If one contains vectors but the other doesn't pull vectors out.
+ if (!hasVectorTypes())
+ MadeChange |= Other.EnforceScalar(TP);
+ if (!hasVectorTypes())
+ MadeChange |= EnforceScalar(TP);
+
+ // This code does not currently handle nodes which have multiple types,
+ // where some types are integer, and some are fp. Assert that this is not
+ // the case.
+ assert(!(hasIntegerTypes() && hasFloatingPointTypes()) &&
+ !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) &&
+ "SDTCisOpSmallerThanOp does not handle mixed int/fp types!");
+
+ // Okay, find the smallest type from the current set and remove it from the
+ // largest set.
+ MVT::SimpleValueType Smallest = TypeVec[0];
+ for (unsigned i = 1, e = TypeVec.size(); i != e; ++i)
+ if (TypeVec[i] < Smallest)
+ Smallest = TypeVec[i];
+
+ // If this is the only type in the large set, the constraint can never be
+ // satisfied.
+ if (Other.TypeVec.size() == 1 && Other.TypeVec[0] == Smallest)
+ TP.error("Type inference contradiction found, '" +
+ Other.getName() + "' has nothing larger than '" + getName() +"'!");
+
+ SmallVector<MVT::SimpleValueType, 2>::iterator TVI =
+ std::find(Other.TypeVec.begin(), Other.TypeVec.end(), Smallest);
+ if (TVI != Other.TypeVec.end()) {
+ Other.TypeVec.erase(TVI);
+ MadeChange = true;
+ }
+
+ // Okay, find the largest type in the Other set and remove it from the
+ // current set.
+ MVT::SimpleValueType Largest = Other.TypeVec[0];
+ for (unsigned i = 1, e = Other.TypeVec.size(); i != e; ++i)
+ if (Other.TypeVec[i] > Largest)
+ Largest = Other.TypeVec[i];
+
+ // If this is the only type in the small set, the constraint can never be
+ // satisfied.
+ if (TypeVec.size() == 1 && TypeVec[0] == Largest)
+ TP.error("Type inference contradiction found, '" +
+ getName() + "' has nothing smaller than '" + Other.getName()+"'!");
+
+ TVI = std::find(TypeVec.begin(), TypeVec.end(), Largest);
+ if (TVI != TypeVec.end()) {
+ TypeVec.erase(TVI);
+ MadeChange = true;
+ }
+
+ return MadeChange;
}
-/// isExtVectorInVTs - Return true if the specified extended value type
-/// vector contains vAny or a vector value type.
-bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs) {
- assert(!EVTs.empty() && "Cannot check for vector in empty ExtVT list!");
- return EVTs[0] == MVT::vAny || !(FilterEVTs(EVTs, isVector).empty());
+/// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type
+/// whose element is specified by VTOperand.
+bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand,
+ TreePattern &TP) {
+ // "This" must be a vector and "VTOperand" must be a scalar.
+ bool MadeChange = false;
+ MadeChange |= EnforceVector(TP);
+ MadeChange |= VTOperand.EnforceScalar(TP);
+
+ // If we know the vector type, it forces the scalar to agree.
+ if (isConcrete()) {
+ EVT IVT = getConcrete();
+ IVT = IVT.getVectorElementType();
+ return MadeChange |
+ VTOperand.MergeInTypeInfo(IVT.getSimpleVT().SimpleTy, TP);
+ }
+
+ // If the scalar type is known, filter out vector types whose element types
+ // disagree.
+ if (!VTOperand.isConcrete())
+ return MadeChange;
+
+ MVT::SimpleValueType VT = VTOperand.getConcrete();
+
+ TypeSet InputSet(*this);
+
+ // Filter out all the types which don't have the right element type.
+ for (unsigned i = 0; i != TypeVec.size(); ++i) {
+ assert(isVector(TypeVec[i]) && "EnforceVector didn't work");
+ if (EVT(TypeVec[i]).getVectorElementType().getSimpleVT().SimpleTy != VT) {
+ TypeVec.erase(TypeVec.begin()+i--);
+ MadeChange = true;
+ }
+ }
+
+ if (TypeVec.empty()) // FIXME: Really want an SMLoc here!
+ TP.error("Type inference contradiction found, forcing '" +
+ InputSet.getName() + "' to have a vector element");
+ return MadeChange;
}
-} // end namespace EEVT.
-} // end namespace llvm.
+
+//===----------------------------------------------------------------------===//
+// Helpers for working with extended types.
bool RecordPtrCmp::operator()(const Record *LHS, const Record *RHS) const {
return LHS->getID() < RHS->getID();
@@ -154,6 +491,59 @@ void DumpDepVars(MultipleUseVarSet &DepVars) {
// PatternToMatch implementation
//
+
+/// getPatternSize - Return the 'size' of this pattern. We want to match large
+/// patterns before small ones. This is used to determine the size of a
+/// pattern.
+static unsigned getPatternSize(const TreePatternNode *P,
+ const CodeGenDAGPatterns &CGP) {
+ unsigned Size = 3; // The node itself.
+ // If the root node is a ConstantSDNode, increases its size.
+ // e.g. (set R32:$dst, 0).
+ if (P->isLeaf() && dynamic_cast<IntInit*>(P->getLeafValue()))
+ Size += 2;
+
+ // FIXME: This is a hack to statically increase the priority of patterns
+ // which maps a sub-dag to a complex pattern. e.g. favors LEA over ADD.
+ // Later we can allow complexity / cost for each pattern to be (optionally)
+ // specified. To get best possible pattern match we'll need to dynamically
+ // calculate the complexity of all patterns a dag can potentially map to.
+ const ComplexPattern *AM = P->getComplexPatternInfo(CGP);
+ if (AM)
+ Size += AM->getNumOperands() * 3;
+
+ // If this node has some predicate function that must match, it adds to the
+ // complexity of this node.
+ if (!P->getPredicateFns().empty())
+ ++Size;
+
+ // Count children in the count if they are also nodes.
+ for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = P->getChild(i);
+ if (!Child->isLeaf() && Child->getNumTypes() &&
+ Child->getType(0) != MVT::Other)
+ Size += getPatternSize(Child, CGP);
+ else if (Child->isLeaf()) {
+ if (dynamic_cast<IntInit*>(Child->getLeafValue()))
+ Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
+ else if (Child->getComplexPatternInfo(CGP))
+ Size += getPatternSize(Child, CGP);
+ else if (!Child->getPredicateFns().empty())
+ ++Size;
+ }
+ }
+
+ return Size;
+}
+
+/// Compute the complexity metric for the input pattern. This roughly
+/// corresponds to the number of nodes that are covered.
+unsigned PatternToMatch::
+getPatternComplexity(const CodeGenDAGPatterns &CGP) const {
+ return getPatternSize(getSrcPattern(), CGP) + getAddedComplexity();
+}
+
+
/// getPredicateCheck - Return a single string containing all of this
/// pattern's predicates concatenated with "&&" operators.
///
@@ -187,6 +577,9 @@ SDTypeConstraint::SDTypeConstraint(Record *R) {
if (R->isSubClassOf("SDTCisVT")) {
ConstraintType = SDTCisVT;
x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT"));
+ if (x.SDTCisVT_Info.VT == MVT::isVoid)
+ throw TGError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT");
+
} else if (R->isSubClassOf("SDTCisPtrTy")) {
ConstraintType = SDTCisPtrTy;
} else if (R->isSubClassOf("SDTCisInt")) {
@@ -208,8 +601,7 @@ SDTypeConstraint::SDTypeConstraint(Record *R) {
R->getValueAsInt("BigOperandNum");
} else if (R->isSubClassOf("SDTCisEltOfVec")) {
ConstraintType = SDTCisEltOfVec;
- x.SDTCisEltOfVec_Info.OtherOperandNum =
- R->getValueAsInt("OtherOpNum");
+ x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum");
} else {
errs() << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n";
exit(1);
@@ -217,24 +609,27 @@ SDTypeConstraint::SDTypeConstraint(Record *R) {
}
/// getOperandNum - Return the node corresponding to operand #OpNo in tree
-/// N, which has NumResults results.
-TreePatternNode *SDTypeConstraint::getOperandNum(unsigned OpNo,
- TreePatternNode *N,
- unsigned NumResults) const {
- assert(NumResults <= 1 &&
- "We only work with nodes with zero or one result so far!");
+/// N, and the result number in ResNo.
+static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N,
+ const SDNodeInfo &NodeInfo,
+ unsigned &ResNo) {
+ unsigned NumResults = NodeInfo.getNumResults();
+ if (OpNo < NumResults) {
+ ResNo = OpNo;
+ return N;
+ }
- if (OpNo >= (NumResults + N->getNumChildren())) {
- errs() << "Invalid operand number " << OpNo << " ";
+ OpNo -= NumResults;
+
+ if (OpNo >= N->getNumChildren()) {
+ errs() << "Invalid operand number in type constraint "
+ << (OpNo+NumResults) << " ";
N->dump();
errs() << '\n';
exit(1);
}
- if (OpNo < NumResults)
- return N; // FIXME: need value #
- else
- return N->getChild(OpNo-NumResults);
+ return N->getChild(OpNo);
}
/// ApplyTypeConstraint - Given a node in a pattern, apply this type
@@ -244,65 +639,32 @@ TreePatternNode *SDTypeConstraint::getOperandNum(unsigned OpNo,
bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
const SDNodeInfo &NodeInfo,
TreePattern &TP) const {
- unsigned NumResults = NodeInfo.getNumResults();
- assert(NumResults <= 1 &&
- "We only work with nodes with zero or one result so far!");
-
- // Check that the number of operands is sane. Negative operands -> varargs.
- if (NodeInfo.getNumOperands() >= 0) {
- if (N->getNumChildren() != (unsigned)NodeInfo.getNumOperands())
- TP.error(N->getOperator()->getName() + " node requires exactly " +
- itostr(NodeInfo.getNumOperands()) + " operands!");
- }
-
- const CodeGenTarget &CGT = TP.getDAGPatterns().getTargetInfo();
-
- TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NumResults);
+ unsigned ResNo = 0; // The result number being referenced.
+ TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo);
switch (ConstraintType) {
default: assert(0 && "Unknown constraint type!");
case SDTCisVT:
// Operand must be a particular type.
- return NodeToApply->UpdateNodeType(x.SDTCisVT_Info.VT, TP);
- case SDTCisPtrTy: {
+ return NodeToApply->UpdateNodeType(ResNo, x.SDTCisVT_Info.VT, TP);
+ case SDTCisPtrTy:
// Operand must be same as target pointer type.
- return NodeToApply->UpdateNodeType(MVT::iPTR, TP);
- }
- case SDTCisInt: {
- // If there is only one integer type supported, this must be it.
- std::vector<MVT::SimpleValueType> IntVTs =
- FilterVTs(CGT.getLegalValueTypes(), isInteger);
-
- // If we found exactly one supported integer type, apply it.
- if (IntVTs.size() == 1)
- return NodeToApply->UpdateNodeType(IntVTs[0], TP);
- return NodeToApply->UpdateNodeType(MVT::iAny, TP);
- }
- case SDTCisFP: {
- // If there is only one FP type supported, this must be it.
- std::vector<MVT::SimpleValueType> FPVTs =
- FilterVTs(CGT.getLegalValueTypes(), isFloatingPoint);
-
- // If we found exactly one supported FP type, apply it.
- if (FPVTs.size() == 1)
- return NodeToApply->UpdateNodeType(FPVTs[0], TP);
- return NodeToApply->UpdateNodeType(MVT::fAny, TP);
- }
- case SDTCisVec: {
- // If there is only one vector type supported, this must be it.
- std::vector<MVT::SimpleValueType> VecVTs =
- FilterVTs(CGT.getLegalValueTypes(), isVector);
-
- // If we found exactly one supported vector type, apply it.
- if (VecVTs.size() == 1)
- return NodeToApply->UpdateNodeType(VecVTs[0], TP);
- return NodeToApply->UpdateNodeType(MVT::vAny, TP);
- }
+ return NodeToApply->UpdateNodeType(ResNo, MVT::iPTR, TP);
+ case SDTCisInt:
+ // Require it to be one of the legal integer VTs.
+ return NodeToApply->getExtType(ResNo).EnforceInteger(TP);
+ case SDTCisFP:
+ // Require it to be one of the legal fp VTs.
+ return NodeToApply->getExtType(ResNo).EnforceFloatingPoint(TP);
+ case SDTCisVec:
+ // Require it to be one of the legal vector VTs.
+ return NodeToApply->getExtType(ResNo).EnforceVector(TP);
case SDTCisSameAs: {
+ unsigned OResNo = 0;
TreePatternNode *OtherNode =
- getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NumResults);
- return NodeToApply->UpdateNodeType(OtherNode->getExtTypes(), TP) |
- OtherNode->UpdateNodeType(NodeToApply->getExtTypes(), TP);
+ getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NodeInfo, OResNo);
+ return NodeToApply->UpdateNodeType(OResNo, OtherNode->getExtType(ResNo),TP)|
+ OtherNode->UpdateNodeType(ResNo,NodeToApply->getExtType(OResNo),TP);
}
case SDTCisVTSmallerThanOp: {
// The NodeToApply must be a leaf node that is a VT. OtherOperandNum must
@@ -314,86 +676,34 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
TP.error(N->getOperator()->getName() + " expects a VT operand!");
MVT::SimpleValueType VT =
getValueType(static_cast<DefInit*>(NodeToApply->getLeafValue())->getDef());
- if (!isInteger(VT))
- TP.error(N->getOperator()->getName() + " VT operand must be integer!");
- TreePatternNode *OtherNode =
- getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N,NumResults);
-
- // It must be integer.
- bool MadeChange = OtherNode->UpdateNodeType(MVT::iAny, TP);
+ EEVT::TypeSet TypeListTmp(VT, TP);
- // This code only handles nodes that have one type set. Assert here so
- // that we can change this if we ever need to deal with multiple value
- // types at this point.
- assert(OtherNode->getExtTypes().size() == 1 && "Node has too many types!");
- if (OtherNode->hasTypeSet() && OtherNode->getTypeNum(0) <= VT)
- OtherNode->UpdateNodeType(MVT::Other, TP); // Throw an error.
- return MadeChange;
+ unsigned OResNo = 0;
+ TreePatternNode *OtherNode =
+ getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo,
+ OResNo);
+
+ return TypeListTmp.EnforceSmallerThan(OtherNode->getExtType(OResNo), TP);
}
case SDTCisOpSmallerThanOp: {
+ unsigned BResNo = 0;
TreePatternNode *BigOperand =
- getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NumResults);
-
- // Both operands must be integer or FP, but we don't care which.
- bool MadeChange = false;
-
- // This code does not currently handle nodes which have multiple types,
- // where some types are integer, and some are fp. Assert that this is not
- // the case.
- assert(!(EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) &&
- EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) &&
- !(EEVT::isExtIntegerInVTs(BigOperand->getExtTypes()) &&
- EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) &&
- "SDTCisOpSmallerThanOp does not handle mixed int/fp types!");
- if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes()))
- MadeChange |= BigOperand->UpdateNodeType(MVT::iAny, TP);
- else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes()))
- MadeChange |= BigOperand->UpdateNodeType(MVT::fAny, TP);
- if (EEVT::isExtIntegerInVTs(BigOperand->getExtTypes()))
- MadeChange |= NodeToApply->UpdateNodeType(MVT::iAny, TP);
- else if (EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes()))
- MadeChange |= NodeToApply->UpdateNodeType(MVT::fAny, TP);
-
- std::vector<MVT::SimpleValueType> VTs = CGT.getLegalValueTypes();
-
- if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) {
- VTs = FilterVTs(VTs, isInteger);
- } else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) {
- VTs = FilterVTs(VTs, isFloatingPoint);
- } else {
- VTs.clear();
- }
-
- switch (VTs.size()) {
- default: // Too many VT's to pick from.
- case 0: break; // No info yet.
- case 1:
- // Only one VT of this flavor. Cannot ever satisfy the constraints.
- return NodeToApply->UpdateNodeType(MVT::Other, TP); // throw
- case 2:
- // If we have exactly two possible types, the little operand must be the
- // small one, the big operand should be the big one. Common with
- // float/double for example.
- assert(VTs[0] < VTs[1] && "Should be sorted!");
- MadeChange |= NodeToApply->UpdateNodeType(VTs[0], TP);
- MadeChange |= BigOperand->UpdateNodeType(VTs[1], TP);
- break;
- }
- return MadeChange;
+ getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NodeInfo,
+ BResNo);
+ return NodeToApply->getExtType(ResNo).
+ EnforceSmallerThan(BigOperand->getExtType(BResNo), TP);
}
case SDTCisEltOfVec: {
- TreePatternNode *OtherOperand =
- getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum,
- N, NumResults);
- if (OtherOperand->hasTypeSet()) {
- if (!isVector(OtherOperand->getTypeNum(0)))
- TP.error(N->getOperator()->getName() + " VT operand must be a vector!");
- EVT IVT = OtherOperand->getTypeNum(0);
- IVT = IVT.getVectorElementType();
- return NodeToApply->UpdateNodeType(IVT.getSimpleVT().SimpleTy, TP);
- }
- return false;
+ unsigned VResNo = 0;
+ TreePatternNode *VecOperand =
+ getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, N, NodeInfo,
+ VResNo);
+
+ // Filter vector types out of VecOperand that don't have the right element
+ // type.
+ return VecOperand->getExtType(VResNo).
+ EnforceVectorEltTypeIs(NodeToApply->getExtType(ResNo), TP);
}
}
return false;
@@ -433,6 +743,8 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
Properties |= 1 << SDNPSideEffect;
} else if (PropList[i]->getName() == "SDNPMemOperand") {
Properties |= 1 << SDNPMemOperand;
+ } else if (PropList[i]->getName() == "SDNPVariadic") {
+ Properties |= 1 << SDNPVariadic;
} else {
errs() << "Unknown SD Node property '" << PropList[i]->getName()
<< "' on node '" << R->getName() << "'!\n";
@@ -449,11 +761,12 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) {
/// getKnownType - If the type constraints on this node imply a fixed type
/// (e.g. all stores return void, etc), then return it as an
-/// MVT::SimpleValueType. Otherwise, return EEVT::isUnknown.
-unsigned SDNodeInfo::getKnownType() const {
+/// MVT::SimpleValueType. Otherwise, return EEVT::Other.
+MVT::SimpleValueType SDNodeInfo::getKnownType(unsigned ResNo) const {
unsigned NumResults = getNumResults();
assert(NumResults <= 1 &&
"We only work with nodes with zero or one result so far!");
+ assert(ResNo == 0 && "Only handles single result nodes so far");
for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i) {
// Make sure that this applies to the correct node result.
@@ -468,7 +781,7 @@ unsigned SDNodeInfo::getKnownType() const {
return MVT::iPTR;
}
}
- return EEVT::isUnknown;
+ return MVT::Other;
}
//===----------------------------------------------------------------------===//
@@ -482,146 +795,61 @@ TreePatternNode::~TreePatternNode() {
#endif
}
-/// UpdateNodeType - Set the node type of N to VT if VT contains
-/// information. If N already contains a conflicting type, then throw an
-/// exception. This returns true if any information was updated.
-///
-bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs,
- TreePattern &TP) {
- assert(!ExtVTs.empty() && "Cannot update node type with empty type vector!");
+static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) {
+ if (Operator->getName() == "set" ||
+ Operator->getName() == "implicit")
+ return 0; // All return nothing.
- if (ExtVTs[0] == EEVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs))
- return false;
- if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) {
- setTypes(ExtVTs);
- return true;
- }
-
- if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) {
- if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny ||
- ExtVTs[0] == MVT::iAny)
- return false;
- if (EEVT::isExtIntegerInVTs(ExtVTs)) {
- std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, isInteger);
- if (FVTs.size()) {
- setTypes(ExtVTs);
- return true;
- }
- }
- }
-
- // Merge vAny with iAny/fAny. The latter include vector types so keep them
- // as the more specific information.
- if (ExtVTs[0] == MVT::vAny &&
- (getExtTypeNum(0) == MVT::iAny || getExtTypeNum(0) == MVT::fAny))
- return false;
- if (getExtTypeNum(0) == MVT::vAny &&
- (ExtVTs[0] == MVT::iAny || ExtVTs[0] == MVT::fAny)) {
- setTypes(ExtVTs);
- return true;
- }
-
- if (ExtVTs[0] == MVT::iAny &&
- EEVT::isExtIntegerInVTs(getExtTypes())) {
- assert(hasTypeSet() && "should be handled above!");
- std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger);
- if (getExtTypes() == FVTs)
- return false;
- setTypes(FVTs);
- return true;
- }
- if ((ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny) &&
- EEVT::isExtIntegerInVTs(getExtTypes())) {
- //assert(hasTypeSet() && "should be handled above!");
- std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger);
- if (getExtTypes() == FVTs)
- return false;
- if (FVTs.size()) {
- setTypes(FVTs);
- return true;
- }
- }
- if (ExtVTs[0] == MVT::fAny &&
- EEVT::isExtFloatingPointInVTs(getExtTypes())) {
- assert(hasTypeSet() && "should be handled above!");
- std::vector<unsigned char> FVTs =
- FilterEVTs(getExtTypes(), isFloatingPoint);
- if (getExtTypes() == FVTs)
- return false;
- setTypes(FVTs);
- return true;
- }
- if (ExtVTs[0] == MVT::vAny &&
- EEVT::isExtVectorInVTs(getExtTypes())) {
- assert(hasTypeSet() && "should be handled above!");
- std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isVector);
- if (getExtTypes() == FVTs)
- return false;
- setTypes(FVTs);
- return true;
- }
-
- // If we know this is an int, FP, or vector type, and we are told it is a
- // specific one, take the advice.
- //
- // Similarly, we should probably set the type here to the intersection of
- // {iAny|fAny|vAny} and ExtVTs
- if ((getExtTypeNum(0) == MVT::iAny &&
- EEVT::isExtIntegerInVTs(ExtVTs)) ||
- (getExtTypeNum(0) == MVT::fAny &&
- EEVT::isExtFloatingPointInVTs(ExtVTs)) ||
- (getExtTypeNum(0) == MVT::vAny &&
- EEVT::isExtVectorInVTs(ExtVTs))) {
- setTypes(ExtVTs);
- return true;
- }
- if (getExtTypeNum(0) == MVT::iAny &&
- (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny)) {
- setTypes(ExtVTs);
- return true;
- }
-
- if (isLeaf()) {
- dump();
- errs() << " ";
- TP.error("Type inference contradiction found in node!");
- } else {
- TP.error("Type inference contradiction found in node " +
- getOperator()->getName() + "!");
+ if (Operator->isSubClassOf("Intrinsic"))
+ return CDP.getIntrinsic(Operator).IS.RetVTs.size();
+
+ if (Operator->isSubClassOf("SDNode"))
+ return CDP.getSDNodeInfo(Operator).getNumResults();
+
+ if (Operator->isSubClassOf("PatFrag")) {
+ // If we've already parsed this pattern fragment, get it. Otherwise, handle
+ // the forward reference case where one pattern fragment references another
+ // before it is processed.
+ if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator))
+ return PFRec->getOnlyTree()->getNumTypes();
+
+ // Get the result tree.
+ DagInit *Tree = Operator->getValueAsDag("Fragment");
+ Record *Op = 0;
+ if (Tree && dynamic_cast<DefInit*>(Tree->getOperator()))
+ Op = dynamic_cast<DefInit*>(Tree->getOperator())->getDef();
+ assert(Op && "Invalid Fragment");
+ return GetNumNodeResults(Op, CDP);
}
- return true; // unreachable
-}
+
+ if (Operator->isSubClassOf("Instruction")) {
+ CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(Operator);
-static std::string GetTypeName(unsigned char TypeID) {
- switch (TypeID) {
- case MVT::Other: return "Other";
- case MVT::iAny: return "iAny";
- case MVT::fAny: return "fAny";
- case MVT::vAny: return "vAny";
- case EEVT::isUnknown: return "isUnknown";
- case MVT::iPTR: return "iPTR";
- case MVT::iPTRAny: return "iPTRAny";
- default:
- std::string VTName = llvm::getName((MVT::SimpleValueType)TypeID);
- // Strip off EVT:: prefix if present.
- if (VTName.substr(0,5) == "MVT::")
- VTName = VTName.substr(5);
- return VTName;
+ // FIXME: Should allow access to all the results here.
+ unsigned NumDefsToAdd = InstInfo.NumDefs ? 1 : 0;
+
+ // Add on one implicit def if it has a resolvable type.
+ if (InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()) !=MVT::Other)
+ ++NumDefsToAdd;
+ return NumDefsToAdd;
}
+
+ if (Operator->isSubClassOf("SDNodeXForm"))
+ return 1; // FIXME: Generalize SDNodeXForm
+
+ Operator->dump();
+ errs() << "Unhandled node in GetNumNodeResults\n";
+ exit(1);
}
-
void TreePatternNode::print(raw_ostream &OS) const {
- if (isLeaf()) {
+ if (isLeaf())
OS << *getLeafValue();
- } else {
+ else
OS << '(' << getOperator()->getName();
- }
-
- // FIXME: At some point we should handle printing all the value types for
- // nodes that are multiply typed.
- if (getExtTypeNum(0) != EEVT::isUnknown)
- OS << ':' << GetTypeName(getExtTypeNum(0));
+
+ for (unsigned i = 0, e = Types.size(); i != e; ++i)
+ OS << ':' << getExtType(i).getName();
if (!isLeaf()) {
if (getNumChildren() != 0) {
@@ -686,16 +914,16 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
TreePatternNode *TreePatternNode::clone() const {
TreePatternNode *New;
if (isLeaf()) {
- New = new TreePatternNode(getLeafValue());
+ New = new TreePatternNode(getLeafValue(), getNumTypes());
} else {
std::vector<TreePatternNode*> CChildren;
CChildren.reserve(Children.size());
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
CChildren.push_back(getChild(i)->clone());
- New = new TreePatternNode(getOperator(), CChildren);
+ New = new TreePatternNode(getOperator(), CChildren, getNumTypes());
}
New->setName(getName());
- New->setTypes(getExtTypes());
+ New->Types = Types;
New->setPredicateFns(getPredicateFns());
New->setTransformFn(getTransformFn());
return New;
@@ -703,7 +931,8 @@ TreePatternNode *TreePatternNode::clone() const {
/// RemoveAllTypes - Recursively strip all the types of this tree.
void TreePatternNode::RemoveAllTypes() {
- removeTypes();
+ for (unsigned i = 0, e = Types.size(); i != e; ++i)
+ Types[i] = EEVT::TypeSet(); // Reset to unknown type.
if (isLeaf()) return;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
getChild(i)->RemoveAllTypes();
@@ -785,7 +1014,8 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
}
FragTree->setName(getName());
- FragTree->UpdateNodeType(getExtTypes(), TP);
+ for (unsigned i = 0, e = Types.size(); i != e; ++i)
+ FragTree->UpdateNodeType(i, getExtType(i), TP);
// Transfer in the old predicates.
for (unsigned i = 0, e = getPredicateFns().size(); i != e; ++i)
@@ -803,47 +1033,57 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
/// type which should be applied to it. This will infer the type of register
/// references from the register file information, for example.
///
-static std::vector<unsigned char> getImplicitType(Record *R, bool NotRegisters,
- TreePattern &TP) {
- // Some common return values
- std::vector<unsigned char> Unknown(1, EEVT::isUnknown);
- std::vector<unsigned char> Other(1, MVT::Other);
-
- // Check to see if this is a register or a register class...
+static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
+ bool NotRegisters, TreePattern &TP) {
+ // Check to see if this is a register or a register class.
if (R->isSubClassOf("RegisterClass")) {
+ assert(ResNo == 0 && "Regclass ref only has one result!");
if (NotRegisters)
- return Unknown;
- const CodeGenRegisterClass &RC =
- TP.getDAGPatterns().getTargetInfo().getRegisterClass(R);
- return ConvertVTs(RC.getValueTypes());
- } else if (R->isSubClassOf("PatFrag")) {
+ return EEVT::TypeSet(); // Unknown.
+ const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
+ return EEVT::TypeSet(T.getRegisterClass(R).getValueTypes());
+ }
+
+ if (R->isSubClassOf("PatFrag")) {
+ assert(ResNo == 0 && "FIXME: PatFrag with multiple results?");
// Pattern fragment types will be resolved when they are inlined.
- return Unknown;
- } else if (R->isSubClassOf("Register")) {
+ return EEVT::TypeSet(); // Unknown.
+ }
+
+ if (R->isSubClassOf("Register")) {
+ assert(ResNo == 0 && "Registers only produce one result!");
if (NotRegisters)
- return Unknown;
+ return EEVT::TypeSet(); // Unknown.
const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
- return T.getRegisterVTs(R);
- } else if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) {
+ return EEVT::TypeSet(T.getRegisterVTs(R));
+ }
+
+ if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) {
+ assert(ResNo == 0 && "This node only has one result!");
// Using a VTSDNode or CondCodeSDNode.
- return Other;
- } else if (R->isSubClassOf("ComplexPattern")) {
+ return EEVT::TypeSet(MVT::Other, TP);
+ }
+
+ if (R->isSubClassOf("ComplexPattern")) {
+ assert(ResNo == 0 && "FIXME: ComplexPattern with multiple results?");
if (NotRegisters)
- return Unknown;
- std::vector<unsigned char>
- ComplexPat(1, TP.getDAGPatterns().getComplexPattern(R).getValueType());
- return ComplexPat;
- } else if (R->isSubClassOf("PointerLikeRegClass")) {
- Other[0] = MVT::iPTR;
- return Other;
- } else if (R->getName() == "node" || R->getName() == "srcvalue" ||
- R->getName() == "zero_reg") {
+ return EEVT::TypeSet(); // Unknown.
+ return EEVT::TypeSet(TP.getDAGPatterns().getComplexPattern(R).getValueType(),
+ TP);
+ }
+ if (R->isSubClassOf("PointerLikeRegClass")) {
+ assert(ResNo == 0 && "Regclass can only have one result!");
+ return EEVT::TypeSet(MVT::iPTR, TP);
+ }
+
+ if (R->getName() == "node" || R->getName() == "srcvalue" ||
+ R->getName() == "zero_reg") {
// Placeholder.
- return Unknown;
+ return EEVT::TypeSet(); // Unknown.
}
TP.error("Unknown node flavor used in pattern: " + R->getName());
- return Other;
+ return EEVT::TypeSet(MVT::Other, TP);
}
@@ -922,45 +1162,44 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
if (isLeaf()) {
if (DefInit *DI = dynamic_cast<DefInit*>(getLeafValue())) {
// If it's a regclass or something else known, include the type.
- return UpdateNodeType(getImplicitType(DI->getDef(), NotRegisters, TP),TP);
+ bool MadeChange = false;
+ for (unsigned i = 0, e = Types.size(); i != e; ++i)
+ MadeChange |= UpdateNodeType(i, getImplicitType(DI->getDef(), i,
+ NotRegisters, TP), TP);
+ return MadeChange;
}
if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) {
+ assert(Types.size() == 1 && "Invalid IntInit");
+
// Int inits are always integers. :)
- bool MadeChange = UpdateNodeType(MVT::iAny, TP);
+ bool MadeChange = Types[0].EnforceInteger(TP);
- if (hasTypeSet()) {
- // At some point, it may make sense for this tree pattern to have
- // multiple types. Assert here that it does not, so we revisit this
- // code when appropriate.
- assert(getExtTypes().size() >= 1 && "TreePattern doesn't have a type!");
- MVT::SimpleValueType VT = getTypeNum(0);
- for (unsigned i = 1, e = getExtTypes().size(); i != e; ++i)
- assert(getTypeNum(i) == VT && "TreePattern has too many types!");
-
- VT = getTypeNum(0);
- if (VT != MVT::iPTR && VT != MVT::iPTRAny) {
- unsigned Size = EVT(VT).getSizeInBits();
- // Make sure that the value is representable for this type.
- if (Size < 32) {
- int Val = (II->getValue() << (32-Size)) >> (32-Size);
- if (Val != II->getValue()) {
- // If sign-extended doesn't fit, does it fit as unsigned?
- unsigned ValueMask;
- unsigned UnsignedVal;
- ValueMask = unsigned(~uint32_t(0UL) >> (32-Size));
- UnsignedVal = unsigned(II->getValue());
-
- if ((ValueMask & UnsignedVal) != UnsignedVal) {
- TP.error("Integer value '" + itostr(II->getValue())+
- "' is out of range for type '" +
- getEnumName(getTypeNum(0)) + "'!");
- }
- }
- }
- }
- }
+ if (!Types[0].isConcrete())
+ return MadeChange;
+
+ MVT::SimpleValueType VT = getType(0);
+ if (VT == MVT::iPTR || VT == MVT::iPTRAny)
+ return MadeChange;
+ unsigned Size = EVT(VT).getSizeInBits();
+ // Make sure that the value is representable for this type.
+ if (Size >= 32) return MadeChange;
+
+ int Val = (II->getValue() << (32-Size)) >> (32-Size);
+ if (Val == II->getValue()) return MadeChange;
+
+ // If sign-extended doesn't fit, does it fit as unsigned?
+ unsigned ValueMask;
+ unsigned UnsignedVal;
+ ValueMask = unsigned(~uint32_t(0UL) >> (32-Size));
+ UnsignedVal = unsigned(II->getValue());
+
+ if ((ValueMask & UnsignedVal) == UnsignedVal)
+ return MadeChange;
+
+ TP.error("Integer value '" + itostr(II->getValue())+
+ "' is out of range for type '" + getEnumName(getType(0)) + "'!");
return MadeChange;
}
return false;
@@ -968,29 +1207,30 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
// special handling for set, which isn't really an SDNode.
if (getOperator()->getName() == "set") {
- assert (getNumChildren() >= 2 && "Missing RHS of a set?");
+ assert(getNumTypes() == 0 && "Set doesn't produce a value");
+ assert(getNumChildren() >= 2 && "Missing RHS of a set?");
unsigned NC = getNumChildren();
- bool MadeChange = false;
+
+ TreePatternNode *SetVal = getChild(NC-1);
+ bool MadeChange = SetVal->ApplyTypeConstraints(TP, NotRegisters);
+
for (unsigned i = 0; i < NC-1; ++i) {
- MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
- MadeChange |= getChild(NC-1)->ApplyTypeConstraints(TP, NotRegisters);
+ TreePatternNode *Child = getChild(i);
+ MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters);
// Types of operands must match.
- MadeChange |= getChild(i)->UpdateNodeType(getChild(NC-1)->getExtTypes(),
- TP);
- MadeChange |= getChild(NC-1)->UpdateNodeType(getChild(i)->getExtTypes(),
- TP);
- MadeChange |= UpdateNodeType(MVT::isVoid, TP);
+ MadeChange |= Child->UpdateNodeType(0, SetVal->getExtType(i), TP);
+ MadeChange |= SetVal->UpdateNodeType(i, Child->getExtType(0), TP);
}
return MadeChange;
}
- if (getOperator()->getName() == "implicit" ||
- getOperator()->getName() == "parallel") {
+ if (getOperator()->getName() == "implicit") {
+ assert(getNumTypes() == 0 && "Node doesn't produce a value");
+
bool MadeChange = false;
for (unsigned i = 0; i < getNumChildren(); ++i)
MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
- MadeChange |= UpdateNodeType(MVT::isVoid, TP);
return MadeChange;
}
@@ -998,6 +1238,18 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
bool MadeChange = false;
MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters);
+
+ assert(getChild(0)->getNumTypes() == 1 &&
+ getChild(1)->getNumTypes() == 1 && "Unhandled case");
+
+ // child #1 of COPY_TO_REGCLASS should be a register class. We don't care
+ // what type it gets, so if it didn't get a concrete type just give it the
+ // first viable type from the reg class.
+ if (!getChild(1)->hasTypeSet(0) &&
+ !getChild(1)->getExtType(0).isCompletelyUnknown()) {
+ MVT::SimpleValueType RCVT = getChild(1)->getExtType(0).getTypeList()[0];
+ MadeChange |= getChild(1)->UpdateNodeType(0, RCVT, TP);
+ }
return MadeChange;
}
@@ -1007,22 +1259,24 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
// Apply the result type to the node.
unsigned NumRetVTs = Int->IS.RetVTs.size();
unsigned NumParamVTs = Int->IS.ParamVTs.size();
-
+
for (unsigned i = 0, e = NumRetVTs; i != e; ++i)
- MadeChange |= UpdateNodeType(Int->IS.RetVTs[i], TP);
+ MadeChange |= UpdateNodeType(i, Int->IS.RetVTs[i], TP);
- if (getNumChildren() != NumParamVTs + NumRetVTs)
+ if (getNumChildren() != NumParamVTs + 1)
TP.error("Intrinsic '" + Int->Name + "' expects " +
- utostr(NumParamVTs + NumRetVTs - 1) + " operands, not " +
+ utostr(NumParamVTs) + " operands, not " +
utostr(getNumChildren() - 1) + " operands!");
// Apply type info to the intrinsic ID.
- MadeChange |= getChild(0)->UpdateNodeType(MVT::iPTR, TP);
+ MadeChange |= getChild(0)->UpdateNodeType(0, MVT::iPTR, TP);
- for (unsigned i = NumRetVTs, e = getNumChildren(); i != e; ++i) {
- MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i - NumRetVTs];
- MadeChange |= getChild(i)->UpdateNodeType(OpVT, TP);
- MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
+ for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i) {
+ MadeChange |= getChild(i+1)->ApplyTypeConstraints(TP, NotRegisters);
+
+ MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i];
+ assert(getChild(i+1)->getNumTypes() == 1 && "Unhandled case");
+ MadeChange |= getChild(i+1)->UpdateNodeType(0, OpVT, TP);
}
return MadeChange;
}
@@ -1030,50 +1284,66 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
if (getOperator()->isSubClassOf("SDNode")) {
const SDNodeInfo &NI = CDP.getSDNodeInfo(getOperator());
+ // Check that the number of operands is sane. Negative operands -> varargs.
+ if (NI.getNumOperands() >= 0 &&
+ getNumChildren() != (unsigned)NI.getNumOperands())
+ TP.error(getOperator()->getName() + " node requires exactly " +
+ itostr(NI.getNumOperands()) + " operands!");
+
bool MadeChange = NI.ApplyTypeConstraints(this, TP);
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
- // Branch, etc. do not produce results and top-level forms in instr pattern
- // must have void types.
- if (NI.getNumResults() == 0)
- MadeChange |= UpdateNodeType(MVT::isVoid, TP);
-
- return MadeChange;
+ return MadeChange;
}
if (getOperator()->isSubClassOf("Instruction")) {
const DAGInstruction &Inst = CDP.getInstruction(getOperator());
- bool MadeChange = false;
- unsigned NumResults = Inst.getNumResults();
+ CodeGenInstruction &InstInfo =
+ CDP.getTargetInfo().getInstruction(getOperator());
- assert(NumResults <= 1 &&
- "Only supports zero or one result instrs!");
+ bool MadeChange = false;
- CodeGenInstruction &InstInfo =
- CDP.getTargetInfo().getInstruction(getOperator()->getName());
- // Apply the result type to the node
- if (NumResults == 0 || InstInfo.NumDefs == 0) {
- MadeChange = UpdateNodeType(MVT::isVoid, TP);
- } else {
- Record *ResultNode = Inst.getResult(0);
+ // Apply the result types to the node, these come from the things in the
+ // (outs) list of the instruction.
+ // FIXME: Cap at one result so far.
+ unsigned NumResultsToAdd = InstInfo.NumDefs ? 1 : 0;
+ for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) {
+ Record *ResultNode = Inst.getResult(ResNo);
if (ResultNode->isSubClassOf("PointerLikeRegClass")) {
- std::vector<unsigned char> VT;
- VT.push_back(MVT::iPTR);
- MadeChange = UpdateNodeType(VT, TP);
+ MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP);
} else if (ResultNode->getName() == "unknown") {
- std::vector<unsigned char> VT;
- VT.push_back(EEVT::isUnknown);
- MadeChange = UpdateNodeType(VT, TP);
+ // Nothing to do.
} else {
assert(ResultNode->isSubClassOf("RegisterClass") &&
"Operands should be register classes!");
-
const CodeGenRegisterClass &RC =
CDP.getTargetInfo().getRegisterClass(ResultNode);
- MadeChange = UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP);
+ MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP);
}
}
+
+ // If the instruction has implicit defs, we apply the first one as a result.
+ // FIXME: This sucks, it should apply all implicit defs.
+ if (!InstInfo.ImplicitDefs.empty()) {
+ unsigned ResNo = NumResultsToAdd;
+
+ // FIXME: Generalize to multiple possible types and multiple possible
+ // ImplicitDefs.
+ MVT::SimpleValueType VT =
+ InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo());
+
+ if (VT != MVT::Other)
+ MadeChange |= UpdateNodeType(ResNo, VT, TP);
+ }
+
+ // If this is an INSERT_SUBREG, constrain the source and destination VTs to
+ // be the same.
+ if (getOperator()->getName() == "INSERT_SUBREG") {
+ assert(getChild(0)->getNumTypes() == 1 && "FIXME: Unhandled");
+ MadeChange |= UpdateNodeType(0, getChild(0)->getExtType(0), TP);
+ MadeChange |= getChild(0)->UpdateNodeType(0, getExtType(0), TP);
+ }
unsigned ChildNo = 0;
for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) {
@@ -1094,17 +1364,19 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
MVT::SimpleValueType VT;
TreePatternNode *Child = getChild(ChildNo++);
+ unsigned ChildResNo = 0; // Instructions always use res #0 of their op.
+
if (OperandNode->isSubClassOf("RegisterClass")) {
const CodeGenRegisterClass &RC =
CDP.getTargetInfo().getRegisterClass(OperandNode);
- MadeChange |= Child->UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP);
+ MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
} else if (OperandNode->isSubClassOf("Operand")) {
VT = getValueType(OperandNode->getValueAsDef("Type"));
- MadeChange |= Child->UpdateNodeType(VT, TP);
+ MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP);
} else if (OperandNode->isSubClassOf("PointerLikeRegClass")) {
- MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP);
+ MadeChange |= Child->UpdateNodeType(ChildResNo, MVT::iPTR, TP);
} else if (OperandNode->getName() == "unknown") {
- MadeChange |= Child->UpdateNodeType(EEVT::isUnknown, TP);
+ // Nothing to do.
} else {
assert(0 && "Unknown operand type!");
abort();
@@ -1126,15 +1398,20 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
TP.error("Node transform '" + getOperator()->getName() +
"' requires one operand!");
+ bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
+
+
// If either the output or input of the xform does not have exact
// type info. We assume they must be the same. Otherwise, it is perfectly
// legal to transform from one type to a completely different type.
+#if 0
if (!hasTypeSet() || !getChild(0)->hasTypeSet()) {
- bool MadeChange = UpdateNodeType(getChild(0)->getExtTypes(), TP);
- MadeChange |= getChild(0)->UpdateNodeType(getExtTypes(), TP);
+ bool MadeChange = UpdateNodeType(getChild(0)->getExtType(), TP);
+ MadeChange |= getChild(0)->UpdateNodeType(getExtType(), TP);
return MadeChange;
}
- return false;
+#endif
+ return MadeChange;
}
/// OnlyOnRHSOfCommutative - Return true if this value is only allowed on the
@@ -1194,15 +1471,15 @@ bool TreePatternNode::canPatternMatch(std::string &Reason,
TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput,
CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){
- isInputPattern = isInput;
- for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i)
- Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i)));
+ isInputPattern = isInput;
+ for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i)
+ Trees.push_back(ParseTreePattern(RawPat->getElement(i), ""));
}
TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput,
CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){
isInputPattern = isInput;
- Trees.push_back(ParseTreePattern(Pat));
+ Trees.push_back(ParseTreePattern(Pat, ""));
}
TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput,
@@ -1211,14 +1488,68 @@ TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput,
Trees.push_back(Pat);
}
-
-
void TreePattern::error(const std::string &Msg) const {
dump();
throw TGError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg);
}
-TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) {
+void TreePattern::ComputeNamedNodes() {
+ for (unsigned i = 0, e = Trees.size(); i != e; ++i)
+ ComputeNamedNodes(Trees[i]);
+}
+
+void TreePattern::ComputeNamedNodes(TreePatternNode *N) {
+ if (!N->getName().empty())
+ NamedNodes[N->getName()].push_back(N);
+
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
+ ComputeNamedNodes(N->getChild(i));
+}
+
+
+TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
+ if (DefInit *DI = dynamic_cast<DefInit*>(TheInit)) {
+ Record *R = DI->getDef();
+
+ // Direct reference to a leaf DagNode or PatFrag? Turn it into a
+ // TreePatternNode if its own. For example:
+ /// (foo GPR, imm) -> (foo GPR, (imm))
+ if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag"))
+ return ParseTreePattern(new DagInit(DI, "",
+ std::vector<std::pair<Init*, std::string> >()),
+ OpName);
+
+ // Input argument?
+ TreePatternNode *Res = new TreePatternNode(DI, 1);
+ if (R->getName() == "node" && !OpName.empty()) {
+ if (OpName.empty())
+ error("'node' argument requires a name to match with operand list");
+ Args.push_back(OpName);
+ }
+
+ Res->setName(OpName);
+ return Res;
+ }
+
+ if (IntInit *II = dynamic_cast<IntInit*>(TheInit)) {
+ if (!OpName.empty())
+ error("Constant int argument should not have a name!");
+ return new TreePatternNode(II, 1);
+ }
+
+ if (BitsInit *BI = dynamic_cast<BitsInit*>(TheInit)) {
+ // Turn this into an IntInit.
+ Init *II = BI->convertInitializerTo(new IntRecTy());
+ if (II == 0 || !dynamic_cast<IntInit*>(II))
+ error("Bits value must be constants!");
+ return ParseTreePattern(II, OpName);
+ }
+
+ DagInit *Dag = dynamic_cast<DagInit*>(TheInit);
+ if (!Dag) {
+ TheInit->dump();
+ error("Pattern has unexpected init kind!");
+ }
DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator());
if (!OpDef) error("Pattern has unexpected operator type!");
Record *Operator = OpDef->getDef();
@@ -1229,41 +1560,14 @@ TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) {
if (Dag->getNumArgs() != 1)
error("Type cast only takes one operand!");
- Init *Arg = Dag->getArg(0);
- TreePatternNode *New;
- if (DefInit *DI = dynamic_cast<DefInit*>(Arg)) {
- Record *R = DI->getDef();
- if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) {
- Dag->setArg(0, new DagInit(DI, "",
- std::vector<std::pair<Init*, std::string> >()));
- return ParseTreePattern(Dag);
- }
- New = new TreePatternNode(DI);
- } else if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) {
- New = ParseTreePattern(DI);
- } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
- New = new TreePatternNode(II);
- if (!Dag->getArgName(0).empty())
- error("Constant int argument should not have a name!");
- } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Arg)) {
- // Turn this into an IntInit.
- Init *II = BI->convertInitializerTo(new IntRecTy());
- if (II == 0 || !dynamic_cast<IntInit*>(II))
- error("Bits value must be constants!");
-
- New = new TreePatternNode(dynamic_cast<IntInit*>(II));
- if (!Dag->getArgName(0).empty())
- error("Constant int argument should not have a name!");
- } else {
- Arg->dump();
- error("Unknown leaf value for tree pattern!");
- return 0;
- }
+ TreePatternNode *New = ParseTreePattern(Dag->getArg(0), Dag->getArgName(0));
// Apply the type cast.
- New->UpdateNodeType(getValueType(Operator), *this);
- if (New->getNumChildren() == 0)
- New->setName(Dag->getArgName(0));
+ assert(New->getNumTypes() == 1 && "FIXME: Unhandled");
+ New->UpdateNodeType(0, getValueType(Operator), *this);
+
+ if (!OpName.empty())
+ error("ValueType cast should not have a name!");
return New;
}
@@ -1274,65 +1578,38 @@ TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) {
!Operator->isSubClassOf("SDNodeXForm") &&
!Operator->isSubClassOf("Intrinsic") &&
Operator->getName() != "set" &&
- Operator->getName() != "implicit" &&
- Operator->getName() != "parallel")
+ Operator->getName() != "implicit")
error("Unrecognized node '" + Operator->getName() + "'!");
// Check to see if this is something that is illegal in an input pattern.
- if (isInputPattern && (Operator->isSubClassOf("Instruction") ||
- Operator->isSubClassOf("SDNodeXForm")))
- error("Cannot use '" + Operator->getName() + "' in an input pattern!");
+ if (isInputPattern) {
+ if (Operator->isSubClassOf("Instruction") ||
+ Operator->isSubClassOf("SDNodeXForm"))
+ error("Cannot use '" + Operator->getName() + "' in an input pattern!");
+ } else {
+ if (Operator->isSubClassOf("Intrinsic"))
+ error("Cannot use '" + Operator->getName() + "' in an output pattern!");
+
+ if (Operator->isSubClassOf("SDNode") &&
+ Operator->getName() != "imm" &&
+ Operator->getName() != "fpimm" &&
+ Operator->getName() != "tglobaltlsaddr" &&
+ Operator->getName() != "tconstpool" &&
+ Operator->getName() != "tjumptable" &&
+ Operator->getName() != "tframeindex" &&
+ Operator->getName() != "texternalsym" &&
+ Operator->getName() != "tblockaddress" &&
+ Operator->getName() != "tglobaladdr" &&
+ Operator->getName() != "bb" &&
+ Operator->getName() != "vt")
+ error("Cannot use '" + Operator->getName() + "' in an output pattern!");
+ }
std::vector<TreePatternNode*> Children;
-
- for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {
- Init *Arg = Dag->getArg(i);
- if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) {
- Children.push_back(ParseTreePattern(DI));
- if (Children.back()->getName().empty())
- Children.back()->setName(Dag->getArgName(i));
- } else if (DefInit *DefI = dynamic_cast<DefInit*>(Arg)) {
- Record *R = DefI->getDef();
- // Direct reference to a leaf DagNode or PatFrag? Turn it into a
- // TreePatternNode if its own.
- if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) {
- Dag->setArg(i, new DagInit(DefI, "",
- std::vector<std::pair<Init*, std::string> >()));
- --i; // Revisit this node...
- } else {
- TreePatternNode *Node = new TreePatternNode(DefI);
- Node->setName(Dag->getArgName(i));
- Children.push_back(Node);
-
- // Input argument?
- if (R->getName() == "node") {
- if (Dag->getArgName(i).empty())
- error("'node' argument requires a name to match with operand list");
- Args.push_back(Dag->getArgName(i));
- }
- }
- } else if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
- TreePatternNode *Node = new TreePatternNode(II);
- if (!Dag->getArgName(i).empty())
- error("Constant int argument should not have a name!");
- Children.push_back(Node);
- } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Arg)) {
- // Turn this into an IntInit.
- Init *II = BI->convertInitializerTo(new IntRecTy());
- if (II == 0 || !dynamic_cast<IntInit*>(II))
- error("Bits value must be constants!");
-
- TreePatternNode *Node = new TreePatternNode(dynamic_cast<IntInit*>(II));
- if (!Dag->getArgName(i).empty())
- error("Constant int argument should not have a name!");
- Children.push_back(Node);
- } else {
- errs() << '"';
- Arg->dump();
- errs() << "\": ";
- error("Unknown leaf value for tree pattern!");
- }
- }
+
+ // Parse all the operands.
+ for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i)
+ Children.push_back(ParseTreePattern(Dag->getArg(i), Dag->getArgName(i)));
// If the operator is an intrinsic, then this is just syntactic sugar for for
// (intrinsic_* <number>, ..children..). Pick the right intrinsic node, and
@@ -1343,34 +1620,127 @@ TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) {
// If this intrinsic returns void, it must have side-effects and thus a
// chain.
- if (Int.IS.RetVTs[0] == MVT::isVoid) {
+ if (Int.IS.RetVTs.empty())
Operator = getDAGPatterns().get_intrinsic_void_sdnode();
- } else if (Int.ModRef != CodeGenIntrinsic::NoMem) {
+ else if (Int.ModRef != CodeGenIntrinsic::NoMem)
// Has side-effects, requires chain.
Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode();
- } else {
- // Otherwise, no chain.
+ else // Otherwise, no chain.
Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode();
- }
- TreePatternNode *IIDNode = new TreePatternNode(new IntInit(IID));
+ TreePatternNode *IIDNode = new TreePatternNode(new IntInit(IID), 1);
Children.insert(Children.begin(), IIDNode);
}
- TreePatternNode *Result = new TreePatternNode(Operator, Children);
- Result->setName(Dag->getName());
+ unsigned NumResults = GetNumNodeResults(Operator, CDP);
+ TreePatternNode *Result = new TreePatternNode(Operator, Children, NumResults);
+ Result->setName(OpName);
+
+ if (!Dag->getName().empty()) {
+ assert(Result->getName().empty());
+ Result->setName(Dag->getName());
+ }
return Result;
}
+/// SimplifyTree - See if we can simplify this tree to eliminate something that
+/// will never match in favor of something obvious that will. This is here
+/// strictly as a convenience to target authors because it allows them to write
+/// more type generic things and have useless type casts fold away.
+///
+/// This returns true if any change is made.
+static bool SimplifyTree(TreePatternNode *&N) {
+ if (N->isLeaf())
+ return false;
+
+ // If we have a bitconvert with a resolved type and if the source and
+ // destination types are the same, then the bitconvert is useless, remove it.
+ if (N->getOperator()->getName() == "bitconvert" &&
+ N->getExtType(0).isConcrete() &&
+ N->getExtType(0) == N->getChild(0)->getExtType(0) &&
+ N->getName().empty()) {
+ N = N->getChild(0);
+ SimplifyTree(N);
+ return true;
+ }
+
+ // Walk all children.
+ bool MadeChange = false;
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) {
+ TreePatternNode *Child = N->getChild(i);
+ MadeChange |= SimplifyTree(Child);
+ N->setChild(i, Child);
+ }
+ return MadeChange;
+}
+
+
+
/// InferAllTypes - Infer/propagate as many types throughout the expression
/// patterns as possible. Return true if all types are inferred, false
/// otherwise. Throw an exception if a type contradiction is found.
-bool TreePattern::InferAllTypes() {
+bool TreePattern::
+InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) {
+ if (NamedNodes.empty())
+ ComputeNamedNodes();
+
bool MadeChange = true;
while (MadeChange) {
MadeChange = false;
- for (unsigned i = 0, e = Trees.size(); i != e; ++i)
+ for (unsigned i = 0, e = Trees.size(); i != e; ++i) {
MadeChange |= Trees[i]->ApplyTypeConstraints(*this, false);
+ MadeChange |= SimplifyTree(Trees[i]);
+ }
+
+ // If there are constraints on our named nodes, apply them.
+ for (StringMap<SmallVector<TreePatternNode*,1> >::iterator
+ I = NamedNodes.begin(), E = NamedNodes.end(); I != E; ++I) {
+ SmallVectorImpl<TreePatternNode*> &Nodes = I->second;
+
+ // If we have input named node types, propagate their types to the named
+ // values here.
+ if (InNamedTypes) {
+ // FIXME: Should be error?
+ assert(InNamedTypes->count(I->getKey()) &&
+ "Named node in output pattern but not input pattern?");
+
+ const SmallVectorImpl<TreePatternNode*> &InNodes =
+ InNamedTypes->find(I->getKey())->second;
+
+ // The input types should be fully resolved by now.
+ for (unsigned i = 0, e = Nodes.size(); i != e; ++i) {
+ // If this node is a register class, and it is the root of the pattern
+ // then we're mapping something onto an input register. We allow
+ // changing the type of the input register in this case. This allows
+ // us to match things like:
+ // def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>;
+ if (Nodes[i] == Trees[0] && Nodes[i]->isLeaf()) {
+ DefInit *DI = dynamic_cast<DefInit*>(Nodes[i]->getLeafValue());
+ if (DI && DI->getDef()->isSubClassOf("RegisterClass"))
+ continue;
+ }
+
+ assert(Nodes[i]->getNumTypes() == 1 &&
+ InNodes[0]->getNumTypes() == 1 &&
+ "FIXME: cannot name multiple result nodes yet");
+ MadeChange |= Nodes[i]->UpdateNodeType(0, InNodes[0]->getExtType(0),
+ *this);
+ }
+ }
+
+ // If there are multiple nodes with the same name, they must all have the
+ // same type.
+ if (I->second.size() > 1) {
+ for (unsigned i = 0, e = Nodes.size()-1; i != e; ++i) {
+ TreePatternNode *N1 = Nodes[i], *N2 = Nodes[i+1];
+ assert(N1->getNumTypes() == 1 && N2->getNumTypes() == 1 &&
+ "FIXME: cannot name multiple result nodes yet");
+
+ MadeChange |= N1->UpdateNodeType(0, N2->getExtType(0), *this);
+ MadeChange |= N2->UpdateNodeType(0, N1->getExtType(0), *this);
+ }
+ }
+ }
}
bool HasUnresolvedTypes = false;
@@ -1622,16 +1992,13 @@ void CodeGenDAGPatterns::ParseDefaultOperands() {
/// HandleUse - Given "Pat" a leaf in the pattern, check to see if it is an
/// instruction input. Return true if this is a real use.
static bool HandleUse(TreePattern *I, TreePatternNode *Pat,
- std::map<std::string, TreePatternNode*> &InstInputs,
- std::vector<Record*> &InstImpInputs) {
+ std::map<std::string, TreePatternNode*> &InstInputs) {
// No name -> not interesting.
if (Pat->getName().empty()) {
if (Pat->isLeaf()) {
DefInit *DI = dynamic_cast<DefInit*>(Pat->getLeafValue());
if (DI && DI->getDef()->isSubClassOf("RegisterClass"))
I->error("Input " + DI->getDef()->getName() + " must be named!");
- else if (DI && DI->getDef()->isSubClassOf("Register"))
- InstImpInputs.push_back(DI->getDef());
}
return false;
}
@@ -1677,10 +2044,9 @@ void CodeGenDAGPatterns::
FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
std::map<std::string, TreePatternNode*> &InstInputs,
std::map<std::string, TreePatternNode*>&InstResults,
- std::vector<Record*> &InstImpInputs,
std::vector<Record*> &InstImpResults) {
if (Pat->isLeaf()) {
- bool isUse = HandleUse(I, Pat, InstInputs, InstImpInputs);
+ bool isUse = HandleUse(I, Pat, InstInputs);
if (!isUse && Pat->getTransformFn())
I->error("Cannot specify a transform function for a non-input value!");
return;
@@ -1704,15 +2070,15 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
// If this is not a set, verify that the children nodes are not void typed,
// and recurse.
for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) {
- if (Pat->getChild(i)->getExtTypeNum(0) == MVT::isVoid)
+ if (Pat->getChild(i)->getNumTypes() == 0)
I->error("Cannot have void nodes inside of patterns!");
FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults,
- InstImpInputs, InstImpResults);
+ InstImpResults);
}
// If this is a non-leaf node with no children, treat it basically as if
// it were a leaf. This handles nodes like (imm).
- bool isUse = HandleUse(I, Pat, InstInputs, InstImpInputs);
+ bool isUse = HandleUse(I, Pat, InstInputs);
if (!isUse && Pat->getTransformFn())
I->error("Cannot specify a transform function for a non-input value!");
@@ -1753,8 +2119,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
// Verify and collect info from the computation.
FindPatternInputsAndOutputs(I, Pat->getChild(NumDests),
- InstInputs, InstResults,
- InstImpInputs, InstImpResults);
+ InstInputs, InstResults, InstImpResults);
}
//===----------------------------------------------------------------------===//
@@ -1766,10 +2131,12 @@ class InstAnalyzer {
bool &mayStore;
bool &mayLoad;
bool &HasSideEffects;
+ bool &IsVariadic;
public:
InstAnalyzer(const CodeGenDAGPatterns &cdp,
- bool &maystore, bool &mayload, bool &hse)
- : CDP(cdp), mayStore(maystore), mayLoad(mayload), HasSideEffects(hse){
+ bool &maystore, bool &mayload, bool &hse, bool &isv)
+ : CDP(cdp), mayStore(maystore), mayLoad(mayload), HasSideEffects(hse),
+ IsVariadic(isv) {
}
/// Analyze - Analyze the specified instruction, returning true if the
@@ -1818,6 +2185,7 @@ private:
if (OpInfo.hasProperty(SDNPMayStore)) mayStore = true;
if (OpInfo.hasProperty(SDNPMayLoad)) mayLoad = true;
if (OpInfo.hasProperty(SDNPSideEffect)) HasSideEffects = true;
+ if (OpInfo.hasProperty(SDNPVariadic)) IsVariadic = true;
if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) {
// If this is an intrinsic, analyze it.
@@ -1837,12 +2205,13 @@ private:
static void InferFromPattern(const CodeGenInstruction &Inst,
bool &MayStore, bool &MayLoad,
- bool &HasSideEffects,
+ bool &HasSideEffects, bool &IsVariadic,
const CodeGenDAGPatterns &CDP) {
- MayStore = MayLoad = HasSideEffects = false;
+ MayStore = MayLoad = HasSideEffects = IsVariadic = false;
bool HadPattern =
- InstAnalyzer(CDP, MayStore, MayLoad, HasSideEffects).Analyze(Inst.TheDef);
+ InstAnalyzer(CDP, MayStore, MayLoad, HasSideEffects, IsVariadic)
+ .Analyze(Inst.TheDef);
// InstAnalyzer only correctly analyzes mayStore/mayLoad so far.
if (Inst.mayStore) { // If the .td file explicitly sets mayStore, use it.
@@ -1880,6 +2249,9 @@ static void InferFromPattern(const CodeGenInstruction &Inst,
"which already inferred this.\n", Inst.TheDef->getName().c_str());
HasSideEffects = true;
}
+
+ if (Inst.isVariadic)
+ IsVariadic = true; // Can warn if we want.
}
/// ParseInstructions - Parse all of the instructions, inlining and resolving
@@ -1901,7 +2273,7 @@ void CodeGenDAGPatterns::ParseInstructions() {
std::vector<Record*> Results;
std::vector<Record*> Operands;
- CodeGenInstruction &InstInfo =Target.getInstruction(Instrs[i]->getName());
+ CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]);
if (InstInfo.OperandList.size() != 0) {
if (InstInfo.NumDefs == 0) {
@@ -1920,10 +2292,8 @@ void CodeGenDAGPatterns::ParseInstructions() {
// Create and insert the instruction.
std::vector<Record*> ImpResults;
- std::vector<Record*> ImpOperands;
Instructions.insert(std::make_pair(Instrs[i],
- DAGInstruction(0, Results, Operands, ImpResults,
- ImpOperands)));
+ DAGInstruction(0, Results, Operands, ImpResults)));
continue; // no pattern.
}
@@ -1945,20 +2315,19 @@ void CodeGenDAGPatterns::ParseInstructions() {
// in the instruction, including what reg class they are.
std::map<std::string, TreePatternNode*> InstResults;
- std::vector<Record*> InstImpInputs;
std::vector<Record*> InstImpResults;
// Verify that the top-level forms in the instruction are of void type, and
// fill in the InstResults map.
for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) {
TreePatternNode *Pat = I->getTree(j);
- if (Pat->getExtTypeNum(0) != MVT::isVoid)
+ if (Pat->getNumTypes() != 0)
I->error("Top-level forms in instruction pattern should have"
" void types");
// Find inputs and outputs, and verify the structure of the uses/defs.
FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults,
- InstImpInputs, InstImpResults);
+ InstImpResults);
}
// Now that we have inputs and outputs of the pattern, inspect the operands
@@ -1968,11 +2337,11 @@ void CodeGenDAGPatterns::ParseInstructions() {
// Parse the operands list from the (ops) list, validating it.
assert(I->getArgList().empty() && "Args list should still be empty here!");
- CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]->getName());
+ CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]);
// Check that all of the results occur first in the list.
std::vector<Record*> Results;
- TreePatternNode *Res0Node = NULL;
+ TreePatternNode *Res0Node = 0;
for (unsigned i = 0; i != NumResults; ++i) {
if (i == CGI.OperandList.size())
I->error("'" + InstResults.begin()->first +
@@ -2050,7 +2419,7 @@ void CodeGenDAGPatterns::ParseInstructions() {
OpNode->setTransformFn(0);
std::vector<TreePatternNode*> Children;
Children.push_back(OpNode);
- OpNode = new TreePatternNode(Xform, Children);
+ OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes());
}
ResultNodeOperands.push_back(OpNode);
@@ -2061,22 +2430,22 @@ void CodeGenDAGPatterns::ParseInstructions() {
" occurs in pattern but not in operands list!");
TreePatternNode *ResultPattern =
- new TreePatternNode(I->getRecord(), ResultNodeOperands);
+ new TreePatternNode(I->getRecord(), ResultNodeOperands,
+ GetNumNodeResults(I->getRecord(), *this));
// Copy fully inferred output node type to instruction result pattern.
- if (NumResults > 0)
- ResultPattern->setTypes(Res0Node->getExtTypes());
+ for (unsigned i = 0; i != NumResults; ++i)
+ ResultPattern->setType(i, Res0Node->getExtType(i));
// Create and insert the instruction.
- // FIXME: InstImpResults and InstImpInputs should not be part of
- // DAGInstruction.
- DAGInstruction TheInst(I, Results, Operands, InstImpResults, InstImpInputs);
+ // FIXME: InstImpResults should not be part of DAGInstruction.
+ DAGInstruction TheInst(I, Results, Operands, InstImpResults);
Instructions.insert(std::make_pair(I->getRecord(), TheInst));
// Use a temporary tree pattern to infer all types and make sure that the
// constructed result is correct. This depends on the instruction already
// being inserted into the Instructions map.
TreePattern Temp(I->getRecord(), ResultPattern, false, *this);
- Temp.InferAllTypes();
+ Temp.InferAllTypes(&I->getNamedNodesMap());
DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second;
TheInsertedInst.setResultPattern(Temp.getOnlyTree());
@@ -2165,24 +2534,6 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern,
if (SrcNames[I->first].first == 0)
Pattern->error("Pattern has input without matching name in output: $" +
I->first);
-
-#if 0
- const std::vector<unsigned char> &SrcTypeVec =
- SrcNames[I->first].first->getExtTypes();
- const std::vector<unsigned char> &DstTypeVec =
- I->second.first->getExtTypes();
- if (SrcTypeVec == DstTypeVec) continue;
-
- std::string SrcType, DstType;
- for (unsigned i = 0, e = SrcTypeVec.size(); i != e; ++i)
- SrcType += ":" + GetTypeName(SrcTypeVec[i]);
- for (unsigned i = 0, e = DstTypeVec.size(); i != e; ++i)
- DstType += ":" + GetTypeName(DstTypeVec[i]);
-
- Pattern->error("Variable $" + I->first +
- " has different types in source (" + SrcType +
- ") and dest (" + DstType + ") pattern!");
-#endif
}
// Scan all of the named values in the source pattern, rejecting them if the
@@ -2198,65 +2549,67 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern,
void CodeGenDAGPatterns::InferInstructionFlags() {
- std::map<std::string, CodeGenInstruction> &InstrDescs =
- Target.getInstructions();
- for (std::map<std::string, CodeGenInstruction>::iterator
- II = InstrDescs.begin(), E = InstrDescs.end(); II != E; ++II) {
- CodeGenInstruction &InstInfo = II->second;
+ const std::vector<const CodeGenInstruction*> &Instructions =
+ Target.getInstructionsByEnumValue();
+ for (unsigned i = 0, e = Instructions.size(); i != e; ++i) {
+ CodeGenInstruction &InstInfo =
+ const_cast<CodeGenInstruction &>(*Instructions[i]);
// Determine properties of the instruction from its pattern.
- bool MayStore, MayLoad, HasSideEffects;
- InferFromPattern(InstInfo, MayStore, MayLoad, HasSideEffects, *this);
+ bool MayStore, MayLoad, HasSideEffects, IsVariadic;
+ InferFromPattern(InstInfo, MayStore, MayLoad, HasSideEffects, IsVariadic,
+ *this);
InstInfo.mayStore = MayStore;
InstInfo.mayLoad = MayLoad;
InstInfo.hasSideEffects = HasSideEffects;
+ InstInfo.isVariadic = IsVariadic;
+ }
+}
+
+/// Given a pattern result with an unresolved type, see if we can find one
+/// instruction with an unresolved result type. Force this result type to an
+/// arbitrary element if it's possible types to converge results.
+static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) {
+ if (N->isLeaf())
+ return false;
+
+ // Analyze children.
+ for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)
+ if (ForceArbitraryInstResultType(N->getChild(i), TP))
+ return true;
+
+ if (!N->getOperator()->isSubClassOf("Instruction"))
+ return false;
+
+ // If this type is already concrete or completely unknown we can't do
+ // anything.
+ for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i) {
+ if (N->getExtType(i).isCompletelyUnknown() || N->getExtType(i).isConcrete())
+ continue;
+
+ // Otherwise, force its type to the first possibility (an arbitrary choice).
+ if (N->getExtType(i).MergeInTypeInfo(N->getExtType(i).getTypeList()[0], TP))
+ return true;
}
+
+ return false;
}
void CodeGenDAGPatterns::ParsePatterns() {
std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern");
for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
- DagInit *Tree = Patterns[i]->getValueAsDag("PatternToMatch");
- DefInit *OpDef = dynamic_cast<DefInit*>(Tree->getOperator());
- Record *Operator = OpDef->getDef();
- TreePattern *Pattern;
- if (Operator->getName() != "parallel")
- Pattern = new TreePattern(Patterns[i], Tree, true, *this);
- else {
- std::vector<Init*> Values;
- RecTy *ListTy = 0;
- for (unsigned j = 0, ee = Tree->getNumArgs(); j != ee; ++j) {
- Values.push_back(Tree->getArg(j));
- TypedInit *TArg = dynamic_cast<TypedInit*>(Tree->getArg(j));
- if (TArg == 0) {
- errs() << "In dag: " << Tree->getAsString();
- errs() << " -- Untyped argument in pattern\n";
- assert(0 && "Untyped argument in pattern");
- }
- if (ListTy != 0) {
- ListTy = resolveTypes(ListTy, TArg->getType());
- if (ListTy == 0) {
- errs() << "In dag: " << Tree->getAsString();
- errs() << " -- Incompatible types in pattern arguments\n";
- assert(0 && "Incompatible types in pattern arguments");
- }
- }
- else {
- ListTy = TArg->getType();
- }
- }
- ListInit *LI = new ListInit(Values, new ListRecTy(ListTy));
- Pattern = new TreePattern(Patterns[i], LI, true, *this);
- }
+ Record *CurPattern = Patterns[i];
+ DagInit *Tree = CurPattern->getValueAsDag("PatternToMatch");
+ TreePattern *Pattern = new TreePattern(CurPattern, Tree, true, *this);
// Inline pattern fragments into it.
Pattern->InlinePatternFragments();
- ListInit *LI = Patterns[i]->getValueAsListInit("ResultInstrs");
+ ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs");
if (LI->getSize() == 0) continue; // no pattern.
// Parse the instruction.
- TreePattern *Result = new TreePattern(Patterns[i], LI, false, *this);
+ TreePattern *Result = new TreePattern(CurPattern, LI, false, *this);
// Inline pattern fragments into it.
Result->InlinePatternFragments();
@@ -2270,38 +2623,61 @@ void CodeGenDAGPatterns::ParsePatterns() {
do {
// Infer as many types as possible. If we cannot infer all of them, we
// can never do anything with this pattern: report it to the user.
- InferredAllPatternTypes = Pattern->InferAllTypes();
+ InferredAllPatternTypes =
+ Pattern->InferAllTypes(&Pattern->getNamedNodesMap());
// Infer as many types as possible. If we cannot infer all of them, we
// can never do anything with this pattern: report it to the user.
- InferredAllResultTypes = Result->InferAllTypes();
+ InferredAllResultTypes =
+ Result->InferAllTypes(&Pattern->getNamedNodesMap());
+ IterateInference = false;
+
// Apply the type of the result to the source pattern. This helps us
// resolve cases where the input type is known to be a pointer type (which
// is considered resolved), but the result knows it needs to be 32- or
// 64-bits. Infer the other way for good measure.
- IterateInference = Pattern->getTree(0)->
- UpdateNodeType(Result->getTree(0)->getExtTypes(), *Result);
- IterateInference |= Result->getTree(0)->
- UpdateNodeType(Pattern->getTree(0)->getExtTypes(), *Result);
+ for (unsigned i = 0, e = std::min(Result->getTree(0)->getNumTypes(),
+ Pattern->getTree(0)->getNumTypes());
+ i != e; ++i) {
+ IterateInference = Pattern->getTree(0)->
+ UpdateNodeType(i, Result->getTree(0)->getExtType(i), *Result);
+ IterateInference |= Result->getTree(0)->
+ UpdateNodeType(i, Pattern->getTree(0)->getExtType(i), *Result);
+ }
+
+ // If our iteration has converged and the input pattern's types are fully
+ // resolved but the result pattern is not fully resolved, we may have a
+ // situation where we have two instructions in the result pattern and
+ // the instructions require a common register class, but don't care about
+ // what actual MVT is used. This is actually a bug in our modelling:
+ // output patterns should have register classes, not MVTs.
+ //
+ // In any case, to handle this, we just go through and disambiguate some
+ // arbitrary types to the result pattern's nodes.
+ if (!IterateInference && InferredAllPatternTypes &&
+ !InferredAllResultTypes)
+ IterateInference = ForceArbitraryInstResultType(Result->getTree(0),
+ *Result);
} while (IterateInference);
// Verify that we inferred enough types that we can do something with the
// pattern and result. If these fire the user has to add type casts.
if (!InferredAllPatternTypes)
Pattern->error("Could not infer all types in pattern!");
- if (!InferredAllResultTypes)
+ if (!InferredAllResultTypes) {
+ Pattern->dump();
Result->error("Could not infer all types in pattern result!");
+ }
// Validate that the input pattern is correct.
std::map<std::string, TreePatternNode*> InstInputs;
std::map<std::string, TreePatternNode*> InstResults;
- std::vector<Record*> InstImpInputs;
std::vector<Record*> InstImpResults;
for (unsigned j = 0, ee = Pattern->getNumTrees(); j != ee; ++j)
FindPatternInputsAndOutputs(Pattern, Pattern->getTree(j),
InstInputs, InstResults,
- InstImpInputs, InstImpResults);
+ InstImpResults);
// Promote the xform function to be an explicit node if set.
TreePatternNode *DstPattern = Result->getOnlyTree();
@@ -2312,25 +2688,29 @@ void CodeGenDAGPatterns::ParsePatterns() {
OpNode->setTransformFn(0);
std::vector<TreePatternNode*> Children;
Children.push_back(OpNode);
- OpNode = new TreePatternNode(Xform, Children);
+ OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes());
}
ResultNodeOperands.push_back(OpNode);
}
DstPattern = Result->getOnlyTree();
if (!DstPattern->isLeaf())
DstPattern = new TreePatternNode(DstPattern->getOperator(),
- ResultNodeOperands);
- DstPattern->setTypes(Result->getOnlyTree()->getExtTypes());
+ ResultNodeOperands,
+ DstPattern->getNumTypes());
+
+ for (unsigned i = 0, e = Result->getOnlyTree()->getNumTypes(); i != e; ++i)
+ DstPattern->setType(i, Result->getOnlyTree()->getExtType(i));
+
TreePattern Temp(Result->getRecord(), DstPattern, false, *this);
Temp.InferAllTypes();
AddPatternToMatch(Pattern,
- PatternToMatch(Patterns[i]->getValueAsListInit("Predicates"),
- Pattern->getTree(0),
- Temp.getOnlyTree(), InstImpResults,
- Patterns[i]->getValueAsInt("AddedComplexity"),
- Patterns[i]->getID()));
+ PatternToMatch(CurPattern->getValueAsListInit("Predicates"),
+ Pattern->getTree(0),
+ Temp.getOnlyTree(), InstImpResults,
+ CurPattern->getValueAsInt("AddedComplexity"),
+ CurPattern->getID()));
}
}
@@ -2364,13 +2744,15 @@ static void CombineChildVariants(TreePatternNode *Orig,
std::vector<TreePatternNode*> NewChildren;
for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i)
NewChildren.push_back(ChildVariants[i][Idxs[i]]);
- TreePatternNode *R = new TreePatternNode(Orig->getOperator(), NewChildren);
+ TreePatternNode *R = new TreePatternNode(Orig->getOperator(), NewChildren,
+ Orig->getNumTypes());
// Copy over properties.
R->setName(Orig->getName());
R->setPredicateFns(Orig->getPredicateFns());
R->setTransformFn(Orig->getTransformFn());
- R->setTypes(Orig->getExtTypes());
+ for (unsigned i = 0, e = Orig->getNumTypes(); i != e; ++i)
+ R->setType(i, Orig->getExtType(i));
// If this pattern cannot match, do not include it as a variant.
std::string ErrString;
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 37d633e..0a1362a 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -15,12 +15,14 @@
#ifndef CODEGEN_DAGPATTERNS_H
#define CODEGEN_DAGPATTERNS_H
+#include "CodeGenTarget.h"
+#include "CodeGenIntrinsics.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
#include <set>
#include <algorithm>
#include <vector>
-
-#include "CodeGenTarget.h"
-#include "CodeGenIntrinsics.h"
+#include <map>
namespace llvm {
class Record;
@@ -39,21 +41,107 @@ namespace llvm {
/// arbitrary integer, floating-point, and vector types, so only an unknown
/// value is needed.
namespace EEVT {
- enum DAGISelGenValueType {
- isUnknown = MVT::LAST_VALUETYPE
- };
+ /// TypeSet - This is either empty if it's completely unknown, or holds a set
+ /// of types. It is used during type inference because register classes can
+ /// have multiple possible types and we don't know which one they get until
+ /// type inference is complete.
+ ///
+ /// TypeSet can have three states:
+ /// Vector is empty: The type is completely unknown, it can be any valid
+ /// target type.
+ /// Vector has multiple constrained types: (e.g. v4i32 + v4f32) it is one
+ /// of those types only.
+ /// Vector has one concrete type: The type is completely known.
+ ///
+ class TypeSet {
+ SmallVector<MVT::SimpleValueType, 4> TypeVec;
+ public:
+ TypeSet() {}
+ TypeSet(MVT::SimpleValueType VT, TreePattern &TP);
+ TypeSet(const std::vector<MVT::SimpleValueType> &VTList);
+
+ bool isCompletelyUnknown() const { return TypeVec.empty(); }
+
+ bool isConcrete() const {
+ if (TypeVec.size() != 1) return false;
+ unsigned char T = TypeVec[0]; (void)T;
+ assert(T < MVT::LAST_VALUETYPE || T == MVT::iPTR || T == MVT::iPTRAny);
+ return true;
+ }
+
+ MVT::SimpleValueType getConcrete() const {
+ assert(isConcrete() && "Type isn't concrete yet");
+ return (MVT::SimpleValueType)TypeVec[0];
+ }
+
+ bool isDynamicallyResolved() const {
+ return getConcrete() == MVT::iPTR || getConcrete() == MVT::iPTRAny;
+ }
+
+ const SmallVectorImpl<MVT::SimpleValueType> &getTypeList() const {
+ assert(!TypeVec.empty() && "Not a type list!");
+ return TypeVec;
+ }
+
+ bool isVoid() const {
+ return TypeVec.size() == 1 && TypeVec[0] == MVT::isVoid;
+ }
+
+ /// hasIntegerTypes - Return true if this TypeSet contains any integer value
+ /// types.
+ bool hasIntegerTypes() const;
+
+ /// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or
+ /// a floating point value type.
+ bool hasFloatingPointTypes() const;
+
+ /// hasVectorTypes - Return true if this TypeSet contains a vector value
+ /// type.
+ bool hasVectorTypes() const;
+
+ /// getName() - Return this TypeSet as a string.
+ std::string getName() const;
+
+ /// MergeInTypeInfo - This merges in type information from the specified
+ /// argument. If 'this' changes, it returns true. If the two types are
+ /// contradictory (e.g. merge f32 into i32) then this throws an exception.
+ bool MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP);
+
+ bool MergeInTypeInfo(MVT::SimpleValueType InVT, TreePattern &TP) {
+ return MergeInTypeInfo(EEVT::TypeSet(InVT, TP), TP);
+ }
+
+ /// Force this type list to only contain integer types.
+ bool EnforceInteger(TreePattern &TP);
- /// isExtIntegerInVTs - Return true if the specified extended value type
- /// vector contains iAny or an integer value type.
- bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs);
+ /// Force this type list to only contain floating point types.
+ bool EnforceFloatingPoint(TreePattern &TP);
- /// isExtFloatingPointInVTs - Return true if the specified extended value
- /// type vector contains fAny or a FP value type.
- bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs);
+ /// EnforceScalar - Remove all vector types from this type list.
+ bool EnforceScalar(TreePattern &TP);
- /// isExtVectorinVTs - Return true if the specified extended value type
- /// vector contains vAny or a vector value type.
- bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs);
+ /// EnforceVector - Remove all non-vector types from this type list.
+ bool EnforceVector(TreePattern &TP);
+
+ /// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update
+ /// this an other based on this information.
+ bool EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP);
+
+ /// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type
+ /// whose element is VT.
+ bool EnforceVectorEltTypeIs(EEVT::TypeSet &VT, TreePattern &TP);
+
+ bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; }
+ bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; }
+
+ private:
+ /// FillWithPossibleTypes - Set to all legal types and return true, only
+ /// valid on completely unknown type sets. If Pred is non-null, only MVTs
+ /// that pass the predicate are added.
+ bool FillWithPossibleTypes(TreePattern &TP,
+ bool (*Pred)(MVT::SimpleValueType) = 0,
+ const char *PredicateName = 0);
+ };
}
/// Set type used to track multiply used variables in patterns
@@ -72,7 +160,7 @@ struct SDTypeConstraint {
union { // The discriminated union.
struct {
- unsigned char VT;
+ MVT::SimpleValueType VT;
} SDTCisVT_Info;
struct {
unsigned OtherOperandNum;
@@ -94,11 +182,6 @@ struct SDTypeConstraint {
/// exception.
bool ApplyTypeConstraint(TreePatternNode *N, const SDNodeInfo &NodeInfo,
TreePattern &TP) const;
-
- /// getOperandNum - Return the node corresponding to operand #OpNo in tree
- /// N, which has NumResults results.
- TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N,
- unsigned NumResults) const;
};
/// SDNodeInfo - One of these records is created for each SDNode instance in
@@ -116,6 +199,9 @@ public:
SDNodeInfo(Record *R); // Parse the specified record.
unsigned getNumResults() const { return NumResults; }
+
+ /// getNumOperands - This is the number of operands required or -1 if
+ /// variadic.
int getNumOperands() const { return NumOperands; }
Record *getRecord() const { return Def; }
const std::string &getEnumName() const { return EnumName; }
@@ -127,8 +213,8 @@ public:
/// getKnownType - If the type constraints on this node imply a fixed type
/// (e.g. all stores return void, etc), then return it as an
- /// MVT::SimpleValueType. Otherwise, return EEVT::isUnknown.
- unsigned getKnownType() const;
+ /// MVT::SimpleValueType. Otherwise, return MVT::Other.
+ MVT::SimpleValueType getKnownType(unsigned ResNo) const;
/// hasProperty - Return true if this node has the specified property.
///
@@ -150,10 +236,10 @@ public:
/// patterns), and as such should be ref counted. We currently just leak all
/// TreePatternNode objects!
class TreePatternNode {
- /// The inferred type for this node, or EEVT::isUnknown if it hasn't
- /// been determined yet. This is a std::vector because during inference
- /// there may be multiple possible types.
- std::vector<unsigned char> Types;
+ /// The type of each node result. Before and during type inference, each
+ /// result may be a set of possible types. After (successful) type inference,
+ /// each is a single concrete type.
+ SmallVector<EEVT::TypeSet, 1> Types;
/// Operator - The Record for the operator if this is an interior node (not
/// a leaf).
@@ -177,41 +263,41 @@ class TreePatternNode {
std::vector<TreePatternNode*> Children;
public:
- TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch)
- : Types(), Operator(Op), Val(0), TransformFn(0),
- Children(Ch) { Types.push_back(EEVT::isUnknown); }
- TreePatternNode(Init *val) // leaf ctor
- : Types(), Operator(0), Val(val), TransformFn(0) {
- Types.push_back(EEVT::isUnknown);
+ TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch,
+ unsigned NumResults)
+ : Operator(Op), Val(0), TransformFn(0), Children(Ch) {
+ Types.resize(NumResults);
+ }
+ TreePatternNode(Init *val, unsigned NumResults) // leaf ctor
+ : Operator(0), Val(val), TransformFn(0) {
+ Types.resize(NumResults);
}
~TreePatternNode();
const std::string &getName() const { return Name; }
- void setName(const std::string &N) { Name = N; }
+ void setName(StringRef N) { Name.assign(N.begin(), N.end()); }
bool isLeaf() const { return Val != 0; }
- bool hasTypeSet() const {
- return (Types[0] < MVT::LAST_VALUETYPE) || (Types[0] == MVT::iPTR) ||
- (Types[0] == MVT::iPTRAny);
- }
- bool isTypeCompletelyUnknown() const {
- return Types[0] == EEVT::isUnknown;
+
+ // Type accessors.
+ unsigned getNumTypes() const { return Types.size(); }
+ MVT::SimpleValueType getType(unsigned ResNo) const {
+ return Types[ResNo].getConcrete();
}
- bool isTypeDynamicallyResolved() const {
- return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny);
+ const SmallVectorImpl<EEVT::TypeSet> &getExtTypes() const { return Types; }
+ const EEVT::TypeSet &getExtType(unsigned ResNo) const { return Types[ResNo]; }
+ EEVT::TypeSet &getExtType(unsigned ResNo) { return Types[ResNo]; }
+ void setType(unsigned ResNo, const EEVT::TypeSet &T) { Types[ResNo] = T; }
+
+ bool hasTypeSet(unsigned ResNo) const {
+ return Types[ResNo].isConcrete();
}
- MVT::SimpleValueType getTypeNum(unsigned Num) const {
- assert(hasTypeSet() && "Doesn't have a type yet!");
- assert(Types.size() > Num && "Type num out of range!");
- return (MVT::SimpleValueType)Types[Num];
+ bool isTypeCompletelyUnknown(unsigned ResNo) const {
+ return Types[ResNo].isCompletelyUnknown();
}
- unsigned char getExtTypeNum(unsigned Num) const {
- assert(Types.size() > Num && "Extended type num out of range!");
- return Types[Num];
+ bool isTypeDynamicallyResolved(unsigned ResNo) const {
+ return Types[ResNo].isDynamicallyResolved();
}
- const std::vector<unsigned char> &getExtTypes() const { return Types; }
- void setTypes(const std::vector<unsigned char> &T) { Types = T; }
- void removeTypes() { Types = std::vector<unsigned char>(1, EEVT::isUnknown); }
Init *getLeafValue() const { assert(isLeaf()); return Val; }
Record *getOperator() const { assert(!isLeaf()); return Operator; }
@@ -304,17 +390,22 @@ public: // Higher level manipulation routines.
/// information. If N already contains a conflicting type, then throw an
/// exception. This returns true if any information was updated.
///
- bool UpdateNodeType(const std::vector<unsigned char> &ExtVTs,
- TreePattern &TP);
- bool UpdateNodeType(unsigned char ExtVT, TreePattern &TP) {
- std::vector<unsigned char> ExtVTs(1, ExtVT);
- return UpdateNodeType(ExtVTs, TP);
+ bool UpdateNodeType(unsigned ResNo, const EEVT::TypeSet &InTy,
+ TreePattern &TP) {
+ return Types[ResNo].MergeInTypeInfo(InTy, TP);
+ }
+
+ bool UpdateNodeType(unsigned ResNo, MVT::SimpleValueType InTy,
+ TreePattern &TP) {
+ return Types[ResNo].MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP);
}
/// ContainsUnresolvedType - Return true if this tree contains any
/// unresolved types.
bool ContainsUnresolvedType() const {
- if (!hasTypeSet() && !isTypeDynamicallyResolved()) return true;
+ for (unsigned i = 0, e = Types.size(); i != e; ++i)
+ if (!Types[i].isConcrete()) return true;
+
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
if (getChild(i)->ContainsUnresolvedType()) return true;
return false;
@@ -340,6 +431,10 @@ class TreePattern {
///
std::vector<TreePatternNode*> Trees;
+ /// NamedNodes - This is all of the nodes that have names in the trees in this
+ /// pattern.
+ StringMap<SmallVector<TreePatternNode*,1> > NamedNodes;
+
/// TheRecord - The actual TableGen record corresponding to this pattern.
///
Record *TheRecord;
@@ -375,6 +470,12 @@ public:
assert(Trees.size() == 1 && "Doesn't have exactly one pattern!");
return Trees[0];
}
+
+ const StringMap<SmallVector<TreePatternNode*,1> > &getNamedNodesMap() {
+ if (NamedNodes.empty())
+ ComputeNamedNodes();
+ return NamedNodes;
+ }
/// getRecord - Return the actual TableGen record corresponding to this
/// pattern.
@@ -401,7 +502,8 @@ public:
/// InferAllTypes - Infer/propagate as many types throughout the expression
/// patterns as possible. Return true if all types are inferred, false
/// otherwise. Throw an exception if a type contradiction is found.
- bool InferAllTypes();
+ bool InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> >
+ *NamedTypes=0);
/// error - Throw an exception, prefixing it with information about this
/// pattern.
@@ -411,7 +513,9 @@ public:
void dump() const;
private:
- TreePatternNode *ParseTreePattern(DagInit *DI);
+ TreePatternNode *ParseTreePattern(Init *DI, StringRef OpName);
+ void ComputeNamedNodes();
+ void ComputeNamedNodes(TreePatternNode *N);
};
/// DAGDefaultOperand - One of these is created for each PredicateOperand
@@ -425,23 +529,19 @@ class DAGInstruction {
std::vector<Record*> Results;
std::vector<Record*> Operands;
std::vector<Record*> ImpResults;
- std::vector<Record*> ImpOperands;
TreePatternNode *ResultPattern;
public:
DAGInstruction(TreePattern *TP,
const std::vector<Record*> &results,
const std::vector<Record*> &operands,
- const std::vector<Record*> &impresults,
- const std::vector<Record*> &impoperands)
+ const std::vector<Record*> &impresults)
: Pattern(TP), Results(results), Operands(operands),
- ImpResults(impresults), ImpOperands(impoperands),
- ResultPattern(0) {}
+ ImpResults(impresults), ResultPattern(0) {}
const TreePattern *getPattern() const { return Pattern; }
unsigned getNumResults() const { return Results.size(); }
unsigned getNumOperands() const { return Operands.size(); }
unsigned getNumImpResults() const { return ImpResults.size(); }
- unsigned getNumImpOperands() const { return ImpOperands.size(); }
const std::vector<Record*>& getImpResults() const { return ImpResults; }
void setResultPattern(TreePatternNode *R) { ResultPattern = R; }
@@ -461,11 +561,6 @@ public:
return ImpResults[RN];
}
- Record *getImpOperand(unsigned ON) const {
- assert(ON < ImpOperands.size());
- return ImpOperands[ON];
- }
-
TreePatternNode *getResultPattern() const { return ResultPattern; }
};
@@ -494,6 +589,10 @@ public:
unsigned getAddedComplexity() const { return AddedComplexity; }
std::string getPredicateCheck() const;
+
+ /// Compute the complexity metric for the input pattern. This roughly
+ /// corresponds to the number of nodes that are covered.
+ unsigned getPatternComplexity(const CodeGenDAGPatterns &CGP) const;
};
// Deterministic comparison of Record*.
@@ -591,6 +690,11 @@ public:
assert(PatternFragments.count(R) && "Invalid pattern fragment request!");
return PatternFragments.find(R)->second;
}
+ TreePattern *getPatternFragmentIfRead(Record *R) const {
+ if (!PatternFragments.count(R)) return 0;
+ return PatternFragments.find(R)->second;
+ }
+
typedef std::map<Record*, TreePattern*, RecordPtrCmp>::const_iterator
pf_iterator;
pf_iterator pf_begin() const { return PatternFragments.begin(); }
@@ -637,7 +741,6 @@ private:
TreePatternNode*> &InstInputs,
std::map<std::string,
TreePatternNode*> &InstResults,
- std::vector<Record*> &InstImpInputs,
std::vector<Record*> &InstImpResults);
};
} // end namespace llvm
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index f5b52ec..99d196c 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenInstruction.h"
+#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
@@ -123,36 +124,43 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq");
hasOptionalDef = false;
isVariadic = false;
+ ImplicitDefs = R->getValueAsListOfDefs("Defs");
+ ImplicitUses = R->getValueAsListOfDefs("Uses");
if (neverHasSideEffects + hasSideEffects > 1)
throw R->getName() + ": multiple conflicting side-effect flags set!";
- DagInit *DI;
- try {
- DI = R->getValueAsDag("OutOperandList");
- } catch (...) {
- // Error getting operand list, just ignore it (sparcv9).
- AsmString.clear();
- OperandList.clear();
- return;
- }
- NumDefs = DI->getNumArgs();
-
- DagInit *IDI;
- try {
- IDI = R->getValueAsDag("InOperandList");
- } catch (...) {
- // Error getting operand list, just ignore it (sparcv9).
- AsmString.clear();
- OperandList.clear();
- return;
- }
- DI = (DagInit*)(new BinOpInit(BinOpInit::CONCAT, DI, IDI, new DagRecTy))->Fold(R, 0);
-
+ DagInit *OutDI = R->getValueAsDag("OutOperandList");
+
+ if (DefInit *Init = dynamic_cast<DefInit*>(OutDI->getOperator())) {
+ if (Init->getDef()->getName() != "outs")
+ throw R->getName() + ": invalid def name for output list: use 'outs'";
+ } else
+ throw R->getName() + ": invalid output list: use 'outs'";
+
+ NumDefs = OutDI->getNumArgs();
+
+ DagInit *InDI = R->getValueAsDag("InOperandList");
+ if (DefInit *Init = dynamic_cast<DefInit*>(InDI->getOperator())) {
+ if (Init->getDef()->getName() != "ins")
+ throw R->getName() + ": invalid def name for input list: use 'ins'";
+ } else
+ throw R->getName() + ": invalid input list: use 'ins'";
+
unsigned MIOperandNo = 0;
std::set<std::string> OperandNames;
- for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) {
- DefInit *Arg = dynamic_cast<DefInit*>(DI->getArg(i));
+ for (unsigned i = 0, e = InDI->getNumArgs()+OutDI->getNumArgs(); i != e; ++i){
+ Init *ArgInit;
+ std::string ArgName;
+ if (i < NumDefs) {
+ ArgInit = OutDI->getArg(i);
+ ArgName = OutDI->getArgName(i);
+ } else {
+ ArgInit = InDI->getArg(i-NumDefs);
+ ArgName = InDI->getArgName(i-NumDefs);
+ }
+
+ DefInit *Arg = dynamic_cast<DefInit*>(ArgInit);
if (!Arg)
throw "Illegal operand for the '" + R->getName() + "' instruction!";
@@ -189,14 +197,14 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
"' in '" + R->getName() + "' instruction!";
// Check that the operand has a name and that it's unique.
- if (DI->getArgName(i).empty())
+ if (ArgName.empty())
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
" has no name!";
- if (!OperandNames.insert(DI->getArgName(i)).second)
+ if (!OperandNames.insert(ArgName).second)
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
" has the same name as a previous operand!";
- OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod,
+ OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod,
MIOperandNo, NumOps, MIOpInfo));
MIOperandNo += NumOps;
}
@@ -287,3 +295,22 @@ CodeGenInstruction::ParseOperandName(const std::string &Op,
// Otherwise, didn't find it!
throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
}
+
+
+/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
+/// implicit def and it has a known VT, return the VT, otherwise return
+/// MVT::Other.
+MVT::SimpleValueType CodeGenInstruction::
+HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
+ if (ImplicitDefs.empty()) return MVT::Other;
+
+ // Check to see if the first implicit def has a resolvable type.
+ Record *FirstImplicitDef = ImplicitDefs[0];
+ assert(FirstImplicitDef->isSubClassOf("Register"));
+ const std::vector<MVT::SimpleValueType> &RegVTs =
+ TargetInfo.getRegisterVTs(FirstImplicitDef);
+ if (RegVTs.size() == 1)
+ return RegVTs[0];
+ return MVT::Other;
+}
+
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index aae2cac..946c2d0 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -22,6 +22,7 @@
namespace llvm {
class Record;
class DagInit;
+ class CodeGenTarget;
class CodeGenInstruction {
public:
@@ -105,7 +106,8 @@ namespace llvm {
MINumOperands(MINO), MIOperandInfo(MIOI) {}
};
- /// NumDefs - Number of def operands declared.
+ /// NumDefs - Number of def operands declared, this is the number of
+ /// elements in the instruction's (outs) list.
///
unsigned NumDefs;
@@ -113,6 +115,10 @@ namespace llvm {
/// type (which is a record).
std::vector<OperandInfo> OperandList;
+ /// ImplicitDefs/ImplicitUses - These are lists of registers that are
+ /// implicitly defined and used by the instruction.
+ std::vector<Record*> ImplicitDefs, ImplicitUses;
+
// Various boolean values we track for the instruction.
bool isReturn;
bool isBranch;
@@ -178,6 +184,12 @@ namespace llvm {
/// non-empty name. If the instruction does not have an operand with the
/// specified name, throw an exception.
unsigned getOperandNamed(const std::string &Name) const;
+
+ /// HasOneImplicitDefWithKnownVT - If the instruction has at least one
+ /// implicit def and it has a known VT, return the VT, otherwise return
+ /// MVT::Other.
+ MVT::SimpleValueType
+ HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const;
};
}
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index 2688091..0392895 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -18,6 +18,7 @@
#include "CodeGenIntrinsics.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
using namespace llvm;
@@ -120,24 +121,21 @@ const std::string &CodeGenTarget::getName() const {
}
std::string CodeGenTarget::getInstNamespace() const {
- std::string InstNS;
-
for (inst_iterator i = inst_begin(), e = inst_end(); i != e; ++i) {
- InstNS = i->second.Namespace;
-
- // Make sure not to pick up "TargetInstrInfo" by accidentally getting
+ // Make sure not to pick up "TargetOpcode" by accidentally getting
// the namespace off the PHI instruction or something.
- if (InstNS != "TargetInstrInfo")
- break;
+ if ((*i)->Namespace != "TargetOpcode")
+ return (*i)->Namespace;
}
- return InstNS;
+ return "";
}
Record *CodeGenTarget::getInstructionSet() const {
return TargetRec->getValueAsDef("InstructionSet");
}
+
/// getAsmParser - Return the AssemblyParser definition for this target.
///
Record *CodeGenTarget::getAsmParser() const {
@@ -184,19 +182,23 @@ void CodeGenTarget::ReadRegisterClasses() const {
RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
}
-std::vector<unsigned char> CodeGenTarget::getRegisterVTs(Record *R) const {
- std::vector<unsigned char> Result;
+std::vector<MVT::SimpleValueType> CodeGenTarget::
+getRegisterVTs(Record *R) const {
+ std::vector<MVT::SimpleValueType> Result;
const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
const CodeGenRegisterClass &RC = RegisterClasses[i];
for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) {
if (R == RC.Elements[ei]) {
const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes();
- for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
- Result.push_back(InVTs[i]);
+ Result.insert(Result.end(), InVTs.begin(), InVTs.end());
}
}
}
+
+ // Remove duplicates.
+ array_pod_sort(Result.begin(), Result.end());
+ Result.erase(std::unique(Result.begin(), Result.end()), Result.end());
return Result;
}
@@ -277,98 +279,92 @@ void CodeGenTarget::ReadInstructions() const {
for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
std::string AsmStr = Insts[i]->getValueAsString(InstFormatName);
- Instructions.insert(std::make_pair(Insts[i]->getName(),
- CodeGenInstruction(Insts[i], AsmStr)));
+ Instructions[Insts[i]] = new CodeGenInstruction(Insts[i], AsmStr);
}
}
-/// getInstructionsByEnumValue - Return all of the instructions defined by the
-/// target, ordered by their enum value.
-void CodeGenTarget::
-getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
- &NumberedInstructions) {
- std::map<std::string, CodeGenInstruction>::const_iterator I;
- I = getInstructions().find("PHI");
- if (I == Instructions.end()) throw "Could not find 'PHI' instruction!";
- const CodeGenInstruction *PHI = &I->second;
-
- I = getInstructions().find("INLINEASM");
- if (I == Instructions.end()) throw "Could not find 'INLINEASM' instruction!";
- const CodeGenInstruction *INLINEASM = &I->second;
-
- I = getInstructions().find("DBG_LABEL");
- if (I == Instructions.end()) throw "Could not find 'DBG_LABEL' instruction!";
- const CodeGenInstruction *DBG_LABEL = &I->second;
+static const CodeGenInstruction *
+GetInstByName(const char *Name,
+ const DenseMap<const Record*, CodeGenInstruction*> &Insts) {
+ const Record *Rec = Records.getDef(Name);
- I = getInstructions().find("EH_LABEL");
- if (I == Instructions.end()) throw "Could not find 'EH_LABEL' instruction!";
- const CodeGenInstruction *EH_LABEL = &I->second;
-
- I = getInstructions().find("GC_LABEL");
- if (I == Instructions.end()) throw "Could not find 'GC_LABEL' instruction!";
- const CodeGenInstruction *GC_LABEL = &I->second;
-
- I = getInstructions().find("KILL");
- if (I == Instructions.end()) throw "Could not find 'KILL' instruction!";
- const CodeGenInstruction *KILL = &I->second;
-
- I = getInstructions().find("EXTRACT_SUBREG");
- if (I == Instructions.end())
- throw "Could not find 'EXTRACT_SUBREG' instruction!";
- const CodeGenInstruction *EXTRACT_SUBREG = &I->second;
-
- I = getInstructions().find("INSERT_SUBREG");
- if (I == Instructions.end())
- throw "Could not find 'INSERT_SUBREG' instruction!";
- const CodeGenInstruction *INSERT_SUBREG = &I->second;
-
- I = getInstructions().find("IMPLICIT_DEF");
- if (I == Instructions.end())
- throw "Could not find 'IMPLICIT_DEF' instruction!";
- const CodeGenInstruction *IMPLICIT_DEF = &I->second;
-
- I = getInstructions().find("SUBREG_TO_REG");
- if (I == Instructions.end())
- throw "Could not find 'SUBREG_TO_REG' instruction!";
- const CodeGenInstruction *SUBREG_TO_REG = &I->second;
+ DenseMap<const Record*, CodeGenInstruction*>::const_iterator
+ I = Insts.find(Rec);
+ if (Rec == 0 || I == Insts.end())
+ throw std::string("Could not find '") + Name + "' instruction!";
+ return I->second;
+}
- I = getInstructions().find("COPY_TO_REGCLASS");
- if (I == Instructions.end())
- throw "Could not find 'COPY_TO_REGCLASS' instruction!";
- const CodeGenInstruction *COPY_TO_REGCLASS = &I->second;
+namespace {
+/// SortInstByName - Sorting predicate to sort instructions by name.
+///
+struct SortInstByName {
+ bool operator()(const CodeGenInstruction *Rec1,
+ const CodeGenInstruction *Rec2) const {
+ return Rec1->TheDef->getName() < Rec2->TheDef->getName();
+ }
+};
+}
- I = getInstructions().find("DBG_VALUE");
- if (I == Instructions.end())
- throw "Could not find 'DBG_VALUE' instruction!";
- const CodeGenInstruction *DBG_VALUE = &I->second;
+/// getInstructionsByEnumValue - Return all of the instructions defined by the
+/// target, ordered by their enum value.
+void CodeGenTarget::ComputeInstrsByEnum() const {
+ const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();
+ const CodeGenInstruction *PHI = GetInstByName("PHI", Insts);
+ const CodeGenInstruction *INLINEASM = GetInstByName("INLINEASM", Insts);
+ const CodeGenInstruction *DBG_LABEL = GetInstByName("DBG_LABEL", Insts);
+ const CodeGenInstruction *EH_LABEL = GetInstByName("EH_LABEL", Insts);
+ const CodeGenInstruction *GC_LABEL = GetInstByName("GC_LABEL", Insts);
+ const CodeGenInstruction *KILL = GetInstByName("KILL", Insts);
+ const CodeGenInstruction *EXTRACT_SUBREG =
+ GetInstByName("EXTRACT_SUBREG", Insts);
+ const CodeGenInstruction *INSERT_SUBREG =
+ GetInstByName("INSERT_SUBREG", Insts);
+ const CodeGenInstruction *IMPLICIT_DEF = GetInstByName("IMPLICIT_DEF", Insts);
+ const CodeGenInstruction *SUBREG_TO_REG =
+ GetInstByName("SUBREG_TO_REG", Insts);
+ const CodeGenInstruction *COPY_TO_REGCLASS =
+ GetInstByName("COPY_TO_REGCLASS", Insts);
+ const CodeGenInstruction *DBG_VALUE = GetInstByName("DBG_VALUE", Insts);
// Print out the rest of the instructions now.
- NumberedInstructions.push_back(PHI);
- NumberedInstructions.push_back(INLINEASM);
- NumberedInstructions.push_back(DBG_LABEL);
- NumberedInstructions.push_back(EH_LABEL);
- NumberedInstructions.push_back(GC_LABEL);
- NumberedInstructions.push_back(KILL);
- NumberedInstructions.push_back(EXTRACT_SUBREG);
- NumberedInstructions.push_back(INSERT_SUBREG);
- NumberedInstructions.push_back(IMPLICIT_DEF);
- NumberedInstructions.push_back(SUBREG_TO_REG);
- NumberedInstructions.push_back(COPY_TO_REGCLASS);
- NumberedInstructions.push_back(DBG_VALUE);
- for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II)
- if (&II->second != PHI &&
- &II->second != INLINEASM &&
- &II->second != DBG_LABEL &&
- &II->second != EH_LABEL &&
- &II->second != GC_LABEL &&
- &II->second != KILL &&
- &II->second != EXTRACT_SUBREG &&
- &II->second != INSERT_SUBREG &&
- &II->second != IMPLICIT_DEF &&
- &II->second != SUBREG_TO_REG &&
- &II->second != COPY_TO_REGCLASS &&
- &II->second != DBG_VALUE)
- NumberedInstructions.push_back(&II->second);
+ InstrsByEnum.push_back(PHI);
+ InstrsByEnum.push_back(INLINEASM);
+ InstrsByEnum.push_back(DBG_LABEL);
+ InstrsByEnum.push_back(EH_LABEL);
+ InstrsByEnum.push_back(GC_LABEL);
+ InstrsByEnum.push_back(KILL);
+ InstrsByEnum.push_back(EXTRACT_SUBREG);
+ InstrsByEnum.push_back(INSERT_SUBREG);
+ InstrsByEnum.push_back(IMPLICIT_DEF);
+ InstrsByEnum.push_back(SUBREG_TO_REG);
+ InstrsByEnum.push_back(COPY_TO_REGCLASS);
+ InstrsByEnum.push_back(DBG_VALUE);
+
+ unsigned EndOfPredefines = InstrsByEnum.size();
+
+ for (DenseMap<const Record*, CodeGenInstruction*>::const_iterator
+ I = Insts.begin(), E = Insts.end(); I != E; ++I) {
+ const CodeGenInstruction *CGI = I->second;
+ if (CGI != PHI &&
+ CGI != INLINEASM &&
+ CGI != DBG_LABEL &&
+ CGI != EH_LABEL &&
+ CGI != GC_LABEL &&
+ CGI != KILL &&
+ CGI != EXTRACT_SUBREG &&
+ CGI != INSERT_SUBREG &&
+ CGI != IMPLICIT_DEF &&
+ CGI != SUBREG_TO_REG &&
+ CGI != COPY_TO_REGCLASS &&
+ CGI != DBG_VALUE)
+ InstrsByEnum.push_back(CGI);
+ }
+
+ // All of the instructions are now in random order based on the map iteration.
+ // Sort them by name.
+ std::sort(InstrsByEnum.begin()+EndOfPredefines, InstrsByEnum.end(),
+ SortInstByName());
}
@@ -404,6 +400,8 @@ ComplexPattern::ComplexPattern(Record *R) {
Properties |= 1 << SDNPSideEffect;
} else if (PropList[i]->getName() == "SDNPMemOperand") {
Properties |= 1 << SDNPMemOperand;
+ } else if (PropList[i]->getName() == "SDNPVariadic") {
+ Properties |= 1 << SDNPVariadic;
} else {
errs() << "Unsupported SD Node property '" << PropList[i]->getName()
<< "' on ComplexPattern '" << R->getName() << "'!\n";
@@ -495,15 +493,17 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
}
if (EVT(VT).isOverloaded()) {
OverloadedVTs.push_back(VT);
- isOverloaded |= true;
+ isOverloaded = true;
}
+
+ // Reject invalid types.
+ if (VT == MVT::isVoid)
+ throw "Intrinsic '" + DefName + " has void in result type list!";
+
IS.RetVTs.push_back(VT);
IS.RetTypeDefs.push_back(TyEl);
}
-
- if (IS.RetVTs.size() == 0)
- throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!";
-
+
// Parse the list of parameter types.
TypeList = R->getValueAsListInit("ParamTypes");
for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
@@ -524,10 +524,16 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
"Expected iAny or vAny type");
} else
VT = getValueType(TyEl->getValueAsDef("VT"));
+
if (EVT(VT).isOverloaded()) {
OverloadedVTs.push_back(VT);
- isOverloaded |= true;
+ isOverloaded = true;
}
+
+ // Reject invalid types.
+ if (VT == MVT::isVoid && i != e-1 /*void at end means varargs*/)
+ throw "Intrinsic '" + DefName + " has void in result type list!";
+
IS.ParamVTs.push_back(VT);
IS.ParamTypeDefs.push_back(TyEl);
}
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index 07bc54d..2926418 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -17,11 +17,11 @@
#ifndef CODEGEN_TARGET_H
#define CODEGEN_TARGET_H
-#include "llvm/Support/raw_ostream.h"
#include "CodeGenRegisters.h"
#include "CodeGenInstruction.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/DenseMap.h"
#include <algorithm>
-#include <map>
namespace llvm {
@@ -43,7 +43,8 @@ enum SDNP {
SDNPMayLoad,
SDNPMayStore,
SDNPSideEffect,
- SDNPMemOperand
+ SDNPMemOperand,
+ SDNPVariadic
};
/// getValueType - Return the MVT::SimpleValueType that the specified TableGen
@@ -62,7 +63,7 @@ std::string getQualifiedName(const Record *R);
class CodeGenTarget {
Record *TargetRec;
- mutable std::map<std::string, CodeGenInstruction> Instructions;
+ mutable DenseMap<const Record*, CodeGenInstruction*> Instructions;
mutable std::vector<CodeGenRegister> Registers;
mutable std::vector<CodeGenRegisterClass> RegisterClasses;
mutable std::vector<MVT::SimpleValueType> LegalValueTypes;
@@ -70,6 +71,8 @@ class CodeGenTarget {
void ReadRegisterClasses() const;
void ReadInstructions() const;
void ReadLegalValueTypes() const;
+
+ mutable std::vector<const CodeGenInstruction*> InstrsByEnum;
public:
CodeGenTarget();
@@ -167,7 +170,7 @@ public:
/// getRegisterVTs - Find the union of all possible SimpleValueTypes for the
/// specified physical register.
- std::vector<unsigned char> getRegisterVTs(Record *R) const;
+ std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const;
const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const {
if (LegalValueTypes.empty()) ReadLegalValueTypes();
@@ -183,37 +186,40 @@ public:
return false;
}
- /// getInstructions - Return all of the instructions defined for this target.
- ///
- const std::map<std::string, CodeGenInstruction> &getInstructions() const {
+private:
+ DenseMap<const Record*, CodeGenInstruction*> &getInstructions() const {
if (Instructions.empty()) ReadInstructions();
return Instructions;
}
- std::map<std::string, CodeGenInstruction> &getInstructions() {
+public:
+
+ CodeGenInstruction &getInstruction(const Record *InstRec) const {
if (Instructions.empty()) ReadInstructions();
- return Instructions;
+ DenseMap<const Record*, CodeGenInstruction*>::iterator I =
+ Instructions.find(InstRec);
+ assert(I != Instructions.end() && "Not an instruction");
+ return *I->second;
}
- CodeGenInstruction &getInstruction(const std::string &Name) const {
- const std::map<std::string, CodeGenInstruction> &Insts = getInstructions();
- assert(Insts.count(Name) && "Not an instruction!");
- return const_cast<CodeGenInstruction&>(Insts.find(Name)->second);
- }
-
- typedef std::map<std::string,
- CodeGenInstruction>::const_iterator inst_iterator;
- inst_iterator inst_begin() const { return getInstructions().begin(); }
- inst_iterator inst_end() const { return Instructions.end(); }
-
/// getInstructionsByEnumValue - Return all of the instructions defined by the
/// target, ordered by their enum value.
- void getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
- &NumberedInstructions);
-
+ const std::vector<const CodeGenInstruction*> &
+ getInstructionsByEnumValue() const {
+ if (InstrsByEnum.empty()) ComputeInstrsByEnum();
+ return InstrsByEnum;
+ }
+ typedef std::vector<const CodeGenInstruction*>::const_iterator inst_iterator;
+ inst_iterator inst_begin() const{return getInstructionsByEnumValue().begin();}
+ inst_iterator inst_end() const { return getInstructionsByEnumValue().end(); }
+
+
/// isLittleEndianEncoding - are instruction bit patterns defined as [0..n]?
///
bool isLittleEndianEncoding() const;
+
+private:
+ void ComputeInstrsByEnum() const;
};
/// ComplexPattern - ComplexPattern info, corresponding to the ComplexPattern
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index e0fa7c8..04c7710 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -21,55 +21,6 @@ using namespace llvm;
// DAGISelEmitter Helper methods
//
-/// getPatternSize - Return the 'size' of this pattern. We want to match large
-/// patterns before small ones. This is used to determine the size of a
-/// pattern.
-static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) {
- assert((EEVT::isExtIntegerInVTs(P->getExtTypes()) ||
- EEVT::isExtFloatingPointInVTs(P->getExtTypes()) ||
- P->getExtTypeNum(0) == MVT::isVoid ||
- P->getExtTypeNum(0) == MVT::Flag ||
- P->getExtTypeNum(0) == MVT::iPTR ||
- P->getExtTypeNum(0) == MVT::iPTRAny) &&
- "Not a valid pattern node to size!");
- unsigned Size = 3; // The node itself.
- // If the root node is a ConstantSDNode, increases its size.
- // e.g. (set R32:$dst, 0).
- if (P->isLeaf() && dynamic_cast<IntInit*>(P->getLeafValue()))
- Size += 2;
-
- // FIXME: This is a hack to statically increase the priority of patterns
- // which maps a sub-dag to a complex pattern. e.g. favors LEA over ADD.
- // Later we can allow complexity / cost for each pattern to be (optionally)
- // specified. To get best possible pattern match we'll need to dynamically
- // calculate the complexity of all patterns a dag can potentially map to.
- const ComplexPattern *AM = P->getComplexPatternInfo(CGP);
- if (AM)
- Size += AM->getNumOperands() * 3;
-
- // If this node has some predicate function that must match, it adds to the
- // complexity of this node.
- if (!P->getPredicateFns().empty())
- ++Size;
-
- // Count children in the count if they are also nodes.
- for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) {
- TreePatternNode *Child = P->getChild(i);
- if (!Child->isLeaf() && Child->getExtTypeNum(0) != MVT::Other)
- Size += getPatternSize(Child, CGP);
- else if (Child->isLeaf()) {
- if (dynamic_cast<IntInit*>(Child->getLeafValue()))
- Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
- else if (Child->getComplexPatternInfo(CGP))
- Size += getPatternSize(Child, CGP);
- else if (!Child->getPredicateFns().empty())
- ++Size;
- }
- }
-
- return Size;
-}
-
/// getResultPatternCost - Compute the number of instructions for this pattern.
/// This is a temporary hack. We should really include the instruction
/// latencies in this calculation.
@@ -81,7 +32,7 @@ static unsigned getResultPatternCost(TreePatternNode *P,
Record *Op = P->getOperator();
if (Op->isSubClassOf("Instruction")) {
Cost++;
- CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op->getName());
+ CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op);
if (II.usesCustomInserter)
Cost += 10;
}
@@ -159,12 +110,25 @@ struct PatternSortingPredicate {
PatternSortingPredicate(CodeGenDAGPatterns &cgp) : CGP(cgp) {}
CodeGenDAGPatterns &CGP;
- bool operator()(const PatternToMatch *LHS,
- const PatternToMatch *RHS) {
- unsigned LHSSize = getPatternSize(LHS->getSrcPattern(), CGP);
- unsigned RHSSize = getPatternSize(RHS->getSrcPattern(), CGP);
- LHSSize += LHS->getAddedComplexity();
- RHSSize += RHS->getAddedComplexity();
+ bool operator()(const PatternToMatch *LHS, const PatternToMatch *RHS) {
+ const TreePatternNode *LHSSrc = LHS->getSrcPattern();
+ const TreePatternNode *RHSSrc = RHS->getSrcPattern();
+
+ if (LHSSrc->getNumTypes() != 0 && RHSSrc->getNumTypes() != 0 &&
+ LHSSrc->getType(0) != RHSSrc->getType(0)) {
+ MVT::SimpleValueType V1 = LHSSrc->getType(0), V2 = RHSSrc->getType(0);
+ if (MVT(V1).isVector() != MVT(V2).isVector())
+ return MVT(V2).isVector();
+
+ if (MVT(V1).isFloatingPoint() != MVT(V2).isFloatingPoint())
+ return MVT(V2).isFloatingPoint();
+ }
+
+ // Otherwise, if the patterns might both match, sort based on complexity,
+ // which means that we prefer to match patterns that cover more nodes in the
+ // input over nodes that cover fewer.
+ unsigned LHSSize = LHS->getPatternComplexity(CGP);
+ unsigned RHSSize = RHS->getPatternComplexity(CGP);
if (LHSSize > RHSSize) return true; // LHS -> bigger -> less cost
if (LHSSize < RHSSize) return false;
@@ -179,7 +143,8 @@ struct PatternSortingPredicate {
if (LHSPatSize < RHSPatSize) return true;
if (LHSPatSize > RHSPatSize) return false;
- // Sort based on the UID of the pattern, giving us a deterministic ordering.
+ // Sort based on the UID of the pattern, giving us a deterministic ordering
+ // if all other sorting conditions fail.
assert(LHS == RHS || LHS->ID != RHS->ID);
return LHS->ID < RHS->ID;
}
@@ -214,8 +179,7 @@ void DAGISelEmitter::run(raw_ostream &OS) {
// We want to process the matches in order of minimal cost. Sort the patterns
// so the least cost one is at the start.
- std::stable_sort(Patterns.begin(), Patterns.end(),
- PatternSortingPredicate(CGP));
+ std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate(CGP));
// Convert each variant of each pattern into a Matcher.
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index 22d2fe8..9f12a68 100644
--- a/utils/TableGen/DAGISelMatcher.cpp
+++ b/utils/TableGen/DAGISelMatcher.cpp
@@ -147,7 +147,8 @@ void SwitchOpcodeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
void CheckTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
- OS.indent(indent) << "CheckType " << getEnumName(Type) << '\n';
+ OS.indent(indent) << "CheckType " << getEnumName(Type) << ", ResNo="
+ << ResNo << '\n';
}
void SwitchTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
@@ -356,15 +357,13 @@ bool CheckOpcodeMatcher::isContradictoryImpl(const Matcher *M) const {
// different, then we know they contradict. For example, a check for
// ISD::STORE will never be true at the same time a check for Type i32 is.
if (const CheckTypeMatcher *CT = dyn_cast<CheckTypeMatcher>(M)) {
- // FIXME: What result is this referring to?
- unsigned NodeType;
- if (getOpcode().getNumResults() == 0)
- NodeType = MVT::isVoid;
- else
- NodeType = getOpcode().getKnownType();
- if (NodeType != EEVT::isUnknown)
- return TypesAreContradictory((MVT::SimpleValueType)NodeType,
- CT->getType());
+ // If checking for a result the opcode doesn't have, it can't match.
+ if (CT->getResNo() >= getOpcode().getNumResults())
+ return true;
+
+ MVT::SimpleValueType NodeType = getOpcode().getKnownType(CT->getResNo());
+ if (NodeType != MVT::Other)
+ return TypesAreContradictory(NodeType, CT->getType());
}
return false;
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index ef7ecf4..d9b25d5 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -492,14 +492,16 @@ private:
};
/// CheckTypeMatcher - This checks to see if the current node has the
-/// specified type, if not it fails to match.
+/// specified type at the specified result, if not it fails to match.
class CheckTypeMatcher : public Matcher {
MVT::SimpleValueType Type;
+ unsigned ResNo;
public:
- CheckTypeMatcher(MVT::SimpleValueType type)
- : Matcher(CheckType), Type(type) {}
+ CheckTypeMatcher(MVT::SimpleValueType type, unsigned resno)
+ : Matcher(CheckType), Type(type), ResNo(resno) {}
MVT::SimpleValueType getType() const { return Type; }
+ unsigned getResNo() const { return ResNo; }
static inline bool classof(const Matcher *N) {
return N->getKind() == CheckType;
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index cabf2d4..4473f0d 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -32,6 +32,7 @@ OmitComments("omit-comments", cl::desc("Do not generate comments"),
namespace {
class MatcherTableEmitter {
+ const CodeGenDAGPatterns &CGP;
StringMap<unsigned> NodePredicateMap, PatternPredicateMap;
std::vector<std::string> NodePredicates, PatternPredicates;
@@ -43,13 +44,12 @@ class MatcherTableEmitter {
std::vector<Record*> NodeXForms;
public:
- MatcherTableEmitter() {}
+ MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) {}
unsigned EmitMatcherList(const Matcher *N, unsigned Indent,
unsigned StartIdx, formatted_raw_ostream &OS);
- void EmitPredicateFunctions(const CodeGenDAGPatterns &CGP,
- formatted_raw_ostream &OS);
+ void EmitPredicateFunctions(formatted_raw_ostream &OS);
void EmitHistogram(const Matcher *N, formatted_raw_ostream &OS);
private:
@@ -255,9 +255,9 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
}
case Matcher::CheckOpcode:
- OS << "OPC_CheckOpcode, "
- << cast<CheckOpcodeMatcher>(N)->getOpcode().getEnumName() << ",\n";
- return 2;
+ OS << "OPC_CheckOpcode, TARGET_OPCODE("
+ << cast<CheckOpcodeMatcher>(N)->getOpcode().getEnumName() << "),\n";
+ return 3;
case Matcher::SwitchOpcode:
case Matcher::SwitchType: {
@@ -280,10 +280,14 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
// For each case we emit the size, then the opcode, then the matcher.
for (unsigned i = 0, e = NumCases; i != e; ++i) {
const Matcher *Child;
- if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
+ unsigned IdxSize;
+ if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) {
Child = SOM->getCaseMatcher(i);
- else
+ IdxSize = 2; // size of opcode in table is 2 bytes.
+ } else {
Child = cast<SwitchTypeMatcher>(N)->getCaseMatcher(i);
+ IdxSize = 1; // size of type in table is 1 byte.
+ }
// We need to encode the opcode and the offset of the case code before
// emitting the case code. Handle this by buffering the output into a
@@ -299,7 +303,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
TmpBuf.clear();
raw_svector_ostream OS(TmpBuf);
formatted_raw_ostream FOS(OS);
- ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+1, FOS);
+ ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+IdxSize,
+ FOS);
} while (GetVBRSize(ChildSize) != VBRSize);
assert(ChildSize != 0 && "Should not have a zero-sized child!");
@@ -316,15 +321,15 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << ' ';
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
- OS << SOM->getCaseOpcode(i).getEnumName();
+ OS << "TARGET_OPCODE(" << SOM->getCaseOpcode(i).getEnumName() << "),";
else
- OS << getEnumName(cast<SwitchTypeMatcher>(N)->getCaseType(i));
- OS << ',';
-
+ OS << getEnumName(cast<SwitchTypeMatcher>(N)->getCaseType(i)) << ',';
+
+ CurrentIdx += IdxSize;
+
if (!OmitComments)
- OS << "// ->" << CurrentIdx+ChildSize+1;
+ OS << "// ->" << CurrentIdx+ChildSize;
OS << '\n';
- ++CurrentIdx;
OS << TmpBuf.str();
CurrentIdx += ChildSize;
}
@@ -341,6 +346,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
}
case Matcher::CheckType:
+ assert(cast<CheckTypeMatcher>(N)->getResNo() == 0 &&
+ "FIXME: Add support for CheckType of resno != 0");
OS << "OPC_CheckType, "
<< getEnumName(cast<CheckTypeMatcher>(N)->getType()) << ",\n";
return 2;
@@ -442,6 +449,13 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
case Matcher::EmitMergeInputChains: {
const EmitMergeInputChainsMatcher *MN =
cast<EmitMergeInputChainsMatcher>(N);
+
+ // Handle the specialized forms OPC_EmitMergeInputChains1_0 and 1_1.
+ if (MN->getNumNodes() == 1 && MN->getNode(0) < 2) {
+ OS << "OPC_EmitMergeInputChains1_" << MN->getNode(0) << ",\n";
+ return 1;
+ }
+
OS << "OPC_EmitMergeInputChains, " << MN->getNumNodes() << ", ";
for (unsigned i = 0, e = MN->getNumNodes(); i != e; ++i)
OS << MN->getNode(i) << ", ";
@@ -507,7 +521,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
if (const MorphNodeToMatcher *SNT = dyn_cast<MorphNodeToMatcher>(N)) {
OS.PadToColumn(Indent*2) << "// Src: "
- << *SNT->getPattern().getSrcPattern() << '\n';
+ << *SNT->getPattern().getSrcPattern() << " - Complexity = "
+ << SNT->getPattern().getPatternComplexity(CGP) << '\n';
OS.PadToColumn(Indent*2) << "// Dst: "
<< *SNT->getPattern().getDstPattern() << '\n';
}
@@ -534,7 +549,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << '\n';
if (!OmitComments) {
OS.PadToColumn(Indent*2) << "// Src: "
- << *CM->getPattern().getSrcPattern() << '\n';
+ << *CM->getPattern().getSrcPattern() << " - Complexity = "
+ << CM->getPattern().getPatternComplexity(CGP) << '\n';
OS.PadToColumn(Indent*2) << "// Dst: "
<< *CM->getPattern().getDstPattern();
}
@@ -565,8 +581,7 @@ EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
return Size;
}
-void MatcherTableEmitter::EmitPredicateFunctions(const CodeGenDAGPatterns &CGP,
- formatted_raw_ostream &OS) {
+void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
// Emit pattern predicates.
if (!PatternPredicates.empty()) {
OS << "bool CheckPatternPredicate(unsigned PredNo) const {\n";
@@ -760,7 +775,7 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher,
OS << "// The main instruction selector code.\n";
OS << "SDNode *SelectCode(SDNode *N) {\n";
- MatcherTableEmitter MatcherEmitter;
+ MatcherTableEmitter MatcherEmitter(CGP);
OS << " // Opcodes are emitted as 2 bytes, TARGET_OPCODE handles this.\n";
OS << " #define TARGET_OPCODE(X) X & 255, unsigned(X) >> 8\n";
@@ -775,5 +790,5 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher,
OS << '\n';
// Next up, emit the function for node and pattern predicates:
- MatcherEmitter.EmitPredicateFunctions(CGP, OS);
+ MatcherEmitter.EmitPredicateFunctions(OS);
}
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index 4951a42..9d469a9 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -408,11 +408,13 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
// If N and NodeNoTypes don't agree on a type, then this is a case where we
// need to do a type check. Emit the check, apply the tyep to NodeNoTypes and
// reinfer any correlated types.
- unsigned NodeType = EEVT::isUnknown;
- if (NodeNoTypes->getExtTypes() != N->getExtTypes()) {
- NodeType = N->getTypeNum(0);
- NodeNoTypes->setTypes(N->getExtTypes());
+ SmallVector<unsigned, 2> ResultsToTypeCheck;
+
+ for (unsigned i = 0, e = NodeNoTypes->getNumTypes(); i != e; ++i) {
+ if (NodeNoTypes->getExtType(i) == N->getExtType(i)) continue;
+ NodeNoTypes->setType(i, N->getExtType(i));
InferPossibleTypes();
+ ResultsToTypeCheck.push_back(i);
}
// If this node has a name associated with it, capture it in VariableMap. If
@@ -442,8 +444,9 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i)
AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i]));
- if (NodeType != EEVT::isUnknown)
- AddMatcher(new CheckTypeMatcher((MVT::SimpleValueType)NodeType));
+ for (unsigned i = 0, e = ResultsToTypeCheck.size(); i != e; ++i)
+ AddMatcher(new CheckTypeMatcher(N->getType(ResultsToTypeCheck[i]),
+ ResultsToTypeCheck[i]));
}
/// EmitMatcherCode - Generate the code that matches the predicate of this
@@ -567,7 +570,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
assert(N->isLeaf() && "Must be a leaf");
if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
- AddMatcher(new EmitIntegerMatcher(II->getValue(),N->getTypeNum(0)));
+ AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
@@ -575,14 +578,13 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
// If this is an explicit register reference, handle it.
if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
if (DI->getDef()->isSubClassOf("Register")) {
- AddMatcher(new EmitRegisterMatcher(DI->getDef(),
- N->getTypeNum(0)));
+ AddMatcher(new EmitRegisterMatcher(DI->getDef(), N->getType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
if (DI->getDef()->getName() == "zero_reg") {
- AddMatcher(new EmitRegisterMatcher(0, N->getTypeNum(0)));
+ AddMatcher(new EmitRegisterMatcher(0, N->getType(0)));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
@@ -628,7 +630,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
SmallVectorImpl<unsigned> &OutputOps) {
Record *Op = N->getOperator();
const CodeGenTarget &CGT = CGP.getTargetInfo();
- CodeGenInstruction &II = CGT.getInstruction(Op->getName());
+ CodeGenInstruction &II = CGT.getInstruction(Op);
const DAGInstruction &Inst = CGP.getInstruction(Op);
// If we can, get the pattern for the instruction we're generating. We derive
@@ -685,9 +687,19 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
continue;
}
+ const TreePatternNode *Child = N->getChild(ChildNo);
+
// Otherwise this is a normal operand or a predicate operand without
// 'execute always'; emit it.
- EmitResultOperand(N->getChild(ChildNo), InstOps);
+ unsigned BeforeAddingNumOps = InstOps.size();
+ EmitResultOperand(Child, InstOps);
+ assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands");
+
+ // If the operand is an instruction and it produced multiple results, just
+ // take the first one.
+ if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction"))
+ InstOps.resize(BeforeAddingNumOps+1);
+
++ChildNo;
}
@@ -699,7 +711,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// occur in patterns like (mul:i8 AL:i8, GR8:i8:$src).
for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i)
AddMatcher(new EmitCopyToRegMatcher(PhysRegInputs[i].second,
- PhysRegInputs[i].first));
+ PhysRegInputs[i].first));
// Even if the node has no other flag inputs, the resultant node must be
// flagged to the CopyFromReg nodes we just generated.
TreeHasInFlag = true;
@@ -709,29 +721,34 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// Determine the result types.
SmallVector<MVT::SimpleValueType, 4> ResultVTs;
- if (NumResults != 0 && N->getTypeNum(0) != MVT::isVoid) {
- // FIXME2: If the node has multiple results, we should add them. For now,
- // preserve existing behavior?!
- ResultVTs.push_back(N->getTypeNum(0));
- }
-
+ for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i)
+ ResultVTs.push_back(N->getType(i));
// If this is the root instruction of a pattern that has physical registers in
// its result pattern, add output VTs for them. For example, X86 has:
// (set AL, (mul ...))
// This also handles implicit results like:
// (implicit EFLAGS)
- if (isRoot && Pattern.getDstRegs().size() != 0) {
- for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i)
- if (Pattern.getDstRegs()[i]->isSubClassOf("Register"))
- ResultVTs.push_back(getRegisterValueType(Pattern.getDstRegs()[i], CGT));
+ if (isRoot && !Pattern.getDstRegs().empty()) {
+ // If the root came from an implicit def in the instruction handling stuff,
+ // don't re-add it.
+ Record *HandledReg = 0;
+ if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other)
+ HandledReg = II.ImplicitDefs[0];
+
+ for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) {
+ Record *Reg = Pattern.getDstRegs()[i];
+ if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue;
+ ResultVTs.push_back(getRegisterValueType(Reg, CGT));
+ }
}
- // FIXME2: Instead of using the isVariadic flag on the instruction, we should
- // have an SDNP that indicates variadicism. The TargetInstrInfo isVariadic
- // property should be inferred from this when an instruction has a pattern.
+ // If this is the root of the pattern and the pattern we're matching includes
+ // a node that is variadic, mark the generated node as variadic so that it
+ // gets the excess operands from the input DAG.
int NumFixedArityOperands = -1;
- if (isRoot && II.isVariadic)
+ if (isRoot &&
+ (Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP)))
NumFixedArityOperands = Pattern.getSrcPattern()->getNumChildren();
// If this is the root node and any of the nodes matched nodes in the input
@@ -750,6 +767,9 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
bool NodeHasMemRefs =
isRoot && Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP);
+ assert((!ResultVTs.empty() || TreeHasOutFlag || NodeHasChain) &&
+ "Node has no result");
+
AddMatcher(new EmitNodeMatcher(II.Namespace+"::"+II.TheDef->getName(),
ResultVTs.data(), ResultVTs.size(),
InstOps.data(), InstOps.size(),
@@ -817,33 +837,35 @@ void MatcherGen::EmitResultCode() {
// At this point, we have however many values the result pattern produces.
// However, the input pattern might not need all of these. If there are
- // excess values at the end (such as condition codes etc) just lop them off.
- // This doesn't need to worry about flags or chains, just explicit results.
- //
- // FIXME2: This doesn't work because there is currently no way to get an
- // accurate count of the # results the source pattern sets. This is because
- // of the "parallel" construct in X86 land, which looks like this:
- //
- //def : Pat<(parallel (X86and_flag GR8:$src1, GR8:$src2),
- // (implicit EFLAGS)),
- // (AND8rr GR8:$src1, GR8:$src2)>;
- //
- // This idiom means to match the two-result node X86and_flag (which is
- // declared as returning a single result, because we can't match multi-result
- // nodes yet). In this case, we would have to know that the input has two
- // results. However, mul8r is modelled exactly the same way, but without
- // implicit defs included. The fix is to support multiple results directly
- // and eliminate 'parallel'.
+ // excess values at the end (such as implicit defs of condition codes etc)
+ // just lop them off. This doesn't need to worry about flags or chains, just
+ // explicit results.
//
- // FIXME2: When this is fixed, we should revert the terrible hack in the
- // OPC_EmitNode code in the interpreter.
-#if 0
- const TreePatternNode *Src = Pattern.getSrcPattern();
- unsigned NumSrcResults = Src->getTypeNum(0) != MVT::isVoid ? 1 : 0;
- NumSrcResults += Pattern.getDstRegs().size();
+ unsigned NumSrcResults = Pattern.getSrcPattern()->getNumTypes();
+
+ // If the pattern also has (implicit) results, count them as well.
+ if (!Pattern.getDstRegs().empty()) {
+ // If the root came from an implicit def in the instruction handling stuff,
+ // don't re-add it.
+ Record *HandledReg = 0;
+ const TreePatternNode *DstPat = Pattern.getDstPattern();
+ if (!DstPat->isLeaf() &&DstPat->getOperator()->isSubClassOf("Instruction")){
+ const CodeGenTarget &CGT = CGP.getTargetInfo();
+ CodeGenInstruction &II = CGT.getInstruction(DstPat->getOperator());
+
+ if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other)
+ HandledReg = II.ImplicitDefs[0];
+ }
+
+ for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) {
+ Record *Reg = Pattern.getDstRegs()[i];
+ if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue;
+ ++NumSrcResults;
+ }
+ }
+
assert(Ops.size() >= NumSrcResults && "Didn't provide enough results");
Ops.resize(NumSrcResults);
-#endif
// If the matched pattern covers nodes which define a flag result, emit a node
// that tells the matcher about them so that it can update their results.
diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp
index 910c4c5..c73bdb9 100644
--- a/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -44,11 +44,14 @@ static void ContractNodes(OwningPtr<Matcher> &MatcherPtr,
if (MoveChildMatcher *MC = dyn_cast<MoveChildMatcher>(N)) {
Matcher *New = 0;
if (RecordMatcher *RM = dyn_cast<RecordMatcher>(MC->getNext()))
- New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(),
- RM->getResultNo());
+ if (MC->getChildNo() < 8) // Only have RecordChild0...7
+ New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(),
+ RM->getResultNo());
- if (CheckTypeMatcher *CT= dyn_cast<CheckTypeMatcher>(MC->getNext()))
- New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType());
+ if (CheckTypeMatcher *CT = dyn_cast<CheckTypeMatcher>(MC->getNext()))
+ if (MC->getChildNo() < 8 && // Only have CheckChildType0...7
+ CT->getResNo() == 0) // CheckChildType checks res #0
+ New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType());
if (New) {
// Insert the new node.
@@ -418,10 +421,12 @@ static void FactorNodes(OwningPtr<Matcher> &MatcherPtr) {
CheckTypeMatcher *CTM =
cast_or_null<CheckTypeMatcher>(FindNodeWithKind(NewOptionsToMatch[i],
Matcher::CheckType));
- if (CTM == 0 ||
+ if (CTM == 0 ||
// iPTR checks could alias any other case without us knowing, don't
// bother with them.
CTM->getType() == MVT::iPTR ||
+ // SwitchType only works for result #0.
+ CTM->getResNo() != 0 ||
// If the CheckType isn't at the start of the list, see if we can move
// it there.
!CTM->canMoveBefore(NewOptionsToMatch[i])) {
@@ -486,7 +491,7 @@ static void FactorNodes(OwningPtr<Matcher> &MatcherPtr) {
MatcherPtr.reset(new SwitchTypeMatcher(&Cases[0], Cases.size()));
} else {
// If we factored and ended up with one case, create it now.
- MatcherPtr.reset(new CheckTypeMatcher(Cases[0].first));
+ MatcherPtr.reset(new CheckTypeMatcher(Cases[0].first, 0));
MatcherPtr->setNext(Cases[0].second);
}
return;
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index 61b9b15..3284366 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -12,6 +12,8 @@
#include "Record.h"
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
+#include "ARMDecoderEmitter.h"
+
using namespace llvm;
using namespace llvm::X86Disassembler;
@@ -108,8 +110,8 @@ void DisassemblerEmitter::run(raw_ostream &OS) {
if (Target.getName() == "X86") {
DisassemblerTables Tables;
- std::vector<const CodeGenInstruction*> numberedInstructions;
- Target.getInstructionsByEnumValue(numberedInstructions);
+ const std::vector<const CodeGenInstruction*> &numberedInstructions =
+ Target.getInstructionsByEnumValue();
for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i)
RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i);
@@ -124,6 +126,12 @@ void DisassemblerEmitter::run(raw_ostream &OS) {
return;
}
+ // Fixed-instruction-length targets use a common disassembler.
+ if (Target.getName() == "ARM") {
+ ARMDecoderEmitter(Records).run(OS);
+ return;
+ }
+
throw TGError(Target.getTargetRecord()->getLoc(),
"Unable to generate disassembler for this target");
}
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index 9aad2f6..d3bf60e 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -19,15 +19,14 @@
#include "CodeGenTarget.h"
#include "Record.h"
+#include "llvm/MC/EDInstInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
-#include <vector>
+#include <map>
#include <string>
-
-#define MAX_OPERANDS 5
-#define MAX_SYNTAXES 2
+#include <vector>
using namespace llvm;
@@ -54,9 +53,9 @@ namespace {
unsigned int index = 0;
unsigned int numEntries = Entries.size();
- for(index = 0; index < numEntries; ++index) {
+ for (index = 0; index < numEntries; ++index) {
o.indent(i) << Entries[index];
- if(index < (numEntries - 1))
+ if (index < (numEntries - 1))
o << ",";
o << "\n";
}
@@ -88,24 +87,24 @@ namespace {
class StructEmitter {
private:
std::string Name;
- std::vector<std::string> MemberTypes;
- std::vector<std::string> MemberNames;
+ typedef std::pair<const char*, const char*> member;
+ std::vector< member > Members;
public:
StructEmitter(const char *N) : Name(N) {
}
void addMember(const char *t, const char *n) {
- MemberTypes.push_back(std::string(t));
- MemberNames.push_back(std::string(n));
+ member m(t, n);
+ Members.push_back(m);
}
void emit(raw_ostream &o, unsigned int &i) {
o.indent(i) << "struct " << Name.c_str() << " {" << "\n";
i += 2;
unsigned int index = 0;
- unsigned int numMembers = MemberTypes.size();
+ unsigned int numMembers = Members.size();
for (index = 0; index < numMembers; ++index) {
- o.indent(i) << MemberTypes[index] << " " << MemberNames[index] << ";";
- o << "\n";
+ o.indent(i) << Members[index].first << " ";
+ o.indent(i) << Members[index].second << ";" << "\n";
}
i -= 2;
@@ -121,47 +120,87 @@ namespace {
class LiteralConstantEmitter : public ConstantEmitter {
private:
- std::string Literal;
+ bool IsNumber;
+ union {
+ int Number;
+ const char* String;
+ };
public:
- LiteralConstantEmitter(const char *literal) : Literal(literal) {
+ LiteralConstantEmitter(const char *string) :
+ IsNumber(false),
+ String(string) {
}
- LiteralConstantEmitter(int literal) {
- char buf[256];
- snprintf(buf, 256, "%d", literal);
- Literal = buf;
+ LiteralConstantEmitter(int number = 0) :
+ IsNumber(true),
+ Number(number) {
+ }
+ void set(const char *string) {
+ IsNumber = false;
+ Number = 0;
+ String = string;
+ }
+ void set(int number) {
+ IsNumber = true;
+ String = NULL;
+ Number = number;
+ }
+ bool is(const char *string) {
+ return !strcmp(String, string);
}
void emit(raw_ostream &o, unsigned int &i) {
- o << Literal;
+ if (IsNumber)
+ o << Number;
+ else
+ o << String;
}
};
class CompoundConstantEmitter : public ConstantEmitter {
private:
- std::vector<ConstantEmitter*> Entries;
+ unsigned int Padding;
+ std::vector<ConstantEmitter *> Entries;
public:
- CompoundConstantEmitter() {
- }
- ~CompoundConstantEmitter() {
- unsigned int index;
- unsigned int numEntries = Entries.size();
- for (index = 0; index < numEntries; ++index) {
- delete Entries[index];
- }
+ CompoundConstantEmitter(unsigned int padding = 0) : Padding(padding) {
}
CompoundConstantEmitter &addEntry(ConstantEmitter *e) {
Entries.push_back(e);
+
return *this;
}
+ ~CompoundConstantEmitter() {
+ while (Entries.size()) {
+ ConstantEmitter *entry = Entries.back();
+ Entries.pop_back();
+ delete entry;
+ }
+ }
void emit(raw_ostream &o, unsigned int &i) {
o << "{" << "\n";
i += 2;
unsigned int index;
unsigned int numEntries = Entries.size();
- for (index = 0; index < numEntries; ++index) {
+
+ unsigned int numToPrint;
+
+ if (Padding) {
+ if (numEntries > Padding) {
+ fprintf(stderr, "%u entries but %u padding\n", numEntries, Padding);
+ llvm_unreachable("More entries than padding");
+ }
+ numToPrint = Padding;
+ } else {
+ numToPrint = numEntries;
+ }
+
+ for (index = 0; index < numToPrint; ++index) {
o.indent(i);
- Entries[index]->emit(o, i);
- if (index < (numEntries - 1))
+ if (index < numEntries)
+ Entries[index]->emit(o, i);
+ else
+ o << "-1";
+
+ if (index < (numToPrint - 1))
o << ",";
o << "\n";
}
@@ -226,49 +265,42 @@ void populateOperandOrder(CompoundConstantEmitter *operandOrder,
++operandIterator) {
if (operandIterator->OperandType ==
AsmWriterOperand::isMachineInstrOperand) {
- char buf[2];
- snprintf(buf, sizeof(buf), "%u", operandIterator->CGIOpNo);
- operandOrder->addEntry(new LiteralConstantEmitter(buf));
+ operandOrder->addEntry(
+ new LiteralConstantEmitter(operandIterator->CGIOpNo));
numArgs++;
}
}
-
- for(; numArgs < MAX_OPERANDS; numArgs++) {
- operandOrder->addEntry(new LiteralConstantEmitter("-1"));
- }
}
/////////////////////////////////////////////////////
// Support functions for handling X86 instructions //
/////////////////////////////////////////////////////
-#define ADDFLAG(flag) flags->addEntry(flag)
+#define SET(flag) { type->set(flag); return 0; }
-#define REG(str) if (name == str) { ADDFLAG("kOperandFlagRegister"); return 0; }
-#define MEM(str) if (name == str) { ADDFLAG("kOperandFlagMemory"); return 0; }
-#define LEA(str) if (name == str) { ADDFLAG("kOperandFlagEffectiveAddress"); \
- return 0; }
-#define IMM(str) if (name == str) { ADDFLAG("kOperandFlagImmediate"); \
- return 0; }
-#define PCR(str) if (name == str) { ADDFLAG("kOperandFlagMemory"); \
- ADDFLAG("kOperandFlagPCRelative"); \
- return 0; }
+#define REG(str) if (name == str) SET("kOperandTypeRegister");
+#define MEM(str) if (name == str) SET("kOperandTypeX86Memory");
+#define LEA(str) if (name == str) SET("kOperandTypeX86EffectiveAddress");
+#define IMM(str) if (name == str) SET("kOperandTypeImmediate");
+#define PCR(str) if (name == str) SET("kOperandTypeX86PCRelative");
-/// X86FlagFromOpName - Processes the name of a single X86 operand (which is
-/// actually its type) and translates it into an operand flag
+/// X86TypeFromOpName - Processes the name of a single X86 operand (which is
+/// actually its type) and translates it into an operand type
///
-/// @arg flags - The flags object to add the flag to
+/// @arg flags - The type object to set
/// @arg name - The name of the operand
-static int X86FlagFromOpName(FlagsConstantEmitter *flags,
+static int X86TypeFromOpName(LiteralConstantEmitter *type,
const std::string &name) {
REG("GR8");
REG("GR8_NOREX");
REG("GR16");
REG("GR32");
REG("GR32_NOREX");
+ REG("GR32_TC");
REG("FR32");
REG("RFP32");
REG("GR64");
+ REG("GR64_TC");
REG("FR64");
REG("VR64");
REG("RFP64");
@@ -280,15 +312,28 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags,
REG("CONTROL_REG_32");
REG("CONTROL_REG_64");
+ IMM("i8imm");
+ IMM("i16imm");
+ IMM("i16i8imm");
+ IMM("i32imm");
+ IMM("i32i8imm");
+ IMM("i64imm");
+ IMM("i64i8imm");
+ IMM("i64i32imm");
+ IMM("SSECC");
+
+ // all R, I, R, I, R
MEM("i8mem");
MEM("i8mem_NOREX");
MEM("i16mem");
MEM("i32mem");
+ MEM("i32mem_TC");
MEM("f32mem");
MEM("ssmem");
MEM("opaque32mem");
MEM("opaque48mem");
MEM("i64mem");
+ MEM("i64mem_TC");
MEM("f64mem");
MEM("sdmem");
MEM("f80mem");
@@ -297,22 +342,14 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags,
MEM("f128mem");
MEM("opaque512mem");
+ // all R, I, R, I
LEA("lea32mem");
LEA("lea64_32mem");
LEA("lea64mem");
- IMM("i8imm");
- IMM("i16imm");
- IMM("i16i8imm");
- IMM("i32imm");
- IMM("i32imm_pcrel");
- IMM("i32i8imm");
- IMM("i64imm");
- IMM("i64i8imm");
- IMM("i64i32imm");
- IMM("i64i32imm_pcrel");
- IMM("SSECC");
-
+ // all I
+ PCR("i32imm_pcrel");
+ PCR("i64i32imm_pcrel");
PCR("brtarget8");
PCR("offset8");
PCR("offset16");
@@ -328,7 +365,8 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags,
#undef LEA
#undef IMM
#undef PCR
-#undef ADDFLAG
+
+#undef SET
/// X86PopulateOperands - Handles all the operands in an X86 instruction, adding
/// the appropriate flags to their descriptors
@@ -336,7 +374,7 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags,
/// @operandFlags - A reference the array of operand flag objects
/// @inst - The instruction to use as a source of information
static void X86PopulateOperands(
- FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS],
+ LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS],
const CodeGenInstruction &inst) {
if (!inst.TheDef->isSubClassOf("X86Inst"))
return;
@@ -349,7 +387,7 @@ static void X86PopulateOperands(
inst.OperandList[index];
Record &rec = *operandInfo.Rec;
- if (X86FlagFromOpName(operandFlags[index], rec.getName())) {
+ if (X86TypeFromOpName(operandTypes[index], rec.getName())) {
errs() << "Operand type: " << rec.getName().c_str() << "\n";
errs() << "Operand name: " << operandInfo.Name.c_str() << "\n";
errs() << "Instruction mame: " << inst.TheDef->getName().c_str() << "\n";
@@ -365,10 +403,11 @@ static void X86PopulateOperands(
/// between names and operand indices
/// @opName - The name of the operand
/// @flag - The name of the flag to add
-static inline void decorate1(FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS],
- const CodeGenInstruction &inst,
- const char *opName,
- const char *opFlag) {
+static inline void decorate1(
+ FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
+ const CodeGenInstruction &inst,
+ const char *opName,
+ const char *opFlag) {
unsigned opIndex;
opIndex = inst.getOperandNamed(std::string(opName));
@@ -378,78 +417,70 @@ static inline void decorate1(FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS]
#define DECORATE1(opName, opFlag) decorate1(operandFlags, inst, opName, opFlag)
-#define MOV(source, target) { \
- instFlags.addEntry("kInstructionFlagMove"); \
- DECORATE1(source, "kOperandFlagSource"); \
- DECORATE1(target, "kOperandFlagTarget"); \
+#define MOV(source, target) { \
+ instType.set("kInstructionTypeMove"); \
+ DECORATE1(source, "kOperandFlagSource"); \
+ DECORATE1(target, "kOperandFlagTarget"); \
}
-#define BRANCH(target) { \
- instFlags.addEntry("kInstructionFlagBranch"); \
- DECORATE1(target, "kOperandFlagTarget"); \
+#define BRANCH(target) { \
+ instType.set("kInstructionTypeBranch"); \
+ DECORATE1(target, "kOperandFlagTarget"); \
}
-#define PUSH(source) { \
- instFlags.addEntry("kInstructionFlagPush"); \
- DECORATE1(source, "kOperandFlagSource"); \
+#define PUSH(source) { \
+ instType.set("kInstructionTypePush"); \
+ DECORATE1(source, "kOperandFlagSource"); \
}
-#define POP(target) { \
- instFlags.addEntry("kInstructionFlagPop"); \
- DECORATE1(target, "kOperandFlagTarget"); \
+#define POP(target) { \
+ instType.set("kInstructionTypePop"); \
+ DECORATE1(target, "kOperandFlagTarget"); \
}
-#define CALL(target) { \
- instFlags.addEntry("kInstructionFlagCall"); \
- DECORATE1(target, "kOperandFlagTarget"); \
+#define CALL(target) { \
+ instType.set("kInstructionTypeCall"); \
+ DECORATE1(target, "kOperandFlagTarget"); \
}
-#define RETURN() { \
- instFlags.addEntry("kInstructionFlagReturn"); \
+#define RETURN() { \
+ instType.set("kInstructionTypeReturn"); \
}
/// X86ExtractSemantics - Performs various checks on the name of an X86
/// instruction to determine what sort of an instruction it is and then adds
/// the appropriate flags to the instruction and its operands
///
-/// @arg instFlags - A reference to the flags for the instruction as a whole
+/// @arg instType - A reference to the type for the instruction as a whole
/// @arg operandFlags - A reference to the array of operand flag object pointers
/// @arg inst - A reference to the original instruction
-static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
- FlagsConstantEmitter *(&operandFlags)[MAX_OPERANDS],
- const CodeGenInstruction &inst) {
+static void X86ExtractSemantics(
+ LiteralConstantEmitter &instType,
+ FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
+ const CodeGenInstruction &inst) {
const std::string &name = inst.TheDef->getName();
if (name.find("MOV") != name.npos) {
if (name.find("MOV_V") != name.npos) {
// ignore (this is a pseudoinstruction)
- }
- else if (name.find("MASK") != name.npos) {
+ } else if (name.find("MASK") != name.npos) {
// ignore (this is a masking move)
- }
- else if (name.find("r0") != name.npos) {
+ } else if (name.find("r0") != name.npos) {
// ignore (this is a pseudoinstruction)
- }
- else if (name.find("PS") != name.npos ||
+ } else if (name.find("PS") != name.npos ||
name.find("PD") != name.npos) {
// ignore (this is a shuffling move)
- }
- else if (name.find("MOVS") != name.npos) {
+ } else if (name.find("MOVS") != name.npos) {
// ignore (this is a string move)
- }
- else if (name.find("_F") != name.npos) {
+ } else if (name.find("_F") != name.npos) {
// TODO handle _F moves to ST(0)
- }
- else if (name.find("a") != name.npos) {
+ } else if (name.find("a") != name.npos) {
// TODO handle moves to/from %ax
- }
- else if (name.find("CMOV") != name.npos) {
+ } else if (name.find("CMOV") != name.npos) {
MOV("src2", "dst");
- }
- else if (name.find("PC") != name.npos) {
+ } else if (name.find("PC") != name.npos) {
MOV("label", "reg")
- }
- else {
+ } else {
MOV("src", "dst");
}
}
@@ -458,8 +489,7 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
name.find("J") == 0) {
if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
BRANCH("off");
- }
- else {
+ } else {
BRANCH("dst");
}
}
@@ -467,19 +497,15 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
if (name.find("PUSH") != name.npos) {
if (name.find("FS") != name.npos ||
name.find("GS") != name.npos) {
- instFlags.addEntry("kInstructionFlagPush");
+ instType.set("kInstructionTypePush");
// TODO add support for fixed operands
- }
- else if (name.find("F") != name.npos) {
+ } else if (name.find("F") != name.npos) {
// ignore (this pushes onto the FP stack)
- }
- else if (name[name.length() - 1] == 'm') {
+ } else if (name[name.length() - 1] == 'm') {
PUSH("src");
- }
- else if (name.find("i") != name.npos) {
+ } else if (name.find("i") != name.npos) {
PUSH("imm");
- }
- else {
+ } else {
PUSH("reg");
}
}
@@ -487,19 +513,15 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
if (name.find("POP") != name.npos) {
if (name.find("POPCNT") != name.npos) {
// ignore (not a real pop)
- }
- else if (name.find("FS") != name.npos ||
+ } else if (name.find("FS") != name.npos ||
name.find("GS") != name.npos) {
- instFlags.addEntry("kInstructionFlagPop");
+ instType.set("kInstructionTypePop");
// TODO add support for fixed operands
- }
- else if (name.find("F") != name.npos) {
+ } else if (name.find("F") != name.npos) {
// ignore (this pops from the FP stack)
- }
- else if (name[name.length() - 1] == 'm') {
+ } else if (name[name.length() - 1] == 'm') {
POP("dst");
- }
- else {
+ } else {
POP("reg");
}
}
@@ -507,17 +529,13 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
if (name.find("CALL") != name.npos) {
if (name.find("ADJ") != name.npos) {
// ignore (not a call)
- }
- else if (name.find("SYSCALL") != name.npos) {
+ } else if (name.find("SYSCALL") != name.npos) {
// ignore (doesn't go anywhere we know about)
- }
- else if (name.find("VMCALL") != name.npos) {
+ } else if (name.find("VMCALL") != name.npos) {
// ignore (rather different semantics than a regular call)
- }
- else if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
+ } else if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
CALL("off");
- }
- else {
+ } else {
CALL("dst");
}
}
@@ -534,9 +552,182 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
#undef CALL
#undef RETURN
-#undef COND_DECORATE_2
-#undef COND_DECORATE_1
-#undef DECORATE1
+/////////////////////////////////////////////////////
+// Support functions for handling ARM instructions //
+/////////////////////////////////////////////////////
+
+#define SET(flag) { type->set(flag); return 0; }
+
+#define REG(str) if (name == str) SET("kOperandTypeRegister");
+#define IMM(str) if (name == str) SET("kOperandTypeImmediate");
+
+#define MISC(str, type) if (name == str) SET(type);
+
+/// ARMFlagFromOpName - Processes the name of a single ARM operand (which is
+/// actually its type) and translates it into an operand type
+///
+/// @arg type - The type object to set
+/// @arg name - The name of the operand
+static int ARMFlagFromOpName(LiteralConstantEmitter *type,
+ const std::string &name) {
+ REG("GPR");
+ REG("cc_out");
+ REG("s_cc_out");
+ REG("tGPR");
+ REG("DPR");
+ REG("SPR");
+ REG("QPR");
+ REG("DPR_VFP2");
+ REG("DPR_8");
+
+ IMM("i32imm");
+ IMM("bf_inv_mask_imm");
+ IMM("jtblock_operand");
+ IMM("nohash_imm");
+ IMM("cpinst_operand");
+ IMM("cps_opt");
+ IMM("vfp_f64imm");
+ IMM("vfp_f32imm");
+ IMM("msr_mask");
+ IMM("neg_zero");
+ IMM("imm0_31");
+ IMM("h8imm");
+ IMM("h16imm");
+ IMM("h32imm");
+ IMM("h64imm");
+ IMM("imm0_4095");
+ IMM("jt2block_operand");
+ IMM("t_imm_s4");
+ IMM("pclabel");
+
+ MISC("brtarget", "kOperandTypeARMBranchTarget"); // ?
+ MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I
+ MISC("t2_so_reg", "kOperandTypeThumb2SoReg"); // R, I
+ MISC("so_imm", "kOperandTypeARMSoImm"); // I
+ MISC("t2_so_imm", "kOperandTypeThumb2SoImm"); // I
+ MISC("so_imm2part", "kOperandTypeARMSoImm2Part"); // I
+ MISC("pred", "kOperandTypeARMPredicate"); // I, R
+ MISC("it_pred", "kOperandTypeARMPredicate"); // I
+ MISC("addrmode2", "kOperandTypeARMAddrMode2"); // R, R, I
+ MISC("am2offset", "kOperandTypeARMAddrMode2Offset"); // R, I
+ MISC("addrmode3", "kOperandTypeARMAddrMode3"); // R, R, I
+ MISC("am3offset", "kOperandTypeARMAddrMode3Offset"); // R, I
+ MISC("addrmode4", "kOperandTypeARMAddrMode4"); // R, I
+ MISC("addrmode5", "kOperandTypeARMAddrMode5"); // R, I
+ MISC("addrmode6", "kOperandTypeARMAddrMode6"); // R, R, I, I
+ MISC("am6offset", "kOperandTypeARMAddrMode6Offset"); // R, I, I
+ MISC("addrmodepc", "kOperandTypeARMAddrModePC"); // R, I
+ MISC("reglist", "kOperandTypeARMRegisterList"); // I, R, ...
+ MISC("it_mask", "kOperandTypeThumbITMask"); // I
+ MISC("t2addrmode_imm8", "kOperandTypeThumb2AddrModeImm8"); // R, I
+ MISC("t2am_imm8_offset", "kOperandTypeThumb2AddrModeImm8Offset");//I
+ MISC("t2addrmode_imm12", "kOperandTypeThumb2AddrModeImm12"); // R, I
+ MISC("t2addrmode_so_reg", "kOperandTypeThumb2AddrModeSoReg"); // R, R, I
+ MISC("t2addrmode_imm8s4", "kOperandTypeThumb2AddrModeImm8s4"); // R, I
+ MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset");
+ // R, I
+ MISC("tb_addrmode", "kOperandTypeARMTBAddrMode"); // I
+ MISC("t_addrmode_s1", "kOperandTypeThumbAddrModeS1"); // R, I, R
+ MISC("t_addrmode_s2", "kOperandTypeThumbAddrModeS2"); // R, I, R
+ MISC("t_addrmode_s4", "kOperandTypeThumbAddrModeS4"); // R, I, R
+ MISC("t_addrmode_rr", "kOperandTypeThumbAddrModeRR"); // R, R
+ MISC("t_addrmode_sp", "kOperandTypeThumbAddrModeSP"); // R, I
+
+ return 1;
+}
+
+#undef SOREG
+#undef SOIMM
+#undef PRED
+#undef REG
+#undef MEM
+#undef LEA
+#undef IMM
+#undef PCR
+
+#undef SET
+
+/// ARMPopulateOperands - Handles all the operands in an ARM instruction, adding
+/// the appropriate flags to their descriptors
+///
+/// @operandFlags - A reference the array of operand flag objects
+/// @inst - The instruction to use as a source of information
+static void ARMPopulateOperands(
+ LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS],
+ const CodeGenInstruction &inst) {
+ if (!inst.TheDef->isSubClassOf("InstARM") &&
+ !inst.TheDef->isSubClassOf("InstThumb"))
+ return;
+
+ unsigned int index;
+ unsigned int numOperands = inst.OperandList.size();
+
+ if (numOperands > EDIS_MAX_OPERANDS) {
+ errs() << "numOperands == " << numOperands << " > " <<
+ EDIS_MAX_OPERANDS << '\n';
+ llvm_unreachable("Too many operands");
+ }
+
+ for (index = 0; index < numOperands; ++index) {
+ const CodeGenInstruction::OperandInfo &operandInfo =
+ inst.OperandList[index];
+ Record &rec = *operandInfo.Rec;
+
+ if (ARMFlagFromOpName(operandTypes[index], rec.getName())) {
+ errs() << "Operand type: " << rec.getName() << '\n';
+ errs() << "Operand name: " << operandInfo.Name << '\n';
+ errs() << "Instruction mame: " << inst.TheDef->getName() << '\n';
+ llvm_unreachable("Unhandled type");
+ }
+ }
+}
+
+#define BRANCH(target) { \
+ instType.set("kInstructionTypeBranch"); \
+ DECORATE1(target, "kOperandFlagTarget"); \
+}
+
+/// ARMExtractSemantics - Performs various checks on the name of an ARM
+/// instruction to determine what sort of an instruction it is and then adds
+/// the appropriate flags to the instruction and its operands
+///
+/// @arg instType - A reference to the type for the instruction as a whole
+/// @arg operandTypes - A reference to the array of operand type object pointers
+/// @arg operandFlags - A reference to the array of operand flag object pointers
+/// @arg inst - A reference to the original instruction
+static void ARMExtractSemantics(
+ LiteralConstantEmitter &instType,
+ LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS],
+ FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
+ const CodeGenInstruction &inst) {
+ const std::string &name = inst.TheDef->getName();
+
+ if (name == "tBcc" ||
+ name == "tB" ||
+ name == "t2Bcc" ||
+ name == "Bcc" ||
+ name == "tCBZ" ||
+ name == "tCBNZ") {
+ BRANCH("target");
+ }
+
+ if (name == "tBLr9" ||
+ name == "BLr9_pred" ||
+ name == "tBLXi_r9" ||
+ name == "tBLXr_r9" ||
+ name == "BLXr9" ||
+ name == "t2BXJ" ||
+ name == "BXJ") {
+ BRANCH("func");
+
+ unsigned opIndex;
+ opIndex = inst.getOperandNamed("func");
+ if (operandTypes[opIndex]->is("kOperandTypeImmediate"))
+ operandTypes[opIndex]->set("kOperandTypeARMBranchTarget");
+ }
+}
+
+#undef BRANCH
/// populateInstInfo - Fills an array of InstInfos with information about each
/// instruction in a target
@@ -545,8 +736,8 @@ static void X86ExtractSemantics(FlagsConstantEmitter &instFlags,
/// @arg target - The CodeGenTarget to use as a source of instructions
static void populateInstInfo(CompoundConstantEmitter &infoArray,
CodeGenTarget &target) {
- std::vector<const CodeGenInstruction*> numberedInstructions;
- target.getInstructionsByEnumValue(numberedInstructions);
+ const std::vector<const CodeGenInstruction*> &numberedInstructions =
+ target.getInstructionsByEnumValue();
unsigned int index;
unsigned int numInstructions = numberedInstructions.size();
@@ -557,19 +748,29 @@ static void populateInstInfo(CompoundConstantEmitter &infoArray,
CompoundConstantEmitter *infoStruct = new CompoundConstantEmitter;
infoArray.addEntry(infoStruct);
- FlagsConstantEmitter *instFlags = new FlagsConstantEmitter;
- infoStruct->addEntry(instFlags);
+ LiteralConstantEmitter *instType = new LiteralConstantEmitter;
+ infoStruct->addEntry(instType);
LiteralConstantEmitter *numOperandsEmitter =
new LiteralConstantEmitter(inst.OperandList.size());
infoStruct->addEntry(numOperandsEmitter);
+
+ CompoundConstantEmitter *operandTypeArray = new CompoundConstantEmitter;
+ infoStruct->addEntry(operandTypeArray);
+
+ LiteralConstantEmitter *operandTypes[EDIS_MAX_OPERANDS];
CompoundConstantEmitter *operandFlagArray = new CompoundConstantEmitter;
infoStruct->addEntry(operandFlagArray);
- FlagsConstantEmitter *operandFlags[MAX_OPERANDS];
+ FlagsConstantEmitter *operandFlags[EDIS_MAX_OPERANDS];
- for (unsigned operandIndex = 0; operandIndex < MAX_OPERANDS; ++operandIndex) {
+ for (unsigned operandIndex = 0;
+ operandIndex < EDIS_MAX_OPERANDS;
+ ++operandIndex) {
+ operandTypes[operandIndex] = new LiteralConstantEmitter;
+ operandTypeArray->addEntry(operandTypes[operandIndex]);
+
operandFlags[operandIndex] = new FlagsConstantEmitter;
operandFlagArray->addEntry(operandFlags[operandIndex]);
}
@@ -577,32 +778,99 @@ static void populateInstInfo(CompoundConstantEmitter &infoArray,
unsigned numSyntaxes = 0;
if (target.getName() == "X86") {
- X86PopulateOperands(operandFlags, inst);
- X86ExtractSemantics(*instFlags, operandFlags, inst);
+ X86PopulateOperands(operandTypes, inst);
+ X86ExtractSemantics(*instType, operandFlags, inst);
numSyntaxes = 2;
}
+ else if (target.getName() == "ARM") {
+ ARMPopulateOperands(operandTypes, inst);
+ ARMExtractSemantics(*instType, operandTypes, operandFlags, inst);
+ numSyntaxes = 1;
+ }
+
+ CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter;
- CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter;
infoStruct->addEntry(operandOrderArray);
- for (unsigned syntaxIndex = 0; syntaxIndex < MAX_SYNTAXES; ++syntaxIndex) {
- CompoundConstantEmitter *operandOrder = new CompoundConstantEmitter;
+ for (unsigned syntaxIndex = 0;
+ syntaxIndex < EDIS_MAX_SYNTAXES;
+ ++syntaxIndex) {
+ CompoundConstantEmitter *operandOrder =
+ new CompoundConstantEmitter(EDIS_MAX_OPERANDS);
+
operandOrderArray->addEntry(operandOrder);
if (syntaxIndex < numSyntaxes) {
populateOperandOrder(operandOrder, inst, syntaxIndex);
}
- else {
- for (unsigned operandIndex = 0;
- operandIndex < MAX_OPERANDS;
- ++operandIndex) {
- operandOrder->addEntry(new LiteralConstantEmitter("-1"));
- }
- }
}
+
+ infoStruct = NULL;
}
}
+static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
+ EnumEmitter operandTypes("OperandTypes");
+ operandTypes.addEntry("kOperandTypeNone");
+ operandTypes.addEntry("kOperandTypeImmediate");
+ operandTypes.addEntry("kOperandTypeRegister");
+ operandTypes.addEntry("kOperandTypeX86Memory");
+ operandTypes.addEntry("kOperandTypeX86EffectiveAddress");
+ operandTypes.addEntry("kOperandTypeX86PCRelative");
+ operandTypes.addEntry("kOperandTypeARMBranchTarget");
+ operandTypes.addEntry("kOperandTypeARMSoReg");
+ operandTypes.addEntry("kOperandTypeARMSoImm");
+ operandTypes.addEntry("kOperandTypeARMSoImm2Part");
+ operandTypes.addEntry("kOperandTypeARMPredicate");
+ operandTypes.addEntry("kOperandTypeARMAddrMode2");
+ operandTypes.addEntry("kOperandTypeARMAddrMode2Offset");
+ operandTypes.addEntry("kOperandTypeARMAddrMode3");
+ operandTypes.addEntry("kOperandTypeARMAddrMode3Offset");
+ operandTypes.addEntry("kOperandTypeARMAddrMode4");
+ operandTypes.addEntry("kOperandTypeARMAddrMode5");
+ operandTypes.addEntry("kOperandTypeARMAddrMode6");
+ operandTypes.addEntry("kOperandTypeARMAddrMode6Offset");
+ operandTypes.addEntry("kOperandTypeARMAddrModePC");
+ operandTypes.addEntry("kOperandTypeARMRegisterList");
+ operandTypes.addEntry("kOperandTypeARMTBAddrMode");
+ operandTypes.addEntry("kOperandTypeThumbITMask");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeS1");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeS2");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeS4");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeRR");
+ operandTypes.addEntry("kOperandTypeThumbAddrModeSP");
+ operandTypes.addEntry("kOperandTypeThumb2SoReg");
+ operandTypes.addEntry("kOperandTypeThumb2SoImm");
+ operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8");
+ operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8Offset");
+ operandTypes.addEntry("kOperandTypeThumb2AddrModeImm12");
+ operandTypes.addEntry("kOperandTypeThumb2AddrModeSoReg");
+ operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4");
+ operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4Offset");
+ operandTypes.emit(o, i);
+
+ o << "\n";
+
+ EnumEmitter operandFlags("OperandFlags");
+ operandFlags.addEntry("kOperandFlagSource");
+ operandFlags.addEntry("kOperandFlagTarget");
+ operandFlags.emitAsFlags(o, i);
+
+ o << "\n";
+
+ EnumEmitter instructionTypes("InstructionTypes");
+ instructionTypes.addEntry("kInstructionTypeNone");
+ instructionTypes.addEntry("kInstructionTypeMove");
+ instructionTypes.addEntry("kInstructionTypeBranch");
+ instructionTypes.addEntry("kInstructionTypePush");
+ instructionTypes.addEntry("kInstructionTypePop");
+ instructionTypes.addEntry("kInstructionTypeCall");
+ instructionTypes.addEntry("kInstructionTypeReturn");
+ instructionTypes.emit(o, i);
+
+ o << "\n";
+}
+
void EDEmitter::run(raw_ostream &o) {
unsigned int i = 0;
@@ -611,9 +879,15 @@ void EDEmitter::run(raw_ostream &o) {
populateInstInfo(infoArray, target);
- o << "InstInfo instInfo" << target.getName().c_str() << "[] = ";
+ emitCommonEnums(o, i);
+
+ o << "namespace {\n";
+
+ o << "llvm::EDInstInfo instInfo" << target.getName().c_str() << "[] = ";
infoArray.emit(o, i);
o << ";" << "\n";
+
+ o << "}\n";
}
void EDEmitter::runHeader(raw_ostream &o) {
@@ -622,43 +896,13 @@ void EDEmitter::runHeader(raw_ostream &o) {
o << "#ifndef EDInfo_" << "\n";
o << "#define EDInfo_" << "\n";
o << "\n";
- o << "#include <inttypes.h>" << "\n";
- o << "\n";
- o << "#define MAX_OPERANDS " << format("%d", MAX_OPERANDS) << "\n";
- o << "#define MAX_SYNTAXES " << format("%d", MAX_SYNTAXES) << "\n";
+ o << "#define EDIS_MAX_OPERANDS " << format("%d", EDIS_MAX_OPERANDS) << "\n";
+ o << "#define EDIS_MAX_SYNTAXES " << format("%d", EDIS_MAX_SYNTAXES) << "\n";
o << "\n";
unsigned int i = 0;
- EnumEmitter operandFlags("OperandFlags");
- operandFlags.addEntry("kOperandFlagImmediate");
- operandFlags.addEntry("kOperandFlagRegister");
- operandFlags.addEntry("kOperandFlagMemory");
- operandFlags.addEntry("kOperandFlagEffectiveAddress");
- operandFlags.addEntry("kOperandFlagPCRelative");
- operandFlags.addEntry("kOperandFlagSource");
- operandFlags.addEntry("kOperandFlagTarget");
- operandFlags.emitAsFlags(o, i);
-
- o << "\n";
-
- EnumEmitter instructionFlags("InstructionFlags");
- instructionFlags.addEntry("kInstructionFlagMove");
- instructionFlags.addEntry("kInstructionFlagBranch");
- instructionFlags.addEntry("kInstructionFlagPush");
- instructionFlags.addEntry("kInstructionFlagPop");
- instructionFlags.addEntry("kInstructionFlagCall");
- instructionFlags.addEntry("kInstructionFlagReturn");
- instructionFlags.emitAsFlags(o, i);
-
- o << "\n";
-
- StructEmitter instInfo("InstInfo");
- instInfo.addMember("uint32_t", "instructionFlags");
- instInfo.addMember("uint8_t", "numOperands");
- instInfo.addMember("uint8_t", "operandFlags[MAX_OPERANDS]");
- instInfo.addMember("const char", "operandOrders[MAX_SYNTAXES][MAX_OPERANDS]");
- instInfo.emit(o, i);
+ emitCommonEnums(o, i);
o << "\n";
o << "#endif" << "\n";
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index f589bcc..ba59e50 100644
--- a/utils/TableGen/FastISelEmitter.cpp
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -70,14 +70,16 @@ struct OperandsSignature {
for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) {
TreePatternNode *Op = InstPatNode->getChild(i);
// For now, filter out any operand with a predicate.
- if (!Op->getPredicateFns().empty())
- return false;
// For now, filter out any operand with multiple values.
- if (Op->getExtTypes().size() != 1)
+ if (!Op->getPredicateFns().empty() ||
+ Op->getNumTypes() != 1)
return false;
+
+ assert(Op->hasTypeSet(0) && "Type infererence not done?");
// For now, all the operands must have the same type.
- if (Op->getTypeNum(0) != VT)
+ if (Op->getType(0) != VT)
return false;
+
if (!Op->isLeaf()) {
if (Op->getOperator()->getName() == "imm") {
Operands.push_back("i");
@@ -255,7 +257,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
Record *Op = Dst->getOperator();
if (!Op->isSubClassOf("Instruction"))
continue;
- CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op->getName());
+ CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op);
if (II.OperandList.empty())
continue;
@@ -294,12 +296,18 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
if (!InstPatNode) continue;
if (InstPatNode->isLeaf()) continue;
+ // Ignore multiple result nodes for now.
+ if (InstPatNode->getNumTypes() > 1) continue;
+
Record *InstPatOp = InstPatNode->getOperator();
std::string OpcodeName = getOpcodeName(InstPatOp, CGP);
- MVT::SimpleValueType RetVT = InstPatNode->getTypeNum(0);
+ MVT::SimpleValueType RetVT = MVT::isVoid;
+ if (InstPatNode->getNumTypes()) RetVT = InstPatNode->getType(0);
MVT::SimpleValueType VT = RetVT;
- if (InstPatNode->getNumChildren())
- VT = InstPatNode->getChild(0)->getTypeNum(0);
+ if (InstPatNode->getNumChildren()) {
+ assert(InstPatNode->getChild(0)->getNumTypes() == 1);
+ VT = InstPatNode->getChild(0)->getType(0);
+ }
// For now, filter out instructions which just set a register to
// an Operand or an immediate, like MOV32ri.
diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp
index d1e7f3d..47a8474 100644
--- a/utils/TableGen/InstrEnumEmitter.cpp
+++ b/utils/TableGen/InstrEnumEmitter.cpp
@@ -26,22 +26,15 @@ void InstrEnumEmitter::run(raw_ostream &OS) {
CodeGenTarget Target;
// We must emit the PHI opcode first...
- std::string Namespace;
- for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
- E = Target.inst_end(); II != E; ++II) {
- if (II->second.Namespace != "TargetOpcode") {
- Namespace = II->second.Namespace;
- break;
- }
- }
+ std::string Namespace = Target.getInstNamespace();
if (Namespace.empty()) {
fprintf(stderr, "No instructions defined!\n");
exit(1);
}
- std::vector<const CodeGenInstruction*> NumberedInstructions;
- Target.getInstructionsByEnumValue(NumberedInstructions);
+ const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ Target.getInstructionsByEnumValue();
OS << "namespace " << Namespace << " {\n";
OS << " enum {\n";
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index 898c92a..006a2a1 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -39,16 +39,10 @@ static void PrintBarriers(std::vector<Record*> &Barriers,
// Instruction Itinerary Information.
//===----------------------------------------------------------------------===//
-struct RecordNameComparator {
- bool operator()(const Record *Rec1, const Record *Rec2) const {
- return Rec1->getName() < Rec2->getName();
- }
-};
-
void InstrInfoEmitter::GatherItinClasses() {
std::vector<Record*> DefList =
Records.getAllDerivedDefinitions("InstrItinClass");
- std::sort(DefList.begin(), DefList.end(), RecordNameComparator());
+ std::sort(DefList.begin(), DefList.end(), LessRecord());
for (unsigned i = 0, N = DefList.size(); i < N; i++)
ItinClassMap[DefList[i]->getName()] = i;
@@ -149,7 +143,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
const CodeGenTarget &Target = CDP.getTargetInfo();
for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
E = Target.inst_end(); II != E; ++II) {
- std::vector<std::string> OperandInfo = GetOperandInfo(II->second);
+ std::vector<std::string> OperandInfo = GetOperandInfo(**II);
unsigned &N = OperandInfoIDs[OperandInfo];
if (N != 0) continue;
@@ -214,7 +208,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
// Emit all of the instruction's implicit uses and defs.
for (CodeGenTarget::inst_iterator II = Target.inst_begin(),
E = Target.inst_end(); II != E; ++II) {
- Record *Inst = II->second.TheDef;
+ Record *Inst = (*II)->TheDef;
std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses");
if (!Uses.empty()) {
unsigned &IL = EmittedLists[Uses];
@@ -244,8 +238,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
//
OS << "\nstatic const TargetInstrDesc " << TargetName
<< "Insts[] = {\n";
- std::vector<const CodeGenInstruction*> NumberedInstructions;
- Target.getInstructionsByEnumValue(NumberedInstructions);
+ const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ Target.getInstructionsByEnumValue();
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i)
emitRecord(*NumberedInstructions[i], i, InstrInfo, EmittedLists,
@@ -294,19 +288,19 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
if (Inst.isAsCheapAsAMove) OS << "|(1<<TID::CheapAsAMove)";
if (Inst.hasExtraSrcRegAllocReq) OS << "|(1<<TID::ExtraSrcRegAllocReq)";
if (Inst.hasExtraDefRegAllocReq) OS << "|(1<<TID::ExtraDefRegAllocReq)";
- OS << ", 0";
// Emit all of the target-specific flags...
- ListInit *LI = InstrInfo->getValueAsListInit("TSFlagsFields");
- ListInit *Shift = InstrInfo->getValueAsListInit("TSFlagsShifts");
- if (LI->getSize() != Shift->getSize())
- throw "Lengths of " + InstrInfo->getName() +
- ":(TargetInfoFields, TargetInfoPositions) must be equal!";
-
- for (unsigned i = 0, e = LI->getSize(); i != e; ++i)
- emitShiftedValue(Inst.TheDef, dynamic_cast<StringInit*>(LI->getElement(i)),
- dynamic_cast<IntInit*>(Shift->getElement(i)), OS);
-
+ BitsInit *TSF = Inst.TheDef->getValueAsBitsInit("TSFlags");
+ if (!TSF) throw "no TSFlags?";
+ uint64_t Value = 0;
+ for (unsigned i = 0, e = TSF->getNumBits(); i != e; ++i) {
+ if (BitInit *Bit = dynamic_cast<BitInit*>(TSF->getBit(i)))
+ Value |= uint64_t(Bit->getValue()) << i;
+ else
+ throw "Invalid TSFlags bit in " + Inst.TheDef->getName();
+ }
+ OS << ", 0x";
+ OS.write_hex(Value);
OS << ", ";
// Emit the implicit uses and defs lists...
@@ -334,66 +328,6 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
OS << "0";
else
OS << "OperandInfo" << OpInfo.find(OperandInfo)->second;
-
- OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
-}
-
-void InstrInfoEmitter::emitShiftedValue(Record *R, StringInit *Val,
- IntInit *ShiftInt, raw_ostream &OS) {
- if (Val == 0 || ShiftInt == 0)
- throw std::string("Illegal value or shift amount in TargetInfo*!");
- RecordVal *RV = R->getValue(Val->getValue());
- int Shift = ShiftInt->getValue();
-
- if (RV == 0 || RV->getValue() == 0) {
- // This isn't an error if this is a builtin instruction.
- if (R->getName() != "PHI" &&
- R->getName() != "INLINEASM" &&
- R->getName() != "DBG_LABEL" &&
- R->getName() != "EH_LABEL" &&
- R->getName() != "GC_LABEL" &&
- R->getName() != "KILL" &&
- R->getName() != "EXTRACT_SUBREG" &&
- R->getName() != "INSERT_SUBREG" &&
- R->getName() != "IMPLICIT_DEF" &&
- R->getName() != "SUBREG_TO_REG" &&
- R->getName() != "COPY_TO_REGCLASS" &&
- R->getName() != "DBG_VALUE")
- throw R->getName() + " doesn't have a field named '" +
- Val->getValue() + "'!";
- return;
- }
-
- Init *Value = RV->getValue();
- if (BitInit *BI = dynamic_cast<BitInit*>(Value)) {
- if (BI->getValue()) OS << "|(1<<" << Shift << ")";
- return;
- } else if (BitsInit *BI = dynamic_cast<BitsInit*>(Value)) {
- // Convert the Bits to an integer to print...
- Init *I = BI->convertInitializerTo(new IntRecTy());
- if (I)
- if (IntInit *II = dynamic_cast<IntInit*>(I)) {
- if (II->getValue()) {
- if (Shift)
- OS << "|(" << II->getValue() << "<<" << Shift << ")";
- else
- OS << "|" << II->getValue();
- }
- return;
- }
-
- } else if (IntInit *II = dynamic_cast<IntInit*>(Value)) {
- if (II->getValue()) {
- if (Shift)
- OS << "|(" << II->getValue() << "<<" << Shift << ")";
- else
- OS << II->getValue();
- }
- return;
- }
-
- errs() << "Unhandled initializer: " << *Val << "\n";
- throw "In record '" + R->getName() + "' for TSFlag emission.";
+ OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
}
-
diff --git a/utils/TableGen/InstrInfoEmitter.h b/utils/TableGen/InstrInfoEmitter.h
index 657939e..abb1c6b 100644
--- a/utils/TableGen/InstrInfoEmitter.h
+++ b/utils/TableGen/InstrInfoEmitter.h
@@ -47,8 +47,6 @@ private:
std::map<Record*, unsigned> &BM,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS);
- void emitShiftedValue(Record *R, StringInit *Val, IntInit *Shift,
- raw_ostream &OS);
// Itinerary information.
void GatherItinClasses();
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index c5df9e4..417aca7 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -172,10 +172,11 @@ static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType,
static void EmitTypeGenerate(raw_ostream &OS,
const std::vector<Record*> &ArgTypes,
unsigned &ArgNo) {
- if (ArgTypes.size() == 1) {
- EmitTypeGenerate(OS, ArgTypes.front(), ArgNo);
- return;
- }
+ if (ArgTypes.empty())
+ return EmitTypeForValueType(OS, MVT::isVoid);
+
+ if (ArgTypes.size() == 1)
+ return EmitTypeGenerate(OS, ArgTypes.front(), ArgNo);
OS << "StructType::get(Context, ";
@@ -251,11 +252,11 @@ namespace {
unsigned RHSSize = RHSVec->size();
unsigned LHSSize = LHSVec->size();
- do {
+ for (; i != LHSSize; ++i) {
if (i == RHSSize) return false; // RHS is shorter than LHS.
if ((*LHSVec)[i] != (*RHSVec)[i])
return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
- } while (++i != LHSSize);
+ }
if (i != RHSSize) return true;
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
index f9e2fe8..4f9f604 100644
--- a/utils/TableGen/Record.cpp
+++ b/utils/TableGen/Record.cpp
@@ -646,18 +646,8 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
if (LHSs && RHSs) {
DefInit *LOp = dynamic_cast<DefInit*>(LHSs->getOperator());
DefInit *ROp = dynamic_cast<DefInit*>(RHSs->getOperator());
- if (LOp->getDef() != ROp->getDef()) {
- bool LIsOps =
- LOp->getDef()->getName() == "outs" ||
- LOp->getDef()->getName() != "ins" ||
- LOp->getDef()->getName() != "defs";
- bool RIsOps =
- ROp->getDef()->getName() == "outs" ||
- ROp->getDef()->getName() != "ins" ||
- ROp->getDef()->getName() != "defs";
- if (!LIsOps || !RIsOps)
- throw "Concated Dag operators do not match!";
- }
+ if (LOp == 0 || ROp == 0 || LOp->getDef() != ROp->getDef())
+ throw "Concated Dag operators do not match!";
std::vector<Init*> Args;
std::vector<std::string> ArgNames;
for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) {
@@ -1118,12 +1108,15 @@ RecTy *VarInit::getFieldType(const std::string &FieldName) const {
return 0;
}
-Init *VarInit::getFieldInit(Record &R, const std::string &FieldName) const {
+Init *VarInit::getFieldInit(Record &R, const RecordVal *RV,
+ const std::string &FieldName) const {
if (dynamic_cast<RecordRecTy*>(getType()))
- if (const RecordVal *RV = R.getValue(VarName)) {
- Init *TheInit = RV->getValue();
+ if (const RecordVal *Val = R.getValue(VarName)) {
+ if (RV != Val && (RV || dynamic_cast<UnsetInit*>(Val->getValue())))
+ return 0;
+ Init *TheInit = Val->getValue();
assert(TheInit != this && "Infinite loop detected!");
- if (Init *I = TheInit->getFieldInit(R, FieldName))
+ if (Init *I = TheInit->getFieldInit(R, RV, FieldName))
return I;
else
return 0;
@@ -1184,7 +1177,8 @@ RecTy *DefInit::getFieldType(const std::string &FieldName) const {
return 0;
}
-Init *DefInit::getFieldInit(Record &R, const std::string &FieldName) const {
+Init *DefInit::getFieldInit(Record &R, const RecordVal *RV,
+ const std::string &FieldName) const {
return Def->getValue(FieldName)->getValue();
}
@@ -1195,7 +1189,7 @@ std::string DefInit::getAsString() const {
Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV,
unsigned Bit) {
- if (Init *BitsVal = Rec->getFieldInit(R, FieldName))
+ if (Init *BitsVal = Rec->getFieldInit(R, RV, FieldName))
if (BitsInit *BI = dynamic_cast<BitsInit*>(BitsVal)) {
assert(Bit < BI->getNumBits() && "Bit reference out of range!");
Init *B = BI->getBit(Bit);
@@ -1208,7 +1202,7 @@ Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV,
Init *FieldInit::resolveListElementReference(Record &R, const RecordVal *RV,
unsigned Elt) {
- if (Init *ListVal = Rec->getFieldInit(R, FieldName))
+ if (Init *ListVal = Rec->getFieldInit(R, RV, FieldName))
if (ListInit *LI = dynamic_cast<ListInit*>(ListVal)) {
if (Elt >= LI->getSize()) return 0;
Init *E = LI->getElement(Elt);
@@ -1225,7 +1219,7 @@ Init *FieldInit::resolveListElementReference(Record &R, const RecordVal *RV,
Init *FieldInit::resolveReferences(Record &R, const RecordVal *RV) {
Init *NewRec = RV ? Rec->resolveReferences(R, RV) : Rec;
- Init *BitsVal = NewRec->getFieldInit(R, FieldName);
+ Init *BitsVal = NewRec->getFieldInit(R, RV, FieldName);
if (BitsVal) {
Init *BVR = BitsVal->resolveReferences(R, RV);
return BVR->isComplete() ? BVR : this;
@@ -1313,7 +1307,6 @@ void Record::resolveReferencesTo(const RecordVal *RV) {
}
}
-
void Record::dump() const { errs() << *this; }
raw_ostream &llvm::operator<<(raw_ostream &OS, const Record &R) {
diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h
index 90096e9..576d626 100644
--- a/utils/TableGen/Record.h
+++ b/utils/TableGen/Record.h
@@ -503,7 +503,8 @@ struct Init {
/// initializer for the specified field. If getFieldType returns non-null
/// this method should return non-null, otherwise it returns null.
///
- virtual Init *getFieldInit(Record &R, const std::string &FieldName) const {
+ virtual Init *getFieldInit(Record &R, const RecordVal *RV,
+ const std::string &FieldName) const {
return 0;
}
@@ -608,6 +609,11 @@ public:
if (!getBit(i)->isComplete()) return false;
return true;
}
+ bool allInComplete() const {
+ for (unsigned i = 0; i != getNumBits(); ++i)
+ if (getBit(i)->isComplete()) return false;
+ return true;
+ }
virtual std::string getAsString() const;
virtual Init *resolveReferences(Record &R, const RecordVal *RV);
@@ -950,7 +956,8 @@ public:
unsigned Elt);
virtual RecTy *getFieldType(const std::string &FieldName) const;
- virtual Init *getFieldInit(Record &R, const std::string &FieldName) const;
+ virtual Init *getFieldInit(Record &R, const RecordVal *RV,
+ const std::string &FieldName) const;
/// resolveReferences - This method is used by classes that refer to other
/// variables which may not be defined at the time they expression is formed.
@@ -1035,7 +1042,8 @@ public:
//virtual Init *convertInitializerBitRange(const std::vector<unsigned> &Bits);
virtual RecTy *getFieldType(const std::string &FieldName) const;
- virtual Init *getFieldInit(Record &R, const std::string &FieldName) const;
+ virtual Init *getFieldInit(Record &R, const RecordVal *RV,
+ const std::string &FieldName) const;
virtual std::string getAsString() const;
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 9ac652f..b04eaf8 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -203,7 +203,8 @@ unsigned SubtargetEmitter::CollectAllItinClasses(raw_ostream &OS,
// data initialization for the specified itinerary. N is the number
// of stages.
//
-void SubtargetEmitter::FormItineraryStageString(Record *ItinData,
+void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
+ Record *ItinData,
std::string &ItinString,
unsigned &NStages) {
// Get states list
@@ -216,7 +217,7 @@ void SubtargetEmitter::FormItineraryStageString(Record *ItinData,
// Next stage
const Record *Stage = StageList[i];
- // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc }
+ // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }
int Cycles = Stage->getValueAsInt("Cycles");
ItinString += " { " + itostr(Cycles) + ", ";
@@ -226,13 +227,16 @@ void SubtargetEmitter::FormItineraryStageString(Record *ItinData,
// For each unit
for (unsigned j = 0, M = UnitList.size(); j < M;) {
// Add name and bitwise or
- ItinString += UnitList[j]->getName();
+ ItinString += Name + "FU::" + UnitList[j]->getName();
if (++j < M) ItinString += " | ";
}
int TimeInc = Stage->getValueAsInt("TimeInc");
ItinString += ", " + itostr(TimeInc);
+ int Kind = Stage->getValueAsInt("Kind");
+ ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);
+
// Close off stage
ItinString += " }";
if (++i < N) ItinString += ", ";
@@ -276,9 +280,29 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
// If just no itinerary then don't bother
if (ProcItinList.size() < 2) return;
+ // Emit functional units for all the itineraries.
+ for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
+ // Next record
+ Record *Proc = ProcItinList[i];
+
+ std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
+ if (FUs.empty())
+ continue;
+
+ const std::string &Name = Proc->getName();
+ OS << "\n// Functional units for itineraries \"" << Name << "\"\n"
+ << "namespace " << Name << "FU {\n";
+
+ for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
+ OS << " const unsigned " << FUs[j]->getName()
+ << " = 1 << " << j << ";\n";
+
+ OS << "}\n";
+ }
+
// Begin stages table
- std::string StageTable = "static const llvm::InstrStage Stages[] = {\n";
- StageTable += " { 0, 0, 0 }, // No itinerary\n";
+ std::string StageTable = "\nstatic const llvm::InstrStage Stages[] = {\n";
+ StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
// Begin operand cycle table
std::string OperandCycleTable = "static const unsigned OperandCycles[] = {\n";
@@ -312,7 +336,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
// Get string and stage count
std::string ItinStageString;
unsigned NStages;
- FormItineraryStageString(ItinData, ItinStageString, NStages);
+ FormItineraryStageString(Name, ItinData, ItinStageString, NStages);
// Get string and operand cycle count
std::string ItinOperandCycleString;
@@ -367,7 +391,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
}
// Closing stage
- StageTable += " { 0, 0, 0 } // End itinerary\n";
+ StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n";
StageTable += "};\n";
// Closing operand cycles
@@ -564,9 +588,9 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "#include \"llvm/Support/raw_ostream.h\"\n";
OS << "#include \"llvm/Target/SubtargetFeature.h\"\n";
OS << "#include \"llvm/Target/TargetInstrItineraries.h\"\n\n";
-
- Enumeration(OS, "FuncUnit", true);
- OS<<"\n";
+
+// Enumeration(OS, "FuncUnit", true);
+// OS<<"\n";
// Enumeration(OS, "InstrItinClass", false);
// OS<<"\n";
Enumeration(OS, "SubtargetFeature", true);
diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h
index 1d7088f..f43a443 100644
--- a/utils/TableGen/SubtargetEmitter.h
+++ b/utils/TableGen/SubtargetEmitter.h
@@ -34,7 +34,8 @@ class SubtargetEmitter : public TableGenBackend {
void CPUKeyValues(raw_ostream &OS);
unsigned CollectAllItinClasses(raw_ostream &OS,
std::map<std::string, unsigned> &ItinClassesMap);
- void FormItineraryStageString(Record *ItinData, std::string &ItinString,
+ void FormItineraryStageString(const std::string &Names,
+ Record *ItinData, std::string &ItinString,
unsigned &NStages);
void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
unsigned &NOperandCycles);
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index f20ec00..1c66399 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -31,10 +31,10 @@
#include "OptParserEmitter.h"
#include "Record.h"
#include "RegisterInfoEmitter.h"
+#include "ARMDecoderEmitter.h"
#include "SubtargetEmitter.h"
#include "TGParser.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
@@ -48,6 +48,7 @@ enum ActionType {
GenEmitter,
GenRegisterEnums, GenRegister, GenRegisterHeader,
GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher,
+ GenARMDecoder,
GenDisassembler,
GenCallingConv,
GenClangDiagsDefs,
@@ -84,6 +85,8 @@ namespace {
"Generate calling convention descriptions"),
clEnumValN(GenAsmWriter, "gen-asm-writer",
"Generate assembly writer"),
+ clEnumValN(GenARMDecoder, "gen-arm-decoder",
+ "Generate decoders for ARM/Thumb"),
clEnumValN(GenDisassembler, "gen-disassembler",
"Generate disassembler"),
clEnumValN(GenAsmMatcher, "gen-asm-matcher",
@@ -229,6 +232,9 @@ int main(int argc, char **argv) {
case GenAsmWriter:
AsmWriterEmitter(Records).run(*Out);
break;
+ case GenARMDecoder:
+ ARMDecoderEmitter(Records).run(*Out);
+ break;
case GenAsmMatcher:
AsmMatcherEmitter(Records).run(*Out);
break;
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index be07031..2176224 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -161,7 +161,7 @@ void DisassemblerTables::emitOneID(raw_ostream &o,
/// @param i - The indentation level for that output stream.
static void emitEmptyTable(raw_ostream &o, uint32_t &i)
{
- o.indent(i * 2) << "InstrUID modRMEmptyTable[1] = { 0 };" << "\n";
+ o.indent(i * 2) << "static InstrUID modRMEmptyTable[1] = { 0 };" << "\n";
o << "\n";
}
@@ -275,7 +275,7 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
return;
}
- o1.indent(i1) << "InstrUID modRMTable" << thisTableNumber;
+ o1.indent(i1) << "static InstrUID modRMTable" << thisTableNumber;
switch (dt) {
default:
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index ea78d41..b15db2f 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -298,6 +298,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
Name.find("_int") != Name.npos ||
Name.find("Int_") != Name.npos ||
Name.find("_NOREX") != Name.npos ||
+ Name.find("_TC") != Name.npos ||
Name.find("EH_RETURN") != Name.npos ||
Name.find("V_SET") != Name.npos ||
Name.find("LOCK_") != Name.npos ||
@@ -819,7 +820,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i128mem", TYPE_M128)
TYPE("i64i32imm_pcrel", TYPE_REL64)
TYPE("i32imm_pcrel", TYPE_REL32)
- TYPE("SSECC", TYPE_IMM8)
+ TYPE("SSECC", TYPE_IMM3)
TYPE("brtarget", TYPE_RELv)
TYPE("brtarget8", TYPE_REL8)
TYPE("f80mem", TYPE_M80FP)
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
index 1fa3fdf..33f471d 100755
--- a/utils/buildit/build_llvm
+++ b/utils/buildit/build_llvm
@@ -106,11 +106,10 @@ if [ "x$RC_ProjectName" = "xllvmCore_EmbeddedHosted" ]; then
# Try to use the platform llvm-gcc. Fall back to gcc if it's not available.
for prog in gcc g++ ; do
P=$DIR/bin/arm-apple-darwin$DARWIN_VERS-${prog}
-# FIXME: Uncomment once llvm-gcc works for this
-# T=`xcrun -find llvm-${prog}`
-# if [ "x$T" = "x" ] ; then
+ T=`xcrun -find llvm-${prog}`
+ if [ "x$T" = "x" ] ; then
T=`xcrun -sdk $SDKROOT -find ${prog}`
-# fi
+ fi
echo '#!/bin/sh' > $P || exit 1
echo 'exec '$T' -arch armv6 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1
chmod a+x $P || exit 1
@@ -204,6 +203,7 @@ fi
make $JOBS_FLAG $OPTIMIZE_OPTS UNIVERSAL=1 UNIVERSAL_ARCH="$TARGETS" \
UNIVERSAL_SDK_PATH=$HOST_SDKROOT \
NO_RUNTIME_LIBS=1 \
+ DISABLE_EDIS=1 \
LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'" \
@@ -228,6 +228,7 @@ cd $DIR/obj-llvm || exit 1
# Install the tree into the destination directory.
make $LOCAL_MAKEFLAGS $OPTIMIZE_OPTS UNIVERSAL=1 UNIVERSAL_ARCH="$TARGETS" \
NO_RUNTIME_LIBS=1 \
+ DISABLE_EDIS=1 \
LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
OPTIMIZE_OPTION='-O3' VERBOSE=1 install
diff --git a/utils/fpcmp/fpcmp.cpp b/utils/fpcmp/fpcmp.cpp
index 66d8ab1..5f6b5e8 100644
--- a/utils/fpcmp/fpcmp.cpp
+++ b/utils/fpcmp/fpcmp.cpp
@@ -14,7 +14,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
-#include <iostream>
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
@@ -37,7 +37,7 @@ int main(int argc, char **argv) {
sys::PathWithStatus(File2),
AbsTolerance, RelTolerance, &ErrorMsg);
if (!ErrorMsg.empty())
- std::cerr << argv[0] << ": " << ErrorMsg << "\n";
+ errs() << argv[0] << ": " << ErrorMsg << "\n";
return DF;
}
diff --git a/utils/lit/lit/ExampleTests/Clang/lit.cfg b/utils/lit/lit/ExampleTests/Clang/lit.cfg
index 114ac60..1e1e807 100644
--- a/utils/lit/lit/ExampleTests/Clang/lit.cfg
+++ b/utils/lit/lit/ExampleTests/Clang/lit.cfg
@@ -41,40 +41,7 @@ def inferClang(PATH):
return clang
-def inferClangCC(clang, PATH):
- clangcc = os.getenv('CLANGCC')
-
- # If the user set clang in the environment, definitely use that and don't
- # try to validate.
- if clangcc:
- return clangcc
-
- # Otherwise try adding -cc since we expect to be looking in a build
- # directory.
- if clang.endswith('.exe'):
- clangccName = clang[:-4] + '-cc.exe'
- else:
- clangccName = clang + '-cc'
- clangcc = lit.util.which(clangccName, PATH)
- if not clangcc:
- # Otherwise ask clang.
- res = lit.util.capture([clang, '-print-prog-name=clang-cc'])
- res = res.strip()
- if res and os.path.exists(res):
- clangcc = res
-
- if not clangcc:
- lit.fatal("couldn't find 'clang-cc' program, try setting "
- "CLANGCC in your environment")
-
- return clangcc
-
clang = inferClang(config.environment['PATH'])
if not lit.quiet:
lit.note('using clang: %r' % clang)
config.substitutions.append( (' clang ', ' ' + clang + ' ') )
-
-clang_cc = inferClangCC(clang, config.environment['PATH'])
-if not lit.quiet:
- lit.note('using clang-cc: %r' % clang_cc)
-config.substitutions.append( (' clang-cc ', ' ' + clang_cc + ' ') )
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll
index 4e8a582..3ff3633 100644
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll
+++ b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll
@@ -1 +1 @@
-; RUN: grep "hi" %S/data.txt \ No newline at end of file
+; RUN: grep "hi" %S/data.txt
diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py
index 0e0a493..9b62470 100644
--- a/utils/lit/lit/LitConfig.py
+++ b/utils/lit/lit/LitConfig.py
@@ -15,7 +15,7 @@ class LitConfig:
import Util as util
def __init__(self, progname, path, quiet,
- useValgrind, valgrindArgs,
+ useValgrind, valgrindLeakCheck, valgrindArgs,
useTclAsSh,
noExecute, debug, isWindows,
params):
@@ -25,7 +25,8 @@ class LitConfig:
self.path = list(map(str, path))
self.quiet = bool(quiet)
self.useValgrind = bool(useValgrind)
- self.valgrindArgs = list(valgrindArgs)
+ self.valgrindLeakCheck = bool(valgrindLeakCheck)
+ self.valgrindUserArgs = list(valgrindArgs)
self.useTclAsSh = bool(useTclAsSh)
self.noExecute = noExecute
self.debug = debug
@@ -36,6 +37,22 @@ class LitConfig:
self.numErrors = 0
self.numWarnings = 0
+ self.valgrindArgs = []
+ self.valgrindTriple = ""
+ if self.useValgrind:
+ self.valgrindTriple = "-vg"
+ self.valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no',
+ '--tool=memcheck', '--trace-children=yes',
+ '--error-exitcode=123']
+ if self.valgrindLeakCheck:
+ self.valgrindTriple += "_leak"
+ self.valgrindArgs.append('--leak-check=full')
+ else:
+ # The default is 'summary'.
+ self.valgrindArgs.append('--leak-check=no')
+ self.valgrindArgs.extend(self.valgrindUserArgs)
+
+
def load_config(self, config, path):
"""load_config(config, path) - Load a config object from an alternate
path."""
diff --git a/utils/lit/lit/LitFormats.py b/utils/lit/lit/LitFormats.py
index 270f087..e86f103 100644
--- a/utils/lit/lit/LitFormats.py
+++ b/utils/lit/lit/LitFormats.py
@@ -1,3 +1,2 @@
from TestFormats import GoogleTest, ShTest, TclTest
from TestFormats import SyntaxCheckTest, OneCommandPerFileTest
-
diff --git a/utils/lit/lit/LitTestCase.py b/utils/lit/lit/LitTestCase.py
new file mode 100644
index 0000000..8951185
--- /dev/null
+++ b/utils/lit/lit/LitTestCase.py
@@ -0,0 +1,30 @@
+import unittest
+import Test
+
+"""
+TestCase adaptor for providing a 'unittest' compatible interface to 'lit' tests.
+"""
+
+class UnresolvedError(RuntimeError):
+ pass
+
+class LitTestCase(unittest.TestCase):
+ def __init__(self, test, lit_config):
+ unittest.TestCase.__init__(self)
+ self._test = test
+ self._lit_config = lit_config
+
+ def id(self):
+ return self._test.getFullName()
+
+ def shortDescription(self):
+ return self._test.getFullName()
+
+ def runTest(self):
+ tr, output = self._test.config.test_format.execute(
+ self._test, self._lit_config)
+
+ if tr is Test.UNRESOLVED:
+ raise UnresolvedError(output)
+ elif tr.isFailure:
+ self.fail(output)
diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py
index d87a467..5e1a811 100644
--- a/utils/lit/lit/TestFormats.py
+++ b/utils/lit/lit/TestFormats.py
@@ -72,6 +72,9 @@ class GoogleTest(object):
testName = os.path.join(namePrefix, testName)
cmd = [testPath, '--gtest_filter=' + testName]
+ if litConfig.useValgrind:
+ cmd = litConfig.valgrindArgs + cmd
+
out, err, exitCode = TestRunner.executeCommand(
cmd, env=test.config.environment)
@@ -87,8 +90,9 @@ class FileBasedTest(object):
litConfig, localConfig):
source_path = testSuite.getSourcePath(path_in_suite)
for filename in os.listdir(source_path):
- # Ignore dot files.
- if filename.startswith('.'):
+ # Ignore dot files and excluded tests.
+ if (filename.startswith('.') or
+ filename in localConfig.excludes):
continue
filepath = os.path.join(source_path, filename)
@@ -125,14 +129,20 @@ class OneCommandPerFileTest:
self.command = [command]
else:
self.command = list(command)
- self.dir = str(dir)
+ if dir is not None:
+ dir = str(dir)
+ self.dir = dir
self.recursive = bool(recursive)
self.pattern = re.compile(pattern)
self.useTempInput = useTempInput
def getTestsInDirectory(self, testSuite, path_in_suite,
litConfig, localConfig):
- for dirname,subdirs,filenames in os.walk(self.dir):
+ dir = self.dir
+ if dir is None:
+ dir = testSuite.getSourcePath(path_in_suite)
+
+ for dirname,subdirs,filenames in os.walk(dir):
if not self.recursive:
subdirs[:] = []
@@ -147,7 +157,7 @@ class OneCommandPerFileTest:
continue
path = os.path.join(dirname,filename)
- suffix = path[len(self.dir):]
+ suffix = path[len(dir):]
if suffix.startswith(os.sep):
suffix = suffix[1:]
test = Test.Test(testSuite,
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index a7de2b7..d10e4b0 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -63,6 +63,7 @@ def executeShCmd(cmd, cfg, cwd, results):
procs = []
input = subprocess.PIPE
stderrTempFiles = []
+ opened_files = []
# To avoid deadlock, we use a single stderr stream for piped
# output. This is null until we have seen some output using
# stderr.
@@ -113,8 +114,11 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
r[2] = open(r[0], r[1])
# Workaround a Win32 and/or subprocess bug when appending.
+ #
+ # FIXME: Actually, this is probably an instance of PR6753.
if r[1] == 'a':
r[2].seek(0, 2)
+ opened_files.append(r[2])
result = r[2]
final_redirects.append(result)
@@ -176,7 +180,7 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
err = ''
procData[i] = (out,err)
-
+
# Read stderr out of the temp files.
for i,f in stderrTempFiles:
f.seek(0, 0)
@@ -199,6 +203,10 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
exitCode = res
+ # Explicitly close any redirected files.
+ for f in opened_files:
+ f.close()
+
if cmd.negate:
exitCode = not exitCode
@@ -252,6 +260,14 @@ def executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd):
except:
return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln)
+ if litConfig.useValgrind:
+ for pipeline in cmds:
+ if pipeline.commands:
+ # Only valgrind the first command in each pipeline, to avoid
+ # valgrinding things like grep, not, and FileCheck.
+ cmd = pipeline.commands[0]
+ cmd.args = litConfig.valgrindArgs + cmd.args
+
cmd = cmds[0]
for c in cmds[1:]:
cmd = ShUtil.Seq(cmd, '&&', c)
@@ -327,12 +343,7 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
if litConfig.useValgrind:
# FIXME: Running valgrind on sh is overkill. We probably could just
# run on clang with no real loss.
- valgrindArgs = ['valgrind', '-q',
- '--tool=memcheck', '--trace-children=yes',
- '--error-exitcode=123']
- valgrindArgs.extend(litConfig.valgrindArgs)
-
- command = valgrindArgs + command
+ command = litConfig.valgrindArgs + command
return executeCommand(command, cwd=cwd, env=test.config.environment)
@@ -353,8 +364,6 @@ def isExpectedFail(xfails, xtargets, target_triple):
return True
-import re
-
def parseIntegratedTestScript(test):
"""parseIntegratedTestScript - Scan an LLVM/Clang style integrated test
script and extract the lines to 'RUN' as well as 'XFAIL' and 'XTARGET'
@@ -387,21 +396,7 @@ def parseIntegratedTestScript(test):
script = []
xfails = []
xtargets = []
- ignoredAny = False
for ln in open(sourcepath):
- conditional = re.search('IF\((.+?)\((.+?)\)\):', ln)
- if conditional:
- ln = ln[conditional.end():]
- condition = conditional.group(1)
- value = conditional.group(2)
-
- # Actually test the condition.
- if condition not in test.config.conditions:
- return (Test.UNRESOLVED, "unknown condition '"+condition+"'")
- if not test.config.conditions[condition](value):
- ignoredAny = True
- continue
-
if 'RUN:' in ln:
# Isolate the command to run.
index = ln.index('RUN:')
@@ -438,8 +433,6 @@ def parseIntegratedTestScript(test):
# Verify the script contains a run line.
if not script:
- if ignoredAny:
- return (Test.UNSUPPORTED, "Test has only ignored run lines")
return (Test.UNRESOLVED, "Test has no run line!")
if script[-1][-1] == '\\':
diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py
index d6f2a4d..dd905ef 100644
--- a/utils/lit/lit/TestingConfig.py
+++ b/utils/lit/lit/TestingConfig.py
@@ -28,8 +28,7 @@ class TestingConfig:
on_clone = None,
test_exec_root = None,
test_source_root = None,
- excludes = [],
- conditions = {})
+ excludes = [])
if os.path.exists(path):
# FIXME: Improve detection and error reporting of errors in the
@@ -55,7 +54,7 @@ class TestingConfig:
def __init__(self, parent, name, suffixes, test_format,
environment, substitutions, unsupported, on_clone,
- test_exec_root, test_source_root, excludes, conditions):
+ test_exec_root, test_source_root, excludes):
self.parent = parent
self.name = str(name)
self.suffixes = set(suffixes)
@@ -67,7 +66,6 @@ class TestingConfig:
self.test_exec_root = test_exec_root
self.test_source_root = test_source_root
self.excludes = set(excludes)
- self.conditions = dict(conditions)
def clone(self, path):
# FIXME: Chain implementations?
@@ -77,7 +75,7 @@ class TestingConfig:
self.environment, self.substitutions,
self.unsupported, self.on_clone,
self.test_exec_root, self.test_source_root,
- self.excludes, self.conditions)
+ self.excludes)
if cfg.on_clone:
cfg.on_clone(self, cfg, path)
return cfg
diff --git a/utils/lit/lit/lit.py b/utils/lit/lit/lit.py
index f1f19c4..a29fa42 100755
--- a/utils/lit/lit/lit.py
+++ b/utils/lit/lit/lit.py
@@ -315,6 +315,48 @@ def runTests(numThreads, litConfig, provider, display):
except KeyboardInterrupt:
sys.exit(2)
+def load_test_suite(inputs):
+ import unittest
+
+ # Create the global config object.
+ litConfig = LitConfig.LitConfig(progname = 'lit',
+ path = [],
+ quiet = False,
+ useValgrind = False,
+ valgrindLeakCheck = False,
+ valgrindArgs = [],
+ useTclAsSh = False,
+ noExecute = False,
+ debug = False,
+ isWindows = (platform.system()=='Windows'),
+ params = {})
+
+ # Load the tests from the inputs.
+ tests = []
+ testSuiteCache = {}
+ localConfigCache = {}
+ for input in inputs:
+ prev = len(tests)
+ tests.extend(getTests(input, litConfig,
+ testSuiteCache, localConfigCache)[1])
+ if prev == len(tests):
+ litConfig.warning('input %r contained no tests' % input)
+
+ # If there were any errors during test discovery, exit now.
+ if litConfig.numErrors:
+ print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors
+ sys.exit(2)
+
+ # Return a unittest test suite which just runs the tests in order.
+ def get_test_fn(test):
+ return unittest.FunctionTestCase(
+ lambda: test.config.test_format.execute(
+ test, litConfig),
+ description = test.getFullName())
+
+ from LitTestCase import LitTestCase
+ return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests])
+
def main():
# Bump the GIL check interval, its more important to get any one thread to a
# blocking operation (hopefully exec) than to try and unblock other threads.
@@ -362,6 +404,9 @@ def main():
group.add_option("", "--vg", dest="useValgrind",
help="Run tests under valgrind",
action="store_true", default=False)
+ group.add_option("", "--vg-leak", dest="valgrindLeakCheck",
+ help="Check for memory leaks under valgrind",
+ action="store_true", default=False)
group.add_option("", "--vg-arg", dest="valgrindArgs", metavar="ARG",
help="Specify an extra argument for valgrind",
type=str, action="append", default=[])
@@ -411,7 +456,14 @@ def main():
gSiteConfigName = '%s.site.cfg' % opts.configPrefix
if opts.numThreads is None:
- opts.numThreads = Util.detectCPUs()
+# Python <2.5 has a race condition causing lit to always fail with numThreads>1
+# http://bugs.python.org/issue1731717
+# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple
+# threads by default there.
+ if sys.hexversion >= 0x2050200:
+ opts.numThreads = Util.detectCPUs()
+ else:
+ opts.numThreads = 1
inputs = args
@@ -429,6 +481,7 @@ def main():
path = opts.path,
quiet = opts.quiet,
useValgrind = opts.useValgrind,
+ valgrindLeakCheck = opts.valgrindLeakCheck,
valgrindArgs = opts.valgrindArgs,
useTclAsSh = opts.useTclAsSh,
noExecute = opts.noExecute,
diff --git a/utils/mkpatch b/utils/mkpatch
index 278a241..2741563 100755
--- a/utils/mkpatch
+++ b/utils/mkpatch
@@ -23,7 +23,7 @@ echo "mkpatch: Generating differences on all directories"
svn diff -x -u >> "$NAME".patch.raw 2>&1 \
autoconf docs utils include lib/System lib/Support lib/VMCore lib/AsmParser \
lib/Bitcode lib/Analysis lib/Transforms lib/CodeGen lib/Target \
- lib/ExecutionEngine lib/Linker \
+ lib/ExecutionEngine lib/Linker lib/MC \
tools test unittests runtime projects examples Xcode
echo "mkpatch: Removing cruft from the patch file"
diff --git a/utils/unittest/UnitTestMain/Makefile b/utils/unittest/UnitTestMain/Makefile
index 328d5e2..5c10049 100644
--- a/utils/unittest/UnitTestMain/Makefile
+++ b/utils/unittest/UnitTestMain/Makefile
@@ -14,7 +14,13 @@ include $(LEVEL)/Makefile.config
LIBRARYNAME = UnitTestMain
BUILD_ARCHIVE = 1
REQUIRES_RTTI = 1
+
CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include
CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS)
+CPP.Flags += -DGTEST_HAS_RTTI=0
+# libstdc++'s TR1 <tuple> header depends on RTTI and uses C++'0x features not
+# supported by Clang, so force googletest to use its own tuple implementation.
+# When we import googletest >=1.4.0, we can drop this line.
+CPP.Flags += -DGTEST_HAS_TR1_TUPLE=0
include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile
index 15bbf4e..1ec979d 100644
--- a/utils/unittest/googletest/Makefile
+++ b/utils/unittest/googletest/Makefile
@@ -14,8 +14,18 @@ include $(LEVEL)/Makefile.config
LIBRARYNAME = GoogleTest
BUILD_ARCHIVE = 1
REQUIRES_RTTI = 1
+
+# Note that these flags are duplicated when building individual tests in
+# unittests/Makefile.unittest and ../UnitTestMain/Makefile; ensure that any
+# changes are made to both.
CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include
CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS)
+CPP.Flags += -DGTEST_HAS_RTTI=0
+# libstdc++'s TR1 <tuple> header depends on RTTI and uses C++'0x features not
+# supported by Clang, so force googletest to use its own tuple implementation.
+# When we import googletest >=1.4.0, we can drop this line.
+CPP.Flags += -DGTEST_HAS_TR1_TUPLE=0
+
ifeq ($(HOST_OS),MingW)
CPP.Flags += -DGTEST_OS_WINDOWS=1
diff --git a/utils/unittest/googletest/gtest-filepath.cc b/utils/unittest/googletest/gtest-filepath.cc
index 640c27c..493ba0b 100644
--- a/utils/unittest/googletest/gtest-filepath.cc
+++ b/utils/unittest/googletest/gtest-filepath.cc
@@ -167,7 +167,7 @@ bool FilePath::FileOrDirectoryExists() const {
return _stat(pathname_.c_str(), &file_stat) == 0;
#endif // _WIN32_WCE
#else
- struct stat file_stat = {};
+ struct stat file_stat;
return stat(pathname_.c_str(), &file_stat) == 0;
#endif // GTEST_OS_WINDOWS
}
@@ -195,7 +195,7 @@ bool FilePath::DirectoryExists() const {
(_S_IFDIR & file_stat.st_mode) != 0;
#endif // _WIN32_WCE
#else
- struct stat file_stat = {};
+ struct stat file_stat;
result = stat(pathname_.c_str(), &file_stat) == 0 &&
S_ISDIR(file_stat.st_mode);
#endif // GTEST_OS_WINDOWS
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h b/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h
index f98af0b..d4c7a39b 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-linked_ptr.h
@@ -176,6 +176,7 @@ class linked_ptr {
// Sole ownership by this linked_ptr object is required.
T* release() {
bool last = link_.depart();
+ (void) last;
assert(last);
T* v = value_;
value_ = NULL;
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
index 3e49993..20a95c9 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
@@ -227,9 +227,10 @@
// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
// is available.
-#if defined(GTEST_OS_CYGWIN) || defined(GTEST_OS_SOLARIS) || defined(GTEST_OS_HAIKU)
+#if defined(GTEST_OS_CYGWIN) || defined(GTEST_OS_SOLARIS) || defined(GTEST_OS_HAIKU) || defined(_MINIX)
// At least some versions of cygwin don't support ::std::wstring.
// Solaris' libc++ doesn't support it either.
+// Minix currently doesn't support it either.
#define GTEST_HAS_STD_WSTRING 0
#else
#define GTEST_HAS_STD_WSTRING GTEST_HAS_STD_STRING