aboutsummaryrefslogtreecommitdiff
path: root/utils/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'utils/TableGen')
-rw-r--r--utils/TableGen/ARMDecoderEmitter.cpp1790
-rw-r--r--utils/TableGen/ARMDecoderEmitter.h49
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp439
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp185
-rw-r--r--utils/TableGen/AsmWriterEmitter.h2
-rw-r--r--utils/TableGen/CMakeLists.txt5
-rw-r--r--utils/TableGen/CallingConvEmitter.cpp6
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp26
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp22
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h10
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp45
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp1028
-rw-r--r--utils/TableGen/CodeGenRegisters.h247
-rw-r--r--utils/TableGen/CodeGenTarget.cpp29
-rw-r--r--utils/TableGen/CodeGenTarget.h10
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp6
-rw-r--r--utils/TableGen/DAGISelMatcher.h3
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp11
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp2
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp512
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.h52
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp1
-rw-r--r--utils/TableGen/EDEmitter.cpp36
-rw-r--r--utils/TableGen/FastISelEmitter.cpp3
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp334
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.h18
-rw-r--r--utils/TableGen/InstrEnumEmitter.cpp48
-rw-r--r--utils/TableGen/InstrEnumEmitter.h33
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp49
-rw-r--r--utils/TableGen/InstrInfoEmitter.h10
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp139
-rw-r--r--utils/TableGen/IntrinsicEmitter.h2
-rw-r--r--utils/TableGen/LLVMBuild.txt22
-rw-r--r--utils/TableGen/PseudoLoweringEmitter.cpp9
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp821
-rw-r--r--utils/TableGen/RegisterInfoEmitter.h6
-rw-r--r--utils/TableGen/SequenceToOffsetTable.h139
-rw-r--r--utils/TableGen/SetTheory.cpp23
-rw-r--r--utils/TableGen/SetTheory.h8
-rw-r--r--utils/TableGen/StringToOffsetTable.h13
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp82
-rw-r--r--utils/TableGen/TableGen.cpp173
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp148
-rw-r--r--utils/TableGen/X86ModRMFilters.cpp26
-rw-r--r--utils/TableGen/X86ModRMFilters.h15
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp236
-rw-r--r--utils/TableGen/X86RecognizableInstr.h10
47 files changed, 3672 insertions, 3211 deletions
diff --git a/utils/TableGen/ARMDecoderEmitter.cpp b/utils/TableGen/ARMDecoderEmitter.cpp
deleted file mode 100644
index 145b96df98e2..000000000000
--- a/utils/TableGen/ARMDecoderEmitter.cpp
+++ /dev/null
@@ -1,1790 +0,0 @@
-//===------------ 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 "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/TableGen/Record.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_DPSOREGREGFRM, 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_SATFRM, 13) \
- ENTRY(ARM_FORMAT_EXTFRM, 14) \
- ENTRY(ARM_FORMAT_VFPUNARYFRM, 15) \
- ENTRY(ARM_FORMAT_VFPBINARYFRM, 16) \
- ENTRY(ARM_FORMAT_VFPCONV1FRM, 17) \
- ENTRY(ARM_FORMAT_VFPCONV2FRM, 18) \
- ENTRY(ARM_FORMAT_VFPCONV3FRM, 19) \
- ENTRY(ARM_FORMAT_VFPCONV4FRM, 20) \
- ENTRY(ARM_FORMAT_VFPCONV5FRM, 21) \
- ENTRY(ARM_FORMAT_VFPLDSTFRM, 22) \
- ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 23) \
- ENTRY(ARM_FORMAT_VFPMISCFRM, 24) \
- ENTRY(ARM_FORMAT_THUMBFRM, 25) \
- ENTRY(ARM_FORMAT_MISCFRM, 26) \
- ENTRY(ARM_FORMAT_NEONGETLNFRM, 27) \
- ENTRY(ARM_FORMAT_NEONSETLNFRM, 28) \
- ENTRY(ARM_FORMAT_NEONDUPFRM, 29) \
- ENTRY(ARM_FORMAT_NLdSt, 30) \
- ENTRY(ARM_FORMAT_N1RegModImm, 31) \
- ENTRY(ARM_FORMAT_N2Reg, 32) \
- ENTRY(ARM_FORMAT_NVCVT, 33) \
- ENTRY(ARM_FORMAT_NVecDupLn, 34) \
- ENTRY(ARM_FORMAT_N2RegVecShL, 35) \
- ENTRY(ARM_FORMAT_N2RegVecShR, 36) \
- ENTRY(ARM_FORMAT_N3Reg, 37) \
- ENTRY(ARM_FORMAT_N3RegVecSh, 38) \
- ENTRY(ARM_FORMAT_NVecExtract, 39) \
- ENTRY(ARM_FORMAT_NVecMulScalar, 40) \
- ENTRY(ARM_FORMAT_NVTBL, 41) \
- ENTRY(ARM_FORMAT_DPSOREGIMMFRM, 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 ARMFilterChooser;
-
-// 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 conflict 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 ARMFilter {
-protected:
- ARMFilterChooser *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, ARMFilterChooser*> 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.
- ARMFilterChooser &getVariableFC() {
- assert(NumFiltered == 1);
- assert(FilterChooserMap.size() == 1);
- return *(FilterChooserMap.find((unsigned)-1)->second);
- }
-
- ARMFilter(const ARMFilter &f);
- ARMFilter(ARMFilterChooser &owner, unsigned startBit, unsigned numBits,
- bool mixed);
-
- ~ARMFilter();
-
- // 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;
-
-/// ARMFilterChooser - 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 ARMFilterChooser {
- static TARGET_NAME_t TargetName;
-
-protected:
- friend class ARMFilter;
-
- // 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<ARMFilter> 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.
- ARMFilterChooser *Parent;
-
- // Index of the best filter from Filters.
- int BestIndex;
-
-public:
- static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; }
-
- ARMFilterChooser(const ARMFilterChooser &FC) :
- AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes),
- Filters(FC.Filters), Parent(FC.Parent), BestIndex(FC.BestIndex) {
- memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues));
- }
-
- ARMFilterChooser(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();
- }
-
- ARMFilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
- const std::vector<unsigned> &IDs,
- bit_value_t (&ParentFilterBitValues)[BIT_WIDTH],
- ARMFilterChooser &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 {
- if (AllInstructions[Opcode]->isPseudo)
- return;
-
- 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.
- Record *R = AllInstructions[Opcode]->TheDef;
- if (R->getValue("IndexModeBits") &&
- getByteField(*R, "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);
-
- ARMFilter &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,
- ARMFilter &Best);
-
- // Assign a single filter and run with it.
- void runSingleFilter(ARMFilterChooser &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 //
-// //
-///////////////////////////
-
-ARMFilter::ARMFilter(const ARMFilter &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) {
-}
-
-ARMFilter::ARMFilter(ARMFilterChooser &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");
-}
-
-ARMFilter::~ARMFilter() {
- std::map<unsigned, ARMFilterChooser*>::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 ARMFilter::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 further processing on this
- // group of instructions whose segment values are variable.
- FilterChooserMap.insert(std::pair<unsigned, ARMFilterChooser*>(
- (unsigned)-1,
- new ARMFilterChooser(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 further processing on this
- // category of instructions.
- FilterChooserMap.insert(std::pair<unsigned, ARMFilterChooser*>(
- mapIterator->first,
- new ARMFilterChooser(Owner->AllInstructions,
- mapIterator->second,
- BitValueArray,
- *Owner)
- ));
- }
-}
-
-// Emit code to decode instructions given a segment or segments of bits.
-void ARMFilter::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, ARMFilterChooser*>::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 ARMFilter::usefulness() const {
- if (VariableInstructions.size())
- return FilteredInstructions.size();
- else
- return FilteredInstructions.size() + 1;
-}
-
-//////////////////////////////////
-// //
-// Filterchooser Implementation //
-// //
-//////////////////////////////////
-
-// Define the symbol here.
-TARGET_NAME_t ARMFilterChooser::TargetName;
-
-// This provides an opportunity for target specific code emission.
-void ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
- ARMFilterChooser *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 ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::emitSingletonDecoder(raw_ostream &o,
- unsigned &Indentation,
- ARMFilter &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 ARMFilterChooser::runSingleFilter(ARMFilterChooser &owner,
- unsigned startBit,
- unsigned numBit, bool mixed) {
- Filters.clear();
- ARMFilter 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 ARMFilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit,
- unsigned BitIndex, bool AllowMixed) {
- if (RA == ATTR_MIXED && AllowMixed)
- Filters.push_back(ARMFilter(*this, StartBit, BitIndex - StartBit, true));
- else if (RA == ATTR_ALL_SET && !AllowMixed)
- Filters.push_back(ARMFilter(*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 ARMFilterChooser::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 ARMFilterChooser::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 ARMFilterChooser::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) {
- ARMFilter &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. tLDMIA, tLDMIA_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 == "tLDMIA" && name2 == "tLDMIA_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, RecordKeeper &Records) :
- NumberedInstructions(),
- Opcodes(),
- Frontend(frontend),
- Target(Records),
- 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;
- ARMFilterChooser *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;
-
- // Ignore "asm parser only" instructions.
- if (Def.getValueAsBit("isAsmParserOnly"))
- return false;
-
- if (TN == TARGET_ARM) {
- if (Form == ARM_FORMAT_PSEUDO)
- return false;
- if (thumbInstruction(Form))
- return false;
-
- // Tail calls are other patterns that generate existing instructions.
- if (Name == "TCRETURNdi" || Name == "TCRETURNdiND" ||
- Name == "TCRETURNri" || Name == "TCRETURNriND" ||
- Name == "TAILJMPd" || Name == "TAILJMPdt" ||
- Name == "TAILJMPdND" || Name == "TAILJMPdNDt" ||
- Name == "TAILJMPr" || Name == "TAILJMPrND" ||
- Name == "MOVr_TC")
- return false;
-
- // Delegate ADR disassembly to the more generic ADDri/SUBri instructions.
- if (Name == "ADR")
- return false;
-
- //
- // The following special cases are for conflict resolutions.
- //
-
- // 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;
- } else if (TN == TARGET_THUMB) {
- if (!thumbInstruction(Form))
- return false;
-
- // A8.6.25 BX. Use the generic tBX_Rm, ignore tBX_RET and tBX_RET_vararg.
- if (Name == "tBX_RET" || Name == "tBX_RET_vararg")
- return false;
-
- // Ignore tADR, prefer tADDrPCi.
- if (Name == "tADR")
- return false;
-
- // Delegate t2ADR disassembly to the more generic t2ADDri12/t2SUBri12
- // instructions.
- if (Name == "t2ADR")
- 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].
- if (Name == "tADDrSP" || Name == "tADDspr" || Name == "tPICADD" ||
- Name == "t2SUBrSPs" || Name == "t2ADDrSPs")
- return false;
-
- // FIXME: Use ldr.n to work around a Darwin assembler bug.
- // Introduce a workaround with tLDRpciDIS opcode.
- if (Name == "tLDRpci")
- return false;
-
- // Ignore t2LDRDpci, prefer the generic t2LDRDi8, t2LDRD_PRE, t2LDRD_POST.
- if (Name == "t2LDRDpci")
- return false;
-
- // Resolve conflicts:
- //
- // t2LDMIA_RET conflict with t2LDM (ditto)
- // tMOVCCi conflicts with tMOVi8
- // tMOVCCr conflicts with tMOVgpr2gpr
- // tLDRcp conflicts with tLDRspi
- // t2MOVCCi16 conflicts with tMOVi16
- if (Name == "t2LDMIA_RET" ||
- Name == "tMOVCCi" || Name == "tMOVCCr" ||
- Name == "tLDRcp" ||
- Name == "t2MOVCCi16")
- return false;
- }
-
- DEBUG({
- // Dumps the instruction encoding format.
- switch (TargetName) {
- case TARGET_ARM:
- case TARGET_THUMB:
- errs() << Name << " " << stringForARMFormat((ARMFormat)Form);
- break;
- }
-
- errs() << " ";
-
- // Dumps the instruction encoding bits.
- dumpBits(errs(), Bits);
-
- errs() << '\n';
-
- // Dumps the list of operand info.
- for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
- const CGIOperandList::OperandInfo &Info = CGI.Operands[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);
-
- unsigned numUIDs = NumberedInstructions.size();
- if (TargetName == TARGET_ARM) {
- for (unsigned uid = 0; uid < numUIDs; uid++) {
- // filter out intrinsics
- if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM"))
- 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.
- for (unsigned 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);
- }
-
- return;
- }
-
- // For other targets.
- for (unsigned uid = 0; uid < numUIDs; uid++) {
- Record *R = NumberedInstructions[uid]->TheDef;
- if (R->getValueAsString("Namespace") == "TargetOpcode")
- continue;
-
- if (populateInstruction(*NumberedInstructions[uid], TargetName))
- Opcodes.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/Support/DataTypes.h\"\n";
- o << "#include <assert.h>\n";
- o << '\n';
- o << "namespace llvm {\n\n";
-
- ARMFilterChooser::setTargetName(TargetName);
-
- switch (TargetName) {
- case TARGET_ARM: {
- // Emit common utility and ARM ISA decoder.
- FC = new ARMFilterChooser(NumberedInstructions, Opcodes);
- // Reset indentation level.
- unsigned Indentation = 0;
- FC->emitTop(o, Indentation);
- delete FC;
-
- // Emit Thumb ISA decoder as well.
- ARMFilterChooser::setTargetName(TARGET_THUMB);
- FC = new ARMFilterChooser(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, Records);
-}
-
-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
deleted file mode 100644
index 486f899354f4..000000000000
--- a/utils/TableGen/ARMDecoderEmitter.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//===------------ 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 "llvm/Support/DataTypes.h"
-#include "llvm/TableGen/TableGenBackend.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/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 8b86c23d0632..39a3c25d99da 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -99,6 +99,7 @@
#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
#include "StringMatcher.h"
+#include "StringToOffsetTable.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -107,6 +108,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include <map>
@@ -251,12 +253,7 @@ public:
switch (Kind) {
case Invalid:
- assert(0 && "Invalid kind!");
- case Token:
- // Tokens are comparable by value.
- //
- // FIXME: Compare by enum value.
- return ValueName < RHS.ValueName;
+ llvm_unreachable("Invalid kind!");
default:
// This class precedes the RHS if it is a proper subset of the RHS.
@@ -287,7 +284,11 @@ struct MatchableInfo {
/// The suboperand index within SrcOpName, or -1 for the entire operand.
int SubOpIdx;
- explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1) {}
+ /// Register record if this token is singleton register.
+ Record *SingletonReg;
+
+ explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1),
+ SingletonReg(0) {}
};
/// ResOperand - This represents a single operand in the result instruction
@@ -366,6 +367,9 @@ struct MatchableInfo {
}
};
+ /// AsmVariantID - Target's assembly syntax variant no.
+ int AsmVariantID;
+
/// TheDef - This is the definition of the instruction or InstAlias that this
/// matchable came from.
Record *const TheDef;
@@ -406,24 +410,28 @@ struct MatchableInfo {
std::string ConversionFnKind;
MatchableInfo(const CodeGenInstruction &CGI)
- : TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) {
+ : AsmVariantID(0), TheDef(CGI.TheDef), DefRec(&CGI),
+ AsmString(CGI.AsmString) {
}
MatchableInfo(const CodeGenInstAlias *Alias)
- : TheDef(Alias->TheDef), DefRec(Alias), AsmString(Alias->AsmString) {
+ : AsmVariantID(0), TheDef(Alias->TheDef), DefRec(Alias),
+ AsmString(Alias->AsmString) {
}
void Initialize(const AsmMatcherInfo &Info,
- SmallPtrSet<Record*, 16> &SingletonRegisters);
+ SmallPtrSet<Record*, 16> &SingletonRegisters,
+ int AsmVariantNo, std::string &RegisterPrefix);
/// Validate - Return true if this matchable is a valid thing to match against
/// and perform a bunch of validity checking.
bool Validate(StringRef CommentDelimiter, bool Hack) const;
- /// getSingletonRegisterForAsmOperand - If the specified token is a singleton
- /// register, return the Record for it, otherwise return null.
- Record *getSingletonRegisterForAsmOperand(unsigned i,
- const AsmMatcherInfo &Info) const;
+ /// extractSingletonRegisterForAsmOperand - Extract singleton register,
+ /// if present, from specified token.
+ void
+ extractSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info,
+ std::string &RegisterPrefix);
/// FindAsmOperand - Find the AsmOperand with the specified name and
/// suboperand index.
@@ -557,9 +565,6 @@ public:
/// Target - The target information.
CodeGenTarget &Target;
- /// The AsmParser "RegisterPrefix" value.
- std::string RegisterPrefix;
-
/// The classes which are needed for matching.
std::vector<ClassInfo*> Classes;
@@ -591,7 +596,8 @@ private:
/// getOperandClass - Lookup or create the class for the given operand.
ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI,
- int SubOpIdx = -1);
+ int SubOpIdx);
+ ClassInfo *getOperandClass(Record *Rec, int SubOpIdx);
/// BuildRegisterClasses - Build the ClassInfo* instances for register
/// classes.
@@ -645,9 +651,11 @@ void MatchableInfo::dump() {
}
void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
- SmallPtrSet<Record*, 16> &SingletonRegisters) {
- // TODO: Eventually support asmparser for Variant != 0.
- AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, 0);
+ SmallPtrSet<Record*, 16> &SingletonRegisters,
+ int AsmVariantNo, std::string &RegisterPrefix) {
+ AsmVariantID = AsmVariantNo;
+ AsmString =
+ CodeGenInstruction::FlattenAsmStringVariants(AsmString, AsmVariantNo);
TokenizeAsmString(Info);
@@ -660,7 +668,8 @@ void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
// Collect singleton registers, if used.
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
- if (Record *Reg = getSingletonRegisterForAsmOperand(i, Info))
+ extractSingletonRegisterForAsmOperand(i, Info, RegisterPrefix);
+ if (Record *Reg = AsmOperands[i].SingletonReg)
SingletonRegisters.insert(Reg);
}
}
@@ -736,9 +745,12 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
// The first token of the instruction is the mnemonic, which must be a
// simple string, not a $foo variable or a singleton register.
- assert(!AsmOperands.empty() && "Instruction has no tokens?");
+ if (AsmOperands.empty())
+ throw TGError(TheDef->getLoc(),
+ "Instruction '" + TheDef->getName() + "' has no tokens");
Mnemonic = AsmOperands[0].Token;
- if (Mnemonic[0] == '$' || getSingletonRegisterForAsmOperand(0, Info))
+ // FIXME : Check and raise an error if it is a register.
+ if (Mnemonic[0] == '$')
throw TGError(TheDef->getLoc(),
"Invalid instruction mnemonic '" + Mnemonic.str() + "'!");
@@ -801,28 +813,30 @@ bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
return true;
}
-/// getSingletonRegisterForAsmOperand - If the specified token is a singleton
-/// register, return the register name, otherwise return a null StringRef.
-Record *MatchableInfo::
-getSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info) const{
- StringRef Tok = AsmOperands[i].Token;
- if (!Tok.startswith(Info.RegisterPrefix))
- return 0;
+/// extractSingletonRegisterForAsmOperand - Extract singleton register,
+/// if present, from specified token.
+void MatchableInfo::
+extractSingletonRegisterForAsmOperand(unsigned OperandNo,
+ const AsmMatcherInfo &Info,
+ std::string &RegisterPrefix) {
+ StringRef Tok = AsmOperands[OperandNo].Token;
+ if (RegisterPrefix.empty()) {
+ std::string LoweredTok = Tok.lower();
+ if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(LoweredTok))
+ AsmOperands[OperandNo].SingletonReg = Reg->TheDef;
+ return;
+ }
+
+ if (!Tok.startswith(RegisterPrefix))
+ return;
- StringRef RegName = Tok.substr(Info.RegisterPrefix.size());
+ StringRef RegName = Tok.substr(RegisterPrefix.size());
if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(RegName))
- return Reg->TheDef;
+ AsmOperands[OperandNo].SingletonReg = Reg->TheDef;
// If there is no register prefix (i.e. "%" in "%eax"), then this may
// be some random non-register token, just ignore it.
- if (Info.RegisterPrefix.empty())
- return 0;
-
- // Otherwise, we have something invalid prefixed with the register prefix,
- // such as %foo.
- std::string Err = "unable to find register for '" + RegName.str() +
- "' (which matches register prefix)";
- throw TGError(TheDef->getLoc(), Err);
+ return;
}
static std::string getEnumNameForToken(StringRef Str) {
@@ -870,7 +884,11 @@ AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI,
Record *Rec = OI.Rec;
if (SubOpIdx != -1)
Rec = dynamic_cast<DefInit*>(OI.MIOperandInfo->getArg(SubOpIdx))->getDef();
+ return getOperandClass(Rec, SubOpIdx);
+}
+ClassInfo *
+AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) {
if (Rec->isSubClassOf("RegisterOperand")) {
// RegisterOperand may have an associated ParserMatchClass. If it does,
// use it, else just fall back to the underlying register class.
@@ -1102,8 +1120,7 @@ void AsmMatcherInfo::BuildOperandClasses() {
AsmMatcherInfo::AsmMatcherInfo(Record *asmParser,
CodeGenTarget &target,
RecordKeeper &records)
- : Records(records), AsmParser(asmParser), Target(target),
- RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) {
+ : Records(records), AsmParser(asmParser), Target(target) {
}
/// BuildOperandMatchInfo - Build the necessary information to handle user
@@ -1158,86 +1175,92 @@ void AsmMatcherInfo::BuildInfo() {
assert(FeatureNo < 32 && "Too many subtarget features!");
}
- std::string CommentDelimiter = AsmParser->getValueAsString("CommentDelimiter");
-
// Parse the instructions; we need to do this first so that we can gather the
// singleton register classes.
SmallPtrSet<Record*, 16> SingletonRegisters;
- for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
- E = Target.inst_end(); I != E; ++I) {
- const CodeGenInstruction &CGI = **I;
-
- // If the tblgen -match-prefix option is specified (for tblgen hackers),
- // filter the set of instructions we consider.
- if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix))
- continue;
+ unsigned VariantCount = Target.getAsmParserVariantCount();
+ for (unsigned VC = 0; VC != VariantCount; ++VC) {
+ Record *AsmVariant = Target.getAsmParserVariant(VC);
+ std::string CommentDelimiter = AsmVariant->getValueAsString("CommentDelimiter");
+ std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
+ int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
+
+ for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
+ E = Target.inst_end(); I != E; ++I) {
+ const CodeGenInstruction &CGI = **I;
+
+ // If the tblgen -match-prefix option is specified (for tblgen hackers),
+ // filter the set of instructions we consider.
+ if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix))
+ continue;
- // Ignore "codegen only" instructions.
- if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
- continue;
+ // Ignore "codegen only" instructions.
+ if (CGI.TheDef->getValueAsBit("isCodeGenOnly"))
+ continue;
- // Validate the operand list to ensure we can handle this instruction.
- for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
- const CGIOperandList::OperandInfo &OI = CGI.Operands[i];
-
- // Validate tied operands.
- if (OI.getTiedRegister() != -1) {
- // If we have a tied operand that consists of multiple MCOperands,
- // reject it. We reject aliases and ignore instructions for now.
- if (OI.MINumOperands != 1) {
- // FIXME: Should reject these. The ARM backend hits this with $lane
- // in a bunch of instructions. It is unclear what the right answer is.
- DEBUG({
- errs() << "warning: '" << CGI.TheDef->getName() << "': "
- << "ignoring instruction with multi-operand tied operand '"
- << OI.Name << "'\n";
- });
- continue;
+ // Validate the operand list to ensure we can handle this instruction.
+ for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) {
+ const CGIOperandList::OperandInfo &OI = CGI.Operands[i];
+
+ // Validate tied operands.
+ if (OI.getTiedRegister() != -1) {
+ // If we have a tied operand that consists of multiple MCOperands,
+ // reject it. We reject aliases and ignore instructions for now.
+ if (OI.MINumOperands != 1) {
+ // FIXME: Should reject these. The ARM backend hits this with $lane
+ // in a bunch of instructions. It is unclear what the right answer is.
+ DEBUG({
+ errs() << "warning: '" << CGI.TheDef->getName() << "': "
+ << "ignoring instruction with multi-operand tied operand '"
+ << OI.Name << "'\n";
+ });
+ continue;
+ }
}
}
- }
- OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
+ OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
- II->Initialize(*this, SingletonRegisters);
+ II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
- // Ignore instructions which shouldn't be matched and diagnose invalid
- // instruction definitions with an error.
- if (!II->Validate(CommentDelimiter, true))
- continue;
+ // Ignore instructions which shouldn't be matched and diagnose invalid
+ // instruction definitions with an error.
+ if (!II->Validate(CommentDelimiter, true))
+ continue;
- // Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
- //
- // FIXME: This is a total hack.
- if (StringRef(II->TheDef->getName()).startswith("Int_") ||
- StringRef(II->TheDef->getName()).endswith("_Int"))
- continue;
+ // Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
+ //
+ // FIXME: This is a total hack.
+ if (StringRef(II->TheDef->getName()).startswith("Int_") ||
+ StringRef(II->TheDef->getName()).endswith("_Int"))
+ continue;
- Matchables.push_back(II.take());
- }
+ Matchables.push_back(II.take());
+ }
- // Parse all of the InstAlias definitions and stick them in the list of
- // matchables.
- std::vector<Record*> AllInstAliases =
- Records.getAllDerivedDefinitions("InstAlias");
- for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) {
- CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target);
-
- // If the tblgen -match-prefix option is specified (for tblgen hackers),
- // filter the set of instruction aliases we consider, based on the target
- // instruction.
- if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith(
- MatchPrefix))
- continue;
+ // Parse all of the InstAlias definitions and stick them in the list of
+ // matchables.
+ std::vector<Record*> AllInstAliases =
+ Records.getAllDerivedDefinitions("InstAlias");
+ for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) {
+ CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target);
+
+ // If the tblgen -match-prefix option is specified (for tblgen hackers),
+ // filter the set of instruction aliases we consider, based on the target
+ // instruction.
+ if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith(
+ MatchPrefix))
+ continue;
- OwningPtr<MatchableInfo> II(new MatchableInfo(Alias));
+ OwningPtr<MatchableInfo> II(new MatchableInfo(Alias));
- II->Initialize(*this, SingletonRegisters);
+ II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
- // Validate the alias definitions.
- II->Validate(CommentDelimiter, false);
+ // Validate the alias definitions.
+ II->Validate(CommentDelimiter, false);
- Matchables.push_back(II.take());
+ Matchables.push_back(II.take());
+ }
}
// Build info for the register classes.
@@ -1260,7 +1283,7 @@ void AsmMatcherInfo::BuildInfo() {
StringRef Token = Op.Token;
// Check for singleton registers.
- if (Record *RegRecord = II->getSingletonRegisterForAsmOperand(i, *this)) {
+ if (Record *RegRecord = II->AsmOperands[i].SingletonReg) {
Op.Class = RegisterClasses[RegRecord];
assert(Op.Class && Op.Class->Registers.size() == 1 &&
"Unexpected class for singleton register");
@@ -1297,6 +1320,17 @@ void AsmMatcherInfo::BuildInfo() {
II->BuildAliasResultOperands();
}
+ // Process token alias definitions and set up the associated superclass
+ // information.
+ std::vector<Record*> AllTokenAliases =
+ Records.getAllDerivedDefinitions("TokenAlias");
+ for (unsigned i = 0, e = AllTokenAliases.size(); i != e; ++i) {
+ Record *Rec = AllTokenAliases[i];
+ ClassInfo *FromClass = getTokenClass(Rec->getValueAsString("FromToken"));
+ ClassInfo *ToClass = getTokenClass(Rec->getValueAsString("ToToken"));
+ FromClass->SuperClasses.push_back(ToClass);
+ }
+
// Reorder classes so that classes precede super classes.
std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
}
@@ -1375,9 +1409,11 @@ void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
CGA.ResultOperands[i].getName() == OperandName) {
// It's safe to go with the first one we find, because CodeGenInstAlias
// validates that all operands with the same name have the same record.
- unsigned ResultIdx = CGA.ResultInstOperandIndex[i].first;
Op.SubOpIdx = CGA.ResultInstOperandIndex[i].second;
- Op.Class = getOperandClass(CGA.ResultInst->Operands[ResultIdx],
+ // Use the match class from the Alias definition, not the
+ // destination instruction, as we may have an immediate that's
+ // being munged by the match class.
+ Op.Class = getOperandClass(CGA.ResultOperands[i].getRecord(),
Op.SubOpIdx);
Op.SrcOpName = OperandName;
return;
@@ -1453,7 +1489,6 @@ void MatchableInfo::BuildAliasResultOperands() {
// Find out what operand from the asmparser that this MCInst operand
// comes from.
switch (CGA.ResultOperands[AliasOpNo].Kind) {
- default: assert(0 && "unexpected InstAlias operand kind");
case CodeGenInstAlias::ResultOperand::K_Record: {
StringRef Name = CGA.ResultOperands[AliasOpNo].getName();
int SrcOperand = FindAsmOperand(Name, SubIdx);
@@ -1656,7 +1691,7 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
/// EmitValidateOperandClass - Emit the function to validate an operand class.
static void EmitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
- OS << "static bool ValidateOperandClass(MCParsedAsmOperand *GOp, "
+ OS << "static bool validateOperandClass(MCParsedAsmOperand *GOp, "
<< "MatchClassKind Kind) {\n";
OS << " " << Info.Target.getName() << "Operand &Operand = *("
<< Info.Target.getName() << "Operand*)GOp;\n";
@@ -1667,7 +1702,8 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
// Check for Token operands first.
OS << " if (Operand.isToken())\n";
- OS << " return MatchTokenString(Operand.getToken()) == Kind;\n\n";
+ OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind);"
+ << "\n\n";
// Check for register operands, including sub-classes.
OS << " if (Operand.isReg()) {\n";
@@ -1681,7 +1717,7 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
<< it->first->getName() << ": OpKind = " << it->second->Name
<< "; break;\n";
OS << " }\n";
- OS << " return IsSubclass(OpKind, Kind);\n";
+ OS << " return isSubclass(OpKind, Kind);\n";
OS << " }\n\n";
// Check the user classes. We don't care what order since we're only
@@ -1708,8 +1744,8 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
static void EmitIsSubclass(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
- OS << "/// IsSubclass - Compute whether \\arg A is a subclass of \\arg B.\n";
- OS << "static bool IsSubclass(MatchClassKind A, MatchClassKind B) {\n";
+ OS << "/// isSubclass - Compute whether \\arg A is a subclass of \\arg B.\n";
+ OS << "static bool isSubclass(MatchClassKind A, MatchClassKind B) {\n";
OS << " if (A == B)\n";
OS << " return true;\n\n";
@@ -1720,32 +1756,30 @@ static void EmitIsSubclass(CodeGenTarget &Target,
ie = Infos.end(); it != ie; ++it) {
ClassInfo &A = **it;
- if (A.Kind != ClassInfo::Token) {
- std::vector<StringRef> SuperClasses;
- for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
- ie = Infos.end(); it != ie; ++it) {
- ClassInfo &B = **it;
-
- if (&A != &B && A.isSubsetOf(B))
- SuperClasses.push_back(B.Name);
- }
+ std::vector<StringRef> SuperClasses;
+ for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
+ ie = Infos.end(); it != ie; ++it) {
+ ClassInfo &B = **it;
- if (SuperClasses.empty())
- continue;
+ if (&A != &B && A.isSubsetOf(B))
+ SuperClasses.push_back(B.Name);
+ }
- OS << "\n case " << A.Name << ":\n";
+ if (SuperClasses.empty())
+ continue;
- if (SuperClasses.size() == 1) {
- OS << " return B == " << SuperClasses.back() << ";\n";
- continue;
- }
+ OS << "\n case " << A.Name << ":\n";
- OS << " switch (B) {\n";
- OS << " default: return false;\n";
- for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
- OS << " case " << SuperClasses[i] << ": return true;\n";
- OS << " }\n";
+ if (SuperClasses.size() == 1) {
+ OS << " return B == " << SuperClasses.back() << ";\n";
+ continue;
}
+
+ OS << " switch (B) {\n";
+ OS << " default: return false;\n";
+ for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
+ OS << " case " << SuperClasses[i] << ": return true;\n";
+ OS << " }\n";
}
OS << " }\n";
OS << "}\n\n";
@@ -1767,7 +1801,7 @@ static void EmitMatchTokenString(CodeGenTarget &Target,
"return " + CI.Name + ";"));
}
- OS << "static MatchClassKind MatchTokenString(StringRef Name) {\n";
+ OS << "static MatchClassKind matchTokenString(StringRef Name) {\n";
StringMatcher("Name", Matches, OS).Emit();
@@ -1905,7 +1939,7 @@ static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
Info.getRecords().getAllDerivedDefinitions("MnemonicAlias");
if (Aliases.empty()) return false;
- OS << "static void ApplyMnemonicAliases(StringRef &Mnemonic, "
+ OS << "static void applyMnemonicAliases(StringRef &Mnemonic, "
"unsigned Features) {\n";
// Keep track of all the aliases from a mnemonic. Use an std::map so that the
@@ -1975,45 +2009,62 @@ static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
return true;
}
+static const char *getMinimalTypeForRange(uint64_t Range) {
+ assert(Range < 0xFFFFFFFFULL && "Enum too large");
+ if (Range > 0xFFFF)
+ return "uint32_t";
+ if (Range > 0xFF)
+ return "uint16_t";
+ return "uint8_t";
+}
+
static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
const AsmMatcherInfo &Info, StringRef ClassName) {
// Emit the static custom operand parsing table;
OS << "namespace {\n";
OS << " struct OperandMatchEntry {\n";
- OS << " const char *Mnemonic;\n";
- OS << " unsigned OperandMask;\n";
- OS << " MatchClassKind Class;\n";
- OS << " unsigned RequiredFeatures;\n";
+ OS << " static const char *const MnemonicTable;\n";
+ OS << " uint32_t OperandMask;\n";
+ OS << " uint32_t Mnemonic;\n";
+ OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size())
+ << " RequiredFeatures;\n";
+ OS << " " << getMinimalTypeForRange(Info.Classes.size())
+ << " Class;\n\n";
+ OS << " StringRef getMnemonic() const {\n";
+ OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n";
+ OS << " MnemonicTable[Mnemonic]);\n";
+ OS << " }\n";
OS << " };\n\n";
OS << " // Predicate for searching for an opcode.\n";
OS << " struct LessOpcodeOperand {\n";
OS << " bool operator()(const OperandMatchEntry &LHS, StringRef RHS) {\n";
- OS << " return StringRef(LHS.Mnemonic) < RHS;\n";
+ OS << " return LHS.getMnemonic() < RHS;\n";
OS << " }\n";
OS << " bool operator()(StringRef LHS, const OperandMatchEntry &RHS) {\n";
- OS << " return LHS < StringRef(RHS.Mnemonic);\n";
+ OS << " return LHS < RHS.getMnemonic();\n";
OS << " }\n";
OS << " bool operator()(const OperandMatchEntry &LHS,";
OS << " const OperandMatchEntry &RHS) {\n";
- OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n";
+ OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n";
OS << " }\n";
OS << " };\n";
OS << "} // end anonymous namespace.\n\n";
+ StringToOffsetTable StringTable;
+
OS << "static const OperandMatchEntry OperandMatchTable["
<< Info.OperandMatchInfo.size() << "] = {\n";
- OS << " /* Mnemonic, Operand List Mask, Operand Class, Features */\n";
+ OS << " /* Operand List Mask, Mnemonic, Operand Class, Features */\n";
for (std::vector<OperandMatchEntry>::const_iterator it =
Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end();
it != ie; ++it) {
const OperandMatchEntry &OMI = *it;
const MatchableInfo &II = *OMI.MI;
- OS << " { \"" << II.Mnemonic << "\""
- << ", " << OMI.OperandMask;
+ OS << " { " << OMI.OperandMask;
OS << " /* ";
bool printComma = false;
@@ -2026,8 +2077,10 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
}
OS << " */";
- OS << ", " << OMI.CI->Name
- << ", ";
+ // Store a pascal-style length byte in the mnemonic.
+ std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
+ OS << ", " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
+ << " /* " << II.Mnemonic << " */, ";
// Write the required features mask.
if (!II.RequiredFeatures.empty()) {
@@ -2037,15 +2090,22 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
}
} else
OS << "0";
+
+ OS << ", " << OMI.CI->Name;
+
OS << " },\n";
}
OS << "};\n\n";
+ OS << "const char *const OperandMatchEntry::MnemonicTable =\n";
+ StringTable.EmitString(OS);
+ OS << ";\n\n";
+
// Emit the operand class switch to call the correct custom parser for
// the found operand class.
OS << Target.getName() << ClassName << "::OperandMatchResultTy "
<< Target.getName() << ClassName << "::\n"
- << "TryCustomParseOperand(SmallVectorImpl<MCParsedAsmOperand*>"
+ << "tryCustomParseOperand(SmallVectorImpl<MCParsedAsmOperand*>"
<< " &Operands,\n unsigned MCK) {\n\n"
<< " switch(MCK) {\n";
@@ -2094,7 +2154,7 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
<< " *ie = MnemonicRange.second; it != ie; ++it) {\n";
OS << " // equal_range guarantees that instruction mnemonic matches.\n";
- OS << " assert(Mnemonic == it->Mnemonic);\n\n";
+ OS << " assert(Mnemonic == it->getMnemonic());\n\n";
// Emit check that the required features are available.
OS << " // check if the available features match\n";
@@ -2111,7 +2171,7 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// Emit call to the custom parser method
OS << " // call custom parse method to handle the operand\n";
OS << " OperandMatchResultTy Result = ";
- OS << "TryCustomParseOperand(Operands, it->Class);\n";
+ OS << "tryCustomParseOperand(Operands, it->Class);\n";
OS << " if (Result != MatchOperand_NoMatch)\n";
OS << " return Result;\n";
OS << " }\n\n";
@@ -2186,7 +2246,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " bool MnemonicIsValid(StringRef Mnemonic);\n";
OS << " unsigned MatchInstructionImpl(\n";
OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
- OS << " MCInst &Inst, unsigned &ErrorInfo);\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo, unsigned VariantID = 0);\n";
if (Info.OperandMatchInfo.size()) {
OS << "\n enum OperandMatchResultTy {\n";
@@ -2198,7 +2258,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
OS << " StringRef Mnemonic);\n";
- OS << " OperandMatchResultTy TryCustomParseOperand(\n";
+ OS << " OperandMatchResultTy tryCustomParseOperand(\n";
OS << " SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
OS << " unsigned MCK);\n\n";
}
@@ -2260,28 +2320,39 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// following the mnemonic.
OS << "namespace {\n";
OS << " struct MatchEntry {\n";
- OS << " unsigned Opcode;\n";
- OS << " const char *Mnemonic;\n";
- OS << " ConversionKind ConvertFn;\n";
- OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n";
- OS << " unsigned RequiredFeatures;\n";
+ OS << " static const char *const MnemonicTable;\n";
+ OS << " uint32_t Mnemonic;\n";
+ OS << " uint16_t Opcode;\n";
+ OS << " " << getMinimalTypeForRange(Info.Matchables.size())
+ << " ConvertFn;\n";
+ OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size())
+ << " RequiredFeatures;\n";
+ OS << " " << getMinimalTypeForRange(Info.Classes.size())
+ << " Classes[" << MaxNumOperands << "];\n";
+ OS << " uint8_t AsmVariantID;\n\n";
+ OS << " StringRef getMnemonic() const {\n";
+ OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n";
+ OS << " MnemonicTable[Mnemonic]);\n";
+ OS << " }\n";
OS << " };\n\n";
OS << " // Predicate for searching for an opcode.\n";
OS << " struct LessOpcode {\n";
OS << " bool operator()(const MatchEntry &LHS, StringRef RHS) {\n";
- OS << " return StringRef(LHS.Mnemonic) < RHS;\n";
+ OS << " return LHS.getMnemonic() < RHS;\n";
OS << " }\n";
OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n";
- OS << " return LHS < StringRef(RHS.Mnemonic);\n";
+ OS << " return LHS < RHS.getMnemonic();\n";
OS << " }\n";
OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n";
- OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n";
+ OS << " return LHS.getMnemonic() < RHS.getMnemonic();\n";
OS << " }\n";
OS << " };\n";
OS << "} // end anonymous namespace.\n\n";
+ StringToOffsetTable StringTable;
+
OS << "static const MatchEntry MatchTable["
<< Info.Matchables.size() << "] = {\n";
@@ -2290,16 +2361,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
it != ie; ++it) {
MatchableInfo &II = **it;
- OS << " { " << Target.getName() << "::"
- << II.getResultInst()->TheDef->getName() << ", \"" << II.Mnemonic << "\""
- << ", " << II.ConversionFnKind << ", { ";
- for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
- MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
-
- if (i) OS << ", ";
- OS << Op.Class->Name;
- }
- OS << " }, ";
+ // Store a pascal-style length byte in the mnemonic.
+ std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
+ OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
+ << " /* " << II.Mnemonic << " */, "
+ << Target.getName() << "::"
+ << II.getResultInst()->TheDef->getName() << ", "
+ << II.ConversionFnKind << ", ";
// Write the required features mask.
if (!II.RequiredFeatures.empty()) {
@@ -2310,11 +2378,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
} else
OS << "0";
+ OS << ", { ";
+ for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
+ MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
+
+ if (i) OS << ", ";
+ OS << Op.Class->Name;
+ }
+ OS << " }, " << II.AsmVariantID;
OS << "},\n";
}
OS << "};\n\n";
+ OS << "const char *const MatchEntry::MnemonicTable =\n";
+ StringTable.EmitString(OS);
+ OS << ";\n\n";
+
// A method to determine if a mnemonic is in the list.
OS << "bool " << Target.getName() << ClassName << "::\n"
<< "MnemonicIsValid(StringRef Mnemonic) {\n";
@@ -2330,7 +2410,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< Target.getName() << ClassName << "::\n"
<< "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>"
<< " &Operands,\n";
- OS << " MCInst &Inst, unsigned &ErrorInfo) {\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo,\n";
+ OS << " unsigned VariantID) {\n";
// Emit code to get the available features.
OS << " // Get the current feature set.\n";
@@ -2342,7 +2423,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (HasMnemonicAliases) {
OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
- OS << " ApplyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
+ OS << " // FIXME : Add an entry in AsmParserVariant to check this.\n";
+ OS << " if (!VariantID)\n";
+ OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
}
// Emit code to compute the class list for this operand vector.
@@ -2375,16 +2458,18 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " it != ie; ++it) {\n";
OS << " // equal_range guarantees that instruction mnemonic matches.\n";
- OS << " assert(Mnemonic == it->Mnemonic);\n";
+ OS << " assert(Mnemonic == it->getMnemonic());\n";
// Emit check that the subclasses match.
+ OS << " if (VariantID != it->AsmVariantID) continue;\n";
OS << " bool OperandsValid = true;\n";
OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n";
OS << " if (i + 1 >= Operands.size()) {\n";
OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
OS << " break;\n";
OS << " }\n";
- OS << " if (ValidateOperandClass(Operands[i+1], it->Classes[i]))\n";
+ OS << " if (validateOperandClass(Operands[i+1], "
+ "(MatchClassKind)it->Classes[i]))\n";
OS << " continue;\n";
OS << " // If this operand is broken for all of the instances of this\n";
OS << " // mnemonic, keep track of it so we can report loc info.\n";
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index 3123e11f774f..e0b0aace33e6 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -16,6 +16,7 @@
#include "AsmWriterInst.h"
#include "CodeGenTarget.h"
#include "StringToOffsetTable.h"
+#include "SequenceToOffsetTable.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
@@ -277,12 +278,27 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i]));
// Build an aggregate string, and build a table of offsets into it.
- StringToOffsetTable StringTable;
+ SequenceToOffsetTable<std::string> StringTable;
/// OpcodeInfo - This encodes the index of the string to use for the first
/// chunk of the output as well as indices used for operand printing.
std::vector<unsigned> OpcodeInfo;
+ // Add all strings to the string table upfront so it can generate an optimized
+ // representation.
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]];
+ if (AWI != 0 &&
+ AWI->Operands[0].OperandType == AsmWriterOperand::isLiteralTextOperand &&
+ !AWI->Operands[0].Str.empty()) {
+ std::string Str = AWI->Operands[0].Str;
+ UnescapeString(Str);
+ StringTable.add(Str);
+ }
+ }
+
+ StringTable.layout();
+
unsigned MaxStringIdx = 0;
for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]];
@@ -294,11 +310,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
AsmWriterOperand::isLiteralTextOperand ||
AWI->Operands[0].Str.empty()) {
// Something handled by the asmwriter printer, but with no leading string.
- Idx = StringTable.GetOrAddStringOffset("");
+ Idx = StringTable.get("");
} else {
std::string Str = AWI->Operands[0].Str;
UnescapeString(Str);
- Idx = StringTable.GetOrAddStringOffset(Str);
+ Idx = StringTable.get(Str);
MaxStringIdx = std::max(MaxStringIdx, Idx);
// Nuke the string from the operand list. It is now handled!
@@ -373,9 +389,9 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
O << " };\n\n";
// Emit the string itself.
- O << " const char *AsmStrs = \n";
- StringTable.EmitString(O);
- O << ";\n\n";
+ O << " const char AsmStrs[] = {\n";
+ StringTable.emit(O, printChar);
+ O << " };\n\n";
O << " O << \"\\t\";\n\n";
@@ -461,13 +477,13 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
static void
emitRegisterNameString(raw_ostream &O, StringRef AltName,
- const std::vector<CodeGenRegister*> &Registers) {
- StringToOffsetTable StringTable;
- O << " static const unsigned RegAsmOffset" << AltName << "[] = {\n ";
+ const std::vector<CodeGenRegister*> &Registers) {
+ SequenceToOffsetTable<std::string> StringTable;
+ SmallVector<std::string, 4> AsmNames(Registers.size());
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
const CodeGenRegister &Reg = *Registers[i];
+ std::string &AsmName = AsmNames[i];
- std::string AsmName;
// "NoRegAltName" is special. We don't need to do a lookup for that,
// as it's just a reference to the default register name.
if (AltName == "" || AltName == "NoRegAltName") {
@@ -495,21 +511,22 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName,
AsmName = AltNames[Idx];
}
}
+ StringTable.add(AsmName);
+ }
- O << StringTable.GetOrAddStringOffset(AsmName);
- if (((i + 1) % 14) == 0)
- O << ",\n ";
- else
- O << ", ";
+ StringTable.layout();
+ O << " static const char AsmStrs" << AltName << "[] = {\n";
+ StringTable.emit(O, printChar);
+ O << " };\n\n";
+ O << " static const unsigned RegAsmOffset" << AltName << "[] = {";
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ if ((i % 14) == 0)
+ O << "\n ";
+ O << StringTable.get(AsmNames[i]) << ", ";
}
- O << "0\n"
- << " };\n"
+ O << "\n };\n"
<< "\n";
-
- O << " const char *AsmStrs" << AltName << " =\n";
- StringTable.EmitString(O);
- O << ";\n";
}
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
@@ -544,7 +561,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
O << " const unsigned *RegAsmOffset;\n"
<< " const char *AsmStrs;\n"
<< " switch(AltIdx) {\n"
- << " default: assert(0 && \"Invalid register alt name index!\");\n";
+ << " default: llvm_unreachable(\"Invalid register alt name index!\");\n";
for (unsigned i = 0, e = AltNameIndices.size(); i < e; ++i) {
StringRef Namespace = AltNameIndices[1]->getValueAsString("Namespace");
StringRef AltName(AltNameIndices[i]->getName());
@@ -563,48 +580,6 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
<< "}\n";
}
-void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) {
- CodeGenTarget Target(Records);
- Record *AsmWriter = Target.getAsmWriter();
- std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
-
- const std::vector<const CodeGenInstruction*> &NumberedInstructions =
- Target.getInstructionsByEnumValue();
-
- StringToOffsetTable StringTable;
- O <<
-"\n\n#ifdef GET_INSTRUCTION_NAME\n"
-"#undef GET_INSTRUCTION_NAME\n\n"
-"/// getInstructionName: This method is automatically generated by tblgen\n"
-"/// from the instruction set description. This returns the enum name of the\n"
-"/// specified instruction.\n"
- "const char *" << Target.getName() << ClassName
- << "::getInstructionName(unsigned Opcode) {\n"
- << " assert(Opcode < " << NumberedInstructions.size()
- << " && \"Invalid instruction number!\");\n"
- << "\n"
- << " static const unsigned InstAsmOffset[] = {";
- for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
- const CodeGenInstruction &Inst = *NumberedInstructions[i];
-
- std::string AsmName = Inst.TheDef->getName();
- if ((i % 14) == 0)
- O << "\n ";
-
- O << StringTable.GetOrAddStringOffset(AsmName) << ", ";
- }
- O << "0\n"
- << " };\n"
- << "\n";
-
- O << " const char *Strs =\n";
- StringTable.EmitString(O);
- O << ";\n";
-
- O << " return Strs+InstAsmOffset[Opcode];\n"
- << "}\n\n#endif\n";
-}
-
namespace {
// IAPrinter - Holds information about an InstAlias. Two InstAliases match if
// they both have the same conditionals. In which case, we cannot print out the
@@ -694,70 +669,7 @@ static void EmitGetMapOperandNumber(raw_ostream &O) {
O << " I = OpMap.begin(), E = OpMap.end(); I != E; ++I)\n";
O << " if (I->first == Name)\n";
O << " return I->second;\n";
- O << " assert(false && \"Operand not in map!\");\n";
- O << " return 0;\n";
- O << "}\n\n";
-}
-
-void AsmWriterEmitter::EmitRegIsInRegClass(raw_ostream &O) {
- CodeGenTarget Target(Records);
-
- // Enumerate the register classes.
- ArrayRef<CodeGenRegisterClass*> RegisterClasses =
- Target.getRegBank().getRegClasses();
-
- O << "namespace { // Register classes\n";
- O << " enum RegClass {\n";
-
- // Emit the register enum value for each RegisterClass.
- for (unsigned I = 0, E = RegisterClasses.size(); I != E; ++I) {
- if (I != 0) O << ",\n";
- O << " RC_" << RegisterClasses[I]->getName();
- }
-
- O << "\n };\n";
- O << "} // end anonymous namespace\n\n";
-
- // Emit a function that returns 'true' if a regsiter is part of a particular
- // register class. I.e., RAX is part of GR64 on X86.
- O << "static bool regIsInRegisterClass"
- << "(unsigned RegClass, unsigned Reg) {\n";
-
- // Emit the switch that checks if a register belongs to a particular register
- // class.
- O << " switch (RegClass) {\n";
- O << " default: break;\n";
-
- for (unsigned I = 0, E = RegisterClasses.size(); I != E; ++I) {
- const CodeGenRegisterClass &RC = *RegisterClasses[I];
-
- // Give the register class a legal C name if it's anonymous.
- std::string Name = RC.getName();
- O << " case RC_" << Name << ":\n";
-
- // Emit the register list now.
- unsigned IE = RC.getOrder().size();
- if (IE == 1) {
- O << " if (Reg == " << getQualifiedName(RC.getOrder()[0]) << ")\n";
- O << " return true;\n";
- } else {
- O << " switch (Reg) {\n";
- O << " default: break;\n";
-
- for (unsigned II = 0; II != IE; ++II) {
- Record *Reg = RC.getOrder()[II];
- O << " case " << getQualifiedName(Reg) << ":\n";
- }
-
- O << " return true;\n";
- O << " }\n";
- }
-
- O << " break;\n";
- }
-
- O << " }\n\n";
- O << " return false;\n";
+ O << " llvm_unreachable(\"Operand not in map!\");\n";
O << "}\n\n";
}
@@ -804,8 +716,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
O << "\n#ifdef PRINT_ALIAS_INSTR\n";
O << "#undef PRINT_ALIAS_INSTR\n\n";
- EmitRegIsInRegClass(O);
-
// Emit the method that prints the alias instruction.
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
@@ -858,7 +768,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
const CodeGenInstAlias::ResultOperand &RO = CGA->ResultOperands[i];
switch (RO.Kind) {
- default: assert(0 && "unexpected InstAlias operand kind");
case CodeGenInstAlias::ResultOperand::K_Record: {
const Record *Rec = RO.getRecord();
StringRef ROName = RO.getName();
@@ -872,9 +781,9 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
if (!IAP->isOpMapped(ROName)) {
IAP->addOperand(ROName, i);
- Cond = std::string("regIsInRegisterClass(RC_") +
- CGA->ResultOperands[i].getRecord()->getName() +
- ", MI->getOperand(" + llvm::utostr(i) + ").getReg())";
+ Cond = std::string("MRI.getRegClass(") + Target.getName() + "::" +
+ CGA->ResultOperands[i].getRecord()->getName() + "RegClassID)"
+ ".contains(MI->getOperand(" + llvm::utostr(i) + ").getReg())";
IAP->addCond(Cond);
} else {
Cond = std::string("MI->getOperand(") +
@@ -900,6 +809,13 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
IAP->addCond(Cond);
break;
case CodeGenInstAlias::ResultOperand::K_Reg:
+ // If this is zero_reg, something's playing tricks we're not
+ // equipped to handle.
+ if (!CGA->ResultOperands[i].getRegister()) {
+ CantHandle = true;
+ break;
+ }
+
Cond = std::string("MI->getOperand(") +
llvm::utostr(i) + ").getReg() == " + Target.getName() +
"::" + CGA->ResultOperands[i].getRegister()->getName();
@@ -1015,7 +931,6 @@ void AsmWriterEmitter::run(raw_ostream &O) {
EmitPrintInstruction(O);
EmitGetRegisterName(O);
- EmitGetInstructionName(O);
EmitPrintAliasInstruction(O);
}
diff --git a/utils/TableGen/AsmWriterEmitter.h b/utils/TableGen/AsmWriterEmitter.h
index 731e31cc746e..9719b202faab 100644
--- a/utils/TableGen/AsmWriterEmitter.h
+++ b/utils/TableGen/AsmWriterEmitter.h
@@ -37,8 +37,6 @@ namespace llvm {
private:
void EmitPrintInstruction(raw_ostream &o);
void EmitGetRegisterName(raw_ostream &o);
- void EmitGetInstructionName(raw_ostream &o);
- void EmitRegIsInRegClass(raw_ostream &O);
void EmitPrintAliasInstruction(raw_ostream &O);
AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 02ebd67ba662..2b70f1c52bd0 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,8 +1,8 @@
set(LLVM_REQUIRES_EH 1)
set(LLVM_REQUIRES_RTTI 1)
+set(LLVM_LINK_COMPONENTS Support)
add_tablegen(llvm-tblgen LLVM
- ARMDecoderEmitter.cpp
AsmMatcherEmitter.cpp
AsmWriterEmitter.cpp
AsmWriterInst.cpp
@@ -17,11 +17,11 @@ add_tablegen(llvm-tblgen LLVM
DAGISelMatcherGen.cpp
DAGISelMatcherOpt.cpp
DAGISelMatcher.cpp
+ DFAPacketizerEmitter.cpp
DisassemblerEmitter.cpp
EDEmitter.cpp
FastISelEmitter.cpp
FixedLenDecoderEmitter.cpp
- InstrEnumEmitter.cpp
InstrInfoEmitter.cpp
IntrinsicEmitter.cpp
PseudoLoweringEmitter.cpp
@@ -32,5 +32,6 @@ add_tablegen(llvm-tblgen LLVM
TGValueTypes.cpp
TableGen.cpp
X86DisassemblerTables.cpp
+ X86ModRMFilters.cpp
X86RecognizableInstr.cpp
)
diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp
index fcdaa082fb2a..afbb3a870894 100644
--- a/utils/TableGen/CallingConvEmitter.cpp
+++ b/utils/TableGen/CallingConvEmitter.cpp
@@ -96,7 +96,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
O << IndentStr << "if (unsigned Reg = State.AllocateReg(";
O << getQualifiedName(RegList->getElementAsRecord(0)) << ")) {\n";
} else {
- O << IndentStr << "static const unsigned RegList" << ++Counter
+ O << IndentStr << "static const uint16_t RegList" << ++Counter
<< "[] = {\n";
O << IndentStr << " ";
for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) {
@@ -127,7 +127,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
unsigned RegListNumber = ++Counter;
unsigned ShadowRegListNumber = ++Counter;
- O << IndentStr << "static const unsigned RegList" << RegListNumber
+ O << IndentStr << "static const uint16_t RegList" << RegListNumber
<< "[] = {\n";
O << IndentStr << " ";
for (unsigned i = 0, e = RegList->getSize(); i != e; ++i) {
@@ -136,7 +136,7 @@ void CallingConvEmitter::EmitAction(Record *Action,
}
O << "\n" << IndentStr << "};\n";
- O << IndentStr << "static const unsigned RegList"
+ O << IndentStr << "static const uint16_t RegList"
<< ShadowRegListNumber << "[] = {\n";
O << IndentStr << " ";
for (unsigned i = 0, e = ShadowRegList->getSize(); i != e; ++i) {
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index c5a152665b06..3943e8a40f87 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -163,19 +163,19 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
--bit;
}
- unsigned opMask = ~0U >> (32-N);
+ uint64_t opMask = ~(uint64_t)0 >> (64-N);
int opShift = beginVarBit - N + 1;
opMask <<= opShift;
opShift = beginInstBit - beginVarBit;
if (opShift > 0) {
- Case += " Value |= (op & " + utostr(opMask) + "U) << " +
+ Case += " Value |= (op & UINT64_C(" + utostr(opMask) + ")) << " +
itostr(opShift) + ";\n";
} else if (opShift < 0) {
- Case += " Value |= (op & " + utostr(opMask) + "U) >> " +
+ Case += " Value |= (op & UINT64_C(" + utostr(opMask) + ")) >> " +
itostr(-opShift) + ";\n";
} else {
- Case += " Value |= op & " + utostr(opMask) + "U;\n";
+ Case += " Value |= op & UINT64_C(" + utostr(opMask) + ");\n";
}
}
}
@@ -220,7 +220,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
Target.getInstructionsByEnumValue();
// Emit function declaration
- o << "unsigned " << Target.getName();
+ o << "uint64_t " << Target.getName();
if (MCEmitter)
o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
<< " SmallVectorImpl<MCFixup> &Fixups) const {\n";
@@ -228,7 +228,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
o << "CodeEmitter::getBinaryCodeForInstr(const MachineInstr &MI) const {\n";
// Emit instruction base values
- o << " static const unsigned InstBits[] = {\n";
+ o << " static const uint64_t InstBits[] = {\n";
for (std::vector<const CodeGenInstruction*>::const_iterator
IN = NumberedInstructions.begin(),
EN = NumberedInstructions.end();
@@ -238,21 +238,21 @@ void CodeEmitterGen::run(raw_ostream &o) {
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
R->getValueAsBit("isPseudo")) {
- o << " 0U,\n";
+ o << " UINT64_C(0),\n";
continue;
}
BitsInit *BI = R->getValueAsBitsInit("Inst");
// Start by filling in fixed values.
- unsigned Value = 0;
+ uint64_t Value = 0;
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1)))
- Value |= B->getValue() << (e-i-1);
+ Value |= (uint64_t)B->getValue() << (e-i-1);
}
- o << " " << Value << "U," << '\t' << "// " << R->getName() << "\n";
+ o << " UINT64_C(" << Value << ")," << '\t' << "// " << R->getName() << "\n";
}
- o << " 0U\n };\n";
+ o << " UINT64_C(0)\n };\n";
// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string> > CaseMap;
@@ -273,8 +273,8 @@ void CodeEmitterGen::run(raw_ostream &o) {
// Emit initial function code
o << " const unsigned opcode = MI.getOpcode();\n"
- << " unsigned Value = InstBits[opcode];\n"
- << " unsigned op = 0;\n"
+ << " uint64_t Value = InstBits[opcode];\n"
+ << " uint64_t op = 0;\n"
<< " (void)op; // suppress warning\n"
<< " switch (opcode) {\n";
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index dbf166262bb6..d2ddf232b32a 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -18,8 +18,10 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
-#include <set>
+#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+#include <cstdio>
+#include <set>
using namespace llvm;
//===----------------------------------------------------------------------===//
@@ -629,11 +631,11 @@ TreePredicateFn::TreePredicateFn(TreePattern *N) : PatFragRec(N) {
}
std::string TreePredicateFn::getPredCode() const {
- return PatFragRec->getRecord()->getValueAsCode("PredicateCode");
+ return PatFragRec->getRecord()->getValueAsString("PredicateCode");
}
std::string TreePredicateFn::getImmCode() const {
- return PatFragRec->getRecord()->getValueAsCode("ImmediateCode");
+ return PatFragRec->getRecord()->getValueAsString("ImmediateCode");
}
@@ -748,7 +750,7 @@ std::string PatternToMatch::getPredicateCheck() const {
#ifndef NDEBUG
Def->dump();
#endif
- assert(0 && "Unknown predicate type!");
+ llvm_unreachable("Unknown predicate type!");
}
if (!PredicateCheck.empty())
PredicateCheck += " && ";
@@ -839,7 +841,6 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
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(ResNo, x.SDTCisVT_Info.VT, TP);
@@ -913,7 +914,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
EnforceVectorSubVectorTypeIs(NodeToApply->getExtType(ResNo), TP);
}
}
- return false;
+ llvm_unreachable("Invalid ConstraintType!");
}
//===----------------------------------------------------------------------===//
@@ -1609,10 +1610,9 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
MadeChange |= Child->UpdateNodeType(ChildResNo, MVT::iPTR, TP);
} else if (OperandNode->getName() == "unknown") {
// Nothing to do.
- } else {
- assert(0 && "Unknown operand type!");
- abort();
- }
+ } else
+ llvm_unreachable("Unknown operand type!");
+
MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters);
}
@@ -2071,7 +2071,7 @@ void CodeGenDAGPatterns::ParseNodeTransforms() {
while (!Xforms.empty()) {
Record *XFormNode = Xforms.back();
Record *SDNode = XFormNode->getValueAsDef("Opcode");
- std::string Code = XFormNode->getValueAsCode("XFormFunction");
+ std::string Code = XFormNode->getValueAsString("XFormFunction");
SDNodeXForms.insert(std::make_pair(XFormNode, NodeXForm(SDNode, Code)));
Xforms.pop_back();
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 936fd0146455..5a2d40aa7c86 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -19,6 +19,7 @@
#include "CodeGenIntrinsics.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/ErrorHandling.h"
#include <set>
#include <algorithm>
#include <vector>
@@ -723,8 +724,7 @@ public:
if (Intrinsics[i].TheDef == R) return Intrinsics[i];
for (unsigned i = 0, e = TgtIntrinsics.size(); i != e; ++i)
if (TgtIntrinsics[i].TheDef == R) return TgtIntrinsics[i];
- assert(0 && "Unknown intrinsic!");
- abort();
+ llvm_unreachable("Unknown intrinsic!");
}
const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const {
@@ -732,8 +732,7 @@ public:
return Intrinsics[IID-1];
if (IID-Intrinsics.size()-1 < TgtIntrinsics.size())
return TgtIntrinsics[IID-Intrinsics.size()-1];
- assert(0 && "Bad intrinsic ID!");
- abort();
+ llvm_unreachable("Bad intrinsic ID!");
}
unsigned getIntrinsicID(Record *R) const {
@@ -741,8 +740,7 @@ public:
if (Intrinsics[i].TheDef == R) return i;
for (unsigned i = 0, e = TgtIntrinsics.size(); i != e; ++i)
if (TgtIntrinsics[i].TheDef == R) return i + Intrinsics.size();
- assert(0 && "Unknown intrinsic!");
- abort();
+ llvm_unreachable("Unknown intrinsic!");
}
const DAGDefaultOperand &getDefaultOperand(Record *R) const {
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 53d499f39553..fb9ad9371bea 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -245,7 +245,7 @@ static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) {
if (!Ops[DestOp.first].Constraints[DestOp.second].isNone())
throw "Operand '" + DestOpName + "' cannot have multiple constraints!";
Ops[DestOp.first].Constraints[DestOp.second] =
- CGIOperandList::ConstraintInfo::getTied(FlatOpNo);
+ CGIOperandList::ConstraintInfo::getTied(FlatOpNo);
}
static void ParseConstraints(const std::string &CStr, CGIOperandList &Ops) {
@@ -423,6 +423,18 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
return true;
}
+ // For register operands, the source register class can be a subclass
+ // of the instruction register class, not just an exact match.
+ if (ADI && ADI->getDef()->isSubClassOf("RegisterClass")) {
+ if (!InstOpRec->isSubClassOf("RegisterClass"))
+ return false;
+ if (!T.getRegisterClass(InstOpRec)
+ .hasSubClass(&T.getRegisterClass(ADI->getDef())))
+ return false;
+ ResOp = ResultOperand(Result->getArgName(AliasOpNo), ADI->getDef());
+ return true;
+ }
+
// Handle explicit registers.
if (ADI && ADI->getDef()->isSubClassOf("Register")) {
if (InstOpRec->isSubClassOf("OptionalDefOperand")) {
@@ -456,14 +468,19 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
if (ADI && ADI->getDef()->getName() == "zero_reg") {
// Check if this is an optional def.
- if (!InstOpRec->isSubClassOf("OptionalDefOperand"))
- throw TGError(Loc, "reg0 used for result that is not an "
- "OptionalDefOperand!");
+ // Tied operands where the source is a sub-operand of a complex operand
+ // need to represent both operands in the alias destination instruction.
+ // Allow zero_reg for the tied portion. This can and should go away once
+ // the MC representation of things doesn't use tied operands at all.
+ //if (!InstOpRec->isSubClassOf("OptionalDefOperand"))
+ // throw TGError(Loc, "reg0 used for result that is not an "
+ // "OptionalDefOperand!");
ResOp = ResultOperand(static_cast<Record*>(0));
return true;
}
+ // Literal integers.
if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
return false;
@@ -475,6 +492,19 @@ bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo,
return true;
}
+ // If both are Operands with the same MVT, allow the conversion. It's
+ // up to the user to make sure the values are appropriate, just like
+ // for isel Pat's.
+ if (InstOpRec->isSubClassOf("Operand") &&
+ ADI->getDef()->isSubClassOf("Operand")) {
+ // FIXME: What other attributes should we check here? Identical
+ // MIOperandInfo perhaps?
+ if (InstOpRec->getValueInit("Type") != ADI->getDef()->getValueInit("Type"))
+ return false;
+ ResOp = ResultOperand(Result->getArgName(AliasOpNo), ADI->getDef());
+ return true;
+ }
+
return false;
}
@@ -511,8 +541,11 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
unsigned AliasOpNo = 0;
for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) {
- // Tied registers don't have an entry in the result dag.
- if (ResultInst->Operands[i].getTiedRegister() != -1)
+ // Tied registers don't have an entry in the result dag unless they're part
+ // of a complex operand, in which case we include them anyways, as we
+ // don't have any other way to specify the whole operand.
+ if (ResultInst->Operands[i].MINumOperands == 1 &&
+ ResultInst->Operands[i].getTiedRegister() != -1)
continue;
if (AliasOpNo >= Result->getNumArgs())
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index 8de461527955..7ce4f878a3e7 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -15,6 +15,7 @@
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Error.h"
+#include "llvm/ADT/IntEqClasses.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@@ -22,6 +23,57 @@
using namespace llvm;
//===----------------------------------------------------------------------===//
+// CodeGenSubRegIndex
+//===----------------------------------------------------------------------===//
+
+CodeGenSubRegIndex::CodeGenSubRegIndex(Record *R, unsigned Enum)
+ : TheDef(R),
+ EnumValue(Enum)
+{}
+
+std::string CodeGenSubRegIndex::getNamespace() const {
+ if (TheDef->getValue("Namespace"))
+ return TheDef->getValueAsString("Namespace");
+ else
+ return "";
+}
+
+const std::string &CodeGenSubRegIndex::getName() const {
+ return TheDef->getName();
+}
+
+std::string CodeGenSubRegIndex::getQualifiedName() const {
+ std::string N = getNamespace();
+ if (!N.empty())
+ N += "::";
+ N += getName();
+ return N;
+}
+
+void CodeGenSubRegIndex::updateComponents(CodeGenRegBank &RegBank) {
+ std::vector<Record*> Comps = TheDef->getValueAsListOfDefs("ComposedOf");
+ if (Comps.empty())
+ return;
+ if (Comps.size() != 2)
+ throw TGError(TheDef->getLoc(), "ComposedOf must have exactly two entries");
+ CodeGenSubRegIndex *A = RegBank.getSubRegIdx(Comps[0]);
+ CodeGenSubRegIndex *B = RegBank.getSubRegIdx(Comps[1]);
+ CodeGenSubRegIndex *X = A->addComposite(B, this);
+ if (X)
+ throw TGError(TheDef->getLoc(), "Ambiguous ComposedOf entries");
+}
+
+void CodeGenSubRegIndex::cleanComposites() {
+ // Clean out redundant mappings of the form this+X -> X.
+ for (CompMap::iterator i = Composed.begin(), e = Composed.end(); i != e;) {
+ CompMap::iterator j = i;
+ ++i;
+ if (j->first == j->second)
+ Composed.erase(j);
+ }
+}
+
+//===----------------------------------------------------------------------===//
// CodeGenRegister
//===----------------------------------------------------------------------===//
@@ -29,6 +81,7 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum)
: TheDef(R),
EnumValue(Enum),
CostPerUse(R->getValueAsInt("CostPerUse")),
+ CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")),
SubRegsComplete(false)
{}
@@ -37,12 +90,81 @@ const std::string &CodeGenRegister::getName() const {
}
namespace {
- struct Orphan {
- CodeGenRegister *SubReg;
- Record *First, *Second;
- Orphan(CodeGenRegister *r, Record *a, Record *b)
- : SubReg(r), First(a), Second(b) {}
- };
+// Iterate over all register units in a set of registers.
+class RegUnitIterator {
+ CodeGenRegister::Set::const_iterator RegI, RegE;
+ CodeGenRegister::RegUnitList::const_iterator UnitI, UnitE;
+
+public:
+ RegUnitIterator(const CodeGenRegister::Set &Regs):
+ RegI(Regs.begin()), RegE(Regs.end()), UnitI(), UnitE() {
+
+ if (RegI != RegE) {
+ UnitI = (*RegI)->getRegUnits().begin();
+ UnitE = (*RegI)->getRegUnits().end();
+ advance();
+ }
+ }
+
+ bool isValid() const { return UnitI != UnitE; }
+
+ unsigned operator* () const { assert(isValid()); return *UnitI; };
+
+ const CodeGenRegister *getReg() const { assert(isValid()); return *RegI; }
+
+ /// Preincrement. Move to the next unit.
+ void operator++() {
+ assert(isValid() && "Cannot advance beyond the last operand");
+ ++UnitI;
+ advance();
+ }
+
+protected:
+ void advance() {
+ while (UnitI == UnitE) {
+ if (++RegI == RegE)
+ break;
+ UnitI = (*RegI)->getRegUnits().begin();
+ UnitE = (*RegI)->getRegUnits().end();
+ }
+ }
+};
+} // namespace
+
+// Merge two RegUnitLists maintaining the order and removing duplicates.
+// Overwrites MergedRU in the process.
+static void mergeRegUnits(CodeGenRegister::RegUnitList &MergedRU,
+ const CodeGenRegister::RegUnitList &RRU) {
+ CodeGenRegister::RegUnitList LRU = MergedRU;
+ MergedRU.clear();
+ std::set_union(LRU.begin(), LRU.end(), RRU.begin(), RRU.end(),
+ std::back_inserter(MergedRU));
+}
+
+// Return true of this unit appears in RegUnits.
+static bool hasRegUnit(CodeGenRegister::RegUnitList &RegUnits, unsigned Unit) {
+ return std::count(RegUnits.begin(), RegUnits.end(), Unit);
+}
+
+// Inherit register units from subregisters.
+// Return true if the RegUnits changed.
+bool CodeGenRegister::inheritRegUnits(CodeGenRegBank &RegBank) {
+ unsigned OldNumUnits = RegUnits.size();
+ for (SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end();
+ I != E; ++I) {
+ // Strangely a register may have itself as a subreg (self-cycle) e.g. XMM.
+ // Only create a unit if no other subregs have units.
+ CodeGenRegister *SR = I->second;
+ if (SR == this) {
+ // RegUnits are only empty during getSubRegs, prior to computing weight.
+ if (RegUnits.empty())
+ RegUnits.push_back(RegBank.newRegUnit(0));
+ continue;
+ }
+ // Merge the subregister's units into this register's RegUnits.
+ mergeRegUnits(RegUnits, SR->RegUnits);
+ }
+ return OldNumUnits != RegUnits.size();
}
const CodeGenRegister::SubRegMap &
@@ -53,23 +175,26 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
SubRegsComplete = true;
std::vector<Record*> SubList = TheDef->getValueAsListOfDefs("SubRegs");
- std::vector<Record*> Indices = TheDef->getValueAsListOfDefs("SubRegIndices");
- if (SubList.size() != Indices.size())
+ std::vector<Record*> IdxList = TheDef->getValueAsListOfDefs("SubRegIndices");
+ if (SubList.size() != IdxList.size())
throw TGError(TheDef->getLoc(), "Register " + getName() +
" SubRegIndices doesn't match SubRegs");
// First insert the direct subregs and make sure they are fully indexed.
+ SmallVector<CodeGenSubRegIndex*, 8> Indices;
for (unsigned i = 0, e = SubList.size(); i != e; ++i) {
CodeGenRegister *SR = RegBank.getReg(SubList[i]);
- if (!SubRegs.insert(std::make_pair(Indices[i], SR)).second)
- throw TGError(TheDef->getLoc(), "SubRegIndex " + Indices[i]->getName() +
+ CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(IdxList[i]);
+ Indices.push_back(Idx);
+ if (!SubRegs.insert(std::make_pair(Idx, SR)).second)
+ throw TGError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() +
" appears twice in Register " + getName());
}
// Keep track of inherited subregs and how they can be reached.
- SmallVector<Orphan, 8> Orphans;
+ SmallPtrSet<CodeGenRegister*, 8> Orphans;
- // Clone inherited subregs and place duplicate entries on Orphans.
+ // Clone inherited subregs and place duplicate entries in Orphans.
// Here the order is important - earlier subregs take precedence.
for (unsigned i = 0, e = SubList.size(); i != e; ++i) {
CodeGenRegister *SR = RegBank.getReg(SubList[i]);
@@ -83,7 +208,7 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
for (SubRegMap::const_iterator SI = Map.begin(), SE = Map.end(); SI != SE;
++SI) {
if (!SubRegs.insert(*SI).second)
- Orphans.push_back(Orphan(SI->second, Indices[i], SI->first));
+ Orphans.insert(SI->second);
// Noop sub-register indexes are possible, so avoid duplicates.
if (SI->second != SR)
@@ -91,6 +216,33 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
}
}
+ // Expand any composed subreg indices.
+ // If dsub_2 has ComposedOf = [qsub_1, dsub_0], and this register has a
+ // qsub_1 subreg, add a dsub_2 subreg. Keep growing Indices and process
+ // expanded subreg indices recursively.
+ for (unsigned i = 0; i != Indices.size(); ++i) {
+ CodeGenSubRegIndex *Idx = Indices[i];
+ const CodeGenSubRegIndex::CompMap &Comps = Idx->getComposites();
+ CodeGenRegister *SR = SubRegs[Idx];
+ const SubRegMap &Map = SR->getSubRegs(RegBank);
+
+ // Look at the possible compositions of Idx.
+ // They may not all be supported by SR.
+ for (CodeGenSubRegIndex::CompMap::const_iterator I = Comps.begin(),
+ E = Comps.end(); I != E; ++I) {
+ SubRegMap::const_iterator SRI = Map.find(I->first);
+ if (SRI == Map.end())
+ continue; // Idx + I->first doesn't exist in SR.
+ // Add I->second as a name for the subreg SRI->second, assuming it is
+ // orphaned, and the name isn't already used for something else.
+ if (SubRegs.count(I->second) || !Orphans.erase(SRI->second))
+ continue;
+ // We found a new name for the orphaned sub-register.
+ SubRegs.insert(std::make_pair(I->second, SRI->second));
+ Indices.push_back(I->second);
+ }
+ }
+
// Process the composites.
ListInit *Comps = TheDef->getValueAsListInit("CompositeIndices");
for (unsigned i = 0, e = Comps->size(); i != e; ++i) {
@@ -103,6 +255,7 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
if (!BaseIdxInit || !BaseIdxInit->getDef()->isSubClassOf("SubRegIndex"))
throw TGError(TheDef->getLoc(), "Invalid SubClassIndex in " +
Pat->getAsString());
+ CodeGenSubRegIndex *BaseIdx = RegBank.getSubRegIdx(BaseIdxInit->getDef());
// Resolve list of subreg indices into R2.
CodeGenRegister *R2 = this;
@@ -112,8 +265,9 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
if (!IdxInit || !IdxInit->getDef()->isSubClassOf("SubRegIndex"))
throw TGError(TheDef->getLoc(), "Invalid SubClassIndex in " +
Pat->getAsString());
+ CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(IdxInit->getDef());
const SubRegMap &R2Subs = R2->getSubRegs(RegBank);
- SubRegMap::const_iterator ni = R2Subs.find(IdxInit->getDef());
+ SubRegMap::const_iterator ni = R2Subs.find(Idx);
if (ni == R2Subs.end())
throw TGError(TheDef->getLoc(), "Composite " + Pat->getAsString() +
" refers to bad index in " + R2->getName());
@@ -121,35 +275,76 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
}
// Insert composite index. Allow overriding inherited indices etc.
- SubRegs[BaseIdxInit->getDef()] = R2;
+ SubRegs[BaseIdx] = R2;
// R2 is no longer an orphan.
- for (unsigned j = 0, je = Orphans.size(); j != je; ++j)
- if (Orphans[j].SubReg == R2)
- Orphans[j].SubReg = 0;
+ Orphans.erase(R2);
}
// Now Orphans contains the inherited subregisters without a direct index.
// Create inferred indexes for all missing entries.
- for (unsigned i = 0, e = Orphans.size(); i != e; ++i) {
- Orphan &O = Orphans[i];
- if (!O.SubReg)
- continue;
- SubRegs[RegBank.getCompositeSubRegIndex(O.First, O.Second, true)] =
- O.SubReg;
+ // Work backwards in the Indices vector in order to compose subregs bottom-up.
+ // Consider this subreg sequence:
+ //
+ // qsub_1 -> dsub_0 -> ssub_0
+ //
+ // The qsub_1 -> dsub_0 composition becomes dsub_2, so the ssub_0 register
+ // can be reached in two different ways:
+ //
+ // qsub_1 -> ssub_0
+ // dsub_2 -> ssub_0
+ //
+ // We pick the latter composition because another register may have [dsub_0,
+ // dsub_1, dsub_2] subregs without neccessarily having a qsub_1 subreg. The
+ // dsub_2 -> ssub_0 composition can be shared.
+ while (!Indices.empty() && !Orphans.empty()) {
+ CodeGenSubRegIndex *Idx = Indices.pop_back_val();
+ CodeGenRegister *SR = SubRegs[Idx];
+ const SubRegMap &Map = SR->getSubRegs(RegBank);
+ for (SubRegMap::const_iterator SI = Map.begin(), SE = Map.end(); SI != SE;
+ ++SI)
+ if (Orphans.erase(SI->second))
+ SubRegs[RegBank.getCompositeSubRegIndex(Idx, SI->first)] = SI->second;
}
+
+ // Initialize RegUnitList. A register with no subregisters creates its own
+ // unit. Otherwise, it inherits all its subregister's units. Because
+ // getSubRegs is called recursively, this processes the register hierarchy in
+ // postorder.
+ //
+ // TODO: We currently assume all register units correspond to a named "leaf"
+ // register. We should also unify register units for ad-hoc register
+ // aliases. This can be done by iteratively merging units for aliasing
+ // registers using a worklist.
+ assert(RegUnits.empty() && "Should only initialize RegUnits once");
+ if (SubRegs.empty())
+ RegUnits.push_back(RegBank.newRegUnit(0));
+ else
+ inheritRegUnits(RegBank);
return SubRegs;
}
void
-CodeGenRegister::addSubRegsPreOrder(SetVector<CodeGenRegister*> &OSet) const {
+CodeGenRegister::addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet,
+ CodeGenRegBank &RegBank) const {
assert(SubRegsComplete && "Must precompute sub-registers");
std::vector<Record*> Indices = TheDef->getValueAsListOfDefs("SubRegIndices");
for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
- CodeGenRegister *SR = SubRegs.find(Indices[i])->second;
+ CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(Indices[i]);
+ CodeGenRegister *SR = SubRegs.find(Idx)->second;
if (OSet.insert(SR))
- SR->addSubRegsPreOrder(OSet);
+ SR->addSubRegsPreOrder(OSet, RegBank);
+ }
+}
+
+// Get the sum of this register's unit weights.
+unsigned CodeGenRegister::getWeight(const CodeGenRegBank &RegBank) const {
+ unsigned Weight = 0;
+ for (RegUnitList::const_iterator I = RegUnits.begin(), E = RegUnits.end();
+ I != E; ++I) {
+ Weight += RegBank.getRegUnitWeight(*I);
}
+ return Weight;
}
//===----------------------------------------------------------------------===//
@@ -215,30 +410,40 @@ struct TupleExpander : SetTheory::Expander {
for (unsigned i = 0, e = Proto->getValues().size(); i != e; ++i) {
RecordVal RV = Proto->getValues()[i];
+ // Skip existing fields, like NAME.
+ if (NewReg->getValue(RV.getNameInit()))
+ continue;
+
+ StringRef Field = RV.getName();
+
// Replace the sub-register list with Tuple.
- if (RV.getName() == "SubRegs")
+ if (Field == "SubRegs")
RV.setValue(ListInit::get(Tuple, RegisterRecTy));
// Provide a blank AsmName. MC hacks are required anyway.
- if (RV.getName() == "AsmName")
+ if (Field == "AsmName")
RV.setValue(BlankName);
// CostPerUse is aggregated from all Tuple members.
- if (RV.getName() == "CostPerUse")
+ if (Field == "CostPerUse")
RV.setValue(IntInit::get(CostPerUse));
+ // Composite registers are always covered by sub-registers.
+ if (Field == "CoveredBySubRegs")
+ RV.setValue(BitInit::get(true));
+
// Copy fields from the RegisterTuples def.
- if (RV.getName() == "SubRegIndices" ||
- RV.getName() == "CompositeIndices") {
- NewReg->addValue(*Def->getValue(RV.getName()));
+ if (Field == "SubRegIndices" ||
+ Field == "CompositeIndices") {
+ NewReg->addValue(*Def->getValue(Field));
continue;
}
// Some fields get their default uninitialized value.
- if (RV.getName() == "DwarfNumbers" ||
- RV.getName() == "DwarfAlias" ||
- RV.getName() == "Aliases") {
- if (const RecordVal *DefRV = RegisterCl->getValue(RV.getName()))
+ if (Field == "DwarfNumbers" ||
+ Field == "DwarfAlias" ||
+ Field == "Aliases") {
+ if (const RecordVal *DefRV = RegisterCl->getValue(Field))
NewReg->addValue(*DefRV);
continue;
}
@@ -330,7 +535,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
SpillAlignment = R->getValueAsInt("Alignment");
CopyCost = R->getValueAsInt("CopyCost");
Allocatable = R->getValueAsBit("isAllocatable");
- AltOrderSelect = R->getValueAsCode("AltOrderSelect");
+ AltOrderSelect = R->getValueAsString("AltOrderSelect");
}
// Create an inferred register class that was missing from the .td files.
@@ -448,7 +653,7 @@ static int TopoOrderRC(const void *PA, const void *PB) {
return 1;
// Finally order by name as a tie breaker.
- return A->getName() < B->getName();
+ return StringRef(A->getName()).compare(B->getName());
}
std::string CodeGenRegisterClass::getQualifiedName() const {
@@ -504,6 +709,30 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) {
RegClasses[rci]->inheritProperties(RegBank);
}
+void
+CodeGenRegisterClass::getSuperRegClasses(CodeGenSubRegIndex *SubIdx,
+ BitVector &Out) const {
+ DenseMap<CodeGenSubRegIndex*,
+ SmallPtrSet<CodeGenRegisterClass*, 8> >::const_iterator
+ FindI = SuperRegClasses.find(SubIdx);
+ if (FindI == SuperRegClasses.end())
+ return;
+ for (SmallPtrSet<CodeGenRegisterClass*, 8>::const_iterator I =
+ FindI->second.begin(), E = FindI->second.end(); I != E; ++I)
+ Out.set((*I)->EnumValue);
+}
+
+// Populate a unique sorted list of units from a register set.
+void CodeGenRegisterClass::buildRegUnitSet(
+ std::vector<unsigned> &RegUnits) const {
+ std::vector<unsigned> TmpUnits;
+ for (RegUnitIterator UnitI(Members); UnitI.isValid(); ++UnitI)
+ TmpUnits.push_back(*UnitI);
+ std::sort(TmpUnits.begin(), TmpUnits.end());
+ std::unique_copy(TmpUnits.begin(), TmpUnits.end(),
+ std::back_inserter(RegUnits));
+}
+
//===----------------------------------------------------------------------===//
// CodeGenRegBank
//===----------------------------------------------------------------------===//
@@ -511,13 +740,19 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) {
CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) : Records(Records) {
// Configure register Sets to understand register classes and tuples.
Sets.addFieldExpander("RegisterClass", "MemberList");
+ Sets.addFieldExpander("CalleeSavedRegs", "SaveList");
Sets.addExpander("RegisterTuples", new TupleExpander());
// Read in the user-defined (named) sub-register indices.
// More indices will be synthesized later.
- SubRegIndices = Records.getAllDerivedDefinitions("SubRegIndex");
- std::sort(SubRegIndices.begin(), SubRegIndices.end(), LessRecord());
- NumNamedIndices = SubRegIndices.size();
+ std::vector<Record*> SRIs = Records.getAllDerivedDefinitions("SubRegIndex");
+ std::sort(SRIs.begin(), SRIs.end(), LessRecord());
+ NumNamedIndices = SRIs.size();
+ for (unsigned i = 0, e = SRIs.size(); i != e; ++i)
+ getSubRegIdx(SRIs[i]);
+ // Build composite maps from ComposedOf fields.
+ for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i)
+ SubRegIndices[i]->updateComponents(*this);
// Read in the register definitions.
std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register");
@@ -538,9 +773,14 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) : Records(Records) {
// Precompute all sub-register maps now all the registers are known.
// This will create Composite entries for all inferred sub-register indices.
+ NumRegUnits = 0;
for (unsigned i = 0, e = Registers.size(); i != e; ++i)
Registers[i]->getSubRegs(*this);
+ // Native register units are associated with a leaf register. They've all been
+ // discovered now.
+ NumNativeRegUnits = NumRegUnits;
+
// Read in register class definitions.
std::vector<Record*> RCs = Records.getAllDerivedDefinitions("RegisterClass");
if (RCs.empty())
@@ -561,6 +801,15 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) : Records(Records) {
CodeGenRegisterClass::computeSubClasses(*this);
}
+CodeGenSubRegIndex *CodeGenRegBank::getSubRegIdx(Record *Def) {
+ CodeGenSubRegIndex *&Idx = Def2SubRegIdx[Def];
+ if (Idx)
+ return Idx;
+ Idx = new CodeGenSubRegIndex(Def, SubRegIndices.size() + 1);
+ SubRegIndices.push_back(Idx);
+ return Idx;
+}
+
CodeGenRegister *CodeGenRegBank::getReg(Record *Def) {
CodeGenRegister *&Reg = Def2Reg[Def];
if (Reg)
@@ -582,6 +831,23 @@ void CodeGenRegBank::addToMaps(CodeGenRegisterClass *RC) {
Key2RC.insert(std::make_pair(K, RC));
}
+// Create a synthetic sub-class if it is missing.
+CodeGenRegisterClass*
+CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
+ const CodeGenRegister::Set *Members,
+ StringRef Name) {
+ // Synthetic sub-class has the same size and alignment as RC.
+ CodeGenRegisterClass::Key K(Members, RC->SpillSize, RC->SpillAlignment);
+ RCKeyMap::const_iterator FoundI = Key2RC.find(K);
+ if (FoundI != Key2RC.end())
+ return FoundI->second;
+
+ // Sub-class doesn't exist, create a new one.
+ CodeGenRegisterClass *NewRC = new CodeGenRegisterClass(Name, K);
+ addToMaps(NewRC);
+ return NewRC;
+}
+
CodeGenRegisterClass *CodeGenRegBank::getRegClass(Record *Def) {
if (CodeGenRegisterClass *RC = Def2RC[Def])
return RC;
@@ -589,34 +855,28 @@ CodeGenRegisterClass *CodeGenRegBank::getRegClass(Record *Def) {
throw TGError(Def->getLoc(), "Not a known RegisterClass!");
}
-Record *CodeGenRegBank::getCompositeSubRegIndex(Record *A, Record *B,
- bool create) {
+CodeGenSubRegIndex*
+CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
+ CodeGenSubRegIndex *B) {
// Look for an existing entry.
- Record *&Comp = Composite[std::make_pair(A, B)];
- if (Comp || !create)
+ CodeGenSubRegIndex *Comp = A->compose(B);
+ if (Comp)
return Comp;
// None exists, synthesize one.
std::string Name = A->getName() + "_then_" + B->getName();
- Comp = new Record(Name, SMLoc(), Records);
- SubRegIndices.push_back(Comp);
+ Comp = getSubRegIdx(new Record(Name, SMLoc(), Records));
+ A->addComposite(B, Comp);
return Comp;
}
-unsigned CodeGenRegBank::getSubRegIndexNo(Record *idx) {
- std::vector<Record*>::const_iterator i =
- std::find(SubRegIndices.begin(), SubRegIndices.end(), idx);
- assert(i != SubRegIndices.end() && "Not a SubRegIndex");
- return (i - SubRegIndices.begin()) + 1;
-}
-
void CodeGenRegBank::computeComposites() {
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
CodeGenRegister *Reg1 = Registers[i];
const CodeGenRegister::SubRegMap &SRM1 = Reg1->getSubRegs();
for (CodeGenRegister::SubRegMap::const_iterator i1 = SRM1.begin(),
e1 = SRM1.end(); i1 != e1; ++i1) {
- Record *Idx1 = i1->first;
+ CodeGenSubRegIndex *Idx1 = i1->first;
CodeGenRegister *Reg2 = i1->second;
// Ignore identity compositions.
if (Reg1 == Reg2)
@@ -625,7 +885,7 @@ void CodeGenRegBank::computeComposites() {
// Try composing Idx1 with another SubRegIndex.
for (CodeGenRegister::SubRegMap::const_iterator i2 = SRM2.begin(),
e2 = SRM2.end(); i2 != e2; ++i2) {
- std::pair<Record*, Record*> IdxPair(Idx1, i2->first);
+ CodeGenSubRegIndex *Idx2 = i2->first;
CodeGenRegister *Reg3 = i2->second;
// Ignore identity compositions.
if (Reg2 == Reg3)
@@ -634,16 +894,13 @@ void CodeGenRegBank::computeComposites() {
for (CodeGenRegister::SubRegMap::const_iterator i1d = SRM1.begin(),
e1d = SRM1.end(); i1d != e1d; ++i1d) {
if (i1d->second == Reg3) {
- std::pair<CompositeMap::iterator, bool> Ins =
- Composite.insert(std::make_pair(IdxPair, i1d->first));
// Conflicting composition? Emit a warning but allow it.
- if (!Ins.second && Ins.first->second != i1d->first) {
- errs() << "Warning: SubRegIndex " << getQualifiedName(Idx1)
- << " and " << getQualifiedName(IdxPair.second)
+ if (CodeGenSubRegIndex *Prev = Idx1->addComposite(Idx2, i1d->first))
+ errs() << "Warning: SubRegIndex " << Idx1->getQualifiedName()
+ << " and " << Idx2->getQualifiedName()
<< " compose ambiguously as "
- << getQualifiedName(Ins.first->second) << " or "
- << getQualifiedName(i1d->first) << "\n";
- }
+ << Prev->getQualifiedName() << " or "
+ << i1d->first->getQualifiedName() << "\n";
}
}
}
@@ -652,12 +909,388 @@ void CodeGenRegBank::computeComposites() {
// We don't care about the difference between (Idx1, Idx2) -> Idx2 and invalid
// compositions, so remove any mappings of that form.
- for (CompositeMap::iterator i = Composite.begin(), e = Composite.end();
- i != e;) {
- CompositeMap::iterator j = i;
- ++i;
- if (j->first.second == j->second)
- Composite.erase(j);
+ for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i)
+ SubRegIndices[i]->cleanComposites();
+}
+
+namespace {
+// UberRegSet is a helper class for computeRegUnitWeights. Each UberRegSet is
+// the transitive closure of the union of overlapping register
+// classes. Together, the UberRegSets form a partition of the registers. If we
+// consider overlapping register classes to be connected, then each UberRegSet
+// is a set of connected components.
+//
+// An UberRegSet will likely be a horizontal slice of register names of
+// the same width. Nontrivial subregisters should then be in a separate
+// UberRegSet. But this property isn't required for valid computation of
+// register unit weights.
+//
+// A Weight field caches the max per-register unit weight in each UberRegSet.
+//
+// A set of SingularDeterminants flags single units of some register in this set
+// for which the unit weight equals the set weight. These units should not have
+// their weight increased.
+struct UberRegSet {
+ CodeGenRegister::Set Regs;
+ unsigned Weight;
+ CodeGenRegister::RegUnitList SingularDeterminants;
+
+ UberRegSet(): Weight(0) {}
+};
+} // namespace
+
+// Partition registers into UberRegSets, where each set is the transitive
+// closure of the union of overlapping register classes.
+//
+// UberRegSets[0] is a special non-allocatable set.
+static void computeUberSets(std::vector<UberRegSet> &UberSets,
+ std::vector<UberRegSet*> &RegSets,
+ CodeGenRegBank &RegBank) {
+
+ const std::vector<CodeGenRegister*> &Registers = RegBank.getRegisters();
+
+ // The Register EnumValue is one greater than its index into Registers.
+ assert(Registers.size() == Registers[Registers.size()-1]->EnumValue &&
+ "register enum value mismatch");
+
+ // For simplicitly make the SetID the same as EnumValue.
+ IntEqClasses UberSetIDs(Registers.size()+1);
+ std::set<unsigned> AllocatableRegs;
+ for (unsigned i = 0, e = RegBank.getRegClasses().size(); i != e; ++i) {
+
+ CodeGenRegisterClass *RegClass = RegBank.getRegClasses()[i];
+ if (!RegClass->Allocatable)
+ continue;
+
+ const CodeGenRegister::Set &Regs = RegClass->getMembers();
+ if (Regs.empty())
+ continue;
+
+ unsigned USetID = UberSetIDs.findLeader((*Regs.begin())->EnumValue);
+ assert(USetID && "register number 0 is invalid");
+
+ AllocatableRegs.insert((*Regs.begin())->EnumValue);
+ for (CodeGenRegister::Set::const_iterator I = llvm::next(Regs.begin()),
+ E = Regs.end(); I != E; ++I) {
+ AllocatableRegs.insert((*I)->EnumValue);
+ UberSetIDs.join(USetID, (*I)->EnumValue);
+ }
+ }
+ // Combine non-allocatable regs.
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ unsigned RegNum = Registers[i]->EnumValue;
+ if (AllocatableRegs.count(RegNum))
+ continue;
+
+ UberSetIDs.join(0, RegNum);
+ }
+ UberSetIDs.compress();
+
+ // Make the first UberSet a special unallocatable set.
+ unsigned ZeroID = UberSetIDs[0];
+
+ // Insert Registers into the UberSets formed by union-find.
+ // Do not resize after this.
+ UberSets.resize(UberSetIDs.getNumClasses());
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ const CodeGenRegister *Reg = Registers[i];
+ unsigned USetID = UberSetIDs[Reg->EnumValue];
+ if (!USetID)
+ USetID = ZeroID;
+ else if (USetID == ZeroID)
+ USetID = 0;
+
+ UberRegSet *USet = &UberSets[USetID];
+ USet->Regs.insert(Reg);
+ RegSets[i] = USet;
+ }
+}
+
+// Recompute each UberSet weight after changing unit weights.
+static void computeUberWeights(std::vector<UberRegSet> &UberSets,
+ CodeGenRegBank &RegBank) {
+ // Skip the first unallocatable set.
+ for (std::vector<UberRegSet>::iterator I = llvm::next(UberSets.begin()),
+ E = UberSets.end(); I != E; ++I) {
+
+ // Initialize all unit weights in this set, and remember the max units/reg.
+ const CodeGenRegister *Reg = 0;
+ unsigned MaxWeight = 0, Weight = 0;
+ for (RegUnitIterator UnitI(I->Regs); UnitI.isValid(); ++UnitI) {
+ if (Reg != UnitI.getReg()) {
+ if (Weight > MaxWeight)
+ MaxWeight = Weight;
+ Reg = UnitI.getReg();
+ Weight = 0;
+ }
+ unsigned UWeight = RegBank.getRegUnitWeight(*UnitI);
+ if (!UWeight) {
+ UWeight = 1;
+ RegBank.increaseRegUnitWeight(*UnitI, UWeight);
+ }
+ Weight += UWeight;
+ }
+ if (Weight > MaxWeight)
+ MaxWeight = Weight;
+
+ // Update the set weight.
+ I->Weight = MaxWeight;
+
+ // Find singular determinants.
+ for (CodeGenRegister::Set::iterator RegI = I->Regs.begin(),
+ RegE = I->Regs.end(); RegI != RegE; ++RegI) {
+ if ((*RegI)->getRegUnits().size() == 1
+ && (*RegI)->getWeight(RegBank) == I->Weight)
+ mergeRegUnits(I->SingularDeterminants, (*RegI)->getRegUnits());
+ }
+ }
+}
+
+// normalizeWeight is a computeRegUnitWeights helper that adjusts the weight of
+// a register and its subregisters so that they have the same weight as their
+// UberSet. Self-recursion processes the subregister tree in postorder so
+// subregisters are normalized first.
+//
+// Side effects:
+// - creates new adopted register units
+// - causes superregisters to inherit adopted units
+// - increases the weight of "singular" units
+// - induces recomputation of UberWeights.
+static bool normalizeWeight(CodeGenRegister *Reg,
+ std::vector<UberRegSet> &UberSets,
+ std::vector<UberRegSet*> &RegSets,
+ CodeGenRegister::RegUnitList &NormalUnits,
+ CodeGenRegBank &RegBank) {
+ bool Changed = false;
+ const CodeGenRegister::SubRegMap &SRM = Reg->getSubRegs();
+ for (CodeGenRegister::SubRegMap::const_iterator SRI = SRM.begin(),
+ SRE = SRM.end(); SRI != SRE; ++SRI) {
+ if (SRI->second == Reg)
+ continue; // self-cycles happen
+
+ Changed |=
+ normalizeWeight(SRI->second, UberSets, RegSets, NormalUnits, RegBank);
+ }
+ // Postorder register normalization.
+
+ // Inherit register units newly adopted by subregisters.
+ if (Reg->inheritRegUnits(RegBank))
+ computeUberWeights(UberSets, RegBank);
+
+ // Check if this register is too skinny for its UberRegSet.
+ UberRegSet *UberSet = RegSets[RegBank.getRegIndex(Reg)];
+
+ unsigned RegWeight = Reg->getWeight(RegBank);
+ if (UberSet->Weight > RegWeight) {
+ // A register unit's weight can be adjusted only if it is the singular unit
+ // for this register, has not been used to normalize a subregister's set,
+ // and has not already been used to singularly determine this UberRegSet.
+ unsigned AdjustUnit = Reg->getRegUnits().front();
+ if (Reg->getRegUnits().size() != 1
+ || hasRegUnit(NormalUnits, AdjustUnit)
+ || hasRegUnit(UberSet->SingularDeterminants, AdjustUnit)) {
+ // We don't have an adjustable unit, so adopt a new one.
+ AdjustUnit = RegBank.newRegUnit(UberSet->Weight - RegWeight);
+ Reg->adoptRegUnit(AdjustUnit);
+ // Adopting a unit does not immediately require recomputing set weights.
+ }
+ else {
+ // Adjust the existing single unit.
+ RegBank.increaseRegUnitWeight(AdjustUnit, UberSet->Weight - RegWeight);
+ // The unit may be shared among sets and registers within this set.
+ computeUberWeights(UberSets, RegBank);
+ }
+ Changed = true;
+ }
+
+ // Mark these units normalized so superregisters can't change their weights.
+ mergeRegUnits(NormalUnits, Reg->getRegUnits());
+
+ return Changed;
+}
+
+// Compute a weight for each register unit created during getSubRegs.
+//
+// The goal is that two registers in the same class will have the same weight,
+// where each register's weight is defined as sum of its units' weights.
+void CodeGenRegBank::computeRegUnitWeights() {
+ assert(RegUnitWeights.empty() && "Only initialize RegUnitWeights once");
+
+ // Only allocatable units will be initialized to nonzero weight.
+ RegUnitWeights.resize(NumRegUnits);
+
+ std::vector<UberRegSet> UberSets;
+ std::vector<UberRegSet*> RegSets(Registers.size());
+ computeUberSets(UberSets, RegSets, *this);
+ // UberSets and RegSets are now immutable.
+
+ computeUberWeights(UberSets, *this);
+
+ // Iterate over each Register, normalizing the unit weights until reaching
+ // a fix point.
+ unsigned NumIters = 0;
+ for (bool Changed = true; Changed; ++NumIters) {
+ assert(NumIters <= NumNativeRegUnits && "Runaway register unit weights");
+ Changed = false;
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
+ CodeGenRegister::RegUnitList NormalUnits;
+ Changed |=
+ normalizeWeight(Registers[i], UberSets, RegSets, NormalUnits, *this);
+ }
+ }
+}
+
+// Find a set in UniqueSets with the same elements as Set.
+// Return an iterator into UniqueSets.
+static std::vector<RegUnitSet>::const_iterator
+findRegUnitSet(const std::vector<RegUnitSet> &UniqueSets,
+ const RegUnitSet &Set) {
+ std::vector<RegUnitSet>::const_iterator
+ I = UniqueSets.begin(), E = UniqueSets.end();
+ for(;I != E; ++I) {
+ if (I->Units == Set.Units)
+ break;
+ }
+ return I;
+}
+
+// Return true if the RUSubSet is a subset of RUSuperSet.
+static bool isRegUnitSubSet(const std::vector<unsigned> &RUSubSet,
+ const std::vector<unsigned> &RUSuperSet) {
+ return std::includes(RUSuperSet.begin(), RUSuperSet.end(),
+ RUSubSet.begin(), RUSubSet.end());
+}
+
+// Iteratively prune unit sets.
+void CodeGenRegBank::pruneUnitSets() {
+ assert(RegClassUnitSets.empty() && "this invalidates RegClassUnitSets");
+
+ // Form an equivalence class of UnitSets with no significant difference.
+ std::vector<unsigned> SuperSetIDs;
+ for (unsigned SubIdx = 0, EndIdx = RegUnitSets.size();
+ SubIdx != EndIdx; ++SubIdx) {
+ const RegUnitSet &SubSet = RegUnitSets[SubIdx];
+ unsigned SuperIdx = 0;
+ for (; SuperIdx != EndIdx; ++SuperIdx) {
+ if (SuperIdx == SubIdx)
+ continue;
+
+ const RegUnitSet &SuperSet = RegUnitSets[SuperIdx];
+ if (isRegUnitSubSet(SubSet.Units, SuperSet.Units)
+ && (SubSet.Units.size() + 3 > SuperSet.Units.size())) {
+ break;
+ }
+ }
+ if (SuperIdx == EndIdx)
+ SuperSetIDs.push_back(SubIdx);
+ }
+ // Populate PrunedUnitSets with each equivalence class's superset.
+ std::vector<RegUnitSet> PrunedUnitSets(SuperSetIDs.size());
+ for (unsigned i = 0, e = SuperSetIDs.size(); i != e; ++i) {
+ unsigned SuperIdx = SuperSetIDs[i];
+ PrunedUnitSets[i].Name = RegUnitSets[SuperIdx].Name;
+ PrunedUnitSets[i].Units.swap(RegUnitSets[SuperIdx].Units);
+ }
+ RegUnitSets.swap(PrunedUnitSets);
+}
+
+// Create a RegUnitSet for each RegClass that contains all units in the class
+// including adopted units that are necessary to model register pressure. Then
+// iteratively compute RegUnitSets such that the union of any two overlapping
+// RegUnitSets is repreresented.
+//
+// RegisterInfoEmitter will map each RegClass to its RegUnitClass and any
+// RegUnitSet that is a superset of that RegUnitClass.
+void CodeGenRegBank::computeRegUnitSets() {
+
+ // Compute a unique RegUnitSet for each RegClass.
+ const ArrayRef<CodeGenRegisterClass*> &RegClasses = getRegClasses();
+ unsigned NumRegClasses = RegClasses.size();
+ for (unsigned RCIdx = 0, RCEnd = NumRegClasses; RCIdx != RCEnd; ++RCIdx) {
+ if (!RegClasses[RCIdx]->Allocatable)
+ continue;
+
+ // Speculatively grow the RegUnitSets to hold the new set.
+ RegUnitSets.resize(RegUnitSets.size() + 1);
+ RegUnitSets.back().Name = RegClasses[RCIdx]->getName();
+
+ // Compute a sorted list of units in this class.
+ RegClasses[RCIdx]->buildRegUnitSet(RegUnitSets.back().Units);
+
+ // Find an existing RegUnitSet.
+ std::vector<RegUnitSet>::const_iterator SetI =
+ findRegUnitSet(RegUnitSets, RegUnitSets.back());
+ if (SetI != llvm::prior(RegUnitSets.end()))
+ RegUnitSets.pop_back();
+ }
+
+ // Iteratively prune unit sets.
+ pruneUnitSets();
+
+ // Iterate over all unit sets, including new ones added by this loop.
+ unsigned NumRegUnitSubSets = RegUnitSets.size();
+ for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx) {
+ // In theory, this is combinatorial. In practice, it needs to be bounded
+ // by a small number of sets for regpressure to be efficient.
+ // If the assert is hit, we need to implement pruning.
+ assert(Idx < (2*NumRegUnitSubSets) && "runaway unit set inference");
+
+ // Compare new sets with all original classes.
+ for (unsigned SearchIdx = (Idx >= NumRegUnitSubSets) ? 0 : Idx+1;
+ SearchIdx != EndIdx; ++SearchIdx) {
+ std::set<unsigned> Intersection;
+ std::set_intersection(RegUnitSets[Idx].Units.begin(),
+ RegUnitSets[Idx].Units.end(),
+ RegUnitSets[SearchIdx].Units.begin(),
+ RegUnitSets[SearchIdx].Units.end(),
+ std::inserter(Intersection, Intersection.begin()));
+ if (Intersection.empty())
+ continue;
+
+ // Speculatively grow the RegUnitSets to hold the new set.
+ RegUnitSets.resize(RegUnitSets.size() + 1);
+ RegUnitSets.back().Name =
+ RegUnitSets[Idx].Name + "+" + RegUnitSets[SearchIdx].Name;
+
+ std::set_union(RegUnitSets[Idx].Units.begin(),
+ RegUnitSets[Idx].Units.end(),
+ RegUnitSets[SearchIdx].Units.begin(),
+ RegUnitSets[SearchIdx].Units.end(),
+ std::inserter(RegUnitSets.back().Units,
+ RegUnitSets.back().Units.begin()));
+
+ // Find an existing RegUnitSet, or add the union to the unique sets.
+ std::vector<RegUnitSet>::const_iterator SetI =
+ findRegUnitSet(RegUnitSets, RegUnitSets.back());
+ if (SetI != llvm::prior(RegUnitSets.end()))
+ RegUnitSets.pop_back();
+ }
+ }
+
+ // Iteratively prune unit sets after inferring supersets.
+ pruneUnitSets();
+
+ // For each register class, list the UnitSets that are supersets.
+ RegClassUnitSets.resize(NumRegClasses);
+ for (unsigned RCIdx = 0, RCEnd = NumRegClasses; RCIdx != RCEnd; ++RCIdx) {
+ if (!RegClasses[RCIdx]->Allocatable)
+ continue;
+
+ // Recompute the sorted list of units in this class.
+ std::vector<unsigned> RegUnits;
+ RegClasses[RCIdx]->buildRegUnitSet(RegUnits);
+
+ // Don't increase pressure for unallocatable regclasses.
+ if (RegUnits.empty())
+ continue;
+
+ // Find all supersets.
+ for (unsigned USIdx = 0, USEnd = RegUnitSets.size();
+ USIdx != USEnd; ++USIdx) {
+ if (isRegUnitSubSet(RegUnits, RegUnitSets[USIdx].Units))
+ RegClassUnitSets[RCIdx].push_back(USIdx);
+ }
+ assert(!RegClassUnitSets[RCIdx].empty() && "missing unit set for regclass");
}
}
@@ -737,62 +1370,187 @@ computeOverlaps(std::map<const CodeGenRegister*, CodeGenRegister::Set> &Map) {
void CodeGenRegBank::computeDerivedInfo() {
computeComposites();
+
+ // Compute a weight for each register unit created during getSubRegs.
+ // This may create adopted register units (with unit # >= NumNativeRegUnits).
+ computeRegUnitWeights();
+
+ // Compute a unique set of RegUnitSets. One for each RegClass and inferred
+ // supersets for the union of overlapping sets.
+ computeRegUnitSets();
}
-// Infer missing register classes.
//
-// For every register class RC, make sure that the set of registers in RC with
-// a given SubIxx sub-register form a register class.
-void CodeGenRegBank::computeInferredRegisterClasses() {
- // When this function is called, the register classes have not been sorted
- // and assigned EnumValues yet. That means getSubClasses(),
- // getSuperClasses(), and hasSubClass() functions are defunct.
+// Synthesize missing register class intersections.
+//
+// Make sure that sub-classes of RC exists such that getCommonSubClass(RC, X)
+// returns a maximal register class for all X.
+//
+void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) {
+ for (unsigned rci = 0, rce = RegClasses.size(); rci != rce; ++rci) {
+ CodeGenRegisterClass *RC1 = RC;
+ CodeGenRegisterClass *RC2 = RegClasses[rci];
+ if (RC1 == RC2)
+ continue;
- // Map SubRegIndex to register set.
- typedef std::map<Record*, CodeGenRegister::Set, LessRecord> SubReg2SetMap;
+ // Compute the set intersection of RC1 and RC2.
+ const CodeGenRegister::Set &Memb1 = RC1->getMembers();
+ const CodeGenRegister::Set &Memb2 = RC2->getMembers();
+ CodeGenRegister::Set Intersection;
+ std::set_intersection(Memb1.begin(), Memb1.end(),
+ Memb2.begin(), Memb2.end(),
+ std::inserter(Intersection, Intersection.begin()),
+ CodeGenRegister::Less());
+
+ // Skip disjoint class pairs.
+ if (Intersection.empty())
+ continue;
- // Visit all register classes, including the ones being added by the loop.
- for (unsigned rci = 0; rci != RegClasses.size(); ++rci) {
- CodeGenRegisterClass &RC = *RegClasses[rci];
+ // If RC1 and RC2 have different spill sizes or alignments, use the
+ // larger size for sub-classing. If they are equal, prefer RC1.
+ if (RC2->SpillSize > RC1->SpillSize ||
+ (RC2->SpillSize == RC1->SpillSize &&
+ RC2->SpillAlignment > RC1->SpillAlignment))
+ std::swap(RC1, RC2);
- // Compute the set of registers supporting each SubRegIndex.
- SubReg2SetMap SRSets;
- for (CodeGenRegister::Set::const_iterator RI = RC.getMembers().begin(),
- RE = RC.getMembers().end(); RI != RE; ++RI) {
- const CodeGenRegister::SubRegMap &SRM = (*RI)->getSubRegs();
- for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(),
- E = SRM.end(); I != E; ++I)
- SRSets[I->first].insert(*RI);
+ getOrCreateSubClass(RC1, &Intersection,
+ RC1->getName() + "_and_" + RC2->getName());
+ }
+}
+
+//
+// Synthesize missing sub-classes for getSubClassWithSubReg().
+//
+// Make sure that the set of registers in RC with a given SubIdx sub-register
+// form a register class. Update RC->SubClassWithSubReg.
+//
+void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) {
+ // Map SubRegIndex to set of registers in RC supporting that SubRegIndex.
+ typedef std::map<CodeGenSubRegIndex*, CodeGenRegister::Set,
+ CodeGenSubRegIndex::Less> SubReg2SetMap;
+
+ // Compute the set of registers supporting each SubRegIndex.
+ SubReg2SetMap SRSets;
+ for (CodeGenRegister::Set::const_iterator RI = RC->getMembers().begin(),
+ RE = RC->getMembers().end(); RI != RE; ++RI) {
+ const CodeGenRegister::SubRegMap &SRM = (*RI)->getSubRegs();
+ for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(),
+ E = SRM.end(); I != E; ++I)
+ SRSets[I->first].insert(*RI);
+ }
+
+ // Find matching classes for all SRSets entries. Iterate in SubRegIndex
+ // numerical order to visit synthetic indices last.
+ for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
+ CodeGenSubRegIndex *SubIdx = SubRegIndices[sri];
+ SubReg2SetMap::const_iterator I = SRSets.find(SubIdx);
+ // Unsupported SubRegIndex. Skip it.
+ if (I == SRSets.end())
+ continue;
+ // In most cases, all RC registers support the SubRegIndex.
+ if (I->second.size() == RC->getMembers().size()) {
+ RC->setSubClassWithSubReg(SubIdx, RC);
+ continue;
+ }
+ // This is a real subset. See if we have a matching class.
+ CodeGenRegisterClass *SubRC =
+ getOrCreateSubClass(RC, &I->second,
+ RC->getName() + "_with_" + I->first->getName());
+ RC->setSubClassWithSubReg(SubIdx, SubRC);
+ }
+}
+
+//
+// Synthesize missing sub-classes of RC for getMatchingSuperRegClass().
+//
+// Create sub-classes of RC such that getMatchingSuperRegClass(RC, SubIdx, X)
+// has a maximal result for any SubIdx and any X >= FirstSubRegRC.
+//
+
+void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
+ unsigned FirstSubRegRC) {
+ SmallVector<std::pair<const CodeGenRegister*,
+ const CodeGenRegister*>, 16> SSPairs;
+
+ // Iterate in SubRegIndex numerical order to visit synthetic indices last.
+ for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
+ CodeGenSubRegIndex *SubIdx = SubRegIndices[sri];
+ // Skip indexes that aren't fully supported by RC's registers. This was
+ // computed by inferSubClassWithSubReg() above which should have been
+ // called first.
+ if (RC->getSubClassWithSubReg(SubIdx) != RC)
+ continue;
+
+ // Build list of (Super, Sub) pairs for this SubIdx.
+ SSPairs.clear();
+ for (CodeGenRegister::Set::const_iterator RI = RC->getMembers().begin(),
+ RE = RC->getMembers().end(); RI != RE; ++RI) {
+ const CodeGenRegister *Super = *RI;
+ const CodeGenRegister *Sub = Super->getSubRegs().find(SubIdx)->second;
+ assert(Sub && "Missing sub-register");
+ SSPairs.push_back(std::make_pair(Super, Sub));
}
- // Find matching classes for all SRSets entries. Iterate in SubRegIndex
- // numerical order to visit synthetic indices last.
- for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
- Record *SubIdx = SubRegIndices[sri];
- SubReg2SetMap::const_iterator I = SRSets.find(SubIdx);
- // Unsupported SubRegIndex. Skip it.
- if (I == SRSets.end())
+ // Iterate over sub-register class candidates. Ignore classes created by
+ // this loop. They will never be useful.
+ for (unsigned rci = FirstSubRegRC, rce = RegClasses.size(); rci != rce;
+ ++rci) {
+ CodeGenRegisterClass *SubRC = RegClasses[rci];
+ // Compute the subset of RC that maps into SubRC.
+ CodeGenRegister::Set SubSet;
+ for (unsigned i = 0, e = SSPairs.size(); i != e; ++i)
+ if (SubRC->contains(SSPairs[i].second))
+ SubSet.insert(SSPairs[i].first);
+ if (SubSet.empty())
continue;
- // In most cases, all RC registers support the SubRegIndex.
- if (I->second.size() == RC.getMembers().size()) {
- RC.setSubClassWithSubReg(SubIdx, &RC);
+ // RC injects completely into SubRC.
+ if (SubSet.size() == SSPairs.size()) {
+ SubRC->addSuperRegClass(SubIdx, RC);
continue;
}
+ // Only a subset of RC maps into SubRC. Make sure it is represented by a
+ // class.
+ getOrCreateSubClass(RC, &SubSet, RC->getName() +
+ "_with_" + SubIdx->getName() +
+ "_in_" + SubRC->getName());
+ }
+ }
+}
- // This is a real subset. See if we have a matching class.
- CodeGenRegisterClass::Key K(&I->second, RC.SpillSize, RC.SpillAlignment);
- RCKeyMap::const_iterator FoundI = Key2RC.find(K);
- if (FoundI != Key2RC.end()) {
- RC.setSubClassWithSubReg(SubIdx, FoundI->second);
- continue;
- }
- // Class doesn't exist.
- CodeGenRegisterClass *NewRC =
- new CodeGenRegisterClass(RC.getName() + "_with_" +
- I->first->getName(), K);
- addToMaps(NewRC);
- RC.setSubClassWithSubReg(SubIdx, NewRC);
+//
+// Infer missing register classes.
+//
+void CodeGenRegBank::computeInferredRegisterClasses() {
+ // When this function is called, the register classes have not been sorted
+ // and assigned EnumValues yet. That means getSubClasses(),
+ // getSuperClasses(), and hasSubClass() functions are defunct.
+ unsigned FirstNewRC = RegClasses.size();
+
+ // Visit all register classes, including the ones being added by the loop.
+ for (unsigned rci = 0; rci != RegClasses.size(); ++rci) {
+ CodeGenRegisterClass *RC = RegClasses[rci];
+
+ // Synthesize answers for getSubClassWithSubReg().
+ inferSubClassWithSubReg(RC);
+
+ // Synthesize answers for getCommonSubClass().
+ inferCommonSubClass(RC);
+
+ // Synthesize answers for getMatchingSuperRegClass().
+ inferMatchingSuperRegClass(RC);
+
+ // New register classes are created while this loop is running, and we need
+ // to visit all of them. I particular, inferMatchingSuperRegClass needs
+ // to match old super-register classes with sub-register classes created
+ // after inferMatchingSuperRegClass was called. At this point,
+ // inferMatchingSuperRegClass has checked SuperRC = [0..rci] with SubRC =
+ // [0..FirstNewRC). We need to cover SubRC = [FirstNewRC..rci].
+ if (rci + 1 == FirstNewRC) {
+ unsigned NextNewRC = RegClasses.size();
+ for (unsigned rci2 = 0; rci2 != FirstNewRC; ++rci2)
+ inferMatchingSuperRegClass(RegClasses[rci2], FirstNewRC);
+ FirstNewRC = NextNewRC;
}
}
}
@@ -843,3 +1601,45 @@ CodeGenRegBank::getRegClassForRegister(Record *R) {
}
return FoundRC;
}
+
+BitVector CodeGenRegBank::computeCoveredRegisters(ArrayRef<Record*> Regs) {
+ SetVector<const CodeGenRegister*> Set;
+
+ // First add Regs with all sub-registers.
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ CodeGenRegister *Reg = getReg(Regs[i]);
+ if (Set.insert(Reg))
+ // Reg is new, add all sub-registers.
+ // The pre-ordering is not important here.
+ Reg->addSubRegsPreOrder(Set, *this);
+ }
+
+ // Second, find all super-registers that are completely covered by the set.
+ for (unsigned i = 0; i != Set.size(); ++i) {
+ const CodeGenRegister::SuperRegList &SR = Set[i]->getSuperRegs();
+ for (unsigned j = 0, e = SR.size(); j != e; ++j) {
+ const CodeGenRegister *Super = SR[j];
+ if (!Super->CoveredBySubRegs || Set.count(Super))
+ continue;
+ // This new super-register is covered by its sub-registers.
+ bool AllSubsInSet = true;
+ const CodeGenRegister::SubRegMap &SRM = Super->getSubRegs();
+ for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(),
+ E = SRM.end(); I != E; ++I)
+ if (!Set.count(I->second)) {
+ AllSubsInSet = false;
+ break;
+ }
+ // All sub-registers in Set, add Super as well.
+ // We will visit Super later to recheck its super-registers.
+ if (AllSubsInSet)
+ Set.insert(Super);
+ }
+ }
+
+ // Convert to BitVector.
+ BitVector BV(Registers.size() + 1);
+ for (unsigned i = 0, e = Set.size(); i != e; ++i)
+ BV.set(Set[i]->EnumValue);
+ return BV;
+}
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index 4fc34b092260..232a6e71de2d 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -22,6 +22,7 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstdlib>
#include <map>
#include <string>
@@ -31,14 +32,69 @@
namespace llvm {
class CodeGenRegBank;
+ /// CodeGenSubRegIndex - Represents a sub-register index.
+ class CodeGenSubRegIndex {
+ Record *const TheDef;
+ const unsigned EnumValue;
+
+ public:
+ CodeGenSubRegIndex(Record *R, unsigned Enum);
+
+ const std::string &getName() const;
+ std::string getNamespace() const;
+ std::string getQualifiedName() const;
+
+ // Order CodeGenSubRegIndex pointers by EnumValue.
+ struct Less {
+ bool operator()(const CodeGenSubRegIndex *A,
+ const CodeGenSubRegIndex *B) const {
+ assert(A && B);
+ return A->EnumValue < B->EnumValue;
+ }
+ };
+
+ // Map of composite subreg indices.
+ typedef std::map<CodeGenSubRegIndex*, CodeGenSubRegIndex*, Less> CompMap;
+
+ // Returns the subreg index that results from composing this with Idx.
+ // Returns NULL if this and Idx don't compose.
+ CodeGenSubRegIndex *compose(CodeGenSubRegIndex *Idx) const {
+ CompMap::const_iterator I = Composed.find(Idx);
+ return I == Composed.end() ? 0 : I->second;
+ }
+
+ // Add a composite subreg index: this+A = B.
+ // Return a conflicting composite, or NULL
+ CodeGenSubRegIndex *addComposite(CodeGenSubRegIndex *A,
+ CodeGenSubRegIndex *B) {
+ std::pair<CompMap::iterator, bool> Ins =
+ Composed.insert(std::make_pair(A, B));
+ return (Ins.second || Ins.first->second == B) ? 0 : Ins.first->second;
+ }
+
+ // Update the composite maps of components specified in 'ComposedOf'.
+ void updateComponents(CodeGenRegBank&);
+
+ // Clean out redundant composite mappings.
+ void cleanComposites();
+
+ // Return the map of composites.
+ const CompMap &getComposites() const { return Composed; }
+
+ private:
+ CompMap Composed;
+ };
+
/// CodeGenRegister - Represents a register definition.
struct CodeGenRegister {
Record *TheDef;
unsigned EnumValue;
unsigned CostPerUse;
+ bool CoveredBySubRegs;
// Map SubRegIndex -> Register.
- typedef std::map<Record*, CodeGenRegister*, LessRecord> SubRegMap;
+ typedef std::map<CodeGenSubRegIndex*, CodeGenRegister*,
+ CodeGenSubRegIndex::Less> SubRegMap;
CodeGenRegister(Record *R, unsigned Enum);
@@ -54,18 +110,37 @@ namespace llvm {
}
// Add sub-registers to OSet following a pre-order defined by the .td file.
- void addSubRegsPreOrder(SetVector<CodeGenRegister*> &OSet) const;
+ void addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet,
+ CodeGenRegBank&) const;
// List of super-registers in topological order, small to large.
- typedef std::vector<CodeGenRegister*> SuperRegList;
+ typedef std::vector<const CodeGenRegister*> SuperRegList;
- // Get the list of super-registers.
- // This is only valid after computeDerivedInfo has visited all registers.
+ // Get the list of super-registers. This is valid after getSubReg
+ // visits all registers during RegBank construction.
const SuperRegList &getSuperRegs() const {
assert(SubRegsComplete && "Must precompute sub-registers");
return SuperRegs;
}
+ // List of register units in ascending order.
+ typedef SmallVector<unsigned, 16> RegUnitList;
+
+ // Get the list of register units.
+ // This is only valid after getSubRegs() completes.
+ const RegUnitList &getRegUnits() const { return RegUnits; }
+
+ // Inherit register units from subregisters.
+ // Return true if the RegUnits changed.
+ bool inheritRegUnits(CodeGenRegBank &RegBank);
+
+ // Adopt a register unit for pressure tracking.
+ // A unit is adopted iff its unit number is >= NumNativeRegUnits.
+ void adoptRegUnit(unsigned RUID) { RegUnits.push_back(RUID); }
+
+ // Get the sum of this register's register unit weights.
+ unsigned getWeight(const CodeGenRegBank &RegBank) const;
+
// Order CodeGenRegister pointers by EnumValue.
struct Less {
bool operator()(const CodeGenRegister *A,
@@ -82,6 +157,7 @@ namespace llvm {
bool SubRegsComplete;
SubRegMap SubRegs;
SuperRegList SuperRegs;
+ RegUnitList RegUnits;
};
@@ -101,8 +177,17 @@ namespace llvm {
// super-class.
void inheritProperties(CodeGenRegBank&);
- // Map SubRegIndex -> sub-class
- DenseMap<Record*, CodeGenRegisterClass*> SubClassWithSubReg;
+ // Map SubRegIndex -> sub-class. This is the largest sub-class where all
+ // registers have a SubRegIndex sub-register.
+ DenseMap<CodeGenSubRegIndex*, CodeGenRegisterClass*> SubClassWithSubReg;
+
+ // Map SubRegIndex -> set of super-reg classes. This is all register
+ // classes SuperRC such that:
+ //
+ // R:SubRegIndex in this RC for all R in SuperRC.
+ //
+ DenseMap<CodeGenSubRegIndex*,
+ SmallPtrSet<CodeGenRegisterClass*, 8> > SuperRegClasses;
public:
unsigned EnumValue;
@@ -128,8 +213,7 @@ namespace llvm {
MVT::SimpleValueType getValueTypeNum(unsigned VTNum) const {
if (VTNum < VTs.size())
return VTs[VTNum];
- assert(0 && "VTNum greater than number of ValueTypes in RegClass!");
- abort();
+ llvm_unreachable("VTNum greater than number of ValueTypes in RegClass!");
}
// Return true if this this class contains the register.
@@ -150,14 +234,26 @@ namespace llvm {
// getSubClassWithSubReg - Returns the largest sub-class where all
// registers have a SubIdx sub-register.
- CodeGenRegisterClass *getSubClassWithSubReg(Record *SubIdx) const {
+ CodeGenRegisterClass*
+ getSubClassWithSubReg(CodeGenSubRegIndex *SubIdx) const {
return SubClassWithSubReg.lookup(SubIdx);
}
- void setSubClassWithSubReg(Record *SubIdx, CodeGenRegisterClass *SubRC) {
+ void setSubClassWithSubReg(CodeGenSubRegIndex *SubIdx,
+ CodeGenRegisterClass *SubRC) {
SubClassWithSubReg[SubIdx] = SubRC;
}
+ // getSuperRegClasses - Returns a bit vector of all register classes
+ // containing only SubIdx super-registers of this class.
+ void getSuperRegClasses(CodeGenSubRegIndex *SubIdx, BitVector &Out) const;
+
+ // addSuperRegClass - Add a class containing only SudIdx super-registers.
+ void addSuperRegClass(CodeGenSubRegIndex *SubIdx,
+ CodeGenRegisterClass *SuperRC) {
+ SuperRegClasses[SubIdx].insert(SuperRC);
+ }
+
// getSubClasses - Returns a constant BitVector of subclasses indexed by
// EnumValue.
// The SubClasses vector includs an entry for this class.
@@ -183,6 +279,9 @@ namespace llvm {
// getOrder(0).
const CodeGenRegister::Set &getMembers() const { return Members; }
+ // Populate a unique sorted list of units from a register set.
+ void buildRegUnitSet(std::vector<unsigned> &RegUnits) const;
+
CodeGenRegisterClass(CodeGenRegBank&, Record *R);
// A key representing the parts of a register class used for forming
@@ -217,16 +316,34 @@ namespace llvm {
static void computeSubClasses(CodeGenRegBank&);
};
+ // Each RegUnitSet is a sorted vector with a name.
+ struct RegUnitSet {
+ typedef std::vector<unsigned>::const_iterator iterator;
+
+ std::string Name;
+ std::vector<unsigned> Units;
+ };
+
// CodeGenRegBank - Represent a target's registers and the relations between
// them.
class CodeGenRegBank {
RecordKeeper &Records;
SetTheory Sets;
- std::vector<Record*> SubRegIndices;
+ // SubRegIndices.
+ std::vector<CodeGenSubRegIndex*> SubRegIndices;
+ DenseMap<Record*, CodeGenSubRegIndex*> Def2SubRegIdx;
unsigned NumNamedIndices;
+
+ // Registers.
std::vector<CodeGenRegister*> Registers;
DenseMap<Record*, CodeGenRegister*> Def2Reg;
+ unsigned NumNativeRegUnits;
+ unsigned NumRegUnits; // # native + adopted register units.
+
+ // Map each register unit to a weight (for register pressure).
+ // Includes native and adopted register units.
+ std::vector<unsigned> RegUnitWeights;
// Register classes.
std::vector<CodeGenRegisterClass*> RegClasses;
@@ -234,16 +351,38 @@ namespace llvm {
typedef std::map<CodeGenRegisterClass::Key, CodeGenRegisterClass*> RCKeyMap;
RCKeyMap Key2RC;
+ // Remember each unique set of register units. Initially, this contains a
+ // unique set for each register class. Simliar sets are coalesced with
+ // pruneUnitSets and new supersets are inferred during computeRegUnitSets.
+ std::vector<RegUnitSet> RegUnitSets;
+
+ // Map RegisterClass index to the index of the RegUnitSet that contains the
+ // class's units and any inferred RegUnit supersets.
+ std::vector<std::vector<unsigned> > RegClassUnitSets;
+
// Add RC to *2RC maps.
void addToMaps(CodeGenRegisterClass*);
+ // Create a synthetic sub-class if it is missing.
+ CodeGenRegisterClass *getOrCreateSubClass(const CodeGenRegisterClass *RC,
+ const CodeGenRegister::Set *Membs,
+ StringRef Name);
+
// Infer missing register classes.
void computeInferredRegisterClasses();
+ void inferCommonSubClass(CodeGenRegisterClass *RC);
+ void inferSubClassWithSubReg(CodeGenRegisterClass *RC);
+ void inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
+ unsigned FirstSubRegRC = 0);
+
+ // Iteratively prune unit sets.
+ void pruneUnitSets();
+
+ // Compute a weight for each register unit created during getSubRegs.
+ void computeRegUnitWeights();
- // Composite SubRegIndex instances.
- // Map (SubRegIndex, SubRegIndex) -> SubRegIndex.
- typedef DenseMap<std::pair<Record*, Record*>, Record*> CompositeMap;
- CompositeMap Composite;
+ // Create a RegUnitSet for each RegClass and infer superclasses.
+ void computeRegUnitSets();
// Populate the Composite map from sub-register relationships.
void computeComposites();
@@ -256,20 +395,44 @@ namespace llvm {
// Sub-register indices. The first NumNamedIndices are defined by the user
// in the .td files. The rest are synthesized such that all sub-registers
// have a unique name.
- const std::vector<Record*> &getSubRegIndices() { return SubRegIndices; }
+ ArrayRef<CodeGenSubRegIndex*> getSubRegIndices() { return SubRegIndices; }
unsigned getNumNamedIndices() { return NumNamedIndices; }
- // Map a SubRegIndex Record to its enum value.
- unsigned getSubRegIndexNo(Record *idx);
+ // Find a SubRegIndex form its Record def.
+ CodeGenSubRegIndex *getSubRegIdx(Record*);
// Find or create a sub-register index representing the A+B composition.
- Record *getCompositeSubRegIndex(Record *A, Record *B, bool create = false);
+ CodeGenSubRegIndex *getCompositeSubRegIndex(CodeGenSubRegIndex *A,
+ CodeGenSubRegIndex *B);
const std::vector<CodeGenRegister*> &getRegisters() { return Registers; }
// Find a register from its Record def.
CodeGenRegister *getReg(Record*);
+ // Get a Register's index into the Registers array.
+ unsigned getRegIndex(const CodeGenRegister *Reg) const {
+ return Reg->EnumValue - 1;
+ }
+
+ // Create a new non-native register unit that can be adopted by a register
+ // to increase its pressure. Note that NumNativeRegUnits is not increased.
+ unsigned newRegUnit(unsigned Weight) {
+ if (!RegUnitWeights.empty()) {
+ assert(Weight && "should only add allocatable units");
+ RegUnitWeights.resize(NumRegUnits+1);
+ RegUnitWeights[NumRegUnits] = Weight;
+ }
+ return NumRegUnits++;
+ }
+
+ // Native units are the singular unit of a leaf register. Register aliasing
+ // is completely characterized by native units. Adopted units exist to give
+ // register additional weight but don't affect aliasing.
+ bool isNativeUnit(unsigned RUID) {
+ return RUID < NumNativeRegUnits;
+ }
+
ArrayRef<CodeGenRegisterClass*> getRegClasses() const {
return RegClasses;
}
@@ -284,6 +447,41 @@ namespace llvm {
/// return the superclass. Otherwise return null.
const CodeGenRegisterClass* getRegClassForRegister(Record *R);
+ // Get a register unit's weight. Zero for unallocatable registers.
+ unsigned getRegUnitWeight(unsigned RUID) const {
+ return RegUnitWeights[RUID];
+ }
+
+ // Get the sum of unit weights.
+ unsigned getRegUnitSetWeight(const std::vector<unsigned> &Units) const {
+ unsigned Weight = 0;
+ for (std::vector<unsigned>::const_iterator
+ I = Units.begin(), E = Units.end(); I != E; ++I)
+ Weight += getRegUnitWeight(*I);
+ return Weight;
+ }
+
+ // Increase a RegUnitWeight.
+ void increaseRegUnitWeight(unsigned RUID, unsigned Inc) {
+ RegUnitWeights[RUID] += Inc;
+ }
+
+ // Get the number of register pressure dimensions.
+ unsigned getNumRegPressureSets() const { return RegUnitSets.size(); }
+
+ // Get a set of register unit IDs for a given dimension of pressure.
+ RegUnitSet getRegPressureSet(unsigned Idx) const {
+ return RegUnitSets[Idx];
+ }
+
+ // Get a list of pressure set IDs for a register class. Liveness of a
+ // register in this class impacts each pressure set in this list by the
+ // weight of the register. An exact solution requires all registers in a
+ // class to have the same class, but it is not strictly guaranteed.
+ ArrayRef<unsigned> getRCPressureSetIDs(unsigned RCIdx) const {
+ return RegClassUnitSets[RCIdx];
+ }
+
// Computed derived records such as missing sub-register indices.
void computeDerivedInfo();
@@ -295,6 +493,15 @@ namespace llvm {
// If R1 is a sub-register of R2, Map[R1] is a subset of Map[R2].
void computeOverlaps(std::map<const CodeGenRegister*,
CodeGenRegister::Set> &Map);
+
+ // Compute the set of registers completely covered by the registers in Regs.
+ // The returned BitVector will have a bit set for each register in Regs,
+ // all sub-registers, and all super-registers that are covered by the
+ // registers in Regs.
+ //
+ // This is used to compute the mask of call-preserved registers from a list
+ // of callee-saves.
+ BitVector computeCoveredRegisters(ArrayRef<Record*> Regs);
};
}
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index 4a7bad7e6d85..cf6793570a26 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -58,6 +58,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::iAny: return "MVT::iAny";
case MVT::fAny: return "MVT::fAny";
case MVT::vAny: return "MVT::vAny";
+ case MVT::f16: return "MVT::f16";
case MVT::f32: return "MVT::f32";
case MVT::f64: return "MVT::f64";
case MVT::f80: return "MVT::f80";
@@ -82,6 +83,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v2i64: return "MVT::v2i64";
case MVT::v4i64: return "MVT::v4i64";
case MVT::v8i64: return "MVT::v8i64";
+ case MVT::v2f16: return "MVT::v2f16";
case MVT::v2f32: return "MVT::v2f32";
case MVT::v4f32: return "MVT::v4f32";
case MVT::v8f32: return "MVT::v8f32";
@@ -90,8 +92,8 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::Metadata: return "MVT::Metadata";
case MVT::iPTR: return "MVT::iPTR";
case MVT::iPTRAny: return "MVT::iPTRAny";
- case MVT::untyped: return "MVT::untyped";
- default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
+ case MVT::Untyped: return "MVT::Untyped";
+ default: llvm_unreachable("ILLEGAL VALUE TYPE!");
}
}
@@ -149,6 +151,26 @@ Record *CodeGenTarget::getAsmParser() const {
return LI[AsmParserNum];
}
+/// getAsmParserVariant - Return the AssmblyParserVariant definition for
+/// this target.
+///
+Record *CodeGenTarget::getAsmParserVariant(unsigned i) const {
+ std::vector<Record*> LI =
+ TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
+ if (i >= LI.size())
+ throw "Target does not have an AsmParserVariant #" + utostr(i) + "!";
+ return LI[i];
+}
+
+/// getAsmParserVariantCount - Return the AssmblyParserVariant definition
+/// available for this target.
+///
+unsigned CodeGenTarget::getAsmParserVariantCount() const {
+ std::vector<Record*> LI =
+ TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
+ return LI.size();
+}
+
/// getAsmWriter - Return the AssemblyWriter definition for this target.
///
Record *CodeGenTarget::getAsmWriter() const {
@@ -267,6 +289,7 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
"DBG_VALUE",
"REG_SEQUENCE",
"COPY",
+ "BUNDLE",
0
};
const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();
@@ -492,7 +515,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
} else
- assert(0 && "Unknown property!");
+ llvm_unreachable("Unknown property!");
}
// Sort the argument attributes for later benefit.
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index 730216c331b4..85463da59731 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -91,6 +91,16 @@ public:
///
Record *getAsmParser() const;
+ /// getAsmParserVariant - Return the AssmblyParserVariant definition for
+ /// this target.
+ ///
+ Record *getAsmParserVariant(unsigned i) const;
+
+ /// getAsmParserVariantCount - Return the AssmblyParserVariant definition
+ /// available for this target.
+ ///
+ unsigned getAsmParserVariantCount() const;
+
/// getAsmWriter - Return the AssemblyWriter definition for this target.
///
Record *getAsmWriter() const;
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index 1367e8dd6e86..bd77907a9bd9 100644
--- a/utils/TableGen/DAGISelMatcher.cpp
+++ b/utils/TableGen/DAGISelMatcher.cpp
@@ -15,6 +15,8 @@
#include "llvm/ADT/StringExtras.h"
using namespace llvm;
+void Matcher::anchor() { }
+
void Matcher::dump() const {
print(errs(), 0);
}
@@ -324,6 +326,10 @@ unsigned EmitNodeMatcherCommon::getHashImpl() const {
}
+void EmitNodeMatcher::anchor() { }
+
+void MorphNodeToMatcher::anchor() { }
+
unsigned MarkGlueResultsMatcher::getHashImpl() const {
return HashUnsigneds(GlueResultNodes.begin(), GlueResultNodes.end());
}
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index dcb8da71086e..99ebf98b1e4b 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -41,6 +41,7 @@ class Matcher {
// The next matcher node that is executed after this one. Null if this is the
// last stage of a match.
OwningPtr<Matcher> Next;
+ virtual void anchor();
public:
enum KindTy {
// Matcher state manipulation.
@@ -1011,6 +1012,7 @@ private:
/// EmitNodeMatcher - This signals a successful match and generates a node.
class EmitNodeMatcher : public EmitNodeMatcherCommon {
+ virtual void anchor();
unsigned FirstResultSlot;
public:
EmitNodeMatcher(const std::string &opcodeName,
@@ -1033,6 +1035,7 @@ public:
};
class MorphNodeToMatcher : public EmitNodeMatcherCommon {
+ virtual void anchor();
const PatternToMatch &Pattern;
public:
MorphNodeToMatcher(const std::string &opcodeName,
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index 3b65b2a6de0c..bd425a9bc1a9 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -573,8 +573,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
return 2 + NumResultBytes;
}
}
- assert(0 && "Unreachable");
- return 0;
+ llvm_unreachable("Unreachable");
}
/// EmitMatcherList - Emit the bytes for the specified matcher subtree.
@@ -601,7 +600,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
if (!PatternPredicates.empty()) {
OS << "bool CheckPatternPredicate(unsigned PredNo) const {\n";
OS << " switch (PredNo) {\n";
- OS << " default: assert(0 && \"Invalid predicate in table?\");\n";
+ OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
for (unsigned i = 0, e = PatternPredicates.size(); i != e; ++i)
OS << " case " << i << ": return " << PatternPredicates[i] << ";\n";
OS << " }\n";
@@ -619,7 +618,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
if (!NodePredicates.empty()) {
OS << "bool CheckNodePredicate(SDNode *Node, unsigned PredNo) const {\n";
OS << " switch (PredNo) {\n";
- OS << " default: assert(0 && \"Invalid predicate in table?\");\n";
+ OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
for (unsigned i = 0, e = NodePredicates.size(); i != e; ++i) {
// Emit the predicate code corresponding to this pattern.
TreePredicateFn PredFn = NodePredicates[i];
@@ -641,7 +640,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
OS << " SmallVectorImpl<std::pair<SDValue, SDNode*> > &Result) {\n";
OS << " unsigned NextRes = Result.size();\n";
OS << " switch (PatternNo) {\n";
- OS << " default: assert(0 && \"Invalid pattern # in table?\");\n";
+ OS << " default: llvm_unreachable(\"Invalid pattern # in table?\");\n";
for (unsigned i = 0, e = ComplexPatterns.size(); i != e; ++i) {
const ComplexPattern &P = *ComplexPatterns[i];
unsigned NumOps = P.getNumOperands();
@@ -679,7 +678,7 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) {
if (!NodeXForms.empty()) {
OS << "SDValue RunSDNodeXForm(SDValue V, unsigned XFormNo) {\n";
OS << " switch (XFormNo) {\n";
- OS << " default: assert(0 && \"Invalid xform # in table?\");\n";
+ OS << " default: llvm_unreachable(\"Invalid xform # in table?\");\n";
// FIXME: The node xform could take SDValue's instead of SDNode*'s.
for (unsigned i = 0, e = NodeXForms.size(); i != e; ++i) {
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index 49ad956f8866..2ac7b87e7010 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -217,7 +217,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue());
if (DI == 0) {
- errs() << "Unknown leaf kind: " << *DI << "\n";
+ errs() << "Unknown leaf kind: " << *N << "\n";
abort();
}
diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp
new file mode 100644
index 000000000000..4abf54ebae2e
--- /dev/null
+++ b/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -0,0 +1,512 @@
+//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine-----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class parses the Schedule.td file and produces an API that can be used
+// to reason about whether an instruction can be added to a packet on a VLIW
+// architecture. The class internally generates a deterministic finite
+// automaton (DFA) that models all possible mappings of machine instructions
+// to functional units as instructions are added to a packet.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Record.h"
+#include "CodeGenTarget.h"
+#include "DFAPacketizerEmitter.h"
+#include <list>
+
+using namespace llvm;
+
+//
+//
+// State represents the usage of machine resources if the packet contains
+// a set of instruction classes.
+//
+// Specifically, currentState is a set of bit-masks.
+// The nth bit in a bit-mask indicates whether the nth resource is being used
+// by this state. The set of bit-masks in a state represent the different
+// possible outcomes of transitioning to this state.
+// For example: consider a two resource architecture: resource L and resource M
+// with three instruction classes: L, M, and L_or_M.
+// From the initial state (currentState = 0x00), if we add instruction class
+// L_or_M we will transition to a state with currentState = [0x01, 0x10]. This
+// represents the possible resource states that can result from adding a L_or_M
+// instruction
+//
+// Another way of thinking about this transition is we are mapping a NDFA with
+// two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10].
+//
+//
+namespace {
+class State {
+ public:
+ static int currentStateNum;
+ int stateNum;
+ bool isInitial;
+ std::set<unsigned> stateInfo;
+
+ State();
+ State(const State &S);
+
+ //
+ // canAddInsnClass - Returns true if an instruction of type InsnClass is a
+ // valid transition from this state, i.e., can an instruction of type InsnClass
+ // be added to the packet represented by this state.
+ //
+ // PossibleStates is the set of valid resource states that ensue from valid
+ // transitions.
+ //
+ bool canAddInsnClass(unsigned InsnClass, std::set<unsigned> &PossibleStates);
+};
+} // End anonymous namespace.
+
+
+namespace {
+struct Transition {
+ public:
+ static int currentTransitionNum;
+ int transitionNum;
+ State *from;
+ unsigned input;
+ State *to;
+
+ Transition(State *from_, unsigned input_, State *to_);
+};
+} // End anonymous namespace.
+
+
+//
+// Comparators to keep set of states sorted.
+//
+namespace {
+struct ltState {
+ bool operator()(const State *s1, const State *s2) const;
+};
+} // End anonymous namespace.
+
+
+//
+// class DFA: deterministic finite automaton for processor resource tracking.
+//
+namespace {
+class DFA {
+public:
+ DFA();
+
+ // Set of states. Need to keep this sorted to emit the transition table.
+ std::set<State*, ltState> states;
+
+ // Map from a state to the list of transitions with that state as source.
+ std::map<State*, SmallVector<Transition*, 16>, ltState> stateTransitions;
+ State *currentState;
+
+ // Highest valued Input seen.
+ unsigned LargestInput;
+
+ //
+ // Modify the DFA.
+ //
+ void initialize();
+ void addState(State *);
+ void addTransition(Transition *);
+
+ //
+ // getTransition - Return the state when a transition is made from
+ // State From with Input I. If a transition is not found, return NULL.
+ //
+ State *getTransition(State *, unsigned);
+
+ //
+ // isValidTransition: Predicate that checks if there is a valid transition
+ // from state From on input InsnClass.
+ //
+ bool isValidTransition(State *From, unsigned InsnClass);
+
+ //
+ // writeTable: Print out a table representing the DFA.
+ //
+ void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName);
+};
+} // End anonymous namespace.
+
+
+//
+// Constructors for State, Transition, and DFA
+//
+State::State() :
+ stateNum(currentStateNum++), isInitial(false) {}
+
+
+State::State(const State &S) :
+ stateNum(currentStateNum++), isInitial(S.isInitial),
+ stateInfo(S.stateInfo) {}
+
+
+Transition::Transition(State *from_, unsigned input_, State *to_) :
+ transitionNum(currentTransitionNum++), from(from_), input(input_),
+ to(to_) {}
+
+
+DFA::DFA() :
+ LargestInput(0) {}
+
+
+bool ltState::operator()(const State *s1, const State *s2) const {
+ return (s1->stateNum < s2->stateNum);
+}
+
+
+//
+// canAddInsnClass - Returns true if an instruction of type InsnClass is a
+// valid transition from this state i.e., can an instruction of type InsnClass
+// be added to the packet represented by this state.
+//
+// PossibleStates is the set of valid resource states that ensue from valid
+// transitions.
+//
+bool State::canAddInsnClass(unsigned InsnClass,
+ std::set<unsigned> &PossibleStates) {
+ //
+ // Iterate over all resource states in currentState.
+ //
+ bool AddedState = false;
+
+ for (std::set<unsigned>::iterator SI = stateInfo.begin();
+ SI != stateInfo.end(); ++SI) {
+ unsigned thisState = *SI;
+
+ //
+ // Iterate over all possible resources used in InsnClass.
+ // For ex: for InsnClass = 0x11, all resources = {0x01, 0x10}.
+ //
+
+ DenseSet<unsigned> VisitedResourceStates;
+ for (unsigned int j = 0; j < sizeof(InsnClass) * 8; ++j) {
+ if ((0x1 << j) & InsnClass) {
+ //
+ // For each possible resource used in InsnClass, generate the
+ // resource state if that resource was used.
+ //
+ unsigned ResultingResourceState = thisState | (0x1 << j);
+ //
+ // Check if the resulting resource state can be accommodated in this
+ // packet.
+ // We compute ResultingResourceState OR thisState.
+ // If the result of the OR is different than thisState, it implies
+ // that there is at least one resource that can be used to schedule
+ // InsnClass in the current packet.
+ // Insert ResultingResourceState into PossibleStates only if we haven't
+ // processed ResultingResourceState before.
+ //
+ if ((ResultingResourceState != thisState) &&
+ (VisitedResourceStates.count(ResultingResourceState) == 0)) {
+ VisitedResourceStates.insert(ResultingResourceState);
+ PossibleStates.insert(ResultingResourceState);
+ AddedState = true;
+ }
+ }
+ }
+ }
+
+ return AddedState;
+}
+
+
+void DFA::initialize() {
+ currentState->isInitial = true;
+}
+
+
+void DFA::addState(State *S) {
+ assert(!states.count(S) && "State already exists");
+ states.insert(S);
+}
+
+
+void DFA::addTransition(Transition *T) {
+ // Update LargestInput.
+ if (T->input > LargestInput)
+ LargestInput = T->input;
+
+ // Add the new transition.
+ stateTransitions[T->from].push_back(T);
+}
+
+
+//
+// getTransition - Return the state when a transition is made from
+// State From with Input I. If a transition is not found, return NULL.
+//
+State *DFA::getTransition(State *From, unsigned I) {
+ // Do we have a transition from state From?
+ if (!stateTransitions.count(From))
+ return NULL;
+
+ // Do we have a transition from state From with Input I?
+ for (SmallVector<Transition*, 16>::iterator VI =
+ stateTransitions[From].begin();
+ VI != stateTransitions[From].end(); ++VI)
+ if ((*VI)->input == I)
+ return (*VI)->to;
+
+ return NULL;
+}
+
+
+bool DFA::isValidTransition(State *From, unsigned InsnClass) {
+ return (getTransition(From, InsnClass) != NULL);
+}
+
+
+int State::currentStateNum = 0;
+int Transition::currentTransitionNum = 0;
+
+DFAGen::DFAGen(RecordKeeper &R):
+ TargetName(CodeGenTarget(R).getName()),
+ allInsnClasses(), Records(R) {}
+
+
+//
+// writeTableAndAPI - Print out a table representing the DFA and the
+// associated API to create a DFA packetizer.
+//
+// Format:
+// DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
+// transitions.
+// DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for
+// the ith state.
+//
+//
+void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
+ std::set<State*, ltState>::iterator SI = states.begin();
+ // This table provides a map to the beginning of the transitions for State s
+ // in DFAStateInputTable.
+ std::vector<int> StateEntry(states.size());
+
+ OS << "namespace llvm {\n\n";
+ OS << "const int " << TargetName << "DFAStateInputTable[][2] = {\n";
+
+ // Tracks the total valid transitions encountered so far. It is used
+ // to construct the StateEntry table.
+ int ValidTransitions = 0;
+ for (unsigned i = 0; i < states.size(); ++i, ++SI) {
+ StateEntry[i] = ValidTransitions;
+ for (unsigned j = 0; j <= LargestInput; ++j) {
+ assert (((*SI)->stateNum == (int) i) && "Mismatch in state numbers");
+ if (!isValidTransition(*SI, j))
+ continue;
+
+ OS << "{" << j << ", "
+ << getTransition(*SI, j)->stateNum
+ << "}, ";
+ ++ValidTransitions;
+ }
+
+ // If there are no valid transitions from this stage, we need a sentinel
+ // transition.
+ if (ValidTransitions == StateEntry[i]) {
+ OS << "{-1, -1},";
+ ++ValidTransitions;
+ }
+
+ OS << "\n";
+ }
+ OS << "};\n\n";
+ OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n";
+
+ // Multiply i by 2 since each entry in DFAStateInputTable is a set of
+ // two numbers.
+ for (unsigned i = 0; i < states.size(); ++i)
+ OS << StateEntry[i] << ", ";
+
+ OS << "\n};\n";
+ OS << "} // namespace\n";
+
+
+ //
+ // Emit DFA Packetizer tables if the target is a VLIW machine.
+ //
+ std::string SubTargetClassName = TargetName + "GenSubtargetInfo";
+ OS << "\n" << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
+ OS << "namespace llvm {\n";
+ OS << "DFAPacketizer *" << SubTargetClassName << "::"
+ << "createDFAPacketizer(const InstrItineraryData *IID) const {\n"
+ << " return new DFAPacketizer(IID, " << TargetName
+ << "DFAStateInputTable, " << TargetName << "DFAStateEntryTable);\n}\n\n";
+ OS << "} // End llvm namespace \n";
+}
+
+
+//
+// collectAllInsnClasses - Populate allInsnClasses which is a set of units
+// used in each stage.
+//
+void DFAGen::collectAllInsnClasses(const std::string &Name,
+ Record *ItinData,
+ unsigned &NStages,
+ raw_ostream &OS) {
+ // Collect processor itineraries.
+ std::vector<Record*> ProcItinList =
+ Records.getAllDerivedDefinitions("ProcessorItineraries");
+
+ // If just no itinerary then don't bother.
+ if (ProcItinList.size() < 2)
+ return;
+ std::map<std::string, unsigned> NameToBitsMap;
+
+ // Parse functional units for all the itineraries.
+ for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
+ Record *Proc = ProcItinList[i];
+ std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
+
+ // Convert macros to bits for each stage.
+ for (unsigned i = 0, N = FUs.size(); i < N; ++i)
+ NameToBitsMap[FUs[i]->getName()] = (unsigned) (1U << i);
+ }
+
+ const std::vector<Record*> &StageList =
+ ItinData->getValueAsListOfDefs("Stages");
+
+ // The number of stages.
+ NStages = StageList.size();
+
+ // For each unit.
+ unsigned UnitBitValue = 0;
+
+ // Compute the bitwise or of each unit used in this stage.
+ for (unsigned i = 0; i < NStages; ++i) {
+ const Record *Stage = StageList[i];
+
+ // Get unit list.
+ const std::vector<Record*> &UnitList =
+ Stage->getValueAsListOfDefs("Units");
+
+ for (unsigned j = 0, M = UnitList.size(); j < M; ++j) {
+ // Conduct bitwise or.
+ std::string UnitName = UnitList[j]->getName();
+ assert(NameToBitsMap.count(UnitName));
+ UnitBitValue |= NameToBitsMap[UnitName];
+ }
+
+ if (UnitBitValue != 0)
+ allInsnClasses.insert(UnitBitValue);
+ }
+}
+
+
+//
+// Run the worklist algorithm to generate the DFA.
+//
+void DFAGen::run(raw_ostream &OS) {
+ EmitSourceFileHeader("Target DFA Packetizer Tables", OS);
+
+ // Collect processor iteraries.
+ std::vector<Record*> ProcItinList =
+ Records.getAllDerivedDefinitions("ProcessorItineraries");
+
+ //
+ // Collect the instruction classes.
+ //
+ for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
+ Record *Proc = ProcItinList[i];
+
+ // Get processor itinerary name.
+ const std::string &Name = Proc->getName();
+
+ // Skip default.
+ if (Name == "NoItineraries")
+ continue;
+
+ // Sanity check for at least one instruction itinerary class.
+ unsigned NItinClasses =
+ Records.getAllDerivedDefinitions("InstrItinClass").size();
+ if (NItinClasses == 0)
+ return;
+
+ // Get itinerary data list.
+ std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
+
+ // Collect instruction classes for all itinerary data.
+ for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) {
+ Record *ItinData = ItinDataList[j];
+ unsigned NStages;
+ collectAllInsnClasses(Name, ItinData, NStages, OS);
+ }
+ }
+
+
+ //
+ // Run a worklist algorithm to generate the DFA.
+ //
+ DFA D;
+ State *Initial = new State;
+ Initial->isInitial = true;
+ Initial->stateInfo.insert(0x0);
+ D.addState(Initial);
+ SmallVector<State*, 32> WorkList;
+ std::map<std::set<unsigned>, State*> Visited;
+
+ WorkList.push_back(Initial);
+
+ //
+ // Worklist algorithm to create a DFA for processor resource tracking.
+ // C = {set of InsnClasses}
+ // Begin with initial node in worklist. Initial node does not have
+ // any consumed resources,
+ // ResourceState = 0x0
+ // Visited = {}
+ // While worklist != empty
+ // S = first element of worklist
+ // For every instruction class C
+ // if we can accommodate C in S:
+ // S' = state with resource states = {S Union C}
+ // Add a new transition: S x C -> S'
+ // If S' is not in Visited:
+ // Add S' to worklist
+ // Add S' to Visited
+ //
+ while (!WorkList.empty()) {
+ State *current = WorkList.pop_back_val();
+ for (DenseSet<unsigned>::iterator CI = allInsnClasses.begin(),
+ CE = allInsnClasses.end(); CI != CE; ++CI) {
+ unsigned InsnClass = *CI;
+
+ std::set<unsigned> NewStateResources;
+ //
+ // If we haven't already created a transition for this input
+ // and the state can accommodate this InsnClass, create a transition.
+ //
+ if (!D.getTransition(current, InsnClass) &&
+ current->canAddInsnClass(InsnClass, NewStateResources)) {
+ State *NewState = NULL;
+
+ //
+ // If we have seen this state before, then do not create a new state.
+ //
+ //
+ std::map<std::set<unsigned>, State*>::iterator VI;
+ if ((VI = Visited.find(NewStateResources)) != Visited.end())
+ NewState = VI->second;
+ else {
+ NewState = new State;
+ NewState->stateInfo = NewStateResources;
+ D.addState(NewState);
+ Visited[NewStateResources] = NewState;
+ WorkList.push_back(NewState);
+ }
+
+ Transition *NewTransition = new Transition(current, InsnClass,
+ NewState);
+ D.addTransition(NewTransition);
+ }
+ }
+ }
+
+ // Print out the table.
+ D.writeTableAndAPI(OS, TargetName);
+}
diff --git a/utils/TableGen/DFAPacketizerEmitter.h b/utils/TableGen/DFAPacketizerEmitter.h
new file mode 100644
index 000000000000..1727150ae926
--- /dev/null
+++ b/utils/TableGen/DFAPacketizerEmitter.h
@@ -0,0 +1,52 @@
+//===- DFAPacketizerEmitter.h - Packetization DFA for a VLIW machine-------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class parses the Schedule.td file and produces an API that can be used
+// to reason about whether an instruction can be added to a packet on a VLIW
+// architecture. The class internally generates a deterministic finite
+// automaton (DFA) that models all possible mappings of machine instructions
+// to functional units as instructions are added to a packet.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <map>
+#include <string>
+
+namespace llvm {
+//
+// class DFAGen: class that generates and prints out the DFA for resource
+// tracking.
+//
+class DFAGen : public TableGenBackend {
+private:
+ std::string TargetName;
+ //
+ // allInsnClasses is the set of all possible resources consumed by an
+ // InstrStage.
+ //
+ DenseSet<unsigned> allInsnClasses;
+ RecordKeeper &Records;
+
+public:
+ DFAGen(RecordKeeper &R);
+
+ //
+ // collectAllInsnClasses: Populate allInsnClasses which is a set of units
+ // used in each stage.
+ //
+ void collectAllInsnClasses(const std::string &Name,
+ Record *ItinData,
+ unsigned &NStages,
+ raw_ostream &OS);
+
+ void run(raw_ostream &OS);
+};
+}
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index ff314e9c4f2f..4650197ae718 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -11,7 +11,6 @@
#include "CodeGenTarget.h"
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
-#include "ARMDecoderEmitter.h"
#include "FixedLenDecoderEmitter.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index abef70e31897..3809a4576a54 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -287,6 +287,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
IMM("i64i8imm");
IMM("i64i32imm");
IMM("SSECC");
+ IMM("AVXCC");
// all R, I, R, I, R
MEM("i8mem");
@@ -519,6 +520,8 @@ static void X86ExtractSemantics(
// ignore (doesn't go anywhere we know about)
} else if (name.find("VMCALL") != name.npos) {
// ignore (rather different semantics than a regular call)
+ } else if (name.find("VMMCALL") != name.npos) {
+ // ignore (rather different semantics than a regular call)
} else if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
CALL("off");
} else {
@@ -567,12 +570,23 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
REG("DPR");
REG("DPR_VFP2");
REG("DPR_8");
+ REG("DPair");
REG("SPR");
REG("QPR");
REG("QQPR");
REG("QQQQPR");
+ REG("VecListOneD");
+ REG("VecListDPair");
+ REG("VecListDPairSpaced");
+ REG("VecListThreeD");
+ REG("VecListFourD");
+ REG("VecListOneDAllLanes");
+ REG("VecListDPairAllLanes");
+ REG("VecListDPairSpacedAllLanes");
IMM("i32imm");
+ IMM("fbits16");
+ IMM("fbits32");
IMM("i32imm_hilo16");
IMM("bf_inv_mask_imm");
IMM("lsb_pos_imm");
@@ -597,6 +611,20 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
IMM("imm1_16");
IMM("imm1_32");
IMM("nModImm");
+ IMM("nImmSplatI8");
+ IMM("nImmSplatI16");
+ IMM("nImmSplatI32");
+ IMM("nImmSplatI64");
+ IMM("nImmVMOVI32");
+ IMM("nImmVMOVF32");
+ IMM("imm8");
+ IMM("imm16");
+ IMM("imm32");
+ IMM("imm1_7");
+ IMM("imm1_15");
+ IMM("imm1_31");
+ IMM("imm0_1");
+ IMM("imm0_3");
IMM("imm0_7");
IMM("imm0_15");
IMM("imm0_255");
@@ -735,7 +763,7 @@ static void ARMPopulateOperands(
errs() << "Operand type: " << rec.getName() << '\n';
errs() << "Operand name: " << operandInfo.Name << '\n';
errs() << "Instruction name: " << inst.TheDef->getName() << '\n';
- llvm_unreachable("Unhandled type");
+ throw("Unhandled type in EDEmitter");
}
}
}
@@ -956,11 +984,7 @@ void EDEmitter::run(raw_ostream &o) {
emitCommonEnums(o, i);
- o << "namespace {\n";
-
- o << "llvm::EDInstInfo instInfo" << target.getName().c_str() << "[] = ";
+ o << "static const llvm::EDInstInfo instInfo" << target.getName() << "[] = ";
infoArray.emit(o, i);
o << ";" << "\n";
-
- o << "}\n";
}
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index 9fdc2e33a546..e8dad77302c3 100644
--- a/utils/TableGen/FastISelEmitter.cpp
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -21,7 +21,6 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/VectorExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
@@ -280,7 +279,7 @@ struct OperandsSignature {
} else if (Operands[i].isImm()) {
OS << "uint64_t imm" << i;
} else if (Operands[i].isFP()) {
- OS << "ConstantFP *f" << i;
+ OS << "const ConstantFP *f" << i;
} else {
llvm_unreachable("Unknown operand kind!");
}
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index 02b966a21431..9b676f21a1d3 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -17,6 +17,7 @@
#include "FixedLenDecoderEmitter.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -48,7 +49,7 @@ static bool ValueNotSet(bit_value_t V) {
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) {
+static bit_value_t bitFromBits(const BitsInit &bits, unsigned index) {
if (BitInit *bit = dynamic_cast<BitInit*>(bits.getBit(index)))
return bit->getValue() ? BIT_TRUE : BIT_FALSE;
@@ -56,7 +57,7 @@ static bit_value_t bitFromBits(BitsInit &bits, unsigned index) {
return BIT_UNSET;
}
// Prints the bit value for each position.
-static void dumpBits(raw_ostream &o, BitsInit &bits) {
+static void dumpBits(raw_ostream &o, const BitsInit &bits) {
unsigned index;
for (index = bits.getNumBits(); index > 0; index--) {
@@ -71,7 +72,7 @@ static void dumpBits(raw_ostream &o, BitsInit &bits) {
o << "_";
break;
default:
- assert(0 && "unexpected return value from bitFromBits");
+ llvm_unreachable("unexpected return value from bitFromBits");
}
}
}
@@ -125,7 +126,7 @@ typedef std::vector<bit_value_t> insn_t;
/// 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
+ const 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
@@ -137,7 +138,7 @@ protected:
std::vector<unsigned> VariableInstructions;
// Map of well-known segment value to its delegate.
- std::map<unsigned, FilterChooser*> FilterChooserMap;
+ std::map<unsigned, const FilterChooser*> FilterChooserMap;
// Number of instructions which fall under FilteredInstructions category.
unsigned NumFiltered;
@@ -145,19 +146,15 @@ protected:
// 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() {
+ unsigned getNumFiltered() const { return NumFiltered; }
+ unsigned getSingletonOpc() const {
assert(NumFiltered == 1);
return LastOpcFiltered;
}
// Return the filter chooser for the group of instructions without constant
// segment values.
- FilterChooser &getVariableFC() {
+ const FilterChooser &getVariableFC() const {
assert(NumFiltered == 1);
assert(FilterChooserMap.size() == 1);
return *(FilterChooserMap.find((unsigned)-1)->second);
@@ -177,7 +174,7 @@ public:
void recurse();
// Emit code to decode instructions given a segment or segments of bits.
- void emit(raw_ostream &o, unsigned &Indentation);
+ void emit(raw_ostream &o, unsigned &Indentation) const;
// Returns the number of fanout produced by the filter. More fanout implies
// the filter distinguishes more categories of instructions.
@@ -217,10 +214,10 @@ protected:
const std::vector<const CodeGenInstruction*> &AllInstructions;
// Vector of uid's for this filter chooser to work on.
- const std::vector<unsigned> Opcodes;
+ const std::vector<unsigned> &Opcodes;
// Lookup table for the operand decoding of instructions.
- std::map<unsigned, std::vector<OperandInfo> > &Operands;
+ const std::map<unsigned, std::vector<OperandInfo> > &Operands;
// Vector of candidate filters.
std::vector<Filter> Filters;
@@ -230,7 +227,7 @@ protected:
std::vector<bit_value_t> FilterBitValues;
// Links to the FilterChooser above us in the decoding tree.
- FilterChooser *Parent;
+ const FilterChooser *Parent;
// Index of the best filter from Filters.
int BestIndex;
@@ -242,19 +239,19 @@ protected:
const FixedLenDecoderEmitter *Emitter;
public:
- FilterChooser(const FilterChooser &FC) :
- AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes),
+ FilterChooser(const FilterChooser &FC)
+ : AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes),
Operands(FC.Operands), Filters(FC.Filters),
FilterBitValues(FC.FilterBitValues), Parent(FC.Parent),
- BestIndex(FC.BestIndex), BitWidth(FC.BitWidth),
- Emitter(FC.Emitter) { }
+ BestIndex(FC.BestIndex), BitWidth(FC.BitWidth),
+ Emitter(FC.Emitter) { }
FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
const std::vector<unsigned> &IDs,
- std::map<unsigned, std::vector<OperandInfo> > &Ops,
+ const std::map<unsigned, std::vector<OperandInfo> > &Ops,
unsigned BW,
- const FixedLenDecoderEmitter *E) :
- AllInstructions(Insts), Opcodes(IDs), Operands(Ops), Filters(),
+ const FixedLenDecoderEmitter *E)
+ : AllInstructions(Insts), Opcodes(IDs), Operands(Ops), Filters(),
Parent(NULL), BestIndex(-1), BitWidth(BW), Emitter(E) {
for (unsigned i = 0; i < BitWidth; ++i)
FilterBitValues.push_back(BIT_UNFILTERED);
@@ -264,10 +261,10 @@ public:
FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
const std::vector<unsigned> &IDs,
- std::map<unsigned, std::vector<OperandInfo> > &Ops,
- std::vector<bit_value_t> &ParentFilterBitValues,
- FilterChooser &parent) :
- AllInstructions(Insts), Opcodes(IDs), Operands(Ops),
+ const std::map<unsigned, std::vector<OperandInfo> > &Ops,
+ const std::vector<bit_value_t> &ParentFilterBitValues,
+ const FilterChooser &parent)
+ : AllInstructions(Insts), Opcodes(IDs), Operands(Ops),
Filters(), FilterBitValues(ParentFilterBitValues),
Parent(&parent), BestIndex(-1), BitWidth(parent.BitWidth),
Emitter(parent.Emitter) {
@@ -275,18 +272,31 @@ public:
}
// The top level filter chooser has NULL as its parent.
- bool isTopLevel() { return Parent == NULL; }
+ bool isTopLevel() const { return Parent == NULL; }
// Emit the top level typedef and decodeInstruction() function.
- void emitTop(raw_ostream &o, unsigned Indentation, std::string Namespace);
+ void emitTop(raw_ostream &o, unsigned Indentation,
+ const std::string &Namespace) const;
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 < BitWidth; ++i)
- Insn.push_back(bitFromBits(Bits, i));
+ // We may have a SoftFail bitmask, which specifies a mask where an encoding
+ // may differ from the value in "Inst" and yet still be valid, but the
+ // disassembler should return SoftFail instead of Success.
+ //
+ // This is used for marking UNPREDICTABLE instructions in the ARM world.
+ BitsInit *SFBits =
+ AllInstructions[Opcode]->TheDef->getValueAsBitsInit("SoftFail");
+
+ for (unsigned i = 0; i < BitWidth; ++i) {
+ if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE)
+ Insn.push_back(BIT_UNSET);
+ else
+ Insn.push_back(bitFromBits(Bits, i));
+ }
}
// Returns the record name.
@@ -300,15 +310,16 @@ protected:
// 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;
+ unsigned NumBits) const;
/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
/// filter array as a series of chars.
- void dumpFilterArray(raw_ostream &o, std::vector<bit_value_t> & filter);
+ void dumpFilterArray(raw_ostream &o,
+ const std::vector<bit_value_t> & filter) const;
/// 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);
+ void dumpStack(raw_ostream &o, const char *prefix) const;
Filter &bestFilter() {
assert(BestIndex != -1 && "BestIndex not set");
@@ -316,9 +327,9 @@ protected:
}
// Called from Filter::recurse() when singleton exists. For debug purpose.
- void SingletonExists(unsigned Opc);
+ void SingletonExists(unsigned Opc) const;
- bool PositionFiltered(unsigned i) {
+ bool PositionFiltered(unsigned i) const {
return ValueSet(FilterBitValues[i]);
}
@@ -327,31 +338,37 @@ protected:
// 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);
+ std::vector<unsigned> &EndBits,
+ std::vector<uint64_t> &FieldVals,
+ const insn_t &Insn) const;
// Emits code to check the Predicates member of an instruction are true.
// Returns true if predicate matches were emitted, false otherwise.
- bool emitPredicateMatch(raw_ostream &o, unsigned &Indentation,unsigned Opc);
+ bool emitPredicateMatch(raw_ostream &o, unsigned &Indentation,
+ unsigned Opc) const;
+
+ void emitSoftFailCheck(raw_ostream &o, unsigned Indentation,
+ unsigned Opc) const;
// 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);
+ bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ unsigned Opc) const;
// Emits code to decode the singleton, and then to decode the rest.
- void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,Filter &Best);
+ void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
+ const Filter &Best) const;
void emitBinaryParser(raw_ostream &o , unsigned &Indentation,
- OperandInfo &OpInfo);
+ const OperandInfo &OpInfo) const;
// Assign a single filter and run with it.
- void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit,
- bool mixed);
+ void runSingleFilter(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);
+ 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
@@ -366,31 +383,30 @@ protected:
// 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);
+ bool emit(raw_ostream &o, unsigned &Indentation) const;
};
///////////////////////////
// //
-// Filter Implmenetation //
+// Filter Implementation //
// //
///////////////////////////
-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(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) {
}
Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
- bool mixed) : Owner(&owner), StartBit(startBit), NumBits(numBits),
- Mixed(mixed) {
+ bool mixed)
+ : Owner(&owner), StartBit(startBit), NumBits(numBits), Mixed(mixed) {
assert(StartBit + NumBits - 1 < Owner->BitWidth);
NumFiltered = 0;
LastOpcFiltered = 0;
- NumVariable = 0;
for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) {
insn_t Insn;
@@ -409,10 +425,9 @@ Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
FilteredInstructions[Field].push_back(LastOpcFiltered);
++NumFiltered;
} else {
- // Some of the encoding bit(s) are unspecfied. This contributes to
+ // Some of the encoding bit(s) are unspecified. This contributes to
// one additional member of "Variable" instructions.
VariableInstructions.push_back(Owner->Opcodes[i]);
- ++NumVariable;
}
}
@@ -421,7 +436,7 @@ Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
}
Filter::~Filter() {
- std::map<unsigned, FilterChooser*>::iterator filterIterator;
+ std::map<unsigned, const FilterChooser*>::iterator filterIterator;
for (filterIterator = FilterChooserMap.begin();
filterIterator != FilterChooserMap.end();
filterIterator++) {
@@ -450,7 +465,7 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for further processing on this
// group of instructions whose segment values are variable.
- FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ FilterChooserMap.insert(std::pair<unsigned, const FilterChooser*>(
(unsigned)-1,
new FilterChooser(Owner->AllInstructions,
VariableInstructions,
@@ -483,7 +498,7 @@ void Filter::recurse() {
// Delegates to an inferior filter chooser for further processing on this
// category of instructions.
- FilterChooserMap.insert(std::pair<unsigned, FilterChooser*>(
+ FilterChooserMap.insert(std::pair<unsigned, const FilterChooser*>(
mapIterator->first,
new FilterChooser(Owner->AllInstructions,
mapIterator->second,
@@ -495,7 +510,7 @@ void Filter::recurse() {
}
// Emit code to decode instructions given a segment or segments of bits.
-void Filter::emit(raw_ostream &o, unsigned &Indentation) {
+void Filter::emit(raw_ostream &o, unsigned &Indentation) const {
o.indent(Indentation) << "// Check Inst{";
if (NumBits > 1)
@@ -507,7 +522,7 @@ void Filter::emit(raw_ostream &o, unsigned &Indentation) {
<< "(insn, " << StartBit << ", "
<< NumBits << ")) {\n";
- std::map<unsigned, FilterChooser*>::iterator filterIterator;
+ std::map<unsigned, const FilterChooser*>::const_iterator filterIterator;
bool DefaultCase = false;
for (filterIterator = FilterChooserMap.begin();
@@ -537,12 +552,12 @@ void Filter::emit(raw_ostream &o, unsigned &Indentation) {
// encoding bits do not match exactly.
if (!DefaultCase) { ++Indentation; ++Indentation; }
- bool finished = filterIterator->second->emit(o, Indentation);
+ 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";
+
+ o.indent(Indentation) << "break;\n";
if (!DefaultCase) { --Indentation; --Indentation; }
}
@@ -571,13 +586,17 @@ unsigned Filter::usefulness() const {
// Emit the top level typedef and decodeInstruction() function.
void FilterChooser::emitTop(raw_ostream &o, unsigned Indentation,
- std::string Namespace) {
+ const std::string &Namespace) const {
o.indent(Indentation) <<
- "static MCDisassembler::DecodeStatus decode" << Namespace << "Instruction" << BitWidth
- << "(MCInst &MI, uint" << BitWidth << "_t insn, uint64_t Address, "
+ "static MCDisassembler::DecodeStatus decode" << Namespace << "Instruction"
+ << BitWidth << "(MCInst &MI, uint" << BitWidth
+ << "_t insn, uint64_t Address, "
<< "const void *Decoder, const MCSubtargetInfo &STI) {\n";
- o.indent(Indentation) << " unsigned tmp = 0;\n (void)tmp;\n" << Emitter->Locals << "\n";
+ o.indent(Indentation) << " unsigned tmp = 0;\n";
+ o.indent(Indentation) << " (void)tmp;\n";
+ o.indent(Indentation) << Emitter->Locals << "\n";
o.indent(Indentation) << " uint64_t Bits = STI.getFeatureBits();\n";
+ o.indent(Indentation) << " (void)Bits;\n";
++Indentation; ++Indentation;
// Emits code to decode the instructions.
@@ -598,7 +617,7 @@ void FilterChooser::emitTop(raw_ostream &o, unsigned Indentation,
// 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 {
+ unsigned StartBit, unsigned NumBits) const {
Field = 0;
for (unsigned i = 0; i < NumBits; ++i) {
@@ -615,7 +634,7 @@ bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn,
/// dumpFilterArray - dumpFilterArray prints out debugging info for the given
/// filter array as a series of chars.
void FilterChooser::dumpFilterArray(raw_ostream &o,
- std::vector<bit_value_t> &filter) {
+ const std::vector<bit_value_t> &filter) const {
unsigned bitIndex;
for (bitIndex = BitWidth; bitIndex > 0; bitIndex--) {
@@ -638,8 +657,8 @@ void FilterChooser::dumpFilterArray(raw_ostream &o,
/// 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;
+void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) const {
+ const FilterChooser *current = this;
while (current) {
o << prefix;
@@ -650,7 +669,7 @@ void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) {
}
// Called from Filter::recurse() when singleton exists. For debug purpose.
-void FilterChooser::SingletonExists(unsigned Opc) {
+void FilterChooser::SingletonExists(unsigned Opc) const {
insn_t Insn0;
insnWithID(Insn0, Opc);
@@ -663,7 +682,7 @@ void FilterChooser::SingletonExists(unsigned Opc) {
errs() << '\n';
dumpStack(errs(), "\t\t");
- for (unsigned i = 0; i < Opcodes.size(); i++) {
+ for (unsigned i = 0; i < Opcodes.size(); ++i) {
const std::string &Name = nameWithID(Opcodes[i]);
errs() << '\t' << Name << " ";
@@ -678,8 +697,9 @@ void FilterChooser::SingletonExists(unsigned Opc) {
// 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) {
+ std::vector<unsigned> &EndBits,
+ std::vector<uint64_t> &FieldVals,
+ const insn_t &Insn) const {
unsigned Num, BitNo;
Num = BitNo = 0;
@@ -695,9 +715,7 @@ unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
Val = Value(Insn[i]);
bool Filtered = PositionFiltered(i);
switch (State) {
- default:
- assert(0 && "Unreachable code!");
- break;
+ default: llvm_unreachable("Unreachable code!");
case 0:
case 1:
if (Filtered || Val == -1)
@@ -736,17 +754,17 @@ unsigned FilterChooser::getIslands(std::vector<unsigned> &StartBits,
}
void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation,
- OperandInfo &OpInfo) {
- std::string &Decoder = OpInfo.Decoder;
+ const OperandInfo &OpInfo) const {
+ const std::string &Decoder = OpInfo.Decoder;
if (OpInfo.numFields() == 1) {
- OperandInfo::iterator OI = OpInfo.begin();
+ OperandInfo::const_iterator OI = OpInfo.begin();
o.indent(Indentation) << " tmp = fieldFromInstruction" << BitWidth
<< "(insn, " << OI->Base << ", " << OI->Width
<< ");\n";
} else {
o.indent(Indentation) << " tmp = 0;\n";
- for (OperandInfo::iterator OI = OpInfo.begin(), OE = OpInfo.end();
+ for (OperandInfo::const_iterator OI = OpInfo.begin(), OE = OpInfo.end();
OI != OE; ++OI) {
o.indent(Indentation) << " tmp |= (fieldFromInstruction" << BitWidth
<< "(insn, " << OI->Base << ", " << OI->Width
@@ -756,14 +774,15 @@ void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation,
if (Decoder != "")
o.indent(Indentation) << " " << Emitter->GuardPrefix << Decoder
- << "(MI, tmp, Address, Decoder)" << Emitter->GuardPostfix << "\n";
+ << "(MI, tmp, Address, Decoder)"
+ << Emitter->GuardPostfix << "\n";
else
o.indent(Indentation) << " MI.addOperand(MCOperand::CreateImm(tmp));\n";
}
static void emitSinglePredicateMatch(raw_ostream &o, StringRef str,
- std::string PredicateNamespace) {
+ const std::string &PredicateNamespace) {
if (str[0] == '!')
o << "!(Bits & " << PredicateNamespace << "::"
<< str.slice(1,str.size()) << ")";
@@ -772,8 +791,9 @@ static void emitSinglePredicateMatch(raw_ostream &o, StringRef str,
}
bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation,
- unsigned Opc) {
- ListInit *Predicates = AllInstructions[Opc]->TheDef->getValueAsListInit("Predicates");
+ unsigned Opc) const {
+ ListInit *Predicates =
+ AllInstructions[Opc]->TheDef->getValueAsListInit("Predicates");
for (unsigned i = 0; i < Predicates->getSize(); ++i) {
Record *Pred = Predicates->getElementAsRecord(i);
if (!Pred->getValue("AssemblerMatcherPredicate"))
@@ -799,10 +819,70 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation,
return Predicates->getSize() > 0;
}
+void FilterChooser::emitSoftFailCheck(raw_ostream &o, unsigned Indentation,
+ unsigned Opc) const {
+ BitsInit *SFBits =
+ AllInstructions[Opc]->TheDef->getValueAsBitsInit("SoftFail");
+ if (!SFBits) return;
+ BitsInit *InstBits = AllInstructions[Opc]->TheDef->getValueAsBitsInit("Inst");
+
+ APInt PositiveMask(BitWidth, 0ULL);
+ APInt NegativeMask(BitWidth, 0ULL);
+ for (unsigned i = 0; i < BitWidth; ++i) {
+ bit_value_t B = bitFromBits(*SFBits, i);
+ bit_value_t IB = bitFromBits(*InstBits, i);
+
+ if (B != BIT_TRUE) continue;
+
+ switch (IB) {
+ case BIT_FALSE:
+ // The bit is meant to be false, so emit a check to see if it is true.
+ PositiveMask.setBit(i);
+ break;
+ case BIT_TRUE:
+ // The bit is meant to be true, so emit a check to see if it is false.
+ NegativeMask.setBit(i);
+ break;
+ default:
+ // The bit is not set; this must be an error!
+ StringRef Name = AllInstructions[Opc]->TheDef->getName();
+ errs() << "SoftFail Conflict: bit SoftFail{" << i << "} in "
+ << Name
+ << " is set but Inst{" << i <<"} is unset!\n"
+ << " - You can only mark a bit as SoftFail if it is fully defined"
+ << " (1/0 - not '?') in Inst\n";
+ o << "#error SoftFail Conflict, " << Name << "::SoftFail{" << i
+ << "} set but Inst{" << i << "} undefined!\n";
+ }
+ }
+
+ bool NeedPositiveMask = PositiveMask.getBoolValue();
+ bool NeedNegativeMask = NegativeMask.getBoolValue();
+
+ if (!NeedPositiveMask && !NeedNegativeMask)
+ return;
+
+ std::string PositiveMaskStr = PositiveMask.toString(16, /*signed=*/false);
+ std::string NegativeMaskStr = NegativeMask.toString(16, /*signed=*/false);
+ StringRef BitExt = "";
+ if (BitWidth > 32)
+ BitExt = "ULL";
+
+ o.indent(Indentation) << "if (";
+ if (NeedPositiveMask)
+ o << "insn & 0x" << PositiveMaskStr << BitExt;
+ if (NeedPositiveMask && NeedNegativeMask)
+ o << " || ";
+ if (NeedNegativeMask)
+ o << "~insn & 0x" << NegativeMaskStr << BitExt;
+ o << ")\n";
+ o.indent(Indentation+2) << "S = MCDisassembler::SoftFail;\n";
+}
+
// 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) {
+ unsigned Opc) const {
std::vector<unsigned> StartBits;
std::vector<unsigned> EndBits;
std::vector<uint64_t> FieldVals;
@@ -821,22 +901,26 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
if (!emitPredicateMatch(o, Indentation, Opc))
o << "1";
o << ") {\n";
+ emitSoftFailCheck(o, Indentation+2, Opc);
o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n";
- std::vector<OperandInfo>& InsnOperands = Operands[Opc];
- for (std::vector<OperandInfo>::iterator
+ std::map<unsigned, std::vector<OperandInfo> >::const_iterator OpIter =
+ Operands.find(Opc);
+ const std::vector<OperandInfo>& InsnOperands = OpIter->second;
+ for (std::vector<OperandInfo>::const_iterator
I = InsnOperands.begin(), E = InsnOperands.end(); I != E; ++I) {
// If a custom instruction decoder was specified, use that.
if (I->numFields() == 0 && I->Decoder.size()) {
o.indent(Indentation) << " " << Emitter->GuardPrefix << I->Decoder
- << "(MI, insn, Address, Decoder)" << Emitter->GuardPostfix << "\n";
+ << "(MI, insn, Address, Decoder)"
+ << Emitter->GuardPostfix << "\n";
break;
}
emitBinaryParser(o, Indentation, *I);
}
- o.indent(Indentation) << " return " << Emitter->ReturnOK << "; // " << nameWithID(Opc)
- << '\n';
+ o.indent(Indentation) << " return " << Emitter->ReturnOK << "; // "
+ << nameWithID(Opc) << '\n';
o.indent(Indentation) << "}\n"; // Closing predicate block.
return true;
}
@@ -870,21 +954,25 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
else
o << ") {\n";
}
+ emitSoftFailCheck(o, Indentation+2, Opc);
o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n";
- std::vector<OperandInfo>& InsnOperands = Operands[Opc];
- for (std::vector<OperandInfo>::iterator
+ std::map<unsigned, std::vector<OperandInfo> >::const_iterator OpIter =
+ Operands.find(Opc);
+ const std::vector<OperandInfo>& InsnOperands = OpIter->second;
+ for (std::vector<OperandInfo>::const_iterator
I = InsnOperands.begin(), E = InsnOperands.end(); I != E; ++I) {
// If a custom instruction decoder was specified, use that.
if (I->numFields() == 0 && I->Decoder.size()) {
o.indent(Indentation) << " " << Emitter->GuardPrefix << I->Decoder
- << "(MI, insn, Address, Decoder)" << Emitter->GuardPostfix << "\n";
+ << "(MI, insn, Address, Decoder)"
+ << Emitter->GuardPostfix << "\n";
break;
}
emitBinaryParser(o, Indentation, *I);
}
- o.indent(Indentation) << " return " << Emitter->ReturnOK << "; // " << nameWithID(Opc)
- << '\n';
+ o.indent(Indentation) << " return " << Emitter->ReturnOK << "; // "
+ << nameWithID(Opc) << '\n';
o.indent(Indentation) << "}\n";
return false;
@@ -892,7 +980,7 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
// Emits code to decode the singleton, and then to decode the rest.
void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
- Filter &Best) {
+ const Filter &Best) const {
unsigned Opc = Best.getSingletonOpc();
@@ -908,8 +996,8 @@ void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,
// 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) {
+void FilterChooser::runSingleFilter(unsigned startBit, unsigned numBit,
+ bool mixed) {
Filters.clear();
Filter F(*this, startBit, numBit, true);
Filters.push_back(F);
@@ -920,7 +1008,7 @@ void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit,
// 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) {
+ 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)
@@ -957,8 +1045,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
// 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);
+ runSingleFilter(StartBits[0], EndBits[0] - StartBits[0] + 1, true);
return true;
}
}
@@ -1066,7 +1153,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
RA = ATTR_MIXED;
break;
default:
- assert(0 && "Unexpected bitAttr!");
+ llvm_unreachable("Unexpected bitAttr!");
}
break;
case ATTR_ALL_SET:
@@ -1087,7 +1174,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
RA = ATTR_MIXED;
break;
default:
- assert(0 && "Unexpected bitAttr!");
+ llvm_unreachable("Unexpected bitAttr!");
}
break;
case ATTR_MIXED:
@@ -1109,13 +1196,13 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
case ATTR_MIXED:
break;
default:
- assert(0 && "Unexpected bitAttr!");
+ llvm_unreachable("Unexpected bitAttr!");
}
break;
case ATTR_ALL_UNSET:
- assert(0 && "regionAttr state machine has no ATTR_UNSET state");
+ llvm_unreachable("regionAttr state machine has no ATTR_UNSET state");
case ATTR_FILTERED:
- assert(0 && "regionAttr state machine has no ATTR_FILTERED state");
+ llvm_unreachable("regionAttr state machine has no ATTR_FILTERED state");
}
}
@@ -1189,7 +1276,7 @@ void FilterChooser::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 FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
+bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) const {
if (Opcodes.size() == 1)
// There is only one instruction in the set, which is great!
// Call emitSingletonDecoder() to see whether there are any remaining
@@ -1198,11 +1285,11 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
// Choose the best filter to do the decodings!
if (BestIndex != -1) {
- Filter &Best = bestFilter();
+ const Filter &Best = Filters[BestIndex];
if (Best.getNumFiltered() == 1)
emitSingletonDecoder(o, Indentation, Best);
else
- bestFilter().emit(o, Indentation);
+ Best.emit(o, Indentation);
return false;
}
@@ -1222,7 +1309,7 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
dumpStack(errs(), "\t\t");
- for (unsigned i = 0; i < Opcodes.size(); i++) {
+ for (unsigned i = 0; i < Opcodes.size(); ++i) {
const std::string &Name = nameWithID(Opcodes[i]);
errs() << '\t' << Name << " ";
@@ -1234,9 +1321,8 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) {
return true;
}
-static bool populateInstruction(const CodeGenInstruction &CGI,
- unsigned Opc,
- std::map<unsigned, std::vector<OperandInfo> >& Operands){
+static bool populateInstruction(const CodeGenInstruction &CGI, unsigned Opc,
+ std::map<unsigned, std::vector<OperandInfo> > &Operands){
const Record &Def = *CGI.TheDef;
// 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
@@ -1290,7 +1376,7 @@ static bool populateInstruction(const CodeGenInstruction &CGI,
}
// For each operand, see if we can figure out where it is encoded.
- for (std::vector<std::pair<Init*, std::string> >::iterator
+ for (std::vector<std::pair<Init*, std::string> >::const_iterator
NI = InOutOperands.begin(), NE = InOutOperands.end(); NI != NE; ++NI) {
std::string Decoder = "";
@@ -1435,8 +1521,7 @@ static void emitHelper(llvm::raw_ostream &o, unsigned BitWidth) {
}
// Emits disassembler code for instruction decoding.
-void FixedLenDecoderEmitter::run(raw_ostream &o)
-{
+void FixedLenDecoderEmitter::run(raw_ostream &o) {
o << "#include \"llvm/MC/MCInst.h\"\n";
o << "#include \"llvm/Support/DataTypes.h\"\n";
o << "#include <assert.h>\n";
@@ -1444,14 +1529,15 @@ void FixedLenDecoderEmitter::run(raw_ostream &o)
o << "namespace llvm {\n\n";
// Parameterize the decoders based on namespace and instruction width.
- NumberedInstructions = Target.getInstructionsByEnumValue();
+ const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ Target.getInstructionsByEnumValue();
std::map<std::pair<std::string, unsigned>,
std::vector<unsigned> > OpcMap;
std::map<unsigned, std::vector<OperandInfo> > Operands;
for (unsigned i = 0; i < NumberedInstructions.size(); ++i) {
const CodeGenInstruction *Inst = NumberedInstructions[i];
- Record *Def = Inst->TheDef;
+ const Record *Def = Inst->TheDef;
unsigned Size = Def->getValueAsInt("Size");
if (Def->getValueAsString("Namespace") == "TargetOpcode" ||
Def->getValueAsBit("isPseudo") ||
@@ -1470,7 +1556,7 @@ void FixedLenDecoderEmitter::run(raw_ostream &o)
std::set<unsigned> Sizes;
for (std::map<std::pair<std::string, unsigned>,
- std::vector<unsigned> >::iterator
+ std::vector<unsigned> >::const_iterator
I = OpcMap.begin(), E = OpcMap.end(); I != E; ++I) {
// If we haven't visited this instruction width before, emit the
// helper method to extract fields.
diff --git a/utils/TableGen/FixedLenDecoderEmitter.h b/utils/TableGen/FixedLenDecoderEmitter.h
index 2df5448aa8d1..195297c966dd 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.h
+++ b/utils/TableGen/FixedLenDecoderEmitter.h
@@ -39,12 +39,12 @@ struct OperandInfo {
Fields.push_back(EncodingField(Base, Width, Offset));
}
- unsigned numFields() { return Fields.size(); }
+ unsigned numFields() const { return Fields.size(); }
- typedef std::vector<EncodingField>::iterator iterator;
+ typedef std::vector<EncodingField>::const_iterator const_iterator;
- iterator begin() { return Fields.begin(); }
- iterator end() { return Fields.end(); }
+ const_iterator begin() const { return Fields.begin(); }
+ const_iterator end() const { return Fields.end(); }
};
class FixedLenDecoderEmitter : public TableGenBackend {
@@ -52,12 +52,12 @@ public:
FixedLenDecoderEmitter(RecordKeeper &R,
std::string PredicateNamespace,
std::string GPrefix = "if (",
- std::string GPostfix = " == MCDisassembler::Fail) return MCDisassembler::Fail;",
+ std::string GPostfix = " == MCDisassembler::Fail)"
+ " return MCDisassembler::Fail;",
std::string ROK = "MCDisassembler::Success",
std::string RFail = "MCDisassembler::Fail",
std::string L = "") :
- Records(R), Target(R),
- NumberedInstructions(Target.getInstructionsByEnumValue()),
+ Target(R),
PredicateNamespace(PredicateNamespace),
GuardPrefix(GPrefix), GuardPostfix(GPostfix),
ReturnOK(ROK), ReturnFail(RFail), Locals(L) {}
@@ -66,11 +66,7 @@ public:
void run(raw_ostream &o);
private:
- RecordKeeper &Records;
CodeGenTarget Target;
- std::vector<const CodeGenInstruction*> NumberedInstructions;
- std::vector<unsigned> Opcodes;
- std::map<unsigned, std::vector<OperandInfo> > Operands;
public:
std::string PredicateNamespace;
std::string GuardPrefix, GuardPostfix;
diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp
deleted file mode 100644
index 5981afde0e7e..000000000000
--- a/utils/TableGen/InstrEnumEmitter.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//===- InstrEnumEmitter.cpp - Generate Instruction Set Enums --------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This tablegen backend is responsible for emitting enums for each machine
-// instruction.
-//
-//===----------------------------------------------------------------------===//
-
-#include "InstrEnumEmitter.h"
-#include "CodeGenTarget.h"
-#include "llvm/TableGen/Record.h"
-#include <cstdio>
-using namespace llvm;
-
-// runEnums - Print out enum values for all of the instructions.
-void InstrEnumEmitter::run(raw_ostream &OS) {
- EmitSourceFileHeader("Target Instruction Enum Values", OS);
- OS << "namespace llvm {\n\n";
-
- CodeGenTarget Target(Records);
-
- // We must emit the PHI opcode first...
- std::string Namespace = Target.getInstNamespace();
-
- if (Namespace.empty()) {
- fprintf(stderr, "No instructions defined!\n");
- exit(1);
- }
-
- const std::vector<const CodeGenInstruction*> &NumberedInstructions =
- Target.getInstructionsByEnumValue();
-
- OS << "namespace " << Namespace << " {\n";
- OS << " enum {\n";
- for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
- OS << " " << NumberedInstructions[i]->TheDef->getName()
- << "\t= " << i << ",\n";
- }
- OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n";
- OS << " };\n}\n";
- OS << "} // End llvm namespace \n";
-}
diff --git a/utils/TableGen/InstrEnumEmitter.h b/utils/TableGen/InstrEnumEmitter.h
deleted file mode 100644
index c29a30938d34..000000000000
--- a/utils/TableGen/InstrEnumEmitter.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//===- InstrEnumEmitter.h - Generate Instruction Set Enums ------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This tablegen backend is responsible for emitting enums for each machine
-// instruction.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef INSTRENUM_EMITTER_H
-#define INSTRENUM_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-
-namespace llvm {
-
-class InstrEnumEmitter : public TableGenBackend {
- RecordKeeper &Records;
-public:
- InstrEnumEmitter(RecordKeeper &R) : Records(R) {}
-
- // run - Output the instruction set description, returning true on failure.
- void run(raw_ostream &OS);
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index 8341724a73e4..8b3efd33f4dc 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -14,14 +14,16 @@
#include "InstrInfoEmitter.h"
#include "CodeGenTarget.h"
+#include "SequenceToOffsetTable.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
+#include <cstdio>
using namespace llvm;
static void PrintDefList(const std::vector<Record*> &Uses,
unsigned Num, raw_ostream &OS) {
- OS << "static const unsigned ImplicitList" << Num << "[] = { ";
+ OS << "static const uint16_t ImplicitList" << Num << "[] = { ";
for (unsigned i = 0, e = Uses.size(); i != e; ++i)
OS << getQualifiedName(Uses[i]) << ", ";
OS << "0 };\n";
@@ -106,6 +108,11 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
if (Inst.Operands[i].Rec->isSubClassOf("OptionalDefOperand"))
Res += "|(1<<MCOI::OptionalDef)";
+ // Fill in operand type.
+ Res += ", MCOI::";
+ assert(!Inst.Operands[i].OperandType.empty() && "Invalid operand type.");
+ Res += Inst.Operands[i].OperandType;
+
// Fill in constraint info.
Res += ", ";
@@ -121,11 +128,6 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
" << 16) | (1 << MCOI::TIED_TO))";
}
- // Fill in operand type.
- Res += ", MCOI::";
- assert(!Inst.Operands[i].OperandType.empty() && "Invalid operand type.");
- Res += Inst.Operands[i].OperandType;
-
Result.push_back(Res);
}
}
@@ -203,7 +205,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
// Emit all of the MCInstrDesc records in their ENUM ordering.
//
- OS << "\nMCInstrDesc " << TargetName << "Insts[] = {\n";
+ OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";
const std::vector<const CodeGenInstruction*> &NumberedInstructions =
Target.getInstructionsByEnumValue();
@@ -212,10 +214,33 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OperandInfoIDs, OS);
OS << "};\n\n";
+ // Build an array of instruction names
+ SequenceToOffsetTable<std::string> InstrNames;
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ const CodeGenInstruction *Instr = NumberedInstructions[i];
+ InstrNames.add(Instr->TheDef->getName());
+ }
+
+ InstrNames.layout();
+ OS << "extern const char " << TargetName << "InstrNameData[] = {\n";
+ InstrNames.emit(OS, printChar);
+ OS << "};\n\n";
+
+ OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {";
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ if (i % 8 == 0)
+ OS << "\n ";
+ const CodeGenInstruction *Instr = NumberedInstructions[i];
+ OS << InstrNames.get(Instr->TheDef->getName()) << "U, ";
+ }
+
+ OS << "\n};\n\n";
+
// MCInstrInfo initialization routine.
OS << "static inline void Init" << TargetName
<< "MCInstrInfo(MCInstrInfo *II) {\n";
OS << " II->InitMCInstrInfo(" << TargetName << "Insts, "
+ << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n\n";
OS << "} // End llvm namespace \n";
@@ -239,10 +264,13 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "#undef GET_INSTRINFO_CTOR\n";
OS << "namespace llvm {\n";
- OS << "extern MCInstrDesc " << TargetName << "Insts[];\n";
+ OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n";
+ OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
+ OS << "extern const char " << TargetName << "InstrNameData[];\n";
OS << ClassName << "::" << ClassName << "(int SO, int DO)\n"
<< " : TargetInstrInfoImpl(SO, DO) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, "
+ << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n";
OS << "} // End llvm namespace \n";
@@ -264,8 +292,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
OS << Num << ",\t" << MinOperands << ",\t"
<< Inst.Operands.NumDefs << ",\t"
<< getItinClassNumber(Inst.TheDef) << ",\t"
- << Inst.TheDef->getValueAsInt("Size") << ",\t\""
- << Inst.TheDef->getName() << "\", 0";
+ << Inst.TheDef->getValueAsInt("Size") << ",\t0";
// Emit all of the target indepedent flags...
if (Inst.isPseudo) OS << "|(1<<MCID::Pseudo)";
@@ -346,7 +373,7 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
// We must emit the PHI opcode first...
std::string Namespace = Target.getInstNamespace();
-
+
if (Namespace.empty()) {
fprintf(stderr, "No instructions defined!\n");
exit(1);
diff --git a/utils/TableGen/InstrInfoEmitter.h b/utils/TableGen/InstrInfoEmitter.h
index 1461e2c5f7cf..f8d3ea51c814 100644
--- a/utils/TableGen/InstrInfoEmitter.h
+++ b/utils/TableGen/InstrInfoEmitter.h
@@ -31,19 +31,19 @@ class InstrInfoEmitter : public TableGenBackend {
RecordKeeper &Records;
CodeGenDAGPatterns CDP;
std::map<std::string, unsigned> ItinClassMap;
-
+
public:
InstrInfoEmitter(RecordKeeper &R) : Records(R), CDP(R) { }
- // run - Output the instruction set description, returning true on failure.
+ // run - Output the instruction set description.
void run(raw_ostream &OS);
private:
void emitEnums(raw_ostream &OS);
- typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
+ typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
- Record *InstrInfo,
+ Record *InstrInfo,
std::map<std::vector<Record*>, unsigned> &EL,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS);
@@ -51,7 +51,7 @@ private:
// Itinerary information.
void GatherItinClasses();
unsigned getItinClassNumber(const Record *InstRec);
-
+
// Operand information.
void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index 782b89ede2e7..8e1bae8c1f0f 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -57,9 +57,6 @@ void IntrinsicEmitter::run(raw_ostream &OS) {
// Emit intrinsic alias analysis mod/ref behavior.
EmitModRefBehavior(Ints, OS);
- // Emit a list of intrinsics with corresponding GCC builtins.
- EmitGCCBuiltinList(Ints, OS);
-
// Emit code to translate GCC builtins into LLVM intrinsics.
EmitIntrinsicToGCCBuiltinMap(Ints, OS);
@@ -160,17 +157,20 @@ EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
void IntrinsicEmitter::
EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
- OS << "// Intrinsic ID to overload table\n";
+ OS << "// Intrinsic ID to overload bitset\n";
OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n";
- OS << " // Note that entry #0 is the invalid intrinsic!\n";
+ OS << "static const uint8_t OTable[] = {\n";
+ OS << " 0";
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
- OS << " ";
+ // Add one to the index so we emit a null bit for the invalid #0 intrinsic.
+ if ((i+1)%8 == 0)
+ OS << ",\n 0";
if (Ints[i].isOverloaded)
- OS << "true";
- else
- OS << "false";
- OS << ",\n";
+ OS << " | (1<<" << (i+1)%8 << ')';
}
+ OS << "\n};\n\n";
+ // OTable contains a true bit at the position if the intrinsic is overloaded.
+ OS << "return (OTable[id/8] & (1 << (id%8))) != 0;\n";
OS << "#endif\n\n";
}
@@ -181,6 +181,8 @@ static void EmitTypeForValueType(raw_ostream &OS, MVT::SimpleValueType VT) {
} else if (VT == MVT::Other) {
// MVT::OtherVT is used to mean the empty struct type here.
OS << "StructType::get(Context)";
+ } else if (VT == MVT::f16) {
+ OS << "Type::getHalfTy(Context)";
} else if (VT == MVT::f32) {
OS << "Type::getFloatTy(Context)";
} else if (VT == MVT::f64) {
@@ -318,7 +320,7 @@ void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
OS << "// Verifier::visitIntrinsicFunctionCall code.\n";
OS << "#ifdef GET_INTRINSIC_VERIFIER\n";
OS << " switch (ID) {\n";
- OS << " default: assert(0 && \"Invalid intrinsic!\");\n";
+ OS << " default: llvm_unreachable(\"Invalid intrinsic!\");\n";
// This checking can emit a lot of very common code. To reduce the amount of
// code that we emit, batch up cases that have identical types. This avoids
@@ -414,7 +416,7 @@ void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
OS << "// Code for generating Intrinsic function declarations.\n";
OS << "#ifdef GET_INTRINSIC_GENERATOR\n";
OS << " switch (id) {\n";
- OS << " default: assert(0 && \"Invalid intrinsic!\");\n";
+ OS << " default: llvm_unreachable(\"Invalid intrinsic!\");\n";
// Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical
// types.
@@ -483,8 +485,7 @@ namespace {
case CodeGenIntrinsic::ReadWriteMem:
return MRK_none;
}
- assert(0 && "bad mod-ref kind");
- return MRK_none;
+ llvm_unreachable("bad mod-ref kind");
}
struct AttributeComparator {
@@ -516,37 +517,50 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
else
OS << "AttrListPtr Intrinsic::getAttributes(ID id) {\n";
- // Compute the maximum number of attribute arguments.
- std::vector<const CodeGenIntrinsic*> sortedIntrinsics(Ints.size());
+ // Compute the maximum number of attribute arguments and the map
+ typedef std::map<const CodeGenIntrinsic*, unsigned,
+ AttributeComparator> UniqAttrMapTy;
+ UniqAttrMapTy UniqAttributes;
unsigned maxArgAttrs = 0;
+ unsigned AttrNum = 0;
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
const CodeGenIntrinsic &intrinsic = Ints[i];
- sortedIntrinsics[i] = &intrinsic;
maxArgAttrs =
std::max(maxArgAttrs, unsigned(intrinsic.ArgumentAttributes.size()));
+ unsigned &N = UniqAttributes[&intrinsic];
+ if (N) continue;
+ assert(AttrNum < 256 && "Too many unique attributes for table!");
+ N = ++AttrNum;
}
// Emit an array of AttributeWithIndex. Most intrinsics will have
// at least one entry, for the function itself (index ~1), which is
// usually nounwind.
- OS << " AttributeWithIndex AWI[" << maxArgAttrs+1 << "];\n";
- OS << " unsigned NumAttrs = 0;\n";
- OS << " switch (id) {\n";
- OS << " default: break;\n";
+ OS << " static const uint8_t IntrinsicsToAttributesMap[] = {\n";
- AttributeComparator precedes;
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ const CodeGenIntrinsic &intrinsic = Ints[i];
- std::stable_sort(sortedIntrinsics.begin(), sortedIntrinsics.end(), precedes);
+ OS << " " << UniqAttributes[&intrinsic] << ", // "
+ << intrinsic.Name << "\n";
+ }
+ OS << " };\n\n";
- for (unsigned i = 0, e = sortedIntrinsics.size(); i != e; ++i) {
- const CodeGenIntrinsic &intrinsic = *sortedIntrinsics[i];
- OS << " case " << TargetPrefix << "Intrinsic::"
- << intrinsic.EnumName << ":\n";
+ OS << " AttributeWithIndex AWI[" << maxArgAttrs+1 << "];\n";
+ OS << " unsigned NumAttrs = 0;\n";
+ OS << " if (id != 0) {\n";
+ OS << " switch(IntrinsicsToAttributesMap[id - ";
+ if (TargetOnly)
+ OS << "Intrinsic::num_intrinsics";
+ else
+ OS << "1";
+ OS << "]) {\n";
+ OS << " default: llvm_unreachable(\"Invalid attribute number\");\n";
+ for (UniqAttrMapTy::const_iterator I = UniqAttributes.begin(),
+ E = UniqAttributes.end(); I != E; ++I) {
+ OS << " case " << I->second << ":\n";
- // Fill out the case if this is the last case for this range of
- // intrinsics.
- if (i + 1 != e && !precedes(&intrinsic, sortedIntrinsics[i + 1]))
- continue;
+ const CodeGenIntrinsic &intrinsic = *(I->first);
// Keep track of the number of attributes we're writing out.
unsigned numAttrs = 0;
@@ -554,8 +568,8 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
// The argument attributes are alreadys sorted by argument index.
for (unsigned ai = 0, ae = intrinsic.ArgumentAttributes.size(); ai != ae;) {
unsigned argNo = intrinsic.ArgumentAttributes[ai].first;
-
- OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get("
+
+ OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get("
<< argNo+1 << ", ";
bool moreThanOne = false;
@@ -579,7 +593,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
ModRefKind modRef = getModRefKind(intrinsic);
if (!intrinsic.canThrow || modRef) {
- OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(~0, ";
+ OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(~0, ";
if (!intrinsic.canThrow) {
OS << "Attribute::NoUnwind";
if (modRef) OS << '|';
@@ -593,13 +607,14 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
}
if (numAttrs) {
- OS << " NumAttrs = " << numAttrs << ";\n";
- OS << " break;\n";
+ OS << " NumAttrs = " << numAttrs << ";\n";
+ OS << " break;\n";
} else {
- OS << " return AttrListPtr();\n";
+ OS << " return AttrListPtr();\n";
}
}
+ OS << " }\n";
OS << " }\n";
OS << " return AttrListPtr::get(AWI, NumAttrs);\n";
OS << "}\n";
@@ -609,50 +624,36 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
/// EmitModRefBehavior - Determine intrinsic alias analysis mod/ref behavior.
void IntrinsicEmitter::
EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
- OS << "// Determine intrinsic alias analysis mod/ref behavior.\n";
- OS << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n";
- OS << "switch (iid) {\n";
- OS << "default:\n return UnknownModRefBehavior;\n";
+ OS << "// Determine intrinsic alias analysis mod/ref behavior.\n"
+ << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n"
+ << "assert(iid <= Intrinsic::" << Ints.back().EnumName << " && "
+ << "\"Unknown intrinsic.\");\n\n";
+
+ OS << "static const uint8_t IntrinsicModRefBehavior[] = {\n"
+ << " /* invalid */ UnknownModRefBehavior,\n";
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
- if (Ints[i].ModRef == CodeGenIntrinsic::ReadWriteMem)
- continue;
- OS << "case " << TargetPrefix << "Intrinsic::" << Ints[i].EnumName
- << ":\n";
+ OS << " /* " << TargetPrefix << Ints[i].EnumName << " */ ";
switch (Ints[i].ModRef) {
- default:
- assert(false && "Unknown Mod/Ref type!");
case CodeGenIntrinsic::NoMem:
- OS << " return DoesNotAccessMemory;\n";
+ OS << "DoesNotAccessMemory,\n";
break;
case CodeGenIntrinsic::ReadArgMem:
- OS << " return OnlyReadsArgumentPointees;\n";
+ OS << "OnlyReadsArgumentPointees,\n";
break;
case CodeGenIntrinsic::ReadMem:
- OS << " return OnlyReadsMemory;\n";
+ OS << "OnlyReadsMemory,\n";
break;
case CodeGenIntrinsic::ReadWriteArgMem:
- OS << " return OnlyAccessesArgumentPointees;\n";
+ OS << "OnlyAccessesArgumentPointees,\n";
+ break;
+ case CodeGenIntrinsic::ReadWriteMem:
+ OS << "UnknownModRefBehavior,\n";
break;
}
}
- OS << "}\n";
- OS << "#endif // GET_INTRINSIC_MODREF_BEHAVIOR\n\n";
-}
-
-void IntrinsicEmitter::
-EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
- OS << "// Get the GCC builtin that corresponds to an LLVM intrinsic.\n";
- OS << "#ifdef GET_GCC_BUILTIN_NAME\n";
- OS << " switch (F->getIntrinsicID()) {\n";
- OS << " default: BuiltinName = \"\"; break;\n";
- for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
- if (!Ints[i].GCCBuiltinName.empty()) {
- OS << " case Intrinsic::" << Ints[i].EnumName << ": BuiltinName = \""
- << Ints[i].GCCBuiltinName << "\"; break;\n";
- }
- }
- OS << " }\n";
- OS << "#endif\n\n";
+ OS << "};\n\n"
+ << "return static_cast<ModRefBehavior>(IntrinsicModRefBehavior[iid]);\n"
+ << "#endif // GET_INTRINSIC_MODREF_BEHAVIOR\n\n";
}
/// EmitTargetBuiltins - All of the builtins in the specified map are for the
diff --git a/utils/TableGen/IntrinsicEmitter.h b/utils/TableGen/IntrinsicEmitter.h
index eb6379cc7414..f9bcd5980226 100644
--- a/utils/TableGen/IntrinsicEmitter.h
+++ b/utils/TableGen/IntrinsicEmitter.h
@@ -48,8 +48,6 @@ namespace llvm {
raw_ostream &OS);
void EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS);
- void EmitGCCBuiltinList(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS);
void EmitSuffix(raw_ostream &OS);
diff --git a/utils/TableGen/LLVMBuild.txt b/utils/TableGen/LLVMBuild.txt
new file mode 100644
index 000000000000..b0081eb588d1
--- /dev/null
+++ b/utils/TableGen/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./utils/TableGen/LLVMBuild.txt ---------------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = BuildTool
+name = tblgen
+parent = BuildTools
+required_libraries = Support TableGen
diff --git a/utils/TableGen/PseudoLoweringEmitter.cpp b/utils/TableGen/PseudoLoweringEmitter.cpp
index c685527a140c..802d112108fa 100644
--- a/utils/TableGen/PseudoLoweringEmitter.cpp
+++ b/utils/TableGen/PseudoLoweringEmitter.cpp
@@ -67,7 +67,7 @@ addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,
// Since we added more than one, we also need to adjust the base.
BaseIdx += NewOps - 1;
} else
- assert(0 && "Unhandled pseudo-expansion argument type!");
+ llvm_unreachable("Unhandled pseudo-expansion argument type!");
}
return OpsAdded;
}
@@ -100,8 +100,11 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
throw TGError(Rec->getLoc(), "Pseudo result '" + Operator->getName() +
"' operand count mismatch");
+ unsigned NumMIOperands = 0;
+ for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i)
+ NumMIOperands += Insn.Operands[i].MINumOperands;
IndexedMap<OpData> OperandMap;
- OperandMap.grow(Insn.Operands.size());
+ OperandMap.grow(NumMIOperands);
addDagOperandMapping(Rec, Dag, Insn, OperandMap, 0);
@@ -176,8 +179,6 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
for (unsigned i = 0, e = Dest.Operands[OpNo].MINumOperands;
i != e; ++i) {
switch (Expansion.OperandMap[MIOpNo + i].Kind) {
- default:
- llvm_unreachable("Unknown operand type?!");
case OpData::Operand:
o << " lowerOperand(MI->getOperand("
<< Source.Operands[Expansion.OperandMap[MIOpNo].Data
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index b0f4ffc84e08..a2478a7330e8 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -16,6 +16,7 @@
#include "RegisterInfoEmitter.h"
#include "CodeGenTarget.h"
#include "CodeGenRegisters.h"
+#include "SequenceToOffsetTable.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -31,6 +32,9 @@ RegisterInfoEmitter::runEnums(raw_ostream &OS,
CodeGenTarget &Target, CodeGenRegBank &Bank) {
const std::vector<CodeGenRegister*> &Registers = Bank.getRegisters();
+ // Register enums are stored as uint16_t in the tables. Make sure we'll fit
+ assert(Registers.size() <= 0xffff && "Too many regs to fit in tables");
+
std::string Namespace = Registers[0]->TheDef->getValueAsString("Namespace");
EmitSourceFileHeader("Target Register Enum Values", OS);
@@ -41,7 +45,8 @@ RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << "namespace llvm {\n\n";
OS << "class MCRegisterClass;\n"
- << "extern MCRegisterClass " << Namespace << "MCRegisterClasses[];\n\n";
+ << "extern const MCRegisterClass " << Namespace
+ << "MCRegisterClasses[];\n\n";
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
@@ -59,6 +64,11 @@ RegisterInfoEmitter::runEnums(raw_ostream &OS,
ArrayRef<CodeGenRegisterClass*> RegisterClasses = Bank.getRegClasses();
if (!RegisterClasses.empty()) {
+
+ // RegisterClass enums are stored as uint16_t in the tables.
+ assert(RegisterClasses.size() <= 0xffff &&
+ "Too many register classes to fit in tables");
+
OS << "\n// Register classes\n";
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
@@ -89,16 +99,104 @@ RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << "}\n";
}
+ ArrayRef<CodeGenSubRegIndex*> SubRegIndices = Bank.getSubRegIndices();
+ if (!SubRegIndices.empty()) {
+ OS << "\n// Subregister indices\n";
+ std::string Namespace =
+ SubRegIndices[0]->getNamespace();
+ if (!Namespace.empty())
+ OS << "namespace " << Namespace << " {\n";
+ OS << "enum {\n NoSubRegister,\n";
+ for (unsigned i = 0, e = Bank.getNumNamedIndices(); i != e; ++i)
+ OS << " " << SubRegIndices[i]->getName() << ",\t// " << i+1 << "\n";
+ OS << " NUM_TARGET_NAMED_SUBREGS\n};\n";
+ if (!Namespace.empty())
+ OS << "}\n";
+ }
OS << "} // End llvm namespace \n";
OS << "#endif // GET_REGINFO_ENUM\n\n";
}
-void
-RegisterInfoEmitter::EmitRegMapping(raw_ostream &OS,
- const std::vector<CodeGenRegister*> &Regs,
- bool isCtor) {
+void RegisterInfoEmitter::
+EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
+ const std::string &ClassName) {
+ unsigned NumRCs = RegBank.getRegClasses().size();
+ unsigned NumSets = RegBank.getNumRegPressureSets();
+
+ OS << "/// Get the weight in units of pressure for this register class.\n"
+ << "const RegClassWeight &" << ClassName << "::\n"
+ << "getRegClassWeight(const TargetRegisterClass *RC) const {\n"
+ << " static const RegClassWeight RCWeightTable[] = {\n";
+ for (unsigned i = 0, e = NumRCs; i != e; ++i) {
+ const CodeGenRegisterClass &RC = *RegBank.getRegClasses()[i];
+ const CodeGenRegister::Set &Regs = RC.getMembers();
+ if (Regs.empty())
+ OS << " {0, 0";
+ else {
+ std::vector<unsigned> RegUnits;
+ RC.buildRegUnitSet(RegUnits);
+ OS << " {" << (*Regs.begin())->getWeight(RegBank)
+ << ", " << RegBank.getRegUnitSetWeight(RegUnits);
+ }
+ OS << "}, \t// " << RC.getName() << "\n";
+ }
+ OS << " {0, 0} };\n"
+ << " return RCWeightTable[RC->getID()];\n"
+ << "}\n\n";
+
+ OS << "\n"
+ << "// Get the number of dimensions of register pressure.\n"
+ << "unsigned " << ClassName << "::getNumRegPressureSets() const {\n"
+ << " return " << NumSets << ";\n}\n\n";
+
+ OS << "// Get the register unit pressure limit for this dimension.\n"
+ << "// This limit must be adjusted dynamically for reserved registers.\n"
+ << "unsigned " << ClassName << "::\n"
+ << "getRegPressureSetLimit(unsigned Idx) const {\n"
+ << " static const unsigned PressureLimitTable[] = {\n";
+ for (unsigned i = 0; i < NumSets; ++i ) {
+ const RegUnitSet &RegUnits = RegBank.getRegPressureSet(i);
+ OS << " " << RegBank.getRegUnitSetWeight(RegUnits.Units)
+ << ", \t// " << i << ": " << RegBank.getRegPressureSet(i).Name << "\n";
+ }
+ OS << " 0 };\n"
+ << " return PressureLimitTable[Idx];\n"
+ << "}\n\n";
+
+ OS << "/// Get the dimensions of register pressure "
+ << "impacted by this register class.\n"
+ << "/// Returns a -1 terminated array of pressure set IDs\n"
+ << "const int* " << ClassName << "::\n"
+ << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n"
+ << " static const int RCSetsTable[] = {\n ";
+ std::vector<unsigned> RCSetStarts(NumRCs);
+ for (unsigned i = 0, StartIdx = 0, e = NumRCs; i != e; ++i) {
+ RCSetStarts[i] = StartIdx;
+ ArrayRef<unsigned> PSetIDs = RegBank.getRCPressureSetIDs(i);
+ for (ArrayRef<unsigned>::iterator PSetI = PSetIDs.begin(),
+ PSetE = PSetIDs.end(); PSetI != PSetE; ++PSetI) {
+ OS << *PSetI << ", ";
+ ++StartIdx;
+ }
+ OS << "-1, \t// " << RegBank.getRegClasses()[i]->getName() << "\n ";
+ ++StartIdx;
+ }
+ OS << "-1 };\n";
+ OS << " static const unsigned RCSetStartTable[] = {\n ";
+ for (unsigned i = 0, e = NumRCs; i != e; ++i) {
+ OS << RCSetStarts[i] << ",";
+ }
+ OS << "0 };\n"
+ << " unsigned SetListStart = RCSetStartTable[RC->getID()];\n"
+ << " return &RCSetsTable[SetListStart];\n"
+ << "}\n\n";
+}
+void
+RegisterInfoEmitter::EmitRegMappingTables(raw_ostream &OS,
+ const std::vector<CodeGenRegister*> &Regs,
+ bool isCtor) {
// Collect all information about dwarf register numbers
typedef std::map<Record*, std::vector<int64_t>, LessRecord> DwarfRegNumsMapTy;
DwarfRegNumsMapTy DwarfRegNums;
@@ -124,6 +222,121 @@ RegisterInfoEmitter::EmitRegMapping(raw_ostream &OS,
for (unsigned i = I->second.size(), e = maxLength; i != e; ++i)
I->second.push_back(-1);
+ std::string Namespace = Regs[0]->TheDef->getValueAsString("Namespace");
+
+ OS << "// " << Namespace << " Dwarf<->LLVM register mappings.\n";
+
+ // Emit reverse information about the dwarf register numbers.
+ for (unsigned j = 0; j < 2; ++j) {
+ for (unsigned i = 0, e = maxLength; i != e; ++i) {
+ OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace;
+ OS << (j == 0 ? "DwarfFlavour" : "EHFlavour");
+ OS << i << "Dwarf2L[]";
+
+ if (!isCtor) {
+ OS << " = {\n";
+
+ // Store the mapping sorted by the LLVM reg num so lookup can be done
+ // with a binary search.
+ std::map<uint64_t, Record*> Dwarf2LMap;
+ for (DwarfRegNumsMapTy::iterator
+ I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) {
+ int DwarfRegNo = I->second[i];
+ if (DwarfRegNo < 0)
+ continue;
+ Dwarf2LMap[DwarfRegNo] = I->first;
+ }
+
+ for (std::map<uint64_t, Record*>::iterator
+ I = Dwarf2LMap.begin(), E = Dwarf2LMap.end(); I != E; ++I)
+ OS << " { " << I->first << "U, " << getQualifiedName(I->second)
+ << " },\n";
+
+ OS << "};\n";
+ } else {
+ OS << ";\n";
+ }
+
+ // We have to store the size in a const global, it's used in multiple
+ // places.
+ OS << "extern const unsigned " << Namespace
+ << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "Dwarf2LSize";
+ if (!isCtor)
+ OS << " = sizeof(" << Namespace
+ << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
+ << "Dwarf2L)/sizeof(MCRegisterInfo::DwarfLLVMRegPair);\n\n";
+ else
+ OS << ";\n\n";
+ }
+ }
+
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record *Reg = Regs[i]->TheDef;
+ const RecordVal *V = Reg->getValue("DwarfAlias");
+ if (!V || !V->getValue())
+ continue;
+
+ DefInit *DI = dynamic_cast<DefInit*>(V->getValue());
+ Record *Alias = DI->getDef();
+ DwarfRegNums[Reg] = DwarfRegNums[Alias];
+ }
+
+ // Emit information about the dwarf register numbers.
+ for (unsigned j = 0; j < 2; ++j) {
+ for (unsigned i = 0, e = maxLength; i != e; ++i) {
+ OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace;
+ OS << (j == 0 ? "DwarfFlavour" : "EHFlavour");
+ OS << i << "L2Dwarf[]";
+ if (!isCtor) {
+ OS << " = {\n";
+ // Store the mapping sorted by the Dwarf reg num so lookup can be done
+ // with a binary search.
+ for (DwarfRegNumsMapTy::iterator
+ I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) {
+ int RegNo = I->second[i];
+ if (RegNo == -1) // -1 is the default value, don't emit a mapping.
+ continue;
+
+ OS << " { " << getQualifiedName(I->first) << ", " << RegNo
+ << "U },\n";
+ }
+ OS << "};\n";
+ } else {
+ OS << ";\n";
+ }
+
+ // We have to store the size in a const global, it's used in multiple
+ // places.
+ OS << "extern const unsigned " << Namespace
+ << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2DwarfSize";
+ if (!isCtor)
+ OS << " = sizeof(" << Namespace
+ << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
+ << "L2Dwarf)/sizeof(MCRegisterInfo::DwarfLLVMRegPair);\n\n";
+ else
+ OS << ";\n\n";
+ }
+ }
+}
+
+void
+RegisterInfoEmitter::EmitRegMapping(raw_ostream &OS,
+ const std::vector<CodeGenRegister*> &Regs,
+ bool isCtor) {
+ // Emit the initializer so the tables from EmitRegMappingTables get wired up
+ // to the MCRegisterInfo object.
+ unsigned maxLength = 0;
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record *Reg = Regs[i]->TheDef;
+ maxLength = std::max((size_t)maxLength,
+ Reg->getValueAsListOfInts("DwarfNumbers").size());
+ }
+
+ if (!maxLength)
+ return;
+
+ std::string Namespace = Regs[0]->TheDef->getValueAsString("Namespace");
+
// Emit reverse information about the dwarf register numbers.
for (unsigned j = 0; j < 2; ++j) {
OS << " switch (";
@@ -133,43 +346,28 @@ RegisterInfoEmitter::EmitRegMapping(raw_ostream &OS,
OS << "EHFlavour";
OS << ") {\n"
<< " default:\n"
- << " assert(0 && \"Unknown DWARF flavour\");\n"
- << " break;\n";
+ << " llvm_unreachable(\"Unknown DWARF flavour\");\n";
for (unsigned i = 0, e = maxLength; i != e; ++i) {
OS << " case " << i << ":\n";
- for (DwarfRegNumsMapTy::iterator
- I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) {
- int DwarfRegNo = I->second[i];
- if (DwarfRegNo < 0)
- continue;
- OS << " ";
- if (!isCtor)
- OS << "RI->";
- OS << "mapDwarfRegToLLVMReg(" << DwarfRegNo << ", "
- << getQualifiedName(I->first) << ", ";
- if (j == 0)
+ OS << " ";
+ if (!isCtor)
+ OS << "RI->";
+ std::string Tmp;
+ raw_string_ostream(Tmp) << Namespace
+ << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
+ << "Dwarf2L";
+ OS << "mapDwarfRegsToLLVMRegs(" << Tmp << ", " << Tmp << "Size, ";
+ if (j == 0)
OS << "false";
else
OS << "true";
- OS << " );\n";
- }
+ OS << ");\n";
OS << " break;\n";
}
OS << " }\n";
}
- for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- Record *Reg = Regs[i]->TheDef;
- const RecordVal *V = Reg->getValue("DwarfAlias");
- if (!V || !V->getValue())
- continue;
-
- DefInit *DI = dynamic_cast<DefInit*>(V->getValue());
- Record *Alias = DI->getDef();
- DwarfRegNums[Reg] = DwarfRegNums[Alias];
- }
-
// Emit information about the dwarf register numbers.
for (unsigned j = 0; j < 2; ++j) {
OS << " switch (";
@@ -179,26 +377,23 @@ RegisterInfoEmitter::EmitRegMapping(raw_ostream &OS,
OS << "EHFlavour";
OS << ") {\n"
<< " default:\n"
- << " assert(0 && \"Unknown DWARF flavour\");\n"
- << " break;\n";
+ << " llvm_unreachable(\"Unknown DWARF flavour\");\n";
for (unsigned i = 0, e = maxLength; i != e; ++i) {
OS << " case " << i << ":\n";
- // Sort by name to get a stable order.
- for (DwarfRegNumsMapTy::iterator
- I = DwarfRegNums.begin(), E = DwarfRegNums.end(); I != E; ++I) {
- int RegNo = I->second[i];
- OS << " ";
- if (!isCtor)
- OS << "RI->";
- OS << "mapLLVMRegToDwarfReg(" << getQualifiedName(I->first) << ", "
- << RegNo << ", ";
- if (j == 0)
+ OS << " ";
+ if (!isCtor)
+ OS << "RI->";
+ std::string Tmp;
+ raw_string_ostream(Tmp) << Namespace
+ << (j == 0 ? "DwarfFlavour" : "EHFlavour") << i
+ << "L2Dwarf";
+ OS << "mapLLVMRegsToDwarfRegs(" << Tmp << ", " << Tmp << "Size, ";
+ if (j == 0)
OS << "false";
else
OS << "true";
- OS << " );\n";
- }
+ OS << ");\n";
OS << " break;\n";
}
OS << " }\n";
@@ -235,6 +430,14 @@ public:
}
};
+static void printRegister(raw_ostream &OS, const CodeGenRegister *Reg) {
+ OS << getQualifiedName(Reg->TheDef);
+}
+
+static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) {
+ OS << getEnumName(VT);
+}
+
//
// runMCDesc - Print out MC register descriptions.
//
@@ -246,87 +449,79 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "\n#ifdef GET_REGINFO_MC_DESC\n";
OS << "#undef GET_REGINFO_MC_DESC\n";
+ const std::vector<CodeGenRegister*> &Regs = RegBank.getRegisters();
std::map<const CodeGenRegister*, CodeGenRegister::Set> Overlaps;
RegBank.computeOverlaps(Overlaps);
- OS << "namespace llvm {\n\n";
-
- const std::string &TargetName = Target.getName();
- std::string ClassName = TargetName + "GenMCRegisterInfo";
- OS << "struct " << ClassName << " : public MCRegisterInfo {\n"
- << " explicit " << ClassName << "(const MCRegisterDesc *D);\n";
- OS << "};\n";
+ // The lists of sub-registers, super-registers, and overlaps all go in the
+ // same array. That allows us to share suffixes.
+ typedef std::vector<const CodeGenRegister*> RegVec;
+ SmallVector<RegVec, 4> SubRegLists(Regs.size());
+ SmallVector<RegVec, 4> OverlapLists(Regs.size());
+ SequenceToOffsetTable<RegVec, CodeGenRegister::Less> RegSeqs;
- OS << "\nnamespace {\n";
-
- const std::vector<CodeGenRegister*> &Regs = RegBank.getRegisters();
-
- // Emit an overlap list for all registers.
+ // Precompute register lists for the SequenceToOffsetTable.
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
const CodeGenRegister *Reg = Regs[i];
- const CodeGenRegister::Set &O = Overlaps[Reg];
- // Move Reg to the front so TRI::getAliasSet can share the list.
- OS << " const unsigned " << Reg->getName() << "_Overlaps[] = { "
- << getQualifiedName(Reg->TheDef) << ", ";
- for (CodeGenRegister::Set::const_iterator I = O.begin(), E = O.end();
- I != E; ++I)
- if (*I != Reg)
- OS << getQualifiedName((*I)->TheDef) << ", ";
- OS << "0 };\n";
- }
- // Emit the empty sub-registers list
- OS << " const unsigned Empty_SubRegsSet[] = { 0 };\n";
- // Loop over all of the registers which have sub-registers, emitting the
- // sub-registers list to memory.
- for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- const CodeGenRegister &Reg = *Regs[i];
- if (Reg.getSubRegs().empty())
- continue;
- // getSubRegs() orders by SubRegIndex. We want a topological order.
- SetVector<CodeGenRegister*> SR;
- Reg.addSubRegsPreOrder(SR);
- OS << " const unsigned " << Reg.getName() << "_SubRegsSet[] = { ";
- for (unsigned j = 0, je = SR.size(); j != je; ++j)
- OS << getQualifiedName(SR[j]->TheDef) << ", ";
- OS << "0 };\n";
+ // Compute the ordered sub-register list.
+ SetVector<const CodeGenRegister*> SR;
+ Reg->addSubRegsPreOrder(SR, RegBank);
+ RegVec &SubRegList = SubRegLists[i];
+ SubRegList.assign(SR.begin(), SR.end());
+ RegSeqs.add(SubRegList);
+
+ // Super-registers are already computed.
+ const RegVec &SuperRegList = Reg->getSuperRegs();
+ RegSeqs.add(SuperRegList);
+
+ // The list of overlaps doesn't need to have any particular order, except
+ // Reg itself must be the first element. Pick an ordering that has one of
+ // the other lists as a suffix.
+ RegVec &OverlapList = OverlapLists[i];
+ const RegVec &Suffix = SubRegList.size() > SuperRegList.size() ?
+ SubRegList : SuperRegList;
+ CodeGenRegister::Set Omit(Suffix.begin(), Suffix.end());
+
+ // First element is Reg itself.
+ OverlapList.push_back(Reg);
+ Omit.insert(Reg);
+
+ // Any elements not in Suffix.
+ const CodeGenRegister::Set &OSet = Overlaps[Reg];
+ std::set_difference(OSet.begin(), OSet.end(),
+ Omit.begin(), Omit.end(),
+ std::back_inserter(OverlapList),
+ CodeGenRegister::Less());
+
+ // Finally, Suffix itself.
+ OverlapList.insert(OverlapList.end(), Suffix.begin(), Suffix.end());
+ RegSeqs.add(OverlapList);
}
- // Emit the empty super-registers list
- OS << " const unsigned Empty_SuperRegsSet[] = { 0 };\n";
- // Loop over all of the registers which have super-registers, emitting the
- // super-registers list to memory.
- for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- const CodeGenRegister &Reg = *Regs[i];
- const CodeGenRegister::SuperRegList &SR = Reg.getSuperRegs();
- if (SR.empty())
- continue;
- OS << " const unsigned " << Reg.getName() << "_SuperRegsSet[] = { ";
- for (unsigned j = 0, je = SR.size(); j != je; ++j)
- OS << getQualifiedName(SR[j]->TheDef) << ", ";
- OS << "0 };\n";
- }
- OS << "}\n"; // End of anonymous namespace...
+ // Compute the final layout of the sequence table.
+ RegSeqs.layout();
- OS << "\nMCRegisterDesc " << TargetName
+ OS << "namespace llvm {\n\n";
+
+ const std::string &TargetName = Target.getName();
+
+ // Emit the shared table of register lists.
+ OS << "extern const uint16_t " << TargetName << "RegLists[] = {\n";
+ RegSeqs.emit(OS, printRegister);
+ OS << "};\n\n";
+
+ OS << "extern const MCRegisterDesc " << TargetName
<< "RegDesc[] = { // Descriptors\n";
- OS << " { \"NOREG\",\t0,\t0,\t0 },\n";
+ OS << " { \"NOREG\", 0, 0, 0 },\n";
- // Now that register alias and sub-registers sets have been emitted, emit the
- // register descriptors now.
+ // Emit the register descriptors now.
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- const CodeGenRegister &Reg = *Regs[i];
- OS << " { \"";
- OS << Reg.getName() << "\",\t" << Reg.getName() << "_Overlaps,\t";
- if (!Reg.getSubRegs().empty())
- OS << Reg.getName() << "_SubRegsSet,\t";
- else
- OS << "Empty_SubRegsSet,\t";
- if (!Reg.getSuperRegs().empty())
- OS << Reg.getName() << "_SuperRegsSet";
- else
- OS << "Empty_SuperRegsSet";
- OS << " },\n";
+ const CodeGenRegister *Reg = Regs[i];
+ OS << " { \"" << Reg->getName() << "\", "
+ << RegSeqs.get(OverlapLists[i]) << ", "
+ << RegSeqs.get(SubRegLists[i]) << ", "
+ << RegSeqs.get(Reg->getSuperRegs()) << " },\n";
}
OS << "};\n\n"; // End of register descriptors...
@@ -345,7 +540,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
// Emit the register list now.
OS << " // " << Name << " Register Class...\n"
- << " static const unsigned " << Name
+ << " const uint16_t " << Name
<< "[] = {\n ";
for (unsigned i = 0, e = Order.size(); i != e; ++i) {
Record *Reg = Order[i];
@@ -354,7 +549,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "\n };\n\n";
OS << " // " << Name << " Bit set.\n"
- << " static const unsigned char " << Name
+ << " const uint8_t " << Name
<< "Bits[] = {\n ";
BitVectorEmitter BVE;
for (unsigned i = 0, e = Order.size(); i != e; ++i) {
@@ -367,37 +562,81 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
}
OS << "}\n\n";
- OS << "MCRegisterClass " << TargetName << "MCRegisterClasses[] = {\n";
+ OS << "extern const MCRegisterClass " << TargetName
+ << "MCRegisterClasses[] = {\n";
for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
const CodeGenRegisterClass &RC = *RegisterClasses[rc];
- OS << " MCRegisterClass(" << RC.getQualifiedName() + "RegClassID" << ", "
- << '\"' << RC.getName() << "\", "
+
+ // Asserts to make sure values will fit in table assuming types from
+ // MCRegisterInfo.h
+ assert((RC.SpillSize/8) <= 0xffff && "SpillSize too large.");
+ assert((RC.SpillAlignment/8) <= 0xffff && "SpillAlignment too large.");
+ assert(RC.CopyCost >= -128 && RC.CopyCost <= 127 && "Copy cost too large.");
+
+ OS << " { " << '\"' << RC.getName() << "\", "
+ << RC.getName() << ", " << RC.getName() << "Bits, "
+ << RC.getOrder().size() << ", sizeof(" << RC.getName() << "Bits), "
+ << RC.getQualifiedName() + "RegClassID" << ", "
<< RC.SpillSize/8 << ", "
<< RC.SpillAlignment/8 << ", "
<< RC.CopyCost << ", "
- << RC.Allocatable << ", "
- << RC.getName() << ", " << RC.getName() << " + "
- << RC.getOrder().size() << ", "
- << RC.getName() << "Bits, sizeof(" << RC.getName() << "Bits)"
- << "),\n";
+ << RC.Allocatable << " },\n";
}
OS << "};\n\n";
+ // Emit the data table for getSubReg().
+ ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices();
+ if (SubRegIndices.size()) {
+ OS << "const uint16_t " << TargetName << "SubRegTable[]["
+ << SubRegIndices.size() << "] = {\n";
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ const CodeGenRegister::SubRegMap &SRM = Regs[i]->getSubRegs();
+ OS << " /* " << Regs[i]->TheDef->getName() << " */\n";
+ if (SRM.empty()) {
+ OS << " {0},\n";
+ continue;
+ }
+ OS << " {";
+ for (unsigned j = 0, je = SubRegIndices.size(); j != je; ++j) {
+ // FIXME: We really should keep this to 80 columns...
+ CodeGenRegister::SubRegMap::const_iterator SubReg =
+ SRM.find(SubRegIndices[j]);
+ if (SubReg != SRM.end())
+ OS << getQualifiedName(SubReg->second->TheDef);
+ else
+ OS << "0";
+ if (j != je - 1)
+ OS << ", ";
+ }
+ OS << "}" << (i != e ? "," : "") << "\n";
+ }
+ OS << "};\n\n";
+ OS << "const uint16_t *get" << TargetName
+ << "SubRegTable() {\n return (const uint16_t *)" << TargetName
+ << "SubRegTable;\n}\n\n";
+ }
+
+ EmitRegMappingTables(OS, Regs, false);
+
// MCRegisterInfo initialization routine.
OS << "static inline void Init" << TargetName
<< "MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, "
<< "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0) {\n";
OS << " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, "
<< Regs.size()+1 << ", RA, " << TargetName << "MCRegisterClasses, "
- << RegisterClasses.size() << ");\n\n";
+ << RegisterClasses.size() << ", " << TargetName << "RegLists, ";
+ if (SubRegIndices.size() != 0)
+ OS << "(uint16_t*)" << TargetName << "SubRegTable, "
+ << SubRegIndices.size() << ");\n\n";
+ else
+ OS << "NULL, 0);\n\n";
EmitRegMapping(OS, Regs, false);
OS << "}\n\n";
-
OS << "} // End llvm namespace \n";
OS << "#endif // GET_REGINFO_MC_DESC\n\n";
}
@@ -413,8 +652,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
const std::string &TargetName = Target.getName();
std::string ClassName = TargetName + "GenRegisterInfo";
- OS << "#include \"llvm/Target/TargetRegisterInfo.h\"\n";
- OS << "#include <string>\n\n";
+ OS << "#include \"llvm/Target/TargetRegisterInfo.h\"\n\n";
OS << "namespace llvm {\n\n";
@@ -423,28 +661,20 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
<< "(unsigned RA, unsigned D = 0, unsigned E = 0);\n"
<< " virtual bool needsStackRealignment(const MachineFunction &) const\n"
<< " { return false; }\n"
- << " unsigned getSubReg(unsigned RegNo, unsigned Index) const;\n"
- << " unsigned getSubRegIndex(unsigned RegNo, unsigned SubRegNo) const;\n"
<< " unsigned composeSubRegIndices(unsigned, unsigned) const;\n"
<< " const TargetRegisterClass *"
"getSubClassWithSubReg(const TargetRegisterClass*, unsigned) const;\n"
+ << " const TargetRegisterClass *getMatchingSuperRegClass("
+ "const TargetRegisterClass*, const TargetRegisterClass*, "
+ "unsigned) const;\n"
+ << " const RegClassWeight &getRegClassWeight("
+ << "const TargetRegisterClass *RC) const;\n"
+ << " unsigned getNumRegPressureSets() const;\n"
+ << " unsigned getRegPressureSetLimit(unsigned Idx) const;\n"
+ << " const int *getRegClassPressureSets("
+ << "const TargetRegisterClass *RC) const;\n"
<< "};\n\n";
- const std::vector<Record*> &SubRegIndices = RegBank.getSubRegIndices();
- if (!SubRegIndices.empty()) {
- OS << "\n// Subregister indices\n";
- std::string Namespace = SubRegIndices[0]->getValueAsString("Namespace");
- if (!Namespace.empty())
- OS << "namespace " << Namespace << " {\n";
- OS << "enum {\n NoSubRegister,\n";
- for (unsigned i = 0, e = RegBank.getNumNamedIndices(); i != e; ++i)
- OS << " " << SubRegIndices[i]->getName() << ",\t// " << i+1 << "\n";
- OS << " NUM_TARGET_NAMED_SUBREGS = " << SubRegIndices.size()+1 << "\n";
- OS << "};\n";
- if (!Namespace.empty())
- OS << "}\n";
- }
-
ArrayRef<CodeGenRegisterClass*> RegisterClasses = RegBank.getRegClasses();
if (!RegisterClasses.empty()) {
@@ -455,19 +685,11 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
const CodeGenRegisterClass &RC = *RegisterClasses[i];
const std::string &Name = RC.getName();
- // Output the register class definition.
- OS << " struct " << Name << "Class : public TargetRegisterClass {\n"
- << " " << Name << "Class();\n";
- if (!RC.AltOrderSelect.empty())
- OS << " ArrayRef<unsigned> "
- "getRawAllocationOrder(const MachineFunction&) const;\n";
- OS << " };\n";
-
// Output the extern for the instance.
- OS << " extern " << Name << "Class\t" << Name << "RegClass;\n";
+ OS << " extern const TargetRegisterClass " << Name << "RegClass;\n";
// Output the extern for the pointer to the instance (should remove).
- OS << " static TargetRegisterClass * const "<< Name <<"RegisterClass = &"
- << Name << "RegClass;\n";
+ OS << " static const TargetRegisterClass * const " << Name
+ << "RegisterClass = &" << Name << "RegClass;\n";
}
OS << "} // end of namespace " << TargetName << "\n\n";
}
@@ -489,8 +711,8 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "namespace llvm {\n\n";
// Get access to MCRegisterClass data.
- OS << "extern MCRegisterClass " << Target.getName()
- << "MCRegisterClasses[];\n";
+ OS << "extern const MCRegisterClass " << Target.getName()
+ << "MCRegisterClasses[];\n";
// Start out by emitting each of the register classes.
ArrayRef<CodeGenRegisterClass*> RegisterClasses = RegBank.getRegClasses();
@@ -507,38 +729,21 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
AllocatableRegs.insert(Order.begin(), Order.end());
}
- OS << "namespace { // Register classes...\n";
-
- // Emit the ValueType arrays for each RegisterClass
- for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
- const CodeGenRegisterClass &RC = *RegisterClasses[rc];
-
- // Give the register class a legal C name if it's anonymous.
- std::string Name = RC.getName() + "VTs";
-
- // Emit the register list now.
- OS << " // " << Name
- << " Register Class Value Types...\n"
- << " static const EVT " << Name
- << "[] = {\n ";
- for (unsigned i = 0, e = RC.VTs.size(); i != e; ++i)
- OS << getEnumName(RC.VTs[i]) << ", ";
- OS << "MVT::Other\n };\n\n";
- }
- OS << "} // end anonymous namespace\n\n";
+ // Build a shared array of value types.
+ SequenceToOffsetTable<std::vector<MVT::SimpleValueType> > VTSeqs;
+ for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc)
+ VTSeqs.add(RegisterClasses[rc]->VTs);
+ VTSeqs.layout();
+ OS << "\nstatic const MVT::SimpleValueType VTLists[] = {\n";
+ VTSeqs.emit(OS, printSimpleValueType, "MVT::Other");
+ OS << "};\n";
// Now that all of the structs have been emitted, emit the instances.
if (!RegisterClasses.empty()) {
- OS << "namespace " << RegisterClasses[0]->Namespace
- << " { // Register class instances\n";
- for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i)
- OS << " " << RegisterClasses[i]->getName() << "Class\t"
- << RegisterClasses[i]->getName() << "RegClass;\n";
-
std::map<unsigned, std::set<unsigned> > SuperRegClassMap;
- OS << "\n static const TargetRegisterClass* const "
- << "NullRegClasses[] = { NULL };\n\n";
+ OS << "\nstatic const TargetRegisterClass *const "
+ << "NullRegClasses[] = { NULL };\n\n";
unsigned NumSubRegIndices = RegBank.getSubRegIndices().size();
@@ -563,10 +768,10 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Give the register class a legal C name if it's anonymous.
std::string Name = RC.getName();
- OS << " // " << Name
+ OS << "// " << Name
<< " Super-register Classes...\n"
- << " static const TargetRegisterClass* const "
- << Name << "SuperRegClasses[] = {\n ";
+ << "static const TargetRegisterClass *const "
+ << Name << "SuperRegClasses[] = {\n ";
bool Empty = true;
std::map<unsigned, std::set<unsigned> >::iterator I =
@@ -583,7 +788,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
}
OS << (!Empty ? ", " : "") << "NULL";
- OS << "\n };\n\n";
+ OS << "\n};\n\n";
}
}
@@ -594,9 +799,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Give the register class a legal C name if it's anonymous.
std::string Name = RC.getName();
- OS << " static const unsigned " << Name << "SubclassMask[] = { ";
+ OS << "static const uint32_t " << Name << "SubclassMask[] = {\n ";
printBitVectorAsHex(OS, RC.getSubClasses(), 32);
- OS << "};\n\n";
+ OS << "\n};\n\n";
}
// Emit NULL terminated super-class lists.
@@ -608,54 +813,71 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
if (Supers.empty())
continue;
- OS << " static const TargetRegisterClass* const "
+ OS << "static const TargetRegisterClass *const "
<< RC.getName() << "Superclasses[] = {\n";
for (unsigned i = 0; i != Supers.size(); ++i)
- OS << " &" << Supers[i]->getQualifiedName() << "RegClass,\n";
- OS << " NULL\n };\n\n";
+ OS << " &" << Supers[i]->getQualifiedName() << "RegClass,\n";
+ OS << " NULL\n};\n\n";
}
// Emit methods.
for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
const CodeGenRegisterClass &RC = *RegisterClasses[i];
- OS << RC.getName() << "Class::" << RC.getName()
- << "Class() : TargetRegisterClass(&"
- << Target.getName() << "MCRegisterClasses["
- << RC.getName() + "RegClassID" << "], "
- << RC.getName() + "VTs" << ", "
- << RC.getName() + "SubclassMask" << ", ";
- if (RC.getSuperClasses().empty())
- OS << "NullRegClasses, ";
- else
- OS << RC.getName() + "Superclasses, ";
- OS << (NumSubRegIndices ? RC.getName() + "Super" : std::string("Null"))
- << "RegClasses"
- << ") {}\n";
if (!RC.AltOrderSelect.empty()) {
OS << "\nstatic inline unsigned " << RC.getName()
<< "AltOrderSelect(const MachineFunction &MF) {"
- << RC.AltOrderSelect << "}\n\nArrayRef<unsigned> "
- << RC.getName() << "Class::"
- << "getRawAllocationOrder(const MachineFunction &MF) const {\n";
+ << RC.AltOrderSelect << "}\n\n"
+ << "static ArrayRef<uint16_t> " << RC.getName()
+ << "GetRawAllocationOrder(const MachineFunction &MF) {\n";
for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) {
ArrayRef<Record*> Elems = RC.getOrder(oi);
- OS << " static const unsigned AltOrder" << oi << "[] = {";
- for (unsigned elem = 0; elem != Elems.size(); ++elem)
- OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]);
- OS << " };\n";
+ if (!Elems.empty()) {
+ OS << " static const uint16_t AltOrder" << oi << "[] = {";
+ for (unsigned elem = 0; elem != Elems.size(); ++elem)
+ OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]);
+ OS << " };\n";
+ }
}
OS << " const MCRegisterClass &MCR = " << Target.getName()
- << "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];"
- << " static const ArrayRef<unsigned> Order[] = {\n"
+ << "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n"
+ << " const ArrayRef<uint16_t> Order[] = {\n"
<< " makeArrayRef(MCR.begin(), MCR.getNumRegs()";
for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi)
- OS << "),\n makeArrayRef(AltOrder" << oi;
+ if (RC.getOrder(oi).empty())
+ OS << "),\n ArrayRef<uint16_t>(";
+ else
+ OS << "),\n makeArrayRef(AltOrder" << oi;
OS << ")\n };\n const unsigned Select = " << RC.getName()
<< "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders()
<< ");\n return Order[Select];\n}\n";
}
}
+ // Now emit the actual value-initialized register class instances.
+ OS << "namespace " << RegisterClasses[0]->Namespace
+ << " { // Register class instances\n";
+
+ for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
+ const CodeGenRegisterClass &RC = *RegisterClasses[i];
+ OS << " extern const TargetRegisterClass "
+ << RegisterClasses[i]->getName() << "RegClass = {\n "
+ << '&' << Target.getName() << "MCRegisterClasses[" << RC.getName()
+ << "RegClassID],\n "
+ << "VTLists + " << VTSeqs.get(RC.VTs) << ",\n "
+ << RC.getName() << "SubclassMask,\n ";
+ if (RC.getSuperClasses().empty())
+ OS << "NullRegClasses,\n ";
+ else
+ OS << RC.getName() << "Superclasses,\n ";
+ OS << (NumSubRegIndices ? RC.getName() + "Super" : std::string("Null"))
+ << "RegClasses,\n ";
+ if (RC.AltOrderSelect.empty())
+ OS << "0\n";
+ else
+ OS << RC.getName() << "GetRawAllocationOrder\n";
+ OS << " };\n\n";
+ }
+
OS << "}\n";
}
@@ -669,28 +891,27 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Emit extra information about registers.
const std::string &TargetName = Target.getName();
- OS << "\n static const TargetRegisterInfoDesc "
- << TargetName << "RegInfoDesc[] = "
- << "{ // Extra Descriptors\n";
- OS << " { 0, 0 },\n";
+ OS << "\nstatic const TargetRegisterInfoDesc "
+ << TargetName << "RegInfoDesc[] = { // Extra Descriptors\n";
+ OS << " { 0, 0 },\n";
const std::vector<CodeGenRegister*> &Regs = RegBank.getRegisters();
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
const CodeGenRegister &Reg = *Regs[i];
- OS << " { ";
+ OS << " { ";
OS << Reg.CostPerUse << ", "
<< int(AllocatableRegs.count(Reg.TheDef)) << " },\n";
}
- OS << " };\n"; // End of register descriptors...
+ OS << "};\n"; // End of register descriptors...
// Calculate the mapping of subregister+index pairs to physical registers.
- // This will also create further anonymous indexes.
+ // This will also create further anonymous indices.
unsigned NamedIndices = RegBank.getNumNamedIndices();
// Emit SubRegIndex names, skipping 0
- const std::vector<Record*> &SubRegIndices = RegBank.getSubRegIndices();
- OS << "\n static const char *const " << TargetName
+ ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices();
+ OS << "\nstatic const char *const " << TargetName
<< "SubRegIndexTable[] = { \"";
for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) {
OS << SubRegIndices[i]->getName();
@@ -699,7 +920,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
}
OS << "\" };\n\n";
- // Emit names of the anonymus subreg indexes.
+ // Emit names of the anonymous subreg indices.
if (SubRegIndices.size() > NamedIndices) {
OS << " enum {";
for (unsigned i = NamedIndices, e = SubRegIndices.size(); i != e; ++i) {
@@ -713,48 +934,6 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
std::string ClassName = Target.getName() + "GenRegisterInfo";
- // Emit the subregister + index mapping function based on the information
- // calculated above.
- OS << "unsigned " << ClassName
- << "::getSubReg(unsigned RegNo, unsigned Index) const {\n"
- << " switch (RegNo) {\n"
- << " default:\n return 0;\n";
- for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- const CodeGenRegister::SubRegMap &SRM = Regs[i]->getSubRegs();
- if (SRM.empty())
- continue;
- OS << " case " << getQualifiedName(Regs[i]->TheDef) << ":\n";
- OS << " switch (Index) {\n";
- OS << " default: return 0;\n";
- for (CodeGenRegister::SubRegMap::const_iterator ii = SRM.begin(),
- ie = SRM.end(); ii != ie; ++ii)
- OS << " case " << getQualifiedName(ii->first)
- << ": return " << getQualifiedName(ii->second->TheDef) << ";\n";
- OS << " };\n" << " break;\n";
- }
- OS << " };\n";
- OS << " return 0;\n";
- OS << "}\n\n";
-
- OS << "unsigned " << ClassName
- << "::getSubRegIndex(unsigned RegNo, unsigned SubRegNo) const {\n"
- << " switch (RegNo) {\n"
- << " default:\n return 0;\n";
- for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- const CodeGenRegister::SubRegMap &SRM = Regs[i]->getSubRegs();
- if (SRM.empty())
- continue;
- OS << " case " << getQualifiedName(Regs[i]->TheDef) << ":\n";
- for (CodeGenRegister::SubRegMap::const_iterator ii = SRM.begin(),
- ie = SRM.end(); ii != ie; ++ii)
- OS << " if (SubRegNo == " << getQualifiedName(ii->second->TheDef)
- << ") return " << getQualifiedName(ii->first) << ";\n";
- OS << " return 0;\n";
- }
- OS << " };\n";
- OS << " return 0;\n";
- OS << "}\n\n";
-
// Emit composeSubRegIndices
OS << "unsigned " << ClassName
<< "::composeSubRegIndices(unsigned IdxA, unsigned IdxB) const {\n"
@@ -763,15 +942,15 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) {
bool Open = false;
for (unsigned j = 0; j != e; ++j) {
- if (Record *Comp = RegBank.getCompositeSubRegIndex(SubRegIndices[i],
- SubRegIndices[j])) {
+ if (CodeGenSubRegIndex *Comp =
+ SubRegIndices[i]->compose(SubRegIndices[j])) {
if (!Open) {
- OS << " case " << getQualifiedName(SubRegIndices[i])
+ OS << " case " << SubRegIndices[i]->getQualifiedName()
<< ": switch(IdxB) {\n default: return IdxB;\n";
Open = true;
}
- OS << " case " << getQualifiedName(SubRegIndices[j])
- << ": return " << getQualifiedName(Comp) << ";\n";
+ OS << " case " << SubRegIndices[j]->getQualifiedName()
+ << ": return " << Comp->getQualifiedName() << ";\n";
}
}
if (Open)
@@ -800,7 +979,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
const CodeGenRegisterClass &RC = *RegisterClasses[rci];
OS << " {\t// " << RC.getName() << "\n";
for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
- Record *Idx = SubRegIndices[sri];
+ CodeGenSubRegIndex *Idx = SubRegIndices[sri];
if (CodeGenRegisterClass *SRC = RC.getSubClassWithSubReg(Idx))
OS << " " << SRC->EnumValue + 1 << ",\t// " << Idx->getName()
<< " -> " << SRC->getName() << "\n";
@@ -817,22 +996,106 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
}
OS << "}\n\n";
+ // Emit getMatchingSuperRegClass.
+ OS << "const TargetRegisterClass *" << ClassName
+ << "::getMatchingSuperRegClass(const TargetRegisterClass *A,"
+ " const TargetRegisterClass *B, unsigned Idx) const {\n";
+ if (SubRegIndices.empty()) {
+ OS << " llvm_unreachable(\"Target has no sub-registers\");\n";
+ } else {
+ // We need to find the largest sub-class of A such that every register has
+ // an Idx sub-register in B. Map (B, Idx) to a bit-vector of
+ // super-register classes that map into B. Then compute the largest common
+ // sub-class with A by taking advantage of the register class ordering,
+ // like getCommonSubClass().
+
+ // Bitvector table is NumRCs x NumSubIndexes x BVWords, where BVWords is
+ // the number of 32-bit words required to represent all register classes.
+ const unsigned BVWords = (RegisterClasses.size()+31)/32;
+ BitVector BV(RegisterClasses.size());
+
+ OS << " static const uint32_t Table[" << RegisterClasses.size()
+ << "][" << SubRegIndices.size() << "][" << BVWords << "] = {\n";
+ for (unsigned rci = 0, rce = RegisterClasses.size(); rci != rce; ++rci) {
+ const CodeGenRegisterClass &RC = *RegisterClasses[rci];
+ OS << " {\t// " << RC.getName() << "\n";
+ for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
+ CodeGenSubRegIndex *Idx = SubRegIndices[sri];
+ BV.reset();
+ RC.getSuperRegClasses(Idx, BV);
+ OS << " { ";
+ printBitVectorAsHex(OS, BV, 32);
+ OS << "},\t// " << Idx->getName() << '\n';
+ }
+ OS << " },\n";
+ }
+ OS << " };\n assert(A && B && \"Missing regclass\");\n"
+ << " --Idx;\n"
+ << " assert(Idx < " << SubRegIndices.size() << " && \"Bad subreg\");\n"
+ << " const uint32_t *TV = Table[B->getID()][Idx];\n"
+ << " const uint32_t *SC = A->getSubClassMask();\n"
+ << " for (unsigned i = 0; i != " << BVWords << "; ++i)\n"
+ << " if (unsigned Common = TV[i] & SC[i])\n"
+ << " return getRegClass(32*i + CountTrailingZeros_32(Common));\n"
+ << " return 0;\n";
+ }
+ OS << "}\n\n";
+
+ EmitRegUnitPressure(OS, RegBank, ClassName);
+
// Emit the constructor of the class...
- OS << "extern MCRegisterDesc " << TargetName << "RegDesc[];\n";
+ OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
+ OS << "extern const uint16_t " << TargetName << "RegLists[];\n";
+ if (SubRegIndices.size() != 0)
+ OS << "extern const uint16_t *get" << TargetName
+ << "SubRegTable();\n";
- OS << ClassName << "::" << ClassName
+ EmitRegMappingTables(OS, Regs, true);
+
+ OS << ClassName << "::\n" << ClassName
<< "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour)\n"
<< " : TargetRegisterInfo(" << TargetName << "RegInfoDesc"
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n"
- << " " << TargetName << "SubRegIndexTable) {\n"
+ << " " << TargetName << "SubRegIndexTable) {\n"
<< " InitMCRegisterInfo(" << TargetName << "RegDesc, "
- << Regs.size()+1 << ", RA, " << TargetName << "MCRegisterClasses, "
- << RegisterClasses.size() << ");\n\n";
+ << Regs.size()+1 << ", RA,\n " << TargetName
+ << "MCRegisterClasses, " << RegisterClasses.size() << ",\n"
+ << " " << TargetName << "RegLists,\n"
+ << " ";
+ if (SubRegIndices.size() != 0)
+ OS << "get" << TargetName << "SubRegTable(), "
+ << SubRegIndices.size() << ");\n\n";
+ else
+ OS << "NULL, 0);\n\n";
EmitRegMapping(OS, Regs, true);
OS << "}\n\n";
+
+ // Emit CalleeSavedRegs information.
+ std::vector<Record*> CSRSets =
+ Records.getAllDerivedDefinitions("CalleeSavedRegs");
+ for (unsigned i = 0, e = CSRSets.size(); i != e; ++i) {
+ Record *CSRSet = CSRSets[i];
+ const SetTheory::RecVec *Regs = RegBank.getSets().expand(CSRSet);
+ assert(Regs && "Cannot expand CalleeSavedRegs instance");
+
+ // Emit the *_SaveList list of callee-saved registers.
+ OS << "static const uint16_t " << CSRSet->getName()
+ << "_SaveList[] = { ";
+ for (unsigned r = 0, re = Regs->size(); r != re; ++r)
+ OS << getQualifiedName((*Regs)[r]) << ", ";
+ OS << "0 };\n";
+
+ // Emit the *_RegMask bit mask of call-preserved registers.
+ OS << "static const uint32_t " << CSRSet->getName()
+ << "_RegMask[] = { ";
+ printBitVectorAsHex(OS, RegBank.computeCoveredRegisters(*Regs), 32);
+ OS << "};\n";
+ }
+ OS << "\n\n";
+
OS << "} // End llvm namespace \n";
OS << "#endif // GET_REGINFO_TARGET_DESC\n\n";
}
diff --git a/utils/TableGen/RegisterInfoEmitter.h b/utils/TableGen/RegisterInfoEmitter.h
index 0fd4d079ebc0..ee9903cac7b1 100644
--- a/utils/TableGen/RegisterInfoEmitter.h
+++ b/utils/TableGen/RegisterInfoEmitter.h
@@ -50,7 +50,13 @@ public:
private:
void EmitRegMapping(raw_ostream &o,
const std::vector<CodeGenRegister*> &Regs, bool isCtor);
+ void EmitRegMappingTables(raw_ostream &o,
+ const std::vector<CodeGenRegister*> &Regs,
+ bool isCtor);
void EmitRegClasses(raw_ostream &OS, CodeGenTarget &Target);
+
+ void EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
+ const std::string &ClassName);
};
} // End llvm namespace
diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h
new file mode 100644
index 000000000000..97c764e61d56
--- /dev/null
+++ b/utils/TableGen/SequenceToOffsetTable.h
@@ -0,0 +1,139 @@
+//===-- SequenceToOffsetTable.h - Compress similar sequences ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// SequenceToOffsetTable can be used to emit a number of null-terminated
+// sequences as one big array. Use the same memory when a sequence is a suffix
+// of another.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TBLGEN_SEQUENCE_TO_OFFSET_TABLE_H
+#define TBLGEN_SEQUENCE_TO_OFFSET_TABLE_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <cassert>
+#include <cctype>
+
+namespace llvm {
+
+/// SequenceToOffsetTable - Collect a number of terminated sequences of T.
+/// Compute the layout of a table that contains all the sequences, possibly by
+/// reusing entries.
+///
+/// @param SeqT The sequence container. (vector or string).
+/// @param Less A stable comparator for SeqT elements.
+template<typename SeqT, typename Less = std::less<typename SeqT::value_type> >
+class SequenceToOffsetTable {
+ typedef typename SeqT::value_type ElemT;
+
+ // Define a comparator for SeqT that sorts a suffix immediately before a
+ // sequence with that suffix.
+ struct SeqLess : public std::binary_function<SeqT, SeqT, bool> {
+ Less L;
+ bool operator()(const SeqT &A, const SeqT &B) const {
+ return std::lexicographical_compare(A.rbegin(), A.rend(),
+ B.rbegin(), B.rend(), L);
+ }
+ };
+
+ // Keep sequences ordered according to SeqLess so suffixes are easy to find.
+ // Map each sequence to its offset in the table.
+ typedef std::map<SeqT, unsigned, SeqLess> SeqMap;
+
+ // Sequences added so far, with suffixes removed.
+ SeqMap Seqs;
+
+ // Entries in the final table, or 0 before layout was called.
+ unsigned Entries;
+
+ // isSuffix - Returns true if A is a suffix of B.
+ static bool isSuffix(const SeqT &A, const SeqT &B) {
+ return A.size() <= B.size() && std::equal(A.rbegin(), A.rend(), B.rbegin());
+ }
+
+public:
+ SequenceToOffsetTable() : Entries(0) {}
+
+ /// add - Add a sequence to the table.
+ /// This must be called before layout().
+ void add(const SeqT &Seq) {
+ assert(Entries == 0 && "Cannot call add() after layout()");
+ typename SeqMap::iterator I = Seqs.lower_bound(Seq);
+
+ // If SeqMap contains a sequence that has Seq as a suffix, I will be
+ // pointing to it.
+ if (I != Seqs.end() && isSuffix(Seq, I->first))
+ return;
+
+ I = Seqs.insert(I, std::make_pair(Seq, 0u));
+
+ // The entry before I may be a suffix of Seq that can now be erased.
+ if (I != Seqs.begin() && isSuffix((--I)->first, Seq))
+ Seqs.erase(I);
+ }
+
+ /// layout - Computes the final table layout.
+ void layout() {
+ assert(Entries == 0 && "Can only call layout() once");
+ // Lay out the table in Seqs iteration order.
+ for (typename SeqMap::iterator I = Seqs.begin(), E = Seqs.end(); I != E;
+ ++I) {
+ I->second = Entries;
+ // Include space for a terminator.
+ Entries += I->first.size() + 1;
+ }
+ }
+
+ /// get - Returns the offset of Seq in the final table.
+ unsigned get(const SeqT &Seq) const {
+ assert(Entries && "Call layout() before get()");
+ typename SeqMap::const_iterator I = Seqs.lower_bound(Seq);
+ assert(I != Seqs.end() && isSuffix(Seq, I->first) &&
+ "get() called with sequence that wasn't added first");
+ return I->second + (I->first.size() - Seq.size());
+ }
+
+ /// emit - Print out the table as the body of an array initializer.
+ /// Use the Print function to print elements.
+ void emit(raw_ostream &OS,
+ void (*Print)(raw_ostream&, ElemT),
+ const char *Term = "0") const {
+ assert(Entries && "Call layout() before emit()");
+ for (typename SeqMap::const_iterator I = Seqs.begin(), E = Seqs.end();
+ I != E; ++I) {
+ OS << " /* " << I->second << " */ ";
+ for (typename SeqT::const_iterator SI = I->first.begin(),
+ SE = I->first.end(); SI != SE; ++SI) {
+ Print(OS, *SI);
+ OS << ", ";
+ }
+ OS << Term << ",\n";
+ }
+ }
+};
+
+// Helper function for SequenceToOffsetTable<string>.
+static inline void printChar(raw_ostream &OS, char C) {
+ unsigned char UC(C);
+ if (isalnum(UC) || ispunct(UC)) {
+ OS << '\'';
+ if (C == '\\' || C == '\'')
+ OS << '\\';
+ OS << C << '\'';
+ } else {
+ OS << unsigned(UC);
+ }
+}
+
+} // end namespace llvm
+
+#endif
diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp
index bef73f33effe..0649fd1cfaf9 100644
--- a/utils/TableGen/SetTheory.cpp
+++ b/utils/TableGen/SetTheory.cpp
@@ -139,6 +139,24 @@ struct DecimateOp : public SetIntBinOp {
}
};
+// (interleave S1, S2, ...) Interleave elements of the arguments.
+struct InterleaveOp : public SetTheory::Operator {
+ void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
+ // Evaluate the arguments individually.
+ SmallVector<RecSet, 4> Args(Expr->getNumArgs());
+ unsigned MaxSize = 0;
+ for (unsigned i = 0, e = Expr->getNumArgs(); i != e; ++i) {
+ ST.evaluate(Expr->getArg(i), Args[i]);
+ MaxSize = std::max(MaxSize, unsigned(Args[i].size()));
+ }
+ // Interleave arguments into Elts.
+ for (unsigned n = 0; n != MaxSize; ++n)
+ for (unsigned i = 0, e = Expr->getNumArgs(); i != e; ++i)
+ if (n < Args[i].size())
+ Elts.insert(Args[i][n]);
+ }
+};
+
// (sequence "Format", From, To) Generate a sequence of records by name.
struct SequenceOp : public SetTheory::Operator {
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
@@ -198,6 +216,10 @@ struct FieldExpander : public SetTheory::Expander {
};
} // end anonymous namespace
+void SetTheory::Operator::anchor() { }
+
+void SetTheory::Expander::anchor() { }
+
SetTheory::SetTheory() {
addOperator("add", new AddOp);
addOperator("sub", new SubOp);
@@ -207,6 +229,7 @@ SetTheory::SetTheory() {
addOperator("rotl", new RotOp(false));
addOperator("rotr", new RotOp(true));
addOperator("decimate", new DecimateOp);
+ addOperator("interleave", new InterleaveOp);
addOperator("sequence", new SequenceOp);
}
diff --git a/utils/TableGen/SetTheory.h b/utils/TableGen/SetTheory.h
index 6e8313be07a3..b394058f4c35 100644
--- a/utils/TableGen/SetTheory.h
+++ b/utils/TableGen/SetTheory.h
@@ -65,7 +65,9 @@ public:
typedef SmallSetVector<Record*, 16> RecSet;
/// Operator - A callback representing a DAG operator.
- struct Operator {
+ class Operator {
+ virtual void anchor();
+ public:
virtual ~Operator() {}
/// apply - Apply this operator to Expr's arguments and insert the result
@@ -76,7 +78,9 @@ public:
/// Expander - A callback function that can transform a Record representing a
/// set into a fully expanded list of elements. Expanders provide a way for
/// users to define named sets that can be used in DAG expressions.
- struct Expander {
+ class Expander {
+ virtual void anchor();
+ public:
virtual ~Expander() {}
virtual void expand(SetTheory&, Record*, RecSet &Elts) =0;
diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h
index ac9422c5d72d..803f5bd5cf01 100644
--- a/utils/TableGen/StringToOffsetTable.h
+++ b/utils/TableGen/StringToOffsetTable.h
@@ -26,16 +26,17 @@ class StringToOffsetTable {
std::string AggregateString;
public:
- unsigned GetOrAddStringOffset(StringRef Str) {
- unsigned &Entry = StringOffset[Str];
- if (Entry == 0) {
+ unsigned GetOrAddStringOffset(StringRef Str, bool appendZero = true) {
+ StringMapEntry<unsigned> &Entry = StringOffset.GetOrCreateValue(Str, -1U);
+ if (Entry.getValue() == -1U) {
// Add the string to the aggregate if this is the first time found.
- Entry = AggregateString.size();
+ Entry.setValue(AggregateString.size());
AggregateString.append(Str.begin(), Str.end());
- AggregateString += '\0';
+ if (appendZero)
+ AggregateString += '\0';
}
- return Entry;
+ return Entry.getValue();
}
void EmitString(raw_ostream &O) {
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 103a4032b02a..986c50f87865 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -39,28 +39,41 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS,
OS << "namespace " << Target << " {\n";
- // Open enumeration
- OS << "enum {\n";
+ // For bit flag enumerations with more than 32 items, emit constants.
+ // Emit an enum for everything else.
+ if (isBits && N > 32) {
+ // For each record
+ for (unsigned i = 0; i < N; i++) {
+ // Next record
+ Record *Def = DefList[i];
+
+ // Get and emit name and expression (1 << i)
+ OS << " const uint64_t " << Def->getName() << " = 1ULL << " << i << ";\n";
+ }
+ } else {
+ // Open enumeration
+ OS << "enum {\n";
- // For each record
- for (unsigned i = 0; i < N;) {
- // Next record
- Record *Def = DefList[i];
+ // For each record
+ for (unsigned i = 0; i < N;) {
+ // Next record
+ Record *Def = DefList[i];
- // Get and emit name
- OS << " " << Def->getName();
+ // Get and emit name
+ OS << " " << Def->getName();
- // If bit flags then emit expression (1 << i)
- if (isBits) OS << " = " << " 1ULL << " << i;
+ // If bit flags then emit expression (1 << i)
+ if (isBits) OS << " = " << " 1ULL << " << i;
- // Depending on 'if more in the list' emit comma
- if (++i < N) OS << ",";
+ // Depending on 'if more in the list' emit comma
+ if (++i < N) OS << ",";
- OS << "\n";
- }
+ OS << "\n";
+ }
- // Close enumeration
- OS << "};\n";
+ // Close enumeration
+ OS << "};\n";
+ }
OS << "}\n";
}
@@ -81,7 +94,8 @@ unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) {
// Begin feature table
OS << "// Sorted (by key) array of values for CPU features.\n"
- << "llvm::SubtargetFeatureKV " << Target << "FeatureKV[] = {\n";
+ << "extern const llvm::SubtargetFeatureKV " << Target
+ << "FeatureKV[] = {\n";
// For each feature
unsigned NumFeatures = 0;
@@ -140,7 +154,8 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) {
// Begin processor table
OS << "// Sorted (by key) array of values for CPU subtype.\n"
- << "llvm::SubtargetFeatureKV " << Target << "SubTypeKV[] = {\n";
+ << "extern const llvm::SubtargetFeatureKV " << Target
+ << "SubTypeKV[] = {\n";
// For each processor
for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
@@ -327,9 +342,9 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name
<< "\"\n" << "namespace " << Name << "Bypass {\n";
- OS << " unsigned NoBypass = 0;\n";
+ OS << " const unsigned NoBypass = 0;\n";
for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
- OS << " unsigned " << BPs[j]->getName()
+ OS << " const unsigned " << BPs[j]->getName()
<< " = 1 << " << j << ";\n";
OS << "}\n";
@@ -337,16 +352,17 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
}
// Begin stages table
- std::string StageTable = "\nllvm::InstrStage " + Target + "Stages[] = {\n";
+ std::string StageTable = "\nextern const llvm::InstrStage " + Target +
+ "Stages[] = {\n";
StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
// Begin operand cycle table
- std::string OperandCycleTable = "unsigned " + Target +
+ std::string OperandCycleTable = "extern const unsigned " + Target +
"OperandCycles[] = {\n";
OperandCycleTable += " 0, // No itinerary\n";
// Begin pipeline bypass table
- std::string BypassTable = "unsigned " + Target +
+ std::string BypassTable = "extern const unsigned " + Target +
"ForwardingPathes[] = {\n";
BypassTable += " 0, // No itinerary\n";
@@ -488,7 +504,7 @@ EmitProcessorData(raw_ostream &OS,
// Begin processor itinerary table
OS << "\n";
- OS << "llvm::InstrItinerary " << Name << "[] = {\n";
+ OS << "static const llvm::InstrItinerary " << Name << "[] = {\n";
// For each itinerary class
std::vector<InstrItinerary> &ItinList = *ProcListIter++;
@@ -530,7 +546,7 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
// Begin processor table
OS << "\n";
OS << "// Sorted (by key) array of itineraries for CPU subtype.\n"
- << "llvm::SubtargetInfoKV "
+ << "extern const llvm::SubtargetInfoKV "
<< Target << "ProcItinKV[] = {\n";
// For each processor
@@ -708,9 +724,13 @@ void SubtargetEmitter::run(raw_ostream &OS) {
std::string ClassName = Target + "GenSubtargetInfo";
OS << "namespace llvm {\n";
+ OS << "class DFAPacketizer;\n";
OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
<< " explicit " << ClassName << "(StringRef TT, StringRef CPU, "
<< "StringRef FS);\n"
+ << "public:\n"
+ << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
+ << " const;\n"
<< "};\n";
OS << "} // End llvm namespace \n";
@@ -720,13 +740,13 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "#undef GET_SUBTARGETINFO_CTOR\n";
OS << "namespace llvm {\n";
- OS << "extern llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
- OS << "extern llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n";
+ OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
+ OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n";
if (HasItineraries) {
- OS << "extern llvm::SubtargetInfoKV " << Target << "ProcItinKV[];\n";
- OS << "extern llvm::InstrStage " << Target << "Stages[];\n";
- OS << "extern unsigned " << Target << "OperandCycles[];\n";
- OS << "extern unsigned " << Target << "ForwardingPathes[];\n";
+ OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcItinKV[];\n";
+ OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
+ OS << "extern const unsigned " << Target << "OperandCycles[];\n";
+ OS << "extern const unsigned " << Target << "ForwardingPathes[];\n";
}
OS << ClassName << "::" << ClassName << "(StringRef TT, StringRef CPU, "
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index eacfdf6fed39..8c41358e3d85 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -16,6 +16,7 @@
#include "CallingConvEmitter.h"
#include "CodeEmitterGen.h"
#include "DAGISelEmitter.h"
+#include "DFAPacketizerEmitter.h"
#include "DisassemblerEmitter.h"
#include "EDEmitter.h"
#include "FastISelEmitter.h"
@@ -23,7 +24,6 @@
#include "IntrinsicEmitter.h"
#include "PseudoLoweringEmitter.h"
#include "RegisterInfoEmitter.h"
-#include "ARMDecoderEmitter.h"
#include "SubtargetEmitter.h"
#include "SetTheory.h"
@@ -44,11 +44,11 @@ enum ActionType {
GenInstrInfo,
GenAsmWriter,
GenAsmMatcher,
- GenARMDecoder,
GenDisassembler,
GenPseudoLowering,
GenCallingConv,
GenDAGISel,
+ GenDFAPacketizer,
GenFastISel,
GenSubtarget,
GenIntrinsic,
@@ -73,8 +73,6 @@ 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(GenPseudoLowering, "gen-pseudo-lowering",
@@ -83,6 +81,8 @@ namespace {
"Generate assembly instruction matcher"),
clEnumValN(GenDAGISel, "gen-dag-isel",
"Generate a DAG instruction selector"),
+ clEnumValN(GenDFAPacketizer, "gen-dfa-packetizer",
+ "Generate DFA Packetizer for VLIW targets"),
clEnumValN(GenFastISel, "gen-fast-isel",
"Generate a \"fast\" instruction selector"),
clEnumValN(GenSubtarget, "gen-subtarget",
@@ -101,92 +101,89 @@ namespace {
cl::opt<std::string>
Class("class", cl::desc("Print Enum list for this class"),
- cl::value_desc("class name"));
-}
-
-class LLVMTableGenAction : public TableGenAction {
-public:
- bool operator()(raw_ostream &OS, RecordKeeper &Records) {
- switch (Action) {
- case PrintRecords:
- OS << Records; // No argument, dump all contents
- break;
- case GenEmitter:
- CodeEmitterGen(Records).run(OS);
- break;
- case GenRegisterInfo:
- RegisterInfoEmitter(Records).run(OS);
- break;
- case GenInstrInfo:
- InstrInfoEmitter(Records).run(OS);
- break;
- case GenCallingConv:
- CallingConvEmitter(Records).run(OS);
- break;
- case GenAsmWriter:
- AsmWriterEmitter(Records).run(OS);
- break;
- case GenARMDecoder:
- ARMDecoderEmitter(Records).run(OS);
- break;
- case GenAsmMatcher:
- AsmMatcherEmitter(Records).run(OS);
- break;
- case GenDisassembler:
- DisassemblerEmitter(Records).run(OS);
- break;
- case GenPseudoLowering:
- PseudoLoweringEmitter(Records).run(OS);
- break;
- case GenDAGISel:
- DAGISelEmitter(Records).run(OS);
- break;
- case GenFastISel:
- FastISelEmitter(Records).run(OS);
- break;
- case GenSubtarget:
- SubtargetEmitter(Records).run(OS);
- break;
- case GenIntrinsic:
- IntrinsicEmitter(Records).run(OS);
- break;
- case GenTgtIntrinsic:
- IntrinsicEmitter(Records, true).run(OS);
- break;
- case GenEDInfo:
- EDEmitter(Records).run(OS);
- break;
- case PrintEnums:
- {
- std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);
- for (unsigned i = 0, e = Recs.size(); i != e; ++i)
- OS << Recs[i]->getName() << ", ";
- OS << "\n";
- break;
- }
- case PrintSets:
- {
- SetTheory Sets;
- Sets.addFieldExpander("Set", "Elements");
- std::vector<Record*> Recs = Records.getAllDerivedDefinitions("Set");
- for (unsigned i = 0, e = Recs.size(); i != e; ++i) {
- OS << Recs[i]->getName() << " = [";
- const std::vector<Record*> *Elts = Sets.expand(Recs[i]);
- assert(Elts && "Couldn't expand Set instance");
- for (unsigned ei = 0, ee = Elts->size(); ei != ee; ++ei)
- OS << ' ' << (*Elts)[ei]->getName();
- OS << " ]\n";
+ cl::value_desc("class name"));
+
+ class LLVMTableGenAction : public TableGenAction {
+ public:
+ bool operator()(raw_ostream &OS, RecordKeeper &Records) {
+ switch (Action) {
+ case PrintRecords:
+ OS << Records; // No argument, dump all contents
+ break;
+ case GenEmitter:
+ CodeEmitterGen(Records).run(OS);
+ break;
+ case GenRegisterInfo:
+ RegisterInfoEmitter(Records).run(OS);
+ break;
+ case GenInstrInfo:
+ InstrInfoEmitter(Records).run(OS);
+ break;
+ case GenCallingConv:
+ CallingConvEmitter(Records).run(OS);
+ break;
+ case GenAsmWriter:
+ AsmWriterEmitter(Records).run(OS);
+ break;
+ case GenAsmMatcher:
+ AsmMatcherEmitter(Records).run(OS);
+ break;
+ case GenDisassembler:
+ DisassemblerEmitter(Records).run(OS);
+ break;
+ case GenPseudoLowering:
+ PseudoLoweringEmitter(Records).run(OS);
+ break;
+ case GenDAGISel:
+ DAGISelEmitter(Records).run(OS);
+ break;
+ case GenDFAPacketizer:
+ DFAGen(Records).run(OS);
+ break;
+ case GenFastISel:
+ FastISelEmitter(Records).run(OS);
+ break;
+ case GenSubtarget:
+ SubtargetEmitter(Records).run(OS);
+ break;
+ case GenIntrinsic:
+ IntrinsicEmitter(Records).run(OS);
+ break;
+ case GenTgtIntrinsic:
+ IntrinsicEmitter(Records, true).run(OS);
+ break;
+ case GenEDInfo:
+ EDEmitter(Records).run(OS);
+ break;
+ case PrintEnums:
+ {
+ std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);
+ for (unsigned i = 0, e = Recs.size(); i != e; ++i)
+ OS << Recs[i]->getName() << ", ";
+ OS << "\n";
+ break;
}
- break;
- }
- default:
- assert(1 && "Invalid Action");
- return true;
+ case PrintSets:
+ {
+ SetTheory Sets;
+ Sets.addFieldExpander("Set", "Elements");
+ std::vector<Record*> Recs = Records.getAllDerivedDefinitions("Set");
+ for (unsigned i = 0, e = Recs.size(); i != e; ++i) {
+ OS << Recs[i]->getName() << " = [";
+ const std::vector<Record*> *Elts = Sets.expand(Recs[i]);
+ assert(Elts && "Couldn't expand Set instance");
+ for (unsigned ei = 0, ee = Elts->size(); ei != ee; ++ei)
+ OS << ' ' << (*Elts)[ei]->getName();
+ OS << " ]\n";
+ }
+ break;
+ }
+ }
+
+ return false;
}
-
- return false;
- }
-};
+ };
+}
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal();
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index e8c9a4897321..2875168a1083 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -41,15 +41,20 @@ static inline bool inheritsFrom(InstructionContext child,
case IC:
return(inheritsFrom(child, IC_64BIT) ||
inheritsFrom(child, IC_OPSIZE) ||
+ inheritsFrom(child, IC_ADSIZE) ||
inheritsFrom(child, IC_XD) ||
inheritsFrom(child, IC_XS));
case IC_64BIT:
return(inheritsFrom(child, IC_64BIT_REXW) ||
inheritsFrom(child, IC_64BIT_OPSIZE) ||
+ inheritsFrom(child, IC_64BIT_ADSIZE) ||
inheritsFrom(child, IC_64BIT_XD) ||
inheritsFrom(child, IC_64BIT_XS));
case IC_OPSIZE:
return inheritsFrom(child, IC_64BIT_OPSIZE);
+ case IC_ADSIZE:
+ case IC_64BIT_ADSIZE:
+ return false;
case IC_XD:
return inheritsFrom(child, IC_64BIT_XD);
case IC_XS:
@@ -95,11 +100,13 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_VEX_L:
case IC_VEX_L_XS:
case IC_VEX_L_XD:
+ return false;
case IC_VEX_L_OPSIZE:
+ return inheritsFrom(child, IC_VEX_L_W_OPSIZE);
+ case IC_VEX_L_W_OPSIZE:
return false;
default:
llvm_unreachable("Unknown instruction class");
- return false;
}
}
@@ -138,8 +145,6 @@ static inline const char* stringForContext(InstructionContext insnContext) {
INSTRUCTION_CONTEXTS
#undef ENUM_ENTRY
}
-
- return 0;
}
/// stringForOperandType - Like stringForContext, but for OperandTypes.
@@ -194,8 +199,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) << "static const InstrUID modRMEmptyTable[1] = { 0 };\n";
- o << "\n";
+ o.indent(i * 2) << "0x0, /* EmptyTable */\n";
}
/// getDecisionType - Determines whether a ModRM decision with 255 entries can
@@ -207,28 +211,40 @@ static ModRMDecisionType getDecisionType(ModRMDecision &decision)
{
bool satisfiesOneEntry = true;
bool satisfiesSplitRM = true;
-
+ bool satisfiesSplitReg = true;
+
uint16_t index;
-
+
for (index = 0; index < 256; ++index) {
if (decision.instructionIDs[index] != decision.instructionIDs[0])
satisfiesOneEntry = false;
-
+
if (((index & 0xc0) == 0xc0) &&
(decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
satisfiesSplitRM = false;
-
+
if (((index & 0xc0) != 0xc0) &&
(decision.instructionIDs[index] != decision.instructionIDs[0x00]))
satisfiesSplitRM = false;
+
+ if (((index & 0xc0) == 0xc0) &&
+ (decision.instructionIDs[index] != decision.instructionIDs[index&0xf8]))
+ satisfiesSplitReg = false;
+
+ if (((index & 0xc0) != 0xc0) &&
+ (decision.instructionIDs[index] != decision.instructionIDs[index&0x38]))
+ satisfiesSplitReg = false;
}
-
+
if (satisfiesOneEntry)
return MODRM_ONEENTRY;
-
+
if (satisfiesSplitRM)
return MODRM_SPLITRM;
-
+
+ if (satisfiesSplitReg)
+ return MODRM_SPLITREG;
+
return MODRM_FULL;
}
@@ -291,71 +307,76 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
ModRMDecision &decision)
const {
static uint64_t sTableNumber = 0;
- uint64_t thisTableNumber = sTableNumber;
+ static uint64_t sEntryNumber = 1;
ModRMDecisionType dt = getDecisionType(decision);
uint16_t index;
-
+
if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
{
o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
i2++;
-
+
o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
- o2.indent(i2) << "modRMEmptyTable";
-
+ o2.indent(i2) << 0 << " /* EmptyTable */\n";
+
i2--;
o2.indent(i2) << "}";
return;
}
-
- o1.indent(i1) << "static const InstrUID modRMTable" << thisTableNumber;
-
- switch (dt) {
- default:
- llvm_unreachable("Unknown decision type");
- case MODRM_ONEENTRY:
- o1 << "[1]";
- break;
- case MODRM_SPLITRM:
- o1 << "[2]";
- break;
- case MODRM_FULL:
- o1 << "[256]";
- break;
- }
- o1 << " = {" << "\n";
+ o1 << "/* Table" << sTableNumber << " */\n";
i1++;
-
+
switch (dt) {
default:
llvm_unreachable("Unknown decision type");
case MODRM_ONEENTRY:
- emitOneID(o1, i1, decision.instructionIDs[0], false);
+ emitOneID(o1, i1, decision.instructionIDs[0], true);
break;
case MODRM_SPLITRM:
emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
- emitOneID(o1, i1, decision.instructionIDs[0xc0], false); // mod = 0b11
+ emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11
+ break;
+ case MODRM_SPLITREG:
+ for (index = 0; index < 64; index += 8)
+ emitOneID(o1, i1, decision.instructionIDs[index], true);
+ for (index = 0xc0; index < 256; index += 8)
+ emitOneID(o1, i1, decision.instructionIDs[index], true);
break;
case MODRM_FULL:
for (index = 0; index < 256; ++index)
- emitOneID(o1, i1, decision.instructionIDs[index], index < 255);
+ emitOneID(o1, i1, decision.instructionIDs[index], true);
break;
}
-
+
i1--;
- o1.indent(i1) << "};" << "\n";
- o1 << "\n";
-
+
o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
i2++;
-
+
o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
- o2.indent(i2) << "modRMTable" << sTableNumber << "\n";
-
+ o2.indent(i2) << sEntryNumber << " /* Table" << sTableNumber << " */\n";
+
i2--;
o2.indent(i2) << "}";
-
+
+ switch (dt) {
+ default:
+ llvm_unreachable("Unknown decision type");
+ case MODRM_ONEENTRY:
+ sEntryNumber += 1;
+ break;
+ case MODRM_SPLITRM:
+ sEntryNumber += 2;
+ break;
+ case MODRM_SPLITREG:
+ sEntryNumber += 16;
+ break;
+ case MODRM_FULL:
+ sEntryNumber += 256;
+ break;
+ }
+
++sTableNumber;
}
@@ -436,11 +457,11 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
for (index = 0; index < numInstructions; ++index) {
o.indent(i * 2) << "{ /* " << index << " */" << "\n";
i++;
-
- o.indent(i * 2) <<
- stringForModifierType(InstructionSpecifiers[index].modifierType);
+
+ o.indent(i * 2) << stringForModifierType(
+ (ModifierType)InstructionSpecifiers[index].modifierType);
o << "," << "\n";
-
+
o.indent(i * 2) << "0x";
o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
o << "," << "\n";
@@ -450,11 +471,11 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
o.indent(i * 2) << "{ ";
- o << stringForOperandEncoding(InstructionSpecifiers[index]
- .operands[operandIndex]
- .encoding);
+ o <<stringForOperandEncoding((OperandEncoding)InstructionSpecifiers[index]
+ .operands[operandIndex]
+ .encoding);
o << ", ";
- o << stringForOperandType(InstructionSpecifiers[index]
+ o << stringForOperandType((OperandType)InstructionSpecifiers[index]
.operands[operandIndex]
.type);
o << " }";
@@ -468,7 +489,7 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
i--;
o.indent(i * 2) << "}," << "\n";
- o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
+ o.indent(i * 2) << "/* " << InstructionSpecifiers[index].name << " */";
o << "\n";
i--;
@@ -494,7 +515,9 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
for (index = 0; index < 256; ++index) {
o.indent(i * 2);
- if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
+ if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
+ o << "IC_VEX_L_W_OPSIZE";
+ else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
o << "IC_VEX_L_OPSIZE";
else if ((index & ATTR_VEXL) && (index & ATTR_XD))
o << "IC_VEX_L_XD";
@@ -535,6 +558,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
o << "IC_64BIT_XD";
else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
o << "IC_64BIT_OPSIZE";
+ else if ((index & ATTR_64BIT) && (index & ATTR_ADSIZE))
+ o << "IC_64BIT_ADSIZE";
else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
o << "IC_64BIT_REXW";
else if ((index & ATTR_64BIT))
@@ -549,6 +574,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
o << "IC_XD";
else if (index & ATTR_OPSIZE)
o << "IC_OPSIZE";
+ else if (index & ATTR_ADSIZE)
+ o << "IC_ADSIZE";
else
o << "IC";
@@ -594,11 +621,16 @@ void DisassemblerTables::emit(raw_ostream &o) const {
emitContextTable(o, i2);
o << "\n";
-
+
+ o << "static const InstrUID modRMTable[] = {\n";
+ i1++;
emitEmptyTable(o1, i1);
+ i1--;
emitContextDecisions(o1, o2, i1, i2);
-
+
o << o1.str();
+ o << " 0x0\n";
+ o << "};\n";
o << "\n";
o << o2.str();
o << "\n";
diff --git a/utils/TableGen/X86ModRMFilters.cpp b/utils/TableGen/X86ModRMFilters.cpp
new file mode 100644
index 000000000000..7166fe02d890
--- /dev/null
+++ b/utils/TableGen/X86ModRMFilters.cpp
@@ -0,0 +1,26 @@
+//===- X86ModRMFilters.cpp - Disassembler ModR/M filterss -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86ModRMFilters.h"
+
+using namespace llvm::X86Disassembler;
+
+void ModRMFilter::anchor() { }
+
+void DumbFilter::anchor() { }
+
+void ModFilter::anchor() { }
+
+void EscapeFilter::anchor() { }
+
+void AddRegEscapeFilter::anchor() { }
+
+void ExtendedFilter::anchor() { }
+
+void ExactFilter::anchor() { }
diff --git a/utils/TableGen/X86ModRMFilters.h b/utils/TableGen/X86ModRMFilters.h
index 199040bad840..19fecbc3a0a5 100644
--- a/utils/TableGen/X86ModRMFilters.h
+++ b/utils/TableGen/X86ModRMFilters.h
@@ -27,6 +27,7 @@ namespace X86Disassembler {
/// ModRMFilter - Abstract base class for clases that recognize patterns in
/// ModR/M bytes.
class ModRMFilter {
+ virtual void anchor();
public:
/// Destructor - Override as necessary.
virtual ~ModRMFilter() { }
@@ -49,6 +50,7 @@ public:
/// require a ModR/M byte or instructions where the entire ModR/M byte is used
/// for operands.
class DumbFilter : public ModRMFilter {
+ virtual void anchor();
public:
bool isDumb() const {
return true;
@@ -63,7 +65,7 @@ public:
/// Some instructions are classified based on whether they are 11 or anything
/// else. This filter performs that classification.
class ModFilter : public ModRMFilter {
-private:
+ virtual void anchor();
bool R;
public:
/// Constructor
@@ -90,7 +92,7 @@ public:
/// possible value. Otherwise, there is one instruction for each value of the
/// nnn field [bits 5-3], known elsewhere as the reg field.
class EscapeFilter : public ModRMFilter {
-private:
+ virtual void anchor();
bool C0_FF;
uint8_t NNN_or_ModRM;
public:
@@ -121,7 +123,7 @@ public:
/// maps to a single instruction. Such instructions require the ModR/M byte
/// to fall between 0xc0 and 0xff.
class AddRegEscapeFilter : public ModRMFilter {
-private:
+ virtual void anchor();
uint8_t ModRM;
public:
/// Constructor
@@ -142,7 +144,7 @@ public:
/// ExtendedFilter - Extended opcodes are classified based on the value of the
/// mod field [bits 7-6] and the value of the nnn field [bits 5-3].
class ExtendedFilter : public ModRMFilter {
-private:
+ virtual void anchor();
bool R;
uint8_t NNN;
public:
@@ -169,9 +171,8 @@ public:
/// ExactFilter - The occasional extended opcode (such as VMCALL or MONITOR)
/// requires the ModR/M byte to have a specific value.
-class ExactFilter : public ModRMFilter
-{
-private:
+class ExactFilter : public ModRMFilter {
+ virtual void anchor();
uint8_t ModRM;
public:
/// Constructor
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index cae823749245..6a01cce637e4 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -36,7 +36,16 @@ using namespace llvm;
MAP(F8, 41) \
MAP(F9, 42) \
MAP(D0, 45) \
- MAP(D1, 46)
+ MAP(D1, 46) \
+ MAP(D4, 47) \
+ MAP(D8, 48) \
+ MAP(D9, 49) \
+ MAP(DA, 50) \
+ MAP(DB, 51) \
+ MAP(DC, 52) \
+ MAP(DD, 53) \
+ MAP(DE, 54) \
+ MAP(DF, 55)
// A clone of X86 since we can't depend on something that is generated.
namespace X86Local {
@@ -68,7 +77,7 @@ namespace X86Local {
DC = 7, DD = 8, DE = 9, DF = 10,
XD = 11, XS = 12,
T8 = 13, P_TA = 14,
- A6 = 15, A7 = 16, TF = 17
+ A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19
};
}
@@ -119,6 +128,9 @@ namespace X86Local {
EXTENSION_TABLE(ba) \
EXTENSION_TABLE(c7)
+#define THREE_BYTE_38_EXTENSION_TABLES \
+ EXTENSION_TABLE(F3)
+
using namespace X86Disassembler;
/// needsModRMForDecode - Indicates whether a particular instruction requires a
@@ -213,10 +225,13 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
SegOvr = byteFromRec(Rec, "SegOvrBits");
HasOpSizePrefix = Rec->getValueAsBit("hasOpSizePrefix");
+ HasAdSizePrefix = Rec->getValueAsBit("hasAdSizePrefix");
HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix");
HasVEXPrefix = Rec->getValueAsBit("hasVEXPrefix");
HasVEX_4VPrefix = Rec->getValueAsBit("hasVEX_4VPrefix");
+ HasVEX_4VOp3Prefix = Rec->getValueAsBit("hasVEX_4VOp3Prefix");
HasVEX_WPrefix = Rec->getValueAsBit("hasVEX_WPrefix");
+ HasMemOp4Prefix = Rec->getValueAsBit("hasMemOp4Prefix");
IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L");
HasLockPrefix = Rec->getValueAsBit("hasLockPrefix");
IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
@@ -230,7 +245,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
(Name.find("CRC32") != Name.npos);
HasFROperands = hasFROperands();
HasVEX_LPrefix = has256BitOperands() || Rec->getValueAsBit("hasVEX_L");
-
+
// Check for 64-bit inst which does not require REX
Is32Bit = false;
Is64Bit = false;
@@ -254,10 +269,6 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
Rec->getName() == "PUSHFS64" ||
Rec->getName() == "PUSHGS64" ||
Rec->getName() == "REX64_PREFIX" ||
- Rec->getName().find("VMREAD64") != Name.npos ||
- Rec->getName().find("VMWRITE64") != Name.npos ||
- Rec->getName().find("INVEPT64") != Name.npos ||
- Rec->getName().find("INVVPID64") != Name.npos ||
Rec->getName().find("MOV64") != Name.npos ||
Rec->getName().find("PUSH64") != Name.npos ||
Rec->getName().find("POP64") != Name.npos;
@@ -284,67 +295,90 @@ void RecognizableInstr::processInstr(DisassemblerTables &tables,
InstructionContext RecognizableInstr::insnContext() const {
InstructionContext insnContext;
- if (HasVEX_4VPrefix || HasVEXPrefix) {
- if (HasVEX_LPrefix && HasVEX_WPrefix)
- llvm_unreachable("Don't support VEX.L and VEX.W together");
- else if (HasOpSizePrefix && HasVEX_LPrefix)
+ if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix|| HasVEXPrefix) {
+ if (HasVEX_LPrefix && HasVEX_WPrefix) {
+ if (HasOpSizePrefix)
+ insnContext = IC_VEX_L_W_OPSIZE;
+ else
+ llvm_unreachable("Don't support VEX.L and VEX.W together");
+ } else if (HasOpSizePrefix && HasVEX_LPrefix)
insnContext = IC_VEX_L_OPSIZE;
else if (HasOpSizePrefix && HasVEX_WPrefix)
insnContext = IC_VEX_W_OPSIZE;
else if (HasOpSizePrefix)
insnContext = IC_VEX_OPSIZE;
- else if (HasVEX_LPrefix && Prefix == X86Local::XS)
+ else if (HasVEX_LPrefix &&
+ (Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_VEX_L_XS;
- else if (HasVEX_LPrefix && Prefix == X86Local::XD)
+ else if (HasVEX_LPrefix && (Prefix == X86Local::XD ||
+ Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD))
insnContext = IC_VEX_L_XD;
- else if (HasVEX_WPrefix && Prefix == X86Local::XS)
+ else if (HasVEX_WPrefix &&
+ (Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_VEX_W_XS;
- else if (HasVEX_WPrefix && Prefix == X86Local::XD)
+ else if (HasVEX_WPrefix && (Prefix == X86Local::XD ||
+ Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD))
insnContext = IC_VEX_W_XD;
else if (HasVEX_WPrefix)
insnContext = IC_VEX_W;
else if (HasVEX_LPrefix)
insnContext = IC_VEX_L;
- else if (Prefix == X86Local::XD)
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
insnContext = IC_VEX_XD;
- else if (Prefix == X86Local::XS)
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = IC_VEX_XS;
else
insnContext = IC_VEX;
} else if (Is64Bit || HasREX_WPrefix) {
if (HasREX_WPrefix && HasOpSizePrefix)
insnContext = IC_64BIT_REXW_OPSIZE;
- else if (HasOpSizePrefix &&
- (Prefix == X86Local::XD || Prefix == X86Local::TF))
+ else if (HasOpSizePrefix && (Prefix == X86Local::XD ||
+ Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD))
insnContext = IC_64BIT_XD_OPSIZE;
- else if (HasOpSizePrefix && Prefix == X86Local::XS)
+ else if (HasOpSizePrefix &&
+ (Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_64BIT_XS_OPSIZE;
else if (HasOpSizePrefix)
insnContext = IC_64BIT_OPSIZE;
- else if (HasREX_WPrefix && Prefix == X86Local::XS)
- insnContext = IC_64BIT_REXW_XS;
+ else if (HasAdSizePrefix)
+ insnContext = IC_64BIT_ADSIZE;
else if (HasREX_WPrefix &&
- (Prefix == X86Local::XD || Prefix == X86Local::TF))
+ (Prefix == X86Local::XS || Prefix == X86Local::T8XS))
+ insnContext = IC_64BIT_REXW_XS;
+ else if (HasREX_WPrefix && (Prefix == X86Local::XD ||
+ Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD))
insnContext = IC_64BIT_REXW_XD;
- else if (Prefix == X86Local::XD || Prefix == X86Local::TF)
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
insnContext = IC_64BIT_XD;
- else if (Prefix == X86Local::XS)
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
insnContext = IC_64BIT_XS;
else if (HasREX_WPrefix)
insnContext = IC_64BIT_REXW;
else
insnContext = IC_64BIT;
} else {
- if (HasOpSizePrefix &&
- (Prefix == X86Local::XD || Prefix == X86Local::TF))
+ if (HasOpSizePrefix && (Prefix == X86Local::XD ||
+ Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD))
insnContext = IC_XD_OPSIZE;
- else if (HasOpSizePrefix && Prefix == X86Local::XS)
+ else if (HasOpSizePrefix &&
+ (Prefix == X86Local::XS || Prefix == X86Local::T8XS))
insnContext = IC_XS_OPSIZE;
else if (HasOpSizePrefix)
insnContext = IC_OPSIZE;
- else if (Prefix == X86Local::XD || Prefix == X86Local::TF)
+ else if (HasAdSizePrefix)
+ insnContext = IC_ADSIZE;
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
insnContext = IC_XD;
- else if (Prefix == X86Local::XS || Prefix == X86Local::REP)
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS ||
+ Prefix == X86Local::REP)
insnContext = IC_XS;
else
insnContext = IC;
@@ -371,19 +405,12 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
return FILTER_STRONG;
- // Filter out artificial instructions
+ // Filter out artificial instructions but leave in the LOCK_PREFIX so it is
+ // printed as a separate "instruction".
- if (Name.find("TAILJMP") != Name.npos ||
- Name.find("_Int") != Name.npos ||
- Name.find("_int") != Name.npos ||
+ if (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 ||
- Name.find("WIN") != Name.npos ||
- Name.find("_AVX") != Name.npos ||
Name.find("2SDL") != Name.npos)
return FILTER_STRONG;
@@ -421,12 +448,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
Name.find("Xrr") != Name.npos ||
Name.find("rr64") != Name.npos)
return FILTER_WEAK;
-
- if (Name == "VMASKMOVDQU64" ||
- Name == "VEXTRACTPSrr64" ||
- Name == "VMOVQd64rr" ||
- Name == "VMOVQs64rr")
- return FILTER_WEAK;
// Special cases.
@@ -441,29 +462,15 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
return FILTER_WEAK;
if (Name.find("Fs") != Name.npos)
return FILTER_WEAK;
- if (Name == "MOVLPDrr" ||
- Name == "MOVLPSrr" ||
- Name == "PUSHFQ" ||
- Name == "BSF16rr" ||
- Name == "BSF16rm" ||
- Name == "BSR16rr" ||
- Name == "BSR16rm" ||
- Name == "MOVSX16rm8" ||
- Name == "MOVSX16rr8" ||
- Name == "MOVZX16rm8" ||
- Name == "MOVZX16rr8" ||
- Name == "PUSH32i16" ||
- Name == "PUSH64i16" ||
+ if (Name == "PUSH64i16" ||
Name == "MOVPQI2QImr" ||
Name == "VMOVPQI2QImr" ||
- Name == "MOVSDmr" ||
- Name == "MOVSDrm" ||
- Name == "MOVSSmr" ||
- Name == "MOVSSrm" ||
Name == "MMX_MOVD64rrv164" ||
- Name == "CRC32m16" ||
Name == "MOV64ri64i32" ||
- Name == "CRC32r16")
+ Name == "VMASKMOVDQU64" ||
+ Name == "VEXTRACTPSrr64" ||
+ Name == "VMOVQd64rr" ||
+ Name == "VMOVQs64rr")
return FILTER_WEAK;
if (HasFROperands && Name.find("MOV") != Name.npos &&
@@ -566,7 +573,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
bool hasFROperands = false;
- assert(numOperands < X86_MAX_OPERANDS && "X86_MAX_OPERANDS is not large enough");
+ assert(numOperands <= X86_MAX_OPERANDS && "X86_MAX_OPERANDS is not large enough");
for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
if (OperandList[operandIndex].Constraints.size()) {
@@ -684,31 +691,40 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
- if (HasVEX_4VPrefix)
- assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 4 &&
+ if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix)
+ assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 &&
"Unexpected number of operands for MRMSrcRegFrm with VEX_4V");
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMSrcRegFrm");
HANDLE_OPERAND(roRegister)
-
+
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
-
+
+ if (HasMemOp4Prefix)
+ HANDLE_OPERAND(immediate)
+
HANDLE_OPERAND(rmRegister)
- HANDLE_OPTIONAL(immediate)
+
+ if (HasVEX_4VOp3Prefix)
+ HANDLE_OPERAND(vvvvRegister)
+
+ if (!HasMemOp4Prefix)
+ HANDLE_OPTIONAL(immediate)
+ HANDLE_OPTIONAL(immediate) // above might be a register in 7:4
break;
case X86Local::MRMSrcMem:
// Operand 1 is a register operand in the Reg/Opcode field.
// Operand 2 is a memory operand (possibly SIB-extended)
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
-
- if (HasVEX_4VPrefix)
- assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 4 &&
+
+ if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix)
+ assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 &&
"Unexpected number of operands for MRMSrcMemFrm with VEX_4V");
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
@@ -721,8 +737,17 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
+ if (HasMemOp4Prefix)
+ HANDLE_OPERAND(immediate)
+
HANDLE_OPERAND(memory)
- HANDLE_OPTIONAL(immediate)
+
+ if (HasVEX_4VOp3Prefix)
+ HANDLE_OPERAND(vvvvRegister)
+
+ if (!HasMemOp4Prefix)
+ HANDLE_OPTIONAL(immediate)
+ HANDLE_OPTIONAL(immediate) // above might be a register in 7:4
break;
case X86Local::MRM0r:
case X86Local::MRM1r:
@@ -736,12 +761,12 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
// Operand 2 (optional) is an immediate or relocation.
if (HasVEX_4VPrefix)
assert(numPhysicalOperands <= 3 &&
- "Unexpected number of operands for MRMSrcMemFrm with VEX_4V");
+ "Unexpected number of operands for MRMnRFrm with VEX_4V");
else
assert(numPhysicalOperands <= 2 &&
"Unexpected number of operands for MRMnRFrm");
if (HasVEX_4VPrefix)
- HANDLE_OPERAND(vvvvRegister);
+ HANDLE_OPERAND(vvvvRegister)
HANDLE_OPTIONAL(rmRegister)
HANDLE_OPTIONAL(relocation)
break;
@@ -755,8 +780,14 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
case X86Local::MRM7m:
// Operand 1 is a memory operand (possibly SIB-extended)
// Operand 2 (optional) is an immediate or relocation.
- assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
- "Unexpected number of operands for MRMnMFrm");
+ if (HasVEX_4VPrefix)
+ assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
+ "Unexpected number of operands for MRMnMFrm");
+ else
+ assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
+ "Unexpected number of operands for MRMnMFrm");
+ if (HasVEX_4VPrefix)
+ HANDLE_OPERAND(vvvvRegister)
HANDLE_OPERAND(memory)
HANDLE_OPTIONAL(relocation)
break;
@@ -843,15 +874,50 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
opcodeToSet = Opcode;
break;
case X86Local::T8:
- case X86Local::TF:
+ case X86Local::T8XD:
+ case X86Local::T8XS:
opcodeType = THREEBYTE_38;
- if (needsModRMForDecode(Form))
- filter = new ModFilter(isRegFormat(Form));
- else
- filter = new DumbFilter();
+ switch (Opcode) {
+ default:
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ break;
+#define EXTENSION_TABLE(n) case 0x##n:
+ THREE_BYTE_38_EXTENSION_TABLES
+#undef EXTENSION_TABLE
+ switch (Form) {
+ default:
+ llvm_unreachable("Unhandled two-byte extended opcode");
+ case X86Local::MRM0r:
+ case X86Local::MRM1r:
+ case X86Local::MRM2r:
+ case X86Local::MRM3r:
+ case X86Local::MRM4r:
+ case X86Local::MRM5r:
+ case X86Local::MRM6r:
+ case X86Local::MRM7r:
+ filter = new ExtendedFilter(true, Form - X86Local::MRM0r);
+ break;
+ case X86Local::MRM0m:
+ case X86Local::MRM1m:
+ case X86Local::MRM2m:
+ case X86Local::MRM3m:
+ case X86Local::MRM4m:
+ case X86Local::MRM5m:
+ case X86Local::MRM6m:
+ case X86Local::MRM7m:
+ filter = new ExtendedFilter(false, Form - X86Local::MRM0m);
+ break;
+ MRM_MAPPING
+ } // switch (Form)
+ break;
+ } // switch (Opcode)
opcodeToSet = Opcode;
break;
case X86Local::P_TA:
+ case X86Local::TAXD:
opcodeType = THREEBYTE_3A;
if (needsModRMForDecode(Form))
filter = new ModFilter(isRegFormat(Form));
@@ -1049,6 +1115,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i16imm_pcrel", TYPE_REL16)
TYPE("i32imm_pcrel", TYPE_REL32)
TYPE("SSECC", TYPE_IMM3)
+ TYPE("AVXCC", TYPE_IMM5)
TYPE("brtarget", TYPE_RELv)
TYPE("uncondbrtarget", TYPE_RELv)
TYPE("brtarget8", TYPE_REL8)
@@ -1090,6 +1157,7 @@ OperandEncoding RecognizableInstr::immediateEncodingFromString
ENCODING("i32i8imm", ENCODING_IB)
ENCODING("u32u8imm", ENCODING_IB)
ENCODING("SSECC", ENCODING_IB)
+ ENCODING("AVXCC", ENCODING_IB)
ENCODING("i16imm", ENCODING_Iv)
ENCODING("i16i8imm", ENCODING_IB)
ENCODING("i32imm", ENCODING_Iv)
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 44415978273f..6c0a234b5eff 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -50,17 +50,23 @@ private:
uint8_t SegOvr;
/// The hasOpSizePrefix field from the record
bool HasOpSizePrefix;
+ /// The hasAdSizePrefix field from the record
+ bool HasAdSizePrefix;
/// The hasREX_WPrefix field from the record
bool HasREX_WPrefix;
/// The hasVEXPrefix field from the record
bool HasVEXPrefix;
/// The hasVEX_4VPrefix field from the record
bool HasVEX_4VPrefix;
+ /// The hasVEX_4VOp3Prefix field from the record
+ bool HasVEX_4VOp3Prefix;
/// The hasVEX_WPrefix field from the record
bool HasVEX_WPrefix;
/// Inferred from the operands; indicates whether the L bit in the VEX prefix is set
bool HasVEX_LPrefix;
- // The ignoreVEX_L field from the record
+ /// The hasMemOp4Prefix field from the record
+ bool HasMemOp4Prefix;
+ /// The ignoreVEX_L field from the record
bool IgnoresVEX_L;
/// The hasLockPrefix field from the record
bool HasLockPrefix;
@@ -70,7 +76,7 @@ private:
bool Is64Bit;
// Whether the instruction has the predicate "In32BitMode"
bool Is32Bit;
-
+
/// The instruction name as listed in the tables
std::string Name;
/// The AT&T AsmString for the instruction