diff options
author | Shih-wei Liao <sliao@google.com> | 2010-04-28 01:47:00 -0700 |
---|---|---|
committer | Shih-wei Liao <sliao@google.com> | 2010-04-28 01:47:00 -0700 |
commit | 7abe37e4aee38cc79d91dd069a37d7e91d5bef53 (patch) | |
tree | c13b26fc3d8909240f981988535c0b82dd9bf37c /utils | |
parent | 6037a7c3c97b651dd70e48ebe5453134713971ed (diff) | |
download | external_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')
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 |