diff options
Diffstat (limited to 'utils/TableGen')
34 files changed, 1423 insertions, 760 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 5ef0db9..cdcc496 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,7 +253,7 @@ public: switch (Kind) { case Invalid: - assert(0 && "Invalid kind!"); + llvm_unreachable("Invalid kind!"); default: // This class precedes the RHS if it is a proper subset of the RHS. @@ -282,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 @@ -361,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; @@ -401,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. @@ -552,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; @@ -641,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); @@ -656,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,7 +749,8 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) { 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() + "'!"); @@ -799,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) { @@ -1104,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 @@ -1160,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; - - // 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; - } + 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; + + // 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. @@ -1262,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"); @@ -1468,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); @@ -2003,40 +2023,48 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, // Emit the static custom operand parsing table; OS << "namespace {\n"; OS << " struct OperandMatchEntry {\n"; - OS << " const char *Mnemonic;\n"; + OS << " static const char *MnemonicTable;\n"; OS << " unsigned OperandMask;\n"; - OS << " MatchClassKind Class;\n"; - OS << " unsigned RequiredFeatures;\n"; + OS << " uint16_t Mnemonic;\n"; + OS << " " << getMinimalTypeForRange(Info.Classes.size()) + << " Class;\n"; + OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size()) + << " RequiredFeatures;\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; @@ -2049,6 +2077,11 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, } 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 << " */"; + OS << ", " << OMI.CI->Name << ", "; @@ -2064,6 +2097,10 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, } OS << "};\n\n"; + OS << "const char *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 " @@ -2117,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"; @@ -2209,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"; @@ -2283,31 +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 << " static const char *MnemonicTable;\n"; + OS << " uint16_t Opcode;\n"; + OS << " uint16_t Mnemonic;\n"; OS << " " << getMinimalTypeForRange(Info.Matchables.size()) << " ConvertFn;\n"; OS << " " << getMinimalTypeForRange(Info.Classes.size()) << " Classes[" << MaxNumOperands << "];\n"; OS << " " << getMinimalTypeForRange(1ULL << Info.SubtargetFeatures.size()) << " RequiredFeatures;\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"; @@ -2316,8 +2361,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { it != ie; ++it) { MatchableInfo &II = **it; + // Store a pascal-style length byte in the mnemonic. + std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); OS << " { " << Target.getName() << "::" - << II.getResultInst()->TheDef->getName() << ", \"" << II.Mnemonic << "\"" + << II.getResultInst()->TheDef->getName() << ", " + << StringTable.GetOrAddStringOffset(LenMnemonic, false) + << " /* " << II.Mnemonic << " */" << ", " << II.ConversionFnKind << ", { "; for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) { MatchableInfo::AsmOperand &Op = II.AsmOperands[i]; @@ -2335,12 +2384,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } } else OS << "0"; - + OS << ", " << II.AsmVariantID; OS << "},\n"; } OS << "};\n\n"; + OS << "const char *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"; @@ -2356,7 +2409,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"; @@ -2368,7 +2422,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. @@ -2401,9 +2457,10 @@ 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"; diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index bbac59c..c4812dc 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -544,7 +544,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()); @@ -858,7 +858,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(); diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index ac33f99..2b70f1c 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -22,7 +22,6 @@ add_tablegen(llvm-tblgen LLVM EDEmitter.cpp FastISelEmitter.cpp FixedLenDecoderEmitter.cpp - InstrEnumEmitter.cpp InstrInfoEmitter.cpp IntrinsicEmitter.cpp PseudoLoweringEmitter.cpp @@ -33,5 +32,6 @@ add_tablegen(llvm-tblgen LLVM TGValueTypes.cpp TableGen.cpp X86DisassemblerTables.cpp + X86ModRMFilters.cpp X86RecognizableInstr.cpp ) diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index a106fc8..2a1bcab 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -169,13 +169,13 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, 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"; @@ -238,7 +238,7 @@ void CodeEmitterGen::run(raw_ostream &o) { if (R->getValueAsString("Namespace") == "TargetOpcode" || R->getValueAsBit("isPseudo")) { - o << " 0U,\n"; + o << " UINT64_C(0),\n"; continue; } @@ -250,9 +250,9 @@ void CodeEmitterGen::run(raw_ostream &o) { if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(e-i-1))) Value |= 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; diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index dbf1662..3280e09 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include <set> #include <algorithm> using namespace llvm; @@ -629,11 +630,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 +749,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 +840,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 +913,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, EnforceVectorSubVectorTypeIs(NodeToApply->getExtType(ResNo), TP); } } - return false; + llvm_unreachable("Invalid ConstraintType!"); } //===----------------------------------------------------------------------===// @@ -1609,10 +1609,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 +2070,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 936fd01..5a2d40a 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/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index 3aadf50..9c61f3f 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -22,6 +22,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 +80,7 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum) : TheDef(R), EnumValue(Enum), CostPerUse(R->getValueAsInt("CostPerUse")), + CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")), SubRegsComplete(false) {} @@ -36,15 +88,6 @@ const std::string &CodeGenRegister::getName() const { return TheDef->getName(); } -namespace { - struct Orphan { - CodeGenRegister *SubReg; - Record *First, *Second; - Orphan(CodeGenRegister *r, Record *a, Record *b) - : SubReg(r), First(a), Second(b) {} - }; -} - const CodeGenRegister::SubRegMap & CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) { // Only compute this map once. @@ -53,23 +96,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 +129,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 +137,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 +176,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 +186,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,34 +196,50 @@ 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; } return SubRegs; } void -CodeGenRegister::addSubRegsPreOrder(SetVector<CodeGenRegister*> &OSet) const { +CodeGenRegister::addSubRegsPreOrder(SetVector<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); } } @@ -215,30 +306,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 +431,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 +549,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 +605,20 @@ 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); +} + + //===----------------------------------------------------------------------===// // CodeGenRegBank //===----------------------------------------------------------------------===// @@ -511,13 +626,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"); @@ -561,6 +682,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) @@ -606,34 +736,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) @@ -642,7 +766,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) @@ -651,16 +775,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"; } } } @@ -669,13 +790,8 @@ 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(); } // Compute sets of overlapping registers. @@ -802,7 +918,8 @@ void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) { // void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) { // Map SubRegIndex to set of registers in RC supporting that SubRegIndex. - typedef std::map<Record*, CodeGenRegister::Set, LessRecord> SubReg2SetMap; + typedef std::map<CodeGenSubRegIndex*, CodeGenRegister::Set, + CodeGenSubRegIndex::Less> SubReg2SetMap; // Compute the set of registers supporting each SubRegIndex. SubReg2SetMap SRSets; @@ -817,7 +934,7 @@ void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) { // 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]; + CodeGenSubRegIndex *SubIdx = SubRegIndices[sri]; SubReg2SetMap::const_iterator I = SRSets.find(SubIdx); // Unsupported SubRegIndex. Skip it. if (I == SRSets.end()) @@ -836,12 +953,71 @@ void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) { } // +// 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)); + } + + // 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; + // 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()); + } + } +} + + +// // 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) { @@ -852,6 +1028,22 @@ void CodeGenRegBank::computeInferredRegisterClasses() { // 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; + } } } @@ -901,3 +1093,45 @@ CodeGenRegBank::getRegClassForRegister(Record *R) { } return FoundRC; } + +BitVector CodeGenRegBank::computeCoveredRegisters(ArrayRef<Record*> Regs) { + SetVector<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) { + 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 c74cfd6..beaa678 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,7 +110,8 @@ 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<CodeGenRegister*> &OSet, + CodeGenRegBank&) const; // List of super-registers in topological order, small to large. typedef std::vector<CodeGenRegister*> SuperRegList; @@ -101,9 +158,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; std::string Namespace; @@ -128,8 +193,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 +214,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. @@ -223,8 +299,12 @@ namespace llvm { 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; @@ -246,11 +326,8 @@ namespace llvm { void computeInferredRegisterClasses(); void inferCommonSubClass(CodeGenRegisterClass *RC); void inferSubClassWithSubReg(CodeGenRegisterClass *RC); - - // Composite SubRegIndex instances. - // Map (SubRegIndex, SubRegIndex) -> SubRegIndex. - typedef DenseMap<std::pair<Record*, Record*>, Record*> CompositeMap; - CompositeMap Composite; + void inferMatchingSuperRegClass(CodeGenRegisterClass *RC, + unsigned FirstSubRegRC = 0); // Populate the Composite map from sub-register relationships. void computeComposites(); @@ -263,14 +340,15 @@ 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; } @@ -302,6 +380,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 c8d2b00..cf67935 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"; @@ -91,7 +93,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { 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 ""; + 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 { @@ -493,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 730216c..85463da 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 1367e8d..bd77907 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 dcb8da7..99ebf98 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 3b65b2a..bd425a9 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/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp index 2862d0c..5721121 100644 --- a/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/utils/TableGen/DFAPacketizerEmitter.cpp @@ -311,8 +311,10 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) { // If there are no valid transitions from this stage, we need a sentinel // transition. - if (ValidTransitions == StateEntry[i]) + if (ValidTransitions == StateEntry[i]) { OS << "{-1, -1},"; + ++ValidTransitions; + } OS << "\n"; } diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index 6c3cae2..70d07bc 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -519,6 +519,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 { @@ -572,14 +574,17 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, REG("QQPR"); REG("QQQQPR"); REG("VecListOneD"); - REG("VecListTwoD"); + REG("VecListDPair"); + REG("VecListDPairSpaced"); REG("VecListThreeD"); REG("VecListFourD"); - REG("VecListTwoQ"); REG("VecListOneDAllLanes"); REG("VecListTwoDAllLanes"); + REG("VecListTwoQAllLanes"); IMM("i32imm"); + IMM("fbits16"); + IMM("fbits32"); IMM("i32imm_hilo16"); IMM("bf_inv_mask_imm"); IMM("lsb_pos_imm"); @@ -977,11 +982,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 9fdc2e3..e8dad77 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 440d44c..19e86db 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" @@ -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"); } } } @@ -285,8 +286,20 @@ protected: 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. @@ -334,6 +347,8 @@ protected: // Returns true if predicate matches were emitted, false otherwise. bool emitPredicateMatch(raw_ostream &o, unsigned &Indentation,unsigned Opc); + void emitSoftFailCheck(raw_ostream &o, unsigned Indentation, unsigned Opc); + // 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); @@ -573,8 +588,9 @@ unsigned Filter::usefulness() const { void FilterChooser::emitTop(raw_ostream &o, unsigned Indentation, std::string Namespace) { 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"; o.indent(Indentation) << " (void)tmp;\n"; @@ -698,9 +714,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) @@ -759,7 +773,8 @@ 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"; @@ -776,7 +791,8 @@ 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"); + ListInit *Predicates = + AllInstructions[Opc]->TheDef->getValueAsListInit("Predicates"); for (unsigned i = 0; i < Predicates->getSize(); ++i) { Record *Pred = Predicates->getElementAsRecord(i); if (!Pred->getValue("AssemblerMatcherPredicate")) @@ -802,6 +818,66 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, return Predicates->getSize() > 0; } +void FilterChooser::emitSoftFailCheck(raw_ostream &o, unsigned Indentation, + unsigned Opc) { + 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, @@ -824,6 +900,7 @@ 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 @@ -831,15 +908,16 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, // 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; } @@ -873,6 +951,7 @@ 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 @@ -880,14 +959,15 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, // 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; @@ -1069,7 +1149,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: @@ -1090,7 +1170,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: @@ -1112,13 +1192,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"); } } diff --git a/utils/TableGen/FixedLenDecoderEmitter.h b/utils/TableGen/FixedLenDecoderEmitter.h index 2df5448..bd5111f 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.h +++ b/utils/TableGen/FixedLenDecoderEmitter.h @@ -52,7 +52,8 @@ 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 = "") : diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp deleted file mode 100644 index 5981afd..0000000 --- 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 c29a309..0000000 --- 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 89abb84..4c4cd18 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -14,6 +14,7 @@ #include "InstrInfoEmitter.h" #include "CodeGenTarget.h" +#include "StringToOffsetTable.h" #include "llvm/TableGen/Record.h" #include "llvm/ADT/StringExtras.h" #include <algorithm> @@ -212,10 +213,26 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OperandInfoIDs, OS); OS << "};\n\n"; + OS << "extern const unsigned " << TargetName <<"InstrNameIndices[] = {\n "; + StringToOffsetTable StringTable; + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { + const CodeGenInstruction *Instr = NumberedInstructions[i]; + OS << StringTable.GetOrAddStringOffset(Instr->TheDef->getName()) << "U, "; + if (i % 8 == 0) + OS << "\n "; + } + + OS << "\n};\n\n"; + + OS << "const char *" << TargetName << "InstrNameData =\n"; + StringTable.EmitString(OS); + OS << ";\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"; @@ -240,9 +257,12 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\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 +284,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)"; diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 782b89e..578b3aa 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -160,17 +160,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 +184,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 +323,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 +419,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 +488,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 +520,45 @@ 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"; + OS << " 255, // Invalid intrinsic\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 << " switch(IntrinsicsToAttributesMap[id]) {\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,7 +566,7 @@ 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(" << argNo+1 << ", "; @@ -609,34 +621,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"; + OS << "};\n\n" + << "return static_cast<ModRefBehavior>(IntrinsicModRefBehavior[iid]);\n" + << "#endif // GET_INTRINSIC_MODREF_BEHAVIOR\n\n"; } void IntrinsicEmitter:: diff --git a/utils/TableGen/PseudoLoweringEmitter.cpp b/utils/TableGen/PseudoLoweringEmitter.cpp index c685527..d3e2389 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; } @@ -176,8 +176,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 d228f72..c949a25 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -90,6 +90,20 @@ 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"; @@ -134,8 +148,7 @@ 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"; @@ -180,8 +193,7 @@ 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"; @@ -189,6 +201,9 @@ RegisterInfoEmitter::EmitRegMapping(raw_ostream &OS, 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 << " "; if (!isCtor) OS << "RI->"; @@ -254,26 +269,28 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, const std::string &TargetName = Target.getName(); - OS << "\nnamespace {\n"; - const std::vector<CodeGenRegister*> &Regs = RegBank.getRegisters(); + OS << "extern const uint16_t " << TargetName << "RegOverlaps[] = {\n"; + // Emit an overlap list for all registers. 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[] = { " + OS << " /* " << 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"; + OS << "0,\n"; } + OS << "};\n\n"; + OS << "extern const uint16_t " << TargetName << "SubRegsSet[] = {\n"; // Emit the empty sub-registers list - OS << " const unsigned Empty_SubRegsSet[] = { 0 };\n"; + OS << " /* 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) { @@ -282,15 +299,17 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, continue; // getSubRegs() orders by SubRegIndex. We want a topological order. SetVector<CodeGenRegister*> SR; - Reg.addSubRegsPreOrder(SR); - OS << " const unsigned " << Reg.getName() << "_SubRegsSet[] = { "; + Reg.addSubRegsPreOrder(SR, RegBank); + OS << " /* " << Reg.getName() << "_SubRegsSet */ "; for (unsigned j = 0, je = SR.size(); j != je; ++j) OS << getQualifiedName(SR[j]->TheDef) << ", "; - OS << "0 };\n"; + OS << "0,\n"; } + OS << "};\n\n"; + OS << "extern const uint16_t " << TargetName << "SuperRegsSet[] = {\n"; // Emit the empty super-registers list - OS << " const unsigned Empty_SuperRegsSet[] = { 0 };\n"; + OS << " /* 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) { @@ -298,31 +317,42 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, const CodeGenRegister::SuperRegList &SR = Reg.getSuperRegs(); if (SR.empty()) continue; - OS << " const unsigned " << Reg.getName() << "_SuperRegsSet[] = { "; + OS << " /* " << Reg.getName() << "_SuperRegsSet */ "; for (unsigned j = 0, je = SR.size(); j != je; ++j) OS << getQualifiedName(SR[j]->TheDef) << ", "; - OS << "0 };\n"; + OS << "0,\n"; } - OS << "}\n"; // End of anonymous namespace... + OS << "};\n\n"; - OS << "\nextern const MCRegisterDesc " << TargetName + 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. + unsigned OverlapsIndex = 0; + unsigned SubRegIndex = 1; // skip 1 for empty set + unsigned SuperRegIndex = 1; // skip 1 for empty set for (unsigned i = 0, e = Regs.size(); i != e; ++i) { - const CodeGenRegister &Reg = *Regs[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 << Reg->getName() << "\", /* " << Reg->getName() << "_Overlaps */ " + << OverlapsIndex << ", "; + OverlapsIndex += Overlaps[Reg].size() + 1; + if (!Reg->getSubRegs().empty()) { + OS << "/* " << Reg->getName() << "_SubRegsSet */ " << SubRegIndex + << ", "; + // FIXME not very nice to recalculate this + SetVector<CodeGenRegister*> SR; + Reg->addSubRegsPreOrder(SR, RegBank); + SubRegIndex += SR.size() + 1; + } else + OS << "/* Empty_SubRegsSet */ 0, "; + if (!Reg->getSuperRegs().empty()) { + OS << "/* " << Reg->getName() << "_SuperRegsSet */ " << SuperRegIndex; + SuperRegIndex += Reg->getSuperRegs().size() + 1; + } else + OS << "/* Empty_SuperRegsSet */ 0"; OS << " },\n"; } OS << "};\n\n"; // End of register descriptors... @@ -342,7 +372,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]; @@ -351,7 +381,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) { @@ -369,33 +399,68 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { const CodeGenRegisterClass &RC = *RegisterClasses[rc]; - OS << " MCRegisterClass(" << RC.getQualifiedName() + "RegClassID" << ", " - << '\"' << RC.getName() << "\", " + 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"; + } + // 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 << "RegOverlaps, " + << TargetName << "SubRegsSet, " << TargetName << "SuperRegsSet, "; + 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"; } @@ -421,28 +486,14 @@ 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" << "};\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()) { @@ -453,19 +504,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"; } @@ -517,7 +560,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // Emit the register list now. OS << " // " << Name << " Register Class Value Types...\n" - << " static const EVT " << Name + << " const MVT::SimpleValueType " << Name << "[] = {\n "; for (unsigned i = 0, e = RC.VTs.size(); i != e; ++i) OS << getEnumName(RC.VTs[i]) << ", "; @@ -527,16 +570,10 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // 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(); @@ -561,10 +598,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 = @@ -581,7 +618,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, } OS << (!Empty ? ", " : "") << "NULL"; - OS << "\n };\n\n"; + OS << "\n};\n\n"; } } @@ -592,9 +629,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. @@ -606,54 +643,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 " + << RC.getName() << "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"; } @@ -683,11 +737,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // 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(); + ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices(); OS << "\n static const char *const " << TargetName << "SubRegIndexTable[] = { \""; for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) { @@ -697,7 +751,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) { @@ -711,48 +765,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" @@ -761,15 +773,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) @@ -798,7 +810,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"; @@ -815,22 +827,105 @@ 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"; + // Emit the constructor of the class... OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n"; - - OS << ClassName << "::" << ClassName + OS << "extern const uint16_t " << TargetName << "RegOverlaps[];\n"; + OS << "extern const uint16_t " << TargetName << "SubRegsSet[];\n"; + OS << "extern const uint16_t " << TargetName << "SuperRegsSet[];\n"; + if (SubRegIndices.size() != 0) + OS << "extern const uint16_t *get" << TargetName + << "SubRegTable();\n"; + + 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 << "RegOverlaps, " + << TargetName << "SubRegsSet, " << TargetName << "SuperRegsSet,\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/SetTheory.cpp b/utils/TableGen/SetTheory.cpp index bef73f3..0649fd1 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 6e8313b..b394058 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 ac9422c..803f5bd 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 34cd9a9..986c50f 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"; } diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 3899a41..8c41358 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -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 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; - } - 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 61e9452..2875168 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: @@ -102,7 +107,6 @@ static inline bool inheritsFrom(InstructionContext child, return false; default: llvm_unreachable("Unknown instruction class"); - return false; } } @@ -141,8 +145,6 @@ static inline const char* stringForContext(InstructionContext insnContext) { INSTRUCTION_CONTEXTS #undef ENUM_ENTRY } - - return 0; } /// stringForOperandType - Like stringForContext, but for OperandTypes. @@ -197,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 @@ -210,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; } @@ -294,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; } @@ -439,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"; @@ -453,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 << " }"; @@ -471,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--; @@ -540,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)) @@ -554,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"; @@ -599,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 0000000..7166fe0 --- /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 199040b..19fecbc 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 ce8ea1a..5bf473d 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 { @@ -216,11 +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"); @@ -333,6 +344,8 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_64BIT_XS_OPSIZE; else if (HasOpSizePrefix) insnContext = IC_64BIT_OPSIZE; + else if (HasAdSizePrefix) + insnContext = IC_64BIT_ADSIZE; else if (HasREX_WPrefix && (Prefix == X86Local::XS || Prefix == X86Local::T8XS)) insnContext = IC_64BIT_REXW_XS; @@ -359,6 +372,8 @@ InstructionContext RecognizableInstr::insnContext() const { insnContext = IC_XS_OPSIZE; else if (HasOpSizePrefix) insnContext = IC_OPSIZE; + else if (HasAdSizePrefix) + insnContext = IC_ADSIZE; else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD || Prefix == X86Local::TAXD) insnContext = IC_XD; @@ -558,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()) { @@ -677,7 +692,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { // Operand 3 (optional) is an immediate. if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix) - assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 4 && + assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 && "Unexpected number of operands for MRMSrcRegFrm with VEX_4V"); else assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 && @@ -690,12 +705,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(rmRegister) if (HasVEX_4VOp3Prefix) HANDLE_OPERAND(vvvvRegister) - HANDLE_OPTIONAL(immediate) + 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. @@ -704,7 +724,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { // Operand 3 (optional) is an immediate. if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix) - assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 4 && + assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 && "Unexpected number of operands for MRMSrcMemFrm with VEX_4V"); else assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 && @@ -717,12 +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) if (HasVEX_4VOp3Prefix) HANDLE_OPERAND(vvvvRegister) - HANDLE_OPTIONAL(immediate) + if (!HasMemOp4Prefix) + HANDLE_OPTIONAL(immediate) + HANDLE_OPTIONAL(immediate) // above might be a register in 7:4 break; case X86Local::MRM0r: case X86Local::MRM1r: diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index 42a5fec..6c0a234 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -50,6 +50,8 @@ 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 @@ -62,7 +64,9 @@ private: 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; |